diff options
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r-- | bin/sh/expand.c | 157 |
1 files changed, 110 insertions, 47 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 7a3b9d9..9c088c9 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -132,11 +132,22 @@ collate_range_cmp(int c1, int c2) void expandhere(union node *arg, int fd) { - herefd = fd; expandarg(arg, (struct arglist *)NULL, 0); xwrite(fd, stackblock(), expdest - stackblock()); } +static char * +stputs_quotes(const char *data, const char *syntax, char *p) +{ + while (*data) { + CHECKSTRSPACE(2, p); + if (syntax[(int)*data] == CCTL) + USTPUTC(CTLESC, p); + USTPUTC(*data++, p); + } + return (p); +} +#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p) /* * Perform expansions on an argument, placing the resulting list of arguments @@ -144,8 +155,7 @@ expandhere(union node *arg, int fd) * expansion are always performed; additional expansions can be requested * via flag (EXP_*). * The result is left in the stack string. - * When arglist is NULL, perform here document expansion. A partial result - * may be written to herefd, which is then not included in the stack string. + * When arglist is NULL, perform here document expansion. * * Caution: this function uses global state and is not reentrant. * However, a new invocation after an interrupted invocation is safe @@ -334,11 +344,10 @@ done: if (*home == '\0') goto lose; *p = c; - while ((c = *home++) != '\0') { - if (quotes && SQSYNTAX[(int)c] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(c, expdest); - } + if (quotes) + STPUTS_QUOTES(home, SQSYNTAX, expdest); + else + STPUTS(home, expdest); return (p); lose: *p = c; @@ -458,7 +467,6 @@ expbackq(union node *cmd, int quoted, int flag) char lastc; int startloc = dest - stackblock(); char const *syntax = quoted? DQSYNTAX : BASESYNTAX; - int saveherefd; int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); int nnl; @@ -466,15 +474,12 @@ expbackq(union node *cmd, int quoted, int flag) saveifs = ifsfirst; savelastp = ifslastp; saveargbackq = argbackq; - saveherefd = herefd; - herefd = -1; p = grabstackstr(dest); evalbackcmd(cmd, &in); ungrabstackstr(p, dest); ifsfirst = saveifs; ifslastp = savelastp; argbackq = saveargbackq; - herefd = saveherefd; p = in.buf; lastc = '\0'; @@ -493,16 +498,17 @@ expbackq(union node *cmd, int quoted, int flag) } lastc = *p++; if (lastc != '\0') { - if (quotes && syntax[(int)lastc] == CCTL) - STPUTC(CTLESC, dest); if (lastc == '\n') { nnl++; } else { + CHECKSTRSPACE(nnl + 2, dest); while (nnl > 0) { nnl--; - STPUTC('\n', dest); + USTPUTC('\n', dest); } - STPUTC(lastc, dest); + if (quotes && syntax[(int)lastc] == CCTL) + USTPUTC(CTLESC, dest); + USTPUTC(lastc, dest); } } } @@ -533,16 +539,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, char *loc = NULL; char *q; int c = 0; - int saveherefd = herefd; struct nodelist *saveargbackq = argbackq; int amount; - herefd = -1; argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ? EXP_CASE : 0) | EXP_TILDE); STACKSTRNUL(expdest); - herefd = saveherefd; argbackq = saveargbackq; startp = stackblock() + startloc; if (str == NULL) @@ -554,8 +557,6 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, amount = startp - expdest; STADJUST(amount, expdest); varflags &= ~VSNUL; - if (c != 0) - *loc = c; return 1; case VSQUESTION: @@ -723,12 +724,10 @@ again: /* jump here after setting a variable with ${var=text} */ varlen++; } else { - while (*val) { - if (quotes && - syntax[(int)*val] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*val++, expdest); - } + if (quotes) + STPUTS_QUOTES(val, syntax, expdest); + else + STPUTS(val, expdest); } } @@ -877,7 +876,14 @@ varisset(char *name, int nulok) return 1; } - +static void +strtodest(const char *p, int flag, int subtype, int quoted) +{ + if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) + STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest); + else + STPUTS(p, expdest); +} /* * Add the value of a specialized variable to the stack string. @@ -891,21 +897,6 @@ varvalue(char *name, int quoted, int subtype, int flag) int i; char sep; char **ap; - char const *syntax; - -#define STRTODEST(p) \ - do {\ - if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \ - syntax = quoted? DQSYNTAX : BASESYNTAX; \ - while (*p) { \ - if (syntax[(int)*p] == CCTL) \ - STPUTC(CTLESC, expdest); \ - STPUTC(*p++, expdest); \ - } \ - } else \ - STPUTS(p, expdest); \ - } while (0) - switch (*name) { case '$': @@ -931,7 +922,7 @@ numvar: case '@': if (flag & EXP_FULL && quoted) { for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - STRTODEST(p); + strtodest(p, flag, subtype, quoted); if (*ap) STPUTC('\0', expdest); } @@ -944,21 +935,21 @@ numvar: else sep = ' '; for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - STRTODEST(p); + strtodest(p, flag, subtype, quoted); if (*ap && sep) STPUTC(sep, expdest); } break; case '0': p = arg0; - STRTODEST(p); + strtodest(p, flag, subtype, quoted); break; default: if (is_digit(*name)) { num = atoi(name); if (num > 0 && num <= shellparam.nparam) { p = shellparam.p[num - 1]; - STRTODEST(p); + strtodest(p, flag, subtype, quoted); } } break; @@ -1578,6 +1569,78 @@ cvtnum(int num, char *buf) } /* + * Check statically if expanding a string may have side effects. + */ +int +expandhassideeffects(const char *p) +{ + int c; + int arinest; + + arinest = 0; + while ((c = *p++) != '\0') { + switch (c) { + case CTLESC: + p++; + break; + case CTLVAR: + c = *p++; + /* Expanding $! sets the job to remembered. */ + if (*p == '!') + return 1; + if ((c & VSTYPE) == VSASSIGN) + return 1; + /* + * If we are in arithmetic, the parameter may contain + * '=' which may cause side effects. Exceptions are + * the length of a parameter and $$, $# and $? which + * are always numeric. + */ + if ((c & VSTYPE) == VSLENGTH) { + while (*p != '=') + p++; + p++; + break; + } + if ((*p == '$' || *p == '#' || *p == '?') && + p[1] == '=') { + p += 2; + break; + } + if (arinest > 0) + return 1; + break; + case CTLBACKQ: + case CTLBACKQ | CTLQUOTE: + if (arinest > 0) + return 1; + break; + case CTLARI: + arinest++; + break; + case CTLENDARI: + arinest--; + break; + case '=': + if (*p == '=') { + /* Allow '==' operator. */ + p++; + continue; + } + if (arinest > 0) + return 1; + break; + case '!': case '<': case '>': + /* Allow '!=', '<=', '>=' operators. */ + if (*p == '=') + p++; + break; + } + } + return 0; +} + +/* * Do most of the work for wordexp(3). */ |