diff options
author | 2014-03-04 02:53:34 -0800 | |
---|---|---|
committer | 2014-03-04 02:54:08 -0800 | |
commit | 79d14521db4c71250109785b8317aeceecd539c9 (patch) | |
tree | c2f8587332924e5887366d7edad98ff5f8c1950a /parse_util.cpp | |
parent | 8d6b0c8d764ee6500301ecb937eb636216d9bcd4 (diff) |
Support for error detection in arguments in new parser. Restores error
reporting for bad arguments (e.g. with bad variable names)
Diffstat (limited to 'parse_util.cpp')
-rw-r--r-- | parse_util.cpp | 201 |
1 files changed, 199 insertions, 2 deletions
diff --git a/parse_util.cpp b/parse_util.cpp index 230a328c..d6e1c9ea 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -1001,11 +1001,205 @@ static bool first_argument_is_help(const parse_node_tree_t &node_tree, const par return is_help; } +void parse_util_expand_variable_error(const parse_node_t &node, const wcstring &token, size_t token_pos, size_t error_pos, parse_error_list_t *out_errors) +{ + size_t stop_pos = token_pos+1; + + switch (token[stop_pos]) + { + case BRACKET_BEGIN: + { + wchar_t *cpy = wcsdup(token.c_str()); + *(cpy+token_pos)=0; + wchar_t *name = &cpy[stop_pos+1]; + wchar_t *end = wcschr(name, BRACKET_END); + wchar_t *post; + int is_var=0; + if (end) + { + post = end+1; + *end = 0; + + if (!wcsvarname(name)) + { + is_var = 1; + } + } + + if (is_var) + { + append_syntax_error(out_errors, + node, + COMPLETE_VAR_BRACKET_DESC, + cpy, + name, + post); + } + else + { + append_syntax_error(out_errors, + node, + COMPLETE_VAR_BRACKET_DESC, + L"", + L"VARIABLE", + L""); + } + free(cpy); + + break; + } + + case INTERNAL_SEPARATOR: + { + append_syntax_error(out_errors, + node, + COMPLETE_VAR_PARAN_DESC); + break; + } + + case 0: + { + append_syntax_error(out_errors, + node, + COMPLETE_VAR_NULL_DESC); + break; + } + + default: + { + wchar_t token_stop_char = token[stop_pos]; + // Unescape (see http://github.com/fish-shell/fish-shell/issues/50) + if (token_stop_char == ANY_CHAR) + token_stop_char = L'?'; + else if (token_stop_char == ANY_STRING || token_stop_char == ANY_STRING_RECURSIVE) + token_stop_char = L'*'; + + append_syntax_error(out_errors, + node, + (token_stop_char == L'?' ? COMPLETE_YOU_WANT_STATUS : COMPLETE_VAR_DESC), + token_stop_char); + break; + } + } +} + + +/** + Test if this argument contains any errors. Detected errors include + syntax errors in command substitutions, improperly escaped + characters and improper use of the variable expansion operator. +*/ +parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t &node, const wcstring &arg_src, parse_error_list_t *out_errors) +{ + int err=0; + + wchar_t *paran_begin, *paran_end; + wchar_t *arg_cpy; + int do_loop = 1; + + arg_cpy = wcsdup(arg_src.c_str()); + + while (do_loop) + { + switch (parse_util_locate_cmdsubst(arg_cpy, + ¶n_begin, + ¶n_end, + false)) + { + case -1: + { + err=1; + if (out_errors) + { + append_syntax_error(out_errors, node, L"Mismatched parenthesis"); + } + free(arg_cpy); + return err; + } + + case 0: + { + do_loop = 0; + break; + } + + case 1: + { + + const wcstring subst(paran_begin + 1, paran_end); + wcstring tmp; + + tmp.append(arg_cpy, paran_begin - arg_cpy); + tmp.push_back(INTERNAL_SEPARATOR); + tmp.append(paran_end+1); + + parse_error_list_t errors; + err |= parse_util_detect_errors(subst, &errors); + if (out_errors != NULL) + { + /* Todo: have to tweak the offsets of the errors in the command substitution */ + out_errors->insert(out_errors->end(), errors.begin(), errors.end()); + } + + free(arg_cpy); + arg_cpy = wcsdup(tmp.c_str()); + + break; + } + } + } + + wcstring unesc; + if (! unescape_string(arg_cpy, &unesc, UNESCAPE_SPECIAL)) + { + if (out_errors) + { + append_syntax_error(out_errors, node, L"Invalid token '%ls'", arg_cpy); + } + return 1; + } + else + { + /* Check for invalid variable expansions */ + const size_t unesc_size = unesc.size(); + for (size_t idx = 0; idx < unesc_size; idx++) + { + switch (unesc.at(idx)) + { + case VARIABLE_EXPAND: + case VARIABLE_EXPAND_SINGLE: + { + wchar_t next_char = (idx + 1 < unesc_size ? unesc.at(idx + 1) : L'\0'); + + if (next_char != VARIABLE_EXPAND && + next_char != VARIABLE_EXPAND_SINGLE && + ! wcsvarchr(next_char)) + { + err=1; + if (out_errors) + { + parse_util_expand_variable_error(node, unesc, idx, node.source_start, out_errors); + } + } + + break; + } + } + } + } + + free(arg_cpy); + + return err; +} + parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors) { parse_node_tree_t node_tree; parse_error_list_t parse_errors; + parser_test_error_bits_t res = 0; + // Whether we encountered a parse error bool errored = false; @@ -1065,6 +1259,11 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars errored = append_syntax_error(&parse_errors, node, EXEC_ERR_MSG, is_and ? L"and" : L"or"); } } + else if (node.type == symbol_argument) + { + const wcstring arg_src = node.get_source(buff_src); + res |= parse_util_detect_errors_in_argument(node, arg_src, &parse_errors); + } else if (node.type == symbol_plain_statement) { // In a few places below, we want to know if we are in a pipeline @@ -1159,8 +1358,6 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars } } - parser_test_error_bits_t res = 0; - if (errored) res |= PARSER_TEST_ERROR; |