summary refs log tree commit diff
path: root/src/expand.c
diff options
context:
space:
mode:
authorherbert <herbert@gondor.apana.org.au>2004-08-21 10:01:16 +1000
committerHerbert Xu <herbert@gondor.apana.org.au>2005-09-26 18:33:02 +1000
commitc989d7247f879a2932adcfb3fcdcd8c465f73e67 (patch)
tree15447a65a58170458942ce2b4fe81a914f0a6aed /src/expand.c
parentFixed expansion when leading argument is null in src/expand.c. (diff)
downloaddash-c989d7247f879a2932adcfb3fcdcd8c465f73e67.tar.gz
dash-c989d7247f879a2932adcfb3fcdcd8c465f73e67.zip
Size optimisations around varvalue() in src/expand.c.
Diffstat (limited to 'src/expand.c')
-rw-r--r--src/expand.c84
1 files changed, 39 insertions, 45 deletions
diff --git a/src/expand.c b/src/expand.c
index b2800c6..7d7f815 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -97,6 +97,11 @@ __RCSID("$NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $");
 #define RMESCAPE_GROW	0x8	/* Grow strings instead of stalloc */
 #define RMESCAPE_HEAP	0x10	/* Malloc strings instead of stalloc */
 
+/* Add CTLESC when necessary. */
+#define QUOTES_ESC	(EXP_FULL | EXP_CASE)
+/* Do not skip NUL characters. */
+#define QUOTES_KEEPNUL	EXP_TILDE
+
 /*
  * Structure specifying which parts of the string should be searched
  * for IFS characters.
@@ -125,7 +130,7 @@ STATIC char *exptilde(char *, char *, int);
 STATIC void expbackq(union node *, int, int);
 STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
 STATIC char *evalvar(char *, int);
-STATIC void strtodest(const char *, const char *, int);
+STATIC size_t strtodest(const char *, const char *, int);
 STATIC void memtodest(const char *, size_t, const char *, int);
 STATIC ssize_t varvalue(char *, int, int);
 STATIC void recordregion(int, int, int);
@@ -272,7 +277,7 @@ argstr(char *p, int flag)
 	};
 	const char *reject = spclchars;
 	int c;
-	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
+	int quotes = flag & QUOTES_ESC;
 	int breakall = flag & EXP_WORD;
 	int inquotes;
 	size_t length;
@@ -393,7 +398,7 @@ exptilde(char *startp, char *p, int flag)
 	char *name;
 	struct passwd *pw;
 	const char *home;
-	int quotes = flag & (EXP_FULL | EXP_CASE);
+	int quotes = flag & QUOTES_ESC;
 	int startloc;
 
 	name = p + 1;
@@ -756,7 +761,7 @@ evalvar(char *p, int flag)
 	int quotes;
 	int quoted;
 
-	quotes = flag & (EXP_FULL | EXP_CASE);
+	quotes = flag & QUOTES_ESC;
 	varflags = *p++;
 	subtype = varflags & VSTYPE;
 	quoted = varflags & VSQUOTE;
@@ -883,30 +888,37 @@ end:
 
 STATIC void
 memtodest(const char *p, size_t len, const char *syntax, int quotes) {
-	char *q = expdest;
+	char *q;
 
-	q = makestrspace(len * 2, q);
+	if (unlikely(!len))
+		return;
 
-	while (len--) {
+	q = makestrspace(len * 2, expdest);
+
+	do {
 		int c = *p++;
-		if (!c)
+		if (c) {
+			if ((quotes & QUOTES_ESC) &&
+			    (syntax[c] == CCTL || syntax[c] == CBACK))
+				USTPUTC(CTLESC, q);
+		} else if (!(quotes & QUOTES_KEEPNUL))
 			continue;
-		if (quotes && (syntax[c] == CCTL || syntax[c] == CBACK))
-			USTPUTC(CTLESC, q);
 		USTPUTC(c, q);
-	}
+	} while (--len);
 
 	expdest = q;
 }
 
 
-STATIC void
+STATIC size_t
 strtodest(p, syntax, quotes)
 	const char *p;
 	const char *syntax;
 	int quotes;
 {
-	memtodest(p, strlen(p), syntax, quotes);
+	size_t len = strlen(p);
+	memtodest(p, len, syntax, quotes);
+	return len;
 }
 
 
@@ -921,19 +933,19 @@ varvalue(char *name, int varflags, int flags)
 	int num;
 	char *p;
 	int i;
-	int sep = 0;
-	int sepq = 0;
-	ssize_t len = 0;
+	int sep;
+	char sepc;
 	char **ap;
 	char const *syntax;
 	int quoted = varflags & VSQUOTE;
 	int subtype = varflags & VSTYPE;
-	int quotes = flags & (EXP_FULL | EXP_CASE);
-
-	if (quoted && (flags & EXP_FULL))
-		sep = 1 << CHAR_BIT;
+	int discard = subtype == VSPLUS || subtype == VSLENGTH;
+	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
+	ssize_t len = 0;
 
+	sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
 	syntax = quoted ? DQSYNTAX : BASESYNTAX;
+
 	switch (*name) {
 	case '$':
 		num = rootpid;
@@ -967,35 +979,19 @@ numvar:
 		/* fall through */
 	case '*':
 		sep = ifsset() ? ifsval()[0] : ' ';
-		if (quotes && (syntax[sep] == CCTL || syntax[sep] == CBACK))
-			sepq = 1;
 param:
 		if (!(ap = shellparam.p))
 			return -1;
+		sepc = sep;
 		while ((p = *ap++)) {
-			size_t partlen;
-
-			partlen = strlen(p);
-			len += partlen;
-
-			if (!(subtype == VSPLUS || subtype == VSLENGTH))
-				memtodest(p, partlen, syntax, quotes);
+			len += strtodest(p, syntax, quotes);
 
 			if (*ap && sep) {
-				char *q;
-
 				len++;
-				if (subtype == VSPLUS || subtype == VSLENGTH) {
-					continue;
-				}
-				q = expdest;
-				if (sepq)
-					STPUTC(CTLESC, q);
-				STPUTC(sep, q);
-				expdest = q;
+				memtodest(&sepc, 1, syntax, quotes);
 			}
 		}
-		return len;
+		break;
 	case '0':
 	case '1':
 	case '2':
@@ -1017,13 +1013,11 @@ value:
 		if (!p)
 			return -1;
 
-		len = strlen(p);
-		if (!(subtype == VSPLUS || subtype == VSLENGTH))
-			memtodest(p, len, syntax, quotes);
-		return len;
+		len = strtodest(p, syntax, quotes);
+		break;
 	}
 
-	if (subtype == VSPLUS || subtype == VSLENGTH)
+	if (discard)
 		STADJUST(-len, expdest);
 	return len;
 }