pathspec: add match_pathspec_depth()
[gitweb.git] / tree-walk.c
index 33feafa964c86bd76df0d9d53d930530cf78918d..7596716cf0dc9bdd7af28778d193b0fd42f20a11 100644 (file)
@@ -553,12 +553,12 @@ 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,
-                          const struct strbuf *base,
+                          struct strbuf *base,
                           const struct pathspec *ps)
 {
        int i;
        int pathlen, baselen = base->len;
-       int never_interesting = -1;
+       int never_interesting = ps->has_wildcard ? 0 : -1;
 
        if (!ps->nr) {
                if (!ps->recursive || ps->max_depth == -1)
@@ -570,7 +570,7 @@ int tree_entry_interesting(const struct name_entry *entry,
 
        pathlen = tree_entry_len(entry->path, entry->sha1);
 
-       for (i = 0; i < ps->nr; i++) {
+       for (i = ps->nr-1; i >= 0; i--) {
                const struct pathspec_item *item = ps->items+i;
                const char *match = item->match;
                int matchlen = item->len;
@@ -578,7 +578,7 @@ int tree_entry_interesting(const struct name_entry *entry,
                if (baselen >= matchlen) {
                        /* If it doesn't match, move along... */
                        if (!match_dir_prefix(base->buf, baselen, match, matchlen))
-                               continue;
+                               goto match_wildcards;
 
                        if (!ps->recursive || ps->max_depth == -1)
                                return 2;
@@ -595,7 +595,45 @@ int tree_entry_interesting(const struct name_entry *entry,
                                        match + baselen, matchlen - baselen,
                                        &never_interesting))
                                return 1;
+
+                       if (ps->items[i].has_wildcard) {
+                               if (!fnmatch(match + baselen, entry->path, 0))
+                                       return 1;
+
+                               /*
+                                * Match all directories. We'll try to
+                                * match files later on.
+                                */
+                               if (ps->recursive && S_ISDIR(entry->mode))
+                                       return 1;
+                       }
+
+                       continue;
                }
+
+match_wildcards:
+               if (!ps->items[i].has_wildcard)
+                       continue;
+
+               /*
+                * Concatenate base and entry->path into one and do
+                * fnmatch() on it.
+                */
+
+               strbuf_add(base, entry->path, pathlen);
+
+               if (!fnmatch(match, base->buf, 0)) {
+                       strbuf_setlen(base, baselen);
+                       return 1;
+               }
+               strbuf_setlen(base, baselen);
+
+               /*
+                * Match all directories. We'll try to match files
+                * later on.
+                */
+               if (ps->recursive && S_ISDIR(entry->mode))
+                       return 1;
        }
        return never_interesting; /* No matches */
 }