diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-18 13:14:26 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-18 13:14:26 +0200 |
| commit | 2bdec03def3054bbd80d5fd23e9bb0c026f85fc4 (patch) | |
| tree | a7cd2ff8f50b7d93171d4e79d9c3ec72a97c5922 /shell | |
| parent | 2ccb8918190f95fe6119bee46ae4b595a2e8306d (diff) | |
| download | busybox-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.c | 52 |
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 |
