summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--src/TOUR12
-rw-r--r--src/eval.c2
-rw-r--r--src/expand.c110
-rw-r--r--src/expand.h2
-rw-r--r--src/jobs.c10
-rw-r--r--src/mystring.c3
-rw-r--r--src/mystring.h2
-rw-r--r--src/parser.c17
-rw-r--r--src/parser.h3
-rw-r--r--src/show.c3
11 files changed, 64 insertions, 101 deletions
diff --git a/ChangeLog b/ChangeLog
index dacc9b3..d5c51bf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2007-09-25  Herbert Xu <herbert@gondor.apana.org.au>
 
 	* Do not expand tilde in parameter expansion within quotes.
+	* Move parse-time quote flag detection to run-time.
 
 2007-09-24  Herbert Xu <herbert@gondor.apana.org.au>
 
diff --git a/src/TOUR b/src/TOUR
index 0c60e2a..4baac62 100644
--- a/src/TOUR
+++ b/src/TOUR
@@ -159,7 +159,6 @@ special codes defined in parser.h.  The special codes are:
         CTLVAR              Variable substitution
         CTLENDVAR           End of variable substitution
         CTLBACKQ            Command substitution
-        CTLBACKQ|CTLQUOTE   Command substitution inside double quotes
         CTLESC              Escape next character
 
 A variable substitution contains the following elements:
@@ -179,16 +178,13 @@ stitution.  The possible types are:
         VSASSIGN            ${var=text}
         VSASSIGN|VSNUL      ${var=text}
 
-In addition, the type field will have the VSQUOTE flag set if the
-variable is enclosed in double quotes.  The name of the variable
-comes next, terminated by an equals sign.  If the type is not
-VSNORMAL, then the text field in the substitution follows, ter-
-minated by a CTLENDVAR byte.
+The name of the variable comes next, terminated by an equals
+sign.  If the type is not VSNORMAL, then the text field in the
+substitution follows, terminated by a CTLENDVAR byte.
 
 Commands in back quotes are parsed and stored in a linked list.
 The locations of these commands in the string are indicated by
-CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
-the back quotes were enclosed in double quotes.
+the CTLBACKQ character.
 
 The character CTLESC escapes the next character, so that in case
 any of the CTL characters mentioned above appear in the input,
diff --git a/src/eval.c b/src/eval.c
index fed82d5..2aa8317 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -377,7 +377,7 @@ evalfor(union node *n, int flags)
 	setstackmark(&smark);
 	arglist.lastp = &arglist.list;
 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
-		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
+		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
 		/* XXX */
 		if (evalskip)
 			goto out;
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:
diff --git a/src/expand.h b/src/expand.h
index be7ec6f..4dfbc43 100644
--- a/src/expand.h
+++ b/src/expand.h
@@ -53,7 +53,7 @@ struct arglist {
 #define	EXP_VARTILDE	0x4	/* expand tildes in an assignment */
 #define	EXP_REDIR	0x8	/* file glob for a redirection (1 match only) */
 #define EXP_CASE	0x10	/* keeps quotes around for CASE pattern */
-#define EXP_RECORD	0x20	/* need to record arguments for ifs breakup */
+#define EXP_QPAT	0x20	/* pattern in quoted parameter expansion */
 #define EXP_VARTILDE2	0x40	/* expand tildes after colons only */
 #define EXP_WORD	0x80	/* expand word in parameter expansion */
 #define EXP_QUOTED	0x100	/* expand word in double quotes */
diff --git a/src/jobs.c b/src/jobs.c
index 7285d0d..529d615 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1377,12 +1377,7 @@ cmdputs(const char *s)
 				str = "${#";
 			else
 				str = "${";
-			if (!(subtype & VSQUOTE) != !(quoted & 1)) {
-				quoted ^= 1;
-				c = '"';
-			} else
-				goto dostr;
-			break;
+			goto dostr;
 		case CTLENDVAR:
 			str = "\"}" + !(quoted & 1);
 			quoted >>= 1;
@@ -1391,9 +1386,6 @@ cmdputs(const char *s)
 		case CTLBACKQ:
 			str = "$(...)";
 			goto dostr;
-		case CTLBACKQ+CTLQUOTE:
-			str = "\"$(...)\"";
-			goto dostr;
 		case CTLARI:
 			str = "$((";
 			goto dostr;
diff --git a/src/mystring.c b/src/mystring.c
index 49201a9..7d937a8 100644
--- a/src/mystring.c
+++ b/src/mystring.c
@@ -55,7 +55,8 @@
 char nullstr[1];		/* zero length string */
 const char spcstr[] = " ";
 const char snlfmt[] = "%s\n";
-const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
+const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=',
+			  CTLQUOTEMARK, '\0' };
 const char illnum[] = "Illegal number: %s";
 const char homestr[] = "HOME";
 
diff --git a/src/mystring.h b/src/mystring.h
index 44fd7e4..f451cc2 100644
--- a/src/mystring.h
+++ b/src/mystring.h
@@ -39,7 +39,7 @@
 extern const char snlfmt[];
 extern const char spcstr[];
 extern const char dolatstr[];
-#define DOLATSTRLEN 4
+#define DOLATSTRLEN 6
 extern const char illnum[];
 extern const char homestr[];
 
diff --git a/src/parser.c b/src/parser.c
index e00fd4b..1a483d4 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -911,11 +911,9 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
 							eofmark != NULL
 						)
 					) {
-						USTPUTC(CTLESC, out);
 						USTPUTC('\\', out);
 					}
-					if (SQSYNTAX[c] == CCTL)
-						USTPUTC(CTLESC, out);
+					USTPUTC(CTLESC, out);
 					USTPUTC(c, out);
 					quotef++;
 				}
@@ -1221,8 +1219,6 @@ badsub:			synerror("Bad substitution");
 		} else {
 			pungetc();
 		}
-		if (dblquote || arinest)
-			flags |= VSQUOTE;
 		*((char *)stackblock() + typeloc) = subtype | flags;
 		if (subtype != VSNORMAL) {
 			varnest++;
@@ -1353,10 +1349,7 @@ done:
 		memcpy(out, str, savelen);
 		STADJUST(savelen, out);
 	}
-	if (arinest || dblquote)
-		USTPUTC(CTLBACKQ | CTLQUOTE, out);
-	else
-		USTPUTC(CTLBACKQ, out);
+	USTPUTC(CTLBACKQ, out);
 	if (oldstyle)
 		goto parsebackq_oldreturn;
 	else
@@ -1373,10 +1366,6 @@ parsearith: {
 		syntax = ARISYNTAX;
 	}
 	USTPUTC(CTLARI, out);
-	if (dblquote)
-		USTPUTC('"',out);
-	else
-		USTPUTC(' ',out);
 	goto parsearith_return;
 }
 
@@ -1503,7 +1492,7 @@ expandstr(const char *ps)
 	n.narg.text = wordtext;
 	n.narg.backquote = backquotelist;
 
-	expandarg(&n, NULL, 0);
+	expandarg(&n, NULL, EXP_QUOTED);
 	return stackblock();
 }
 
diff --git a/src/parser.h b/src/parser.h
index 76ec839..badbd07 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -40,8 +40,6 @@
 #define CTLVAR -126		/* variable defn */
 #define CTLENDVAR -125
 #define CTLBACKQ -124
-#define CTLQUOTE 01		/* ored with CTLBACKQ code if in quotes */
-/*	CTLBACKQ | CTLQUOTE == -123 */
 #define	CTLARI -122		/* arithmetic expression */
 #define	CTLENDARI -121
 #define	CTLQUOTEMARK -120
@@ -50,7 +48,6 @@
 /* variable substitution byte (follows CTLVAR) */
 #define VSTYPE	0x0f		/* type of variable substitution */
 #define VSNUL	0x10		/* colon--treat the empty string as unset */
-#define VSQUOTE 0x80		/* inside double quotes--suppress splitting */
 
 /* values of VSTYPE field */
 #define VSNORMAL	0x1		/* normal variable:  $var or ${var} */
diff --git a/src/show.c b/src/show.c
index 1b58de1..14dbef3 100644
--- a/src/show.c
+++ b/src/show.c
@@ -222,7 +222,6 @@ sharg(union node *arg, FILE *fp)
 		     putc('}', fp);
 		     break;
 		case CTLBACKQ:
-		case CTLBACKQ|CTLQUOTE:
 			putc('$', fp);
 			putc('(', fp);
 			shtree(bqlist->n, -1, NULL, fp);
@@ -314,9 +313,7 @@ trstring(char *s)
 		case '\\':  c = '\\';  goto backslash;
 		case CTLESC:  c = 'e';  goto backslash;
 		case CTLVAR:  c = 'v';  goto backslash;
-		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
 		case CTLBACKQ:  c = 'q';  goto backslash;
-		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
 backslash:	  putc('\\', tracefile);
 			putc(c, tracefile);
 			break;