ash: [EXPAND] Do not split quoted VSLENGTH and VSTRIM

Upstream patch:

    Date: Wed, 8 Oct 2014 15:42:08 +0800
    [EXPAND] Do not split quoted VSLENGTH and VSTRIM

    Currently VSLENGTH and VSTRIM* are field-split even within quotes.
    This is obviously wrong.  This patch fixes that.

    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash.c b/shell/ash.c
index 56dbcb7..d830e39 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6753,7 +6753,7 @@
  * input string.
  */
 static char *
-evalvar(char *p, int flags, struct strlist *var_str_list)
+evalvar(char *p, int flag, struct strlist *var_str_list)
 {
 	char varflags;
 	char subtype;
@@ -6767,7 +6767,7 @@
 
 	varflags = (unsigned char) *p++;
 	subtype = varflags & VSTYPE;
-	quoted = flags & EXP_QUOTED;
+	quoted = flag & EXP_QUOTED;
 	var = p;
 	easy = (!quoted || (*var == '@' && shellparam.nparam));
 	nulonly = easy;
@@ -6775,7 +6775,7 @@
 	p = strchr(p, '=') + 1; //TODO: use var_end(p)?
 
  again:
-	varlen = varvalue(var, varflags, flags, var_str_list, &nulonly);
+	varlen = varvalue(var, varflags, flag, var_str_list, &nulonly);
 	if (varflags & VSNUL)
 		varlen--;
 
@@ -6789,36 +6789,27 @@
 		if (varlen < 0) {
 			argstr(
 				p,
-				flags | EXP_TILDE | EXP_WORD,
+				flag | EXP_TILDE | EXP_WORD,
 				var_str_list
 			);
 			goto end;
 		}
-		if (easy)
-			goto record;
-		goto end;
+		goto record;
 	}
 
 	if (subtype == VSASSIGN || subtype == VSQUESTION) {
-		if (varlen < 0) {
-			if (subevalvar(p, var, /* strloc: */ 0,
-					subtype, startloc, varflags,
-					/* quotes: */ flags & ~QUOTES_ESC,
-					var_str_list)
-			) {
-				varflags &= ~VSNUL;
-				/*
-				 * Remove any recorded regions beyond
-				 * start of variable
-				 */
-				removerecordregions(startloc);
-				goto again;
-			}
-			goto end;
-		}
-		if (easy)
+		if (varlen >= 0)
 			goto record;
-		goto end;
+
+		subevalvar(p, var, 0, subtype, startloc, varflags,
+			   flag & ~QUOTES_ESC, var_str_list);
+		varflags &= ~VSNUL;
+		/*
+		 * Remove any recorded regions beyond
+		 * start of variable
+		 */
+		removerecordregions(startloc);
+		goto again;
 	}
 
 	if (varlen < 0 && uflag)
@@ -6830,8 +6821,10 @@
 	}
 
 	if (subtype == VSNORMAL) {
-		if (easy)
-			goto record;
+ record:
+		if (!easy)
+			goto end;
+		recordregion(startloc, expdest - (char *)stackblock(), nulonly);
 		goto end;
 	}
 
@@ -6860,7 +6853,7 @@
 		STPUTC('\0', expdest);
 		patloc = expdest - (char *)stackblock();
 		if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
-				startloc, varflags, flags, var_str_list)) {
+				startloc, varflags, flag, var_str_list)) {
 			int amount = expdest - (
 				(char *)stackblock() + patloc - 1
 			);
@@ -6868,8 +6861,7 @@
 		}
 		/* Remove any recorded regions beyond start of variable */
 		removerecordregions(startloc);
- record:
-		recordregion(startloc, expdest - (char *)stackblock(), nulonly);
+		goto record;
 	}
 
  end: