From 3718168b87a5bf5009b90b1e1253bec2c7ce9edf Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 3 Apr 2009 03:19:15 +0000 Subject: [PATCH] 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 --- shell/hush.c | 70 +++++++++----------- shell/hush_test/hush-vars/var_in_pipes.right | 6 ++ shell/hush_test/hush-vars/var_in_pipes.tests | 7 ++ 3 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 shell/hush_test/hush-vars/var_in_pipes.right create mode 100755 shell/hush_test/hush-vars/var_in_pipes.tests 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) /* Expansion can recurse */ #if ENABLE_HUSH_TICK -static int process_command_subs(o_string *dest, - struct in_str *input, const char *subst_end); +static int process_command_subs(o_string *dest, struct in_str *input); #endif static char *expand_string_to_string(const char *str); static 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) //TODO: can we just stuff it into "output" directly? debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); setup_string_in_str(&input, arg); - process_command_subs(&subst_result, &input, NULL); + process_command_subs(&subst_result, &input); debug_printf_subst("SUBST RES '%s'\n", subst_result.data); val = subst_result.data; goto store_val; @@ -1971,7 +1970,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) } } /* default: */ } /* switch (char after ) */ - if (val) { o_addQstr(output, val, strlen(val)); } @@ -2265,7 +2263,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignme if (argv_expanded) { argv = argv_expanded; } else { - argv = expand_strvec_to_strvec(argv); + argv = expand_strvec_to_strvec(argv + assignment_cnt); #if !BB_MMU nommu_save->argv = argv; #endif @@ -3628,7 +3626,6 @@ static int done_word(o_string *word, struct parse_context *ctx) ctx->ctx_dsemicolon = 0; } else #endif - if (!command->argv /* if it's the first word... */ #if ENABLE_HUSH_LOOPS && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ @@ -3767,8 +3764,7 @@ static FILE *generate_stream_from_list(struct pipe *head) /* Return code is exit status of the process that is run. */ static int process_command_subs(o_string *dest, - struct in_str *input, - const char *subst_end) + struct in_str *input) { int retcode, ch, eol_cnt; o_string result = NULL_O_STRING; @@ -3777,7 +3773,7 @@ static int process_command_subs(o_string *dest, struct in_str pipe_str; /* Recursion to generate command */ - retcode = parse_stream(&result, &inner, input, subst_end); + retcode = parse_stream(&result, &inner, input, NULL); if (retcode != 0) return retcode; /* syntax error or EOF */ o_free(&result); @@ -4236,9 +4232,11 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, * A single-quote triggers a bypass of the main loop until its mate is * found. When recursing, quote state is passed in via dest->o_escape. */ - debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); - initialize_context(ctx); + debug_printf_parse("parse_stream entered, end_trigger='%s' " + "dest->o_assignment:%d\n", end_trigger, dest->o_assignment); + dest->o_assignment = MAYBE_ASSIGNMENT; + initialize_context(ctx); is_in_dquote = dest->o_escape; while (1) { if (is_in_dquote) { @@ -4269,51 +4267,47 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, } continue; } - /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) - */ + /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ if (m == CHAR_IFS) { + if (ch == EOF) + goto ret_EOF; if (done_word(dest, ctx)) { debug_printf_parse("parse_stream return 1: done_word!=0\n"); return 1; } - if (ch == EOF) - goto ret_EOF; - /* If we aren't performing a substitution, treat - * a newline as a command separator. - * [why don't we handle it exactly like ';'? --vda] */ - if (end_trigger && ch == '\n') { + if (ch == '\n') { #if ENABLE_HUSH_CASE /* "case ... in word) ..." - * newlines are ignored (but ';' wouldn't be) */ - if (dest->length == 0 // && argv[0] == NULL + if (ctx->command->argv == NULL && ctx->ctx_res_w == RES_MATCH ) { continue; } #endif + /* Treat newline as a command separator. + * [why don't we handle it exactly like ';'? --vda] */ done_pipe(ctx, PIPE_SEQ); dest->o_assignment = MAYBE_ASSIGNMENT; } } - if (end_trigger) { - if (strchr(end_trigger, ch)) { - /* Special case: (...word) makes last word terminate, - * as if ';' is seen */ - if (ch == ')') { - done_word(dest, ctx); + if (end_trigger && strchr(end_trigger, ch)) { + /* Special case: (...word) makes last word terminate, + * as if ';' is seen */ + if (ch == ')') { + done_word(dest, ctx); //err chk? - done_pipe(ctx, PIPE_SEQ); - dest->o_assignment = MAYBE_ASSIGNMENT; - } - /* What do we check here? */ - if (!HAS_KEYWORDS - IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) - ) { - debug_printf_parse("parse_stream return 0: end_trigger char found\n"); - /* this makes us return 0, not -1 */ - end_trigger = NULL; - goto ret; - } + done_pipe(ctx, PIPE_SEQ); + dest->o_assignment = MAYBE_ASSIGNMENT; + } + /* What do we check here? */ + if (!HAS_KEYWORDS + IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) + ) { + debug_printf_parse("parse_stream return 0: end_trigger char found\n"); + /* this makes us return 0, not -1 */ + end_trigger = NULL; + goto ret; } } 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 @@ +b=1 +b=2 +b=3 +b=4 +b=5 +b=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 @@ +b=1 env | grep ^b= +true | b=2 env | grep ^b= +a=1 true | b=3 env | grep ^b= + +(b=4 env) | grep ^b= +(true | b=5 env) | grep ^b= +(a=1 true | b=6 env) | grep ^b= -- 2.25.1