summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-08 13:31:53 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-08 13:31:53 +0200
commit1fd3d94a6c4c45d6106958c0a634dbbb7a7a5e12 (patch)
treea6695baab798ab9c253a3e9dade83e2b39efd65b
parentb103fb10cfb09902df1581efc81ea386e63c71b5 (diff)
downloadbusybox-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.c65
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 */
5004static char *expand_string_to_string(const char *str) 5010static 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];