diff options
author | Denys Vlasenko | 2016-10-01 20:35:10 +0200 |
---|---|---|
committer | Denys Vlasenko | 2016-10-01 20:35:10 +0200 |
commit | c4d4380a0700542796887b2e6dbd41e9a7916997 (patch) | |
tree | fd6010b5cc072a098e868dfd9bec105ca9bbabcd | |
parent | a2633aa8197a866a7c00406f7eb7e9c9b4554166 (diff) | |
download | busybox-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.c | 14 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var_wordsplit_ifs1.right | 25 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var_wordsplit_ifs1.tests | 21 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_wordsplit_ifs1.right | 25 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_wordsplit_ifs1.tests | 21 |
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 |