aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJilles Tjoelker <jilles@FreeBSD.org>2014-03-02 22:59:34 +0000
committerJilles Tjoelker <jilles@FreeBSD.org>2014-03-02 22:59:34 +0000
commitce16da82ddb6b93243b141b8ab9ce9199e58b7fa (patch)
tree08b6007f5b355994afc0c1ae759393786e10d20a
parent45b1c8bbda1a9a980553831679145e8b2f50c6ae (diff)
downloadsrc-ce16da82ddb6b93243b141b8ab9ce9199e58b7fa.tar.gz
src-ce16da82ddb6b93243b141b8ab9ce9199e58b7fa.zip
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.
Notes
Notes: svn path=/head/; revision=262697
-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 be07e6c90848..cad0116fba3c 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;
}