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 prefixcmp(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 void shortlog_add_commit(struct shortlog *log, struct commit *commit)
34 const char *author = NULL, *buffer;
35 struct strbuf buf = STRBUF_INIT;
36 struct strbuf ufbuf = STRBUF_INIT;
38 pp_commit_easy(CMIT_FMT_RAW, commit, &buf);
40 while (*buffer && *buffer != '\n') {
41 const char *eol = strchr(buffer, '\n');
44 eol = buffer + strlen(buffer);
48 if (!prefixcmp(buffer, "author "))
53 warning(_("Missing author: %s"),
54 sha1_to_hex(commit->object.sha1));
57 if (log->user_format) {
58 struct pretty_print_context ctx = {0};
59 ctx.fmt = CMIT_FMT_USERFORMAT;
60 ctx.abbrev = log->abbrev;
62 ctx.after_subject = "";
63 ctx.date_mode = DATE_NORMAL;
64 ctx.output_encoding = get_log_output_encoding();
65 pretty_print_commit(&ctx, commit, &ufbuf);
70 insert_one_record(log, author, !*buffer ? "<none>" : buffer);
71 strbuf_release(&ufbuf);
75 static void get_from_rev(struct rev_info *rev, struct shortlog *log)
77 struct commit *commit;
79 if (prepare_revision_walk(rev))
80 die(_("revision walk setup failed"));
81 while ((commit = get_revision(rev)) != NULL)
82 shortlog_add_commit(log, commit);
85 static int parse_uint(char const **arg, int comma, int defval)
91 ul = strtoul(*arg, &endp, 10);
92 if (*endp && *endp != comma)
96 ret = *arg == endp ? defval : (int)ul;
97 *arg = *endp ? endp + 1 : endp;
101 static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
103 static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
105 struct shortlog *log = opt->value;
107 log->wrap_lines = !unset;
111 log->wrap = DEFAULT_WRAPLEN;
112 log->in1 = DEFAULT_INDENT1;
113 log->in2 = DEFAULT_INDENT2;
117 log->wrap = parse_uint(&arg, ',', DEFAULT_WRAPLEN);
118 log->in1 = parse_uint(&arg, ',', DEFAULT_INDENT1);
119 log->in2 = parse_uint(&arg, '\0', DEFAULT_INDENT2);
120 if (log->wrap < 0 || log->in1 < 0 || log->in2 < 0)
121 return error(wrap_arg_usage);
123 ((log->in1 && log->wrap <= log->in1) ||
124 (log->in2 && log->wrap <= log->in2)))
125 return error(wrap_arg_usage);
129 int cmd_shortlog(int argc, const char **argv, const char *prefix)
131 static struct shortlog log;
132 static struct rev_info rev;
133 int nongit = !startup_info->have_repository;
135 static const struct option options[] = {
136 OPT_BOOL('n', "numbered", &log.sort_by_number,
137 N_("sort output according to the number of commits per author")),
138 OPT_BOOL('s', "summary", &log.summary,
139 N_("Suppress commit descriptions, only provides commit count")),
140 OPT_BOOL('e', "email", &log.email,
141 N_("Show the email address of each author")),
142 { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
143 N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
147 struct parse_opt_ctx_t ctx;
149 git_config(git_default_config, NULL);
151 init_revisions(&rev, prefix);
152 parse_options_start(&ctx, argc, argv, prefix, options,
153 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
156 switch (parse_options_step(&ctx, options, shortlog_usage)) {
162 parse_revision_opt(&rev, &ctx, options, shortlog_usage);
165 argc = parse_options_end(&ctx);
167 if (setup_revisions(argc, argv, &rev, NULL) != 1) {
168 error(_("unrecognized argument: %s"), argv[1]);
169 usage_with_options(shortlog_usage, options);
172 log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
173 log.abbrev = rev.abbrev;
175 /* assume HEAD if from a tty */
176 if (!nongit && !rev.pending.nr && isatty(0))
177 add_head_to_pending(&rev);
178 if (rev.pending.nr == 0) {
180 fprintf(stderr, _("(reading log message from standard input)\n"));
181 read_from_stdin(&log);
184 get_from_rev(&rev, &log);
186 shortlog_output(&log);