aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
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/hush.c
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/hush.c')
-rw-r--r--shell/hush.c82
1 files changed, 55 insertions, 27 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! */