summaryrefslogtreecommitdiff
path: root/refs.c
diff options
context:
space:
mode:
authorLibravatar Taylor Blau <me@ttaylorr.com>2021-01-20 11:04:21 -0500
committerLibravatar Junio C Hamano <gitster@pobox.com>2021-01-22 18:57:27 -0800
commit16b1985be553b5fc6273eb9d7277173623e2d7cb (patch)
tree08a7ce8e52c33ae5b08eeeb4897d438ec0122e18 /refs.c
parentGit 2.30 (diff)
downloadtgif-16b1985be553b5fc6273eb9d7277173623e2d7cb.tar.xz
refs: expose 'for_each_fullref_in_prefixes'
This function was used in the ref-filter.c code to find the longest common prefix of among a set of refspecs, and then to iterate all of the references that descend from that prefix. A future patch will want to use that same code from ls-refs.c, so prepare by exposing and moving it to refs.c. Since there is nothing specific to the ref-filter code here (other than that it was previously the only caller of this function), this really belongs in the more generic refs.h header. The code moved in this patch is identical before and after, with the one exception of renaming some arguments to be consistent with other functions exposed in refs.h. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/refs.c b/refs.c
index 13dc2c3291..e0f439b7fd 100644
--- a/refs.c
+++ b/refs.c
@@ -1546,6 +1546,93 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
}
+static int qsort_strcmp(const void *va, const void *vb)
+{
+ const char *a = *(const char **)va;
+ const char *b = *(const char **)vb;
+
+ return strcmp(a, b);
+}
+
+static void find_longest_prefixes_1(struct string_list *out,
+ struct strbuf *prefix,
+ const char **patterns, size_t nr)
+{
+ size_t i;
+
+ for (i = 0; i < nr; i++) {
+ char c = patterns[i][prefix->len];
+ if (!c || is_glob_special(c)) {
+ string_list_append(out, prefix->buf);
+ return;
+ }
+ }
+
+ i = 0;
+ while (i < nr) {
+ size_t end;
+
+ /*
+ * Set "end" to the index of the element _after_ the last one
+ * in our group.
+ */
+ for (end = i + 1; end < nr; end++) {
+ if (patterns[i][prefix->len] != patterns[end][prefix->len])
+ break;
+ }
+
+ strbuf_addch(prefix, patterns[i][prefix->len]);
+ find_longest_prefixes_1(out, prefix, patterns + i, end - i);
+ strbuf_setlen(prefix, prefix->len - 1);
+
+ i = end;
+ }
+}
+
+static void find_longest_prefixes(struct string_list *out,
+ const char **patterns)
+{
+ struct strvec sorted = STRVEC_INIT;
+ struct strbuf prefix = STRBUF_INIT;
+
+ strvec_pushv(&sorted, patterns);
+ QSORT(sorted.v, sorted.nr, qsort_strcmp);
+
+ find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
+
+ strvec_clear(&sorted);
+ strbuf_release(&prefix);
+}
+
+int for_each_fullref_in_prefixes(const char *namespace,
+ const char **patterns,
+ each_ref_fn fn, void *cb_data,
+ unsigned int broken)
+{
+ struct string_list prefixes = STRING_LIST_INIT_DUP;
+ struct string_list_item *prefix;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 0, namespace_len;
+
+ find_longest_prefixes(&prefixes, patterns);
+
+ if (namespace)
+ strbuf_addstr(&buf, namespace);
+ namespace_len = buf.len;
+
+ for_each_string_list_item(prefix, &prefixes) {
+ strbuf_addstr(&buf, prefix->string);
+ ret = for_each_fullref_in(buf.buf, fn, cb_data, broken);
+ if (ret)
+ break;
+ strbuf_setlen(&buf, namespace_len);
+ }
+
+ string_list_clear(&prefixes, 0);
+ strbuf_release(&buf);
+ return ret;
+}
+
static int refs_read_special_head(struct ref_store *ref_store,
const char *refname, struct object_id *oid,
struct strbuf *referent, unsigned int *type)