summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko2009-04-16 10:59:40 +0000
committerDenis Vlasenko2009-04-16 10:59:40 +0000
commitbb929517a86092481ed8547e9f247c1b58bc4745 (patch)
tree61113710afec0eb112df4b6854c5ec6d2f9662a3
parent74a931ac9ea807d14a44baf3fdb957bc58db14c6 (diff)
downloadbusybox-bb929517a86092481ed8547e9f247c1b58bc4745.zip
busybox-bb929517a86092481ed8547e9f247c1b58bc4745.tar.gz
hush: fix "if { echo foo; } then { echo bar; } fi" parsing
function old new delta done_word 728 793 +65 parse_stream 2084 2098 +14
-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 a5d5741..21cea32 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4154,6 +4154,8 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
}
return NULL;
}
+/* Return 0: not a keyword, 1: keyword
+ */
static int reserved_word(o_string *word, struct parse_context *ctx)
{
#if ENABLE_HUSH_CASE
@@ -4163,6 +4165,8 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
#endif
const struct reserved_combo *r;
+ if (word->o_quoted)
+ return 0;
r = match_reserved_word(word);
if (!r)
return 0;
@@ -4177,13 +4181,14 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
if (r->flag == 0) { /* '!' */
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
syntax_error("! ! command");
- IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
+ ctx->ctx_res_w = RES_SNTX;
}
ctx->ctx_inverted = 1;
return 1;
}
if (r->flag & FLAG_START) {
struct parse_context *old;
+
old = xmalloc(sizeof(*old));
debug_printf_parse("push stack %p\n", old);
*old = *ctx; /* physical copy */
@@ -4193,11 +4198,21 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
syntax_error_at(word->data);
ctx->ctx_res_w = RES_SNTX;
return 1;
+ } else {
+ /* "{...} fi" is ok. "{...} if" is not
+ * Example:
+ * if { echo foo; } then { echo bar; } fi */
+ if (ctx->command->group)
+ done_pipe(ctx, PIPE_SEQ);
}
+
ctx->ctx_res_w = r->res;
ctx->old_flag = r->flag;
+ word->o_assignment = r->assignment_flag;
+
if (ctx->old_flag & FLAG_END) {
struct parse_context *old;
+
done_pipe(ctx, PIPE_SEQ);
debug_printf_parse("pop stack %p\n", ctx->stack);
old = ctx->stack;
@@ -4213,7 +4228,6 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
*ctx = *old; /* physical copy */
free(old);
}
- word->o_assignment = r->assignment_flag;
return 1;
}
#endif
@@ -4273,19 +4287,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
word->o_assignment = MAYBE_ASSIGNMENT;
}
- if (command->group) {
- /* "{ echo foo; } echo bar" - bad */
- /* NB: bash allows e.g.:
- * if true; then { echo foo; } fi
- * while if false; then false; fi do break; done
- * and disallows:
- * while if false; then false; fi; do; break; done
- * TODO? */
- syntax_error_at(word->data);
- debug_printf_parse("done_word return 1: syntax error, "
- "groups and arglists don't mix\n");
- return 1;
- }
#if HAS_KEYWORDS
# if ENABLE_HUSH_CASE
if (ctx->ctx_dsemicolon
@@ -4311,6 +4312,13 @@ static int done_word(o_string *word, struct parse_context *ctx)
}
}
#endif
+ if (command->group) {
+ /* "{ echo foo; } echo bar" - bad */
+ syntax_error_at(word->data);
+ debug_printf_parse("done_word return 1: syntax error, "
+ "groups and arglists don't mix\n");
+ return 1;
+ }
if (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */
/* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
&& (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,
#if ENABLE_HUSH_FUNCTIONS
if (ch == '(' && !dest->o_quoted) {
if (dest->length)
- done_word(dest, ctx);
+ if (done_word(dest, ctx))
+ return 1;
if (!command->argv)
goto skip; /* (... */
if (command->argv[1]) { /* word word ... (... */
@@ -4778,10 +4787,10 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
#endif
/* empty ()/{} or parse error? */
if (!pipe_list || pipe_list == ERR_PTR) {
+ /* parse_stream already emitted error msg */
#if !BB_MMU
free(as_string);
#endif
- syntax_error(NULL);
debug_printf_parse("parse_group return 1: "
"parse_stream returned %p\n", pipe_list);
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 0000000..4c46650
--- /dev/null
+++ b/shell/hush_test/hush-parsing/groups_and_keywords1.right
@@ -0,0 +1,11 @@
+Semicolons after } can be omitted 1:
+foo
+bar
+Semicolons after } can be omitted 2:
+foo
+bar
+Semicolons after fi can be omitted:
+foo
+bar
+baz
+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 0000000..01944d7
--- /dev/null
+++ b/shell/hush_test/hush-parsing/groups_and_keywords1.tests
@@ -0,0 +1,10 @@
+echo "Semicolons after } can be omitted 1:"
+if { echo foo; } then { echo bar; } fi
+
+echo "Semicolons after } can be omitted 2:"
+while { echo foo; } do { echo bar; break; } done
+
+echo "Semicolons after fi can be omitted:"
+while if echo foo; then echo bar; fi do echo baz; break; done
+
+echo Done:$?
diff --git a/shell/hush_test/hush-vars/param_glob.tests b/shell/hush_test/hush-vars/param_glob.tests
index 801d58e..0173fd7 100755
--- a/shell/hush_test/hush-vars/param_glob.tests
+++ b/shell/hush_test/hush-vars/param_glob.tests
@@ -1,5 +1,5 @@
if test $# = 0; then
- #BUG in builtin_exec! will glob param!
+ # UNFIXED BUG in builtin_exec! will glob param!
#exec "$THIS_SH" "$0" 'param_glob.t*'
"$THIS_SH" "$0" 'param_glob.t*'
exit