4 #include "string-list.h"
7 #include "parse-options.h"
9 static char const * const shortlog_usage[] = {
10 N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
14 static void read_from_stdin(struct shortlog *log)
16 struct strbuf author = STRBUF_INIT;
17 struct strbuf oneline = STRBUF_INIT;
19 while (strbuf_getline_lf(&author, stdin) != EOF) {
21 if (!skip_prefix(author.buf, "Author: ", &v) &&
22 !skip_prefix(author.buf, "author ", &v))
24 while (strbuf_getline_lf(&oneline, stdin) != EOF &&
26 ; /* discard headers */
27 while (strbuf_getline_lf(&oneline, stdin) != EOF &&
29 ; /* discard blanks */
30 shortlog_insert_one_record(log, v, oneline.buf);
32 strbuf_release(&author);
33 strbuf_release(&oneline);
36 static void get_from_rev(struct rev_info *rev, struct shortlog *log)
38 struct commit *commit;
40 if (prepare_revision_walk(rev))
41 die(_("revision walk setup failed"));
42 while ((commit = get_revision(rev)) != NULL)
43 shortlog_add_commit(log, commit);
46 static int parse_uint(char const **arg, int comma, int defval)
52 ul = strtoul(*arg, &endp, 10);
53 if (*endp && *endp != comma)
57 ret = *arg == endp ? defval : (int)ul;
58 *arg = *endp ? endp + 1 : endp;
62 static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
64 static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
66 struct shortlog *log = opt->value;
68 log->wrap_lines = !unset;
72 log->wrap = DEFAULT_WRAPLEN;
73 log->in1 = DEFAULT_INDENT1;
74 log->in2 = DEFAULT_INDENT2;
78 log->wrap = parse_uint(&arg, ',', DEFAULT_WRAPLEN);
79 log->in1 = parse_uint(&arg, ',', DEFAULT_INDENT1);
80 log->in2 = parse_uint(&arg, '\0', DEFAULT_INDENT2);
81 if (log->wrap < 0 || log->in1 < 0 || log->in2 < 0)
82 return error(wrap_arg_usage);
84 ((log->in1 && log->wrap <= log->in1) ||
85 (log->in2 && log->wrap <= log->in2)))
86 return error(wrap_arg_usage);
90 int cmd_shortlog(int argc, const char **argv, const char *prefix)
92 static struct shortlog log;
93 static struct rev_info rev;
94 int nongit = !startup_info->have_repository;
96 static const struct option options[] = {
97 OPT_BOOL('n', "numbered", &log.sort_by_number,
98 N_("sort output according to the number of commits per author")),
99 OPT_BOOL('s', "summary", &log.summary,
100 N_("Suppress commit descriptions, only provides commit count")),
101 OPT_BOOL('e', "email", &log.email,
102 N_("Show the email address of each author")),
103 { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
104 N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
108 struct parse_opt_ctx_t ctx;
110 git_config(git_default_config, NULL);
112 init_revisions(&rev, prefix);
113 parse_options_start(&ctx, argc, argv, prefix, options,
114 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
117 switch (parse_options_step(&ctx, options, shortlog_usage)) {
123 parse_revision_opt(&rev, &ctx, options, shortlog_usage);
126 argc = parse_options_end(&ctx);
128 if (setup_revisions(argc, argv, &rev, NULL) != 1) {
129 error(_("unrecognized argument: %s"), argv[1]);
130 usage_with_options(shortlog_usage, options);
133 log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
134 log.abbrev = rev.abbrev;
136 /* assume HEAD if from a tty */
137 if (!nongit && !rev.pending.nr && isatty(0))
138 add_head_to_pending(&rev);
139 if (rev.pending.nr == 0) {
141 fprintf(stderr, _("(reading log message from standard input)\n"));
142 read_from_stdin(&log);
145 get_from_rev(&rev, &log);
147 shortlog_output(&log);