aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2025-08-18 13:14:26 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2025-08-18 13:14:26 +0200
commit2bdec03def3054bbd80d5fd23e9bb0c026f85fc4 (patch)
treea7cd2ff8f50b7d93171d4e79d9c3ec72a97c5922 /shell
parent2ccb8918190f95fe6119bee46ae4b595a2e8306d (diff)
downloadbusybox-w32-2bdec03def3054bbd80d5fd23e9bb0c026f85fc4.tar.gz
busybox-w32-2bdec03def3054bbd80d5fd23e9bb0c026f85fc4.tar.bz2
busybox-w32-2bdec03def3054bbd80d5fd23e9bb0c026f85fc4.zip
hush: disentangle keyword detection, no logic changes
function old new delta done_word 790 766 -24 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c52
1 files changed, 27 insertions, 25 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 00887d45f..f776a6468 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3947,7 +3947,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3947# endif 3947# endif
3948# if ENABLE_HUSH_CASE 3948# if ENABLE_HUSH_CASE
3949 [RES_CASE ] = "CASE" , 3949 [RES_CASE ] = "CASE" ,
3950 [RES_CASE_IN ] = "CASE_IN" , 3950 [RES_CASE_IN] = "CASE_IN" ,
3951 [RES_MATCH] = "MATCH", 3951 [RES_MATCH] = "MATCH",
3952 [RES_CASE_BODY] = "CASE_BODY", 3952 [RES_CASE_BODY] = "CASE_BODY",
3953 [RES_ESAC ] = "ESAC" , 3953 [RES_ESAC ] = "ESAC" ,
@@ -4289,11 +4289,22 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx)
4289# endif 4289# endif
4290 const struct reserved_combo *r; 4290 const struct reserved_combo *r;
4291 4291
4292 if (ctx->word.has_quoted_part)
4293 return 0;
4294 r = match_reserved_word(ctx->word.data); 4292 r = match_reserved_word(ctx->word.data);
4295 if (!r) 4293 if (!r)
4296 return r; /* NULL */ 4294 return r; /* NULL */
4295# if ENABLE_HUSH_CASE /* "case" syntax has a curveball */
4296 if (ctx->ctx_res_w == RES_MATCH
4297 && r->res != RES_ESAC
4298 ) {
4299 /* We are at WORD in ";; WORD" or "case .. in WORD".
4300 * Here, only "esac" is a keyword.
4301 * Else WORD is a case pattern, can be keyword-like:
4302 * if) echo got_if;;
4303 * is allowed.
4304 */
4305 return NULL;
4306 }
4307# endif
4297 4308
4298 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 4309 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
4299# if ENABLE_HUSH_CASE 4310# if ENABLE_HUSH_CASE
@@ -4309,7 +4320,7 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx)
4309 return r; 4320 return r;
4310 } 4321 }
4311# endif 4322# endif
4312 if (ctx->pipe->cmds != ctx->command /* bash disallows: nice | ! cat */ 4323 if (ctx->pipe->num_cmds != 0 /* bash disallows: nice | ! cat */
4313 /* || ctx->pipe->pi_inverted - bash used to disallow "! ! true" bash 5.2.15 allows it */ 4324 /* || ctx->pipe->pi_inverted - bash used to disallow "! ! true" bash 5.2.15 allows it */
4314 ) { 4325 ) {
4315 syntax_error_unexpected_ch('!'); 4326 syntax_error_unexpected_ch('!');
@@ -4443,36 +4454,26 @@ static int done_word(struct parse_context *ctx)
4443 } 4454 }
4444 4455
4445#if HAS_KEYWORDS 4456#if HAS_KEYWORDS
4446# if ENABLE_HUSH_CASE
4447 if (ctx->ctx_res_w == RES_MATCH
4448 && (ctx->word.has_quoted_part
4449 || strcmp(ctx->word.data, "esac") != 0
4450 )
4451 ) { /* ";; WORD" but not ";; esac" */
4452 /* Do not match WORD as keyword:
4453 * the WORD is a case match, can be keyword-like:
4454 * if) echo got_if;;
4455 * is allowed.
4456 */
4457 } else
4458# endif
4459# if defined(CMD_TEST2_SINGLEWORD_NOGLOB) 4457# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4460 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB 4458 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
4461 && !ctx->word.has_quoted_part 4459 && !ctx->word.has_quoted_part
4462 && strcmp(ctx->word.data, "]]") == 0 4460 && strcmp(ctx->word.data, "]]") == 0
4463 ) { 4461 ) {
4464 /* allow "[[ ]] >file" etc */ 4462 /* End test2-specific parsing rules */
4463 /* Allow "[[ ]] >file" etc (> is a redirect symbol again) */
4465 command->cmd_type = CMD_SINGLEWORD_NOGLOB; 4464 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4466 } else 4465 } else
4467# endif 4466# endif
4468 if (!command->argv /* if it's the first word of command... */ 4467 /* Is it a place where keyword can appear? */
4469 && !command->redirects /* no redirects yet... disallows: </dev/null if true; then... */ 4468 if (!command->argv /* if it's the first word of command... */
4469 && !ctx->word.has_quoted_part /* ""WORD never matches any keywords */
4470 && !command->redirects /* no redirects yet... disallows: </dev/null if true; then... */
4470# if ENABLE_HUSH_LOOPS 4471# if ENABLE_HUSH_LOOPS
4471 && ctx->ctx_res_w != RES_FOR /* not after FOR or IN */ 4472 && ctx->ctx_res_w != RES_FOR /* not after "for" or "in" */
4472 && ctx->ctx_res_w != RES_IN 4473 && ctx->ctx_res_w != RES_IN
4473# endif 4474# endif
4474# if ENABLE_HUSH_CASE 4475# if ENABLE_HUSH_CASE
4475 && ctx->ctx_res_w != RES_CASE /* not after CASE */ 4476 && ctx->ctx_res_w != RES_CASE /* not after "case" */
4476# endif 4477# endif
4477 ) { 4478 ) {
4478 const struct reserved_combo *reserved; 4479 const struct reserved_combo *reserved;
@@ -4481,10 +4482,10 @@ static int done_word(struct parse_context *ctx)
4481 if (reserved) { 4482 if (reserved) {
4482# if ENABLE_HUSH_LINENO_VAR 4483# if ENABLE_HUSH_LINENO_VAR
4483/* Case: 4484/* Case:
4484 * "while ...; do 4485 * while ...; do
4485 * cmd ..." 4486 * CMD
4486 * If we don't close the pipe _now_, immediately after "do", lineno logic 4487 * If we don't close the pipe _now_, immediately after "do", lineno logic
4487 * sees "cmd" as starting at "do" - i.e., at the previous line. 4488 * sees CMD as starting at "do" - i.e., at the previous line.
4488 */ 4489 */
4489 if (0 4490 if (0
4490 IF_HUSH_IF(|| reserved->res == RES_THEN) 4491 IF_HUSH_IF(|| reserved->res == RES_THEN)
@@ -4502,6 +4503,7 @@ static int done_word(struct parse_context *ctx)
4502 } 4503 }
4503# if defined(CMD_TEST2_SINGLEWORD_NOGLOB) 4504# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4504 if (strcmp(ctx->word.data, "[[") == 0) { 4505 if (strcmp(ctx->word.data, "[[") == 0) {
4506 /* Inside [[ ]], parsing rules are different */
4505 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB; 4507 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
4506 } else 4508 } else
4507# endif 4509# endif