diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-05-23 16:50:07 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-05-23 16:50:07 +0200 |
commit | e9bda90e549d1470c7630e1f015b7c1e1560b56b (patch) | |
tree | 171240523541449a1d97562564c2f0037057782d /shell | |
parent | 342a63d659ed41b0fe9f412eb75d495e64cc2096 (diff) | |
download | busybox-w32-e9bda90e549d1470c7630e1f015b7c1e1560b56b.tar.gz busybox-w32-e9bda90e549d1470c7630e1f015b7c1e1560b56b.tar.bz2 busybox-w32-e9bda90e549d1470c7630e1f015b7c1e1560b56b.zip |
hush: fix problems with case in subshells and with "case esac"
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 35 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/case1.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/case1.tests | 15 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/unset.right | 2 |
4 files changed, 42 insertions, 18 deletions
diff --git a/shell/hush.c b/shell/hush.c index d6286b61c..acc8ef944 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -192,9 +192,10 @@ typedef enum reserved_style { | |||
192 | #endif | 192 | #endif |
193 | #if ENABLE_HUSH_CASE | 193 | #if ENABLE_HUSH_CASE |
194 | RES_CASE , | 194 | RES_CASE , |
195 | /* two pseudo-keywords support contrived "case" syntax: */ | 195 | /* three pseudo-keywords support contrived "case" syntax: */ |
196 | RES_MATCH , /* "word)" */ | 196 | RES_CASE_IN, /* "case ... IN", turns into RES_MATCH when IN is observed */ |
197 | RES_CASEI , /* "this command is inside CASE" */ | 197 | RES_MATCH , /* "word)" */ |
198 | RES_CASE_BODY, /* "this command is inside CASE" */ | ||
198 | RES_ESAC , | 199 | RES_ESAC , |
199 | #endif | 200 | #endif |
200 | RES_XXXX , | 201 | RES_XXXX , |
@@ -3766,8 +3767,9 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3766 | #endif | 3767 | #endif |
3767 | #if ENABLE_HUSH_CASE | 3768 | #if ENABLE_HUSH_CASE |
3768 | [RES_CASE ] = "CASE" , | 3769 | [RES_CASE ] = "CASE" , |
3770 | [RES_CASE_IN ] = "CASE_IN" , | ||
3769 | [RES_MATCH] = "MATCH", | 3771 | [RES_MATCH] = "MATCH", |
3770 | [RES_CASEI] = "CASEI", | 3772 | [RES_CASE_BODY] = "CASE_BODY", |
3771 | [RES_ESAC ] = "ESAC" , | 3773 | [RES_ESAC ] = "ESAC" , |
3772 | #endif | 3774 | #endif |
3773 | [RES_XXXX ] = "XXXX" , | 3775 | [RES_XXXX ] = "XXXX" , |
@@ -4011,7 +4013,7 @@ static int run_list(struct pipe *pi) | |||
4011 | } | 4013 | } |
4012 | continue; | 4014 | continue; |
4013 | } | 4015 | } |
4014 | if (rword == RES_CASEI) { /* inside of a case branch */ | 4016 | if (rword == RES_CASE_BODY) { /* inside of a case branch */ |
4015 | if (cond_code != 0) | 4017 | if (cond_code != 0) |
4016 | continue; /* not matched yet, skip this pipe */ | 4018 | continue; /* not matched yet, skip this pipe */ |
4017 | } | 4019 | } |
@@ -4252,7 +4254,9 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
4252 | #endif | 4254 | #endif |
4253 | #if ENABLE_HUSH_CASE | 4255 | #if ENABLE_HUSH_CASE |
4254 | if (ctx->ctx_res_w == RES_MATCH) | 4256 | if (ctx->ctx_res_w == RES_MATCH) |
4255 | ctx->ctx_res_w = RES_CASEI; | 4257 | ctx->ctx_res_w = RES_CASE_BODY; |
4258 | if (ctx->ctx_res_w == RES_CASE) | ||
4259 | ctx->ctx_res_w = RES_CASE_IN; | ||
4256 | #endif | 4260 | #endif |
4257 | ctx->command = NULL; /* trick done_command below */ | 4261 | ctx->command = NULL; /* trick done_command below */ |
4258 | /* Create the memory for command, roughly: | 4262 | /* Create the memory for command, roughly: |
@@ -4366,10 +4370,10 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
4366 | 4370 | ||
4367 | debug_printf("found reserved word %s, res %d\n", r->literal, r->res); | 4371 | debug_printf("found reserved word %s, res %d\n", r->literal, r->res); |
4368 | #if ENABLE_HUSH_CASE | 4372 | #if ENABLE_HUSH_CASE |
4369 | if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE) | 4373 | if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) { |
4370 | /* "case word IN ..." - IN part starts first match part */ | 4374 | /* "case word IN ..." - IN part starts first MATCH part */ |
4371 | r = &reserved_match; | 4375 | r = &reserved_match; |
4372 | else | 4376 | } else |
4373 | #endif | 4377 | #endif |
4374 | if (r->flag == 0) { /* '!' */ | 4378 | if (r->flag == 0) { /* '!' */ |
4375 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ | 4379 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ |
@@ -4495,6 +4499,9 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4495 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 4499 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
4496 | && ctx->ctx_res_w != RES_IN | 4500 | && ctx->ctx_res_w != RES_IN |
4497 | # endif | 4501 | # endif |
4502 | # if ENABLE_HUSH_CASE | ||
4503 | && ctx->ctx_res_w != RES_CASE | ||
4504 | # endif | ||
4498 | ) { | 4505 | ) { |
4499 | debug_printf_parse("checking '%s' for reserved-ness\n", word->data); | 4506 | debug_printf_parse("checking '%s' for reserved-ness\n", word->data); |
4500 | if (reserved_word(word, ctx)) { | 4507 | if (reserved_word(word, ctx)) { |
@@ -5578,7 +5585,13 @@ static struct pipe *parse_stream(char **pstring, | |||
5578 | } | 5585 | } |
5579 | 5586 | ||
5580 | if (end_trigger && end_trigger == ch | 5587 | if (end_trigger && end_trigger == ch |
5581 | && (heredoc_cnt == 0 || end_trigger != ';') | 5588 | && (ch != ';' || heredoc_cnt == 0) |
5589 | #if ENABLE_HUSH_CASE | ||
5590 | && (ch != ')' | ||
5591 | || ctx.ctx_res_w != RES_MATCH | ||
5592 | || (!dest.o_quoted && strcmp(dest.data, "esac") == 0) | ||
5593 | ) | ||
5594 | #endif | ||
5582 | ) { | 5595 | ) { |
5583 | if (heredoc_cnt) { | 5596 | if (heredoc_cnt) { |
5584 | /* This is technically valid: | 5597 | /* This is technically valid: |
@@ -5784,7 +5797,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5784 | break; | 5797 | break; |
5785 | ch = i_getch(input); | 5798 | ch = i_getch(input); |
5786 | nommu_addchr(&ctx.as_string, ch); | 5799 | nommu_addchr(&ctx.as_string, ch); |
5787 | if (ctx.ctx_res_w == RES_CASEI) { | 5800 | if (ctx.ctx_res_w == RES_CASE_BODY) { |
5788 | ctx.ctx_dsemicolon = 1; | 5801 | ctx.ctx_dsemicolon = 1; |
5789 | ctx.ctx_res_w = RES_MATCH; | 5802 | ctx.ctx_res_w = RES_MATCH; |
5790 | break; | 5803 | break; |
diff --git a/shell/hush_test/hush-misc/case1.right b/shell/hush_test/hush-misc/case1.right index e9e371ac0..4afb2f51c 100644 --- a/shell/hush_test/hush-misc/case1.right +++ b/shell/hush_test/hush-misc/case1.right | |||
@@ -12,3 +12,11 @@ OK_44 | |||
12 | OK_51 | 12 | OK_51 |
13 | OK_52 | 13 | OK_52 |
14 | OK_53 | 14 | OK_53 |
15 | OK_sub1 | ||
16 | OK_sub2 | ||
17 | OK_sub3 | ||
18 | OK_sub4 | ||
19 | OK_sub5 | ||
20 | OK_sub6 | ||
21 | OK_esac1 | ||
22 | Done | ||
diff --git a/shell/hush_test/hush-misc/case1.tests b/shell/hush_test/hush-misc/case1.tests index b2c96ccf8..d72b57f53 100755 --- a/shell/hush_test/hush-misc/case1.tests +++ b/shell/hush_test/hush-misc/case1.tests | |||
@@ -25,13 +25,16 @@ case w in `echo w`) echo OK_51;; `echo WRONG >&2`w) echo WRONG;; esac; | |||
25 | case w in `echo OK_52 >&2`) echo SKIP;; `echo`w) echo OK_53;; esac; | 25 | case w in `echo OK_52 >&2`) echo SKIP;; `echo`w) echo OK_53;; esac; |
26 | 26 | ||
27 | # parsing cases in subshells can easily get messy | 27 | # parsing cases in subshells can easily get messy |
28 | case m in m) echo ok-sub1;; esac | 28 | case m in m) echo OK_sub1;; esac |
29 | case m in (m) echo ok-sub2;; esac | 29 | case m in (m) echo OK_sub2;; esac |
30 | (case m in m) echo ok-sub3;; esac) | 30 | (case m in m) echo OK_sub3;; esac) |
31 | (case m in (m) echo ok-sub4;; esac) | 31 | (case m in (m) echo OK_sub4;; esac) |
32 | ( | 32 | ( |
33 | case m in m) echo ok-sub5;; esac | 33 | case m in m) echo OK_sub5;; esac |
34 | ) | 34 | ) |
35 | ( | 35 | ( |
36 | case m in (m) echo ok-sub6;; esac | 36 | case m in (m) echo OK_sub6;; esac |
37 | ) | 37 | ) |
38 | (case esac in "esac") echo OK_esac1;; esac) | ||
39 | |||
40 | echo Done | ||
diff --git a/shell/hush_test/hush-vars/unset.right b/shell/hush_test/hush-vars/unset.right index 0da0e5736..1fbe76a73 100644 --- a/shell/hush_test/hush-vars/unset.right +++ b/shell/hush_test/hush-vars/unset.right | |||
@@ -1,5 +1,5 @@ | |||
1 | 0 | 1 | 0 |
2 | unset: invalid option -- 'm' | 2 | unset: invalid option -- m |
3 | 1 | 3 | 1 |
4 | 0 | 4 | 0 |
5 | ___ | 5 | ___ |