diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-08-01 14:06:20 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-08-01 14:06:20 +0200 |
commit | 4fb53fb08ce3da8eac13438ce613df20e523c75d (patch) | |
tree | f54399ad4ae2015d87fee1a064354220f16a4f7e | |
parent | 954dbd3a004dcb8df7e1e7283c4e249e02a300a4 (diff) | |
download | busybox-w32-4fb53fb08ce3da8eac13438ce613df20e523c75d.tar.gz busybox-w32-4fb53fb08ce3da8eac13438ce613df20e523c75d.tar.bz2 busybox-w32-4fb53fb08ce3da8eac13438ce613df20e523c75d.zip |
hush: partially fix wrong expansion on $IFS (bug 4027).
In the added testcase, before patch we failed 8 out of 9 tests,
now we fail only 2 (4th and 5th).
function old new delta
expand_on_ifs 225 258 +33
expand_vars_to_list 1038 1054 +16
o_save_ptr_helper 115 119 +4
builtin_umask 132 133 +1
o_addQstr 165 161 -4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 54/-4) Total: 50 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 39 | ||||
-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 |
3 files changed, 50 insertions, 9 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1082738a2..503cb770b 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 | } |
@@ -4754,8 +4755,13 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len | |||
4754 | static int expand_on_ifs(o_string *output, int n, const char *str) | 4755 | static int expand_on_ifs(o_string *output, int n, const char *str) |
4755 | { | 4756 | { |
4756 | while (1) { | 4757 | while (1) { |
4757 | int word_len = strcspn(str, G.ifs); | 4758 | int word_len; |
4759 | |||
4760 | if (!*str) /* EOL - do not finalize word */ | ||
4761 | break; | ||
4762 | word_len = strcspn(str, G.ifs); | ||
4758 | if (word_len) { | 4763 | if (word_len) { |
4764 | /* We have WORD_LEN leading non-IFS chars */ | ||
4759 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { | 4765 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { |
4760 | o_addblock(output, str, word_len); | 4766 | o_addblock(output, str, word_len); |
4761 | } else { | 4767 | } else { |
@@ -4769,13 +4775,25 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
4769 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ | 4775 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ |
4770 | } | 4776 | } |
4771 | str += word_len; | 4777 | str += word_len; |
4778 | if (!*str) /* EOL - do not finalize word */ | ||
4779 | break; | ||
4780 | goto finalize; /* optimization (can just fall thru) */ | ||
4781 | } | ||
4782 | /* Case "v=' a'; echo ''$v": we do need to finalize empty word */ | ||
4783 | if (output->has_quoted_part | ||
4784 | /* Case "v=' a'; echo $v": | ||
4785 | * here nothing precedes the space in $v expansion, | ||
4786 | * therefore we should not finish the word | ||
4787 | * (IOW: if there *is* word to finalize, only then do it) | ||
4788 | */ | ||
4789 | || (output->length && output->data[output->length - 1]) | ||
4790 | ) { | ||
4791 | finalize: | ||
4792 | o_addchr(output, '\0'); | ||
4793 | debug_print_list("expand_on_ifs", output, n); | ||
4794 | n = o_save_ptr(output, n); | ||
4772 | } | 4795 | } |
4773 | if (!*str) /* EOL - do not finalize word */ | 4796 | str += strspn(str, G.ifs); /* skip IFS chars */ |
4774 | break; | ||
4775 | o_addchr(output, '\0'); | ||
4776 | debug_print_list("expand_on_ifs", output, n); | ||
4777 | n = o_save_ptr(output, n); | ||
4778 | str += strspn(str, G.ifs); /* skip ifs chars */ | ||
4779 | } | 4797 | } |
4780 | debug_print_list("expand_on_ifs[1]", output, n); | 4798 | debug_print_list("expand_on_ifs[1]", output, n); |
4781 | return n; | 4799 | return n; |
@@ -5270,11 +5288,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5270 | if (G.ifs[0]) | 5288 | if (G.ifs[0]) |
5271 | o_addchr(output, G.ifs[0]); | 5289 | o_addchr(output, G.ifs[0]); |
5272 | } | 5290 | } |
5291 | output->has_quoted_part = 1; | ||
5273 | } | 5292 | } |
5274 | break; | 5293 | break; |
5275 | } | 5294 | } |
5276 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ | 5295 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ |
5277 | /* "Empty variable", used to make "" etc to not disappear */ | 5296 | /* "Empty variable", used to make "" etc to not disappear */ |
5297 | output->has_quoted_part = 1; | ||
5278 | arg++; | 5298 | arg++; |
5279 | cant_be_null = 0x80; | 5299 | cant_be_null = 0x80; |
5280 | break; | 5300 | break; |
@@ -5316,6 +5336,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5316 | val = NULL; | 5336 | val = NULL; |
5317 | } | 5337 | } |
5318 | } else { /* quoted $VAR, val will be appended below */ | 5338 | } else { /* quoted $VAR, val will be appended below */ |
5339 | output->has_quoted_part = 1; | ||
5319 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, | 5340 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, |
5320 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5341 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
5321 | } | 5342 | } |
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 | ||