X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-shortlog.c;h=d03f14fdad3d17dde06734d78ddb4aade6ed4f2b;hb=49129d3731a6d74ad403ecdffc0e7940a597bc65;hp=e6a2865019cceadfcbfc8575a2bd1f97b7159dcb;hpb=a2fa254bd24c6f21c66869fc74b56b0aa1719851;p=git.git diff --git a/builtin-shortlog.c b/builtin-shortlog.c index e6a286501..d03f14fda 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -2,19 +2,24 @@ #include "cache.h" #include "commit.h" #include "diff.h" -#include "path-list.h" +#include "string-list.h" #include "revision.h" #include "utf8.h" #include "mailmap.h" #include "shortlog.h" +#include "parse-options.h" -static const char shortlog_usage[] = -"git-shortlog [-n] [-s] [-e] [-w] [... ]"; +static char const * const shortlog_usage[] = { + "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [... ]", + "", + "[rev-opts] are documented in git-rev-list(1)", + NULL +}; static int compare_by_number(const void *a1, const void *a2) { - const struct path_list_item *i1 = a1, *i2 = a2; - const struct path_list *l1 = i1->util, *l2 = i2->util; + const struct string_list_item *i1 = a1, *i2 = a2; + const struct string_list *l1 = i1->util, *l2 = i2->util; if (l1->nr < l2->nr) return 1; @@ -30,8 +35,8 @@ static void insert_one_record(struct shortlog *log, { const char *dot3 = log->common_repo_prefix; char *buffer, *p; - struct path_list_item *item; - struct path_list *onelines; + struct string_list_item *item; + struct string_list *onelines; char namebuf[1024]; size_t len; const char *eol; @@ -64,9 +69,9 @@ static void insert_one_record(struct shortlog *log, } buffer = xstrdup(namebuf); - item = path_list_insert(buffer, &log->list); + item = string_list_insert(buffer, &log->list); if (item->util == NULL) - item->util = xcalloc(1, sizeof(struct path_list)); + item->util = xcalloc(1, sizeof(struct string_list)); else free(buffer); @@ -104,11 +109,11 @@ static void insert_one_record(struct shortlog *log, onelines->alloc = alloc_nr(onelines->nr); onelines->items = xrealloc(onelines->items, onelines->alloc - * sizeof(struct path_list_item)); + * sizeof(struct string_list_item)); } onelines->items[onelines->nr].util = NULL; - onelines->items[onelines->nr++].path = buffer; + onelines->items[onelines->nr++].string = buffer; } static void read_from_stdin(struct shortlog *log) @@ -149,6 +154,15 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) if (!author) die("Missing author: %s", sha1_to_hex(commit->object.sha1)); + if (log->user_format) { + struct strbuf buf = STRBUF_INIT; + + pretty_print_commit(CMIT_FMT_USERFORMAT, commit, &buf, + DEFAULT_ABBREV, "", "", DATE_NORMAL, 0); + insert_one_record(log, author, buf.buf); + strbuf_release(&buf); + return; + } if (*buffer) buffer++; insert_one_record(log, author, !*buffer ? "" : buffer); @@ -164,21 +178,19 @@ static void get_from_rev(struct rev_info *rev, struct shortlog *log) shortlog_add_commit(log, commit); } -static int parse_uint(char const **arg, int comma) +static int parse_uint(char const **arg, int comma, int defval) { unsigned long ul; int ret; char *endp; ul = strtoul(*arg, &endp, 10); - if (endp != *arg && *endp && *endp != comma) + if (*endp && *endp != comma) return -1; - ret = (int) ul; - if (ret != ul) + if (ul > INT_MAX) return -1; - *arg = endp; - if (**arg) - (*arg)++; + ret = *arg == endp ? defval : (int)ul; + *arg = *endp ? endp + 1 : endp; return ret; } @@ -187,30 +199,30 @@ static const char wrap_arg_usage[] = "-w[[,[,]]]"; #define DEFAULT_INDENT1 6 #define DEFAULT_INDENT2 9 -static void parse_wrap_args(const char *arg, int *in1, int *in2, int *wrap) +static int parse_wrap_args(const struct option *opt, const char *arg, int unset) { - arg += 2; /* skip -w */ - - *wrap = parse_uint(&arg, ','); - if (*wrap < 0) - die(wrap_arg_usage); - *in1 = parse_uint(&arg, ','); - if (*in1 < 0) - die(wrap_arg_usage); - *in2 = parse_uint(&arg, '\0'); - if (*in2 < 0) - die(wrap_arg_usage); - - if (!*wrap) - *wrap = DEFAULT_WRAPLEN; - if (!*in1) - *in1 = DEFAULT_INDENT1; - if (!*in2) - *in2 = DEFAULT_INDENT2; - if (*wrap && - ((*in1 && *wrap <= *in1) || - (*in2 && *wrap <= *in2))) - die(wrap_arg_usage); + struct shortlog *log = opt->value; + + log->wrap_lines = !unset; + if (unset) + return 0; + if (!arg) { + log->wrap = DEFAULT_WRAPLEN; + log->in1 = DEFAULT_INDENT1; + log->in2 = DEFAULT_INDENT2; + return 0; + } + + log->wrap = parse_uint(&arg, ',', DEFAULT_WRAPLEN); + log->in1 = parse_uint(&arg, ',', DEFAULT_INDENT1); + log->in2 = parse_uint(&arg, '\0', DEFAULT_INDENT2); + if (log->wrap < 0 || log->in1 < 0 || log->in2 < 0) + return error(wrap_arg_usage); + if (log->wrap && + ((log->in1 && log->wrap <= log->in1) || + (log->in2 && log->wrap <= log->in2))) + return error(wrap_arg_usage); + return 0; } void shortlog_init(struct shortlog *log) @@ -219,7 +231,7 @@ void shortlog_init(struct shortlog *log) read_mailmap(&log->mailmap, ".mailmap", &log->common_repo_prefix); - log->list.strdup_paths = 1; + log->list.strdup_strings = 1; log->wrap = DEFAULT_WRAPLEN; log->in1 = DEFAULT_INDENT1; log->in2 = DEFAULT_INDENT2; @@ -227,38 +239,48 @@ void shortlog_init(struct shortlog *log) int cmd_shortlog(int argc, const char **argv, const char *prefix) { - struct shortlog log; - struct rev_info rev; + static struct shortlog log; + static struct rev_info rev; int nongit; + static const struct option options[] = { + OPT_BOOLEAN('n', "numbered", &log.sort_by_number, + "sort output according to the number of commits per author"), + OPT_BOOLEAN('s', "summary", &log.summary, + "Suppress commit descriptions, only provides commit count"), + OPT_BOOLEAN('e', "email", &log.email, + "Show the email address of each author"), + { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]", + "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args }, + OPT_END(), + }; + + struct parse_opt_ctx_t ctx; + prefix = setup_git_directory_gently(&nongit); shortlog_init(&log); - - /* since -n is a shadowed rev argument, parse our args first */ - while (argc > 1) { - if (!strcmp(argv[1], "-n") || !strcmp(argv[1], "--numbered")) - log.sort_by_number = 1; - else if (!strcmp(argv[1], "-s") || - !strcmp(argv[1], "--summary")) - log.summary = 1; - else if (!strcmp(argv[1], "-e") || - !strcmp(argv[1], "--email")) - log.email = 1; - else if (!prefixcmp(argv[1], "-w")) { - log.wrap_lines = 1; - parse_wrap_args(argv[1], &log.in1, &log.in2, &log.wrap); + init_revisions(&rev, prefix); + parse_options_start(&ctx, argc, argv, PARSE_OPT_KEEP_DASHDASH | + PARSE_OPT_KEEP_ARGV0); + + for (;;) { + switch (parse_options_step(&ctx, options, shortlog_usage)) { + case PARSE_OPT_HELP: + exit(129); + case PARSE_OPT_DONE: + goto parse_done; } - else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) - usage(shortlog_usage); - else - break; - argv++; - argc--; + parse_revision_opt(&rev, &ctx, options, shortlog_usage); } - init_revisions(&rev, prefix); - argc = setup_revisions(argc, argv, &rev, NULL); - if (argc > 1) - die ("unrecognized argument: %s", argv[1]); +parse_done: + argc = parse_options_end(&ctx); + + if (setup_revisions(argc, argv, &rev, NULL) != 1) { + error("unrecognized argument: %s", argv[1]); + usage_with_options(shortlog_usage, options); + } + + log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT; /* assume HEAD if from a tty */ if (!nongit && !rev.pending.nr && isatty(0)) @@ -277,17 +299,17 @@ void shortlog_output(struct shortlog *log) { int i, j; if (log->sort_by_number) - qsort(log->list.items, log->list.nr, sizeof(struct path_list_item), + qsort(log->list.items, log->list.nr, sizeof(struct string_list_item), compare_by_number); for (i = 0; i < log->list.nr; i++) { - struct path_list *onelines = log->list.items[i].util; + struct string_list *onelines = log->list.items[i].util; if (log->summary) { - printf("%6d\t%s\n", onelines->nr, log->list.items[i].path); + printf("%6d\t%s\n", onelines->nr, log->list.items[i].string); } else { - printf("%s (%d):\n", log->list.items[i].path, onelines->nr); + printf("%s (%d):\n", log->list.items[i].string, onelines->nr); for (j = onelines->nr - 1; j >= 0; j--) { - const char *msg = onelines->items[j].path; + const char *msg = onelines->items[j].string; if (log->wrap_lines) { int col = print_wrapped_text(msg, log->in1, log->in2, log->wrap); @@ -300,14 +322,14 @@ void shortlog_output(struct shortlog *log) putchar('\n'); } - onelines->strdup_paths = 1; - path_list_clear(onelines, 1); + onelines->strdup_strings = 1; + string_list_clear(onelines, 1); free(onelines); log->list.items[i].util = NULL; } - log->list.strdup_paths = 1; - path_list_clear(&log->list, 1); - log->mailmap.strdup_paths = 1; - path_list_clear(&log->mailmap, 1); + log->list.strdup_strings = 1; + string_list_clear(&log->list, 1); + log->mailmap.strdup_strings = 1; + string_list_clear(&log->mailmap, 1); }