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 *);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to