ash: fix obscure case of replacing + globbing + backslashes

function                                             old     new   delta
subevalvar                                          1152    1178     +26
readtoken1                                          3267    3275      +8
redirect                                            1284    1286      +2
expandarg                                            957     958      +1
expdir                                                 4       -      -4
evalcommand                                         1219    1209     -10
expmeta                                              481     469     -12
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 4/2 up/down: 37/-26)             Total: 11 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash.c b/shell/ash.c
index cfd8154..0337a55 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6184,8 +6184,7 @@
 	char *startp;
 	char *loc;
 	char *rmesc, *rmescend;
-	IF_ASH_BASH_COMPAT(char *repl = NULL;)
-	IF_ASH_BASH_COMPAT(char null = '\0';)
+	IF_ASH_BASH_COMPAT(const char *repl = NULL;)
 	IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
 	int saveherefd = herefd;
 	int amount, workloc, resetloc;
@@ -6306,7 +6305,7 @@
 		if (!repl) {
 			repl = parse_sub_pattern(str, varflags & VSQUOTE);
 			if (!repl)
-				repl = &null;
+				repl = nullstr;
 		}
 
 		/* If there's no pattern to match, return the expansion unmolested */
@@ -6357,8 +6356,12 @@
 				idx = loc;
 			}
 
-			for (loc = repl; *loc; loc++) {
+			for (loc = (char*)repl; *loc; loc++) {
 				char *restart_detect = stackblock();
+				if (quotes && *loc == '\\') {
+					STPUTC(CTLESC, expdest);
+					len++;
+				}
 				STPUTC(*loc, expdest);
 				if (stackblock() != restart_detect)
 					goto restart;
@@ -6368,6 +6371,10 @@
 			if (subtype == VSREPLACE) {
 				while (*idx) {
 					char *restart_detect = stackblock();
+					if (quotes && *idx == '\\') {
+						STPUTC(CTLESC, expdest);
+						len++;
+					}
 					STPUTC(*idx, expdest);
 					if (stackblock() != restart_detect)
 						goto restart;
@@ -6381,11 +6388,10 @@
 		/* We've put the replaced text into a buffer at workloc, now
 		 * move it to the right place and adjust the stack.
 		 */
-		startp = stackblock() + startloc;
 		STPUTC('\0', expdest);
-		memmove(startp, stackblock() + workloc, len);
-		startp[len++] = '\0';
-		amount = expdest - ((char *)stackblock() + startloc + len - 1);
+		startp = (char *)stackblock() + startloc;
+		memmove(startp, (char *)stackblock() + workloc, len + 1);
+		amount = expdest - (startp + len);
 		STADJUST(-amount, expdest);
 		return startp;
 	}
@@ -6685,7 +6691,7 @@
 		 */
 		STPUTC('\0', expdest);
 		patloc = expdest - (char *)stackblock();
-		if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
+		if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype,
 				startloc, varflags,
 //TODO: | EXP_REDIR too? All other such places do it too
 				/* quotes: */ flags & (EXP_FULL | EXP_CASE),
@@ -6848,13 +6854,11 @@
 	exparg.lastp = &sp->next;
 }
 
-static char *expdir;
-
 /*
  * Do metacharacter (i.e. *, ?, [...]) expansion.
  */
 static void
-expmeta(char *enddir, char *name)
+expmeta(char *expdir, char *enddir, char *name)
 {
 	char *p;
 	const char *cp;
@@ -6953,7 +6957,7 @@
 				for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
 					continue;
 				p[-1] = '/';
-				expmeta(p, endname);
+				expmeta(expdir, p, endname);
 			}
 		}
 	}
@@ -7035,6 +7039,7 @@
 	/* TODO - EXP_REDIR */
 
 	while (str) {
+		char *expdir;
 		struct strlist **savelastp;
 		struct strlist *sp;
 		char *p;
@@ -7051,8 +7056,7 @@
 			int i = strlen(str->text);
 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
 		}
-
-		expmeta(expdir, p);
+		expmeta(expdir, expdir, p);
 		free(expdir);
 		if (p != str->text)
 			free(p);
@@ -9101,19 +9105,15 @@
 	/* Print the command if xflag is set. */
 	if (xflag) {
 		int n;
-		const char *p = " %s";
+		const char *p = " %s" + 1;
 
-		p++;
 		fdprintf(preverrout_fd, p, expandstr(ps4val()));
-
 		sp = varlist.list;
 		for (n = 0; n < 2; n++) {
 			while (sp) {
 				fdprintf(preverrout_fd, p, sp->text);
 				sp = sp->next;
-				if (*p == '%') {
-					p--;
-				}
+				p = " %s";
 			}
 			sp = arglist.list;
 		}