summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko2016-10-01 20:35:10 +0200
committerDenys Vlasenko2016-10-01 20:35:10 +0200
commitc4d4380a0700542796887b2e6dbd41e9a7916997 (patch)
treefd6010b5cc072a098e868dfd9bec105ca9bbabcd
parenta2633aa8197a866a7c00406f7eb7e9c9b4554166 (diff)
downloadbusybox-c4d4380a0700542796887b2e6dbd41e9a7916997.zip
busybox-c4d4380a0700542796887b2e6dbd41e9a7916997.tar.gz
ash: [EXPAND] Split unquoted $@/$* correctly when IFS is set but empty
Upstream commit: Date: Wed, 8 Oct 2014 15:24:23 +0800 [EXPAND] Split unquoted $@/$* correctly when IFS is set but empty Currently we do not field-split $@/$* when it isn't quoted and IFS is set but empty. This is obviously wrong. This patch fixes this. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c14
-rw-r--r--shell/ash_test/ash-vars/var_wordsplit_ifs1.right25
-rwxr-xr-xshell/ash_test/ash-vars/var_wordsplit_ifs1.tests21
-rw-r--r--shell/hush_test/hush-vars/var_wordsplit_ifs1.right25
-rwxr-xr-xshell/hush_test/hush-vars/var_wordsplit_ifs1.tests21
5 files changed, 101 insertions, 5 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e4349cc..56dbcb7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6606,7 +6606,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
* ash -c 'echo ${#1#}' name:'1=#'
*/
static NOINLINE ssize_t
-varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
+varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *nulonly)
{
const char *p;
int num;
@@ -6619,7 +6619,8 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
int syntax = quoted ? DQSYNTAX : BASESYNTAX;
- sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+ sep = *nulonly ? (flags & EXP_FULL) << CHAR_BIT : 0;
+ *nulonly = 0;
switch (*name) {
case '$':
@@ -6664,10 +6665,11 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
}
/* fall through */
case '*':
- sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
+ sep |= ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
param:
ap = shellparam.p;
sepc = sep;
+ *nulonly = !sepc;
if (!ap)
return -1;
while ((p = *ap++) != NULL) {
@@ -6757,6 +6759,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
char subtype;
int quoted;
char easy;
+ int nulonly;
char *var;
int patloc;
int startloc;
@@ -6767,11 +6770,12 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
quoted = flags & EXP_QUOTED;
var = p;
easy = (!quoted || (*var == '@' && shellparam.nparam));
+ nulonly = easy;
startloc = expdest - (char *)stackblock();
p = strchr(p, '=') + 1; //TODO: use var_end(p)?
again:
- varlen = varvalue(var, varflags, flags, var_str_list);
+ varlen = varvalue(var, varflags, flags, var_str_list, &nulonly);
if (varflags & VSNUL)
varlen--;
@@ -6865,7 +6869,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
/* Remove any recorded regions beyond start of variable */
removerecordregions(startloc);
record:
- recordregion(startloc, expdest - (char *)stackblock(), quoted);
+ recordregion(startloc, expdest - (char *)stackblock(), nulonly);
}
end:
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.right b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right
new file mode 100644
index 0000000..efdafc7
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right
@@ -0,0 +1,25 @@
+Testing: !IFS $*
+.abc.
+.d.
+.e.
+Testing: !IFS $@
+.abc.
+.d.
+.e.
+Testing: !IFS "$*"
+.abc d e.
+Testing: !IFS "$@"
+.abc.
+.d e.
+Testing: IFS="" $*
+.abc.
+.d e.
+Testing: IFS="" $@
+.abc.
+.d e.
+Testing: IFS="" "$*"
+.abcd e.
+Testing: IFS="" "$@"
+.abc.
+.d e.
+Finished
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
new file mode 100755
index 0000000..532ab99
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
@@ -0,0 +1,21 @@
+set -- abc "d e"
+
+echo 'Testing: !IFS $*'
+unset IFS; for a in $*; do echo ".$a."; done
+echo 'Testing: !IFS $@'
+unset IFS; for a in $@; do echo ".$a."; done
+echo 'Testing: !IFS "$*"'
+unset IFS; for a in "$*"; do echo ".$a."; done
+echo 'Testing: !IFS "$@"'
+unset IFS; for a in "$@"; do echo ".$a."; done
+
+echo 'Testing: IFS="" $*'
+IFS=""; for a in $*; do echo ".$a."; done
+echo 'Testing: IFS="" $@'
+IFS=""; for a in $@; do echo ".$a."; done
+echo 'Testing: IFS="" "$*"'
+IFS=""; for a in "$*"; do echo ".$a."; done
+echo 'Testing: IFS="" "$@"'
+IFS=""; for a in "$@"; do echo ".$a."; done
+
+echo Finished
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.right b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right
new file mode 100644
index 0000000..efdafc7
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right
@@ -0,0 +1,25 @@
+Testing: !IFS $*
+.abc.
+.d.
+.e.
+Testing: !IFS $@
+.abc.
+.d.
+.e.
+Testing: !IFS "$*"
+.abc d e.
+Testing: !IFS "$@"
+.abc.
+.d e.
+Testing: IFS="" $*
+.abc.
+.d e.
+Testing: IFS="" $@
+.abc.
+.d e.
+Testing: IFS="" "$*"
+.abcd e.
+Testing: IFS="" "$@"
+.abc.
+.d e.
+Finished
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
new file mode 100755
index 0000000..532ab99
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
@@ -0,0 +1,21 @@
+set -- abc "d e"
+
+echo 'Testing: !IFS $*'
+unset IFS; for a in $*; do echo ".$a."; done
+echo 'Testing: !IFS $@'
+unset IFS; for a in $@; do echo ".$a."; done
+echo 'Testing: !IFS "$*"'
+unset IFS; for a in "$*"; do echo ".$a."; done
+echo 'Testing: !IFS "$@"'
+unset IFS; for a in "$@"; do echo ".$a."; done
+
+echo 'Testing: IFS="" $*'
+IFS=""; for a in $*; do echo ".$a."; done
+echo 'Testing: IFS="" $@'
+IFS=""; for a in $@; do echo ".$a."; done
+echo 'Testing: IFS="" "$*"'
+IFS=""; for a in "$*"; do echo ".$a."; done
+echo 'Testing: IFS="" "$@"'
+IFS=""; for a in "$@"; do echo ".$a."; done
+
+echo Finished