svn commit: r262697 - head/bin/sh

Jilles Tjoelker jilles at FreeBSD.org
Sun Mar 2 22:59:35 UTC 2014


Author: jilles
Date: Sun Mar  2 22:59:34 2014
New Revision: 262697
URL: http://svnweb.freebsd.org/changeset/base/262697

Log:
  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.

Modified:
  head/bin/sh/expand.c

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c	Sun Mar  2 21:25:32 2014	(r262696)
+++ head/bin/sh/expand.c	Sun Mar  2 22:59:34 2014	(r262697)
@@ -100,7 +100,7 @@ static struct arglist exparg;		/* holds 
 
 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 arglis
 /*
  * 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;
 }
 
 


More information about the svn-src-all mailing list