[git commit master 1/1] ash: add a testcase for bug 2281 (currently fails). Small code cleanups.

Denys Vlasenko vda.linux at googlemail.com
Thu Aug 5 15:19:27 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=b0fbe4b5409b136e0c80788cf183ec24237e9c97
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
changepath                                           195     192      -3
subevalvar                                          1204    1200      -4
readtoken1                                          3247    3240      -7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-14)             Total: -14 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                             |   83 +++++++++++++++++++-----------
 shell/ash_test/ash-vars/var_bash3.right |   40 +++++++-------
 shell/ash_test/ash-vars/var_bash3.tests |   47 ++++++++++-------
 shell/ash_test/ash-vars/var_bash4.right |    2 +
 shell/ash_test/ash-vars/var_bash4.tests |    3 +
 5 files changed, 104 insertions(+), 71 deletions(-)
 mode change 100644 => 100755 shell/ash_test/ash-redir/redir9.tests
 create mode 100644 shell/ash_test/ash-vars/var_bash4.right
 create mode 100755 shell/ash_test/ash-vars/var_bash4.tests

diff --git a/shell/ash.c b/shell/ash.c
index d8becc3..16783f2 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6296,13 +6296,14 @@ parse_sub_pattern(char *arg, int inquotes)
 #endif /* ENABLE_ASH_BASH_COMPAT */
 
 static const char *
-subevalvar(char *p, char *str, int strloc, int subtype,
+subevalvar(char *p, char *varname, int strloc, int subtype,
 		int startloc, int varflags, int quotes, struct strlist *var_str_list)
 {
 	struct nodelist *saveargbackq = argbackq;
 	char *startp;
 	char *loc;
 	char *rmesc, *rmescend;
+	char *str;
 	IF_ASH_BASH_COMPAT(const char *repl = NULL;)
 	IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
 	int saveherefd = herefd;
@@ -6310,6 +6311,9 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 	int zero;
 	char *(*scan)(char*, char*, char*, char*, int, int);
 
+	//bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d",
+	//			p, varname, strloc, subtype, startloc, varflags, quotes);
+
 	herefd = -1;
 	argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
 			var_str_list);
@@ -6320,11 +6324,15 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 
 	switch (subtype) {
 	case VSASSIGN:
-		setvar(str, startp, 0);
+		setvar(varname, startp, 0);
 		amount = startp - expdest;
 		STADJUST(amount, expdest);
 		return startp;
 
+	case VSQUESTION:
+		varunset(p, varname, startp, varflags);
+		/* NOTREACHED */
+
 #if ENABLE_ASH_BASH_COMPAT
 	case VSSUBSTR:
 		loc = str = stackblock() + strloc;
@@ -6385,11 +6393,8 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 		STADJUST(amount, expdest);
 		return loc;
 #endif
-
-	case VSQUESTION:
-		varunset(p, str, startp, varflags);
-		/* NOTREACHED */
 	}
+
 	resetloc = expdest - (char *)stackblock();
 
 	/* We'll comeback here if we grow the stack while handling
@@ -6423,13 +6428,14 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 
 		if (!repl) {
 			repl = parse_sub_pattern(str, varflags & VSQUOTE);
+			//bb_error_msg("repl:'%s'", repl);
 			if (!repl)
 				repl = nullstr;
 		}
 
 		/* If there's no pattern to match, return the expansion unmolested */
 		if (str[0] == '\0')
-			return 0;
+			return NULL;
 
 		len = 0;
 		idx = startp;
@@ -6437,6 +6443,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 		while (idx < end) {
  try_to_match:
 			loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
+			//bb_error_msg("scanright('%s'):'%s'", str, loc);
 			if (!loc) {
 				/* No match, advance */
 				char *restart_detect = stackblock();
@@ -6475,6 +6482,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 				idx = loc;
 			}
 
+			//bb_error_msg("repl:'%s'", repl);
 			for (loc = (char*)repl; *loc; loc++) {
 				char *restart_detect = stackblock();
 				if (quotes && *loc == '\\') {
@@ -6510,6 +6518,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
 		STPUTC('\0', expdest);
 		startp = (char *)stackblock() + startloc;
 		memmove(startp, (char *)stackblock() + workloc, len + 1);
+		//bb_error_msg("startp:'%s'", startp);
 		amount = expdest - (startp + len);
 		STADJUST(-amount, expdest);
 		return startp;
@@ -6810,7 +6819,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
 		 */
 		STPUTC('\0', expdest);
 		patloc = expdest - (char *)stackblock();
-		if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype,
+		if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
 				startloc, varflags,
 //TODO: | EXP_REDIR too? All other such places do it too
 				/* quotes: */ flags & (EXP_FULL | EXP_CASE),
@@ -11114,8 +11123,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
 						USTPUTC('\\', out);
 					}
 #endif
-					if (dblquote &&	c != '\\'
-					 && c != '`' &&	c != '$'
+					/* Backslash is retained if we are in "str" and next char isn't special */
+					if (dblquote
+					 && c != '\\'
+					 && c != '`'
+					 && c != '$'
 					 && (c != '"' || eofmark != NULL)
 					) {
 						USTPUTC(CTLESC, out);
@@ -11187,7 +11199,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
 					} else {
 						/*
 						 * unbalanced parens
-						 *  (don't 2nd guess - no error)
+						 * (don't 2nd guess - no error)
 						 */
 						pungetc();
 						USTPUTC(')', out);
@@ -11380,8 +11392,6 @@ parsesub: {
 	unsigned char subtype;
 	int typeloc;
 	int flags;
-	char *p;
-	static const char types[] ALIGN1 = "}-+?=";
 
 	c = pgetc();
 	if (c > 255 /* PEOA or PEOF */
@@ -11394,7 +11404,8 @@ parsesub: {
 #endif
 			USTPUTC('$', out);
 		pungetc();
-	} else if (c == '(') {  /* $(command) or $((arith)) */
+	} else if (c == '(') {
+		/* $(command) or $((arith)) */
 		if (pgetc() == '(') {
 #if ENABLE_SH_MATH_SUPPORT
 			PARSEARITH();
@@ -11406,6 +11417,7 @@ parsesub: {
 			PARSEBACKQNEW();
 		}
 	} else {
+		/* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
 		USTPUTC(CTLVAR, out);
 		typeloc = out - (char *)stackblock();
 		USTPUTC(VSNORMAL, out);
@@ -11415,76 +11427,85 @@ parsesub: {
 			if (c == '#') {
 				c = pgetc();
 				if (c == '}')
-					c = '#';
+					c = '#'; /* ${#} - same as $# */
 				else
-					subtype = VSLENGTH;
-			} else
+					subtype = VSLENGTH; /* ${#VAR} */
+			} else {
 				subtype = 0;
+			}
 		}
 		if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
+			/* $[{[#]]NAME[}] */
 			do {
 				STPUTC(c, out);
 				c = pgetc();
 			} while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
 		} else if (isdigit(c)) {
+			/* $[{[#]]NUM[}] */
 			do {
 				STPUTC(c, out);
 				c = pgetc();
 			} while (isdigit(c));
 		} else if (is_special(c)) {
+			/* $[{[#]]<specialchar>[}] */
 			USTPUTC(c, out);
 			c = pgetc();
 		} else {
  badsub:
 			raise_error_syntax("bad substitution");
 		}
-		if (c != '}' && subtype == VSLENGTH)
+		if (c != '}' && subtype == VSLENGTH) {
+			/* ${#VAR didn't end with } */
 			goto badsub;
+		}
 
 		STPUTC('=', out);
 		flags = 0;
 		if (subtype == 0) {
+			/* ${VAR...} but not $VAR or ${#VAR} */
+			/* c == first char after VAR */
 			switch (c) {
 			case ':':
 				c = pgetc();
 #if ENABLE_ASH_BASH_COMPAT
 				if (c == ':' || c == '$' || isdigit(c)) {
-					pungetc();
 					subtype = VSSUBSTR;
-					break;
+					pungetc();
+					break; /* "goto do_pungetc" is bigger (!) */
 				}
 #endif
 				flags = VSNUL;
 				/*FALLTHROUGH*/
-			default:
-				p = strchr(types, c);
+			default: {
+				static const char types[] ALIGN1 = "}-+?=";
+				const char *p = strchr(types, c);
 				if (p == NULL)
 					goto badsub;
 				subtype = p - types + VSNORMAL;
 				break;
+			}
 			case '%':
 			case '#': {
 				int cc = c;
-				subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
+				subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
 				c = pgetc();
-				if (c == cc)
-					subtype++;
-				else
-					pungetc();
+				if (c != cc)
+					goto do_pungetc;
+				subtype++;
 				break;
 			}
 #if ENABLE_ASH_BASH_COMPAT
 			case '/':
 				subtype = VSREPLACE;
 				c = pgetc();
-				if (c == '/')
-					subtype++; /* VSREPLACEALL */
-				else
-					pungetc();
+				if (c != '/')
+					goto do_pungetc;
+				subtype++; /* VSREPLACEALL */
 				break;
 #endif
 			}
 		} else {
+ do_pungetc:
 			pungetc();
 		}
 		if (dblquote || arinest)
diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests
old mode 100644
new mode 100755
diff --git a/shell/ash_test/ash-vars/var_bash3.right b/shell/ash_test/ash-vars/var_bash3.right
index f7f1479..a97c850 100644
--- a/shell/ash_test/ash-vars/var_bash3.right
+++ b/shell/ash_test/ash-vars/var_bash3.right
@@ -1,20 +1,20 @@
-a041#c
-a041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\c
-a\c
-a\c
-a\\c
-a\\c
-a\\c
-a\tc
-a\tc
-a\tc
-atc
-a\tc
+1 a041#c
+2 a041#c
+3 a\041#c
+4 a\041#c
+5 a\041#c
+6 a\041#c
+7 a\041#c
+8 a\041#c
+9 a\041#c
+10 a\c
+11 a\c
+12 a\c
+13 a\\c
+14 a\\c
+15 a\\c
+16 a\tc
+17 a\tc
+18 a\tc
+19 atc
+20 a\tc
diff --git a/shell/ash_test/ash-vars/var_bash3.tests b/shell/ash_test/ash-vars/var_bash3.tests
index b905027..eca3318 100755
--- a/shell/ash_test/ash-vars/var_bash3.tests
+++ b/shell/ash_test/ash-vars/var_bash3.tests
@@ -1,41 +1,48 @@
 a='abc'
 r=${a//b/\041#}
-echo $r
-echo ${a//b/\041#}
-echo "${a//b/\041#}"
+echo 1 $r
+echo 2 ${a//b/\041#}
+echo 3 "${a//b/\041#}"
+# --- var_bash3.xx
+# +++ var_bash3.right
+# -1 a\041#c
+# +1 a041#c
+#  2 a041#c
+# -3 a041#c
+# +3 a\041#c
 
 a='abc'
 r=${a//b/\\041#}
-echo $r
-echo ${a//b/\\041#}
-echo "${a//b/\\041#}"
+echo 4 $r
+echo 5 ${a//b/\\041#}
+echo 6 "${a//b/\\041#}"
 
 a='abc'
 b='\041#'
 r=${a//b/$b}
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 7 $r
+echo 8 ${a//b/$b}
+echo 9 "${a//b/$b}"
 
 a='abc'
 b='\'
 r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 10 $r
+echo 11 ${a//b/$b}
+echo 12 "${a//b/$b}"
 
 a='abc'
 b='\\'
 r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 13 $r
+echo 14 ${a//b/$b}
+echo 15 "${a//b/$b}"
 
 a='abc'
 b='\t'
 r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
-echo ${a//b/\t}
-echo "${a//b/\t}"
+echo 16 $r
+echo 17 ${a//b/$b}
+echo 18 "${a//b/$b}"
+echo 19 ${a//b/\t}
+echo 20 "${a//b/\t}"
diff --git a/shell/ash_test/ash-vars/var_bash4.right b/shell/ash_test/ash-vars/var_bash4.right
new file mode 100644
index 0000000..33a5112
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash4.right
@@ -0,0 +1,2 @@
+a*b-backslashstar-
+Done: 0
diff --git a/shell/ash_test/ash-vars/var_bash4.tests b/shell/ash_test/ash-vars/var_bash4.tests
new file mode 100755
index 0000000..304b3d9
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash4.tests
@@ -0,0 +1,3 @@
+FOO='a*b\*c'
+echo "${FOO//\\*/-backslashstar-}"
+echo Done: $?
-- 
1.7.1



More information about the busybox-cvs mailing list