summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r--bin/sh/expand.c157
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).
*/
OpenPOWER on IntegriCloud