Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libc/gen Add GLOB_STAR support from Greg Dionne.



details:   https://anonhg.NetBSD.org/src/rev/9425e57cda01
branches:  trunk
changeset: 757569:9425e57cda01
user:      christos <christos%NetBSD.org@localhost>
date:      Mon Sep 06 14:40:24 2010 +0000

description:
Add GLOB_STAR support from Greg Dionne.

diffstat:

 lib/libc/gen/glob.3 |   11 +++-
 lib/libc/gen/glob.c |  126 +++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 105 insertions(+), 32 deletions(-)

diffs (281 lines):

diff -r db8935693999 -r 9425e57cda01 lib/libc/gen/glob.3
--- a/lib/libc/gen/glob.3       Mon Sep 06 14:38:56 2010 +0000
+++ b/lib/libc/gen/glob.3       Mon Sep 06 14:40:24 2010 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: glob.3,v 1.37 2010/07/06 14:59:22 christos Exp $
+.\"    $NetBSD: glob.3,v 1.38 2010/09/06 14:40:24 christos Exp $
 .\"
 .\" Copyright (c) 1989, 1991, 1993, 1994
 .\"    The Regents of the University of California.  All rights reserved.
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)glob.3     8.3 (Berkeley) 4/16/94
 .\"
-.Dd July 6, 2010
+.Dd September 3, 2010
 .Dt GLOB 3
 .Os
 .Sh NAME
@@ -277,6 +277,13 @@
 from metacharacter matches, regardless of whether
 .Dv GLOB_PERIOD
 is set and whether the pattern component begins with a literal period.
+.Dv GLOB_STAR
+Indicates that two adjacent
+.Li *
+characters will do a recursive match in all subdirs, without following
+symbolic links and three adjacent
+.Li *
+characters will also follow symbolic links.
 .El
 .Pp
 If, during the search, a directory is encountered that cannot be opened
diff -r db8935693999 -r 9425e57cda01 lib/libc/gen/glob.c
--- a/lib/libc/gen/glob.c       Mon Sep 06 14:38:56 2010 +0000
+++ b/lib/libc/gen/glob.c       Mon Sep 06 14:40:24 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: glob.c,v 1.26 2010/07/06 14:59:22 christos Exp $       */
+/*     $NetBSD: glob.c,v 1.27 2010/09/06 14:40:25 christos Exp $       */
 
 /*
  * Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)glob.c     8.3 (Berkeley) 10/13/93";
 #else
-__RCSID("$NetBSD: glob.c,v 1.26 2010/07/06 14:59:22 christos Exp $");
+__RCSID("$NetBSD: glob.c,v 1.27 2010/09/06 14:40:25 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -160,16 +160,16 @@
 static int      g_stat(Char *, __gl_stat_t *, glob_t *);
 static int      glob0(const Char *, glob_t *, size_t *);
 static int      glob1(Char *, glob_t *, size_t *);
-static int      glob2(Char *, Char *, Char *, Char *, glob_t *,
+static int      glob2(Char *, Char *, Char *, const Char *, glob_t *,
     size_t *);
-static int      glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
-    size_t *);
+static int      glob3(Char *, Char *, Char *, const Char *, const Char *,
+    const Char *, glob_t *, size_t *);
 static int      globextend(const Char *, glob_t *, size_t *);
 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
 static int      globexp1(const Char *, glob_t *, size_t *);
 static int      globexp2(const Char *, const Char *, glob_t *, int *,
     size_t *);
-static int      match(Char *, Char *, Char *);
+static int      match(const Char *, const Char *, const Char *);
 #ifdef DEBUG
 static void     qprintf(const char *, Char *);
 #endif
@@ -346,7 +346,7 @@
 
                                /* Expand the current pattern */
 #ifdef DEBUG
-                               qprintf("globexp2:", patbuf);
+                               qprintf("globexp2", patbuf);
 #endif
                                *rv = globexp1(patbuf, pglob, limit);
 
@@ -513,10 +513,13 @@
                        break;
                case STAR:
                        pglob->gl_flags |= GLOB_MAGCHAR;
-                       /* collapse adjacent stars to one, 
+                       /* collapse adjacent stars to one [or three if globstar]
                         * to avoid exponential behavior
                         */
-                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
+                       if (bufnext == patbuf || bufnext[-1] != M_ALL ||
+                           ((pglob->gl_flags & GLOB_STAR) != 0 && 
+                           (bufnext - 1 == patbuf || bufnext[-2] != M_ALL ||
+                           bufnext - 2 == patbuf || bufnext[-3] != M_ALL)))
                                *bufnext++ = M_ALL;
                        break;
                default:
@@ -526,7 +529,7 @@
        }
        *bufnext = EOS;
 #ifdef DEBUG
-       qprintf("glob0:", patbuf);
+       qprintf("glob0", patbuf);
 #endif
 
        if ((error = glob1(patbuf, pglob, limit)) != 0)
@@ -592,11 +595,12 @@
  * meta characters.
  */
 static int
-glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob,
-    size_t *limit)
+glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    glob_t *pglob, size_t *limit)
 {
        __gl_stat_t sb;
-       Char *p, *q;
+       const Char *p;
+       Char *q;
        int anymeta;
        Char *pend;
        ptrdiff_t diff;
@@ -606,6 +610,9 @@
        _DIAGASSERT(pattern != NULL);
        _DIAGASSERT(pglob != NULL);
 
+#ifdef DEBUG
+       qprintf("glob2", pathbuf);
+#endif
        /*
         * Loop over pattern segments until end of pattern or until
         * segment with meta character found.
@@ -677,19 +684,24 @@
                        }
                } else                  /* Need expansion, recurse. */
                        return glob3(pathbuf, pathend, pathlim, pattern, p,
-                           pglob, limit);
+                           pattern, pglob, limit);
        }
        /* NOTREACHED */
 }
 
 static int
-glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern,
-    Char *restpattern, glob_t *pglob, size_t *limit)
+glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
+    const Char *restpattern, const Char *pglobstar, glob_t *pglob,
+    size_t *limit)
 {
        struct dirent *dp;
        DIR *dirp;
+       __gl_stat_t sbuf;
        int error;
        char buf[MAXPATHLEN];
+       int globstar = 0;
+       int chase_symlinks = 0;
+       const Char *termstar = NULL;
 
        /*
         * The readdirfunc declaration can't be prototyped, because it is
@@ -708,6 +720,39 @@
        *pathend = EOS;
        errno = 0;
            
+       while (pglobstar < restpattern) {
+               if ((pglobstar[0] & M_MASK) == M_ALL &&
+                   (pglobstar[1] & M_MASK) == M_ALL) {
+                       globstar = 1;
+                       chase_symlinks = (pglobstar[2] & M_MASK) == M_ALL;
+                       termstar = pglobstar + (2 + chase_symlinks);
+                       break;
+               }
+               pglobstar++;
+       } 
+
+       if (globstar) {
+               error = pglobstar == pattern && termstar == restpattern ?
+                   *restpattern == EOS ?
+                   glob2(pathbuf, pathend, pathlim, restpattern - 1, pglob,
+                   limit) :
+                   glob2(pathbuf, pathend, pathlim, restpattern + 1, pglob,
+                   limit) :
+                   glob3(pathbuf, pathend, pathlim, pattern, restpattern,
+                   termstar, pglob, limit);
+               if (error)
+                       return error;
+               *pathend = EOS;
+       }
+
+       if (*pathbuf && (g_lstat(pathbuf, &sbuf, pglob) ||
+           !S_ISDIR(sbuf.st_mode)
+#ifdef S_IFLINK
+            && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode))
+#endif
+           ))
+               return 0;
+
        if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
                if (pglob->gl_errfunc) {
                        if (g_Ctoc(pathbuf, buf, sizeof(buf)))
@@ -789,16 +834,36 @@
                        }
                }
 
-               if (!match(pathend, pattern, restpattern)) {
+               if (globstar) {
+#ifdef S_IFLNK
+                       if (!chase_symlinks &&
+                           (g_lstat(pathbuf, &sbuf, pglob) ||
+                           S_ISLNK(sbuf.st_mode)))
+                               continue;
+#endif
+
+                       if (!match(pathend, pattern, termstar))
+                               continue;
+           
+                       if (--dc < pathlim - 2)
+                               *dc++ = SEP;
+                       *dc = EOS;
+                       error = glob2(pathbuf, dc, pathlim, pglobstar,
+                           pglob, limit);
+                       if (error)
+                               break;
                        *pathend = EOS;
-                       continue;
+               } else {
+                       if (!match(pathend, pattern, restpattern)) {
+                               *pathend = EOS;
+                               continue;
+                       }
+                       error = glob2(pathbuf, --dc, pathlim, restpattern,
+                           pglob, limit);
+                       if (error)
+                               break;
                }
-               error = glob2(pathbuf, --dc, pathlim, restpattern, pglob,
-                   limit);
-               if (error)
-                       break;
        }
-
        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
                (*pglob->gl_closedir)(dirp);
        else
@@ -881,7 +946,7 @@
  * pattern causes a recursion level.
  */
 static int
-match(Char *name, Char *pat, Char *patend)
+match(const Char *name, const Char *pat, const Char *patend)
 {
        int ok, negate_range;
        Char c, k;
@@ -894,13 +959,14 @@
                c = *pat++;
                switch (c & M_MASK) {
                case M_ALL:
+                       while (pat < patend && (*pat & M_MASK) == M_ALL)
+                               pat++;  /* eat consecutive '*' */
                        if (pat == patend)
                                return 1;
-                       do 
-                           if (match(name, pat, patend))
-                                   return 1;
-                       while (*name++ != EOS);
-                       return 0;
+                       for (; !match(name, pat, patend); name++)
+                               if (*name == EOS)
+                                       return 0;
+                       return 1;
                case M_ONE:
                        if (*name++ == EOS)
                                return 0;
@@ -963,7 +1029,7 @@
                        return 1;
 
                case QUOTE:
-                       if (quote && pattern[1] != '\0')
+                       if (quote && pattern[1] != EOS)
                              ++pattern;
                        break;
 



Home | Main Index | Thread Index | Old Index