aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-08-01 18:16:43 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-08-01 18:16:43 +0200
commit6e42b89b8d136316e1b97b56cf885e8ef9d64caf (patch)
treeb22a7d3e771d5262c39058764f13ac62c5cfe731 /shell
parent4fb53fb08ce3da8eac13438ce613df20e523c75d (diff)
downloadbusybox-w32-6e42b89b8d136316e1b97b56cf885e8ef9d64caf.tar.gz
busybox-w32-6e42b89b8d136316e1b97b56cf885e8ef9d64caf.tar.bz2
busybox-w32-6e42b89b8d136316e1b97b56cf885e8ef9d64caf.zip
hush: fix remaining known two bugs with IFS expansion. Closes 4027.
function old new delta expand_vars_to_list 1054 1140 +86 parse_stream 2425 2479 +54 expand_on_ifs 258 310 +52 builtin_umask 133 132 -1 done_word 820 779 -41 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 192/-42) Total: 150 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c82
-rw-r--r--shell/hush_test/hush-parsing/starquoted2.right3
-rwxr-xr-xshell/hush_test/hush-parsing/starquoted2.tests6
3 files changed, 61 insertions, 30 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 503cb770b..6b3027771 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3265,14 +3265,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3265 ) { 3265 ) {
3266 p += 3; 3266 p += 3;
3267 } 3267 }
3268 if (p == word->data || p[0] != '\0') {
3269 /* saw no "$@", or not only "$@" but some
3270 * real text is there too */
3271 /* insert "empty variable" reference, this makes
3272 * e.g. "", $empty"" etc to not disappear */
3273 o_addchr(word, SPECIAL_VAR_SYMBOL);
3274 o_addchr(word, SPECIAL_VAR_SYMBOL);
3275 }
3276 } 3268 }
3277 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 3269 command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
3278 debug_print_strings("word appended to argv", command->argv); 3270 debug_print_strings("word appended to argv", command->argv);
@@ -4516,20 +4508,30 @@ static struct pipe *parse_stream(char **pstring,
4516 break; 4508 break;
4517 case '\'': 4509 case '\'':
4518 dest.has_quoted_part = 1; 4510 dest.has_quoted_part = 1;
4519 while (1) { 4511 if (next == '\'' && !ctx.pending_redirect) {
4520 ch = i_getch(input); 4512 insert_empty_quoted_str_marker:
4521 if (ch == EOF) { 4513 nommu_addchr(&ctx.as_string, next);
4522 syntax_error_unterm_ch('\''); 4514 i_getch(input); /* eat second ' */
4523 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);
4524 } 4528 }
4525 nommu_addchr(&ctx.as_string, ch);
4526 if (ch == '\'')
4527 break;
4528 o_addqchr(&dest, ch);
4529 } 4529 }
4530 break; 4530 break;
4531 case '"': 4531 case '"':
4532 dest.has_quoted_part = 1; 4532 dest.has_quoted_part = 1;
4533 if (next == '"' && !ctx.pending_redirect)
4534 goto insert_empty_quoted_str_marker;
4533 if (dest.o_assignment == NOT_ASSIGNMENT) 4535 if (dest.o_assignment == NOT_ASSIGNMENT)
4534 dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 4536 dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
4535 if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) 4537 if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))
@@ -4751,9 +4753,14 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
4751 4753
4752/* Store given string, finalizing the word and starting new one whenever 4754/* Store given string, finalizing the word and starting new one whenever
4753 * 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.
4754 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4756 * End-of-string does NOT finalize word: think about 'echo -$VAR-'.
4755static 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 */
4760static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str)
4756{ 4761{
4762 int last_is_ifs = 0;
4763
4757 while (1) { 4764 while (1) {
4758 int word_len; 4765 int word_len;
4759 4766
@@ -4774,27 +4781,36 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
4774 /*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\*" */
4775 /*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 */
4776 } 4783 }
4784 last_is_ifs = 0;
4777 str += word_len; 4785 str += word_len;
4778 if (!*str) /* EOL - do not finalize word */ 4786 if (!*str) /* EOL - do not finalize word */
4779 break; 4787 break;
4780 goto finalize; /* optimization (can just fall thru) */
4781 } 4788 }
4782 /* Case "v=' a'; echo ''$v": we do need to finalize empty word */ 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 */
4793 if (!*str) /* EOL - do not finalize word */
4794 break;
4795
4796 /* Start new word... but not always! */
4797 /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */
4783 if (output->has_quoted_part 4798 if (output->has_quoted_part
4784 /* Case "v=' a'; echo $v": 4799 /* Case "v=' a'; echo $v":
4785 * here nothing precedes the space in $v expansion, 4800 * here nothing precedes the space in $v expansion,
4786 * therefore we should not finish the word 4801 * therefore we should not finish the word
4787 * (IOW: if there *is* word to finalize, only then do it) 4802 * (IOW: if there *is* word to finalize, only then do it):
4788 */ 4803 */
4789 || (output->length && output->data[output->length - 1]) 4804 || (n > 0 && output->data[output->length - 1])
4790 ) { 4805 ) {
4791 finalize:
4792 o_addchr(output, '\0'); 4806 o_addchr(output, '\0');
4793 debug_print_list("expand_on_ifs", output, n); 4807 debug_print_list("expand_on_ifs", output, n);
4794 n = o_save_ptr(output, n); 4808 n = o_save_ptr(output, n);
4795 } 4809 }
4796 str += strspn(str, G.ifs); /* skip IFS chars */
4797 } 4810 }
4811
4812 if (ended_with_ifs)
4813 *ended_with_ifs = last_is_ifs;
4798 debug_print_list("expand_on_ifs[1]", output, n); 4814 debug_print_list("expand_on_ifs[1]", output, n);
4799 return n; 4815 return n;
4800} 4816}
@@ -5209,6 +5225,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5209 * expansion of right-hand side of assignment == 1-element expand. 5225 * expansion of right-hand side of assignment == 1-element expand.
5210 */ 5226 */
5211 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? */
5212 char *p; 5229 char *p;
5213 5230
5214 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,
@@ -5227,6 +5244,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5227#if ENABLE_SH_MATH_SUPPORT 5244#if ENABLE_SH_MATH_SUPPORT
5228 char arith_buf[sizeof(arith_t)*3 + 2]; 5245 char arith_buf[sizeof(arith_t)*3 + 2];
5229#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
5230 o_addblock(output, arg, p - arg); 5254 o_addblock(output, arg, p - arg);
5231 debug_print_list("expand_vars_to_list[1]", output, n); 5255 debug_print_list("expand_vars_to_list[1]", output, n);
5232 arg = ++p; 5256 arg = ++p;
@@ -5255,7 +5279,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5255 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 */
5256 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 5280 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
5257 while (G.global_argv[i]) { 5281 while (G.global_argv[i]) {
5258 n = expand_on_ifs(output, n, G.global_argv[i]); 5282 n = expand_on_ifs(NULL, output, n, G.global_argv[i]);
5259 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);
5260 if (G.global_argv[i++][0] && G.global_argv[i]) { 5284 if (G.global_argv[i++][0] && G.global_argv[i]) {
5261 /* this argv[] is not empty and not last: 5285 /* this argv[] is not empty and not last:
@@ -5332,7 +5356,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5332 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, 5356 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val,
5333 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5357 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5334 if (val && val[0]) { 5358 if (val && val[0]) {
5335 n = expand_on_ifs(output, n, val); 5359 n = expand_on_ifs(&ended_in_ifs, output, n, val);
5336 val = NULL; 5360 val = NULL;
5337 } 5361 }
5338 } else { /* quoted $VAR, val will be appended below */ 5362 } else { /* quoted $VAR, val will be appended below */
@@ -5361,6 +5385,10 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5361 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ 5385 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */
5362 5386
5363 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 }
5364 debug_print_list("expand_vars_to_list[a]", output, n); 5392 debug_print_list("expand_vars_to_list[a]", output, n);
5365 /* this part is literal, and it was already pre-quoted 5393 /* this part is literal, and it was already pre-quoted
5366 * if needed (much earlier), do not use o_addQstr here! */ 5394 * if needed (much earlier), do not use o_addQstr here! */
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 @@
1Should be printed 1Should be printed
2Would not be printed by bash
3Would not be printed by bash
4Would not be printed by bash
2Should be printed 5Should be printed
3Empty: 6Empty:
4Empty: 7Empty:
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.
11for a in "$@"""; do echo Should not be printed; done 11for a in "$@"""; do echo Would not be printed by bash; done
12for a in """$@"; do echo Should not be printed; done 12for a in """$@"; do echo Would not be printed by bash; done
13for a in """$@"''"$@"''; do echo Should not be printed; done 13for a in """$@"''"$@"''; do echo Would not be printed by bash; done
14for a in ""; do echo Should be printed; done 14for 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: