grep: drop pathspec_matches() in favor of tree_entry_interesting()
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Fri, 17 Dec 2010 12:45:33 +0000 (19:45 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 3 Feb 2011 22:08:31 +0000 (14:08 -0800)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/grep.c
tree-diff.c
tree-walk.c
tree-walk.h

index c9622d6aa99658664e5a72129400987a9e3a5553..c3af8760cc778b4eb835d4fb543f45aa333b214c 100644 (file)
@@ -329,106 +329,6 @@ static int grep_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
-/*
- * Return non-zero if max_depth is negative or path has no more then max_depth
- * slashes.
- */
-static int accept_subdir(const char *path, int max_depth)
-{
-       if (max_depth < 0)
-               return 1;
-
-       while ((path = strchr(path, '/')) != NULL) {
-               max_depth--;
-               if (max_depth < 0)
-                       return 0;
-               path++;
-       }
-       return 1;
-}
-
-/*
- * Return non-zero if name is a subdirectory of match and is not too deep.
- */
-static int is_subdir(const char *name, int namelen,
-               const char *match, int matchlen, int max_depth)
-{
-       if (matchlen > namelen || strncmp(name, match, matchlen))
-               return 0;
-
-       if (name[matchlen] == '\0') /* exact match */
-               return 1;
-
-       if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
-               return accept_subdir(name + matchlen + 1, max_depth);
-
-       return 0;
-}
-
-/*
- * git grep pathspecs are somewhat different from diff-tree pathspecs;
- * pathname wildcards are allowed.
- */
-static int pathspec_matches(const char **paths, const char *name, int max_depth)
-{
-       int namelen, i;
-       if (!paths || !*paths)
-               return accept_subdir(name, max_depth);
-       namelen = strlen(name);
-       for (i = 0; paths[i]; i++) {
-               const char *match = paths[i];
-               int matchlen = strlen(match);
-               const char *cp, *meta;
-
-               if (is_subdir(name, namelen, match, matchlen, max_depth))
-                       return 1;
-               if (!fnmatch(match, name, 0))
-                       return 1;
-               if (name[namelen-1] != '/')
-                       continue;
-
-               /* 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, meta = NULL; cp - match < matchlen; cp++) {
-                       char ch = *cp;
-                       if (ch == '*' || ch == '[' || ch == '?') {
-                               meta = cp;
-                               break;
-                       }
-               }
-               if (!meta)
-                       meta = cp; /* fully literal */
-
-               if (namelen <= meta - match) {
-                       /* Looking at "Documentation/" and
-                        * the pattern says "Documentation/howto/", or
-                        * "Documentation/diff*.txt".  The name we
-                        * have should match prefix.
-                        */
-                       if (!memcmp(match, name, namelen))
-                               return 1;
-                       continue;
-               }
-
-               if (meta - match < namelen) {
-                       /* Looking at "Documentation/howto/" and
-                        * the pattern says "Documentation/h*";
-                        * match up to "Do.../h"; this avoids descending
-                        * into "Documentation/technical/".
-                        */
-                       if (!memcmp(match, name, meta - match))
-                               return 1;
-                       continue;
-               }
-       }
-       return 0;
-}
-
 static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
 {
        void *data;
@@ -621,25 +521,24 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len)
 {
-       int hit = 0;
+       int hit = 0, matched = 0;
        struct name_entry entry;
        int old_baselen = base->len;
 
        while (tree_entry(tree, &entry)) {
                int te_len = tree_entry_len(entry.path, entry.sha1);
 
-               strbuf_add(base, entry.path, te_len);
+               if (matched != 2) {
+                       matched = tree_entry_interesting(&entry, base, tn_len, pathspec);
+                       if (matched == -1)
+                               break; /* no more matches */
+                       if (!matched)
+                               continue;
+               }
 
-               if (S_ISDIR(entry.mode))
-                       /* Match "abc/" against pathspec to
-                        * decide if we want to descend into "abc"
-                        * directory.
-                        */
-                       strbuf_addch(base, '/');
+               strbuf_add(base, entry.path, te_len);
 
-               if (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth))
-                       ;
-               else if (S_ISREG(entry.mode)) {
+               if (S_ISREG(entry.mode)) {
                        hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
                }
                else if (S_ISDIR(entry.mode)) {
@@ -652,6 +551,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                        if (!data)
                                die("unable to read tree (%s)",
                                    sha1_to_hex(entry.sha1));
+
+                       strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
                        hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
                        free(data);
@@ -1058,6 +959,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                paths[1] = NULL;
        }
        init_pathspec(&pathspec, paths);
+       pathspec.max_depth = opt.max_depth;
+       pathspec.recursive = 1;
 
        if (show_in_pager && (cached || list.nr))
                die("--open-files-in-pager only works on the worktree");
index 03dc5c8e7010ebcb16678375319e9a97ca4675eb..3954281f509bbed9a9b095ed92d24b67275fed82 100644 (file)
@@ -72,7 +72,7 @@ static void show_tree(struct diff_options *opt, const char *prefix,
                if (all_interesting)
                        show = 1;
                else {
-                       show = tree_entry_interesting(&desc->entry, base,
+                       show = tree_entry_interesting(&desc->entry, base, 0,
                                                      &opt->pathspec);
                        if (show == 2)
                                all_interesting = 1;
@@ -124,7 +124,7 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
                               struct diff_options *opt, int *all_interesting)
 {
        while (t->size) {
-               int show = tree_entry_interesting(&t->entry, base, &opt->pathspec);
+               int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
                if (show == 2)
                        *all_interesting = 1;
                if (!show) {
index 7596716cf0dc9bdd7af28778d193b0fd42f20a11..322becc3b4ad50b8e87fae8f6d5d38f7edc51f01 100644 (file)
@@ -544,7 +544,8 @@ static int match_dir_prefix(const char *base, int baselen,
 /*
  * Is a tree entry interesting given the pathspec we have?
  *
- * Pre-condition: baselen == 0 || base[baselen-1] == '/'
+ * Pre-condition: either baselen == base_offset (i.e. empty path)
+ * or base[baselen-1] == '/' (i.e. with trailing slash).
  *
  * Return:
  *  - 2 for "yes, and all subsequent entries will be"
@@ -553,44 +554,45 @@ static int match_dir_prefix(const char *base, int baselen,
  *  - negative for "no, and no subsequent entries will be either"
  */
 int tree_entry_interesting(const struct name_entry *entry,
-                          struct strbuf *base,
+                          struct strbuf *base, int base_offset,
                           const struct pathspec *ps)
 {
        int i;
-       int pathlen, baselen = base->len;
+       int pathlen, baselen = base->len - base_offset;
        int never_interesting = ps->has_wildcard ? 0 : -1;
 
        if (!ps->nr) {
                if (!ps->recursive || ps->max_depth == -1)
                        return 2;
-               return !!within_depth(base->buf, baselen,
+               return !!within_depth(base->buf + base_offset, baselen,
                                      !!S_ISDIR(entry->mode),
                                      ps->max_depth);
        }
 
        pathlen = tree_entry_len(entry->path, entry->sha1);
 
-       for (i = ps->nr-1; i >= 0; i--) {
+       for (i = ps->nr - 1; i >= 0; i--) {
                const struct pathspec_item *item = ps->items+i;
                const char *match = item->match;
+               const char *base_str = base->buf + base_offset;
                int matchlen = item->len;
 
                if (baselen >= matchlen) {
                        /* If it doesn't match, move along... */
-                       if (!match_dir_prefix(base->buf, baselen, match, matchlen))
+                       if (!match_dir_prefix(base_str, baselen, match, matchlen))
                                goto match_wildcards;
 
                        if (!ps->recursive || ps->max_depth == -1)
                                return 2;
 
-                       return !!within_depth(base->buf + matchlen + 1,
+                       return !!within_depth(base_str + matchlen + 1,
                                              baselen - matchlen - 1,
                                              !!S_ISDIR(entry->mode),
                                              ps->max_depth);
                }
 
                /* Does the base match? */
-               if (!strncmp(base->buf, match, baselen)) {
+               if (!strncmp(base_str, match, baselen)) {
                        if (match_entry(entry, pathlen,
                                        match + baselen, matchlen - baselen,
                                        &never_interesting))
@@ -622,11 +624,11 @@ match_wildcards:
 
                strbuf_add(base, entry->path, pathlen);
 
-               if (!fnmatch(match, base->buf, 0)) {
-                       strbuf_setlen(base, baselen);
+               if (!fnmatch(match, base->buf + base_offset, 0)) {
+                       strbuf_setlen(base, base_offset + baselen);
                        return 1;
                }
-               strbuf_setlen(base, baselen);
+               strbuf_setlen(base, base_offset + baselen);
 
                /*
                 * Match all directories. We'll try to match files
index 6589ee27e4047d5c8d1636de72250a864cf42b6b..39524b7dba6a1d0b63c4cd2b42db59a27a030b21 100644 (file)
@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
        return info->pathlen + tree_entry_len(n->path, n->sha1);
 }
 
-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps);
+extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
 
 #endif