aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-03 03:19:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-03 03:19:15 +0000
commit3718168b87a5bf5009b90b1e1253bec2c7ce9edf (patch)
tree64037be3206c0ce3cb0c68c114828010cd3da367
parentf9f74293465e98f2af117a1821a8fbb97cdbc3ed (diff)
downloadbusybox-w32-3718168b87a5bf5009b90b1e1253bec2c7ce9edf.tar.gz
busybox-w32-3718168b87a5bf5009b90b1e1253bec2c7ce9edf.tar.bz2
busybox-w32-3718168b87a5bf5009b90b1e1253bec2c7ce9edf.zip
hush: fix bug with local environment vars in pipes; simplify parse_stream()
function old new delta parse_stream 1238 1218 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-20) Total: -20 bytes
-rw-r--r--shell/hush.c70
-rw-r--r--shell/hush_test/hush-vars/var_in_pipes.right6
-rwxr-xr-xshell/hush_test/hush-vars/var_in_pipes.tests7
3 files changed, 45 insertions, 38 deletions
diff --git a/shell/hush.c b/shell/hush.c
index d401948aa..e2259ce38 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1657,8 +1657,7 @@ static char **o_finalize_list(o_string *o, int n)
1657 1657
1658/* Expansion can recurse */ 1658/* Expansion can recurse */
1659#if ENABLE_HUSH_TICK 1659#if ENABLE_HUSH_TICK
1660static int process_command_subs(o_string *dest, 1660static int process_command_subs(o_string *dest, struct in_str *input);
1661 struct in_str *input, const char *subst_end);
1662#endif 1661#endif
1663static char *expand_string_to_string(const char *str); 1662static char *expand_string_to_string(const char *str);
1664static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); 1663static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
@@ -1814,7 +1813,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1814//TODO: can we just stuff it into "output" directly? 1813//TODO: can we just stuff it into "output" directly?
1815 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); 1814 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
1816 setup_string_in_str(&input, arg); 1815 setup_string_in_str(&input, arg);
1817 process_command_subs(&subst_result, &input, NULL); 1816 process_command_subs(&subst_result, &input);
1818 debug_printf_subst("SUBST RES '%s'\n", subst_result.data); 1817 debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
1819 val = subst_result.data; 1818 val = subst_result.data;
1820 goto store_val; 1819 goto store_val;
@@ -1971,7 +1970,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1971 } 1970 }
1972 } /* default: */ 1971 } /* default: */
1973 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ 1972 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */
1974
1975 if (val) { 1973 if (val) {
1976 o_addQstr(output, val, strlen(val)); 1974 o_addQstr(output, val, strlen(val));
1977 } 1975 }
@@ -2265,7 +2263,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignme
2265 if (argv_expanded) { 2263 if (argv_expanded) {
2266 argv = argv_expanded; 2264 argv = argv_expanded;
2267 } else { 2265 } else {
2268 argv = expand_strvec_to_strvec(argv); 2266 argv = expand_strvec_to_strvec(argv + assignment_cnt);
2269#if !BB_MMU 2267#if !BB_MMU
2270 nommu_save->argv = argv; 2268 nommu_save->argv = argv;
2271#endif 2269#endif
@@ -3628,7 +3626,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3628 ctx->ctx_dsemicolon = 0; 3626 ctx->ctx_dsemicolon = 0;
3629 } else 3627 } else
3630#endif 3628#endif
3631
3632 if (!command->argv /* if it's the first word... */ 3629 if (!command->argv /* if it's the first word... */
3633#if ENABLE_HUSH_LOOPS 3630#if ENABLE_HUSH_LOOPS
3634 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ 3631 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
@@ -3767,8 +3764,7 @@ static FILE *generate_stream_from_list(struct pipe *head)
3767 3764
3768/* Return code is exit status of the process that is run. */ 3765/* Return code is exit status of the process that is run. */
3769static int process_command_subs(o_string *dest, 3766static int process_command_subs(o_string *dest,
3770 struct in_str *input, 3767 struct in_str *input)
3771 const char *subst_end)
3772{ 3768{
3773 int retcode, ch, eol_cnt; 3769 int retcode, ch, eol_cnt;
3774 o_string result = NULL_O_STRING; 3770 o_string result = NULL_O_STRING;
@@ -3777,7 +3773,7 @@ static int process_command_subs(o_string *dest,
3777 struct in_str pipe_str; 3773 struct in_str pipe_str;
3778 3774
3779 /* Recursion to generate command */ 3775 /* Recursion to generate command */
3780 retcode = parse_stream(&result, &inner, input, subst_end); 3776 retcode = parse_stream(&result, &inner, input, NULL);
3781 if (retcode != 0) 3777 if (retcode != 0)
3782 return retcode; /* syntax error or EOF */ 3778 return retcode; /* syntax error or EOF */
3783 o_free(&result); 3779 o_free(&result);
@@ -4236,9 +4232,11 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4236 * A single-quote triggers a bypass of the main loop until its mate is 4232 * A single-quote triggers a bypass of the main loop until its mate is
4237 * found. When recursing, quote state is passed in via dest->o_escape. */ 4233 * found. When recursing, quote state is passed in via dest->o_escape. */
4238 4234
4239 debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); 4235 debug_printf_parse("parse_stream entered, end_trigger='%s' "
4240 initialize_context(ctx); 4236 "dest->o_assignment:%d\n", end_trigger, dest->o_assignment);
4241 4237
4238 dest->o_assignment = MAYBE_ASSIGNMENT;
4239 initialize_context(ctx);
4242 is_in_dquote = dest->o_escape; 4240 is_in_dquote = dest->o_escape;
4243 while (1) { 4241 while (1) {
4244 if (is_in_dquote) { 4242 if (is_in_dquote) {
@@ -4269,51 +4267,47 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4269 } 4267 }
4270 continue; 4268 continue;
4271 } 4269 }
4272 /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) 4270 /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
4273 */
4274 if (m == CHAR_IFS) { 4271 if (m == CHAR_IFS) {
4272 if (ch == EOF)
4273 goto ret_EOF;
4275 if (done_word(dest, ctx)) { 4274 if (done_word(dest, ctx)) {
4276 debug_printf_parse("parse_stream return 1: done_word!=0\n"); 4275 debug_printf_parse("parse_stream return 1: done_word!=0\n");
4277 return 1; 4276 return 1;
4278 } 4277 }
4279 if (ch == EOF) 4278 if (ch == '\n') {
4280 goto ret_EOF;
4281 /* If we aren't performing a substitution, treat
4282 * a newline as a command separator.
4283 * [why don't we handle it exactly like ';'? --vda] */
4284 if (end_trigger && ch == '\n') {
4285#if ENABLE_HUSH_CASE 4279#if ENABLE_HUSH_CASE
4286 /* "case ... in <newline> word) ..." - 4280 /* "case ... in <newline> word) ..." -
4287 * newlines are ignored (but ';' wouldn't be) */ 4281 * newlines are ignored (but ';' wouldn't be) */
4288 if (dest->length == 0 // && argv[0] == NULL 4282 if (ctx->command->argv == NULL
4289 && ctx->ctx_res_w == RES_MATCH 4283 && ctx->ctx_res_w == RES_MATCH
4290 ) { 4284 ) {
4291 continue; 4285 continue;
4292 } 4286 }
4293#endif 4287#endif
4288 /* Treat newline as a command separator.
4289 * [why don't we handle it exactly like ';'? --vda] */
4294 done_pipe(ctx, PIPE_SEQ); 4290 done_pipe(ctx, PIPE_SEQ);
4295 dest->o_assignment = MAYBE_ASSIGNMENT; 4291 dest->o_assignment = MAYBE_ASSIGNMENT;
4296 } 4292 }
4297 } 4293 }
4298 if (end_trigger) { 4294 if (end_trigger && strchr(end_trigger, ch)) {
4299 if (strchr(end_trigger, ch)) { 4295 /* Special case: (...word) makes last word terminate,
4300 /* Special case: (...word) makes last word terminate, 4296 * as if ';' is seen */
4301 * as if ';' is seen */ 4297 if (ch == ')') {
4302 if (ch == ')') { 4298 done_word(dest, ctx);
4303 done_word(dest, ctx);
4304//err chk? 4299//err chk?
4305 done_pipe(ctx, PIPE_SEQ); 4300 done_pipe(ctx, PIPE_SEQ);
4306 dest->o_assignment = MAYBE_ASSIGNMENT; 4301 dest->o_assignment = MAYBE_ASSIGNMENT;
4307 } 4302 }
4308 /* What do we check here? */ 4303 /* What do we check here? */
4309 if (!HAS_KEYWORDS 4304 if (!HAS_KEYWORDS
4310 IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) 4305 IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
4311 ) { 4306 ) {
4312 debug_printf_parse("parse_stream return 0: end_trigger char found\n"); 4307 debug_printf_parse("parse_stream return 0: end_trigger char found\n");
4313 /* this makes us return 0, not -1 */ 4308 /* this makes us return 0, not -1 */
4314 end_trigger = NULL; 4309 end_trigger = NULL;
4315 goto ret; 4310 goto ret;
4316 }
4317 } 4311 }
4318 } 4312 }
4319 if (m == CHAR_IFS) 4313 if (m == CHAR_IFS)
diff --git a/shell/hush_test/hush-vars/var_in_pipes.right b/shell/hush_test/hush-vars/var_in_pipes.right
new file mode 100644
index 000000000..faf65bed4
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_in_pipes.right
@@ -0,0 +1,6 @@
1b=1
2b=2
3b=3
4b=4
5b=5
6b=6
diff --git a/shell/hush_test/hush-vars/var_in_pipes.tests b/shell/hush_test/hush-vars/var_in_pipes.tests
new file mode 100755
index 000000000..3f8cd2729
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_in_pipes.tests
@@ -0,0 +1,7 @@
1b=1 env | grep ^b=
2true | b=2 env | grep ^b=
3a=1 true | b=3 env | grep ^b=
4
5(b=4 env) | grep ^b=
6(true | b=5 env) | grep ^b=
7(a=1 true | b=6 env) | grep ^b=