Correctly apply IFS to unquoted text in ${x-text}.

Fixes PR/26058 and the 'for i in ${x-a b c}; do ...' and ${x-'a b' c}.
I can't find a PR for the latter problem.
Regression test goind in shortly.
This commit is contained in:
dsl 2004-06-26 22:09:49 +00:00
parent 6d4eb37378
commit c6cbc16d26
4 changed files with 94 additions and 52 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: eval.c,v 1.77 2004/06/26 14:09:58 dsl Exp $ */
/* $NetBSD: eval.c,v 1.78 2004/06/26 22:09:49 dsl Exp $ */
/*-
* Copyright (c) 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
#else
__RCSID("$NetBSD: eval.c,v 1.77 2004/06/26 14:09:58 dsl Exp $");
__RCSID("$NetBSD: eval.c,v 1.78 2004/06/26 22:09:49 dsl Exp $");
#endif
#endif /* not lint */
@ -354,7 +354,7 @@ evalfor(union node *n, int flags)
setstackmark(&smark);
arglist.lastp = &arglist.list;
for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_IFS_SPLIT);
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
if (evalskip)
goto out;
}
@ -702,6 +702,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
arglist.lastp = &arglist.list;
varflag = 1;
/* Expand arguments, ignoring the initial 'name=value' ones */
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;
if (varflag && is_name(*p)) {
@ -718,6 +719,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
expredir(cmd->ncmd.redirect);
/* Now do the initial 'name=value' ones we skipped above */
varlist.lastp = &varlist.list;
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;

View File

@ -1,4 +1,4 @@
/* $NetBSD: expand.c,v 1.65 2004/06/26 20:48:44 dsl Exp $ */
/* $NetBSD: expand.c,v 1.66 2004/06/26 22:09:49 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
#else
__RCSID("$NetBSD: expand.c,v 1.65 2004/06/26 20:48:44 dsl Exp $");
__RCSID("$NetBSD: expand.c,v 1.66 2004/06/26 22:09:49 dsl Exp $");
#endif
#endif /* not lint */
@ -175,9 +175,9 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
/*
* Perform variable and command substitution. If EXP_FULL is set, output CTLESC
* characters to allow for further processing. Otherwise treat
* $@ like $* since no splitting will be performed.
* Perform variable and command substitution.
* If EXP_FULL is set, output CTLESC characters to allow for further processing.
* Otherwise treat $@ like $* since no splitting will be performed.
*/
STATIC void
@ -186,6 +186,11 @@ argstr(char *p, int flag)
char c;
int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
int firsteq = 1;
const char *ifs;
int ifs_split = EXP_IFS_SPLIT;
if (flag & EXP_IFS_SPLIT)
ifs = ifsset() ? ifsval() : " \t\n";
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
p = exptilde(p, flag);
@ -200,6 +205,10 @@ argstr(char *p, int flag)
break;
if ((flag & EXP_FULL) != 0)
STPUTC(c, expdest);
ifs_split = 0;
break;
case CTLQUOTEEND:
ifs_split = EXP_IFS_SPLIT;
break;
case CTLESC:
if (quotes)
@ -208,7 +217,7 @@ argstr(char *p, int flag)
STPUTC(c, expdest);
break;
case CTLVAR:
p = evalvar(p, flag);
p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
break;
case CTLBACKQ:
case CTLBACKQ|CTLQUOTE:
@ -237,6 +246,11 @@ argstr(char *p, int flag)
break;
default:
STPUTC(c, expdest);
if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) {
/* We need to get the output split here... */
recordregion(expdest - stackblock() - 1,
expdest - stackblock(), 0);
}
break;
}
}
@ -685,7 +699,7 @@ again: /* jump here after setting a variable with ${var=text} */
/* FALLTHROUGH */
case VSMINUS:
if (!set) {
argstr(p, flag);
argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
/*
* ${x-a b c} doesn't get split, but removing the
* 'apply_ifs = 0' apparantly breaks ${1+"$@"}..
@ -907,6 +921,11 @@ recordregion(int start, int end, int inquotes)
if (ifslastp == NULL) {
ifsp = &ifsfirst;
} else {
if (ifslastp->endoff == start) {
/* extend previous area */
ifslastp->endoff = end;
return;
}
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
ifslastp->next = ifsp;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: parser.c,v 1.55 2003/08/07 09:05:37 agc Exp $ */
/* $NetBSD: parser.c,v 1.56 2004/06/26 22:09:49 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
#else
__RCSID("$NetBSD: parser.c,v 1.55 2003/08/07 09:05:37 agc Exp $");
__RCSID("$NetBSD: parser.c,v 1.56 2004/06/26 22:09:49 dsl Exp $");
#endif
#endif /* not lint */
@ -961,7 +961,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
#endif
CHECKEND(); /* set c to PEOF if at end of here document */
for (;;) { /* until end of line or end of word */
CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
switch(syntax[c]) {
case CNL: /* '\n' */
if (syntax == BASESYNTAX)
@ -987,57 +987,77 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
if (c == PEOF) {
USTPUTC('\\', out);
pungetc();
} else if (c == '\n') {
break;
}
if (c == '\n') {
if (doprompt)
setprompt(2);
else
setprompt(0);
} else {
if (ISDBLQUOTE() && c != '\\' &&
c != '`' && c != '$' &&
(c != '"' || eofmark != NULL))
USTPUTC('\\', out);
if (SQSYNTAX[c] == CCTL)
USTPUTC(CTLESC, out);
else if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
USTPUTC(c, out);
quotef++;
break;
}
quotef = 1;
if (ISDBLQUOTE() && c != '\\' &&
c != '`' && c != '$' &&
(c != '"' || eofmark != NULL))
USTPUTC('\\', out);
if (SQSYNTAX[c] == CCTL)
USTPUTC(CTLESC, out);
else if (eofmark == NULL) {
USTPUTC(CTLQUOTEMARK, out);
USTPUTC(c, out);
if (varnest != 0)
USTPUTC(CTLQUOTEEND, out);
break;
}
USTPUTC(c, out);
break;
case CSQUOTE:
if (syntax != SQSYNTAX) {
if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
syntax = SQSYNTAX;
break;
if (eofmark == NULL)
USTPUTC(CTLQUOTEMARK, out);
quotef = 1;
syntax = SQSYNTAX;
break;
}
/* FALLTHROUGH */
/* End of single quotes... */
if (arinest)
syntax = ARISYNTAX;
else {
syntax = BASESYNTAX;
if (varnest != 0)
USTPUTC(CTLQUOTEEND, out);
}
break;
case CDQUOTE:
if (eofmark != NULL && arinest == 0 &&
varnest == 0) {
USTPUTC(c, out);
} else {
if (arinest) {
if (c != '"' || ISDBLQUOTE()) {
syntax = ARISYNTAX;
CLRDBLQUOTE();
} else {
syntax = DQSYNTAX;
SETDBLQUOTE();
USTPUTC(CTLQUOTEMARK, out);
}
} else if (eofmark == NULL) {
if (c != '"' || ISDBLQUOTE()) {
syntax = BASESYNTAX;
CLRDBLQUOTE();
} else {
syntax = DQSYNTAX;
SETDBLQUOTE();
USTPUTC(CTLQUOTEMARK, out);
}
break;
}
quotef = 1;
if (arinest) {
if (ISDBLQUOTE()) {
syntax = ARISYNTAX;
CLRDBLQUOTE();
} else {
syntax = DQSYNTAX;
SETDBLQUOTE();
USTPUTC(CTLQUOTEMARK, out);
}
quotef++;
break;
}
if (eofmark != NULL)
break;
if (ISDBLQUOTE()) {
if (varnest != 0)
USTPUTC(CTLQUOTEEND, out);
syntax = BASESYNTAX;
CLRDBLQUOTE();
} else {
syntax = DQSYNTAX;
SETDBLQUOTE();
USTPUTC(CTLQUOTEMARK, out);
}
break;
case CVAR: /* '$' */

View File

@ -1,4 +1,4 @@
/* $NetBSD: parser.h,v 1.16 2003/08/07 09:05:37 agc Exp $ */
/* $NetBSD: parser.h,v 1.17 2004/06/26 22:09:49 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -45,7 +45,8 @@
#define CTLARI '\206' /* arithmetic expression */
#define CTLENDARI '\207'
#define CTLQUOTEMARK '\210'
#define CTL_LAST '\210' /* last 'special' character */
#define CTLQUOTEEND '\211' /* only inside ${...} */
#define CTL_LAST '\211' /* last 'special' character */
/* variable substitution byte (follows CTLVAR) */
#define VSTYPE 0x0f /* type of variable substitution */