diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-08 13:31:53 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-08 13:31:53 +0200 |
commit | 1fd3d94a6c4c45d6106958c0a634dbbb7a7a5e12 (patch) | |
tree | a6695baab798ab9c253a3e9dade83e2b39efd65b | |
parent | b103fb10cfb09902df1581efc81ea386e63c71b5 (diff) | |
download | busybox-w32-1fd3d94a6c4c45d6106958c0a634dbbb7a7a5e12.tar.gz busybox-w32-1fd3d94a6c4c45d6106958c0a634dbbb7a7a5e12.tar.bz2 busybox-w32-1fd3d94a6c4c45d6106958c0a634dbbb7a7a5e12.zip |
hush: fix set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*"
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r-- | shell/hush.c | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/shell/hush.c b/shell/hush.c index 3e8c387e7..57782f52b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -3839,10 +3839,10 @@ static struct pipe *parse_stream(char **pstring, | |||
3839 | o_addchr(&dest, '\0'); | 3839 | o_addchr(&dest, '\0'); |
3840 | dest.length = 0; | 3840 | dest.length = 0; |
3841 | 3841 | ||
3842 | G.ifs = get_local_var_value("IFS"); | 3842 | /* We used to separate words on $IFS here. This was wrong. |
3843 | if (G.ifs == NULL) | 3843 | * $IFS is used only for word splitting when $var is expanded, |
3844 | G.ifs = defifs; | 3844 | * here we should use blank chars as separators, not $iFS |
3845 | 3845 | */ | |
3846 | reset: | 3846 | reset: |
3847 | #if ENABLE_HUSH_INTERACTIVE | 3847 | #if ENABLE_HUSH_INTERACTIVE |
3848 | input->promptmode = 0; /* PS1 */ | 3848 | input->promptmode = 0; /* PS1 */ |
@@ -3852,7 +3852,7 @@ static struct pipe *parse_stream(char **pstring, | |||
3852 | is_in_dquote = 0; | 3852 | is_in_dquote = 0; |
3853 | heredoc_cnt = 0; | 3853 | heredoc_cnt = 0; |
3854 | while (1) { | 3854 | while (1) { |
3855 | const char *is_ifs; | 3855 | const char *is_blank; |
3856 | const char *is_special; | 3856 | const char *is_special; |
3857 | int ch; | 3857 | int ch; |
3858 | int next; | 3858 | int next; |
@@ -3922,20 +3922,20 @@ static struct pipe *parse_stream(char **pstring, | |||
3922 | if (ctx.command->argv /* word [word]{... - non-special */ | 3922 | if (ctx.command->argv /* word [word]{... - non-special */ |
3923 | || dest.length /* word{... - non-special */ | 3923 | || dest.length /* word{... - non-special */ |
3924 | || dest.has_quoted_part /* ""{... - non-special */ | 3924 | || dest.has_quoted_part /* ""{... - non-special */ |
3925 | || (next != ';' /* }; - special */ | 3925 | || (next != ';' /* }; - special */ |
3926 | && next != ')' /* }) - special */ | 3926 | && next != ')' /* }) - special */ |
3927 | && next != '&' /* }& and }&& ... - special */ | 3927 | && next != '&' /* }& and }&& ... - special */ |
3928 | && next != '|' /* }|| ... - special */ | 3928 | && next != '|' /* }|| ... - special */ |
3929 | && !strchr(G.ifs, next) /* {word - non-special */ | 3929 | && !strchr(defifs, next) /* {word - non-special */ |
3930 | ) | 3930 | ) |
3931 | ) { | 3931 | ) { |
3932 | /* They are not special, skip "{}" */ | 3932 | /* They are not special, skip "{}" */ |
3933 | is_special += 2; | 3933 | is_special += 2; |
3934 | } | 3934 | } |
3935 | is_special = strchr(is_special, ch); | 3935 | is_special = strchr(is_special, ch); |
3936 | is_ifs = strchr(G.ifs, ch); | 3936 | is_blank = strchr(defifs, ch); |
3937 | 3937 | ||
3938 | if (!is_special && !is_ifs) { /* ordinary char */ | 3938 | if (!is_special && !is_blank) { /* ordinary char */ |
3939 | ordinary_char: | 3939 | ordinary_char: |
3940 | o_addQchr(&dest, ch); | 3940 | o_addQchr(&dest, ch); |
3941 | if ((dest.o_assignment == MAYBE_ASSIGNMENT | 3941 | if ((dest.o_assignment == MAYBE_ASSIGNMENT |
@@ -3948,7 +3948,7 @@ static struct pipe *parse_stream(char **pstring, | |||
3948 | continue; | 3948 | continue; |
3949 | } | 3949 | } |
3950 | 3950 | ||
3951 | if (is_ifs) { | 3951 | if (is_blank) { |
3952 | if (done_word(&dest, &ctx)) { | 3952 | if (done_word(&dest, &ctx)) { |
3953 | goto parse_error; | 3953 | goto parse_error; |
3954 | } | 3954 | } |
@@ -3973,7 +3973,7 @@ static struct pipe *parse_stream(char **pstring, | |||
3973 | } | 3973 | } |
3974 | dest.o_assignment = MAYBE_ASSIGNMENT; | 3974 | dest.o_assignment = MAYBE_ASSIGNMENT; |
3975 | ch = ';'; | 3975 | ch = ';'; |
3976 | /* note: if (is_ifs) continue; | 3976 | /* note: if (is_blank) continue; |
3977 | * will still trigger for us */ | 3977 | * will still trigger for us */ |
3978 | } | 3978 | } |
3979 | } | 3979 | } |
@@ -4041,7 +4041,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4041 | } | 4041 | } |
4042 | } | 4042 | } |
4043 | skip_end_trigger: | 4043 | skip_end_trigger: |
4044 | if (is_ifs) | 4044 | if (is_blank) |
4045 | continue; | 4045 | continue; |
4046 | 4046 | ||
4047 | /* Catch <, > before deciding whether this word is | 4047 | /* Catch <, > before deciding whether this word is |
@@ -4348,7 +4348,7 @@ static int process_command_subs(o_string *dest, const char *s); | |||
4348 | * of strings. (Think VAR="a b"; echo $VAR). | 4348 | * of strings. (Think VAR="a b"; echo $VAR). |
4349 | * This new list is allocated as a single malloc block. | 4349 | * This new list is allocated as a single malloc block. |
4350 | * NULL-terminated list of char* pointers is at the beginning of it, | 4350 | * NULL-terminated list of char* pointers is at the beginning of it, |
4351 | * followed by strings themself. | 4351 | * followed by strings themselves. |
4352 | * Caller can deallocate entire list by single free(list). */ | 4352 | * Caller can deallocate entire list by single free(list). */ |
4353 | 4353 | ||
4354 | /* Store given string, finalizing the word and starting new one whenever | 4354 | /* Store given string, finalizing the word and starting new one whenever |
@@ -4505,18 +4505,20 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4505 | char *exp_saveptr; /* points to expansion operator */ | 4505 | char *exp_saveptr; /* points to expansion operator */ |
4506 | char *exp_word = exp_word; /* for compiler */ | 4506 | char *exp_word = exp_word; /* for compiler */ |
4507 | 4507 | ||
4508 | *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */ | ||
4508 | var = arg; | 4509 | var = arg; |
4509 | *p = '\0'; | ||
4510 | exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; | 4510 | exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; |
4511 | first_char = arg[0] = first_ch & 0x7f; | 4511 | first_char = arg[0] = first_ch & 0x7f; |
4512 | exp_op = 0; | 4512 | exp_op = 0; |
4513 | 4513 | ||
4514 | if (first_char == '#' && arg[1] && !exp_saveptr) { | 4514 | if (first_char == '#' /* ${#... */ |
4515 | /* handle length expansion ${#var} */ | 4515 | && arg[1] && !exp_saveptr /* not ${#} and not ${#<op_char>...} */ |
4516 | ) { | ||
4517 | /* It must be length operator: ${#var} */ | ||
4516 | var++; | 4518 | var++; |
4517 | exp_op = 'L'; | 4519 | exp_op = 'L'; |
4518 | } else { | 4520 | } else { |
4519 | /* maybe handle parameter expansion */ | 4521 | /* Maybe handle parameter expansion */ |
4520 | if (exp_saveptr /* if 2nd char is one of expansion operators */ | 4522 | if (exp_saveptr /* if 2nd char is one of expansion operators */ |
4521 | && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ | 4523 | && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ |
4522 | ) { | 4524 | ) { |
@@ -4531,8 +4533,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4531 | exp_word = exp_saveptr + 1; | 4533 | exp_word = exp_saveptr + 1; |
4532 | if (exp_op == ':') { | 4534 | if (exp_op == ':') { |
4533 | exp_op = *exp_word++; | 4535 | exp_op = *exp_word++; |
4536 | //TODO: try ${var:} and ${var:bogus} in non-bash config | ||
4534 | if (ENABLE_HUSH_BASH_COMPAT | 4537 | if (ENABLE_HUSH_BASH_COMPAT |
4535 | && (exp_op == '\0' || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op)) | 4538 | && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op)) |
4536 | ) { | 4539 | ) { |
4537 | /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ | 4540 | /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ |
4538 | exp_op = ':'; | 4541 | exp_op = ':'; |
@@ -4543,7 +4546,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4543 | } /* else: it's not an expansion op, but bare ${var} */ | 4546 | } /* else: it's not an expansion op, but bare ${var} */ |
4544 | } | 4547 | } |
4545 | 4548 | ||
4546 | /* lookup the variable in question */ | 4549 | /* Look up the variable in question */ |
4547 | if (isdigit(var[0])) { | 4550 | if (isdigit(var[0])) { |
4548 | /* parse_dollar() should have vetted var for us */ | 4551 | /* parse_dollar() should have vetted var for us */ |
4549 | int n = xatoi_positive(var); | 4552 | int n = xatoi_positive(var); |
@@ -4622,7 +4625,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4622 | /* It's ${var/[/]pattern[/repl]} thing */ | 4625 | /* It's ${var/[/]pattern[/repl]} thing */ |
4623 | /* | 4626 | /* |
4624 | * Pattern is taken literally, while | 4627 | * Pattern is taken literally, while |
4625 | * repl should be de-backslased and globbed | 4628 | * repl should be unbackslashed and globbed |
4626 | * by the usual expansion rules: | 4629 | * by the usual expansion rules: |
4627 | * >az; >bz; | 4630 | * >az; >bz; |
4628 | * v='a bz'; echo "${v/a*z/a*z}" prints "a*z" | 4631 | * v='a bz'; echo "${v/a*z/a*z}" prints "a*z" |
@@ -4998,9 +5001,12 @@ static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | |||
4998 | } | 5001 | } |
4999 | #endif | 5002 | #endif |
5000 | 5003 | ||
5001 | /* Used for expansion of right hand of assignments */ | 5004 | /* Used for expansion of right hand of assignments, |
5002 | /* NB: should NOT do globbing! | 5005 | * $((...)), heredocs, variable espansion parts. |
5003 | * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */ | 5006 | * |
5007 | * NB: should NOT do globbing! | ||
5008 | * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" | ||
5009 | */ | ||
5004 | static char *expand_string_to_string(const char *str) | 5010 | static char *expand_string_to_string(const char *str) |
5005 | { | 5011 | { |
5006 | char *argv[2], **list; | 5012 | char *argv[2], **list; |
@@ -6413,6 +6419,13 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
6413 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); | 6419 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); |
6414 | debug_enter(); | 6420 | debug_enter(); |
6415 | 6421 | ||
6422 | /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" | ||
6423 | * Result should be 3 lines: q w e, qwe, q w e | ||
6424 | */ | ||
6425 | G.ifs = get_local_var_value("IFS"); | ||
6426 | if (!G.ifs) | ||
6427 | G.ifs = defifs; | ||
6428 | |||
6416 | IF_HUSH_JOB(pi->pgrp = -1;) | 6429 | IF_HUSH_JOB(pi->pgrp = -1;) |
6417 | pi->stopped_cmds = 0; | 6430 | pi->stopped_cmds = 0; |
6418 | command = &pi->cmds[0]; | 6431 | command = &pi->cmds[0]; |