hush: support "for v; do ... done" syntax (implied 'in "$@"')
This commit is contained in:
parent
afdcd12ed7
commit
ff182a3d68
42
shell/hush.c
42
shell/hush.c
@ -508,7 +508,7 @@ static void syntax(const char *msg)
|
|||||||
/* Debug */
|
/* Debug */
|
||||||
static void syntax_lineno(int line)
|
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 = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
|
||||||
fp("syntax error hush.c:%d", line);
|
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);
|
debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
|
if (/* Extra statement after IN: "for a in a b; echo Hi; do ...; done" ? */
|
||||||
|| (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN)
|
(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");
|
||||||
syntax("malformed for"); /* 2nd condition: FOR not followed by IN */
|
|
||||||
debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
|
debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -2116,12 +2117,25 @@ static int run_list(struct pipe *pi)
|
|||||||
if (rword == RES_FOR && pi->num_progs) {
|
if (rword == RES_FOR && pi->num_progs) {
|
||||||
if (!for_lcur) {
|
if (!for_lcur) {
|
||||||
/* first loop through for */
|
/* first loop through for */
|
||||||
/* if no variable values after "in" we skip "for" */
|
|
||||||
if (!pi->next->progs->argv)
|
static const char encoded_dollar_at[] ALIGN1 = {
|
||||||
continue;
|
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 */
|
/* create list of variable values */
|
||||||
debug_print_strings("for_list made from", pi->next->progs->argv);
|
debug_print_strings("for_list made from", vals);
|
||||||
for_list = expand_strvec_to_strvec(pi->next->progs->argv);
|
for_list = expand_strvec_to_strvec(vals);
|
||||||
debug_print_strings("for_list", for_list);
|
debug_print_strings("for_list", for_list);
|
||||||
for_lcur = for_list;
|
for_lcur = for_list;
|
||||||
for_varname = pi->progs->argv[0];
|
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".
|
* for file descriptor duplication, e.g., "2>&1".
|
||||||
* Return code is 0 normally, 1 if a syntax error is detected in src.
|
* Return code is 0 normally, 1 if a syntax error is detected in src.
|
||||||
* Resource errors (in xmalloc) cause the process to exit */
|
* 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 },
|
{ "fi", RES_FI, FLAG_END },
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_HUSH_LOOPS
|
#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 },
|
{ "while", RES_WHILE, FLAG_DO | FLAG_START },
|
||||||
{ "until", RES_UNTIL, FLAG_DO | FLAG_START },
|
{ "until", RES_UNTIL, FLAG_DO | FLAG_START },
|
||||||
{ "in", RES_IN, FLAG_DO },
|
{ "in", RES_IN, FLAG_DO },
|
||||||
@ -2936,12 +2950,12 @@ static int done_word(o_string *word, struct p_context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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`...): */
|
/* 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)
|
||||||
/* (otherwise it's "abc".... and is already safe) */
|
/* (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;
|
char *p = word->data;
|
||||||
while (p[0] == SPECIAL_VAR_SYMBOL
|
while (p[0] == SPECIAL_VAR_SYMBOL
|
||||||
&& (p[1] & 0x7f) == '@'
|
&& (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