Code

i18n: git-submodule "path not initialized" message
[git.git] / tree-walk.c
index be8182c72f90764c77807f6e872a0f333efa3edc..33f749e1e77484694e7b8f40a65755a7818c4abb 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,49 +554,88 @@ 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, int base_offset,
                           const struct pathspec *ps)
 {
        int i;
-       int pathlen, baselen = base->len;
-       int never_interesting = -1;
+       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))
-                               continue;
+                       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))
                                return 1;
+
+                       if (ps->items[i].use_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].use_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 + base_offset, 0)) {
+                       strbuf_setlen(base, base_offset + baselen);
+                       return 1;
+               }
+               strbuf_setlen(base, base_offset + 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 */
 }