summaryrefslogtreecommitdiff
path: root/ref-filter.c
diff options
context:
space:
mode:
authorLibravatar Jiang Xin <worldhello.net@gmail.com>2021-10-30 09:34:30 +0800
committerLibravatar Jiang Xin <worldhello.net@gmail.com>2021-10-30 09:34:30 +0800
commitcd9ef9ce67bf2934845a6a76a1ecdbc9a5f7a6e0 (patch)
treeba34cf45622ddcd8e9d250a048661a7e6a8a35ee /ref-filter.c
parentMerge branch 'master' of github.com:nafmo/git-l10n-sv (diff)
parentGit 2.34-rc0 (diff)
downloadtgif-cd9ef9ce67bf2934845a6a76a1ecdbc9a5f7a6e0.tar.xz
Merge branch 'master' of github.com:git/git
* 'master' of github.com:git/git: (762 commits) Git 2.34-rc0 wrapper: remove xunsetenv() log: document --encoding behavior on iconv() failure Revert "logmsg_reencode(): warn when iconv() fails" completion: fix incorrect bash/zsh string equality check add, rm, mv: fix bug that prevents the update of non-sparse dirs git-bundle.txt: add missing words and punctuation Documentation/Makefile: fix lint-docs mkdir dependency submodule: drop unused sm_name parameter from append_fetch_remotes() The fifteenth batch gitweb.txt: change "folder" to "directory" gitignore.txt: change "folder" to "directory" git-multi-pack-index.txt: change "folder" to "directory" git.txt: fix typo archive: describe compression level option config.txt: fix typo command-list.txt: remove 'sparse-index' from main help userdiff-cpp: back out the digit-separators in numbers submodule--helper: fix incorrect newlines in an error message branch (doc): -m/-c copies config and reflog ...
Diffstat (limited to 'ref-filter.c')
-rw-r--r--ref-filter.c276
1 files changed, 203 insertions, 73 deletions
diff --git a/ref-filter.c b/ref-filter.c
index 0cfef7b719..282cdad103 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -144,6 +144,7 @@ enum atom_type {
ATOM_BODY,
ATOM_TRAILERS,
ATOM_CONTENTS,
+ ATOM_RAW,
ATOM_UPSTREAM,
ATOM_PUSH,
ATOM_SYMREF,
@@ -156,6 +157,7 @@ enum atom_type {
ATOM_IF,
ATOM_THEN,
ATOM_ELSE,
+ ATOM_REST,
};
/*
@@ -190,6 +192,9 @@ static struct used_atom {
unsigned int nlines;
} contents;
struct {
+ enum { RAW_BARE, RAW_LENGTH } option;
+ } raw_data;
+ struct {
cmp_status cmp_status;
const char *str;
} if_then_else;
@@ -223,7 +228,7 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
return ret;
}
-static int color_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *color_value, struct strbuf *err)
{
if (!color_value)
@@ -261,7 +266,7 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
return 0;
}
-static int remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct string_list params = STRING_LIST_INIT_DUP;
@@ -308,7 +313,7 @@ static int remote_ref_atom_parser(const struct ref_format *format, struct used_a
return 0;
}
-static int objecttype_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int objecttype_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -320,7 +325,7 @@ static int objecttype_atom_parser(const struct ref_format *format, struct used_a
return 0;
}
-static int objectsize_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int objectsize_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -340,7 +345,7 @@ static int objectsize_atom_parser(const struct ref_format *format, struct used_a
return 0;
}
-static int deltabase_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int deltabase_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -352,7 +357,7 @@ static int deltabase_atom_parser(const struct ref_format *format, struct used_at
return 0;
}
-static int body_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
@@ -361,7 +366,7 @@ static int body_atom_parser(const struct ref_format *format, struct used_atom *a
return 0;
}
-static int subject_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int subject_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -373,7 +378,7 @@ static int subject_atom_parser(const struct ref_format *format, struct used_atom
return 0;
}
-static int trailers_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int trailers_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
atom->u.contents.trailer_opts.no_divider = 1;
@@ -399,7 +404,7 @@ static int trailers_atom_parser(const struct ref_format *format, struct used_ato
return 0;
}
-static int contents_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int contents_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -427,7 +432,19 @@ static int contents_atom_parser(const struct ref_format *format, struct used_ato
return 0;
}
-static int oid_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+ if (!arg)
+ atom->u.raw_data.option = RAW_BARE;
+ else if (!strcmp(arg, "size"))
+ atom->u.raw_data.option = RAW_LENGTH;
+ else
+ return strbuf_addf_ret(err, -1, _("unrecognized %%(raw) argument: %s"), arg);
+ return 0;
+}
+
+static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -446,7 +463,7 @@ static int oid_atom_parser(const struct ref_format *format, struct used_atom *at
return 0;
}
-static int person_email_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int person_email_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -460,7 +477,7 @@ static int person_email_atom_parser(const struct ref_format *format, struct used
return 0;
}
-static int refname_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int refname_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
@@ -477,7 +494,7 @@ static align_type parse_align_position(const char *s)
return -1;
}
-static int align_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct align *align = &atom->u.align;
@@ -529,7 +546,7 @@ static int align_atom_parser(const struct ref_format *format, struct used_atom *
return 0;
}
-static int if_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -544,7 +561,16 @@ static int if_atom_parser(const struct ref_format *format, struct used_atom *ato
return 0;
}
-static int head_atom_parser(const struct ref_format *format, struct used_atom *atom,
+static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+ if (arg)
+ return strbuf_addf_ret(err, -1, _("%%(rest) does not take arguments"));
+ format->use_rest = 1;
+ return 0;
+}
+
+static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *unused_err)
{
atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
@@ -555,7 +581,7 @@ static struct {
const char *name;
info_source source;
cmp_type cmp_type;
- int (*parser)(const struct ref_format *format, struct used_atom *atom,
+ int (*parser)(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err);
} valid_atom[] = {
[ATOM_REFNAME] = { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
@@ -587,6 +613,7 @@ static struct {
[ATOM_BODY] = { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
[ATOM_TRAILERS] = { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
[ATOM_CONTENTS] = { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+ [ATOM_RAW] = { "raw", SOURCE_OBJ, FIELD_STR, raw_atom_parser },
[ATOM_UPSTREAM] = { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
[ATOM_PUSH] = { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
[ATOM_SYMREF] = { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
@@ -599,13 +626,14 @@ static struct {
[ATOM_IF] = { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
[ATOM_THEN] = { "then", SOURCE_NONE },
[ATOM_ELSE] = { "else", SOURCE_NONE },
+ [ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
/*
* Please update $__git_ref_fieldlist in git-completion.bash
* when you add new atoms
*/
};
-#define REF_FORMATTING_STATE_INIT { 0, NULL }
+#define REF_FORMATTING_STATE_INIT { 0 }
struct ref_formatting_stack {
struct ref_formatting_stack *prev;
@@ -621,16 +649,23 @@ struct ref_formatting_state {
struct atom_value {
const char *s;
+ ssize_t s_size;
int (*handler)(struct atom_value *atomv, struct ref_formatting_state *state,
struct strbuf *err);
uintmax_t value; /* used for sorting when not FIELD_STR */
struct used_atom *atom;
};
+#define ATOM_SIZE_UNSPECIFIED (-1)
+
+#define ATOM_VALUE_INIT { \
+ .s_size = ATOM_SIZE_UNSPECIFIED \
+}
+
/*
* Used to parse format string and sort specifiers
*/
-static int parse_ref_filter_atom(const struct ref_format *format,
+static int parse_ref_filter_atom(struct ref_format *format,
const char *atom, const char *ep,
struct strbuf *err)
{
@@ -645,13 +680,6 @@ static int parse_ref_filter_atom(const struct ref_format *format,
return strbuf_addf_ret(err, -1, _("malformed field name: %.*s"),
(int)(ep-atom), atom);
- /* Do we have the atom already used elsewhere? */
- for (i = 0; i < used_atom_cnt; i++) {
- int len = strlen(used_atom[i].name);
- if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
- return i;
- }
-
/*
* If the atom name has a colon, strip it and everything after
* it off - it specifies the format for this entry, and
@@ -661,6 +689,13 @@ static int parse_ref_filter_atom(const struct ref_format *format,
arg = memchr(sp, ':', ep - sp);
atom_len = (arg ? arg : ep) - sp;
+ /* Do we have the atom already used elsewhere? */
+ for (i = 0; i < used_atom_cnt; i++) {
+ int len = strlen(used_atom[i].name);
+ if (len == ep - atom && !memcmp(used_atom[i].name, atom, len))
+ return i;
+ }
+
/* Is the atom a valid one? */
for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
int len = strlen(valid_atom[i].name);
@@ -710,17 +745,23 @@ static int parse_ref_filter_atom(const struct ref_format *format,
return at;
}
-static void quote_formatting(struct strbuf *s, const char *str, int quote_style)
+static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int quote_style)
{
switch (quote_style) {
case QUOTE_NONE:
- strbuf_addstr(s, str);
+ if (len < 0)
+ strbuf_addstr(s, str);
+ else
+ strbuf_add(s, str, len);
break;
case QUOTE_SHELL:
sq_quote_buf(s, str);
break;
case QUOTE_PERL:
- perl_quote_buf(s, str);
+ if (len < 0)
+ perl_quote_buf(s, str);
+ else
+ perl_quote_buf_with_len(s, str, len);
break;
case QUOTE_PYTHON:
python_quote_buf(s, str);
@@ -741,9 +782,11 @@ static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
* encountered.
*/
if (!state->stack->prev)
- quote_formatting(&state->stack->output, v->s, state->quote_style);
- else
+ quote_formatting(&state->stack->output, v->s, v->s_size, state->quote_style);
+ else if (v->s_size < 0)
strbuf_addstr(&state->stack->output, v->s);
+ else
+ strbuf_add(&state->stack->output, v->s, v->s_size);
return 0;
}
@@ -843,21 +886,23 @@ static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state
return 0;
}
-static int is_empty(const char *s)
+static int is_empty(struct strbuf *buf)
{
- while (*s != '\0') {
- if (!isspace(*s))
- return 0;
- s++;
- }
- return 1;
-}
+ const char *cur = buf->buf;
+ const char *end = buf->buf + buf->len;
+
+ while (cur != end && (isspace(*cur)))
+ cur++;
+
+ return cur == end;
+ }
static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *cur = state->stack;
struct if_then_else *if_then_else = NULL;
+ size_t str_len = 0;
if (cur->at_end == if_then_else_handler)
if_then_else = (struct if_then_else *)cur->at_end_data;
@@ -868,18 +913,22 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
if (if_then_else->else_atom_seen)
return strbuf_addf_ret(err, -1, _("format: %%(then) atom used after %%(else)"));
if_then_else->then_atom_seen = 1;
+ if (if_then_else->str)
+ str_len = strlen(if_then_else->str);
/*
* If the 'equals' or 'notequals' attribute is used then
* perform the required comparison. If not, only non-empty
* strings satisfy the 'if' condition.
*/
if (if_then_else->cmp_status == COMPARE_EQUAL) {
- if (!strcmp(if_then_else->str, cur->output.buf))
+ if (str_len == cur->output.len &&
+ !memcmp(if_then_else->str, cur->output.buf, cur->output.len))
if_then_else->condition_satisfied = 1;
} else if (if_then_else->cmp_status == COMPARE_UNEQUAL) {
- if (strcmp(if_then_else->str, cur->output.buf))
+ if (str_len != cur->output.len ||
+ memcmp(if_then_else->str, cur->output.buf, cur->output.len))
if_then_else->condition_satisfied = 1;
- } else if (cur->output.len && !is_empty(cur->output.buf))
+ } else if (cur->output.len && !is_empty(&cur->output))
if_then_else->condition_satisfied = 1;
strbuf_reset(&cur->output);
return 0;
@@ -925,7 +974,7 @@ static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
* only on the topmost supporting atom.
*/
if (!current->prev->prev) {
- quote_formatting(&s, current->output.buf, state->quote_style);
+ quote_formatting(&s, current->output.buf, current->output.len, state->quote_style);
strbuf_swap(&current->output, &s);
}
strbuf_release(&s);
@@ -955,6 +1004,11 @@ static const char *find_next(const char *cp)
return NULL;
}
+static int reject_atom(enum atom_type atom_type)
+{
+ return atom_type == ATOM_REST;
+}
+
/*
* Make sure the format string is well formed, and parse out
* the used atoms.
@@ -975,6 +1029,16 @@ int verify_ref_format(struct ref_format *format)
at = parse_ref_filter_atom(format, sp + 2, ep, &err);
if (at < 0)
die("%s", err.buf);
+ if (reject_atom(used_atom[at].atom_type))
+ die(_("this command reject atom %%(%.*s)"), (int)(ep - sp - 2), sp + 2);
+
+ if ((format->quote_style == QUOTE_PYTHON ||
+ format->quote_style == QUOTE_SHELL ||
+ format->quote_style == QUOTE_TCL) &&
+ used_atom[at].atom_type == ATOM_RAW &&
+ used_atom[at].u.raw_data.option == RAW_BARE)
+ die(_("--format=%.*s cannot be used with"
+ "--python, --shell, --tcl"), (int)(ep - sp - 2), sp + 2);
cp = ep + 1;
if (skip_prefix(used_atom[at].name, "color:", &color))
@@ -1357,25 +1421,42 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
}
/* See grab_values */
-static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
+static void grab_sub_body_contents(struct atom_value *val, int deref, struct expand_data *data)
{
int i;
const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
size_t sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;
+ void *buf = data->content;
for (i = 0; i < used_atom_cnt; i++) {
struct used_atom *atom = &used_atom[i];
const char *name = atom->name;
struct atom_value *v = &val[i];
+ enum atom_type atom_type = atom->atom_type;
if (!!deref != (*name == '*'))
continue;
if (deref)
name++;
- if (strcmp(name, "body") &&
- !starts_with(name, "subject") &&
- !starts_with(name, "trailers") &&
- !starts_with(name, "contents"))
+
+ if (atom_type == ATOM_RAW) {
+ unsigned long buf_size = data->size;
+
+ if (atom->u.raw_data.option == RAW_BARE) {
+ v->s = xmemdupz(buf, buf_size);
+ v->s_size = buf_size;
+ } else if (atom->u.raw_data.option == RAW_LENGTH) {
+ v->s = xstrfmt("%"PRIuMAX, (uintmax_t)buf_size);
+ }
+ continue;
+ }
+
+ if ((data->type != OBJ_TAG &&
+ data->type != OBJ_COMMIT) ||
+ (strcmp(name, "body") &&
+ !starts_with(name, "subject") &&
+ !starts_with(name, "trailers") &&
+ !starts_with(name, "contents")))
continue;
if (!subpos)
find_subpos(buf,
@@ -1439,25 +1520,29 @@ static void fill_missing_values(struct atom_value *val)
* pointed at by the ref itself; otherwise it is the object the
* ref (which is a tag) refers to.
*/
-static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf)
+static void grab_values(struct atom_value *val, int deref, struct object *obj, struct expand_data *data)
{
+ void *buf = data->content;
+
switch (obj->type) {
case OBJ_TAG:
grab_tag_values(val, deref, obj);
- grab_sub_body_contents(val, deref, buf);
+ grab_sub_body_contents(val, deref, data);
grab_person("tagger", val, deref, buf);
break;
case OBJ_COMMIT:
grab_commit_values(val, deref, obj);
- grab_sub_body_contents(val, deref, buf);
+ grab_sub_body_contents(val, deref, data);
grab_person("author", val, deref, buf);
grab_person("committer", val, deref, buf);
break;
case OBJ_TREE:
/* grab_tree_values(val, deref, obj, buf, sz); */
+ grab_sub_body_contents(val, deref, data);
break;
case OBJ_BLOB:
/* grab_blob_values(val, deref, obj, buf, sz); */
+ grab_sub_body_contents(val, deref, data);
break;
default:
die("Eh? Object of type %d?", obj->type);
@@ -1679,7 +1764,7 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
oid_to_hex(&oi->oid), ref->refname);
}
- grab_values(ref->value, deref, *obj, oi->content);
+ grab_values(ref->value, deref, *obj, oi);
}
grab_common_values(ref->value, deref, oi);
@@ -1761,6 +1846,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
const char *refname;
struct branch *branch = NULL;
+ v->s_size = ATOM_SIZE_UNSPECIFIED;
v->handler = append_atom;
v->atom = atom;
@@ -1864,6 +1950,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
v->handler = else_atom_handler;
v->s = xstrdup("");
continue;
+ } else if (atom_type == ATOM_REST) {
+ if (ref->rest)
+ v->s = xstrdup(ref->rest);
+ else
+ v->s = xstrdup("");
+ continue;
} else
continue;
@@ -2008,8 +2100,7 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
*/
static int for_each_fullref_in_pattern(struct ref_filter *filter,
each_ref_fn cb,
- void *cb_data,
- int broken)
+ void *cb_data)
{
if (!filter->match_as_path) {
/*
@@ -2017,7 +2108,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
* prefixes like "refs/heads/" etc. are stripped off,
* so we have to look at everything:
*/
- return for_each_fullref_in("", cb, cb_data, broken);
+ return for_each_fullref_in("", cb, cb_data);
}
if (filter->ignore_case) {
@@ -2026,16 +2117,16 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
* so just return everything and let the caller
* sort it out.
*/
- return for_each_fullref_in("", cb, cb_data, broken);
+ return for_each_fullref_in("", cb, cb_data);
}
if (!filter->name_patterns[0]) {
/* no patterns; we have to look at everything */
- return for_each_fullref_in("", cb, cb_data, broken);
+ return for_each_fullref_in("", cb, cb_data);
}
return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
- cb, cb_data, broken);
+ cb, cb_data);
}
/*
@@ -2081,6 +2172,7 @@ static struct ref_array_item *new_ref_array_item(const char *refname,
FLEX_ALLOC_STR(ref, refname, refname);
oidcpy(&ref->objectname, oid);
+ ref->rest = NULL;
return ref;
}
@@ -2312,13 +2404,10 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
{
struct ref_filter_cbdata ref_cbdata;
int ret = 0;
- unsigned int broken = 0;
ref_cbdata.array = array;
ref_cbdata.filter = filter;
- if (type & FILTER_REFS_INCLUDE_BROKEN)
- broken = 1;
filter->kind = type & FILTER_REFS_KIND_MASK;
init_contains_cache(&ref_cbdata.contains_cache);
@@ -2335,13 +2424,13 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
* of filter_ref_kind().
*/
if (filter->kind == FILTER_REFS_BRANCHES)
- ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata, broken);
+ ret = for_each_fullref_in("refs/heads/", ref_filter_handler, &ref_cbdata);
else if (filter->kind == FILTER_REFS_REMOTES)
- ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata, broken);
+ ret = for_each_fullref_in("refs/remotes/", ref_filter_handler, &ref_cbdata);
else if (filter->kind == FILTER_REFS_TAGS)
- ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken);
+ ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata);
else if (filter->kind & FILTER_REFS_ALL)
- ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata, broken);
+ ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata);
if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
head_ref(ref_filter_handler, &ref_cbdata);
}
@@ -2368,6 +2457,19 @@ static int compare_detached_head(struct ref_array_item *a, struct ref_array_item
return 0;
}
+static int memcasecmp(const void *vs1, const void *vs2, size_t n)
+{
+ const char *s1 = vs1, *s2 = vs2;
+ const char *end = s1 + n;
+
+ for (; s1 < end; s1++, s2++) {
+ int diff = tolower(*s1) - tolower(*s2);
+ if (diff)
+ return diff;
+ }
+ return 0;
+}
+
static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
{
struct atom_value *va, *vb;
@@ -2388,10 +2490,29 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
} else if (s->sort_flags & REF_SORTING_VERSION) {
cmp = versioncmp(va->s, vb->s);
} else if (cmp_type == FIELD_STR) {
- int (*cmp_fn)(const char *, const char *);
- cmp_fn = s->sort_flags & REF_SORTING_ICASE
- ? strcasecmp : strcmp;
- cmp = cmp_fn(va->s, vb->s);
+ if (va->s_size < 0 && vb->s_size < 0) {
+ int (*cmp_fn)(const char *, const char *);
+ cmp_fn = s->sort_flags & REF_SORTING_ICASE
+ ? strcasecmp : strcmp;
+ cmp = cmp_fn(va->s, vb->s);
+ } else {
+ size_t a_size = va->s_size < 0 ?
+ strlen(va->s) : va->s_size;
+ size_t b_size = vb->s_size < 0 ?
+ strlen(vb->s) : vb->s_size;
+ int (*cmp_fn)(const void *, const void *, size_t);
+ cmp_fn = s->sort_flags & REF_SORTING_ICASE
+ ? memcasecmp : memcmp;
+
+ cmp = cmp_fn(va->s, vb->s, b_size > a_size ?
+ a_size : b_size);
+ if (!cmp) {
+ if (a_size > b_size)
+ cmp = 1;
+ else if (a_size < b_size)
+ cmp = -1;
+ }
+ }
} else {
if (va->value < vb->value)
cmp = -1;
@@ -2461,9 +2582,9 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
}
int format_ref_array_item(struct ref_array_item *info,
- const struct ref_format *format,
- struct strbuf *final_buf,
- struct strbuf *error_buf)
+ struct ref_format *format,
+ struct strbuf *final_buf,
+ struct strbuf *error_buf)
{
const char *cp, *sp, *ep;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
@@ -2490,7 +2611,7 @@ int format_ref_array_item(struct ref_array_item *info,
append_literal(cp, sp, &state);
}
if (format->need_color_reset_at_eol) {
- struct atom_value resetv;
+ struct atom_value resetv = ATOM_VALUE_INIT;
resetv.s = GIT_COLOR_RESET;
if (append_atom(&resetv, &state, error_buf)) {
pop_stack_element(&state.stack);
@@ -2507,7 +2628,7 @@ int format_ref_array_item(struct ref_array_item *info,
}
void pretty_print_ref(const char *name, const struct object_id *oid,
- const struct ref_format *format)
+ struct ref_format *format)
{
struct ref_array_item *ref_item;
struct strbuf output = STRBUF_INIT;
@@ -2584,6 +2705,15 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
return 0;
}
+void ref_sorting_release(struct ref_sorting *sorting)
+{
+ while (sorting) {
+ struct ref_sorting *next = sorting->next;
+ free(sorting);
+ sorting = next;
+ }
+}
+
int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
{
struct ref_filter *rf = opt->value;