summaryrefslogtreecommitdiffstats
path: root/bin/sh
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2014-03-02 22:59:34 +0000
committerjilles <jilles@FreeBSD.org>2014-03-02 22:59:34 +0000
commitd941f4e61cbf24c9b151ec7818bcc6c91ea85031 (patch)
tree08b6007f5b355994afc0c1ae759393786e10d20a /bin/sh
parentf13342ade493ec4dd025f15d53d7f37aa845c538 (diff)
downloadFreeBSD-src-d941f4e61cbf24c9b151ec7818bcc6c91ea85031.zip
FreeBSD-src-d941f4e61cbf24c9b151ec7818bcc6c91ea85031.tar.gz
sh: Simplify expari().
Redo expari() like evalvar(). This makes the logic more understandable and avoids possible problems if arithmetic expansion occurs if CTLESC characters are not generated (looking backwards for CTLARI is not generally possible in that case but the old code tried anyway). This adds an extra argstr() recursion.
Diffstat (limited to 'bin/sh')
-rw-r--r--bin/sh/expand.c94
1 files changed, 46 insertions, 48 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index be07e6c..cad0116 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -100,7 +100,7 @@ static struct arglist exparg; /* holds expanded arg list */
static void argstr(char *, int);
static char *exptilde(char *, int);
-static void expari(int);
+static char *expari(char *);
static void expbackq(union node *, int, int);
static int subevalvar(char *, char *, int, int, int, int, int);
static char *evalvar(char *, int);
@@ -207,7 +207,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
/*
* Perform parameter expansion, command substitution and arithmetic
* expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
- * Processing ends at a CTLENDVAR character as well as '\0'.
+ * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
* This is used to expand word in ${var+word} etc.
* If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
* characters to allow for further processing.
@@ -232,6 +232,7 @@ argstr(char *p, int flag)
switch (c = *p++) {
case '\0':
case CTLENDVAR:
+ case CTLENDARI:
goto breakloop;
case CTLQUOTEMARK:
lit_quoted = 1;
@@ -262,8 +263,8 @@ argstr(char *p, int flag)
expbackq(argbackq->n, c & CTLQUOTE, flag);
argbackq = argbackq->next;
break;
- case CTLENDARI:
- expari(flag);
+ case CTLARI:
+ p = expari(p);
break;
case ':':
case '=':
@@ -388,59 +389,56 @@ removerecordregions(int endoff)
}
/*
- * Expand arithmetic expression. Backup to start of expression,
- * evaluate, place result in (backed up) result, adjust string position.
+ * Expand arithmetic expression.
+ * Note that flag is not required as digits never require CTLESC characters.
*/
-static void
-expari(int flag)
+static char *
+expari(char *p)
{
- char *p, *q, *start;
+ char *q, *start;
arith_t result;
int begoff;
- int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
int quoted;
+ int c;
+ int nesting;
+ int adj;
- /*
- * This routine is slightly over-complicated for
- * efficiency. First we make sure there is
- * enough space for the result, which may be bigger
- * than the expression. Next we
- * scan backwards looking for the start of arithmetic. If the
- * next previous character is a CTLESC character, then we
- * have to rescan starting from the beginning since CTLESC
- * characters have to be processed left to right.
- */
- CHECKSTRSPACE(DIGITS(result) - 2, expdest);
- USTPUTC('\0', expdest);
- start = stackblock();
- p = expdest - 2;
- while (p >= start && *p != CTLARI)
- --p;
- if (p < start || *p != CTLARI)
- error("missing CTLARI (shouldn't happen)");
- if (p > start && *(p - 1) == CTLESC)
- for (p = start; *p != CTLARI; p++)
- if (*p == CTLESC)
- p++;
-
- if (p[1] == '"')
- quoted=1;
- else
- quoted=0;
- begoff = p - start;
+ quoted = *p++ == '"';
+ begoff = expdest - stackblock();
+ argstr(p, 0);
removerecordregions(begoff);
- if (quotes)
- rmescapes(p+2);
+ STPUTC('\0', expdest);
+ start = stackblock() + begoff;
+
q = grabstackstr(expdest);
- result = arith(p+2);
+ result = arith(start);
ungrabstackstr(q, expdest);
- fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
- while (*p++)
- ;
- if (quoted == 0)
- recordregion(begoff, p - 1 - start, 0);
- result = expdest - p + 1;
- STADJUST(-result, expdest);
+
+ start = stackblock() + begoff;
+ adj = start - expdest;
+ STADJUST(adj, expdest);
+
+ CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
+ fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
+ adj = strlen(expdest);
+ STADJUST(adj, expdest);
+ if (!quoted)
+ recordregion(begoff, expdest - stackblock(), 0);
+ nesting = 1;
+ while (nesting > 0) {
+ c = *p++;
+ if (c == CTLESC)
+ p++;
+ else if (c == CTLARI)
+ nesting++;
+ else if (c == CTLENDARI)
+ nesting--;
+ else if (c == CTLVAR)
+ p++; /* ignore variable substitution byte */
+ else if (c == '\0')
+ return p - 1;
+ }
+ return p;
}
OpenPOWER on IntegriCloud