diff options
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 91 | ||||
| -rw-r--r-- | shell/hush_test/hush-misc/case2.right | 1 | ||||
| -rwxr-xr-x | shell/hush_test/hush-misc/case2.tests | 6 | ||||
| -rw-r--r-- | shell/hush_test/hush-misc/case3.right | 2 | ||||
| -rwxr-xr-x | shell/hush_test/hush-misc/case3.tests | 8 |
5 files changed, 55 insertions, 53 deletions
diff --git a/shell/hush.c b/shell/hush.c index b32d903ae..9ec813df2 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -748,9 +748,6 @@ struct parse_context { smallint is_assignment; /* 0:maybe, 1:yes, 2:no, 3:keyword */ #if HAS_KEYWORDS smallint ctx_res_w; -#if ENABLE_HUSH_CASE - smallint ctx_dsemicolon; /* ";;" seen */ -#endif /* bitmask of FLAG_xxx, for figuring out valid reserved words */ int old_flag; /* group we are enclosed in: @@ -4170,7 +4167,7 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx) { # if ENABLE_HUSH_CASE static const struct reserved_combo reserved_match = { - "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC + "", RES_MATCH, NOT_ASSIGNMENT, FLAG_MATCH | FLAG_ESAC }; # endif const struct reserved_combo *r; @@ -4266,7 +4263,7 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx) * Look at it and update current command: * update current command's argv/cmd_type/etc, fill in redirect name and type, * check reserved-ness and assignment-ness, etc... - * Normal return is 0. Syntax errors return 1. + * Normal return is 0. Syntax errors print error message and return 1. * Note: on return, word is reset, but not o_free'd! */ static int done_word(struct parse_context *ctx) @@ -4324,15 +4321,16 @@ static int done_word(struct parse_context *ctx) #if HAS_KEYWORDS # if ENABLE_HUSH_CASE - - if (ctx->ctx_dsemicolon + if (ctx->ctx_res_w == RES_MATCH && (ctx->word.has_quoted_part || strcmp(ctx->word.data, "esac") != 0 ) - ) { /* ";; WORD" but not "... PATTERN) CMD;; esac" */ - /* already done when ctx_dsemicolon was set to 1: */ - /* ctx->ctx_res_w = RES_MATCH; */ - ctx->ctx_dsemicolon = 0; + ) { /* ";; WORD" but not ";; esac" */ + /* Do not match WORD as keyword: + * the WORD is a case match, can be keyword-like: + * if) echo got_if;; + * is allowed. + */ } else # endif # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) @@ -4345,13 +4343,13 @@ static int done_word(struct parse_context *ctx) } else # endif if (!command->argv /* if it's the first word of command... */ - && !command->redirects /* no redirects yet... disallows: </dev/null ! true; echo $? */ + && !command->redirects /* no redirects yet... disallows: </dev/null if true; then... */ # if ENABLE_HUSH_LOOPS && ctx->ctx_res_w != RES_FOR /* not after FOR or IN */ && ctx->ctx_res_w != RES_IN # endif # if ENABLE_HUSH_CASE - && ctx->ctx_res_w != RES_CASE /* not after CASE */ + && ctx->ctx_res_w != RES_CASE /* not after CASE */ # endif ) { const struct reserved_combo *reserved; @@ -5648,7 +5646,7 @@ static struct pipe *parse_stream(char **pstring, if (ch == EOF) { /* Testcase: eval 'echo Ok\' */ /* bash-4.3.43 was removing backslash, - * but 4.4.19 retains it, most other shells too + * but 4.4.19 retains it, most other shells retain too */ break; } @@ -5749,9 +5747,8 @@ static struct pipe *parse_stream(char **pstring, } /* ch == last eaten whitespace char */ #endif - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } if (ch == '\n') { /* Is this a case when newline is simply ignored? * Some examples: @@ -5784,10 +5781,10 @@ static struct pipe *parse_stream(char **pstring, if (pi->num_cmds != 0 /* check #1 */ && pi->followup != PIPE_BG /* check #2 */ ) { - continue; + continue; /* ignore newline */ } } - /* Treat newline as a command separator. */ + /* Treat newline as a command separator */ done_pipe(&ctx, PIPE_SEQ); debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt); if (heredoc_cnt) { @@ -5805,11 +5802,11 @@ static struct pipe *parse_stream(char **pstring, /* "cmd}" or "cmd }..." without semicolon or &: * } is an ordinary char in this case, even inside { cmd; } - * Pathological example: { ""}; } should exec "}" cmd + * Pathological example: { ""}; } should run "}" command. */ if (ch == '}') { - if (ctx.word.length != 0 /* word} */ - || ctx.word.has_quoted_part /* ""} */ + if (ctx.word.length != 0 /* word} */ + || ctx.word.has_quoted_part /* ""} */ ) { goto ordinary_char; } @@ -5842,9 +5839,8 @@ static struct pipe *parse_stream(char **pstring, ) #endif ) { - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } if (done_pipe(&ctx, PIPE_SEQ)) { /* Testcase: sh -c 'date|;not_reached' */ syntax_error_unterm_ch('|'); @@ -5889,9 +5885,8 @@ static struct pipe *parse_stream(char **pstring, switch (ch) { case '>': redir_fd = redirect_opt_num(&ctx.word); - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } redir_style = REDIRECT_OVERWRITE; if (next == '>') { redir_style = REDIRECT_APPEND; @@ -5909,9 +5904,8 @@ static struct pipe *parse_stream(char **pstring, continue; /* get next char */ case '<': redir_fd = redirect_opt_num(&ctx.word); - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } redir_style = REDIRECT_INPUT; if (next == '<') { redir_style = REDIRECT_HEREDOC; @@ -5951,7 +5945,7 @@ static struct pipe *parse_stream(char **pstring, } ch = i_getch(input); if (ch == EOF) - break; + goto eof; } continue; /* get next char */ } @@ -6026,27 +6020,17 @@ static struct pipe *parse_stream(char **pstring, } #endif case ';': -#if ENABLE_HUSH_CASE - case_semi: -#endif - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } done_pipe(&ctx, PIPE_SEQ); #if ENABLE_HUSH_CASE - /* Eat multiple semicolons, detect - * whether it means something special */ - while (1) { - ch = i_peek_and_eat_bkslash_nl(input); - if (ch != ';') - break; + if (ctx.ctx_res_w == RES_CASE_BODY + && !is_blank /* is it really actual semicolon? */ + && i_peek_and_eat_bkslash_nl(input) == ';' /* and next char is ';' too? */ + ) { ch = i_getch(input); nommu_addchr(&ctx.as_string, ch); - if (ctx.ctx_res_w == RES_CASE_BODY) { - ctx.ctx_dsemicolon = 1; - ctx.ctx_res_w = RES_MATCH; - break; - } + ctx.ctx_res_w = RES_MATCH; /* "we are in PATTERN)" */ } #endif new_cmd: @@ -6056,9 +6040,8 @@ static struct pipe *parse_stream(char **pstring, debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); continue; /* get next char */ case '&': - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } if (ctx.pipe->num_cmds == 0 && IS_NULL_CMD(ctx.command)) { /* Testcase: sh -c '&& date' */ /* Testcase: sh -c '&' */ @@ -6082,9 +6065,8 @@ static struct pipe *parse_stream(char **pstring, } goto new_cmd; case '|': - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } #if ENABLE_HUSH_CASE if (ctx.ctx_res_w == RES_MATCH) break; /* we are in case's "word | word)" */ @@ -6135,8 +6117,12 @@ static struct pipe *parse_stream(char **pstring, } case ')': #if ENABLE_HUSH_CASE - if (ctx.ctx_res_w == RES_MATCH) - goto case_semi; + if (ctx.ctx_res_w == RES_MATCH) { + if (done_word(&ctx)) + goto parse_error_exitcode1; + done_pipe(&ctx, PIPE_SEQ); + goto new_cmd; + } #endif case '}': /* proper use of this character is caught by end_trigger: @@ -6150,7 +6136,7 @@ static struct pipe *parse_stream(char **pstring, bb_error_msg_and_die("BUG: unexpected %c", ch); } } /* while (1) */ - + eof: /* Reached EOF */ if (heredoc_cnt) { syntax_error_unterm_str("here document"); @@ -6165,9 +6151,8 @@ static struct pipe *parse_stream(char **pstring, goto parse_error_exitcode1; } - if (done_word(&ctx)) { + if (done_word(&ctx)) goto parse_error_exitcode1; - } o_free_and_set_NULL(&ctx.word); if (done_pipe(&ctx, PIPE_SEQ)) { /* Testcase: sh -c 'date |' */ diff --git a/shell/hush_test/hush-misc/case2.right b/shell/hush_test/hush-misc/case2.right new file mode 100644 index 000000000..4780199de --- /dev/null +++ b/shell/hush_test/hush-misc/case2.right @@ -0,0 +1 @@ +hush: syntax error: unexpected ) diff --git a/shell/hush_test/hush-misc/case2.tests b/shell/hush_test/hush-misc/case2.tests new file mode 100755 index 000000000..b9475392e --- /dev/null +++ b/shell/hush_test/hush-misc/case2.tests @@ -0,0 +1,6 @@ +# had a parser bug which incorrectly detected ";;" +case w in +a); +b);; +esac +echo Should not be reached diff --git a/shell/hush_test/hush-misc/case3.right b/shell/hush_test/hush-misc/case3.right new file mode 100644 index 000000000..02a29ccbc --- /dev/null +++ b/shell/hush_test/hush-misc/case3.right @@ -0,0 +1,2 @@ +Keyword-like word may be in pattern +Ok:0 diff --git a/shell/hush_test/hush-misc/case3.tests b/shell/hush_test/hush-misc/case3.tests new file mode 100755 index 000000000..63b9dfd99 --- /dev/null +++ b/shell/hush_test/hush-misc/case3.tests @@ -0,0 +1,8 @@ +if=if +case if in +if) echo "Keyword-like word may be in pattern";; +fi) echo "Not reached";; +# esac) echo "Not reached";; # not accepted by bash 5.2.15 +do) echo "Not reached" +esac +echo Ok:$? |
