Merge branch 'tb/multi-pack-verbatim-reuse' into HEAD
[alt-git.git] / pretty.c
blobcf964b060cd128e2bc271c07ed8bb8b4c28bfe29
1 #include "git-compat-util.h"
2 #include "config.h"
3 #include "commit.h"
4 #include "environment.h"
5 #include "gettext.h"
6 #include "hash.h"
7 #include "hex.h"
8 #include "utf8.h"
9 #include "diff.h"
10 #include "pager.h"
11 #include "revision.h"
12 #include "string-list.h"
13 #include "mailmap.h"
14 #include "log-tree.h"
15 #include "notes.h"
16 #include "color.h"
17 #include "reflog-walk.h"
18 #include "gpg-interface.h"
19 #include "trailer.h"
20 #include "run-command.h"
21 #include "object-name.h"
24 * The limit for formatting directives, which enable the caller to append
25 * arbitrarily many bytes to the formatted buffer. This includes padding
26 * and wrapping formatters.
28 #define FORMATTING_LIMIT (16 * 1024)
30 static char *user_format;
31 static struct cmt_fmt_map {
32 const char *name;
33 enum cmit_fmt format;
34 int is_tformat;
35 int expand_tabs_in_log;
36 int is_alias;
37 enum date_mode_type default_date_mode_type;
38 const char *user_format;
39 } *commit_formats;
40 static size_t builtin_formats_len;
41 static size_t commit_formats_len;
42 static size_t commit_formats_alloc;
43 static struct cmt_fmt_map *find_commit_format(const char *sought);
45 int commit_format_is_empty(enum cmit_fmt fmt)
47 return fmt == CMIT_FMT_USERFORMAT && !*user_format;
50 static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
52 free(user_format);
53 user_format = xstrdup(cp);
54 if (is_tformat)
55 rev->use_terminator = 1;
56 rev->commit_format = CMIT_FMT_USERFORMAT;
59 static int git_pretty_formats_config(const char *var, const char *value,
60 const struct config_context *ctx UNUSED,
61 void *cb UNUSED)
63 struct cmt_fmt_map *commit_format = NULL;
64 const char *name;
65 const char *fmt;
66 int i;
68 if (!skip_prefix(var, "pretty.", &name))
69 return 0;
71 for (i = 0; i < builtin_formats_len; i++) {
72 if (!strcmp(commit_formats[i].name, name))
73 return 0;
76 for (i = builtin_formats_len; i < commit_formats_len; i++) {
77 if (!strcmp(commit_formats[i].name, name)) {
78 commit_format = &commit_formats[i];
79 break;
83 if (!commit_format) {
84 ALLOC_GROW(commit_formats, commit_formats_len+1,
85 commit_formats_alloc);
86 commit_format = &commit_formats[commit_formats_len];
87 memset(commit_format, 0, sizeof(*commit_format));
88 commit_formats_len++;
91 commit_format->name = xstrdup(name);
92 commit_format->format = CMIT_FMT_USERFORMAT;
93 if (git_config_string(&fmt, var, value))
94 return -1;
96 if (skip_prefix(fmt, "format:", &fmt))
97 commit_format->is_tformat = 0;
98 else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
99 commit_format->is_tformat = 1;
100 else
101 commit_format->is_alias = 1;
102 commit_format->user_format = fmt;
104 return 0;
107 static void setup_commit_formats(void)
109 struct cmt_fmt_map builtin_formats[] = {
110 { "raw", CMIT_FMT_RAW, 0, 0 },
111 { "medium", CMIT_FMT_MEDIUM, 0, 8 },
112 { "short", CMIT_FMT_SHORT, 0, 0 },
113 { "email", CMIT_FMT_EMAIL, 0, 0 },
114 { "mboxrd", CMIT_FMT_MBOXRD, 0, 0 },
115 { "fuller", CMIT_FMT_FULLER, 0, 8 },
116 { "full", CMIT_FMT_FULL, 0, 8 },
117 { "oneline", CMIT_FMT_ONELINE, 1, 0 },
118 { "reference", CMIT_FMT_USERFORMAT, 1, 0,
119 0, DATE_SHORT, "%C(auto)%h (%s, %ad)" },
121 * Please update $__git_log_pretty_formats in
122 * git-completion.bash when you add new formats.
125 commit_formats_len = ARRAY_SIZE(builtin_formats);
126 builtin_formats_len = commit_formats_len;
127 ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
128 COPY_ARRAY(commit_formats, builtin_formats,
129 ARRAY_SIZE(builtin_formats));
131 git_config(git_pretty_formats_config, NULL);
134 static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
135 const char *original,
136 int num_redirections)
138 struct cmt_fmt_map *found = NULL;
139 size_t found_match_len = 0;
140 int i;
142 if (num_redirections >= commit_formats_len)
143 die("invalid --pretty format: "
144 "'%s' references an alias which points to itself",
145 original);
147 for (i = 0; i < commit_formats_len; i++) {
148 size_t match_len;
150 if (!starts_with(commit_formats[i].name, sought))
151 continue;
153 match_len = strlen(commit_formats[i].name);
154 if (found == NULL || found_match_len > match_len) {
155 found = &commit_formats[i];
156 found_match_len = match_len;
160 if (found && found->is_alias) {
161 found = find_commit_format_recursive(found->user_format,
162 original,
163 num_redirections+1);
166 return found;
169 static struct cmt_fmt_map *find_commit_format(const char *sought)
171 if (!commit_formats)
172 setup_commit_formats();
174 return find_commit_format_recursive(sought, sought, 0);
177 void get_commit_format(const char *arg, struct rev_info *rev)
179 struct cmt_fmt_map *commit_format;
181 rev->use_terminator = 0;
182 if (!arg) {
183 rev->commit_format = CMIT_FMT_DEFAULT;
184 return;
186 if (skip_prefix(arg, "format:", &arg)) {
187 save_user_format(rev, arg, 0);
188 return;
191 if (!*arg || skip_prefix(arg, "tformat:", &arg) || strchr(arg, '%')) {
192 save_user_format(rev, arg, 1);
193 return;
196 commit_format = find_commit_format(arg);
197 if (!commit_format)
198 die("invalid --pretty format: %s", arg);
200 rev->commit_format = commit_format->format;
201 rev->use_terminator = commit_format->is_tformat;
202 rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log;
203 if (!rev->date_mode_explicit && commit_format->default_date_mode_type)
204 rev->date_mode.type = commit_format->default_date_mode_type;
205 if (commit_format->format == CMIT_FMT_USERFORMAT) {
206 save_user_format(rev, commit_format->user_format,
207 commit_format->is_tformat);
212 * Generic support for pretty-printing the header
214 static int get_one_line(const char *msg)
216 int ret = 0;
218 for (;;) {
219 char c = *msg++;
220 if (!c)
221 break;
222 ret++;
223 if (c == '\n')
224 break;
226 return ret;
229 /* High bit set, or ISO-2022-INT */
230 static int non_ascii(int ch)
232 return !isascii(ch) || ch == '\033';
235 int has_non_ascii(const char *s)
237 int ch;
238 if (!s)
239 return 0;
240 while ((ch = *s++) != '\0') {
241 if (non_ascii(ch))
242 return 1;
244 return 0;
247 static int is_rfc822_special(char ch)
249 switch (ch) {
250 case '(':
251 case ')':
252 case '<':
253 case '>':
254 case '[':
255 case ']':
256 case ':':
257 case ';':
258 case '@':
259 case ',':
260 case '.':
261 case '"':
262 case '\\':
263 return 1;
264 default:
265 return 0;
269 static int needs_rfc822_quoting(const char *s, int len)
271 int i;
272 for (i = 0; i < len; i++)
273 if (is_rfc822_special(s[i]))
274 return 1;
275 return 0;
278 static int last_line_length(struct strbuf *sb)
280 int i;
282 /* How many bytes are already used on the last line? */
283 for (i = sb->len - 1; i >= 0; i--)
284 if (sb->buf[i] == '\n')
285 break;
286 return sb->len - (i + 1);
289 static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
291 int i;
293 /* just a guess, we may have to also backslash-quote */
294 strbuf_grow(out, len + 2);
296 strbuf_addch(out, '"');
297 for (i = 0; i < len; i++) {
298 switch (s[i]) {
299 case '"':
300 case '\\':
301 strbuf_addch(out, '\\');
302 /* fall through */
303 default:
304 strbuf_addch(out, s[i]);
307 strbuf_addch(out, '"');
310 enum rfc2047_type {
311 RFC2047_SUBJECT,
312 RFC2047_ADDRESS
315 static int is_rfc2047_special(char ch, enum rfc2047_type type)
318 * rfc2047, section 4.2:
320 * 8-bit values which correspond to printable ASCII characters other
321 * than "=", "?", and "_" (underscore), MAY be represented as those
322 * characters. (But see section 5 for restrictions.) In
323 * particular, SPACE and TAB MUST NOT be represented as themselves
324 * within encoded words.
328 * rule out non-ASCII characters and non-printable characters (the
329 * non-ASCII check should be redundant as isprint() is not localized
330 * and only knows about ASCII, but be defensive about that)
332 if (non_ascii(ch) || !isprint(ch))
333 return 1;
336 * rule out special printable characters (' ' should be the only
337 * whitespace character considered printable, but be defensive and use
338 * isspace())
340 if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
341 return 1;
344 * rfc2047, section 5.3:
346 * As a replacement for a 'word' entity within a 'phrase', for example,
347 * one that precedes an address in a From, To, or Cc header. The ABNF
348 * definition for 'phrase' from RFC 822 thus becomes:
350 * phrase = 1*( encoded-word / word )
352 * In this case the set of characters that may be used in a "Q"-encoded
353 * 'encoded-word' is restricted to: <upper and lower case ASCII
354 * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
355 * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
356 * 'phrase' MUST be separated from any adjacent 'word', 'text' or
357 * 'special' by 'linear-white-space'.
360 if (type != RFC2047_ADDRESS)
361 return 0;
363 /* '=' and '_' are special cases and have been checked above */
364 return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
367 static int needs_rfc2047_encoding(const char *line, int len)
369 int i;
371 for (i = 0; i < len; i++) {
372 int ch = line[i];
373 if (non_ascii(ch) || ch == '\n')
374 return 1;
375 if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
376 return 1;
379 return 0;
382 static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
383 const char *encoding, enum rfc2047_type type)
385 static const int max_encoded_length = 76; /* per rfc2047 */
386 int i;
387 int line_len = last_line_length(sb);
389 strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
390 strbuf_addf(sb, "=?%s?q?", encoding);
391 line_len += strlen(encoding) + 5; /* 5 for =??q? */
393 while (len) {
395 * RFC 2047, section 5 (3):
397 * Each 'encoded-word' MUST represent an integral number of
398 * characters. A multi-octet character may not be split across
399 * adjacent 'encoded- word's.
401 const unsigned char *p = (const unsigned char *)line;
402 int chrlen = mbs_chrlen(&line, &len, encoding);
403 int is_special = (chrlen > 1) || is_rfc2047_special(*p, type);
405 /* "=%02X" * chrlen, or the byte itself */
406 const char *encoded_fmt = is_special ? "=%02X" : "%c";
407 int encoded_len = is_special ? 3 * chrlen : 1;
410 * According to RFC 2047, we could encode the special character
411 * ' ' (space) with '_' (underscore) for readability. But many
412 * programs do not understand this and just leave the
413 * underscore in place. Thus, we do nothing special here, which
414 * causes ' ' to be encoded as '=20', avoiding this problem.
417 if (line_len + encoded_len + 2 > max_encoded_length) {
418 /* It won't fit with trailing "?=" --- break the line */
419 strbuf_addf(sb, "?=\n =?%s?q?", encoding);
420 line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
423 for (i = 0; i < chrlen; i++)
424 strbuf_addf(sb, encoded_fmt, p[i]);
425 line_len += encoded_len;
427 strbuf_addstr(sb, "?=");
430 const char *show_ident_date(const struct ident_split *ident,
431 const struct date_mode *mode)
433 timestamp_t date = 0;
434 long tz = 0;
436 if (ident->date_begin && ident->date_end)
437 date = parse_timestamp(ident->date_begin, NULL, 10);
438 if (date_overflows(date))
439 date = 0;
440 else {
441 if (ident->tz_begin && ident->tz_end)
442 tz = strtol(ident->tz_begin, NULL, 10);
443 if (tz >= INT_MAX || tz <= INT_MIN)
444 tz = 0;
446 return show_date(date, tz, mode);
449 static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,
450 const char *buf, size_t buflen)
452 strbuf_addstr(sb, color);
453 strbuf_add(sb, buf, buflen);
454 if (*color)
455 strbuf_addstr(sb, GIT_COLOR_RESET);
458 static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,
459 const char *line, size_t linelen,
460 int color, enum grep_context ctx,
461 enum grep_header_field field)
463 const char *buf, *eol, *line_color, *match_color;
464 regmatch_t match;
465 int eflags = 0;
467 buf = line;
468 eol = buf + linelen;
470 if (!opt || !want_color(color) || opt->invert)
471 goto end;
473 line_color = opt->colors[GREP_COLOR_SELECTED];
474 match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
476 while (grep_next_match(opt, buf, eol, ctx, &match, field, eflags)) {
477 if (match.rm_so == match.rm_eo)
478 break;
480 strbuf_add_with_color(sb, line_color, buf, match.rm_so);
481 strbuf_add_with_color(sb, match_color, buf + match.rm_so,
482 match.rm_eo - match.rm_so);
483 buf += match.rm_eo;
484 eflags = REG_NOTBOL;
487 if (eflags)
488 strbuf_add_with_color(sb, line_color, buf, eol - buf);
489 else {
490 end:
491 strbuf_add(sb, buf, eol - buf);
495 static int use_in_body_from(const struct pretty_print_context *pp,
496 const struct ident_split *ident)
498 if (pp->rev && pp->rev->force_in_body_from)
499 return 1;
500 if (ident_cmp(pp->from_ident, ident))
501 return 1;
502 return 0;
505 void pp_user_info(struct pretty_print_context *pp,
506 const char *what, struct strbuf *sb,
507 const char *line, const char *encoding)
509 struct ident_split ident;
510 char *line_end;
511 const char *mailbuf, *namebuf;
512 size_t namelen, maillen;
513 int max_length = 78; /* per rfc2822 */
515 if (pp->fmt == CMIT_FMT_ONELINE)
516 return;
518 line_end = strchrnul(line, '\n');
519 if (split_ident_line(&ident, line, line_end - line))
520 return;
522 mailbuf = ident.mail_begin;
523 maillen = ident.mail_end - ident.mail_begin;
524 namebuf = ident.name_begin;
525 namelen = ident.name_end - ident.name_begin;
527 if (pp->mailmap)
528 map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
530 if (cmit_fmt_is_mail(pp->fmt)) {
531 if (pp->from_ident && use_in_body_from(pp, &ident)) {
532 struct strbuf buf = STRBUF_INIT;
534 strbuf_addstr(&buf, "From: ");
535 strbuf_add(&buf, namebuf, namelen);
536 strbuf_addstr(&buf, " <");
537 strbuf_add(&buf, mailbuf, maillen);
538 strbuf_addstr(&buf, ">\n");
539 string_list_append(&pp->in_body_headers,
540 strbuf_detach(&buf, NULL));
542 mailbuf = pp->from_ident->mail_begin;
543 maillen = pp->from_ident->mail_end - mailbuf;
544 namebuf = pp->from_ident->name_begin;
545 namelen = pp->from_ident->name_end - namebuf;
548 strbuf_addstr(sb, "From: ");
549 if (pp->encode_email_headers &&
550 needs_rfc2047_encoding(namebuf, namelen)) {
551 add_rfc2047(sb, namebuf, namelen,
552 encoding, RFC2047_ADDRESS);
553 max_length = 76; /* per rfc2047 */
554 } else if (needs_rfc822_quoting(namebuf, namelen)) {
555 struct strbuf quoted = STRBUF_INIT;
556 add_rfc822_quoted(&quoted, namebuf, namelen);
557 strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
558 -6, 1, max_length);
559 strbuf_release(&quoted);
560 } else {
561 strbuf_add_wrapped_bytes(sb, namebuf, namelen,
562 -6, 1, max_length);
565 if (max_length <
566 last_line_length(sb) + strlen(" <") + maillen + strlen(">"))
567 strbuf_addch(sb, '\n');
568 strbuf_addf(sb, " <%.*s>\n", (int)maillen, mailbuf);
569 } else {
570 struct strbuf id = STRBUF_INIT;
571 enum grep_header_field field = GREP_HEADER_FIELD_MAX;
572 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
574 if (!strcmp(what, "Author"))
575 field = GREP_HEADER_AUTHOR;
576 else if (!strcmp(what, "Commit"))
577 field = GREP_HEADER_COMMITTER;
579 strbuf_addf(sb, "%s: ", what);
580 if (pp->fmt == CMIT_FMT_FULLER)
581 strbuf_addchars(sb, ' ', 4);
583 strbuf_addf(&id, "%.*s <%.*s>", (int)namelen, namebuf,
584 (int)maillen, mailbuf);
586 append_line_with_color(sb, opt, id.buf, id.len, pp->color,
587 GREP_CONTEXT_HEAD, field);
588 strbuf_addch(sb, '\n');
589 strbuf_release(&id);
592 switch (pp->fmt) {
593 case CMIT_FMT_MEDIUM:
594 strbuf_addf(sb, "Date: %s\n",
595 show_ident_date(&ident, &pp->date_mode));
596 break;
597 case CMIT_FMT_EMAIL:
598 case CMIT_FMT_MBOXRD:
599 strbuf_addf(sb, "Date: %s\n",
600 show_ident_date(&ident, DATE_MODE(RFC2822)));
601 break;
602 case CMIT_FMT_FULLER:
603 strbuf_addf(sb, "%sDate: %s\n", what,
604 show_ident_date(&ident, &pp->date_mode));
605 break;
606 default:
607 /* notin' */
608 break;
612 static int is_blank_line(const char *line, int *len_p)
614 int len = *len_p;
615 while (len && isspace(line[len - 1]))
616 len--;
617 *len_p = len;
618 return !len;
621 const char *skip_blank_lines(const char *msg)
623 for (;;) {
624 int linelen = get_one_line(msg);
625 int ll = linelen;
626 if (!linelen)
627 break;
628 if (!is_blank_line(msg, &ll))
629 break;
630 msg += linelen;
632 return msg;
635 static void add_merge_info(const struct pretty_print_context *pp,
636 struct strbuf *sb, const struct commit *commit)
638 struct commit_list *parent = commit->parents;
640 if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) ||
641 !parent || !parent->next)
642 return;
644 strbuf_addstr(sb, "Merge:");
646 while (parent) {
647 struct object_id *oidp = &parent->item->object.oid;
648 strbuf_addch(sb, ' ');
649 if (pp->abbrev)
650 strbuf_add_unique_abbrev(sb, oidp, pp->abbrev);
651 else
652 strbuf_addstr(sb, oid_to_hex(oidp));
653 parent = parent->next;
655 strbuf_addch(sb, '\n');
658 static char *get_header(const char *msg, const char *key)
660 size_t len;
661 const char *v = find_commit_header(msg, key, &len);
662 return v ? xmemdupz(v, len) : NULL;
665 static char *replace_encoding_header(char *buf, const char *encoding)
667 struct strbuf tmp = STRBUF_INIT;
668 size_t start, len;
669 char *cp = buf;
671 /* guess if there is an encoding header before a \n\n */
672 while (!starts_with(cp, "encoding ")) {
673 cp = strchr(cp, '\n');
674 if (!cp || *++cp == '\n')
675 return buf;
677 start = cp - buf;
678 cp = strchr(cp, '\n');
679 if (!cp)
680 return buf; /* should not happen but be defensive */
681 len = cp + 1 - (buf + start);
683 strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
684 if (is_encoding_utf8(encoding)) {
685 /* we have re-coded to UTF-8; drop the header */
686 strbuf_remove(&tmp, start, len);
687 } else {
688 /* just replaces XXXX in 'encoding XXXX\n' */
689 strbuf_splice(&tmp, start + strlen("encoding "),
690 len - strlen("encoding \n"),
691 encoding, strlen(encoding));
693 return strbuf_detach(&tmp, NULL);
696 const char *repo_logmsg_reencode(struct repository *r,
697 const struct commit *commit,
698 char **commit_encoding,
699 const char *output_encoding)
701 static const char *utf8 = "UTF-8";
702 const char *use_encoding;
703 char *encoding;
704 const char *msg = repo_get_commit_buffer(r, commit, NULL);
705 char *out;
707 if (!output_encoding || !*output_encoding) {
708 if (commit_encoding)
709 *commit_encoding = get_header(msg, "encoding");
710 return msg;
712 encoding = get_header(msg, "encoding");
713 if (commit_encoding)
714 *commit_encoding = encoding;
715 use_encoding = encoding ? encoding : utf8;
716 if (same_encoding(use_encoding, output_encoding)) {
718 * No encoding work to be done. If we have no encoding header
719 * at all, then there's nothing to do, and we can return the
720 * message verbatim (whether newly allocated or not).
722 if (!encoding)
723 return msg;
726 * Otherwise, we still want to munge the encoding header in the
727 * result, which will be done by modifying the buffer. If we
728 * are using a fresh copy, we can reuse it. But if we are using
729 * the cached copy from repo_get_commit_buffer, we need to duplicate it
730 * to avoid munging the cached copy.
732 if (msg == get_cached_commit_buffer(r, commit, NULL))
733 out = xstrdup(msg);
734 else
735 out = (char *)msg;
737 else {
739 * There's actual encoding work to do. Do the reencoding, which
740 * still leaves the header to be replaced in the next step. At
741 * this point, we are done with msg. If we allocated a fresh
742 * copy, we can free it.
744 out = reencode_string(msg, output_encoding, use_encoding);
745 if (out)
746 repo_unuse_commit_buffer(r, commit, msg);
750 * This replacement actually consumes the buffer we hand it, so we do
751 * not have to worry about freeing the old "out" here.
753 if (out)
754 out = replace_encoding_header(out, output_encoding);
756 if (!commit_encoding)
757 free(encoding);
759 * If the re-encoding failed, out might be NULL here; in that
760 * case we just return the commit message verbatim.
762 return out ? out : msg;
765 static int mailmap_name(const char **email, size_t *email_len,
766 const char **name, size_t *name_len)
768 static struct string_list *mail_map;
769 if (!mail_map) {
770 CALLOC_ARRAY(mail_map, 1);
771 read_mailmap(mail_map);
773 return mail_map->nr && map_user(mail_map, email, email_len, name, name_len);
776 static size_t format_person_part(struct strbuf *sb, char part,
777 const char *msg, int len,
778 const struct date_mode *dmode)
780 /* currently all placeholders have same length */
781 const int placeholder_len = 2;
782 struct ident_split s;
783 const char *name, *mail;
784 size_t maillen, namelen;
786 if (split_ident_line(&s, msg, len) < 0)
787 goto skip;
789 name = s.name_begin;
790 namelen = s.name_end - s.name_begin;
791 mail = s.mail_begin;
792 maillen = s.mail_end - s.mail_begin;
794 if (part == 'N' || part == 'E' || part == 'L') /* mailmap lookup */
795 mailmap_name(&mail, &maillen, &name, &namelen);
796 if (part == 'n' || part == 'N') { /* name */
797 strbuf_add(sb, name, namelen);
798 return placeholder_len;
800 if (part == 'e' || part == 'E') { /* email */
801 strbuf_add(sb, mail, maillen);
802 return placeholder_len;
804 if (part == 'l' || part == 'L') { /* local-part */
805 const char *at = memchr(mail, '@', maillen);
806 if (at)
807 maillen = at - mail;
808 strbuf_add(sb, mail, maillen);
809 return placeholder_len;
812 if (!s.date_begin)
813 goto skip;
815 if (part == 't') { /* date, UNIX timestamp */
816 strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
817 return placeholder_len;
820 switch (part) {
821 case 'd': /* date */
822 strbuf_addstr(sb, show_ident_date(&s, dmode));
823 return placeholder_len;
824 case 'D': /* date, RFC2822 style */
825 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RFC2822)));
826 return placeholder_len;
827 case 'r': /* date, relative */
828 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RELATIVE)));
829 return placeholder_len;
830 case 'i': /* date, ISO 8601-like */
831 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601)));
832 return placeholder_len;
833 case 'I': /* date, ISO 8601 strict */
834 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT)));
835 return placeholder_len;
836 case 'h': /* date, human */
837 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(HUMAN)));
838 return placeholder_len;
839 case 's':
840 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(SHORT)));
841 return placeholder_len;
844 skip:
846 * reading from either a bogus commit, or a reflog entry with
847 * %gn, %ge, etc.; 'sb' cannot be updated, but we still need
848 * to compute a valid return value.
850 if (part == 'n' || part == 'e' || part == 't' || part == 'd'
851 || part == 'D' || part == 'r' || part == 'i')
852 return placeholder_len;
854 return 0; /* unknown placeholder */
857 struct chunk {
858 size_t off;
859 size_t len;
862 enum flush_type {
863 no_flush,
864 flush_right,
865 flush_left,
866 flush_left_and_steal,
867 flush_both
870 enum trunc_type {
871 trunc_none,
872 trunc_left,
873 trunc_middle,
874 trunc_right
877 struct format_commit_context {
878 struct repository *repository;
879 const struct commit *commit;
880 const struct pretty_print_context *pretty_ctx;
881 unsigned commit_header_parsed:1;
882 unsigned commit_message_parsed:1;
883 struct signature_check signature_check;
884 enum flush_type flush_type;
885 enum trunc_type truncate;
886 const char *message;
887 char *commit_encoding;
888 size_t width, indent1, indent2;
889 int auto_color;
890 int padding;
892 /* These offsets are relative to the start of the commit message. */
893 struct chunk author;
894 struct chunk committer;
895 size_t message_off;
896 size_t subject_off;
897 size_t body_off;
899 /* The following ones are relative to the result struct strbuf. */
900 size_t wrap_start;
903 static void parse_commit_header(struct format_commit_context *context)
905 const char *msg = context->message;
906 int i;
908 for (i = 0; msg[i]; i++) {
909 const char *name;
910 int eol;
911 for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
912 ; /* do nothing */
914 if (i == eol) {
915 break;
916 } else if (skip_prefix(msg + i, "author ", &name)) {
917 context->author.off = name - msg;
918 context->author.len = msg + eol - name;
919 } else if (skip_prefix(msg + i, "committer ", &name)) {
920 context->committer.off = name - msg;
921 context->committer.len = msg + eol - name;
923 i = eol;
925 context->message_off = i;
926 context->commit_header_parsed = 1;
929 static int istitlechar(char c)
931 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
932 (c >= '0' && c <= '9') || c == '.' || c == '_';
935 void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len)
937 size_t trimlen;
938 size_t start_len = sb->len;
939 int space = 2;
940 int i;
942 for (i = 0; i < len; i++) {
943 if (istitlechar(msg[i])) {
944 if (space == 1)
945 strbuf_addch(sb, '-');
946 space = 0;
947 strbuf_addch(sb, msg[i]);
948 if (msg[i] == '.')
949 while (msg[i+1] == '.')
950 i++;
951 } else
952 space |= 1;
955 /* trim any trailing '.' or '-' characters */
956 trimlen = 0;
957 while (sb->len - trimlen > start_len &&
958 (sb->buf[sb->len - 1 - trimlen] == '.'
959 || sb->buf[sb->len - 1 - trimlen] == '-'))
960 trimlen++;
961 strbuf_remove(sb, sb->len - trimlen, trimlen);
964 const char *format_subject(struct strbuf *sb, const char *msg,
965 const char *line_separator)
967 int first = 1;
969 for (;;) {
970 const char *line = msg;
971 int linelen = get_one_line(line);
973 msg += linelen;
974 if (!linelen || is_blank_line(line, &linelen))
975 break;
977 if (!sb)
978 continue;
979 strbuf_grow(sb, linelen + 2);
980 if (!first)
981 strbuf_addstr(sb, line_separator);
982 strbuf_add(sb, line, linelen);
983 first = 0;
985 return msg;
988 static void parse_commit_message(struct format_commit_context *c)
990 const char *msg = c->message + c->message_off;
991 const char *start = c->message;
993 msg = skip_blank_lines(msg);
994 c->subject_off = msg - start;
996 msg = format_subject(NULL, msg, NULL);
997 msg = skip_blank_lines(msg);
998 c->body_off = msg - start;
1000 c->commit_message_parsed = 1;
1003 static void strbuf_wrap(struct strbuf *sb, size_t pos,
1004 size_t width, size_t indent1, size_t indent2)
1006 struct strbuf tmp = STRBUF_INIT;
1008 if (pos)
1009 strbuf_add(&tmp, sb->buf, pos);
1010 strbuf_add_wrapped_text(&tmp, sb->buf + pos,
1011 cast_size_t_to_int(indent1),
1012 cast_size_t_to_int(indent2),
1013 cast_size_t_to_int(width));
1014 strbuf_swap(&tmp, sb);
1015 strbuf_release(&tmp);
1018 static void rewrap_message_tail(struct strbuf *sb,
1019 struct format_commit_context *c,
1020 size_t new_width, size_t new_indent1,
1021 size_t new_indent2)
1023 if (c->width == new_width && c->indent1 == new_indent1 &&
1024 c->indent2 == new_indent2)
1025 return;
1026 if (c->wrap_start < sb->len)
1027 strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
1028 c->wrap_start = sb->len;
1029 c->width = new_width;
1030 c->indent1 = new_indent1;
1031 c->indent2 = new_indent2;
1034 static int format_reflog_person(struct strbuf *sb,
1035 char part,
1036 struct reflog_walk_info *log,
1037 const struct date_mode *dmode)
1039 const char *ident;
1041 if (!log)
1042 return 2;
1044 ident = get_reflog_ident(log);
1045 if (!ident)
1046 return 2;
1048 return format_person_part(sb, part, ident, strlen(ident), dmode);
1051 static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
1052 const char *placeholder,
1053 struct format_commit_context *c)
1055 const char *rest = placeholder;
1056 const char *basic_color = NULL;
1058 if (placeholder[1] == '(') {
1059 const char *begin = placeholder + 2;
1060 const char *end = strchr(begin, ')');
1061 char color[COLOR_MAXLEN];
1063 if (!end)
1064 return 0;
1066 if (skip_prefix(begin, "auto,", &begin)) {
1067 if (!want_color(c->pretty_ctx->color))
1068 return end - placeholder + 1;
1069 } else if (skip_prefix(begin, "always,", &begin)) {
1070 /* nothing to do; we do not respect want_color at all */
1071 } else {
1072 /* the default is the same as "auto" */
1073 if (!want_color(c->pretty_ctx->color))
1074 return end - placeholder + 1;
1077 if (color_parse_mem(begin, end - begin, color) < 0)
1078 die(_("unable to parse --pretty format"));
1079 strbuf_addstr(sb, color);
1080 return end - placeholder + 1;
1084 * We handle things like "%C(red)" above; for historical reasons, there
1085 * are a few colors that can be specified without parentheses (and
1086 * they cannot support things like "auto" or "always" at all).
1088 if (skip_prefix(placeholder + 1, "red", &rest))
1089 basic_color = GIT_COLOR_RED;
1090 else if (skip_prefix(placeholder + 1, "green", &rest))
1091 basic_color = GIT_COLOR_GREEN;
1092 else if (skip_prefix(placeholder + 1, "blue", &rest))
1093 basic_color = GIT_COLOR_BLUE;
1094 else if (skip_prefix(placeholder + 1, "reset", &rest))
1095 basic_color = GIT_COLOR_RESET;
1097 if (basic_color && want_color(c->pretty_ctx->color))
1098 strbuf_addstr(sb, basic_color);
1100 return rest - placeholder;
1103 static size_t parse_padding_placeholder(const char *placeholder,
1104 struct format_commit_context *c)
1106 const char *ch = placeholder;
1107 enum flush_type flush_type;
1108 int to_column = 0;
1110 switch (*ch++) {
1111 case '<':
1112 flush_type = flush_right;
1113 break;
1114 case '>':
1115 if (*ch == '<') {
1116 flush_type = flush_both;
1117 ch++;
1118 } else if (*ch == '>') {
1119 flush_type = flush_left_and_steal;
1120 ch++;
1121 } else
1122 flush_type = flush_left;
1123 break;
1124 default:
1125 return 0;
1128 /* the next value means "wide enough to that column" */
1129 if (*ch == '|') {
1130 to_column = 1;
1131 ch++;
1134 if (*ch == '(') {
1135 const char *start = ch + 1;
1136 const char *end = start + strcspn(start, ",)");
1137 char *next;
1138 int width;
1139 if (!*end || end == start)
1140 return 0;
1141 width = strtol(start, &next, 10);
1144 * We need to limit the amount of padding, or otherwise this
1145 * would allow the user to pad the buffer by arbitrarily many
1146 * bytes and thus cause resource exhaustion.
1148 if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
1149 return 0;
1151 if (next == start || width == 0)
1152 return 0;
1153 if (width < 0) {
1154 if (to_column)
1155 width += term_columns();
1156 if (width < 0)
1157 return 0;
1159 c->padding = to_column ? -width : width;
1160 c->flush_type = flush_type;
1162 if (*end == ',') {
1163 start = end + 1;
1164 end = strchr(start, ')');
1165 if (!end || end == start)
1166 return 0;
1167 if (starts_with(start, "trunc)"))
1168 c->truncate = trunc_right;
1169 else if (starts_with(start, "ltrunc)"))
1170 c->truncate = trunc_left;
1171 else if (starts_with(start, "mtrunc)"))
1172 c->truncate = trunc_middle;
1173 else
1174 return 0;
1175 } else
1176 c->truncate = trunc_none;
1178 return end - placeholder + 1;
1180 return 0;
1183 static int match_placeholder_arg_value(const char *to_parse, const char *candidate,
1184 const char **end, const char **valuestart,
1185 size_t *valuelen)
1187 const char *p;
1189 if (!(skip_prefix(to_parse, candidate, &p)))
1190 return 0;
1191 if (valuestart) {
1192 if (*p == '=') {
1193 *valuestart = p + 1;
1194 *valuelen = strcspn(*valuestart, ",)");
1195 p = *valuestart + *valuelen;
1196 } else {
1197 if (*p != ',' && *p != ')')
1198 return 0;
1199 *valuestart = NULL;
1200 *valuelen = 0;
1203 if (*p == ',') {
1204 *end = p + 1;
1205 return 1;
1207 if (*p == ')') {
1208 *end = p;
1209 return 1;
1211 return 0;
1214 static int match_placeholder_bool_arg(const char *to_parse, const char *candidate,
1215 const char **end, int *val)
1217 const char *argval;
1218 char *strval;
1219 size_t arglen;
1220 int v;
1222 if (!match_placeholder_arg_value(to_parse, candidate, end, &argval, &arglen))
1223 return 0;
1225 if (!argval) {
1226 *val = 1;
1227 return 1;
1230 strval = xstrndup(argval, arglen);
1231 v = git_parse_maybe_bool(strval);
1232 free(strval);
1234 if (v == -1)
1235 return 0;
1237 *val = v;
1239 return 1;
1242 static int format_trailer_match_cb(const struct strbuf *key, void *ud)
1244 const struct string_list *list = ud;
1245 const struct string_list_item *item;
1247 for_each_string_list_item (item, list) {
1248 if (key->len == (uintptr_t)item->util &&
1249 !strncasecmp(item->string, key->buf, key->len))
1250 return 1;
1252 return 0;
1255 static struct strbuf *expand_string_arg(struct strbuf *sb,
1256 const char *argval, size_t arglen)
1258 char *fmt = xstrndup(argval, arglen);
1259 const char *format = fmt;
1261 strbuf_reset(sb);
1262 while (strbuf_expand_step(sb, &format)) {
1263 size_t len;
1265 if (skip_prefix(format, "%", &format))
1266 strbuf_addch(sb, '%');
1267 else if ((len = strbuf_expand_literal(sb, format)))
1268 format += len;
1269 else
1270 strbuf_addch(sb, '%');
1272 free(fmt);
1273 return sb;
1276 int format_set_trailers_options(struct process_trailer_options *opts,
1277 struct string_list *filter_list,
1278 struct strbuf *sepbuf,
1279 struct strbuf *kvsepbuf,
1280 const char **arg,
1281 char **invalid_arg)
1283 for (;;) {
1284 const char *argval;
1285 size_t arglen;
1287 if (**arg == ')')
1288 break;
1290 if (match_placeholder_arg_value(*arg, "key", arg, &argval, &arglen)) {
1291 uintptr_t len = arglen;
1293 if (!argval)
1294 return -1;
1296 if (len && argval[len - 1] == ':')
1297 len--;
1298 string_list_append(filter_list, argval)->util = (char *)len;
1300 opts->filter = format_trailer_match_cb;
1301 opts->filter_data = filter_list;
1302 opts->only_trailers = 1;
1303 } else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
1304 opts->separator = expand_string_arg(sepbuf, argval, arglen);
1305 } else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
1306 opts->key_value_separator = expand_string_arg(kvsepbuf, argval, arglen);
1307 } else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
1308 !match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
1309 !match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
1310 !match_placeholder_bool_arg(*arg, "valueonly", arg, &opts->value_only)) {
1311 if (invalid_arg) {
1312 size_t len = strcspn(*arg, ",)");
1313 *invalid_arg = xstrndup(*arg, len);
1315 return -1;
1318 return 0;
1321 static size_t parse_describe_args(const char *start, struct strvec *args)
1323 struct {
1324 char *name;
1325 enum {
1326 DESCRIBE_ARG_BOOL,
1327 DESCRIBE_ARG_INTEGER,
1328 DESCRIBE_ARG_STRING,
1329 } type;
1330 } option[] = {
1331 { "tags", DESCRIBE_ARG_BOOL},
1332 { "abbrev", DESCRIBE_ARG_INTEGER },
1333 { "exclude", DESCRIBE_ARG_STRING },
1334 { "match", DESCRIBE_ARG_STRING },
1336 const char *arg = start;
1338 for (;;) {
1339 int found = 0;
1340 const char *argval;
1341 size_t arglen = 0;
1342 int optval = 0;
1343 int i;
1345 for (i = 0; !found && i < ARRAY_SIZE(option); i++) {
1346 switch (option[i].type) {
1347 case DESCRIBE_ARG_BOOL:
1348 if (match_placeholder_bool_arg(arg, option[i].name, &arg, &optval)) {
1349 if (optval)
1350 strvec_pushf(args, "--%s", option[i].name);
1351 else
1352 strvec_pushf(args, "--no-%s", option[i].name);
1353 found = 1;
1355 break;
1356 case DESCRIBE_ARG_INTEGER:
1357 if (match_placeholder_arg_value(arg, option[i].name, &arg,
1358 &argval, &arglen)) {
1359 char *endptr;
1360 if (!arglen)
1361 return 0;
1362 strtol(argval, &endptr, 10);
1363 if (endptr - argval != arglen)
1364 return 0;
1365 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval);
1366 found = 1;
1368 break;
1369 case DESCRIBE_ARG_STRING:
1370 if (match_placeholder_arg_value(arg, option[i].name, &arg,
1371 &argval, &arglen)) {
1372 if (!arglen)
1373 return 0;
1374 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval);
1375 found = 1;
1377 break;
1380 if (!found)
1381 break;
1384 return arg - start;
1388 static int parse_decoration_option(const char **arg,
1389 const char *name,
1390 char **opt)
1392 const char *argval;
1393 size_t arglen;
1395 if (match_placeholder_arg_value(*arg, name, arg, &argval, &arglen)) {
1396 struct strbuf sb = STRBUF_INIT;
1398 expand_string_arg(&sb, argval, arglen);
1399 *opt = strbuf_detach(&sb, NULL);
1400 return 1;
1402 return 0;
1405 static void parse_decoration_options(const char **arg,
1406 struct decoration_options *opts)
1408 while (parse_decoration_option(arg, "prefix", &opts->prefix) ||
1409 parse_decoration_option(arg, "suffix", &opts->suffix) ||
1410 parse_decoration_option(arg, "separator", &opts->separator) ||
1411 parse_decoration_option(arg, "pointer", &opts->pointer) ||
1412 parse_decoration_option(arg, "tag", &opts->tag))
1416 static void free_decoration_options(const struct decoration_options *opts)
1418 free(opts->prefix);
1419 free(opts->suffix);
1420 free(opts->separator);
1421 free(opts->pointer);
1422 free(opts->tag);
1425 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
1426 const char *placeholder,
1427 void *context)
1429 struct format_commit_context *c = context;
1430 const struct commit *commit = c->commit;
1431 const char *msg = c->message;
1432 struct commit_list *p;
1433 const char *arg, *eol;
1434 size_t res;
1435 char **slot;
1437 /* these are independent of the commit */
1438 res = strbuf_expand_literal(sb, placeholder);
1439 if (res)
1440 return res;
1442 switch (placeholder[0]) {
1443 case 'C':
1444 if (starts_with(placeholder + 1, "(auto)")) {
1445 c->auto_color = want_color(c->pretty_ctx->color);
1446 if (c->auto_color && sb->len)
1447 strbuf_addstr(sb, GIT_COLOR_RESET);
1448 return 7; /* consumed 7 bytes, "C(auto)" */
1449 } else {
1450 int ret = parse_color(sb, placeholder, c);
1451 if (ret)
1452 c->auto_color = 0;
1454 * Otherwise, we decided to treat %C<unknown>
1455 * as a literal string, and the previous
1456 * %C(auto) is still valid.
1458 return ret;
1460 case 'w':
1461 if (placeholder[1] == '(') {
1462 unsigned long width = 0, indent1 = 0, indent2 = 0;
1463 char *next;
1464 const char *start = placeholder + 2;
1465 const char *end = strchr(start, ')');
1466 if (!end)
1467 return 0;
1468 if (end > start) {
1469 width = strtoul(start, &next, 10);
1470 if (*next == ',') {
1471 indent1 = strtoul(next + 1, &next, 10);
1472 if (*next == ',') {
1473 indent2 = strtoul(next + 1,
1474 &next, 10);
1477 if (*next != ')')
1478 return 0;
1482 * We need to limit the format here as it allows the
1483 * user to prepend arbitrarily many bytes to the buffer
1484 * when rewrapping.
1486 if (width > FORMATTING_LIMIT ||
1487 indent1 > FORMATTING_LIMIT ||
1488 indent2 > FORMATTING_LIMIT)
1489 return 0;
1490 rewrap_message_tail(sb, c, width, indent1, indent2);
1491 return end - placeholder + 1;
1492 } else
1493 return 0;
1495 case '<':
1496 case '>':
1497 return parse_padding_placeholder(placeholder, c);
1500 if (skip_prefix(placeholder, "(describe", &arg)) {
1501 struct child_process cmd = CHILD_PROCESS_INIT;
1502 struct strbuf out = STRBUF_INIT;
1503 struct strbuf err = STRBUF_INIT;
1504 struct pretty_print_describe_status *describe_status;
1506 describe_status = c->pretty_ctx->describe_status;
1507 if (describe_status) {
1508 if (!describe_status->max_invocations)
1509 return 0;
1510 describe_status->max_invocations--;
1513 cmd.git_cmd = 1;
1514 strvec_push(&cmd.args, "describe");
1516 if (*arg == ':') {
1517 arg++;
1518 arg += parse_describe_args(arg, &cmd.args);
1521 if (*arg != ')') {
1522 child_process_clear(&cmd);
1523 return 0;
1526 strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
1527 pipe_command(&cmd, NULL, 0, &out, 0, &err, 0);
1528 strbuf_rtrim(&out);
1529 strbuf_addbuf(sb, &out);
1530 strbuf_release(&out);
1531 strbuf_release(&err);
1532 return arg - placeholder + 1;
1535 /* these depend on the commit */
1536 if (!commit->object.parsed)
1537 parse_object(the_repository, &commit->object.oid);
1539 switch (placeholder[0]) {
1540 case 'H': /* commit hash */
1541 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
1542 strbuf_addstr(sb, oid_to_hex(&commit->object.oid));
1543 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
1544 return 1;
1545 case 'h': /* abbreviated commit hash */
1546 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
1547 strbuf_add_unique_abbrev(sb, &commit->object.oid,
1548 c->pretty_ctx->abbrev);
1549 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
1550 return 1;
1551 case 'T': /* tree hash */
1552 strbuf_addstr(sb, oid_to_hex(get_commit_tree_oid(commit)));
1553 return 1;
1554 case 't': /* abbreviated tree hash */
1555 strbuf_add_unique_abbrev(sb,
1556 get_commit_tree_oid(commit),
1557 c->pretty_ctx->abbrev);
1558 return 1;
1559 case 'P': /* parent hashes */
1560 for (p = commit->parents; p; p = p->next) {
1561 if (p != commit->parents)
1562 strbuf_addch(sb, ' ');
1563 strbuf_addstr(sb, oid_to_hex(&p->item->object.oid));
1565 return 1;
1566 case 'p': /* abbreviated parent hashes */
1567 for (p = commit->parents; p; p = p->next) {
1568 if (p != commit->parents)
1569 strbuf_addch(sb, ' ');
1570 strbuf_add_unique_abbrev(sb, &p->item->object.oid,
1571 c->pretty_ctx->abbrev);
1573 return 1;
1574 case 'm': /* left/right/bottom */
1575 strbuf_addstr(sb, get_revision_mark(NULL, commit));
1576 return 1;
1577 case 'd':
1578 format_decorations(sb, commit, c->auto_color, NULL);
1579 return 1;
1580 case 'D':
1582 const struct decoration_options opts = {
1583 .prefix = "",
1584 .suffix = ""
1587 format_decorations(sb, commit, c->auto_color, &opts);
1588 return 1;
1590 case 'S': /* tag/branch like --source */
1591 if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
1592 return 0;
1593 slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
1594 if (!(slot && *slot))
1595 return 0;
1596 strbuf_addstr(sb, *slot);
1597 return 1;
1598 case 'g': /* reflog info */
1599 switch(placeholder[1]) {
1600 case 'd': /* reflog selector */
1601 case 'D':
1602 if (c->pretty_ctx->reflog_info)
1603 get_reflog_selector(sb,
1604 c->pretty_ctx->reflog_info,
1605 &c->pretty_ctx->date_mode,
1606 c->pretty_ctx->date_mode_explicit,
1607 (placeholder[1] == 'd'));
1608 return 2;
1609 case 's': /* reflog message */
1610 if (c->pretty_ctx->reflog_info)
1611 get_reflog_message(sb, c->pretty_ctx->reflog_info);
1612 return 2;
1613 case 'n':
1614 case 'N':
1615 case 'e':
1616 case 'E':
1617 return format_reflog_person(sb,
1618 placeholder[1],
1619 c->pretty_ctx->reflog_info,
1620 &c->pretty_ctx->date_mode);
1622 return 0; /* unknown %g placeholder */
1623 case 'N':
1624 if (c->pretty_ctx->notes_message) {
1625 strbuf_addstr(sb, c->pretty_ctx->notes_message);
1626 return 1;
1628 return 0;
1631 if (placeholder[0] == 'G') {
1632 if (!c->signature_check.result)
1633 check_commit_signature(c->commit, &(c->signature_check));
1634 switch (placeholder[1]) {
1635 case 'G':
1636 if (c->signature_check.output)
1637 strbuf_addstr(sb, c->signature_check.output);
1638 break;
1639 case '?':
1640 switch (c->signature_check.result) {
1641 case 'G':
1642 switch (c->signature_check.trust_level) {
1643 case TRUST_UNDEFINED:
1644 case TRUST_NEVER:
1645 strbuf_addch(sb, 'U');
1646 break;
1647 default:
1648 strbuf_addch(sb, 'G');
1649 break;
1651 break;
1652 case 'B':
1653 case 'E':
1654 case 'N':
1655 case 'X':
1656 case 'Y':
1657 case 'R':
1658 strbuf_addch(sb, c->signature_check.result);
1660 break;
1661 case 'S':
1662 if (c->signature_check.signer)
1663 strbuf_addstr(sb, c->signature_check.signer);
1664 break;
1665 case 'K':
1666 if (c->signature_check.key)
1667 strbuf_addstr(sb, c->signature_check.key);
1668 break;
1669 case 'F':
1670 if (c->signature_check.fingerprint)
1671 strbuf_addstr(sb, c->signature_check.fingerprint);
1672 break;
1673 case 'P':
1674 if (c->signature_check.primary_key_fingerprint)
1675 strbuf_addstr(sb, c->signature_check.primary_key_fingerprint);
1676 break;
1677 case 'T':
1678 strbuf_addstr(sb, gpg_trust_level_to_str(c->signature_check.trust_level));
1679 break;
1680 default:
1681 return 0;
1683 return 2;
1686 if (skip_prefix(placeholder, "(decorate", &arg)) {
1687 struct decoration_options opts = { NULL };
1688 size_t ret = 0;
1690 if (*arg == ':') {
1691 arg++;
1692 parse_decoration_options(&arg, &opts);
1694 if (*arg == ')') {
1695 format_decorations(sb, commit, c->auto_color, &opts);
1696 ret = arg - placeholder + 1;
1699 free_decoration_options(&opts);
1700 return ret;
1703 /* For the rest we have to parse the commit header. */
1704 if (!c->commit_header_parsed) {
1705 msg = c->message =
1706 repo_logmsg_reencode(c->repository, commit,
1707 &c->commit_encoding, "UTF-8");
1708 parse_commit_header(c);
1711 switch (placeholder[0]) {
1712 case 'a': /* author ... */
1713 return format_person_part(sb, placeholder[1],
1714 msg + c->author.off, c->author.len,
1715 &c->pretty_ctx->date_mode);
1716 case 'c': /* committer ... */
1717 return format_person_part(sb, placeholder[1],
1718 msg + c->committer.off, c->committer.len,
1719 &c->pretty_ctx->date_mode);
1720 case 'e': /* encoding */
1721 if (c->commit_encoding)
1722 strbuf_addstr(sb, c->commit_encoding);
1723 return 1;
1724 case 'B': /* raw body */
1725 /* message_off is always left at the initial newline */
1726 strbuf_addstr(sb, msg + c->message_off + 1);
1727 return 1;
1730 /* Now we need to parse the commit message. */
1731 if (!c->commit_message_parsed)
1732 parse_commit_message(c);
1734 switch (placeholder[0]) {
1735 case 's': /* subject */
1736 format_subject(sb, msg + c->subject_off, " ");
1737 return 1;
1738 case 'f': /* sanitized subject */
1739 eol = strchrnul(msg + c->subject_off, '\n');
1740 format_sanitized_subject(sb, msg + c->subject_off, eol - (msg + c->subject_off));
1741 return 1;
1742 case 'b': /* body */
1743 strbuf_addstr(sb, msg + c->body_off);
1744 return 1;
1747 if (skip_prefix(placeholder, "(trailers", &arg)) {
1748 struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1749 struct string_list filter_list = STRING_LIST_INIT_NODUP;
1750 struct strbuf sepbuf = STRBUF_INIT;
1751 struct strbuf kvsepbuf = STRBUF_INIT;
1752 size_t ret = 0;
1754 opts.no_divider = 1;
1756 if (*arg == ':') {
1757 arg++;
1758 if (format_set_trailers_options(&opts, &filter_list, &sepbuf, &kvsepbuf, &arg, NULL))
1759 goto trailer_out;
1761 if (*arg == ')') {
1762 format_trailers_from_commit(sb, msg + c->subject_off, &opts);
1763 ret = arg - placeholder + 1;
1765 trailer_out:
1766 string_list_clear(&filter_list, 0);
1767 strbuf_release(&sepbuf);
1768 return ret;
1771 return 0; /* unknown placeholder */
1774 static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
1775 const char *placeholder,
1776 struct format_commit_context *c)
1778 struct strbuf local_sb = STRBUF_INIT;
1779 size_t total_consumed = 0;
1780 int len, padding = c->padding;
1782 if (padding < 0) {
1783 const char *start = strrchr(sb->buf, '\n');
1784 int occupied;
1785 if (!start)
1786 start = sb->buf;
1787 occupied = utf8_strnwidth(start, strlen(start), 1);
1788 occupied += c->pretty_ctx->graph_width;
1789 padding = (-padding) - occupied;
1791 while (1) {
1792 int modifier = *placeholder == 'C';
1793 size_t consumed = format_commit_one(&local_sb, placeholder, c);
1794 total_consumed += consumed;
1796 if (!modifier)
1797 break;
1799 placeholder += consumed;
1800 if (*placeholder != '%')
1801 break;
1802 placeholder++;
1803 total_consumed++;
1805 len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
1807 if (c->flush_type == flush_left_and_steal) {
1808 const char *ch = sb->buf + sb->len - 1;
1809 while (len > padding && ch > sb->buf) {
1810 const char *p;
1811 if (*ch == ' ') {
1812 ch--;
1813 padding++;
1814 continue;
1816 /* check for trailing ansi sequences */
1817 if (*ch != 'm')
1818 break;
1819 p = ch - 1;
1820 while (p > sb->buf && ch - p < 10 && *p != '\033')
1821 p--;
1822 if (*p != '\033' ||
1823 ch + 1 - p != display_mode_esc_sequence_len(p))
1824 break;
1826 * got a good ansi sequence, put it back to
1827 * local_sb as we're cutting sb
1829 strbuf_insert(&local_sb, 0, p, ch + 1 - p);
1830 ch = p - 1;
1832 strbuf_setlen(sb, ch + 1 - sb->buf);
1833 c->flush_type = flush_left;
1836 if (len > padding) {
1837 switch (c->truncate) {
1838 case trunc_left:
1839 strbuf_utf8_replace(&local_sb,
1840 0, len - (padding - 2),
1841 "..");
1842 break;
1843 case trunc_middle:
1844 strbuf_utf8_replace(&local_sb,
1845 padding / 2 - 1,
1846 len - (padding - 2),
1847 "..");
1848 break;
1849 case trunc_right:
1850 strbuf_utf8_replace(&local_sb,
1851 padding - 2, len - (padding - 2),
1852 "..");
1853 break;
1854 case trunc_none:
1855 break;
1857 strbuf_addbuf(sb, &local_sb);
1858 } else {
1859 size_t sb_len = sb->len, offset = 0;
1860 if (c->flush_type == flush_left)
1861 offset = padding - len;
1862 else if (c->flush_type == flush_both)
1863 offset = (padding - len) / 2;
1865 * we calculate padding in columns, now
1866 * convert it back to chars
1868 padding = padding - len + local_sb.len;
1869 strbuf_addchars(sb, ' ', padding);
1870 memcpy(sb->buf + sb_len + offset, local_sb.buf,
1871 local_sb.len);
1873 strbuf_release(&local_sb);
1874 c->flush_type = no_flush;
1875 return total_consumed;
1878 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
1879 const char *placeholder,
1880 struct format_commit_context *context)
1882 size_t consumed, orig_len;
1883 enum {
1884 NO_MAGIC,
1885 ADD_LF_BEFORE_NON_EMPTY,
1886 DEL_LF_BEFORE_EMPTY,
1887 ADD_SP_BEFORE_NON_EMPTY
1888 } magic = NO_MAGIC;
1890 switch (placeholder[0]) {
1891 case '-':
1892 magic = DEL_LF_BEFORE_EMPTY;
1893 break;
1894 case '+':
1895 magic = ADD_LF_BEFORE_NON_EMPTY;
1896 break;
1897 case ' ':
1898 magic = ADD_SP_BEFORE_NON_EMPTY;
1899 break;
1900 default:
1901 break;
1903 if (magic != NO_MAGIC) {
1904 placeholder++;
1906 switch (placeholder[0]) {
1907 case 'w':
1909 * `%+w()` cannot ever expand to a non-empty string,
1910 * and it potentially changes the layout of preceding
1911 * contents. We're thus not able to handle the magic in
1912 * this combination and refuse the pattern.
1914 return 0;
1918 orig_len = sb->len;
1919 if (context->flush_type == no_flush)
1920 consumed = format_commit_one(sb, placeholder, context);
1921 else
1922 consumed = format_and_pad_commit(sb, placeholder, context);
1923 if (magic == NO_MAGIC)
1924 return consumed;
1926 if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
1927 while (sb->len && sb->buf[sb->len - 1] == '\n')
1928 strbuf_setlen(sb, sb->len - 1);
1929 } else if (orig_len != sb->len) {
1930 if (magic == ADD_LF_BEFORE_NON_EMPTY)
1931 strbuf_insertstr(sb, orig_len, "\n");
1932 else if (magic == ADD_SP_BEFORE_NON_EMPTY)
1933 strbuf_insertstr(sb, orig_len, " ");
1935 return consumed + 1;
1938 void userformat_find_requirements(const char *fmt, struct userformat_want *w)
1940 if (!fmt) {
1941 if (!user_format)
1942 return;
1943 fmt = user_format;
1945 while ((fmt = strchr(fmt, '%'))) {
1946 fmt++;
1947 if (skip_prefix(fmt, "%", &fmt))
1948 continue;
1950 if (*fmt == '+' || *fmt == '-' || *fmt == ' ')
1951 fmt++;
1953 switch (*fmt) {
1954 case 'N':
1955 w->notes = 1;
1956 break;
1957 case 'S':
1958 w->source = 1;
1959 break;
1960 case 'd':
1961 case 'D':
1962 w->decorate = 1;
1963 break;
1964 case '(':
1965 if (starts_with(fmt + 1, "decorate"))
1966 w->decorate = 1;
1967 break;
1972 void repo_format_commit_message(struct repository *r,
1973 const struct commit *commit,
1974 const char *format, struct strbuf *sb,
1975 const struct pretty_print_context *pretty_ctx)
1977 struct format_commit_context context = {
1978 .repository = r,
1979 .commit = commit,
1980 .pretty_ctx = pretty_ctx,
1981 .wrap_start = sb->len
1983 const char *output_enc = pretty_ctx->output_encoding;
1984 const char *utf8 = "UTF-8";
1986 while (strbuf_expand_step(sb, &format)) {
1987 size_t len;
1989 if (skip_prefix(format, "%", &format))
1990 strbuf_addch(sb, '%');
1991 else if ((len = format_commit_item(sb, format, &context)))
1992 format += len;
1993 else
1994 strbuf_addch(sb, '%');
1996 rewrap_message_tail(sb, &context, 0, 0, 0);
1999 * Convert output to an actual output encoding; note that
2000 * format_commit_item() will always use UTF-8, so we don't
2001 * have to bother if that's what the output wants.
2003 if (output_enc) {
2004 if (same_encoding(utf8, output_enc))
2005 output_enc = NULL;
2006 } else {
2007 if (context.commit_encoding &&
2008 !same_encoding(context.commit_encoding, utf8))
2009 output_enc = context.commit_encoding;
2012 if (output_enc) {
2013 size_t outsz;
2014 char *out = reencode_string_len(sb->buf, sb->len,
2015 output_enc, utf8, &outsz);
2016 if (out)
2017 strbuf_attach(sb, out, outsz, outsz + 1);
2020 free(context.commit_encoding);
2021 repo_unuse_commit_buffer(r, commit, context.message);
2024 static void pp_header(struct pretty_print_context *pp,
2025 const char *encoding,
2026 const struct commit *commit,
2027 const char **msg_p,
2028 struct strbuf *sb)
2030 int parents_shown = 0;
2032 for (;;) {
2033 const char *name, *line = *msg_p;
2034 int linelen = get_one_line(*msg_p);
2036 if (!linelen)
2037 return;
2038 *msg_p += linelen;
2040 if (linelen == 1)
2041 /* End of header */
2042 return;
2044 if (pp->fmt == CMIT_FMT_RAW) {
2045 strbuf_add(sb, line, linelen);
2046 continue;
2049 if (starts_with(line, "parent ")) {
2050 if (linelen != the_hash_algo->hexsz + 8)
2051 die("bad parent line in commit");
2052 continue;
2055 if (!parents_shown) {
2056 unsigned num = commit_list_count(commit->parents);
2057 /* with enough slop */
2058 strbuf_grow(sb, num * (GIT_MAX_HEXSZ + 10) + 20);
2059 add_merge_info(pp, sb, commit);
2060 parents_shown = 1;
2064 * MEDIUM == DEFAULT shows only author with dates.
2065 * FULL shows both authors but not dates.
2066 * FULLER shows both authors and dates.
2068 if (skip_prefix(line, "author ", &name)) {
2069 strbuf_grow(sb, linelen + 80);
2070 pp_user_info(pp, "Author", sb, name, encoding);
2072 if (skip_prefix(line, "committer ", &name) &&
2073 (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
2074 strbuf_grow(sb, linelen + 80);
2075 pp_user_info(pp, "Commit", sb, name, encoding);
2080 void pp_title_line(struct pretty_print_context *pp,
2081 const char **msg_p,
2082 struct strbuf *sb,
2083 const char *encoding,
2084 int need_8bit_cte)
2086 static const int max_length = 78; /* per rfc2047 */
2087 struct strbuf title;
2089 strbuf_init(&title, 80);
2090 *msg_p = format_subject(&title, *msg_p,
2091 pp->preserve_subject ? "\n" : " ");
2093 strbuf_grow(sb, title.len + 1024);
2094 if (pp->print_email_subject) {
2095 if (pp->rev)
2096 fmt_output_email_subject(sb, pp->rev);
2097 if (pp->encode_email_headers &&
2098 needs_rfc2047_encoding(title.buf, title.len))
2099 add_rfc2047(sb, title.buf, title.len,
2100 encoding, RFC2047_SUBJECT);
2101 else
2102 strbuf_add_wrapped_bytes(sb, title.buf, title.len,
2103 -last_line_length(sb), 1, max_length);
2104 } else {
2105 strbuf_addbuf(sb, &title);
2107 strbuf_addch(sb, '\n');
2109 if (need_8bit_cte == 0) {
2110 int i;
2111 for (i = 0; i < pp->in_body_headers.nr; i++) {
2112 if (has_non_ascii(pp->in_body_headers.items[i].string)) {
2113 need_8bit_cte = 1;
2114 break;
2119 if (need_8bit_cte > 0) {
2120 const char *header_fmt =
2121 "MIME-Version: 1.0\n"
2122 "Content-Type: text/plain; charset=%s\n"
2123 "Content-Transfer-Encoding: 8bit\n";
2124 strbuf_addf(sb, header_fmt, encoding);
2126 if (pp->after_subject) {
2127 strbuf_addstr(sb, pp->after_subject);
2129 if (cmit_fmt_is_mail(pp->fmt)) {
2130 strbuf_addch(sb, '\n');
2133 if (pp->in_body_headers.nr) {
2134 int i;
2135 for (i = 0; i < pp->in_body_headers.nr; i++) {
2136 strbuf_addstr(sb, pp->in_body_headers.items[i].string);
2137 free(pp->in_body_headers.items[i].string);
2139 string_list_clear(&pp->in_body_headers, 0);
2140 strbuf_addch(sb, '\n');
2143 strbuf_release(&title);
2146 static int pp_utf8_width(const char *start, const char *end)
2148 int width = 0;
2149 size_t remain = end - start;
2151 while (remain) {
2152 int n = utf8_width(&start, &remain);
2153 if (n < 0 || !start)
2154 return -1;
2155 width += n;
2157 return width;
2160 static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,
2161 int color, int tabwidth, const char *line,
2162 int linelen)
2164 const char *tab;
2166 while ((tab = memchr(line, '\t', linelen)) != NULL) {
2167 int width = pp_utf8_width(line, tab);
2170 * If it wasn't well-formed utf8, or it
2171 * had characters with badly defined
2172 * width (control characters etc), just
2173 * give up on trying to align things.
2175 if (width < 0)
2176 break;
2178 /* Output the data .. */
2179 append_line_with_color(sb, opt, line, tab - line, color,
2180 GREP_CONTEXT_BODY,
2181 GREP_HEADER_FIELD_MAX);
2183 /* .. and the de-tabified tab */
2184 strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth));
2186 /* Skip over the printed part .. */
2187 linelen -= tab + 1 - line;
2188 line = tab + 1;
2192 * Print out everything after the last tab without
2193 * worrying about width - there's nothing more to
2194 * align.
2196 append_line_with_color(sb, opt, line, linelen, color, GREP_CONTEXT_BODY,
2197 GREP_HEADER_FIELD_MAX);
2201 * pp_handle_indent() prints out the intendation, and
2202 * the whole line (without the final newline), after
2203 * de-tabifying.
2205 static void pp_handle_indent(struct pretty_print_context *pp,
2206 struct strbuf *sb, int indent,
2207 const char *line, int linelen)
2209 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
2211 strbuf_addchars(sb, ' ', indent);
2212 if (pp->expand_tabs_in_log)
2213 strbuf_add_tabexpand(sb, opt, pp->color, pp->expand_tabs_in_log,
2214 line, linelen);
2215 else
2216 append_line_with_color(sb, opt, line, linelen, pp->color,
2217 GREP_CONTEXT_BODY,
2218 GREP_HEADER_FIELD_MAX);
2221 static int is_mboxrd_from(const char *line, int len)
2224 * a line matching /^From $/ here would only have len == 4
2225 * at this point because is_empty_line would've trimmed all
2226 * trailing space
2228 return len > 4 && starts_with(line + strspn(line, ">"), "From ");
2231 void pp_remainder(struct pretty_print_context *pp,
2232 const char **msg_p,
2233 struct strbuf *sb,
2234 int indent)
2236 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
2237 int first = 1;
2239 for (;;) {
2240 const char *line = *msg_p;
2241 int linelen = get_one_line(line);
2242 *msg_p += linelen;
2244 if (!linelen)
2245 break;
2247 if (is_blank_line(line, &linelen)) {
2248 if (first)
2249 continue;
2250 if (pp->fmt == CMIT_FMT_SHORT)
2251 break;
2253 first = 0;
2255 strbuf_grow(sb, linelen + indent + 20);
2256 if (indent)
2257 pp_handle_indent(pp, sb, indent, line, linelen);
2258 else if (pp->expand_tabs_in_log)
2259 strbuf_add_tabexpand(sb, opt, pp->color,
2260 pp->expand_tabs_in_log, line,
2261 linelen);
2262 else {
2263 if (pp->fmt == CMIT_FMT_MBOXRD &&
2264 is_mboxrd_from(line, linelen))
2265 strbuf_addch(sb, '>');
2267 append_line_with_color(sb, opt, line, linelen,
2268 pp->color, GREP_CONTEXT_BODY,
2269 GREP_HEADER_FIELD_MAX);
2271 strbuf_addch(sb, '\n');
2275 void pretty_print_commit(struct pretty_print_context *pp,
2276 const struct commit *commit,
2277 struct strbuf *sb)
2279 unsigned long beginning_of_body;
2280 int indent = 4;
2281 const char *msg;
2282 const char *reencoded;
2283 const char *encoding;
2284 int need_8bit_cte = pp->need_8bit_cte;
2286 if (pp->fmt == CMIT_FMT_USERFORMAT) {
2287 repo_format_commit_message(the_repository, commit,
2288 user_format, sb, pp);
2289 return;
2292 encoding = get_log_output_encoding();
2293 msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL,
2294 encoding);
2296 if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
2297 indent = 0;
2300 * We need to check and emit Content-type: to mark it
2301 * as 8-bit if we haven't done so.
2303 if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {
2304 int i, ch, in_body;
2306 for (in_body = i = 0; (ch = msg[i]); i++) {
2307 if (!in_body) {
2308 /* author could be non 7-bit ASCII but
2309 * the log may be so; skip over the
2310 * header part first.
2312 if (ch == '\n' && msg[i+1] == '\n')
2313 in_body = 1;
2315 else if (non_ascii(ch)) {
2316 need_8bit_cte = 1;
2317 break;
2322 pp_header(pp, encoding, commit, &msg, sb);
2323 if (pp->fmt != CMIT_FMT_ONELINE && !pp->print_email_subject) {
2324 strbuf_addch(sb, '\n');
2327 /* Skip excess blank lines at the beginning of body, if any... */
2328 msg = skip_blank_lines(msg);
2330 /* These formats treat the title line specially. */
2331 if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
2332 pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
2334 beginning_of_body = sb->len;
2335 if (pp->fmt != CMIT_FMT_ONELINE)
2336 pp_remainder(pp, &msg, sb, indent);
2337 strbuf_rtrim(sb);
2339 /* Make sure there is an EOLN for the non-oneline case */
2340 if (pp->fmt != CMIT_FMT_ONELINE)
2341 strbuf_addch(sb, '\n');
2344 * The caller may append additional body text in e-mail
2345 * format. Make sure we did not strip the blank line
2346 * between the header and the body.
2348 if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
2349 strbuf_addch(sb, '\n');
2351 repo_unuse_commit_buffer(the_repository, commit, reencoded);
2354 void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
2355 struct strbuf *sb)
2357 struct pretty_print_context pp = {0};
2358 pp.fmt = fmt;
2359 pretty_print_commit(&pp, commit, sb);