diff options
Diffstat (limited to 'builtin/for-each-ref.c')
-rw-r--r-- | builtin/for-each-ref.c | 193 |
1 files changed, 135 insertions, 58 deletions
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 7f059c31df..f3ce004d53 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -9,6 +9,7 @@ #include "quote.h" #include "parse-options.h" #include "remote.h" +#include "color.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -75,6 +76,8 @@ static struct { { "upstream" }, { "symref" }, { "flag" }, + { "HEAD" }, + { "color" }, }; /* @@ -89,7 +92,8 @@ static struct { */ static const char **used_atom; static cmp_type *used_atom_type; -static int used_atom_cnt, sort_atom_limit, need_tagged, need_symref; +static int used_atom_cnt, need_tagged, need_symref; +static int need_color_reset_at_eol; /* * Used to parse format string and sort specifiers @@ -134,10 +138,8 @@ static int parse_atom(const char *atom, const char *ep) /* Add it in, including the deref prefix */ at = used_atom_cnt; used_atom_cnt++; - used_atom = xrealloc(used_atom, - (sizeof *used_atom) * used_atom_cnt); - used_atom_type = xrealloc(used_atom_type, - (sizeof(*used_atom_type) * used_atom_cnt)); + REALLOC_ARRAY(used_atom, used_atom_cnt); + REALLOC_ARRAY(used_atom_type, used_atom_cnt); used_atom[at] = xmemdupz(atom, ep - atom); used_atom_type[at] = valid_atom[i].cmp_type; if (*atom == '*') @@ -176,13 +178,21 @@ static const char *find_next(const char *cp) static int verify_format(const char *format) { const char *cp, *sp; + static const char color_reset[] = "color:reset"; + + need_color_reset_at_eol = 0; for (cp = format; *cp && (sp = find_next(cp)); ) { const char *ep = strchr(sp, ')'); + int at; + if (!ep) return error("malformed format string %s", sp); /* sp points at "%(" and ep points at the closing ")" */ - parse_atom(sp + 2, ep); + at = parse_atom(sp + 2, ep); cp = ep + 1; + + if (starts_with(used_atom[at], "color:")) + need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset); } return 0; } @@ -205,6 +215,22 @@ static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned lo return buf; } +static int grab_objectname(const char *name, const unsigned char *sha1, + struct atom_value *v) +{ + if (!strcmp(name, "objectname")) { + char *s = xmalloc(41); + strcpy(s, sha1_to_hex(sha1)); + v->s = s; + return 1; + } + if (!strcmp(name, "objectname:short")) { + v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); + return 1; + } + return 0; +} + /* See grab_values */ static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) { @@ -225,15 +251,8 @@ static void grab_common_values(struct atom_value *val, int deref, struct object v->ul = sz; v->s = s; } - else if (!strcmp(name, "objectname")) { - char *s = xmalloc(41); - strcpy(s, sha1_to_hex(obj->sha1)); - v->s = s; - } - else if (!strcmp(name, "objectname:short")) { - v->s = xstrdup(find_unique_abbrev(obj->sha1, - DEFAULT_ABBREV)); - } + else if (deref) + grab_objectname(name, obj->sha1, v); } } @@ -262,18 +281,6 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob } } -static int num_parents(struct commit *commit) -{ - struct commit_list *parents; - int i; - - for (i = 0, parents = commit->parents; - parents; - parents = parents->next) - i++; - return i; -} - /* See grab_values */ static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) { @@ -294,12 +301,12 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object } if (!strcmp(name, "numparent")) { char *s = xmalloc(40); - v->ul = num_parents(commit); + v->ul = commit_list_count(commit->parents); sprintf(s, "%lu", v->ul); v->s = s; } else if (!strcmp(name, "parent")) { - int num = num_parents(commit); + int num = commit_list_count(commit->parents); int i; struct commit_list *parents; char *s = xmalloc(41 * num + 1); @@ -432,7 +439,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru if (name[wholen] != 0 && strcmp(name + wholen, "name") && strcmp(name + wholen, "email") && - prefixcmp(name + wholen, "date")) + !starts_with(name + wholen, "date")) continue; if (!wholine) wholine = find_wholine(who, wholen, buf, sz); @@ -444,7 +451,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru v->s = copy_name(wholine); else if (!strcmp(name + wholen, "email")) v->s = copy_email(wholine); - else if (!prefixcmp(name + wholen, "date")) + else if (starts_with(name + wholen, "date")) grab_date(wholine, v, name); } @@ -466,7 +473,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru if (deref) name++; - if (!prefixcmp(name, "creatordate")) + if (starts_with(name, "creatordate")) grab_date(wholine, v, name); else if (!strcmp(name, "creator")) v->s = copy_line(wholine); @@ -624,11 +631,12 @@ static void populate_value(struct refinfo *ref) unsigned long size; const unsigned char *tagged; - ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt); + ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value)); if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) { unsigned char unused1[20]; - ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL); + ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING, + unused1, NULL); if (!ref->symref) ref->symref = ""; } @@ -640,20 +648,20 @@ static void populate_value(struct refinfo *ref) int deref = 0; const char *refname; const char *formatp; + struct branch *branch = NULL; if (*name == '*') { deref = 1; name++; } - if (!prefixcmp(name, "refname")) + if (starts_with(name, "refname")) refname = ref->refname; - else if (!prefixcmp(name, "symref")) + else if (starts_with(name, "symref")) refname = ref->symref ? ref->symref : ""; - else if (!prefixcmp(name, "upstream")) { - struct branch *branch; + else if (starts_with(name, "upstream")) { /* only local branches may have an upstream */ - if (prefixcmp(ref->refname, "refs/heads/")) + if (!starts_with(ref->refname, "refs/heads/")) continue; branch = branch_get(ref->refname + 11); @@ -661,8 +669,14 @@ static void populate_value(struct refinfo *ref) !branch->merge[0]->dst) continue; refname = branch->merge[0]->dst; - } - else if (!strcmp(name, "flag")) { + } else if (starts_with(name, "color:")) { + char color[COLOR_MAXLEN] = ""; + + if (color_parse(name + 6, color) < 0) + die(_("unable to parse format")); + v->s = xstrdup(color); + continue; + } else if (!strcmp(name, "flag")) { char buf[256], *cp = buf; if (ref->flag & REF_ISSYMREF) cp = copy_advance(cp, ",symref"); @@ -675,18 +689,63 @@ static void populate_value(struct refinfo *ref) v->s = xstrdup(buf + 1); } continue; - } - else + } else if (!deref && grab_objectname(name, ref->objectname, v)) { + continue; + } else if (!strcmp(name, "HEAD")) { + const char *head; + unsigned char sha1[20]; + + head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, + sha1, NULL); + if (!strcmp(ref->refname, head)) + v->s = "*"; + else + v->s = " "; + continue; + } else continue; formatp = strchr(name, ':'); - /* look for "short" refname format */ if (formatp) { + int num_ours, num_theirs; + formatp++; if (!strcmp(formatp, "short")) refname = shorten_unambiguous_ref(refname, warn_ambiguous_refs); - else + else if (!strcmp(formatp, "track") && + starts_with(name, "upstream")) { + char buf[40]; + + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = ""; + else if (!num_ours) { + sprintf(buf, "[behind %d]", num_theirs); + v->s = xstrdup(buf); + } else if (!num_theirs) { + sprintf(buf, "[ahead %d]", num_ours); + v->s = xstrdup(buf); + } else { + sprintf(buf, "[ahead %d, behind %d]", + num_ours, num_theirs); + v->s = xstrdup(buf); + } + continue; + } else if (!strcmp(formatp, "trackshort") && + starts_with(name, "upstream")) { + assert(branch); + stat_tracking_info(branch, &num_ours, &num_theirs); + if (!num_ours && !num_theirs) + v->s = "="; + else if (!num_ours) + v->s = "<"; + else if (!num_theirs) + v->s = ">"; + else + v->s = "<>"; + continue; + } else die("unknown %.*s format %s", (int)(formatp - name), name, formatp); } @@ -781,6 +840,11 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f struct refinfo *ref; int cnt; + if (flag & REF_BAD_NAME) { + warning("ignoring ref with broken name %s", refname); + return 0; + } + if (*cb->grab_pattern) { const char **pattern; int namelen = strlen(refname); @@ -794,7 +858,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f refname[plen] == '/' || p[plen-1] == '/')) break; - if (!fnmatch(p, refname, FNM_PATHNAME)) + if (!wildmatch(p, refname, WM_PATHNAME, NULL)) break; } if (!*pattern) @@ -812,8 +876,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f ref->flag = flag; cnt = cb->grab_cnt; - cb->grab_array = xrealloc(cb->grab_array, - sizeof(*cb->grab_array) * (cnt + 1)); + REALLOC_ARRAY(cb->grab_array, cnt + 1); cb->grab_array[cnt++] = ref; cb->grab_cnt = cnt; return 0; @@ -864,27 +927,30 @@ static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs); } -static void print_value(struct refinfo *ref, int atom, int quote_style) +static void print_value(struct atom_value *v, int quote_style) { - struct atom_value *v; - get_value(ref, atom, &v); + struct strbuf sb = STRBUF_INIT; switch (quote_style) { case QUOTE_NONE: fputs(v->s, stdout); break; case QUOTE_SHELL: - sq_quote_print(stdout, v->s); + sq_quote_buf(&sb, v->s); break; case QUOTE_PERL: - perl_quote_print(stdout, v->s); + perl_quote_buf(&sb, v->s); break; case QUOTE_PYTHON: - python_quote_print(stdout, v->s); + python_quote_buf(&sb, v->s); break; case QUOTE_TCL: - tcl_quote_print(stdout, v->s); + tcl_quote_buf(&sb, v->s); break; } + if (quote_style != QUOTE_NONE) { + fputs(sb.buf, stdout); + strbuf_release(&sb); + } } static int hex1(char ch) @@ -930,15 +996,27 @@ static void show_ref(struct refinfo *info, const char *format, int quote_style) const char *cp, *sp, *ep; for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) { + struct atom_value *atomv; + ep = strchr(sp, ')'); if (cp < sp) emit(cp, sp); - print_value(info, parse_atom(sp + 2, ep), quote_style); + get_value(info, parse_atom(sp + 2, ep), &atomv); + print_value(atomv, quote_style); } if (*cp) { sp = cp + strlen(cp); emit(cp, sp); } + if (need_color_reset_at_eol) { + struct atom_value resetv; + char color[COLOR_MAXLEN] = ""; + + if (color_parse("reset", color) < 0) + die("BUG: couldn't parse 'reset' as a color"); + resetv.s = color; + print_value(&resetv, quote_style); + } putchar('\n'); } @@ -997,7 +1075,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_BIT(0 , "python", "e_style, N_("quote placeholders suitably for python"), QUOTE_PYTHON), OPT_BIT(0 , "tcl", "e_style, - N_("quote placeholders suitably for tcl"), QUOTE_TCL), + N_("quote placeholders suitably for Tcl"), QUOTE_TCL), OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), @@ -1021,7 +1099,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) if (!sort) sort = default_sort(); - sort_atom_limit = used_atom_cnt; /* for warn_ambiguous_refs */ git_config(git_default_config, NULL); |