[git commit] ash: expand: Fixed "$@" expansion when EXP_FULL is false

Denys Vlasenko vda.linux at googlemail.com
Sun Oct 2 00:46:56 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=0aaaa50b4551ab5912ccd95d66d633844eac6d85
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Upstream commit:

    Date: Thu, 1 Jan 2015 07:53:10 +1100
    expand: Fixed "$@" expansion when EXP_FULL is false

    The commit 3c06acdac0b1ba0e0acdda513a57ee6e31385dce ([EXPAND]
    Split unquoted $@/$* correctly when IFS is set but empty) broke
    the case where $@ is in quotes and EXP_FULL is false.

    In that case we should still emit IFS as field splitting is not
    performed.

    Reported-by: Juergen Daubert <jue at jue.li>
    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                                        | 28 ++++++++++------------
 shell/ash_test/ash-vars/var_wordsplit_ifs1.right   | 16 +++++++++++++
 shell/ash_test/ash-vars/var_wordsplit_ifs1.tests   | 21 ++++++++++++++++
 shell/hush_test/hush-vars/var_wordsplit_ifs1.right | 16 +++++++++++++
 shell/hush_test/hush-vars/var_wordsplit_ifs1.tests | 21 ++++++++++++++++
 5 files changed, 87 insertions(+), 15 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 731c4b2..4f6ba0c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6615,7 +6615,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
 	int subtype = varflags & VSTYPE;
 	int discard = subtype == VSPLUS || subtype == VSLENGTH;
 	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
-	int syntax = quoted ? DQSYNTAX : BASESYNTAX;
+	int syntax;
+
+	sep = (flags & EXP_FULL) << CHAR_BIT;
+	syntax = quoted ? DQSYNTAX : BASESYNTAX;
 
 	switch (*name) {
 	case '$':
@@ -6649,23 +6652,18 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
 			raise_error_syntax("bad substitution");
 #endif
 		break;
-	case '@': {
+	case '@':
+		if (quoted && sep)
+			goto param;
+		/* fall through */
+	case '*': {
 		char **ap;
 		char sepc;
 
-		sep = 0;
-		if (quoted && (flags & EXP_FULL)) {
-			/* note: this is not meant as PEOF value */
-			sep = 1 << CHAR_BIT;
-			goto param;
-		}
-		/* fall through */
-	case '*':
-		sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
-		if (!quoted) {
+		if (quoted)
+			sep = 0;
+		sep |= ifsset() ? ifsval()[0] : ' ';
  param:
-			sep |= (flags & EXP_FULL) << CHAR_BIT;
-		}
 		sepc = sep;
 		*quotedp = !sepc;
 		ap = shellparam.p;
@@ -6680,7 +6678,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
 			}
 		}
 		break;
-	} /* case '@' and '*' */
+	} /* case '*' */
 	case '0':
 	case '1':
 	case '2':
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.right b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right
index efdafc7..cf583d0 100644
--- a/shell/ash_test/ash-vars/var_wordsplit_ifs1.right
+++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right
@@ -22,4 +22,20 @@ Testing: IFS="" "$*"
 Testing: IFS="" "$@"
 .abc.
 .d e.
+Testing: !IFS v=$*
+v='abc d e'
+Testing: !IFS v=$@
+v='abc d e'
+Testing: !IFS v="$*"
+v='abc d e'
+Testing: !IFS v="$@"
+v='abc d e'
+Testing: IFS="" v=$*
+v='abcd e'
+Testing: IFS="" v=$@
+v='abcd e'
+Testing: IFS="" v="$*"
+v='abcd e'
+Testing: IFS="" v="$@"
+v='abcd e'
 Finished
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
index 532ab99..a62afc6 100755
--- a/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
+++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
@@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done
 echo 'Testing: IFS="" "$@"'
 IFS=""; for a in "$@"; do echo ".$a."; done
 
+echo 'Testing: !IFS v=$*'
+unset IFS; v=$*; echo "v='$v'"
+echo 'Testing: !IFS v=$@'
+unset IFS; v=$@; echo "v='$v'"
+echo 'Testing: !IFS v="$*"'
+unset IFS; v="$*"; echo "v='$v'"
+echo 'Testing: !IFS v="$@"'
+unset IFS; v="$@"; echo "v='$v'"
+
+echo 'Testing: IFS="" v=$*'
+IFS=""; v=$*; echo "v='$v'"
+echo 'Testing: IFS="" v=$@'
+IFS=""; v=$@; echo "v='$v'"
+echo 'Testing: IFS="" v="$*"'
+IFS=""; v="$*"; echo "v='$v'"
+echo 'Testing: IFS="" v="$@"'
+IFS=""; v="$@"; echo "v='$v'"
+
+# Note: in IFS="" v=$@ and IFS="" v="$@" cases, bash produces "abc d e"
+# We produce "abcd e"
+
 echo Finished
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.right b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right
index efdafc7..cf583d0 100644
--- a/shell/hush_test/hush-vars/var_wordsplit_ifs1.right
+++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right
@@ -22,4 +22,20 @@ Testing: IFS="" "$*"
 Testing: IFS="" "$@"
 .abc.
 .d e.
+Testing: !IFS v=$*
+v='abc d e'
+Testing: !IFS v=$@
+v='abc d e'
+Testing: !IFS v="$*"
+v='abc d e'
+Testing: !IFS v="$@"
+v='abc d e'
+Testing: IFS="" v=$*
+v='abcd e'
+Testing: IFS="" v=$@
+v='abcd e'
+Testing: IFS="" v="$*"
+v='abcd e'
+Testing: IFS="" v="$@"
+v='abcd e'
 Finished
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
index 532ab99..a62afc6 100755
--- a/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
+++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
@@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done
 echo 'Testing: IFS="" "$@"'
 IFS=""; for a in "$@"; do echo ".$a."; done
 
+echo 'Testing: !IFS v=$*'
+unset IFS; v=$*; echo "v='$v'"
+echo 'Testing: !IFS v=$@'
+unset IFS; v=$@; echo "v='$v'"
+echo 'Testing: !IFS v="$*"'
+unset IFS; v="$*"; echo "v='$v'"
+echo 'Testing: !IFS v="$@"'
+unset IFS; v="$@"; echo "v='$v'"
+
+echo 'Testing: IFS="" v=$*'
+IFS=""; v=$*; echo "v='$v'"
+echo 'Testing: IFS="" v=$@'
+IFS=""; v=$@; echo "v='$v'"
+echo 'Testing: IFS="" v="$*"'
+IFS=""; v="$*"; echo "v='$v'"
+echo 'Testing: IFS="" v="$@"'
+IFS=""; v="$@"; echo "v='$v'"
+
+# Note: in IFS="" v=$@ and IFS="" v="$@" cases, bash produces "abc d e"
+# We produce "abcd e"
+
 echo Finished


More information about the busybox-cvs mailing list