diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-16 10:59:40 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-16 10:59:40 +0000 |
commit | bb929517a86092481ed8547e9f247c1b58bc4745 (patch) | |
tree | 61113710afec0eb112df4b6854c5ec6d2f9662a3 /shell | |
parent | 74a931ac9ea807d14a44baf3fdb957bc58db14c6 (diff) | |
download | busybox-w32-bb929517a86092481ed8547e9f247c1b58bc4745.tar.gz busybox-w32-bb929517a86092481ed8547e9f247c1b58bc4745.tar.bz2 busybox-w32-bb929517a86092481ed8547e9f247c1b58bc4745.zip |
hush: fix "if { echo foo; } then { echo bar; } fi" parsing
function old new delta
done_word 728 793 +65
parse_stream 2084 2098 +14
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 43 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/groups_and_keywords1.right | 11 | ||||
-rwxr-xr-x | shell/hush_test/hush-parsing/groups_and_keywords1.tests | 10 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/param_glob.tests | 2 |
4 files changed, 48 insertions, 18 deletions
diff --git a/shell/hush.c b/shell/hush.c index a5d5741da..21cea32a1 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -4154,6 +4154,8 @@ static const struct reserved_combo* match_reserved_word(o_string *word) | |||
4154 | } | 4154 | } |
4155 | return NULL; | 4155 | return NULL; |
4156 | } | 4156 | } |
4157 | /* Return 0: not a keyword, 1: keyword | ||
4158 | */ | ||
4157 | static int reserved_word(o_string *word, struct parse_context *ctx) | 4159 | static int reserved_word(o_string *word, struct parse_context *ctx) |
4158 | { | 4160 | { |
4159 | #if ENABLE_HUSH_CASE | 4161 | #if ENABLE_HUSH_CASE |
@@ -4163,6 +4165,8 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
4163 | #endif | 4165 | #endif |
4164 | const struct reserved_combo *r; | 4166 | const struct reserved_combo *r; |
4165 | 4167 | ||
4168 | if (word->o_quoted) | ||
4169 | return 0; | ||
4166 | r = match_reserved_word(word); | 4170 | r = match_reserved_word(word); |
4167 | if (!r) | 4171 | if (!r) |
4168 | return 0; | 4172 | return 0; |
@@ -4177,13 +4181,14 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
4177 | if (r->flag == 0) { /* '!' */ | 4181 | if (r->flag == 0) { /* '!' */ |
4178 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ | 4182 | if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ |
4179 | syntax_error("! ! command"); | 4183 | syntax_error("! ! command"); |
4180 | IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) | 4184 | ctx->ctx_res_w = RES_SNTX; |
4181 | } | 4185 | } |
4182 | ctx->ctx_inverted = 1; | 4186 | ctx->ctx_inverted = 1; |
4183 | return 1; | 4187 | return 1; |
4184 | } | 4188 | } |
4185 | if (r->flag & FLAG_START) { | 4189 | if (r->flag & FLAG_START) { |
4186 | struct parse_context *old; | 4190 | struct parse_context *old; |
4191 | |||
4187 | old = xmalloc(sizeof(*old)); | 4192 | old = xmalloc(sizeof(*old)); |
4188 | debug_printf_parse("push stack %p\n", old); | 4193 | debug_printf_parse("push stack %p\n", old); |
4189 | *old = *ctx; /* physical copy */ | 4194 | *old = *ctx; /* physical copy */ |
@@ -4193,11 +4198,21 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
4193 | syntax_error_at(word->data); | 4198 | syntax_error_at(word->data); |
4194 | ctx->ctx_res_w = RES_SNTX; | 4199 | ctx->ctx_res_w = RES_SNTX; |
4195 | return 1; | 4200 | return 1; |
4201 | } else { | ||
4202 | /* "{...} fi" is ok. "{...} if" is not | ||
4203 | * Example: | ||
4204 | * if { echo foo; } then { echo bar; } fi */ | ||
4205 | if (ctx->command->group) | ||
4206 | done_pipe(ctx, PIPE_SEQ); | ||
4196 | } | 4207 | } |
4208 | |||
4197 | ctx->ctx_res_w = r->res; | 4209 | ctx->ctx_res_w = r->res; |
4198 | ctx->old_flag = r->flag; | 4210 | ctx->old_flag = r->flag; |
4211 | word->o_assignment = r->assignment_flag; | ||
4212 | |||
4199 | if (ctx->old_flag & FLAG_END) { | 4213 | if (ctx->old_flag & FLAG_END) { |
4200 | struct parse_context *old; | 4214 | struct parse_context *old; |
4215 | |||
4201 | done_pipe(ctx, PIPE_SEQ); | 4216 | done_pipe(ctx, PIPE_SEQ); |
4202 | debug_printf_parse("pop stack %p\n", ctx->stack); | 4217 | debug_printf_parse("pop stack %p\n", ctx->stack); |
4203 | old = ctx->stack; | 4218 | old = ctx->stack; |
@@ -4213,7 +4228,6 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
4213 | *ctx = *old; /* physical copy */ | 4228 | *ctx = *old; /* physical copy */ |
4214 | free(old); | 4229 | free(old); |
4215 | } | 4230 | } |
4216 | word->o_assignment = r->assignment_flag; | ||
4217 | return 1; | 4231 | return 1; |
4218 | } | 4232 | } |
4219 | #endif | 4233 | #endif |
@@ -4273,19 +4287,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4273 | word->o_assignment = MAYBE_ASSIGNMENT; | 4287 | word->o_assignment = MAYBE_ASSIGNMENT; |
4274 | } | 4288 | } |
4275 | 4289 | ||
4276 | if (command->group) { | ||
4277 | /* "{ echo foo; } echo bar" - bad */ | ||
4278 | /* NB: bash allows e.g.: | ||
4279 | * if true; then { echo foo; } fi | ||
4280 | * while if false; then false; fi do break; done | ||
4281 | * and disallows: | ||
4282 | * while if false; then false; fi; do; break; done | ||
4283 | * TODO? */ | ||
4284 | syntax_error_at(word->data); | ||
4285 | debug_printf_parse("done_word return 1: syntax error, " | ||
4286 | "groups and arglists don't mix\n"); | ||
4287 | return 1; | ||
4288 | } | ||
4289 | #if HAS_KEYWORDS | 4290 | #if HAS_KEYWORDS |
4290 | # if ENABLE_HUSH_CASE | 4291 | # if ENABLE_HUSH_CASE |
4291 | if (ctx->ctx_dsemicolon | 4292 | if (ctx->ctx_dsemicolon |
@@ -4311,6 +4312,13 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4311 | } | 4312 | } |
4312 | } | 4313 | } |
4313 | #endif | 4314 | #endif |
4315 | if (command->group) { | ||
4316 | /* "{ echo foo; } echo bar" - bad */ | ||
4317 | syntax_error_at(word->data); | ||
4318 | debug_printf_parse("done_word return 1: syntax error, " | ||
4319 | "groups and arglists don't mix\n"); | ||
4320 | return 1; | ||
4321 | } | ||
4314 | if (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */ | 4322 | if (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */ |
4315 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ | 4323 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ |
4316 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) | 4324 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) |
@@ -4720,7 +4728,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4720 | #if ENABLE_HUSH_FUNCTIONS | 4728 | #if ENABLE_HUSH_FUNCTIONS |
4721 | if (ch == '(' && !dest->o_quoted) { | 4729 | if (ch == '(' && !dest->o_quoted) { |
4722 | if (dest->length) | 4730 | if (dest->length) |
4723 | done_word(dest, ctx); | 4731 | if (done_word(dest, ctx)) |
4732 | return 1; | ||
4724 | if (!command->argv) | 4733 | if (!command->argv) |
4725 | goto skip; /* (... */ | 4734 | goto skip; /* (... */ |
4726 | if (command->argv[1]) { /* word word ... (... */ | 4735 | if (command->argv[1]) { /* word word ... (... */ |
@@ -4778,10 +4787,10 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4778 | #endif | 4787 | #endif |
4779 | /* empty ()/{} or parse error? */ | 4788 | /* empty ()/{} or parse error? */ |
4780 | if (!pipe_list || pipe_list == ERR_PTR) { | 4789 | if (!pipe_list || pipe_list == ERR_PTR) { |
4790 | /* parse_stream already emitted error msg */ | ||
4781 | #if !BB_MMU | 4791 | #if !BB_MMU |
4782 | free(as_string); | 4792 | free(as_string); |
4783 | #endif | 4793 | #endif |
4784 | syntax_error(NULL); | ||
4785 | debug_printf_parse("parse_group return 1: " | 4794 | debug_printf_parse("parse_group return 1: " |
4786 | "parse_stream returned %p\n", pipe_list); | 4795 | "parse_stream returned %p\n", pipe_list); |
4787 | return 1; | 4796 | return 1; |
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords1.right b/shell/hush_test/hush-parsing/groups_and_keywords1.right new file mode 100644 index 000000000..4c46650dc --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords1.right | |||
@@ -0,0 +1,11 @@ | |||
1 | Semicolons after } can be omitted 1: | ||
2 | foo | ||
3 | bar | ||
4 | Semicolons after } can be omitted 2: | ||
5 | foo | ||
6 | bar | ||
7 | Semicolons after fi can be omitted: | ||
8 | foo | ||
9 | bar | ||
10 | baz | ||
11 | Done:0 | ||
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords1.tests b/shell/hush_test/hush-parsing/groups_and_keywords1.tests new file mode 100755 index 000000000..01944d714 --- /dev/null +++ b/shell/hush_test/hush-parsing/groups_and_keywords1.tests | |||
@@ -0,0 +1,10 @@ | |||
1 | echo "Semicolons after } can be omitted 1:" | ||
2 | if { echo foo; } then { echo bar; } fi | ||
3 | |||
4 | echo "Semicolons after } can be omitted 2:" | ||
5 | while { echo foo; } do { echo bar; break; } done | ||
6 | |||
7 | echo "Semicolons after fi can be omitted:" | ||
8 | while if echo foo; then echo bar; fi do echo baz; break; done | ||
9 | |||
10 | echo Done:$? | ||
diff --git a/shell/hush_test/hush-vars/param_glob.tests b/shell/hush_test/hush-vars/param_glob.tests index 801d58ee7..0173fd771 100755 --- a/shell/hush_test/hush-vars/param_glob.tests +++ b/shell/hush_test/hush-vars/param_glob.tests | |||
@@ -1,5 +1,5 @@ | |||
1 | if test $# = 0; then | 1 | if test $# = 0; then |
2 | #BUG in builtin_exec! will glob param! | 2 | # UNFIXED BUG in builtin_exec! will glob param! |
3 | #exec "$THIS_SH" "$0" 'param_glob.t*' | 3 | #exec "$THIS_SH" "$0" 'param_glob.t*' |
4 | "$THIS_SH" "$0" 'param_glob.t*' | 4 | "$THIS_SH" "$0" 'param_glob.t*' |
5 | exit | 5 | exit |