aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-05 20:29:59 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-05 20:29:59 +0000
commitff182a3d68462cb7ec38affa1afb04a06031862f (patch)
treede807b96e14cf7125843f91a5d6c3f72d41deb69 /shell
parentafdcd12ed71abdeab16961a0308c84f7147b66b2 (diff)
downloadbusybox-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.c42
-rw-r--r--shell/hush_test/hush-misc/empty_for2.right4
-rwxr-xr-xshell/hush_test/hush-misc/empty_for2.tests6
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 */
509static void syntax_lineno(int line) 509static 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 @@
1PARAM:abc
2PARAM:d e
3PARAM:123
4OK: 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 @@
1if test $# = 0; then
2 exec "$THIS_SH" $0 abc "d e" 123
3fi
4false
5for v; do echo "PARAM:$v"; done
6echo OK: $?