diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-03 03:19:15 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-03 03:19:15 +0000 |
commit | 3718168b87a5bf5009b90b1e1253bec2c7ce9edf (patch) | |
tree | 64037be3206c0ce3cb0c68c114828010cd3da367 | |
parent | f9f74293465e98f2af117a1821a8fbb97cdbc3ed (diff) | |
download | busybox-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.c | 70 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_in_pipes.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_in_pipes.tests | 7 |
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 |
1660 | static int process_command_subs(o_string *dest, | 1660 | static int process_command_subs(o_string *dest, struct in_str *input); |
1661 | struct in_str *input, const char *subst_end); | ||
1662 | #endif | 1661 | #endif |
1663 | static char *expand_string_to_string(const char *str); | 1662 | static char *expand_string_to_string(const char *str); |
1664 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); | 1663 | 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) | |||
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. */ |
3769 | static int process_command_subs(o_string *dest, | 3766 | static 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 @@ | |||
1 | b=1 | ||
2 | b=2 | ||
3 | b=3 | ||
4 | b=4 | ||
5 | b=5 | ||
6 | 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 @@ | |||
1 | b=1 env | grep ^b= | ||
2 | true | b=2 env | grep ^b= | ||
3 | a=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= | ||