sh: Fix some issues with CTL* bytes and ${var#pat}.

subevalvar() incorrectly assumed that CTLESC bytes were present iff the
expansion was quoted. However, they are present iff various processing such
as word splitting is to be done later on.

Example:
  v=@$e@$e@$e@
  y="${v##*"$e"}"
  echo "$y"
failed if $e contained the magic CTLESC byte.

Exp-run done by:	pav (with some other sh(1) changes)
This commit is contained in:
Jilles Tjoelker 2010-10-29 19:34:57 +00:00
parent 67fb1bc8ed
commit 60f7eec450
2 changed files with 35 additions and 14 deletions

View File

@ -98,7 +98,7 @@ static struct arglist exparg; /* holds expanded arg list */
static void argstr(char *, int); static void argstr(char *, int);
static char *exptilde(char *, int); static char *exptilde(char *, int);
static void expbackq(union node *, int, int); static void expbackq(union node *, int, int);
static int subevalvar(char *, char *, int, int, int, int); static int subevalvar(char *, char *, int, int, int, int, int);
static char *evalvar(char *, int); static char *evalvar(char *, int);
static int varisset(char *, int); static int varisset(char *, int);
static void varvalue(char *, int, int, int); static void varvalue(char *, int, int, int);
@ -526,7 +526,7 @@ expbackq(union node *cmd, int quoted, int flag)
static int static int
subevalvar(char *p, char *str, int strloc, int subtype, int startloc, subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
int varflags) int varflags, int quotes)
{ {
char *startp; char *startp;
char *loc = NULL; char *loc = NULL;
@ -571,12 +571,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
for (loc = startp; loc < str; loc++) { for (loc = startp; loc < str; loc++) {
c = *loc; c = *loc;
*loc = '\0'; *loc = '\0';
if (patmatch(str, startp, varflags & VSQUOTE)) { if (patmatch(str, startp, quotes)) {
*loc = c; *loc = c;
goto recordleft; goto recordleft;
} }
*loc = c; *loc = c;
if ((varflags & VSQUOTE) && *loc == CTLESC) if (quotes && *loc == CTLESC)
loc++; loc++;
} }
return 0; return 0;
@ -585,14 +585,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
for (loc = str - 1; loc >= startp;) { for (loc = str - 1; loc >= startp;) {
c = *loc; c = *loc;
*loc = '\0'; *loc = '\0';
if (patmatch(str, startp, varflags & VSQUOTE)) { if (patmatch(str, startp, quotes)) {
*loc = c; *loc = c;
goto recordleft; goto recordleft;
} }
*loc = c; *loc = c;
loc--; loc--;
if ((varflags & VSQUOTE) && loc > startp && if (quotes && loc > startp && *(loc - 1) == CTLESC) {
*(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++) for (q = startp; q < loc; q++)
if (*q == CTLESC) if (*q == CTLESC)
q++; q++;
@ -604,14 +603,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
case VSTRIMRIGHT: case VSTRIMRIGHT:
for (loc = str - 1; loc >= startp;) { for (loc = str - 1; loc >= startp;) {
if (patmatch(str, loc, varflags & VSQUOTE)) { if (patmatch(str, loc, quotes)) {
amount = loc - expdest; amount = loc - expdest;
STADJUST(amount, expdest); STADJUST(amount, expdest);
return 1; return 1;
} }
loc--; loc--;
if ((varflags & VSQUOTE) && loc > startp && if (quotes && loc > startp && *(loc - 1) == CTLESC) {
*(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++) for (q = startp; q < loc; q++)
if (*q == CTLESC) if (*q == CTLESC)
q++; q++;
@ -623,12 +621,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
case VSTRIMRIGHTMAX: case VSTRIMRIGHTMAX:
for (loc = startp; loc < str - 1; loc++) { for (loc = startp; loc < str - 1; loc++) {
if (patmatch(str, loc, varflags & VSQUOTE)) { if (patmatch(str, loc, quotes)) {
amount = loc - expdest; amount = loc - expdest;
STADJUST(amount, expdest); STADJUST(amount, expdest);
return 1; return 1;
} }
if ((varflags & VSQUOTE) && *loc == CTLESC) if (quotes && *loc == CTLESC)
loc++; loc++;
} }
return 0; return 0;
@ -779,7 +777,7 @@ record:
STPUTC('\0', expdest); STPUTC('\0', expdest);
patloc = expdest - stackblock(); patloc = expdest - stackblock();
if (subevalvar(p, NULL, patloc, subtype, if (subevalvar(p, NULL, patloc, subtype,
startloc, varflags) == 0) { startloc, varflags, quotes) == 0) {
int amount = (expdest - stackblock() - patloc) + 1; int amount = (expdest - stackblock() - patloc) + 1;
STADJUST(-amount, expdest); STADJUST(-amount, expdest);
} }
@ -790,7 +788,8 @@ record:
case VSASSIGN: case VSASSIGN:
case VSQUESTION: case VSQUESTION:
if (!set) { if (!set) {
if (subevalvar(p, var, 0, subtype, startloc, varflags)) { if (subevalvar(p, var, 0, subtype, startloc, varflags,
quotes)) {
varflags &= ~VSNUL; varflags &= ~VSNUL;
/* /*
* Remove any recorded regions beyond * Remove any recorded regions beyond

View File

@ -0,0 +1,22 @@
# $FreeBSD$
e=
for i in 0 1 2 3; do
for j in 0 1 2 3 4 5 6 7; do
for k in 0 1 2 3 4 5 6 7; do
case $i$j$k in
000) continue ;;
esac
e="$e\\$i$j$k"
done
done
done
e=$(printf "$e")
v=@$e@$e@
y=${v##*"$e"}
yq="${v##*"$e"}"
[ "$y" = @ ] || echo "error when unquoted in non-splitting context"
[ "$yq" = @ ] || echo "error when quoted in non-splitting context"
[ "${v##*"$e"}" = @ ] || echo "error when quoted in splitting context"
IFS=
[ ${v##*"$e"} = @ ] || echo "error when unquoted in splitting context"