ash: expand: Fixed "$@" expansion when EXP_FULL is false
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 2 Oct 2016 00:46:56 +0000 (02:46 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 2 Oct 2016 00:46:56 +0000 (02:46 +0200)
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@jue.li>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-vars/var_wordsplit_ifs1.right
shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
shell/hush_test/hush-vars/var_wordsplit_ifs1.right
shell/hush_test/hush-vars/var_wordsplit_ifs1.tests

index 731c4b2b0a3d0712ab0c2db94b5e891cabce66cd..4f6ba0c70d3eb37643304fbb43e48365553f114e 100644 (file)
@@ -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':
index efdafc70ffc3f2682e53addb9eae2f2af39566de..cf583d0aa79f64d1e0f050f6b42b7fdf82e1f9c5 100644 (file)
@@ -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
index 532ab992e57db01a19333133d39f6225a4206dda..a62afc6fd2ee3eef7cf38e96c1595da5bf1a2ed8 100755 (executable)
@@ -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
index efdafc70ffc3f2682e53addb9eae2f2af39566de..cf583d0aa79f64d1e0f050f6b42b7fdf82e1f9c5 100644 (file)
@@ -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
index 532ab992e57db01a19333133d39f6225a4206dda..a62afc6fd2ee3eef7cf38e96c1595da5bf1a2ed8 100755 (executable)
@@ -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