convert report_path_error to take struct pathspec
[gitweb.git] / pathspec.c
index 6d99a3dcedbf7bec234094da37f1212cbd2fe368..2774bda47601664f9131d5b86afc6026139d0585 100644 (file)
@@ -57,49 +57,6 @@ char *find_pathspecs_matching_against_index(const char **pathspec)
        return seen;
 }
 
-/*
- * Check the index to see whether path refers to a submodule, or
- * something inside a submodule.  If the former, returns the path with
- * any trailing slash stripped.  If the latter, dies with an error
- * message.
- */
-const char *check_path_for_gitlink(const char *path)
-{
-       int i, path_len = strlen(path);
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
-               if (S_ISGITLINK(ce->ce_mode)) {
-                       int ce_len = ce_namelen(ce);
-                       if (path_len <= ce_len || path[ce_len] != '/' ||
-                           memcmp(ce->name, path, ce_len))
-                               /* path does not refer to this
-                                * submodule or anything inside it */
-                               continue;
-                       if (path_len == ce_len + 1) {
-                               /* path refers to submodule;
-                                * strip trailing slash */
-                               return xstrndup(ce->name, ce_len);
-                       } else {
-                               die (_("Path '%s' is in submodule '%.*s'"),
-                                    path, ce_len, ce->name);
-                       }
-               }
-       }
-       return path;
-}
-
-/*
- * Dies if the given path refers to a file inside a symlinked
- * directory in the index.
- */
-void die_if_path_beyond_symlink(const char *path, const char *prefix)
-{
-       if (has_symlink_leading_path(path, strlen(path))) {
-               int len = prefix ? strlen(prefix) : 0;
-               die(_("'%s' is beyond a symbolic link"), path + len);
-       }
-}
-
 /*
  * Magic pathspec
  *
@@ -203,8 +160,47 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
        else
                match = prefix_path(prefix, prefixlen, copyfrom);
        *raw = item->match = match;
-       item->original = elt;
+       /*
+        * Prefix the pathspec (keep all magic) and assign to
+        * original. Useful for passing to another command.
+        */
+       if (flags & PATHSPEC_PREFIX_ORIGIN) {
+               struct strbuf sb = STRBUF_INIT;
+               strbuf_add(&sb, elt, copyfrom - elt);
+               strbuf_addstr(&sb, match);
+               item->original = strbuf_detach(&sb, NULL);
+       } else
+               item->original = elt;
        item->len = strlen(item->match);
+
+       if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
+           (item->len >= 1 && item->match[item->len - 1] == '/') &&
+           (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
+           S_ISGITLINK(active_cache[i]->ce_mode)) {
+               item->len--;
+               match[item->len] = '\0';
+       }
+
+       if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
+               for (i = 0; i < active_nr; i++) {
+                       struct cache_entry *ce = active_cache[i];
+                       int ce_len = ce_namelen(ce);
+
+                       if (!S_ISGITLINK(ce->ce_mode))
+                               continue;
+
+                       if (item->len <= ce_len || match[ce_len] != '/' ||
+                           memcmp(ce->name, match, ce_len))
+                               continue;
+                       if (item->len == ce_len + 1) {
+                               /* strip trailing slash */
+                               item->len--;
+                               match[item->len] = '\0';
+                       } else
+                               die (_("Pathspec '%s' is in submodule '%.*s'"),
+                                    elt, ce_len, ce->name);
+               }
+
        if (limit_pathspec_to_literal())
                item->nowildcard_len = item->len;
        else
@@ -267,6 +263,9 @@ void parse_pathspec(struct pathspec *pathspec,
 
        memset(pathspec, 0, sizeof(*pathspec));
 
+       if (flags & PATHSPEC_MAXDEPTH_VALID)
+               pathspec->magic |= PATHSPEC_MAXDEPTH;
+
        /* No arguments, no prefix -> no pathspec */
        if (!entry && !prefix)
                return;
@@ -317,13 +316,24 @@ void parse_pathspec(struct pathspec *pathspec,
                        unsupported_magic(entry,
                                          item[i].magic & magic_mask,
                                          short_magic);
+
+               if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
+                   has_symlink_leading_path(item[i].match, item[i].len)) {
+                       die(_("pathspec '%s' is beyond a symbolic link"), entry);
+               }
+
                if (item[i].nowildcard_len < item[i].len)
                        pathspec->has_wildcard = 1;
                pathspec->magic |= item[i].magic;
        }
 
-       qsort(pathspec->items, pathspec->nr,
-             sizeof(struct pathspec_item), pathspec_item_cmp);
+
+       if (pathspec->magic & PATHSPEC_MAXDEPTH) {
+               if (flags & PATHSPEC_KEEP_ORDER)
+                       die("BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
+               qsort(pathspec->items, pathspec->nr,
+                     sizeof(struct pathspec_item), pathspec_item_cmp);
+       }
 }
 
 /*