rebase -i: implement the main part of interactive rebase as a builtin
[gitweb.git] / refspec.c
index ab37b5ba1ef8303a49e6b96c1c8d709eeb5ccf86..e8010dce0ce27472c2b3269e13b9c1de6a69f3cc 100644 (file)
--- a/refspec.c
+++ b/refspec.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "argv-array.h"
 #include "refs.h"
 #include "refspec.h"
 
@@ -48,6 +49,8 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
                size_t rlen = strlen(++rhs);
                is_glob = (1 <= rlen && strchr(rhs, '*'));
                item->dst = xstrndup(rhs, rlen);
+       } else {
+               item->dst = NULL;
        }
 
        llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
@@ -121,60 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
        return 1;
 }
 
-static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
-{
-       int i;
-       struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
-
-       for (i = 0; i < nr_refspec; i++) {
-               if (!parse_refspec(&rs[i], refspec[i], fetch))
-                       goto invalid;
-       }
-
-       return rs;
-
- invalid:
-       if (verify) {
-               /*
-                * nr_refspec must be greater than zero and i must be valid
-                * since it is only possible to reach this point from within
-                * the for loop above.
-                */
-               free_refspec(i+1, rs);
-               return NULL;
-       }
-       die("Invalid refspec '%s'", refspec[i]);
-}
-
-struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
+int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
 {
-       return parse_refspec_internal(nr_refspec, refspec, 1, 0);
-}
-
-struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
-{
-       return parse_refspec_internal(nr_refspec, refspec, 0, 0);
-}
-
-void free_refspec(int nr_refspec, struct refspec_item *refspec)
-{
-       int i;
-
-       if (!refspec)
-               return;
-
-       for (i = 0; i < nr_refspec; i++) {
-               free(refspec[i].src);
-               free(refspec[i].dst);
-       }
-       free(refspec);
+       memset(item, 0, sizeof(*item));
+       return parse_refspec(item, refspec, fetch);
 }
 
-void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
+                             int fetch)
 {
-       memset(item, 0, sizeof(*item));
-
-       if (!parse_refspec(item, refspec, fetch))
+       if (!refspec_item_init(item, refspec, fetch))
                die("Invalid refspec '%s'", refspec);
 }
 
@@ -198,7 +157,7 @@ void refspec_append(struct refspec *rs, const char *refspec)
 {
        struct refspec_item item;
 
-       refspec_item_init(&item, refspec, rs->fetch);
+       refspec_item_init_or_die(&item, refspec, rs->fetch);
 
        ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
        rs->items[rs->nr++] = item;
@@ -237,7 +196,37 @@ void refspec_clear(struct refspec *rs)
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
        struct refspec_item refspec;
-       int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+       int ret = refspec_item_init(&refspec, fetch_refspec_str, REFSPEC_FETCH);
        refspec_item_clear(&refspec);
        return ret;
 }
+
+void refspec_ref_prefixes(const struct refspec *rs,
+                         struct argv_array *ref_prefixes)
+{
+       int i;
+       for (i = 0; i < rs->nr; i++) {
+               const struct refspec_item *item = &rs->items[i];
+               const char *prefix = NULL;
+
+               if (item->exact_sha1)
+                       continue;
+               if (rs->fetch == REFSPEC_FETCH)
+                       prefix = item->src;
+               else if (item->dst)
+                       prefix = item->dst;
+               else if (item->src && !item->exact_sha1)
+                       prefix = item->src;
+
+               if (prefix) {
+                       if (item->pattern) {
+                               const char *glob = strchr(prefix, '*');
+                               argv_array_pushf(ref_prefixes, "%.*s",
+                                                (int)(glob - prefix),
+                                                prefix);
+                       } else {
+                               expand_ref_prefix(ref_prefixes, prefix);
+                       }
+               }
+       }
+}