hush: support "for v; do ... done" syntax (implied 'in "$@"')
This commit is contained in:
parent
afdcd12ed7
commit
ff182a3d68
36
shell/hush.c
36
shell/hush.c
@ -508,7 +508,7 @@ static void syntax(const char *msg)
|
||||
/* Debug */
|
||||
static void syntax_lineno(int line)
|
||||
{
|
||||
void (*fp)(const char *s, ...);
|
||||
void FAST_FUNC (*fp)(const char *s, ...);
|
||||
|
||||
fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
|
||||
fp("syntax error hush.c:%d", line);
|
||||
@ -2026,11 +2026,12 @@ static int run_list(struct pipe *pi)
|
||||
debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
|
||||
return 1;
|
||||
}
|
||||
if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
|
||||
|| (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN)
|
||||
if (/* Extra statement after IN: "for a in a b; echo Hi; do ...; done" ? */
|
||||
(rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
|
||||
/* FOR not followed by IN or DO ("for var; do..." case)? */
|
||||
|| (rpipe->res_word == RES_FOR && (rpipe->next->res_word != RES_IN && rpipe->next->res_word != RES_DO))
|
||||
) {
|
||||
/* TODO: what is tested in the first condition? */
|
||||
syntax("malformed for"); /* 2nd condition: FOR not followed by IN */
|
||||
syntax("malformed for");
|
||||
debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
|
||||
return 1;
|
||||
}
|
||||
@ -2116,12 +2117,25 @@ static int run_list(struct pipe *pi)
|
||||
if (rword == RES_FOR && pi->num_progs) {
|
||||
if (!for_lcur) {
|
||||
/* first loop through for */
|
||||
|
||||
static const char encoded_dollar_at[] ALIGN1 = {
|
||||
SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0'
|
||||
}; /* encoded representation of "$@" */
|
||||
static const char *const encoded_dollar_at_argv[] = {
|
||||
encoded_dollar_at, NULL
|
||||
}; /* argv list with one element: "$@" */
|
||||
char **vals;
|
||||
|
||||
vals = (char**)encoded_dollar_at_argv;
|
||||
if (rpipe->next->res_word == RES_IN) {
|
||||
/* if no variable values after "in" we skip "for" */
|
||||
if (!pi->next->progs->argv)
|
||||
continue;
|
||||
vals = pi->next->progs->argv;
|
||||
} /* else: "for var; do..." -> assume "$@" list */
|
||||
/* create list of variable values */
|
||||
debug_print_strings("for_list made from", pi->next->progs->argv);
|
||||
for_list = expand_strvec_to_strvec(pi->next->progs->argv);
|
||||
debug_print_strings("for_list made from", vals);
|
||||
for_list = expand_strvec_to_strvec(vals);
|
||||
debug_print_strings("for_list", for_list);
|
||||
for_lcur = for_list;
|
||||
for_varname = pi->progs->argv[0];
|
||||
@ -2707,7 +2721,7 @@ static void unset_local_var(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
/* the src parameter allows us to peek forward to a possible &n syntax
|
||||
/* The src parameter allows us to peek forward to a possible &n syntax
|
||||
* for file descriptor duplication, e.g., "2>&1".
|
||||
* Return code is 0 normally, 1 if a syntax error is detected in src.
|
||||
* Resource errors (in xmalloc) cause the process to exit */
|
||||
@ -2824,7 +2838,7 @@ static int reserved_word(const o_string *word, struct p_context *ctx)
|
||||
{ "fi", RES_FI, FLAG_END },
|
||||
#endif
|
||||
#if ENABLE_HUSH_LOOPS
|
||||
{ "for", RES_FOR, FLAG_IN | FLAG_START },
|
||||
{ "for", RES_FOR, FLAG_IN | FLAG_DO | FLAG_START },
|
||||
{ "while", RES_WHILE, FLAG_DO | FLAG_START },
|
||||
{ "until", RES_UNTIL, FLAG_DO | FLAG_START },
|
||||
{ "in", RES_IN, FLAG_DO },
|
||||
@ -2936,12 +2950,12 @@ static int done_word(o_string *word, struct p_context *ctx)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (word->nonnull /* word had "xx" or 'xx' at least as part of it */
|
||||
if (word->nonnull /* 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)
|
||||
/* (otherwise it's "abc".... and is already safe) */
|
||||
) {
|
||||
/* but exclude "$@"! it expands to no word despite "" */
|
||||
/* but exclude "$@" - it expands to no word despite "" */
|
||||
char *p = word->data;
|
||||
while (p[0] == SPECIAL_VAR_SYMBOL
|
||||
&& (p[1] & 0x7f) == '@'
|
||||
|
4
shell/hush_test/hush-misc/empty_for2.right
Normal file
4
shell/hush_test/hush-misc/empty_for2.right
Normal file
@ -0,0 +1,4 @@
|
||||
PARAM:abc
|
||||
PARAM:d e
|
||||
PARAM:123
|
||||
OK: 0
|
6
shell/hush_test/hush-misc/empty_for2.tests
Executable file
6
shell/hush_test/hush-misc/empty_for2.tests
Executable file
@ -0,0 +1,6 @@
|
||||
if test $# = 0; then
|
||||
exec "$THIS_SH" $0 abc "d e" 123
|
||||
fi
|
||||
false
|
||||
for v; do echo "PARAM:$v"; done
|
||||
echo OK: $?
|
Loading…
Reference in New Issue
Block a user