builtin-grep: tighten path wildcard vs tree traversal.
authorJunio C Hamano <junkio@cox.net>
Wed, 3 May 2006 00:27:07 +0000 (17:27 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 3 May 2006 00:30:07 +0000 (17:30 -0700)
The earlier code descended into Documentation/technical when
given "Documentation/how*" as the pattern, which was too loose.

Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-grep.c

index 09e3677824595d71d02fc7bfc03eef0428df8b90..2124fa62e8900754615bf7eb49228a4d2b790d52 100644 (file)
@@ -26,7 +26,7 @@ static int pathspec_matches(const char **paths, const char *name)
        for (i = 0; paths[i]; i++) {
                const char *match = paths[i];
                int matchlen = strlen(match);
-               const char *slash, *cp;
+               const char *cp, *meta;
 
                if ((matchlen <= namelen) &&
                    !strncmp(name, match, matchlen) &&
@@ -38,38 +38,43 @@ static int pathspec_matches(const char **paths, const char *name)
                if (name[namelen-1] != '/')
                        continue;
 
-               /* We are being asked if the name directory is worth
+               /* We are being asked if the directory ("name") is worth
                 * descending into.
                 *
                 * Find the longest leading directory name that does
                 * not have metacharacter in the pathspec; the name
                 * we are looking at must overlap with that directory.
                 */
-               for (cp = match, slash = NULL; cp - match < matchlen; cp++) {
+               for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
                        char ch = *cp;
-                       if (ch == '/')
-                               slash = cp;
-                       if (ch == '*' || ch == '[')
+                       if (ch == '*' || ch == '[' || ch == '?') {
+                               meta = cp;
                                break;
+                       }
                }
-               if (!slash)
-                       slash = match; /* toplevel */
-               else
-                       slash++;
-               if (namelen <= slash - match) {
+               if (!meta)
+                       meta = cp; /* fully literal */
+
+               if (namelen <= meta - match) {
                        /* Looking at "Documentation/" and
                         * the pattern says "Documentation/howto/", or
-                        * "Documentation/diff*.txt".
+                        * "Documentation/diff*.txt".  The name we
+                        * have should match prefix.
                         */
                        if (!memcmp(match, name, namelen))
                                return 1;
+                       continue;
                }
-               else {
+
+               if (meta - match < namelen) {
                        /* Looking at "Documentation/howto/" and
-                        * the pattern says "Documentation/h*".
+                        * the pattern says "Documentation/h*";
+                        * match up to "Do.../h"; this avoids descending
+                        * into "Documentation/technical/".
                         */
-                       if (!memcmp(match, name, slash - match))
+                       if (!memcmp(match, name, meta - match))
                                return 1;
+                       continue;
                }
        }
        return 0;