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.
This commit is contained in:
Jilles Tjoelker 2014-03-02 22:59:34 +00:00
parent 45b1c8bbda
commit ce16da82dd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=262697

View File

@ -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;
}