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>
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 '$':
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;
}
}
break;
- } /* case '@' and '*' */
+ } /* case '*' */
case '0':
case '1':
case '2':
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
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
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
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