ash: expand: Fixed "$@" expansion when EXP_FULL is false

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>
This commit is contained in:
Denys Vlasenko 2016-10-02 02:46:56 +02:00
parent 42eeb255c1
commit 0aaaa50b45
5 changed files with 87 additions and 15 deletions

View File

@ -6615,7 +6615,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
int subtype = varflags & VSTYPE; int subtype = varflags & VSTYPE;
int discard = subtype == VSPLUS || subtype == VSLENGTH; int discard = subtype == VSPLUS || subtype == VSLENGTH;
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 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) { switch (*name) {
case '$': case '$':
@ -6649,23 +6652,18 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
raise_error_syntax("bad substitution"); raise_error_syntax("bad substitution");
#endif #endif
break; break;
case '@': { case '@':
if (quoted && sep)
goto param;
/* fall through */
case '*': {
char **ap; char **ap;
char sepc; char sepc;
if (quoted)
sep = 0; sep = 0;
if (quoted && (flags & EXP_FULL)) { sep |= ifsset() ? ifsval()[0] : ' ';
/* 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) {
param: param:
sep |= (flags & EXP_FULL) << CHAR_BIT;
}
sepc = sep; sepc = sep;
*quotedp = !sepc; *quotedp = !sepc;
ap = shellparam.p; ap = shellparam.p;
@ -6680,7 +6678,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
} }
} }
break; break;
} /* case '@' and '*' */ } /* case '*' */
case '0': case '0':
case '1': case '1':
case '2': case '2':

View File

@ -22,4 +22,20 @@ Testing: IFS="" "$*"
Testing: IFS="" "$@" Testing: IFS="" "$@"
.abc. .abc.
.d e. .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 Finished

View File

@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done
echo 'Testing: IFS="" "$@"' echo 'Testing: IFS="" "$@"'
IFS=""; for a in "$@"; do echo ".$a."; done 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 echo Finished

View File

@ -22,4 +22,20 @@ Testing: IFS="" "$*"
Testing: IFS="" "$@" Testing: IFS="" "$@"
.abc. .abc.
.d e. .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 Finished

View File

@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done
echo 'Testing: IFS="" "$@"' echo 'Testing: IFS="" "$@"'
IFS=""; for a in "$@"; do echo ".$a."; done 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 echo Finished