diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-09-25 22:29:00 +0800 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2007-09-25 22:29:00 +0800 |
commit | 7cfd8be0dc83342b4a71f3a8e5b7efab4670e50c (patch) | |
tree | 58bea2cd50124e8599e4ebdbbd2f622138bdc8c2 /src/expand.c | |
parent | [EXPAND] Do not expand tilde in parameter expansion within quotes (diff) | |
download | dash-7cfd8be0dc83342b4a71f3a8e5b7efab4670e50c.tar.gz dash-7cfd8be0dc83342b4a71f3a8e5b7efab4670e50c.zip |
[EXPAND] Move parse-time quote flag detection to run-time
Because the parser does not recursively parse parameter expansion with respect to quotes, we can't accurately determine quote status at parse time. This patch works around this by moving the quote detection to run-time where we do interpret it recursively. Test case: foo=\\ echo "<${foo#[\\]}>" Old result: <\> New result: <>
Diffstat (limited to 'src/expand.c')
-rw-r--r-- | src/expand.c | 110 |
1 files changed, 50 insertions, 60 deletions
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: |