summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko2011-08-01 14:06:20 +0200
committerDenys Vlasenko2011-08-01 14:06:20 +0200
commit4fb53fb08ce3da8eac13438ce613df20e523c75d (patch)
treef54399ad4ae2015d87fee1a064354220f16a4f7e /shell
parent954dbd3a004dcb8df7e1e7283c4e249e02a300a4 (diff)
downloadbusybox-4fb53fb08ce3da8eac13438ce613df20e523c75d.zip
busybox-4fb53fb08ce3da8eac13438ce613df20e523c75d.tar.gz
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>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c39
-rw-r--r--shell/hush_test/hush-vars/var_expand_on_ifs.right9
-rwxr-xr-xshell/hush_test/hush-vars/var_expand_on_ifs.tests11
3 files changed, 50 insertions, 9 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 1082738..503cb77 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)
ordinary_cnt = len;
o_addblock(o, str, ordinary_cnt);
if (ordinary_cnt == len)
- return;
+ return; /* NUL is already added by o_addblock */
str += ordinary_cnt;
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->data[o->length] = ch;
o->length++;
- o->data[o->length] = '\0';
}
+ o->data[o->length] = '\0';
}
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);
o->has_empty_slot = 0;
}
+ o->has_quoted_part = 0;
list[n] = (char*)(uintptr_t)string_len;
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)
{
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) {
+ /* We have WORD_LEN leading non-IFS chars */
if (!(output->o_expflags & EXP_FLAG_GLOB)) {
o_addblock(output, str, word_len);
} 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 */
}
str += word_len;
+ if (!*str) /* EOL - do not finalize word */
+ break;
+ goto finalize; /* optimization (can just fall thru) */
+ }
+ /* Case "v=' a'; echo ''$v": we do need to finalize empty word */
+ if (output->has_quoted_part
+ /* Case "v=' a'; echo $v":
+ * here nothing precedes the space in $v expansion,
+ * therefore we should not finish the word
+ * (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);
}
- if (!*str) /* EOL - do not finalize word */
- break;
- 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 */
+ str += strspn(str, G.ifs); /* skip IFS chars */
}
debug_print_list("expand_on_ifs[1]", output, 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])
o_addchr(output, G.ifs[0]);
}
+ output->has_quoted_part = 1;
}
break;
}
case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
/* "Empty variable", used to make "" etc to not disappear */
+ output->has_quoted_part = 1;
arg++;
cant_be_null = 0x80;
break;
@@ -5316,6 +5336,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
val = NULL;
}
} else { /* quoted $VAR, val will be appended below */
+ output->has_quoted_part = 1;
debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
!!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
}
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 0000000..2ed2069
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_expand_on_ifs.right
@@ -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
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 0000000..a12ff8e
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_expand_on_ifs.tests
@@ -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