diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-05 20:29:59 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-05 20:29:59 +0000 |
commit | ff182a3d68462cb7ec38affa1afb04a06031862f (patch) | |
tree | de807b96e14cf7125843f91a5d6c3f72d41deb69 /shell | |
parent | afdcd12ed71abdeab16961a0308c84f7147b66b2 (diff) | |
download | busybox-w32-ff182a3d68462cb7ec38affa1afb04a06031862f.tar.gz busybox-w32-ff182a3d68462cb7ec38affa1afb04a06031862f.tar.bz2 busybox-w32-ff182a3d68462cb7ec38affa1afb04a06031862f.zip |
hush: support "for v; do ... done" syntax (implied 'in "$@"')
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 42 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/empty_for2.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/empty_for2.tests | 6 |
3 files changed, 38 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c index 2c1d31c6d..f38f3752b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -508,7 +508,7 @@ static void syntax(const char *msg) | |||
508 | /* Debug */ | 508 | /* Debug */ |
509 | static void syntax_lineno(int line) | 509 | static void syntax_lineno(int line) |
510 | { | 510 | { |
511 | void (*fp)(const char *s, ...); | 511 | void FAST_FUNC (*fp)(const char *s, ...); |
512 | 512 | ||
513 | fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); | 513 | fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die); |
514 | fp("syntax error hush.c:%d", line); | 514 | fp("syntax error hush.c:%d", line); |
@@ -2026,11 +2026,12 @@ static int run_list(struct pipe *pi) | |||
2026 | debug_printf_exec("run_list lvl %d return 1\n", run_list_level); | 2026 | debug_printf_exec("run_list lvl %d return 1\n", run_list_level); |
2027 | return 1; | 2027 | return 1; |
2028 | } | 2028 | } |
2029 | if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) | 2029 | if (/* Extra statement after IN: "for a in a b; echo Hi; do ...; done" ? */ |
2030 | || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) | 2030 | (rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) |
2031 | /* FOR not followed by IN or DO ("for var; do..." case)? */ | ||
2032 | || (rpipe->res_word == RES_FOR && (rpipe->next->res_word != RES_IN && rpipe->next->res_word != RES_DO)) | ||
2031 | ) { | 2033 | ) { |
2032 | /* TODO: what is tested in the first condition? */ | 2034 | syntax("malformed for"); |
2033 | syntax("malformed for"); /* 2nd condition: FOR not followed by IN */ | ||
2034 | debug_printf_exec("run_list lvl %d return 1\n", run_list_level); | 2035 | debug_printf_exec("run_list lvl %d return 1\n", run_list_level); |
2035 | return 1; | 2036 | return 1; |
2036 | } | 2037 | } |
@@ -2116,12 +2117,25 @@ static int run_list(struct pipe *pi) | |||
2116 | if (rword == RES_FOR && pi->num_progs) { | 2117 | if (rword == RES_FOR && pi->num_progs) { |
2117 | if (!for_lcur) { | 2118 | if (!for_lcur) { |
2118 | /* first loop through for */ | 2119 | /* first loop through for */ |
2119 | /* if no variable values after "in" we skip "for" */ | 2120 | |
2120 | if (!pi->next->progs->argv) | 2121 | static const char encoded_dollar_at[] ALIGN1 = { |
2121 | continue; | 2122 | SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0' |
2123 | }; /* encoded representation of "$@" */ | ||
2124 | static const char *const encoded_dollar_at_argv[] = { | ||
2125 | encoded_dollar_at, NULL | ||
2126 | }; /* argv list with one element: "$@" */ | ||
2127 | char **vals; | ||
2128 | |||
2129 | vals = (char**)encoded_dollar_at_argv; | ||
2130 | if (rpipe->next->res_word == RES_IN) { | ||
2131 | /* if no variable values after "in" we skip "for" */ | ||
2132 | if (!pi->next->progs->argv) | ||
2133 | continue; | ||
2134 | vals = pi->next->progs->argv; | ||
2135 | } /* else: "for var; do..." -> assume "$@" list */ | ||
2122 | /* create list of variable values */ | 2136 | /* create list of variable values */ |
2123 | debug_print_strings("for_list made from", pi->next->progs->argv); | 2137 | debug_print_strings("for_list made from", vals); |
2124 | for_list = expand_strvec_to_strvec(pi->next->progs->argv); | 2138 | for_list = expand_strvec_to_strvec(vals); |
2125 | debug_print_strings("for_list", for_list); | 2139 | debug_print_strings("for_list", for_list); |
2126 | for_lcur = for_list; | 2140 | for_lcur = for_list; |
2127 | for_varname = pi->progs->argv[0]; | 2141 | for_varname = pi->progs->argv[0]; |
@@ -2707,7 +2721,7 @@ static void unset_local_var(const char *name) | |||
2707 | } | 2721 | } |
2708 | } | 2722 | } |
2709 | 2723 | ||
2710 | /* the src parameter allows us to peek forward to a possible &n syntax | 2724 | /* The src parameter allows us to peek forward to a possible &n syntax |
2711 | * for file descriptor duplication, e.g., "2>&1". | 2725 | * for file descriptor duplication, e.g., "2>&1". |
2712 | * Return code is 0 normally, 1 if a syntax error is detected in src. | 2726 | * Return code is 0 normally, 1 if a syntax error is detected in src. |
2713 | * Resource errors (in xmalloc) cause the process to exit */ | 2727 | * 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) | |||
2824 | { "fi", RES_FI, FLAG_END }, | 2838 | { "fi", RES_FI, FLAG_END }, |
2825 | #endif | 2839 | #endif |
2826 | #if ENABLE_HUSH_LOOPS | 2840 | #if ENABLE_HUSH_LOOPS |
2827 | { "for", RES_FOR, FLAG_IN | FLAG_START }, | 2841 | { "for", RES_FOR, FLAG_IN | FLAG_DO | FLAG_START }, |
2828 | { "while", RES_WHILE, FLAG_DO | FLAG_START }, | 2842 | { "while", RES_WHILE, FLAG_DO | FLAG_START }, |
2829 | { "until", RES_UNTIL, FLAG_DO | FLAG_START }, | 2843 | { "until", RES_UNTIL, FLAG_DO | FLAG_START }, |
2830 | { "in", RES_IN, FLAG_DO }, | 2844 | { "in", RES_IN, FLAG_DO }, |
@@ -2936,12 +2950,12 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
2936 | } | 2950 | } |
2937 | } | 2951 | } |
2938 | #endif | 2952 | #endif |
2939 | if (word->nonnull /* word had "xx" or 'xx' at least as part of it */ | 2953 | if (word->nonnull /* word had "xx" or 'xx' at least as part of it. */ |
2940 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ | 2954 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ |
2941 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) | 2955 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) |
2942 | /* (otherwise it's "abc".... and is already safe) */ | 2956 | /* (otherwise it's "abc".... and is already safe) */ |
2943 | ) { | 2957 | ) { |
2944 | /* but exclude "$@"! it expands to no word despite "" */ | 2958 | /* but exclude "$@" - it expands to no word despite "" */ |
2945 | char *p = word->data; | 2959 | char *p = word->data; |
2946 | while (p[0] == SPECIAL_VAR_SYMBOL | 2960 | while (p[0] == SPECIAL_VAR_SYMBOL |
2947 | && (p[1] & 0x7f) == '@' | 2961 | && (p[1] & 0x7f) == '@' |
diff --git a/shell/hush_test/hush-misc/empty_for2.right b/shell/hush_test/hush-misc/empty_for2.right new file mode 100644 index 000000000..1acee9eb8 --- /dev/null +++ b/shell/hush_test/hush-misc/empty_for2.right | |||
@@ -0,0 +1,4 @@ | |||
1 | PARAM:abc | ||
2 | PARAM:d e | ||
3 | PARAM:123 | ||
4 | OK: 0 | ||
diff --git a/shell/hush_test/hush-misc/empty_for2.tests b/shell/hush_test/hush-misc/empty_for2.tests new file mode 100755 index 000000000..2b12ec2c1 --- /dev/null +++ b/shell/hush_test/hush-misc/empty_for2.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | if test $# = 0; then | ||
2 | exec "$THIS_SH" $0 abc "d e" 123 | ||
3 | fi | ||
4 | false | ||
5 | for v; do echo "PARAM:$v"; done | ||
6 | echo OK: $? | ||