diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | src/TOUR | 12 | ||||
-rw-r--r-- | src/eval.c | 2 | ||||
-rw-r--r-- | src/expand.c | 110 | ||||
-rw-r--r-- | src/expand.h | 2 | ||||
-rw-r--r-- | src/jobs.c | 10 | ||||
-rw-r--r-- | src/mystring.c | 3 | ||||
-rw-r--r-- | src/mystring.h | 2 | ||||
-rw-r--r-- | src/parser.c | 17 | ||||
-rw-r--r-- | src/parser.h | 3 | ||||
-rw-r--r-- | src/show.c | 3 |
11 files changed, 64 insertions, 101 deletions
diff --git a/ChangeLog b/ChangeLog index dacc9b3..d5c51bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2007-09-25 Herbert Xu <herbert@gondor.apana.org.au> * Do not expand tilde in parameter expansion within quotes. + * Move parse-time quote flag detection to run-time. 2007-09-24 Herbert Xu <herbert@gondor.apana.org.au> diff --git a/src/TOUR b/src/TOUR index 0c60e2a..4baac62 100644 --- a/src/TOUR +++ b/src/TOUR @@ -159,7 +159,6 @@ special codes defined in parser.h. The special codes are: CTLVAR Variable substitution CTLENDVAR End of variable substitution CTLBACKQ Command substitution - CTLBACKQ|CTLQUOTE Command substitution inside double quotes CTLESC Escape next character A variable substitution contains the following elements: @@ -179,16 +178,13 @@ stitution. The possible types are: VSASSIGN ${var=text} VSASSIGN|VSNUL ${var=text} -In addition, the type field will have the VSQUOTE flag set if the -variable is enclosed in double quotes. The name of the variable -comes next, terminated by an equals sign. If the type is not -VSNORMAL, then the text field in the substitution follows, ter- -minated by a CTLENDVAR byte. +The name of the variable comes next, terminated by an equals +sign. If the type is not VSNORMAL, then the text field in the +substitution follows, terminated by a CTLENDVAR byte. Commands in back quotes are parsed and stored in a linked list. The locations of these commands in the string are indicated by -CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether -the back quotes were enclosed in double quotes. +the CTLBACKQ character. The character CTLESC escapes the next character, so that in case any of the CTL characters mentioned above appear in the input, diff --git a/src/eval.c b/src/eval.c index fed82d5..2aa8317 100644 --- a/src/eval.c +++ b/src/eval.c @@ -377,7 +377,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_RECORD); + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); /* XXX */ if (evalskip) goto out; diff --git a/src/expand.c b/src/expand.c index c9f09ff..8c6c7f9 100644 --- a/src/expand.c +++ b/src/expand.c @@ -82,12 +82,11 @@ */ #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ -#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ /* Add CTLESC when necessary. */ -#define QUOTES_ESC (EXP_FULL | EXP_CASE) +#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) /* Do not skip NUL characters. */ #define QUOTES_KEEPNUL EXP_TILDE @@ -116,7 +115,7 @@ static struct arglist exparg; STATIC void argstr(char *, int); STATIC char *exptilde(char *, char *, int); -STATIC void expbackq(union node *, int, int); +STATIC void expbackq(union node *, int); STATIC const char *subevalvar(char *, char *, int, int, int, int, int); STATIC char *evalvar(char *, int); STATIC size_t strtodest(const char *, const char *, int); @@ -158,11 +157,8 @@ STATIC void varunset(const char *, const char *, const char *, int) */ STATIC inline char * -preglob(const char *pattern, int quoted, int flag) { +preglob(const char *pattern, int flag) { flag |= RMESCAPE_GLOB; - if (quoted) { - flag |= RMESCAPE_QUOTED; - } return _rmescapes((char *)pattern, flag); } @@ -197,7 +193,7 @@ void expandhere(union node *arg, int fd) { herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); + expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); xwrite(fd, stackblock(), expdest - (char *)stackblock()); } @@ -271,13 +267,11 @@ argstr(char *p, int flag) CTLESC, CTLVAR, CTLBACKQ, - CTLBACKQ | CTLQUOTE, CTLENDARI, 0 }; const char *reject = spclchars; int c; - int quotes = flag & QUOTES_ESC; int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; int inquotes; size_t length; @@ -346,21 +340,15 @@ start: case CTLENDVAR: /* ??? */ goto breakloop; case CTLQUOTEMARK: + inquotes ^= EXP_QUOTED; /* "$@" syntax adherence hack */ - if ( - !inquotes && - !memcmp(p, dolatstr, DOLATSTRLEN) && - (p[4] == (char)CTLQUOTEMARK || ( - p[4] == (char)CTLENDVAR && - p[5] == (char)CTLQUOTEMARK - )) - ) { - p = evalvar(p + 1, flag) + 1; + if (inquotes && !memcmp(p, dolatstr + 1, + DOLATSTRLEN - 1)) { + p = evalvar(p + 1, flag | inquotes) + 1; goto start; } - inquotes = !inquotes; addquote: - if (quotes) { + if (flag & QUOTES_ESC) { p--; length++; startloc++; @@ -369,19 +357,27 @@ addquote: case CTLESC: startloc++; length++; + + /* + * Quoted parameter expansion pattern: remove quote + * unless inside inner quotes or we have a literal + * backslash. + */ + if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) == + EXP_QPAT && *p != '\\') + break; + goto addquote; case CTLVAR: - p = evalvar(p, flag); + p = evalvar(p, flag | inquotes); goto start; case CTLBACKQ: - c = 0; - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c, quotes); + expbackq(argbackq->n, flag | inquotes); argbackq = argbackq->next; goto start; case CTLENDARI: p--; - expari(quotes); + expari(flag | inquotes); goto start; } } @@ -480,11 +476,10 @@ removerecordregions(int endoff) * evaluate, place result in (backed up) result, adjust string position. */ void -expari(int quotes) +expari(int flag) { char *p, *start; int begoff; - int flag; int len; /* ifsfree(); */ @@ -522,16 +517,14 @@ expari(int quotes) removerecordregions(begoff); - flag = p[1]; - expdest = p; - if (quotes) - rmescapes(p + 2); + if (flag & QUOTES_ESC) + rmescapes(p + 1); - len = cvtnum(arith(p + 2)); + len = cvtnum(arith(p + 1)); - if (flag != '"') + if (!(flag & EXP_QUOTED)) recordregion(begoff, begoff + len, 0); } @@ -541,7 +534,7 @@ expari(int quotes) */ STATIC void -expbackq(union node *cmd, int quoted, int quotes) +expbackq(union node *cmd, int flag) { struct backcmd in; int i; @@ -549,7 +542,7 @@ expbackq(union node *cmd, int quoted, int quotes) char *p; char *dest; int startloc; - char const *syntax = quoted? DQSYNTAX : BASESYNTAX; + char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; struct stackmark smark; INTOFF; @@ -565,7 +558,7 @@ expbackq(union node *cmd, int quoted, int quotes) if (i == 0) goto read; for (;;) { - memtodest(p, i, syntax, quotes); + memtodest(p, i, syntax, flag & QUOTES_ESC); read: if (in.fd < 0) break; @@ -592,7 +585,7 @@ read: STUNPUTC(dest); expdest = dest; - if (quoted == 0) + if (!(flag & EXP_QUOTED)) recordregion(startloc, dest - (char *)stackblock(), 0); TRACE(("evalbackq: size=%d: \"%.*s\"\n", (dest - (char *)stackblock()) - startloc, @@ -669,8 +662,9 @@ scanright( } STATIC const char * -subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) +subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag) { + int quotes = flag & QUOTES_ESC; char *startp; char *loc; int saveherefd = herefd; @@ -682,7 +676,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla herefd = -1; argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? - EXP_CASE : 0)); + (flag & EXP_QUOTED ? EXP_QPAT : EXP_CASE) : 0)); STPUTC('\0', expdest); herefd = saveherefd; argbackq = saveargbackq; @@ -717,7 +711,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla } rmescend--; str = stackblock() + strloc; - preglob(str, varflags & VSQUOTE, 0); + preglob(str, 0); /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ zero = subtype >> 1; @@ -753,13 +747,11 @@ evalvar(char *p, int flag) int startloc; ssize_t varlen; int easy; - int quotes; int quoted; - quotes = flag & QUOTES_ESC; varflags = *p++; subtype = varflags & VSTYPE; - quoted = varflags & VSQUOTE; + quoted = flag & EXP_QUOTED; var = p; easy = (!quoted || (*var == '@' && shellparam.nparam)); startloc = expdest - (char *)stackblock(); @@ -778,8 +770,7 @@ again: if (subtype == VSMINUS) { vsplus: if (varlen < 0) { - argstr(p, flag | EXP_TILDE | EXP_WORD | - (quoted ? EXP_QUOTED : 0)); + argstr(p, flag | EXP_TILDE | EXP_WORD); goto end; } if (easy) @@ -790,7 +781,7 @@ vsplus: if (subtype == VSASSIGN || subtype == VSQUESTION) { if (varlen < 0) { if (subevalvar(p, var, 0, subtype, startloc, - varflags, 0)) { + varflags, flag & ~QUOTES_ESC)) { varflags &= ~VSNUL; /* * Remove any recorded regions beyond @@ -842,7 +833,7 @@ record: STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); if (subevalvar(p, NULL, patloc, subtype, - startloc, varflags, quotes) == 0) { + startloc, varflags, flag) == 0) { int amount = expdest - ( (char *)stackblock() + patloc - 1 ); @@ -859,7 +850,7 @@ end: for (;;) { if ((c = (signed char)*p++) == CTLESC) p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { + else if (c == CTLBACKQ) { if (varlen >= 0) argbackq = argbackq->next; } else if (c == CTLVAR) { @@ -930,7 +921,7 @@ varvalue(char *name, int varflags, int flags) char sepc; char **ap; char const *syntax; - int quoted = varflags & VSQUOTE; + int quoted = flags & EXP_QUOTED; int subtype = varflags & VSTYPE; int discard = subtype == VSPLUS || subtype == VSLENGTH; int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; @@ -1175,7 +1166,7 @@ expandmeta(str, flag) if (fflag) goto nometa; INTOFF; - p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); i = glob(p, GLOB_NOMAGIC, 0, &pglob); if (p != str->text) ckfree(p); @@ -1244,7 +1235,7 @@ expandmeta(struct strlist *str, int flag) savelastp = exparg.lastp; INTOFF; - p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ @@ -1475,7 +1466,7 @@ msort(struct strlist *list, int len) STATIC inline int patmatch(char *pattern, const char *string) { - return pmatch(preglob(pattern, 0, 0), string); + return pmatch(preglob(pattern, 0), string); } @@ -1651,7 +1642,7 @@ _rmescapes(char *str, int flag) q = mempcpy(q, str, len); } } - inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; + inquotes = 0; globbing = flag & RMESCAPE_GLOB; notescaped = globbing; while (*p) { @@ -1661,15 +1652,14 @@ _rmescapes(char *str, int flag) notescaped = globbing; continue; } - if (*p == '\\') { - /* naked back slash */ - notescaped = 0; - goto copy; - } if (*p == (char)CTLESC) { p++; - if (notescaped && inquotes) + if (notescaped) *q++ = '\\'; + } else if (*p == '\\' && !inquotes) { + /* naked back slash */ + notescaped = 0; + goto copy; } notescaped = globbing; copy: diff --git a/src/expand.h b/src/expand.h index be7ec6f..4dfbc43 100644 --- a/src/expand.h +++ b/src/expand.h @@ -53,7 +53,7 @@ struct arglist { #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ +#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ #define EXP_QUOTED 0x100 /* expand word in double quotes */ diff --git a/src/jobs.c b/src/jobs.c index 7285d0d..529d615 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1377,12 +1377,7 @@ cmdputs(const char *s) str = "${#"; else str = "${"; - if (!(subtype & VSQUOTE) != !(quoted & 1)) { - quoted ^= 1; - c = '"'; - } else - goto dostr; - break; + goto dostr; case CTLENDVAR: str = "\"}" + !(quoted & 1); quoted >>= 1; @@ -1391,9 +1386,6 @@ cmdputs(const char *s) case CTLBACKQ: str = "$(...)"; goto dostr; - case CTLBACKQ+CTLQUOTE: - str = "\"$(...)\""; - goto dostr; case CTLARI: str = "$(("; goto dostr; diff --git a/src/mystring.c b/src/mystring.c index 49201a9..7d937a8 100644 --- a/src/mystring.c +++ b/src/mystring.c @@ -55,7 +55,8 @@ char nullstr[1]; /* zero length string */ const char spcstr[] = " "; const char snlfmt[] = "%s\n"; -const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; +const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', + CTLQUOTEMARK, '\0' }; const char illnum[] = "Illegal number: %s"; const char homestr[] = "HOME"; diff --git a/src/mystring.h b/src/mystring.h index 44fd7e4..f451cc2 100644 --- a/src/mystring.h +++ b/src/mystring.h @@ -39,7 +39,7 @@ extern const char snlfmt[]; extern const char spcstr[]; extern const char dolatstr[]; -#define DOLATSTRLEN 4 +#define DOLATSTRLEN 6 extern const char illnum[]; extern const char homestr[]; diff --git a/src/parser.c b/src/parser.c index e00fd4b..1a483d4 100644 --- a/src/parser.c +++ b/src/parser.c @@ -911,11 +911,9 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) eofmark != NULL ) ) { - USTPUTC(CTLESC, out); USTPUTC('\\', out); } - if (SQSYNTAX[c] == CCTL) - USTPUTC(CTLESC, out); + USTPUTC(CTLESC, out); USTPUTC(c, out); quotef++; } @@ -1221,8 +1219,6 @@ badsub: synerror("Bad substitution"); } else { pungetc(); } - if (dblquote || arinest) - flags |= VSQUOTE; *((char *)stackblock() + typeloc) = subtype | flags; if (subtype != VSNORMAL) { varnest++; @@ -1353,10 +1349,7 @@ done: memcpy(out, str, savelen); STADJUST(savelen, out); } - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); + USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; else @@ -1373,10 +1366,6 @@ parsearith: { syntax = ARISYNTAX; } USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"',out); - else - USTPUTC(' ',out); goto parsearith_return; } @@ -1503,7 +1492,7 @@ expandstr(const char *ps) n.narg.text = wordtext; n.narg.backquote = backquotelist; - expandarg(&n, NULL, 0); + expandarg(&n, NULL, EXP_QUOTED); return stackblock(); } diff --git a/src/parser.h b/src/parser.h index 76ec839..badbd07 100644 --- a/src/parser.h +++ b/src/parser.h @@ -40,8 +40,6 @@ #define CTLVAR -126 /* variable defn */ #define CTLENDVAR -125 #define CTLBACKQ -124 -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == -123 */ #define CTLARI -122 /* arithmetic expression */ #define CTLENDARI -121 #define CTLQUOTEMARK -120 @@ -50,7 +48,6 @@ /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ #define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ diff --git a/src/show.c b/src/show.c index 1b58de1..14dbef3 100644 --- a/src/show.c +++ b/src/show.c @@ -222,7 +222,6 @@ sharg(union node *arg, FILE *fp) putc('}', fp); break; case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: putc('$', fp); putc('(', fp); shtree(bqlist->n, -1, NULL, fp); @@ -314,9 +313,7 @@ trstring(char *s) case '\\': c = '\\'; goto backslash; case CTLESC: c = 'e'; goto backslash; case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; backslash: putc('\\', tracefile); putc(c, tracefile); break; |