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>
This commit is contained in:
parent
a2633aa819
commit
c4d4380a07
14
shell/ash.c
14
shell/ash.c
@ -6606,7 +6606,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
|||||||
* ash -c 'echo ${#1#}' name:'1=#'
|
* ash -c 'echo ${#1#}' name:'1=#'
|
||||||
*/
|
*/
|
||||||
static NOINLINE ssize_t
|
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;
|
const char *p;
|
||||||
int num;
|
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 quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
|
||||||
int syntax = quoted ? DQSYNTAX : BASESYNTAX;
|
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) {
|
switch (*name) {
|
||||||
case '$':
|
case '$':
|
||||||
@ -6664,10 +6665,11 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
|
|||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case '*':
|
case '*':
|
||||||
sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
|
sep |= ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
|
||||||
param:
|
param:
|
||||||
ap = shellparam.p;
|
ap = shellparam.p;
|
||||||
sepc = sep;
|
sepc = sep;
|
||||||
|
*nulonly = !sepc;
|
||||||
if (!ap)
|
if (!ap)
|
||||||
return -1;
|
return -1;
|
||||||
while ((p = *ap++) != NULL) {
|
while ((p = *ap++) != NULL) {
|
||||||
@ -6757,6 +6759,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
|
|||||||
char subtype;
|
char subtype;
|
||||||
int quoted;
|
int quoted;
|
||||||
char easy;
|
char easy;
|
||||||
|
int nulonly;
|
||||||
char *var;
|
char *var;
|
||||||
int patloc;
|
int patloc;
|
||||||
int startloc;
|
int startloc;
|
||||||
@ -6767,11 +6770,12 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
|
|||||||
quoted = flags & EXP_QUOTED;
|
quoted = flags & EXP_QUOTED;
|
||||||
var = p;
|
var = p;
|
||||||
easy = (!quoted || (*var == '@' && shellparam.nparam));
|
easy = (!quoted || (*var == '@' && shellparam.nparam));
|
||||||
|
nulonly = easy;
|
||||||
startloc = expdest - (char *)stackblock();
|
startloc = expdest - (char *)stackblock();
|
||||||
p = strchr(p, '=') + 1; //TODO: use var_end(p)?
|
p = strchr(p, '=') + 1; //TODO: use var_end(p)?
|
||||||
|
|
||||||
again:
|
again:
|
||||||
varlen = varvalue(var, varflags, flags, var_str_list);
|
varlen = varvalue(var, varflags, flags, var_str_list, &nulonly);
|
||||||
if (varflags & VSNUL)
|
if (varflags & VSNUL)
|
||||||
varlen--;
|
varlen--;
|
||||||
|
|
||||||
@ -6865,7 +6869,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
|
|||||||
/* Remove any recorded regions beyond start of variable */
|
/* Remove any recorded regions beyond start of variable */
|
||||||
removerecordregions(startloc);
|
removerecordregions(startloc);
|
||||||
record:
|
record:
|
||||||
recordregion(startloc, expdest - (char *)stackblock(), quoted);
|
recordregion(startloc, expdest - (char *)stackblock(), nulonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
25
shell/ash_test/ash-vars/var_wordsplit_ifs1.right
Normal file
25
shell/ash_test/ash-vars/var_wordsplit_ifs1.right
Normal file
@ -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
|
21
shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
Executable file
21
shell/ash_test/ash-vars/var_wordsplit_ifs1.tests
Executable file
@ -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
|
25
shell/hush_test/hush-vars/var_wordsplit_ifs1.right
Normal file
25
shell/hush_test/hush-vars/var_wordsplit_ifs1.right
Normal file
@ -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
|
21
shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
Executable file
21
shell/hush_test/hush-vars/var_wordsplit_ifs1.tests
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user