summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 2c1d31c..f38f375 100644
--- a/shell/hush.c
+++ b/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 */
- /* if no variable values after "in" we skip "for" */
- if (!pi->next->progs->argv)
- continue;
+
+ 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) == '@'