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 char author[1024], oneline[1024];
18 while (fgets(author, sizeof(author), stdin) != NULL) {
19 if (!(author[0] == 'A' || author[0] == 'a') ||
20 !starts_with(author + 1, "uthor: "))
22 while (fgets(oneline, sizeof(oneline), stdin) &&
24 ; /* discard headers */
25 while (fgets(oneline, sizeof(oneline), stdin) &&
27 ; /* discard blanks */
28 shortlog_insert_one_record(log, author + 8, oneline);
32 static void get_from_rev(struct rev_info *rev, struct shortlog *log)
34 struct commit *commit;
36 if (prepare_revision_walk(rev))
37 die(_("revision walk setup failed"));
38 while ((commit = get_revision(rev)) != NULL)
39 shortlog_add_commit(log, commit);
42 static int parse_uint(char const **arg, int comma, int defval)
48 ul = strtoul(*arg, &endp, 10);
49 if (*endp && *endp != comma)
53 ret = *arg == endp ? defval : (int)ul;
54 *arg = *endp ? endp + 1 : endp;
58 static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
60 static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
62 struct shortlog *log = opt->value;
64 log->wrap_lines = !unset;
68 log->wrap = DEFAULT_WRAPLEN;
69 log->in1 = DEFAULT_INDENT1;
70 log->in2 = DEFAULT_INDENT2;
74 log->wrap = parse_uint(&arg, ',', DEFAULT_WRAPLEN);
75 log->in1 = parse_uint(&arg, ',', DEFAULT_INDENT1);
76 log->in2 = parse_uint(&arg, '\0', DEFAULT_INDENT2);
77 if (log->wrap < 0 || log->in1 < 0 || log->in2 < 0)
78 return error(wrap_arg_usage);
80 ((log->in1 && log->wrap <= log->in1) ||
81 (log->in2 && log->wrap <= log->in2)))
82 return error(wrap_arg_usage);
86 int cmd_shortlog(int argc, const char **argv, const char *prefix)
88 static struct shortlog log;
89 static struct rev_info rev;
90 int nongit = !startup_info->have_repository;
92 static const struct option options[] = {
93 OPT_BOOL('n', "numbered", &log.sort_by_number,
94 N_("sort output according to the number of commits per author")),
95 OPT_BOOL('s', "summary", &log.summary,
96 N_("Suppress commit descriptions, only provides commit count")),
97 OPT_BOOL('e', "email", &log.email,
98 N_("Show the email address of each author")),
99 { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
100 N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
104 struct parse_opt_ctx_t ctx;
106 git_config(git_default_config, NULL);
108 init_revisions(&rev, prefix);
109 parse_options_start(&ctx, argc, argv, prefix, options,
110 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
113 switch (parse_options_step(&ctx, options, shortlog_usage)) {
119 parse_revision_opt(&rev, &ctx, options, shortlog_usage);
122 argc = parse_options_end(&ctx);
124 if (setup_revisions(argc, argv, &rev, NULL) != 1) {
125 error(_("unrecognized argument: %s"), argv[1]);
126 usage_with_options(shortlog_usage, options);
129 log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
130 log.abbrev = rev.abbrev;
132 /* assume HEAD if from a tty */
133 if (!nongit && !rev.pending.nr && isatty(0))
134 add_head_to_pending(&rev);
135 if (rev.pending.nr == 0) {
137 fprintf(stderr, _("(reading log message from standard input)\n"));
138 read_from_stdin(&log);
141 get_from_rev(&rev, &log);
143 shortlog_output(&log);