diff options
Diffstat (limited to 'builtin-for-each-ref.c')
-rw-r--r-- | builtin-for-each-ref.c | 218 |
1 files changed, 102 insertions, 116 deletions
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 0327f40306..daf3a08165 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -7,6 +7,7 @@ #include "tree.h" #include "blob.h" #include "quote.h" +#include "parse-options.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -87,7 +88,6 @@ static int used_atom_cnt, sort_atom_limit, need_tagged; static int parse_atom(const char *atom, const char *ep) { const char *sp; - char *n; int i, at; sp = atom; @@ -106,7 +106,16 @@ static int parse_atom(const char *atom, const char *ep) /* Is the atom a valid one? */ for (i = 0; i < ARRAY_SIZE(valid_atom); i++) { int len = strlen(valid_atom[i].name); - if (len == ep - sp && !memcmp(valid_atom[i].name, sp, len)) + /* + * If the atom name has a colon, strip it and everything after + * it off - it specifies the format for this entry, and + * shouldn't be used for checking against the valid_atom + * table. + */ + const char *formatp = strchr(sp, ':'); + if (!formatp || ep < formatp) + formatp = ep; + if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len)) break; } @@ -120,10 +129,7 @@ static int parse_atom(const char *atom, const char *ep) (sizeof *used_atom) * used_atom_cnt); used_atom_type = xrealloc(used_atom_type, (sizeof(*used_atom_type) * used_atom_cnt)); - n = xmalloc(ep - atom + 1); - memcpy(n, atom, ep - atom); - n[ep-atom] = 0; - used_atom[at] = n; + used_atom[at] = xmemdupz(atom, ep - atom); used_atom_type[at] = valid_atom[i].cmp_type; return at; } @@ -153,17 +159,18 @@ static const char *find_next(const char *cp) * Make sure the format string is well formed, and parse out * the used atoms. */ -static void verify_format(const char *format) +static int verify_format(const char *format) { const char *cp, *sp; for (cp = format; *cp && (sp = find_next(cp)); ) { const char *ep = strchr(sp, ')'); if (!ep) - die("malformatted format string %s", sp); + return error("malformatted format string %s", sp); /* sp points at "%(" and ep points at the closing ")" */ parse_atom(sp + 2, ep); cp = ep + 1; } + return 0; } /* @@ -307,54 +314,50 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un static const char *copy_line(const char *buf) { const char *eol = strchr(buf, '\n'); - char *line; - int len; if (!eol) return ""; - len = eol - buf; - line = xmalloc(len + 1); - memcpy(line, buf, len); - line[len] = 0; - return line; + return xmemdupz(buf, eol - buf); } static const char *copy_name(const char *buf) { - const char *eol = strchr(buf, '\n'); - const char *eoname = strstr(buf, " <"); - char *line; - int len; - if (!(eoname && eol && eoname < eol)) - return ""; - len = eoname - buf; - line = xmalloc(len + 1); - memcpy(line, buf, len); - line[len] = 0; - return line; + const char *cp; + for (cp = buf; *cp && *cp != '\n'; cp++) { + if (!strncmp(cp, " <", 2)) + return xmemdupz(buf, cp - buf); + } + return ""; } static const char *copy_email(const char *buf) { const char *email = strchr(buf, '<'); const char *eoemail = strchr(email, '>'); - char *line; - int len; if (!email || !eoemail) return ""; - eoemail++; - len = eoemail - email; - line = xmalloc(len + 1); - memcpy(line, email, len); - line[len] = 0; - return line; + return xmemdupz(email, eoemail + 1 - email); } -static void grab_date(const char *buf, struct atom_value *v) +static void grab_date(const char *buf, struct atom_value *v, const char *atomname) { const char *eoemail = strstr(buf, "> "); char *zone; unsigned long timestamp; long tz; + enum date_mode date_mode = DATE_NORMAL; + const char *formatp; + + /* + * We got here because atomname ends in "date" or "date<something>"; + * it's not possible that <something> is not ":<format>" because + * parse_atom() wouldn't have allowed it, so we can assume that no + * ":" means no format is specified, and use the default. + */ + formatp = strchr(atomname, ':'); + if (formatp != NULL) { + formatp++; + date_mode = parse_date_format(formatp); + } if (!eoemail) goto bad; @@ -364,7 +367,7 @@ static void grab_date(const char *buf, struct atom_value *v) tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; - v->s = xstrdup(show_date(timestamp, tz, 0)); + v->s = xstrdup(show_date(timestamp, tz, date_mode)); v->ul = timestamp; return; bad: @@ -391,7 +394,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") && - strcmp(name + wholen, "date")) + prefixcmp(name + wholen, "date")) continue; if (!wholine) wholine = find_wholine(who, wholen, buf, sz); @@ -403,8 +406,8 @@ 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 (!strcmp(name + wholen, "date")) - grab_date(wholine, v); + else if (!prefixcmp(name + wholen, "date")) + grab_date(wholine, v, name); } /* For a tag or a commit object, if "creator" or "creatordate" is @@ -424,8 +427,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru if (deref) name++; - if (!strcmp(name, "creatordate")) - grab_date(wholine, v); + if (!prefixcmp(name, "creatordate")) + grab_date(wholine, v, name); else if (!strcmp(name, "creator")) v->s = copy_line(wholine); } @@ -799,94 +802,77 @@ static struct ref_sort *default_sort(void) return sort; } -int cmd_for_each_ref(int ac, const char **av, const char *prefix) +int opt_parse_sort(const struct option *opt, const char *arg, int unset) +{ + struct ref_sort **sort_tail = opt->value; + struct ref_sort *s; + int len; + + if (!arg) /* should --no-sort void the list ? */ + return -1; + + *sort_tail = s = xcalloc(1, sizeof(*s)); + sort_tail = &s->next; + + if (*arg == '-') { + s->reverse = 1; + arg++; + } + len = strlen(arg); + s->atom = parse_atom(arg, arg+len); + return 0; +} + +static char const * const for_each_ref_usage[] = { + "git-for-each-ref [options] [<pattern>]", + NULL +}; + +int cmd_for_each_ref(int argc, const char **argv, const char *prefix) { int i, num_refs; - const char *format = NULL; + const char *format = "%(objectname) %(objecttype)\t%(refname)"; struct ref_sort *sort = NULL, **sort_tail = &sort; - int maxcount = 0; - int quote_style = -1; /* unspecified yet */ + int maxcount = 0, quote_style = 0; struct refinfo **refs; struct grab_ref_cbdata cbdata; - for (i = 1; i < ac; i++) { - const char *arg = av[i]; - if (arg[0] != '-') - break; - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!prefixcmp(arg, "--format=")) { - if (format) - die("more than one --format?"); - format = arg + 9; - continue; - } - if (!strcmp(arg, "-s") || !strcmp(arg, "--shell") ) { - if (0 <= quote_style) - die("more than one quoting style?"); - quote_style = QUOTE_SHELL; - continue; - } - if (!strcmp(arg, "-p") || !strcmp(arg, "--perl") ) { - if (0 <= quote_style) - die("more than one quoting style?"); - quote_style = QUOTE_PERL; - continue; - } - if (!strcmp(arg, "--python") ) { - if (0 <= quote_style) - die("more than one quoting style?"); - quote_style = QUOTE_PYTHON; - continue; - } - if (!strcmp(arg, "--tcl") ) { - if (0 <= quote_style) - die("more than one quoting style?"); - quote_style = QUOTE_TCL; - continue; - } - if (!prefixcmp(arg, "--count=")) { - if (maxcount) - die("more than one --count?"); - maxcount = atoi(arg + 8); - if (maxcount <= 0) - die("The number %s did not parse", arg); - continue; - } - if (!prefixcmp(arg, "--sort=")) { - struct ref_sort *s = xcalloc(1, sizeof(*s)); - int len; - - s->next = NULL; - *sort_tail = s; - sort_tail = &s->next; - - arg += 7; - if (*arg == '-') { - s->reverse = 1; - arg++; - } - len = strlen(arg); - sort->atom = parse_atom(arg, arg+len); - continue; - } - break; + struct option opts[] = { + OPT_BIT('s', "shell", "e_style, + "quote placeholders suitably for shells", QUOTE_SHELL), + OPT_BIT('p', "perl", "e_style, + "quote placeholders suitably for perl", QUOTE_PERL), + OPT_BIT(0 , "python", "e_style, + "quote placeholders suitably for python", QUOTE_PYTHON), + OPT_BIT(0 , "tcl", "e_style, + "quote placeholders suitably for tcl", QUOTE_TCL), + + OPT_GROUP(""), + OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"), + OPT_STRING( 0 , "format", &format, "format", "format to use for the output"), + OPT_CALLBACK(0 , "sort", sort_tail, "key", + "field name to sort on", &opt_parse_sort), + OPT_END(), + }; + + parse_options(argc, argv, opts, for_each_ref_usage, 0); + if (maxcount < 0) { + error("invalid --count argument: `%d'", maxcount); + usage_with_options(for_each_ref_usage, opts); } - if (quote_style < 0) - quote_style = QUOTE_NONE; + if (HAS_MULTI_BITS(quote_style)) { + error("more than one quoting style ?"); + usage_with_options(for_each_ref_usage, opts); + } + if (verify_format(format)) + usage_with_options(for_each_ref_usage, opts); if (!sort) sort = default_sort(); sort_atom_limit = used_atom_cnt; - if (!format) - format = "%(objectname) %(objecttype)\t%(refname)"; - - verify_format(format); memset(&cbdata, 0, sizeof(cbdata)); - cbdata.grab_pattern = av + i; + cbdata.grab_pattern = argv; for_each_ref(grab_single_ref, &cbdata); refs = cbdata.grab_array; num_refs = cbdata.grab_cnt; |