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>
This commit is contained in:
Denys Vlasenko 2011-08-01 14:06:20 +02:00
parent 954dbd3a00
commit 4fb53fb08c
3 changed files with 50 additions and 9 deletions

View File

@ -2281,7 +2281,7 @@ static void o_addqblock(o_string *o, const char *str, int len)
ordinary_cnt = len; ordinary_cnt = len;
o_addblock(o, str, ordinary_cnt); o_addblock(o, str, ordinary_cnt);
if (ordinary_cnt == len) if (ordinary_cnt == len)
return; return; /* NUL is already added by o_addblock */
str += ordinary_cnt; str += ordinary_cnt;
len -= ordinary_cnt + 1; /* we are processing + 1 char below */ len -= ordinary_cnt + 1; /* we are processing + 1 char below */
@ -2295,8 +2295,8 @@ static void o_addqblock(o_string *o, const char *str, int len)
o_grow_by(o, sz); o_grow_by(o, sz);
o->data[o->length] = ch; o->data[o->length] = ch;
o->length++; o->length++;
o->data[o->length] = '\0';
} }
o->data[o->length] = '\0';
} }
static void o_addQblock(o_string *o, const char *str, int len) 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)
n, string_len, string_start); n, string_len, string_start);
o->has_empty_slot = 0; o->has_empty_slot = 0;
} }
o->has_quoted_part = 0;
list[n] = (char*)(uintptr_t)string_len; list[n] = (char*)(uintptr_t)string_len;
return n + 1; return n + 1;
} }
@ -4754,8 +4755,13 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
static int expand_on_ifs(o_string *output, int n, const char *str) static int expand_on_ifs(o_string *output, int n, const char *str)
{ {
while (1) { while (1) {
int word_len = strcspn(str, G.ifs); int word_len;
if (!*str) /* EOL - do not finalize word */
break;
word_len = strcspn(str, G.ifs);
if (word_len) { if (word_len) {
/* We have WORD_LEN leading non-IFS chars */
if (!(output->o_expflags & EXP_FLAG_GLOB)) { if (!(output->o_expflags & EXP_FLAG_GLOB)) {
o_addblock(output, str, word_len); o_addblock(output, str, word_len);
} else { } else {
@ -4769,13 +4775,25 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
/*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */
} }
str += word_len; str += word_len;
if (!*str) /* EOL - do not finalize word */
break;
goto finalize; /* optimization (can just fall thru) */
} }
if (!*str) /* EOL - do not finalize word */ /* Case "v=' a'; echo ''$v": we do need to finalize empty word */
break; if (output->has_quoted_part
o_addchr(output, '\0'); /* Case "v=' a'; echo $v":
debug_print_list("expand_on_ifs", output, n); * here nothing precedes the space in $v expansion,
n = o_save_ptr(output, n); * therefore we should not finish the word
str += strspn(str, G.ifs); /* skip ifs chars */ * (IOW: if there *is* word to finalize, only then do it)
*/
|| (output->length && output->data[output->length - 1])
) {
finalize:
o_addchr(output, '\0');
debug_print_list("expand_on_ifs", output, n);
n = o_save_ptr(output, n);
}
str += strspn(str, G.ifs); /* skip IFS chars */
} }
debug_print_list("expand_on_ifs[1]", output, n); debug_print_list("expand_on_ifs[1]", output, n);
return n; return n;
@ -5270,11 +5288,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
if (G.ifs[0]) if (G.ifs[0])
o_addchr(output, G.ifs[0]); o_addchr(output, G.ifs[0]);
} }
output->has_quoted_part = 1;
} }
break; break;
} }
case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
/* "Empty variable", used to make "" etc to not disappear */ /* "Empty variable", used to make "" etc to not disappear */
output->has_quoted_part = 1;
arg++; arg++;
cant_be_null = 0x80; cant_be_null = 0x80;
break; break;
@ -5316,6 +5336,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
val = NULL; val = NULL;
} }
} else { /* quoted $VAR, val will be appended below */ } else { /* quoted $VAR, val will be appended below */
output->has_quoted_part = 1;
debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
!!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
} }

View File

@ -0,0 +1,9 @@
1 a b c
2 a + b c
3 a b c
4 a b c
5 a b c
6 a b + c
7 a b c
8 a b c
9 a b c

View File

@ -0,0 +1,11 @@
b=' b '
e=''
echo 1 a $b c
echo 2 a +$b c
echo 3 a $e$b c
echo 4 a "$e"$b c
echo 5 a ""$b c
echo 6 a $b+ c
echo 7 a $b$e c
echo 8 a $b"$e" c
echo 9 a $b"" c