mirror of
https://github.com/sheumann/hush.git
synced 2024-12-28 07:30:23 +00:00
hush: fix "if { echo foo; } then { echo bar; } fi" parsing
function old new delta done_word 728 793 +65 parse_stream 2084 2098 +14
This commit is contained in:
parent
74a931ac9e
commit
bb929517a8
43
shell/hush.c
43
shell/hush.c
@ -4154,6 +4154,8 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/* Return 0: not a keyword, 1: keyword
|
||||||
|
*/
|
||||||
static int reserved_word(o_string *word, struct parse_context *ctx)
|
static int reserved_word(o_string *word, struct parse_context *ctx)
|
||||||
{
|
{
|
||||||
#if ENABLE_HUSH_CASE
|
#if ENABLE_HUSH_CASE
|
||||||
@ -4163,6 +4165,8 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
#endif
|
#endif
|
||||||
const struct reserved_combo *r;
|
const struct reserved_combo *r;
|
||||||
|
|
||||||
|
if (word->o_quoted)
|
||||||
|
return 0;
|
||||||
r = match_reserved_word(word);
|
r = match_reserved_word(word);
|
||||||
if (!r)
|
if (!r)
|
||||||
return 0;
|
return 0;
|
||||||
@ -4177,13 +4181,14 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
if (r->flag == 0) { /* '!' */
|
if (r->flag == 0) { /* '!' */
|
||||||
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
|
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
|
||||||
syntax_error("! ! command");
|
syntax_error("! ! command");
|
||||||
IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
|
ctx->ctx_res_w = RES_SNTX;
|
||||||
}
|
}
|
||||||
ctx->ctx_inverted = 1;
|
ctx->ctx_inverted = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (r->flag & FLAG_START) {
|
if (r->flag & FLAG_START) {
|
||||||
struct parse_context *old;
|
struct parse_context *old;
|
||||||
|
|
||||||
old = xmalloc(sizeof(*old));
|
old = xmalloc(sizeof(*old));
|
||||||
debug_printf_parse("push stack %p\n", old);
|
debug_printf_parse("push stack %p\n", old);
|
||||||
*old = *ctx; /* physical copy */
|
*old = *ctx; /* physical copy */
|
||||||
@ -4193,11 +4198,21 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
syntax_error_at(word->data);
|
syntax_error_at(word->data);
|
||||||
ctx->ctx_res_w = RES_SNTX;
|
ctx->ctx_res_w = RES_SNTX;
|
||||||
return 1;
|
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->ctx_res_w = r->res;
|
||||||
ctx->old_flag = r->flag;
|
ctx->old_flag = r->flag;
|
||||||
|
word->o_assignment = r->assignment_flag;
|
||||||
|
|
||||||
if (ctx->old_flag & FLAG_END) {
|
if (ctx->old_flag & FLAG_END) {
|
||||||
struct parse_context *old;
|
struct parse_context *old;
|
||||||
|
|
||||||
done_pipe(ctx, PIPE_SEQ);
|
done_pipe(ctx, PIPE_SEQ);
|
||||||
debug_printf_parse("pop stack %p\n", ctx->stack);
|
debug_printf_parse("pop stack %p\n", ctx->stack);
|
||||||
old = ctx->stack;
|
old = ctx->stack;
|
||||||
@ -4213,7 +4228,6 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
|
|||||||
*ctx = *old; /* physical copy */
|
*ctx = *old; /* physical copy */
|
||||||
free(old);
|
free(old);
|
||||||
}
|
}
|
||||||
word->o_assignment = r->assignment_flag;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -4273,19 +4287,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
|
|||||||
word->o_assignment = MAYBE_ASSIGNMENT;
|
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 HAS_KEYWORDS
|
||||||
# if ENABLE_HUSH_CASE
|
# if ENABLE_HUSH_CASE
|
||||||
if (ctx->ctx_dsemicolon
|
if (ctx->ctx_dsemicolon
|
||||||
@ -4311,6 +4312,13 @@ static int done_word(o_string *word, struct parse_context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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. */
|
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`...): */
|
/* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
|
||||||
&& (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
|
&& (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 ENABLE_HUSH_FUNCTIONS
|
||||||
if (ch == '(' && !dest->o_quoted) {
|
if (ch == '(' && !dest->o_quoted) {
|
||||||
if (dest->length)
|
if (dest->length)
|
||||||
done_word(dest, ctx);
|
if (done_word(dest, ctx))
|
||||||
|
return 1;
|
||||||
if (!command->argv)
|
if (!command->argv)
|
||||||
goto skip; /* (... */
|
goto skip; /* (... */
|
||||||
if (command->argv[1]) { /* word word ... (... */
|
if (command->argv[1]) { /* word word ... (... */
|
||||||
@ -4778,10 +4787,10 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
|
|||||||
#endif
|
#endif
|
||||||
/* empty ()/{} or parse error? */
|
/* empty ()/{} or parse error? */
|
||||||
if (!pipe_list || pipe_list == ERR_PTR) {
|
if (!pipe_list || pipe_list == ERR_PTR) {
|
||||||
|
/* parse_stream already emitted error msg */
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
free(as_string);
|
free(as_string);
|
||||||
#endif
|
#endif
|
||||||
syntax_error(NULL);
|
|
||||||
debug_printf_parse("parse_group return 1: "
|
debug_printf_parse("parse_group return 1: "
|
||||||
"parse_stream returned %p\n", pipe_list);
|
"parse_stream returned %p\n", pipe_list);
|
||||||
return 1;
|
return 1;
|
||||||
|
11
shell/hush_test/hush-parsing/groups_and_keywords1.right
Normal file
11
shell/hush_test/hush-parsing/groups_and_keywords1.right
Normal file
@ -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
|
10
shell/hush_test/hush-parsing/groups_and_keywords1.tests
Executable file
10
shell/hush_test/hush-parsing/groups_and_keywords1.tests
Executable file
@ -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:$?
|
@ -1,5 +1,5 @@
|
|||||||
if test $# = 0; then
|
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*'
|
#exec "$THIS_SH" "$0" 'param_glob.t*'
|
||||||
"$THIS_SH" "$0" 'param_glob.t*'
|
"$THIS_SH" "$0" 'param_glob.t*'
|
||||||
exit
|
exit
|
||||||
|
Loading…
Reference in New Issue
Block a user