svn commit: r292994 - head/bin/sh

Jilles Tjoelker jilles at FreeBSD.org
Thu Dec 31 18:47:56 UTC 2015


Author: jilles
Date: Thu Dec 31 18:47:54 2015
New Revision: 292994
URL: https://svnweb.freebsd.org/changeset/base/292994

Log:
  sh: Perform pathname generation during the first expansion phases.
  
  This avoids the need to add and remove CTLESC bytes if pathname generation
  will not be performed (set -f).
  
  Side effect: the order of operations is slightly different: pathname
  generation in ${$+* $(CMD)} will not see filesystem changes from CMD.

Modified:
  head/bin/sh/expand.c
  head/bin/sh/expand.h

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c	Thu Dec 31 18:29:24 2015	(r292993)
+++ head/bin/sh/expand.c	Thu Dec 31 18:47:54 2015	(r292994)
@@ -84,7 +84,7 @@ __FBSDID("$FreeBSD$");
 enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK };
 
 struct worddest {
-	struct arglist list;
+	struct arglist *list;
 	enum wordstate state;
 };
 
@@ -102,7 +102,7 @@ static int varisset(const char *, int);
 static void strtodest(const char *, int, int, int, struct worddest *);
 static void reprocess(int, int, int, int, struct worddest *);
 static void varvalue(const char *, int, int, int, struct worddest *);
-static void expandmeta(struct arglist *, struct arglist *);
+static void expandmeta(char *, struct arglist *);
 static void expmeta(char *, char *, struct arglist *);
 static int expsortcmp(const void *, const void *);
 static int patmatch(const char *, const char *);
@@ -162,7 +162,7 @@ stputs_quotes(const char *data, const ch
 #define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
 
 static char *
-nextword(char c, char *p, struct worddest *dst)
+nextword(char c, int flag, char *p, struct worddest *dst)
 {
 	int is_ws;
 
@@ -170,20 +170,23 @@ nextword(char c, char *p, struct worddes
 	if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK :
 	    dst->state != WORD_WS_DELIMITED) || c == '\0') {
 		STPUTC('\0', p);
-		appendarglist(&dst->list, grabstackstr(p));
+		if (flag & EXP_GLOB)
+			expandmeta(grabstackstr(p), dst->list);
+		else
+			appendarglist(dst->list, grabstackstr(p));
 		dst->state = is_ws ? WORD_WS_DELIMITED : WORD_IDLE;
 	} else if (!is_ws && dst->state == WORD_WS_DELIMITED)
 		dst->state = WORD_IDLE;
 	/* Reserve space while the stack string is empty. */
-	appendarglist(&dst->list, NULL);
-	dst->list.count--;
+	appendarglist(dst->list, NULL);
+	dst->list->count--;
 	STARTSTACKSTR(p);
 	return p;
 }
-#define NEXTWORD(c, p, dstlist) p = nextword(c, p, dstlist)
+#define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist)
 
 static char *
-stputs_split(const char *data, const char *syntax, char *p,
+stputs_split(const char *data, const char *syntax, int flag, char *p,
     struct worddest *dst)
 {
 	const char *ifs;
@@ -194,16 +197,16 @@ stputs_split(const char *data, const cha
 		CHECKSTRSPACE(2, p);
 		c = *data++;
 		if (strchr(ifs, c) != NULL) {
-			NEXTWORD(c, p, dst);
+			NEXTWORD(c, flag, p, dst);
 			continue;
 		}
-		if (syntax[(int)c] == CCTL)
+		if (flag & EXP_GLOB && syntax[(int)c] == CCTL)
 			USTPUTC(CTLESC, p);
 		USTPUTC(c, p);
 	}
 	return (p);
 }
-#define STPUTS_SPLIT(data, syntax, p, dst) p = stputs_split((data), syntax, p, dst)
+#define STPUTS_SPLIT(data, syntax, flag, p, dst) p = stputs_split((data), syntax, flag, p, dst)
 
 /*
  * Perform expansions on an argument, placing the resulting list of arguments
@@ -222,8 +225,10 @@ expandarg(union node *arg, struct arglis
 {
 	struct worddest exparg;
 
+	if (fflag)
+		flag &= ~EXP_GLOB;
 	argbackq = arg->narg.backquote;
-	emptyarglist(&exparg.list);
+	exparg.list = arglist;
 	exparg.state = WORD_IDLE;
 	STARTSTACKSTR(expdest);
 	argstr(arg->narg.text, flag, &exparg);
@@ -231,15 +236,17 @@ expandarg(union node *arg, struct arglis
 		STACKSTRNUL(expdest);
 		return;			/* here document expanded */
 	}
-	if ((flag & EXP_FULL) == 0 || expdest != stackblock() ||
+	if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() ||
 	    exparg.state == WORD_QUOTEMARK) {
 		STPUTC('\0', expdest);
-		if (flag & EXP_FULL)
-			appendarglist(&exparg.list, grabstackstr(expdest));
+		if (flag & EXP_SPLIT) {
+			if (flag & EXP_GLOB)
+				expandmeta(grabstackstr(expdest), exparg.list);
+			else
+				appendarglist(exparg.list, grabstackstr(expdest));
+		}
 	}
-	if (flag & EXP_FULL)
-		expandmeta(&exparg.list, arglist);
-	else
+	if ((flag & EXP_SPLIT) == 0)
 		appendarglist(arglist, grabstackstr(expdest));
 }
 
@@ -250,16 +257,16 @@ expandarg(union node *arg, struct arglis
  * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
  * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
  * This is used to expand word in ${var+word} etc.
- * If EXP_FULL or EXP_CASE are set, keep and/or generate CTLESC
+ * If EXP_GLOB or EXP_CASE are set, keep and/or generate CTLESC
  * characters to allow for further processing.
  *
- * If EXP_FULL is set, dst receives any complete words produced.
+ * If EXP_SPLIT is set, dst receives any complete words produced.
  */
 static char *
 argstr(char *p, int flag, struct worddest *dst)
 {
 	char c;
-	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
+	int quotes = flag & (EXP_GLOB | EXP_CASE);	/* do CTLESC */
 	int firsteq = 1;
 	int split_lit;
 	int lit_quoted;
@@ -283,7 +290,7 @@ argstr(char *p, int flag, struct worddes
 			if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 &&
 			    p[2] == '@' && p[3] == '=')
 				break;
-			if ((flag & EXP_FULL) != 0 && expdest == stackblock())
+			if ((flag & EXP_SPLIT) != 0 && expdest == stackblock())
 				dst->state = WORD_QUOTEMARK;
 			break;
 		case CTLQUOTEEND:
@@ -293,7 +300,7 @@ argstr(char *p, int flag, struct worddes
 			c = *p++;
 			if (split_lit && !lit_quoted &&
 			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
-				NEXTWORD(c, expdest, dst);
+				NEXTWORD(c, flag, expdest, dst);
 				break;
 			}
 			if (quotes)
@@ -319,7 +326,7 @@ argstr(char *p, int flag, struct worddes
 			 */
 			if (split_lit && !lit_quoted &&
 			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
-				NEXTWORD(c, expdest, dst);
+				NEXTWORD(c, flag, expdest, dst);
 				break;
 			}
 			USTPUTC(c, expdest);
@@ -333,7 +340,7 @@ argstr(char *p, int flag, struct worddes
 		default:
 			if (split_lit && !lit_quoted &&
 			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
-				NEXTWORD(c, expdest, dst);
+				NEXTWORD(c, flag, expdest, dst);
 				break;
 			}
 			USTPUTC(c, expdest);
@@ -438,7 +445,7 @@ expbackq(union node *cmd, int quoted, in
 	struct nodelist *saveargbackq;
 	char lastc;
 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
-	int quotes = flag & (EXP_FULL | EXP_CASE);
+	int quotes = flag & (EXP_GLOB | EXP_CASE);
 	size_t nnl;
 	const char *ifs;
 
@@ -452,7 +459,7 @@ expbackq(union node *cmd, int quoted, in
 	p = in.buf;
 	lastc = '\0';
 	nnl = 0;
-	if (!quoted && flag & EXP_FULL)
+	if (!quoted && flag & EXP_SPLIT)
 		ifs = ifsset() ? ifsval() : " \t\n";
 	else
 		ifs = "";
@@ -476,7 +483,7 @@ expbackq(union node *cmd, int quoted, in
 		} else {
 			if (nnl > 0) {
 				if (strchr(ifs, '\n') != NULL) {
-					NEXTWORD('\n', dest, dst);
+					NEXTWORD('\n', flag, dest, dst);
 					nnl = 0;
 				} else {
 					CHECKSTRSPACE(nnl + 2, dest);
@@ -487,7 +494,7 @@ expbackq(union node *cmd, int quoted, in
 				}
 			}
 			if (strchr(ifs, lastc) != NULL)
-				NEXTWORD(lastc, dest, dst);
+				NEXTWORD(lastc, flag, dest, dst);
 			else {
 				CHECKSTRSPACE(2, dest);
 				if (quotes && syntax[(int)lastc] == CCTL)
@@ -743,7 +750,7 @@ again: /* jump here after setting a vari
 	case VSPLUS:
 	case VSMINUS:
 		if (!set) {
-			argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
+			argstr(p, flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) |
 			    (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst);
 			break;
 		}
@@ -763,7 +770,7 @@ again: /* jump here after setting a vari
 		patloc = expdest - stackblock();
 		subevalvar_trim(p, patloc, subtype, startloc);
 		reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst);
-		if (flag & EXP_FULL && *var == '@' && varflags & VSQUOTE)
+		if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE)
 			dst->state = WORD_QUOTEMARK;
 		break;
 
@@ -860,9 +867,9 @@ strtodest(const char *p, int flag, int s
 	    subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT ||
 	    subtype == VSTRIMRIGHTMAX)
 		STPUTS(p, expdest);
-	else if (flag & EXP_FULL && !quoted && dst != NULL)
-		STPUTS_SPLIT(p, BASESYNTAX, expdest, dst);
-	else if (flag & (EXP_FULL | EXP_CASE))
+	else if (flag & EXP_SPLIT && !quoted && dst != NULL)
+		STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst);
+	else if (flag & (EXP_GLOB | EXP_CASE))
 		STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
 	else
 		STPUTS(p, expdest);
@@ -902,8 +909,8 @@ reprocess(int startloc, int flag, int su
 		zpos += zlen + 1;
 		if (zpos == len + 1)
 			break;
-		if (flag & EXP_FULL && (quoted || (zlen > 0 && zpos < len)))
-			NEXTWORD('\0', expdest, dst);
+		if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len)))
+			NEXTWORD('\0', flag, expdest, dst);
 	}
 }
 
@@ -951,14 +958,15 @@ varvalue(const char *name, int quoted, i
 		strtodest(buf, flag, subtype, quoted, dst);
 		return;
 	case '@':
-		if (flag & EXP_FULL && quoted) {
+		if (flag & EXP_SPLIT && quoted) {
 			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
 				strtodest(p, flag, subtype, quoted, dst);
 				if (*ap) {
 					if (splitlater)
 						STPUTC('\0', expdest);
 					else
-						NEXTWORD('\0', expdest, dst);
+						NEXTWORD('\0', flag, expdest,
+						    dst);
 				}
 			}
 			if (shellparam.nparam > 0)
@@ -978,11 +986,11 @@ varvalue(const char *name, int quoted, i
 				break;
 			if (sep[0])
 				strtodest(sep, flag, subtype, quoted, dst);
-			else if (flag & EXP_FULL && !quoted && **ap != '\0') {
+			else if (flag & EXP_SPLIT && !quoted && **ap != '\0') {
 				if (splitlater)
 					STPUTC('\0', expdest);
 				else
-					NEXTWORD('\0', expdest, dst);
+					NEXTWORD('\0', flag, expdest, dst);
 			}
 		}
 		return;
@@ -1014,40 +1022,34 @@ static char expdir[PATH_MAX];
  * The results are stored in the list dstlist.
  */
 static void
-expandmeta(struct arglist *srclist, struct arglist *dstlist)
+expandmeta(char *pattern, struct arglist *dstlist)
 {
 	char *p;
 	int firstmatch;
-	int i;
 	char c;
 
-	for (i = 0; i < srclist->count; i++) {
 		firstmatch = dstlist->count;
-		if (!fflag) {
-			p = srclist->args[i];
+			p = pattern;
 			for (; (c = *p) != '\0'; p++) {
 				/* fast check for meta chars */
 				if (c == '*' || c == '?' || c == '[') {
 					INTOFF;
-					expmeta(expdir, srclist->args[i],
-					    dstlist);
+					expmeta(expdir, pattern, dstlist);
 					INTON;
 					break;
 				}
 			}
-		}
 		if (dstlist->count == firstmatch) {
 			/*
 			 * no matches
 			 */
-			rmescapes(srclist->args[i]);
-			appendarglist(dstlist, srclist->args[i]);
+			rmescapes(pattern);
+			appendarglist(dstlist, pattern);
 		} else {
 			qsort(&dstlist->args[firstmatch],
 			    dstlist->count - firstmatch,
 			    sizeof(dstlist->args[0]), expsortcmp);
 		}
-	}
 }
 
 

Modified: head/bin/sh/expand.h
==============================================================================
--- head/bin/sh/expand.h	Thu Dec 31 18:29:24 2015	(r292993)
+++ head/bin/sh/expand.h	Thu Dec 31 18:47:54 2015	(r292994)
@@ -43,12 +43,15 @@ struct arglist {
 /*
  * expandarg() flags
  */
-#define EXP_FULL	0x1	/* perform word splitting & file globbing */
+#define EXP_SPLIT	0x1	/* perform word splitting */
 #define EXP_TILDE	0x2	/* do normal tilde expansion */
 #define	EXP_VARTILDE	0x4	/* expand tildes in an assignment */
 #define EXP_CASE	0x10	/* keeps quotes around for CASE pattern */
 #define EXP_SPLIT_LIT	0x20	/* IFS split literal text ${v+-a b c} */
 #define EXP_LIT_QUOTED	0x40	/* for EXP_SPLIT_LIT, start off quoted */
+#define EXP_GLOB	0x80	/* perform file globbing */
+
+#define EXP_FULL	(EXP_SPLIT | EXP_GLOB)
 
 
 void emptyarglist(struct arglist *);


More information about the svn-src-head mailing list