diff options
| author | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:48:57 +0000 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2012-03-22 15:48:57 +0000 |
| commit | 9db164d6e39050d09f38288c6045cd2a2cbf6d63 (patch) | |
| tree | ea5dc2d28d15da0de25c197ed7d059c3656af1a0 /shell | |
| parent | 1118c95535ea51961437089fc3dece5ab4ea7e1b (diff) | |
| parent | d84b175cb6948eb17f847313bf912174e2f934e1 (diff) | |
| download | busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.tar.gz busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.tar.bz2 busybox-w32-9db164d6e39050d09f38288c6045cd2a2cbf6d63.zip | |
Merge commit 'd84b175cb6948eb17f847313bf912174e2f934e1' into merge
Conflicts:
include/platform.h
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/cttyhack.c | 81 | ||||
| -rw-r--r-- | shell/hush.c | 117 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/starquoted2.right | 3 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/starquoted2.tests | 6 | ||||
| -rw-r--r-- | shell/hush_test/hush-vars/var_expand_on_ifs.right | 9 | ||||
| -rwxr-xr-x | shell/hush_test/hush-vars/var_expand_on_ifs.tests | 11 |
6 files changed, 159 insertions, 68 deletions
diff --git a/shell/cttyhack.c b/shell/cttyhack.c index d1ac2cd23..4261289b4 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c | |||
| @@ -14,18 +14,22 @@ | |||
| 14 | //config: bool "cttyhack" | 14 | //config: bool "cttyhack" |
| 15 | //config: default y | 15 | //config: default y |
| 16 | //config: help | 16 | //config: help |
| 17 | //config: One common problem reported on the mailing list is "can't access tty; | 17 | //config: One common problem reported on the mailing list is the "can't |
| 18 | //config: job control turned off" error message which typically appears when | 18 | //config: access tty; job control turned off" error message, which typically |
| 19 | //config: one tries to use shell with stdin/stdout opened to /dev/console. | 19 | //config: appears when one tries to use a shell with stdin/stdout on |
| 20 | //config: /dev/console. | ||
| 20 | //config: This device is special - it cannot be a controlling tty. | 21 | //config: This device is special - it cannot be a controlling tty. |
| 21 | //config: | 22 | //config: |
| 22 | //config: Proper solution is to use correct device instead of /dev/console. | 23 | //config: The proper solution is to use the correct device instead of |
| 24 | //config: /dev/console. | ||
| 23 | //config: | 25 | //config: |
| 24 | //config: cttyhack provides "quick and dirty" solution to this problem. | 26 | //config: cttyhack provides a "quick and dirty" solution to this problem. |
| 25 | //config: It analyzes stdin with various ioctls, trying to determine whether | 27 | //config: It analyzes stdin with various ioctls, trying to determine whether |
| 26 | //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). | 28 | //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). |
| 27 | //config: If it detects one, it closes stdin/out/err and reopens that device. | 29 | //config: On Linux it also checks sysfs for a pointer to the active console. |
| 28 | //config: Then it executes given program. Opening the device will make | 30 | //config: If cttyhack is able to find the real console device, it closes |
| 31 | //config: stdin/out/err and reopens that device. | ||
| 32 | //config: Then it executes the given program. Opening the device will make | ||
| 29 | //config: that device a controlling tty. This may require cttyhack | 33 | //config: that device a controlling tty. This may require cttyhack |
| 30 | //config: to be a session leader. | 34 | //config: to be a session leader. |
| 31 | //config: | 35 | //config: |
| @@ -115,33 +119,48 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) | |||
| 115 | close(fd); | 119 | close(fd); |
| 116 | } else { | 120 | } else { |
| 117 | /* We don't have ctty (or don't have "/dev/tty" node...) */ | 121 | /* We don't have ctty (or don't have "/dev/tty" node...) */ |
| 118 | if (0) {} | 122 | do { |
| 119 | #ifdef TIOCGSERIAL | ||
| 120 | else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { | ||
| 121 | /* this is a serial console */ | ||
| 122 | sprintf(console + 8, "S%d", u.sr.line); | ||
| 123 | } | ||
| 124 | #endif | ||
| 125 | #ifdef __linux__ | 123 | #ifdef __linux__ |
| 126 | else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { | 124 | int s = open_read_close("/sys/class/tty/console/active", |
| 127 | /* this is linux virtual tty */ | 125 | console + 5, sizeof(console) - 5 - 1); |
| 128 | sprintf(console + 8, "S%d" + 1, u.vt.v_active); | 126 | if (s > 0) { |
| 129 | } | 127 | /* found active console via sysfs (Linux 2.6.38+) */ |
| 128 | console[5 + s] = '\0'; | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { | ||
| 133 | /* this is linux virtual tty */ | ||
| 134 | sprintf(console + 8, "S%d" + 1, u.vt.v_active); | ||
| 135 | break; | ||
| 136 | } | ||
| 130 | #endif | 137 | #endif |
| 131 | if (console[8]) { | 138 | #ifdef TIOCGSERIAL |
| 132 | fd = xopen(console, O_RDWR); | 139 | if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { |
| 133 | //bb_error_msg("switching to '%s'", console); | 140 | /* this is a serial console, asuming it is named /dev/ttySn */ |
| 134 | dup2(fd, 0); | 141 | sprintf(console + 8, "S%d", u.sr.line); |
| 135 | dup2(fd, 1); | 142 | break; |
| 136 | dup2(fd, 2); | 143 | } |
| 137 | while (fd > 2) | 144 | #endif |
| 138 | close(fd--); | 145 | /* nope, could not find it */ |
| 139 | /* Some other session may have it as ctty, | 146 | goto ret; |
| 140 | * steal it from them: | 147 | } while (0); |
| 141 | */ | 148 | |
| 142 | ioctl(0, TIOCSCTTY, 1); | 149 | fd = open_or_warn(console, O_RDWR); |
| 143 | } | 150 | if (fd < 0) |
| 151 | goto ret; | ||
| 152 | //bb_error_msg("switching to '%s'", console); | ||
| 153 | dup2(fd, 0); | ||
| 154 | dup2(fd, 1); | ||
| 155 | dup2(fd, 2); | ||
| 156 | while (fd > 2) | ||
| 157 | close(fd--); | ||
| 158 | /* Some other session may have it as ctty, | ||
| 159 | * steal it from them: | ||
| 160 | */ | ||
| 161 | ioctl(0, TIOCSCTTY, 1); | ||
| 144 | } | 162 | } |
| 145 | 163 | ||
| 164 | ret: | ||
| 146 | BB_EXECVP_or_die(argv); | 165 | BB_EXECVP_or_die(argv); |
| 147 | } | 166 | } |
diff --git a/shell/hush.c b/shell/hush.c index 1082738a2..e4138adf7 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -2281,7 +2281,7 @@ static void o_addqblock(o_string *o, const char *str, int len) | |||
| 2281 | ordinary_cnt = len; | 2281 | ordinary_cnt = len; |
| 2282 | o_addblock(o, str, ordinary_cnt); | 2282 | o_addblock(o, str, ordinary_cnt); |
| 2283 | if (ordinary_cnt == len) | 2283 | if (ordinary_cnt == len) |
| 2284 | return; | 2284 | return; /* NUL is already added by o_addblock */ |
| 2285 | str += ordinary_cnt; | 2285 | str += ordinary_cnt; |
| 2286 | len -= ordinary_cnt + 1; /* we are processing + 1 char below */ | 2286 | len -= ordinary_cnt + 1; /* we are processing + 1 char below */ |
| 2287 | 2287 | ||
| @@ -2295,8 +2295,8 @@ static void o_addqblock(o_string *o, const char *str, int len) | |||
| 2295 | o_grow_by(o, sz); | 2295 | o_grow_by(o, sz); |
| 2296 | o->data[o->length] = ch; | 2296 | o->data[o->length] = ch; |
| 2297 | o->length++; | 2297 | o->length++; |
| 2298 | o->data[o->length] = '\0'; | ||
| 2299 | } | 2298 | } |
| 2299 | o->data[o->length] = '\0'; | ||
| 2300 | } | 2300 | } |
| 2301 | 2301 | ||
| 2302 | static void o_addQblock(o_string *o, const char *str, int len) | 2302 | static void o_addQblock(o_string *o, const char *str, int len) |
| @@ -2385,6 +2385,7 @@ static int o_save_ptr_helper(o_string *o, int n) | |||
| 2385 | n, string_len, string_start); | 2385 | n, string_len, string_start); |
| 2386 | o->has_empty_slot = 0; | 2386 | o->has_empty_slot = 0; |
| 2387 | } | 2387 | } |
| 2388 | o->has_quoted_part = 0; | ||
| 2388 | list[n] = (char*)(uintptr_t)string_len; | 2389 | list[n] = (char*)(uintptr_t)string_len; |
| 2389 | return n + 1; | 2390 | return n + 1; |
| 2390 | } | 2391 | } |
| @@ -3264,14 +3265,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
| 3264 | ) { | 3265 | ) { |
| 3265 | p += 3; | 3266 | p += 3; |
| 3266 | } | 3267 | } |
| 3267 | if (p == word->data || p[0] != '\0') { | ||
| 3268 | /* saw no "$@", or not only "$@" but some | ||
| 3269 | * real text is there too */ | ||
| 3270 | /* insert "empty variable" reference, this makes | ||
| 3271 | * e.g. "", $empty"" etc to not disappear */ | ||
| 3272 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
| 3273 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
| 3274 | } | ||
| 3275 | } | 3268 | } |
| 3276 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); | 3269 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); |
| 3277 | debug_print_strings("word appended to argv", command->argv); | 3270 | debug_print_strings("word appended to argv", command->argv); |
| @@ -4515,20 +4508,30 @@ static struct pipe *parse_stream(char **pstring, | |||
| 4515 | break; | 4508 | break; |
| 4516 | case '\'': | 4509 | case '\'': |
| 4517 | dest.has_quoted_part = 1; | 4510 | dest.has_quoted_part = 1; |
| 4518 | while (1) { | 4511 | if (next == '\'' && !ctx.pending_redirect) { |
| 4519 | ch = i_getch(input); | 4512 | insert_empty_quoted_str_marker: |
| 4520 | if (ch == EOF) { | 4513 | nommu_addchr(&ctx.as_string, next); |
| 4521 | syntax_error_unterm_ch('\''); | 4514 | i_getch(input); /* eat second ' */ |
| 4522 | goto parse_error; | 4515 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
| 4516 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | ||
| 4517 | } else { | ||
| 4518 | while (1) { | ||
| 4519 | ch = i_getch(input); | ||
| 4520 | if (ch == EOF) { | ||
| 4521 | syntax_error_unterm_ch('\''); | ||
| 4522 | goto parse_error; | ||
| 4523 | } | ||
| 4524 | nommu_addchr(&ctx.as_string, ch); | ||
| 4525 | if (ch == '\'') | ||
| 4526 | break; | ||
| 4527 | o_addqchr(&dest, ch); | ||
| 4523 | } | 4528 | } |
| 4524 | nommu_addchr(&ctx.as_string, ch); | ||
| 4525 | if (ch == '\'') | ||
| 4526 | break; | ||
| 4527 | o_addqchr(&dest, ch); | ||
| 4528 | } | 4529 | } |
| 4529 | break; | 4530 | break; |
| 4530 | case '"': | 4531 | case '"': |
| 4531 | dest.has_quoted_part = 1; | 4532 | dest.has_quoted_part = 1; |
| 4533 | if (next == '"' && !ctx.pending_redirect) | ||
| 4534 | goto insert_empty_quoted_str_marker; | ||
| 4532 | if (dest.o_assignment == NOT_ASSIGNMENT) | 4535 | if (dest.o_assignment == NOT_ASSIGNMENT) |
| 4533 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 4536 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
| 4534 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) | 4537 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) |
| @@ -4750,12 +4753,22 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len | |||
| 4750 | 4753 | ||
| 4751 | /* Store given string, finalizing the word and starting new one whenever | 4754 | /* Store given string, finalizing the word and starting new one whenever |
| 4752 | * we encounter IFS char(s). This is used for expanding variable values. | 4755 | * we encounter IFS char(s). This is used for expanding variable values. |
| 4753 | * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ | 4756 | * End-of-string does NOT finalize word: think about 'echo -$VAR-'. |
| 4754 | static int expand_on_ifs(o_string *output, int n, const char *str) | 4757 | * Return in *ended_with_ifs: |
| 4758 | * 1 - ended with IFS char, else 0 (this includes case of empty str). | ||
| 4759 | */ | ||
| 4760 | static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) | ||
| 4755 | { | 4761 | { |
| 4762 | int last_is_ifs = 0; | ||
| 4763 | |||
| 4756 | while (1) { | 4764 | while (1) { |
| 4757 | int word_len = strcspn(str, G.ifs); | 4765 | int word_len; |
| 4766 | |||
| 4767 | if (!*str) /* EOL - do not finalize word */ | ||
| 4768 | break; | ||
| 4769 | word_len = strcspn(str, G.ifs); | ||
| 4758 | if (word_len) { | 4770 | if (word_len) { |
| 4771 | /* We have WORD_LEN leading non-IFS chars */ | ||
| 4759 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { | 4772 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { |
| 4760 | o_addblock(output, str, word_len); | 4773 | o_addblock(output, str, word_len); |
| 4761 | } else { | 4774 | } else { |
| @@ -4768,15 +4781,36 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
| 4768 | /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ | 4781 | /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ |
| 4769 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ | 4782 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ |
| 4770 | } | 4783 | } |
| 4784 | last_is_ifs = 0; | ||
| 4771 | str += word_len; | 4785 | str += word_len; |
| 4786 | if (!*str) /* EOL - do not finalize word */ | ||
| 4787 | break; | ||
| 4772 | } | 4788 | } |
| 4789 | |||
| 4790 | /* We know str here points to at least one IFS char */ | ||
| 4791 | last_is_ifs = 1; | ||
| 4792 | str += strspn(str, G.ifs); /* skip IFS chars */ | ||
| 4773 | if (!*str) /* EOL - do not finalize word */ | 4793 | if (!*str) /* EOL - do not finalize word */ |
| 4774 | break; | 4794 | break; |
| 4775 | o_addchr(output, '\0'); | 4795 | |
| 4776 | debug_print_list("expand_on_ifs", output, n); | 4796 | /* Start new word... but not always! */ |
| 4777 | n = o_save_ptr(output, n); | 4797 | /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ |
| 4778 | str += strspn(str, G.ifs); /* skip ifs chars */ | 4798 | if (output->has_quoted_part |
| 4799 | /* Case "v=' a'; echo $v": | ||
| 4800 | * here nothing precedes the space in $v expansion, | ||
| 4801 | * therefore we should not finish the word | ||
| 4802 | * (IOW: if there *is* word to finalize, only then do it): | ||
| 4803 | */ | ||
| 4804 | || (n > 0 && output->data[output->length - 1]) | ||
| 4805 | ) { | ||
| 4806 | o_addchr(output, '\0'); | ||
| 4807 | debug_print_list("expand_on_ifs", output, n); | ||
| 4808 | n = o_save_ptr(output, n); | ||
| 4809 | } | ||
| 4779 | } | 4810 | } |
| 4811 | |||
| 4812 | if (ended_with_ifs) | ||
| 4813 | *ended_with_ifs = last_is_ifs; | ||
| 4780 | debug_print_list("expand_on_ifs[1]", output, n); | 4814 | debug_print_list("expand_on_ifs[1]", output, n); |
| 4781 | return n; | 4815 | return n; |
| 4782 | } | 4816 | } |
| @@ -5191,6 +5225,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5191 | * expansion of right-hand side of assignment == 1-element expand. | 5225 | * expansion of right-hand side of assignment == 1-element expand. |
| 5192 | */ | 5226 | */ |
| 5193 | char cant_be_null = 0; /* only bit 0x80 matters */ | 5227 | char cant_be_null = 0; /* only bit 0x80 matters */ |
| 5228 | int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ | ||
| 5194 | char *p; | 5229 | char *p; |
| 5195 | 5230 | ||
| 5196 | debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, | 5231 | debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, |
| @@ -5209,6 +5244,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5209 | #if ENABLE_SH_MATH_SUPPORT | 5244 | #if ENABLE_SH_MATH_SUPPORT |
| 5210 | char arith_buf[sizeof(arith_t)*3 + 2]; | 5245 | char arith_buf[sizeof(arith_t)*3 + 2]; |
| 5211 | #endif | 5246 | #endif |
| 5247 | |||
| 5248 | if (ended_in_ifs) { | ||
| 5249 | o_addchr(output, '\0'); | ||
| 5250 | n = o_save_ptr(output, n); | ||
| 5251 | ended_in_ifs = 0; | ||
| 5252 | } | ||
| 5253 | |||
| 5212 | o_addblock(output, arg, p - arg); | 5254 | o_addblock(output, arg, p - arg); |
| 5213 | debug_print_list("expand_vars_to_list[1]", output, n); | 5255 | debug_print_list("expand_vars_to_list[1]", output, n); |
| 5214 | arg = ++p; | 5256 | arg = ++p; |
| @@ -5237,7 +5279,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5237 | cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ | 5279 | cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ |
| 5238 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ | 5280 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ |
| 5239 | while (G.global_argv[i]) { | 5281 | while (G.global_argv[i]) { |
| 5240 | n = expand_on_ifs(output, n, G.global_argv[i]); | 5282 | n = expand_on_ifs(NULL, output, n, G.global_argv[i]); |
| 5241 | debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); | 5283 | debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); |
| 5242 | if (G.global_argv[i++][0] && G.global_argv[i]) { | 5284 | if (G.global_argv[i++][0] && G.global_argv[i]) { |
| 5243 | /* this argv[] is not empty and not last: | 5285 | /* this argv[] is not empty and not last: |
| @@ -5270,11 +5312,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5270 | if (G.ifs[0]) | 5312 | if (G.ifs[0]) |
| 5271 | o_addchr(output, G.ifs[0]); | 5313 | o_addchr(output, G.ifs[0]); |
| 5272 | } | 5314 | } |
| 5315 | output->has_quoted_part = 1; | ||
| 5273 | } | 5316 | } |
| 5274 | break; | 5317 | break; |
| 5275 | } | 5318 | } |
| 5276 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ | 5319 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ |
| 5277 | /* "Empty variable", used to make "" etc to not disappear */ | 5320 | /* "Empty variable", used to make "" etc to not disappear */ |
| 5321 | output->has_quoted_part = 1; | ||
| 5278 | arg++; | 5322 | arg++; |
| 5279 | cant_be_null = 0x80; | 5323 | cant_be_null = 0x80; |
| 5280 | break; | 5324 | break; |
| @@ -5312,10 +5356,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5312 | debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, | 5356 | debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, |
| 5313 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5357 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
| 5314 | if (val && val[0]) { | 5358 | if (val && val[0]) { |
| 5315 | n = expand_on_ifs(output, n, val); | 5359 | n = expand_on_ifs(&ended_in_ifs, output, n, val); |
| 5316 | val = NULL; | 5360 | val = NULL; |
| 5317 | } | 5361 | } |
| 5318 | } else { /* quoted $VAR, val will be appended below */ | 5362 | } else { /* quoted $VAR, val will be appended below */ |
| 5363 | output->has_quoted_part = 1; | ||
| 5319 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, | 5364 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, |
| 5320 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5365 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
| 5321 | } | 5366 | } |
| @@ -5340,6 +5385,10 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
| 5340 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ | 5385 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ |
| 5341 | 5386 | ||
| 5342 | if (arg[0]) { | 5387 | if (arg[0]) { |
| 5388 | if (ended_in_ifs) { | ||
| 5389 | o_addchr(output, '\0'); | ||
| 5390 | n = o_save_ptr(output, n); | ||
| 5391 | } | ||
| 5343 | debug_print_list("expand_vars_to_list[a]", output, n); | 5392 | debug_print_list("expand_vars_to_list[a]", output, n); |
| 5344 | /* this part is literal, and it was already pre-quoted | 5393 | /* this part is literal, and it was already pre-quoted |
| 5345 | * if needed (much earlier), do not use o_addQstr here! */ | 5394 | * if needed (much earlier), do not use o_addQstr here! */ |
| @@ -5470,12 +5519,6 @@ static char **expand_assignments(char **argv, int count) | |||
| 5470 | } | 5519 | } |
| 5471 | 5520 | ||
| 5472 | 5521 | ||
| 5473 | #if BB_MMU | ||
| 5474 | /* never called */ | ||
| 5475 | void re_execute_shell(char ***to_free, const char *s, | ||
| 5476 | char *g_argv0, char **g_argv, | ||
| 5477 | char **builtin_argv) NORETURN; | ||
| 5478 | |||
| 5479 | static void switch_off_special_sigs(unsigned mask) | 5522 | static void switch_off_special_sigs(unsigned mask) |
| 5480 | { | 5523 | { |
| 5481 | unsigned sig = 0; | 5524 | unsigned sig = 0; |
| @@ -5495,6 +5538,12 @@ static void switch_off_special_sigs(unsigned mask) | |||
| 5495 | } | 5538 | } |
| 5496 | } | 5539 | } |
| 5497 | 5540 | ||
| 5541 | #if BB_MMU | ||
| 5542 | /* never called */ | ||
| 5543 | void re_execute_shell(char ***to_free, const char *s, | ||
| 5544 | char *g_argv0, char **g_argv, | ||
| 5545 | char **builtin_argv) NORETURN; | ||
| 5546 | |||
| 5498 | static void reset_traps_to_defaults(void) | 5547 | static void reset_traps_to_defaults(void) |
| 5499 | { | 5548 | { |
| 5500 | /* This function is always called in a child shell | 5549 | /* This function is always called in a child shell |
diff --git a/shell/hush_test/hush-parsing/starquoted2.right b/shell/hush_test/hush-parsing/starquoted2.right index e1562ed6d..1bff408ca 100644 --- a/shell/hush_test/hush-parsing/starquoted2.right +++ b/shell/hush_test/hush-parsing/starquoted2.right | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | Should be printed | 1 | Should be printed |
| 2 | Would not be printed by bash | ||
| 3 | Would not be printed by bash | ||
| 4 | Would not be printed by bash | ||
| 2 | Should be printed | 5 | Should be printed |
| 3 | Empty: | 6 | Empty: |
| 4 | Empty: | 7 | Empty: |
diff --git a/shell/hush_test/hush-parsing/starquoted2.tests b/shell/hush_test/hush-parsing/starquoted2.tests index f305c4cd9..7c5ff45b8 100755 --- a/shell/hush_test/hush-parsing/starquoted2.tests +++ b/shell/hush_test/hush-parsing/starquoted2.tests | |||
| @@ -8,9 +8,9 @@ for a in "$@"; do echo Should not be printed; done | |||
| 8 | # Yes, believe it or not, bash is mesmerized by "$@" and stops | 8 | # Yes, believe it or not, bash is mesmerized by "$@" and stops |
| 9 | # treating "" as "this word cannot be expanded to nothing, | 9 | # treating "" as "this word cannot be expanded to nothing, |
| 10 | # but must be at least null string". Now it can be expanded to nothing. | 10 | # but must be at least null string". Now it can be expanded to nothing. |
| 11 | for a in "$@"""; do echo Should not be printed; done | 11 | for a in "$@"""; do echo Would not be printed by bash; done |
| 12 | for a in """$@"; do echo Should not be printed; done | 12 | for a in """$@"; do echo Would not be printed by bash; done |
| 13 | for a in """$@"''"$@"''; do echo Should not be printed; done | 13 | for a in """$@"''"$@"''; do echo Would not be printed by bash; done |
| 14 | for a in ""; do echo Should be printed; done | 14 | for a in ""; do echo Should be printed; done |
| 15 | 15 | ||
| 16 | # Bug 207: "$@" expands to nothing, and we erroneously glob "%s\n" twice: | 16 | # Bug 207: "$@" expands to nothing, and we erroneously glob "%s\n" twice: |
diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.right b/shell/hush_test/hush-vars/var_expand_on_ifs.right new file mode 100644 index 000000000..2ed2069f7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.right | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | 1 a b c | ||
| 2 | 2 a + b c | ||
| 3 | 3 a b c | ||
| 4 | 4 a b c | ||
| 5 | 5 a b c | ||
| 6 | 6 a b + c | ||
| 7 | 7 a b c | ||
| 8 | 8 a b c | ||
| 9 | 9 a b c | ||
diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.tests b/shell/hush_test/hush-vars/var_expand_on_ifs.tests new file mode 100755 index 000000000..a12ff8ec8 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.tests | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | b=' b ' | ||
| 2 | e='' | ||
| 3 | echo 1 a $b c | ||
| 4 | echo 2 a +$b c | ||
| 5 | echo 3 a $e$b c | ||
| 6 | echo 4 a "$e"$b c | ||
| 7 | echo 5 a ""$b c | ||
| 8 | echo 6 a $b+ c | ||
| 9 | echo 7 a $b$e c | ||
| 10 | echo 8 a $b"$e" c | ||
| 11 | echo 9 a $b"" c | ||
