summary refs log tree commit diff
path: root/src/expand.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/expand.c110
1 files changed, 50 insertions, 60 deletions
diff --git a/src/expand.c b/src/expand.c
index c9f09ff..8c6c7f9 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -82,12 +82,11 @@
  */
 #define RMESCAPE_ALLOC	0x1	/* Allocate a new string */
 #define RMESCAPE_GLOB	0x2	/* Add backslashes for glob */
-#define RMESCAPE_QUOTED	0x4	/* Remove CTLESC unless in quotes */
 #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)
+#define QUOTES_ESC	(EXP_FULL | EXP_CASE | EXP_QPAT)
 /* Do not skip NUL characters. */
 #define QUOTES_KEEPNUL	EXP_TILDE
 
@@ -116,7 +115,7 @@ static struct arglist exparg;
 
 STATIC void argstr(char *, int);
 STATIC char *exptilde(char *, char *, int);
-STATIC void expbackq(union node *, int, int);
+STATIC void expbackq(union node *, int);
 STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
 STATIC char *evalvar(char *, int);
 STATIC size_t strtodest(const char *, const char *, int);
@@ -158,11 +157,8 @@ STATIC void varunset(const char *, const char *, const char *, int)
  */
 
 STATIC inline char *
-preglob(const char *pattern, int quoted, int flag) {
+preglob(const char *pattern, int flag) {
 	flag |= RMESCAPE_GLOB;
-	if (quoted) {
-		flag |= RMESCAPE_QUOTED;
-	}
 	return _rmescapes((char *)pattern, flag);
 }
 
@@ -197,7 +193,7 @@ void
 expandhere(union node *arg, int fd)
 {
 	herefd = fd;
-	expandarg(arg, (struct arglist *)NULL, 0);
+	expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
 	xwrite(fd, stackblock(), expdest - (char *)stackblock());
 }
 
@@ -271,13 +267,11 @@ argstr(char *p, int flag)
 		CTLESC,
 		CTLVAR,
 		CTLBACKQ,
-		CTLBACKQ | CTLQUOTE,
 		CTLENDARI,
 		0
 	};
 	const char *reject = spclchars;
 	int c;
-	int quotes = flag & QUOTES_ESC;
 	int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
 	int inquotes;
 	size_t length;
@@ -346,21 +340,15 @@ start:
 		case CTLENDVAR: /* ??? */
 			goto breakloop;
 		case CTLQUOTEMARK:
+			inquotes ^= EXP_QUOTED;
 			/* "$@" syntax adherence hack */
-			if (
-				!inquotes &&
-				!memcmp(p, dolatstr, DOLATSTRLEN) &&
-				(p[4] == (char)CTLQUOTEMARK || (
-					p[4] == (char)CTLENDVAR &&
-					p[5] == (char)CTLQUOTEMARK
-				))
-			) {
-				p = evalvar(p + 1, flag) + 1;
+			if (inquotes && !memcmp(p, dolatstr + 1,
+						DOLATSTRLEN - 1)) {
+				p = evalvar(p + 1, flag | inquotes) + 1;
 				goto start;
 			}
-			inquotes = !inquotes;
 addquote:
-			if (quotes) {
+			if (flag & QUOTES_ESC) {
 				p--;
 				length++;
 				startloc++;
@@ -369,19 +357,27 @@ addquote:
 		case CTLESC:
 			startloc++;
 			length++;
+
+			/*
+			 * Quoted parameter expansion pattern: remove quote
+			 * unless inside inner quotes or we have a literal
+			 * backslash.
+			 */
+			if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
+			    EXP_QPAT && *p != '\\')
+				break;
+
 			goto addquote;
 		case CTLVAR:
-			p = evalvar(p, flag);
+			p = evalvar(p, flag | inquotes);
 			goto start;
 		case CTLBACKQ:
-			c = 0;
-		case CTLBACKQ|CTLQUOTE:
-			expbackq(argbackq->n, c, quotes);
+			expbackq(argbackq->n, flag | inquotes);
 			argbackq = argbackq->next;
 			goto start;
 		case CTLENDARI:
 			p--;
-			expari(quotes);
+			expari(flag | inquotes);
 			goto start;
 		}
 	}
@@ -480,11 +476,10 @@ removerecordregions(int endoff)
  * evaluate, place result in (backed up) result, adjust string position.
  */
 void
-expari(int quotes)
+expari(int flag)
 {
 	char *p, *start;
 	int begoff;
-	int flag;
 	int len;
 
 	/*	ifsfree(); */
@@ -522,16 +517,14 @@ expari(int quotes)
 
 	removerecordregions(begoff);
 
-	flag = p[1];
-
 	expdest = p;
 
-	if (quotes)
-		rmescapes(p + 2);
+	if (flag & QUOTES_ESC)
+		rmescapes(p + 1);
 
-	len = cvtnum(arith(p + 2));
+	len = cvtnum(arith(p + 1));
 
-	if (flag != '"')
+	if (!(flag & EXP_QUOTED))
 		recordregion(begoff, begoff + len, 0);
 }
 
@@ -541,7 +534,7 @@ expari(int quotes)
  */
 
 STATIC void
-expbackq(union node *cmd, int quoted, int quotes)
+expbackq(union node *cmd, int flag)
 {
 	struct backcmd in;
 	int i;
@@ -549,7 +542,7 @@ expbackq(union node *cmd, int quoted, int quotes)
 	char *p;
 	char *dest;
 	int startloc;
-	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
+	char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
 	struct stackmark smark;
 
 	INTOFF;
@@ -565,7 +558,7 @@ expbackq(union node *cmd, int quoted, int quotes)
 	if (i == 0)
 		goto read;
 	for (;;) {
-		memtodest(p, i, syntax, quotes);
+		memtodest(p, i, syntax, flag & QUOTES_ESC);
 read:
 		if (in.fd < 0)
 			break;
@@ -592,7 +585,7 @@ read:
 		STUNPUTC(dest);
 	expdest = dest;
 
-	if (quoted == 0)
+	if (!(flag & EXP_QUOTED))
 		recordregion(startloc, dest - (char *)stackblock(), 0);
 	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
 		(dest - (char *)stackblock()) - startloc,
@@ -669,8 +662,9 @@ scanright(
 }
 
 STATIC const char *
-subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag)
 {
+	int quotes = flag & QUOTES_ESC;
 	char *startp;
 	char *loc;
 	int saveherefd = herefd;
@@ -682,7 +676,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla
 
 	herefd = -1;
 	argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
-			       EXP_CASE : 0));
+			       (flag & EXP_QUOTED ? EXP_QPAT : EXP_CASE) : 0));
 	STPUTC('\0', expdest);
 	herefd = saveherefd;
 	argbackq = saveargbackq;
@@ -717,7 +711,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla
 	}
 	rmescend--;
 	str = stackblock() + strloc;
-	preglob(str, varflags & VSQUOTE, 0);
+	preglob(str, 0);
 
 	/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
 	zero = subtype >> 1;
@@ -753,13 +747,11 @@ evalvar(char *p, int flag)
 	int startloc;
 	ssize_t varlen;
 	int easy;
-	int quotes;
 	int quoted;
 
-	quotes = flag & QUOTES_ESC;
 	varflags = *p++;
 	subtype = varflags & VSTYPE;
-	quoted = varflags & VSQUOTE;
+	quoted = flag & EXP_QUOTED;
 	var = p;
 	easy = (!quoted || (*var == '@' && shellparam.nparam));
 	startloc = expdest - (char *)stackblock();
@@ -778,8 +770,7 @@ again:
 	if (subtype == VSMINUS) {
 vsplus:
 		if (varlen < 0) {
-			argstr(p, flag | EXP_TILDE | EXP_WORD |
-				  (quoted ? EXP_QUOTED : 0));
+			argstr(p, flag | EXP_TILDE | EXP_WORD);
 			goto end;
 		}
 		if (easy)
@@ -790,7 +781,7 @@ vsplus:
 	if (subtype == VSASSIGN || subtype == VSQUESTION) {
 		if (varlen < 0) {
 			if (subevalvar(p, var, 0, subtype, startloc,
-				       varflags, 0)) {
+				       varflags, flag & ~QUOTES_ESC)) {
 				varflags &= ~VSNUL;
 				/* 
 				 * Remove any recorded regions beyond 
@@ -842,7 +833,7 @@ record:
 		STPUTC('\0', expdest);
 		patloc = expdest - (char *)stackblock();
 		if (subevalvar(p, NULL, patloc, subtype,
-			       startloc, varflags, quotes) == 0) {
+			       startloc, varflags, flag) == 0) {
 			int amount = expdest - (
 				(char *)stackblock() + patloc - 1
 			);
@@ -859,7 +850,7 @@ end:
 		for (;;) {
 			if ((c = (signed char)*p++) == CTLESC)
 				p++;
-			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
+			else if (c == CTLBACKQ) {
 				if (varlen >= 0)
 					argbackq = argbackq->next;
 			} else if (c == CTLVAR) {
@@ -930,7 +921,7 @@ varvalue(char *name, int varflags, int flags)
 	char sepc;
 	char **ap;
 	char const *syntax;
-	int quoted = varflags & VSQUOTE;
+	int quoted = flags & EXP_QUOTED;
 	int subtype = varflags & VSTYPE;
 	int discard = subtype == VSPLUS || subtype == VSLENGTH;
 	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
@@ -1175,7 +1166,7 @@ expandmeta(str, flag)
 		if (fflag)
 			goto nometa;
 		INTOFF;
-		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+		p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
 		i = glob(p, GLOB_NOMAGIC, 0, &pglob);
 		if (p != str->text)
 			ckfree(p);
@@ -1244,7 +1235,7 @@ expandmeta(struct strlist *str, int flag)
 		savelastp = exparg.lastp;
 
 		INTOFF;
-		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+		p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
 		{
 			int i = strlen(str->text);
 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
@@ -1475,7 +1466,7 @@ msort(struct strlist *list, int len)
 STATIC inline int
 patmatch(char *pattern, const char *string)
 {
-	return pmatch(preglob(pattern, 0, 0), string);
+	return pmatch(preglob(pattern, 0), string);
 }
 
 
@@ -1651,7 +1642,7 @@ _rmescapes(char *str, int flag)
 			q = mempcpy(q, str, len);
 		}
 	}
-	inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
+	inquotes = 0;
 	globbing = flag & RMESCAPE_GLOB;
 	notescaped = globbing;
 	while (*p) {
@@ -1661,15 +1652,14 @@ _rmescapes(char *str, int flag)
 			notescaped = globbing;
 			continue;
 		}
-		if (*p == '\\') {
-			/* naked back slash */
-			notescaped = 0;
-			goto copy;
-		}
 		if (*p == (char)CTLESC) {
 			p++;
-			if (notescaped && inquotes)
+			if (notescaped)
 				*q++ = '\\';
+		} else if (*p == '\\' && !inquotes) {
+			/* naked back slash */
+			notescaped = 0;
+			goto copy;
 		}
 		notescaped = globbing;
 copy: