summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-16 10:59:40 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-16 10:59:40 +0000
commitbb929517a86092481ed8547e9f247c1b58bc4745 (patch)
tree61113710afec0eb112df4b6854c5ec6d2f9662a3 /shell
parent74a931ac9ea807d14a44baf3fdb957bc58db14c6 (diff)
downloadbusybox-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.c43
-rw-r--r--shell/hush_test/hush-parsing/groups_and_keywords1.right11
-rwxr-xr-xshell/hush_test/hush-parsing/groups_and_keywords1.tests10
-rwxr-xr-xshell/hush_test/hush-vars/param_glob.tests2
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 */
4157static int reserved_word(o_string *word, struct parse_context *ctx) 4159static 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 @@
1Semicolons after } can be omitted 1:
2foo
3bar
4Semicolons after } can be omitted 2:
5foo
6bar
7Semicolons after fi can be omitted:
8foo
9bar
10baz
11Done: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 @@
1echo "Semicolons after } can be omitted 1:"
2if { echo foo; } then { echo bar; } fi
3
4echo "Semicolons after } can be omitted 2:"
5while { echo foo; } do { echo bar; break; } done
6
7echo "Semicolons after fi can be omitted:"
8while if echo foo; then echo bar; fi do echo baz; break; done
9
10echo 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 @@
1if test $# = 0; then 1if 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