8 * The util field of our string_list_items will contain one of two things:
10 * - if --summary is not in use, it will point to a string list of the
11 * oneline subjects assigned to this author
13 * - if --summary is in use, we don't need that list; we only need to know
14 * its size. So we abuse the pointer slot to store our integer counter.
16 * This macro accesses the latter.
18 #define UTIL_TO_INT(x) ((intptr_t)(x)->util)
20 void shortlog_init(struct shortlog *log)
22 memset(log, 0, sizeof(*log));
24 read_mailmap(&log->mailmap, &log->common_repo_prefix);
26 log->list.strdup_strings = 1;
27 log->wrap = DEFAULT_WRAPLEN;
28 log->in1 = DEFAULT_INDENT1;
29 log->in2 = DEFAULT_INDENT2;
32 void shortlog_insert_one_record(struct shortlog *log,
36 struct string_list_item *item;
37 const char *mailbuf, *namebuf;
38 size_t namelen, maillen;
39 struct strbuf namemailbuf = STRBUF_INIT;
40 struct ident_split ident;
42 if (split_ident_line(&ident, author, strlen(author)))
45 namebuf = ident.name_begin;
46 mailbuf = ident.mail_begin;
47 namelen = ident.name_end - ident.name_begin;
48 maillen = ident.mail_end - ident.mail_begin;
50 map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
51 strbuf_add(&namemailbuf, namebuf, namelen);
54 strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf);
56 item = string_list_insert(&log->list, namemailbuf.buf);
59 item->util = (void *)(UTIL_TO_INT(item) + 1);
61 const char *dot3 = log->common_repo_prefix;
63 struct strbuf subject = STRBUF_INIT;
66 /* Skip any leading whitespace, including any blank lines. */
67 while (*oneline && isspace(*oneline))
69 eol = strchr(oneline, '\n');
71 eol = oneline + strlen(oneline);
72 if (starts_with(oneline, "[PATCH")) {
73 char *eob = strchr(oneline, ']');
74 if (eob && (!eol || eob < eol))
77 while (*oneline && isspace(*oneline) && *oneline != '\n')
79 format_subject(&subject, oneline, " ");
80 buffer = strbuf_detach(&subject, NULL);
83 int dot3len = strlen(dot3);
85 while ((p = strstr(buffer, dot3)) != NULL) {
86 int taillen = strlen(p) - dot3len;
87 memcpy(p, "/.../", 5);
88 memmove(p + 5, p + dot3len, taillen + 1);
93 if (item->util == NULL)
94 item->util = xcalloc(1, sizeof(struct string_list));
95 string_list_append(item->util, buffer);
99 void shortlog_add_commit(struct shortlog *log, struct commit *commit)
101 const char *author = NULL, *buffer;
102 struct strbuf buf = STRBUF_INIT;
103 struct strbuf ufbuf = STRBUF_INIT;
105 pp_commit_easy(CMIT_FMT_RAW, commit, &buf);
107 while (*buffer && *buffer != '\n') {
108 const char *eol = strchr(buffer, '\n');
111 eol = buffer + strlen(buffer);
115 if (starts_with(buffer, "author "))
120 warning(_("Missing author: %s"),
121 oid_to_hex(&commit->object.oid));
124 if (log->user_format) {
125 struct pretty_print_context ctx = {0};
126 ctx.fmt = CMIT_FMT_USERFORMAT;
127 ctx.abbrev = log->abbrev;
129 ctx.after_subject = "";
130 ctx.date_mode.type = DATE_NORMAL;
131 ctx.output_encoding = get_log_output_encoding();
132 pretty_print_commit(&ctx, commit, &ufbuf);
134 } else if (*buffer) {
137 shortlog_insert_one_record(log, author, !*buffer ? "<none>" : buffer);
138 strbuf_release(&ufbuf);
139 strbuf_release(&buf);
142 static int compare_by_counter(const void *a1, const void *a2)
144 const struct string_list_item *i1 = a1, *i2 = a2;
145 return UTIL_TO_INT(i2) - UTIL_TO_INT(i1);
148 static int compare_by_list(const void *a1, const void *a2)
150 const struct string_list_item *i1 = a1, *i2 = a2;
151 const struct string_list *l1 = i1->util, *l2 = i2->util;
155 else if (l1->nr == l2->nr)
161 static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
162 const struct shortlog *log)
164 strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
165 strbuf_addch(sb, '\n');
168 void shortlog_output(struct shortlog *log)
171 struct strbuf sb = STRBUF_INIT;
173 if (log->sort_by_number)
174 qsort(log->list.items, log->list.nr, sizeof(struct string_list_item),
175 log->summary ? compare_by_counter : compare_by_list);
176 for (i = 0; i < log->list.nr; i++) {
177 const struct string_list_item *item = &log->list.items[i];
179 printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string);
181 struct string_list *onelines = item->util;
182 printf("%s (%d):\n", item->string, onelines->nr);
183 for (j = onelines->nr - 1; j >= 0; j--) {
184 const char *msg = onelines->items[j].string;
186 if (log->wrap_lines) {
188 add_wrapped_shortlog_msg(&sb, msg, log);
189 fwrite(sb.buf, sb.len, 1, stdout);
192 printf(" %s\n", msg);
195 onelines->strdup_strings = 1;
196 string_list_clear(onelines, 0);
200 log->list.items[i].util = NULL;
204 log->list.strdup_strings = 1;
205 string_list_clear(&log->list, 1);
206 clear_mailmap(&log->mailmap);