From 76f715c48613686d02a9513375065cbd7dad7921 Mon Sep 17 00:00:00 2001 From: Cheer Xiao Date: Fri, 22 Feb 2013 22:34:30 +0800 Subject: [PATCH] add class scoped_push to automatically restore variable on function exit --- common.h | 43 ++++++++++++++++++++++++++++++++++ parser.cpp | 69 ++++++++++++++++-------------------------------------- 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/common.h b/common.h index f018dedf4..8a10a7efb 100644 --- a/common.h +++ b/common.h @@ -444,6 +444,49 @@ class scoped_lock ~scoped_lock(); }; + +/** + A scoped manager to save the current value of some variable, and optionally + set it to a new value. On destruction it restores the variable to its old + value. + + This can be handy when there are multiple code paths to exit a block. +*/ +template +class scoped_push +{ + T &ref; + T saved_value; + bool restored; + +public: + scoped_push(T &r): + ref(r), restored(false) + { + saved_value = ref; + } + + scoped_push(T &r, T new_value): + ref(r), restored(false) + { + saved_value = ref; + ref = new_value; + } + + ~scoped_push() + { + if (!restored) + restore(); + } + + void restore() + { + ref = saved_value; + restored = true; + } +}; + + /* Wrapper around wcstok */ class wcstokenizer { diff --git a/parser.cpp b/parser.cpp index 529550d79..82c108a6d 100644 --- a/parser.cpp +++ b/parser.cpp @@ -731,12 +731,6 @@ int parser_t::eval_args(const wchar_t *line, std::vector &args) if (this->parser_type != PARSER_TYPE_GENERAL) eflags |= EXPAND_SKIP_CMDSUBST; - /* - eval_args may be called while evaulating another command, so we - save the previous tokenizer and restore it on exit - */ - tokenizer_t * const previous_tokenizer = current_tokenizer; - const int previous_pos = current_tokenizer_pos; int do_loop=1; CHECK(line, 1); @@ -747,8 +741,13 @@ int parser_t::eval_args(const wchar_t *line, std::vector &args) proc_push_interactive(0); tokenizer_t tok(line, (show_errors ? 0 : TOK_SQUASH_ERRORS)); - current_tokenizer = &tok; - current_tokenizer_pos = 0; + + /* + eval_args may be called while evaulating another command, so we + save the previous tokenizer and restore it on exit + */ + scoped_push tokenizer_push(current_tokenizer, &tok); + scoped_push tokenizer_pos_push(current_tokenizer_pos, 0); error_code=0; @@ -802,9 +801,6 @@ int parser_t::eval_args(const wchar_t *line, std::vector &args) if (show_errors) this->print_errors_stderr(); - current_tokenizer=previous_tokenizer; - current_tokenizer_pos = previous_pos; - if (this->parser_type == PARSER_TYPE_GENERAL) proc_pop_interactive(); @@ -1652,9 +1648,7 @@ int parser_t::parse_job(process_t *p, bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands block_t *prev_block = current_block; - int prev_tokenizer_pos = current_tokenizer_pos; - - current_tokenizer_pos = tok_get_pos(tok); + scoped_push tokenizer_pos_push(current_tokenizer_pos, tok_get_pos(tok)); while (args.empty()) { @@ -1677,7 +1671,6 @@ int parser_t::parse_job(process_t *p, ILLEGAL_CMD_ERR_MSG, tok_last(tok)); - current_tokenizer_pos = prev_tokenizer_pos; return 0; } break; @@ -1690,7 +1683,6 @@ int parser_t::parse_job(process_t *p, TOK_ERR_MSG, tok_last(tok)); - current_tokenizer_pos = prev_tokenizer_pos; return 0; } @@ -1712,7 +1704,6 @@ int parser_t::parse_job(process_t *p, tok_get_desc(tok_last_type(tok))); } - current_tokenizer_pos = prev_tokenizer_pos; return 0; } @@ -1723,7 +1714,6 @@ int parser_t::parse_job(process_t *p, CMD_ERR_MSG, tok_get_desc(tok_last_type(tok))); - current_tokenizer_pos = prev_tokenizer_pos; return 0; } } @@ -1746,7 +1736,6 @@ int parser_t::parse_job(process_t *p, error(SYNTAX_ERROR, tok_get_pos(tok), EXEC_ERR_MSG); - current_tokenizer_pos = prev_tokenizer_pos; return 0; } @@ -1801,7 +1790,7 @@ int parser_t::parse_job(process_t *p, use_function = 0; use_builtin=0; p->type=INTERNAL_EXEC; - current_tokenizer_pos = prev_tokenizer_pos; + tokenizer_pos_push.restore(); } } } @@ -2231,7 +2220,6 @@ int parser_t::parse_job(process_t *p, parser_t::pop_block(); } } - current_tokenizer_pos = prev_tokenizer_pos; return !error_code; } @@ -2333,7 +2321,7 @@ void parser_t::eval_job(tokenizer_t *tok) profile_item_t *profile_item = NULL; bool skip = false; - int job_begin_pos, prev_tokenizer_pos; + int job_begin_pos; const bool do_profile = profile; if (do_profile) @@ -2422,10 +2410,8 @@ void parser_t::eval_job(tokenizer_t *tok) int was_builtin = 0; if (j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next) was_builtin = 1; - prev_tokenizer_pos = current_tokenizer_pos; - current_tokenizer_pos = job_begin_pos; + scoped_push tokenizer_pos_push(current_tokenizer_pos, job_begin_pos); exec(*this, j); - current_tokenizer_pos = prev_tokenizer_pos; /* Only external commands require a new fishd barrier */ if (!was_builtin) @@ -2563,14 +2549,12 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type const wchar_t * const cmd = cmdStr.c_str(); size_t forbid_count; int code; - tokenizer_t *previous_tokenizer=current_tokenizer; block_t *start_current_block = current_block; /* Record the current chain so we can put it back later */ - const io_chain_t prev_io = block_io; - block_io = io; + scoped_push block_io_push(block_io, io); - std::vector prev_forbidden = forbidden_function; + scoped_push > forbidden_function_push(forbidden_function); if (block_type == SUBST) { @@ -2581,8 +2565,6 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type forbid_count = forbidden_function.size(); - block_io = io; - job_reap(0); debug(4, L"eval: %ls", cmd); @@ -2609,7 +2591,7 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type this->push_block(new scope_block_t(block_type)); - current_tokenizer = new tokenizer_t(cmd, 0); + scoped_push tokenizer_push(current_tokenizer, new tokenizer_t(cmd, 0)); error_code = 0; @@ -2667,9 +2649,6 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type /* Restore previous eval state */ - forbidden_function = prev_forbidden; - current_tokenizer=previous_tokenizer; - block_io = prev_io; eval_level--; code=error_code; @@ -2834,16 +2813,15 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha int parser_t::test_args(const wchar_t * buff, wcstring *out, const wchar_t *prefix) { - tokenizer_t *const previous_tokenizer = current_tokenizer; - const int previous_pos = current_tokenizer_pos; int do_loop = 1; int err = 0; CHECK(buff, 1); - tokenizer_t tok(buff, 0); - current_tokenizer = &tok; + scoped_push tokenizer_push(current_tokenizer, &tok); + scoped_push tokenizer_pos_push(current_tokenizer_pos); + for (; do_loop && tok_has_next(&tok); tok_next(&tok)) { current_tokenizer_pos = tok_get_pos(&tok); @@ -2893,9 +2871,6 @@ int parser_t::test_args(const wchar_t * buff, wcstring *out, const wchar_t *pre } } - current_tokenizer = previous_tokenizer; - current_tokenizer_pos = previous_pos; - error_code=0; return err; @@ -2923,9 +2898,6 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w int err=0; int unfinished = 0; - tokenizer_t * const previous_tokenizer=current_tokenizer; - const int previous_pos=current_tokenizer_pos; - // These are very nearly stacks, but sometimes we have to inspect non-top elements (e.g. return) std::vector block_infos; int indentation_sum = 0; //sum of indentation in block_infos @@ -2973,7 +2945,9 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w } tokenizer_t tok(buff, 0); - current_tokenizer = &tok; + + scoped_push tokenizer_push(current_tokenizer, &tok); + scoped_push tokenizer_pos_push(current_tokenizer_pos); for (;; tok_next(&tok)) { @@ -3714,9 +3688,6 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w Cleanup */ - current_tokenizer=previous_tokenizer; - current_tokenizer_pos = previous_pos; - error_code=0;