diff options
Diffstat (limited to 'ref-filter.c')
-rw-r--r-- | ref-filter.c | 148 |
1 files changed, 108 insertions, 40 deletions
diff --git a/ref-filter.c b/ref-filter.c index 3a64044..ab32bc9 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -93,6 +93,7 @@ static struct used_atom { unsigned int length; } objectname; struct refname_atom refname; + char *head; } u; } *used_atom; static int used_atom_cnt, need_tagged, need_symref; @@ -287,6 +288,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg) } } +static void head_atom_parser(struct used_atom *atom, const char *arg) +{ + struct object_id unused; + + atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused.hash, NULL); +} static struct { const char *name; @@ -325,7 +332,7 @@ static struct { { "push", FIELD_STR, remote_ref_atom_parser }, { "symref", FIELD_STR, refname_atom_parser }, { "flag" }, - { "HEAD" }, + { "HEAD", FIELD_STR, head_atom_parser }, { "color", FIELD_STR, color_atom_parser }, { "align", FIELD_STR, align_atom_parser }, { "end" }, @@ -351,7 +358,7 @@ struct ref_formatting_state { struct atom_value { const char *s; void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state); - unsigned long ul; /* used for sorting when not FIELD_STR */ + uintmax_t value; /* used for sorting when not FIELD_STR */ struct used_atom *atom; }; @@ -677,13 +684,13 @@ int verify_ref_format(const char *format) * by the "struct object" representation, set *eaten as well---it is a * signal from parse_object_buffer to us not to free the buffer. */ -static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten) +static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten) { enum object_type type; - void *buf = read_sha1_file(sha1, &type, sz); + void *buf = read_sha1_file(oid->hash, &type, sz); if (buf) - *obj = parse_object_buffer(sha1, type, *sz, buf, eaten); + *obj = parse_object_buffer(oid, type, *sz, buf, eaten); else *obj = NULL; return buf; @@ -723,7 +730,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object if (!strcmp(name, "objecttype")) v->s = typename(obj->type); else if (!strcmp(name, "objectsize")) { - v->ul = sz; + v->value = sz; v->s = xstrfmt("%lu", sz); } else if (deref) @@ -770,8 +777,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object v->s = xstrdup(oid_to_hex(&commit->tree->object.oid)); } else if (!strcmp(name, "numparent")) { - v->ul = commit_list_count(commit->parents); - v->s = xstrfmt("%lu", v->ul); + v->value = commit_list_count(commit->parents); + v->s = xstrfmt("%lu", (unsigned long)v->value); } else if (!strcmp(name, "parent")) { struct commit_list *parents; @@ -849,7 +856,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam { const char *eoemail = strstr(buf, "> "); char *zone; - unsigned long timestamp; + timestamp_t timestamp; long tz; struct date_mode date_mode = { DATE_NORMAL }; const char *formatp; @@ -868,18 +875,18 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam if (!eoemail) goto bad; - timestamp = strtoul(eoemail + 2, &zone, 10); - if (timestamp == ULONG_MAX) + timestamp = parse_timestamp(eoemail + 2, &zone, 10); + if (timestamp == TIME_MAX) goto bad; tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; v->s = xstrdup(show_date(timestamp, tz, &date_mode)); - v->ul = timestamp; + v->value = timestamp; return; bad: v->s = ""; - v->ul = 0; + v->value = 0; } /* See grab_values */ @@ -1251,13 +1258,17 @@ char *get_head_description(void) state.branch); else if (state.detached_from) { if (state.detached_at) - /* TRANSLATORS: make sure this matches - "HEAD detached at " in wt-status.c */ + /* + * TRANSLATORS: make sure this matches "HEAD + * detached at " in wt-status.c + */ strbuf_addf(&desc, _("(HEAD detached at %s)"), state.detached_from); else - /* TRANSLATORS: make sure this matches - "HEAD detached from " in wt-status.c */ + /* + * TRANSLATORS: make sure this matches "HEAD + * detached from " in wt-status.c + */ strbuf_addf(&desc, _("(HEAD detached from %s)"), state.detached_from); } @@ -1293,7 +1304,7 @@ static void populate_value(struct ref_array_item *ref) struct object *obj; int eaten, i; unsigned long size; - const unsigned char *tagged; + const struct object_id *tagged; ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value)); @@ -1366,15 +1377,10 @@ static void populate_value(struct ref_array_item *ref) v->s = xstrdup(buf + 1); } continue; - } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) { + } else if (!deref && grab_objectname(name, ref->objectname.hash, v, atom)) { continue; } else if (!strcmp(name, "HEAD")) { - const char *head; - unsigned char sha1[20]; - - head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, - sha1, NULL); - if (head && !strcmp(ref->refname, head)) + if (atom->u.head && !strcmp(ref->refname, atom->u.head)) v->s = "*"; else v->s = " "; @@ -1415,13 +1421,13 @@ static void populate_value(struct ref_array_item *ref) return; need_obj: - buf = get_obj(ref->objectname, &obj, &size, &eaten); + buf = get_obj(&ref->objectname, &obj, &size, &eaten); if (!buf) die(_("missing object %s for %s"), - sha1_to_hex(ref->objectname), ref->refname); + oid_to_hex(&ref->objectname), ref->refname); if (!obj) die(_("parse_object_buffer failed on %s for %s"), - sha1_to_hex(ref->objectname), ref->refname); + oid_to_hex(&ref->objectname), ref->refname); grab_values(ref->value, 0, obj, buf, size); if (!eaten) @@ -1438,7 +1444,7 @@ static void populate_value(struct ref_array_item *ref) * If it is a tag object, see if we use a value that derefs * the object, and if we do grab the object it refers to. */ - tagged = ((struct tag *)obj)->tagged->oid.hash; + tagged = &((struct tag *)obj)->tagged->oid; /* * NEEDSWORK: This derefs tag only once, which @@ -1449,10 +1455,10 @@ static void populate_value(struct ref_array_item *ref) buf = get_obj(tagged, &obj, &size, &eaten); if (!buf) die(_("missing object %s for %s"), - sha1_to_hex(tagged), ref->refname); + oid_to_hex(tagged), ref->refname); if (!obj) die(_("parse_object_buffer failed on %s for %s"), - sha1_to_hex(tagged), ref->refname); + oid_to_hex(tagged), ref->refname); grab_values(ref->value, 1, obj, buf, size); if (!eaten) free(buf); @@ -1666,6 +1672,68 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname) } /* + * Find the longest prefix of pattern we can pass to + * `for_each_fullref_in()`, namely the part of pattern preceding the + * first glob character. (Note that `for_each_fullref_in()` is + * perfectly happy working with a prefix that doesn't end at a + * pathname component boundary.) + */ +static void find_longest_prefix(struct strbuf *out, const char *pattern) +{ + const char *p; + + for (p = pattern; *p && !is_glob_special(*p); p++) + ; + + strbuf_add(out, pattern, p - pattern); +} + +/* + * This is the same as for_each_fullref_in(), but it tries to iterate + * only over the patterns we'll care about. Note that it _doesn't_ do a full + * pattern match, so the callback still has to match each ref individually. + */ +static int for_each_fullref_in_pattern(struct ref_filter *filter, + each_ref_fn cb, + void *cb_data, + int broken) +{ + struct strbuf prefix = STRBUF_INIT; + int ret; + + if (!filter->match_as_path) { + /* + * in this case, the patterns are applied after + * prefixes like "refs/heads/" etc. are stripped off, + * so we have to look at everything: + */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + if (!filter->name_patterns[0]) { + /* no patterns; we have to look at everything */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + if (filter->name_patterns[1]) { + /* + * multiple patterns; in theory this could still work as long + * as the patterns are disjoint. We'd just make multiple calls + * to for_each_ref(). But if they're not disjoint, we'd end up + * reporting the same ref multiple times. So let's punt on that + * for now. + */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + find_longest_prefix(&prefix, filter->name_patterns[0]); + + ret = for_each_fullref_in(prefix.buf, cb, cb_data, broken); + strbuf_release(&prefix); + return ret; +} + +/* * Given a ref (sha1, refname), check if the ref belongs to the array * of sha1s. If the given ref is a tag, check if the given tag points * at one of the sha1s in the given sha1 array. @@ -1687,7 +1755,7 @@ static const struct object_id *match_points_at(struct oid_array *points_at, if (oid_array_lookup(points_at, oid) >= 0) return oid; - obj = parse_object(oid->hash); + obj = parse_object(oid); if (!obj) die(_("malformed object at '%s'"), refname); if (obj->type == OBJ_TAG) @@ -1704,7 +1772,7 @@ static struct ref_array_item *new_ref_array_item(const char *refname, { struct ref_array_item *ref; FLEX_ALLOC_STR(ref, refname, refname); - hashcpy(ref->objectname, objectname); + hashcpy(ref->objectname.hash, objectname); ref->flag = flag; return ref; @@ -1782,7 +1850,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * non-commits early. The actual filtering is done later. */ if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { - commit = lookup_commit_reference_gently(oid->hash, 1); + commit = lookup_commit_reference_gently(oid, 1); if (!commit) return 0; /* We perform the filtering for the '--contains' option... */ @@ -1911,7 +1979,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int else if (filter->kind == FILTER_REFS_TAGS) ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken); else if (filter->kind & FILTER_REFS_ALL) - ret = for_each_fullref_in("", ref_filter_handler, &ref_cbdata, broken); + ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata, broken); if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD)) head_ref(ref_filter_handler, &ref_cbdata); } @@ -1941,9 +2009,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru else if (cmp_type == FIELD_STR) cmp = cmp_fn(va->s, vb->s); else { - if (va->ul < vb->ul) + if (va->value < vb->value) cmp = -1; - else if (va->ul == vb->ul) + else if (va->value == vb->value) cmp = cmp_fn(a->refname, b->refname); else cmp = 1; @@ -2090,7 +2158,7 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset) int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; - unsigned char sha1[20]; + struct object_id oid; int no_merged = starts_with(opt->long_name, "no"); if (rf->merge) { @@ -2105,10 +2173,10 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) ? REF_FILTER_MERGED_OMIT : REF_FILTER_MERGED_INCLUDE; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) die(_("malformed object name %s"), arg); - rf->merge_commit = lookup_commit_reference_gently(sha1, 0); + rf->merge_commit = lookup_commit_reference_gently(&oid, 0); if (!rf->merge_commit) return opterror(opt, "must point to a commit", 0); |