🌐 AI搜索 & 代理 主页
blob: 29579f89b759c197f4bd8a4bad43920404ed72d7 [file] [log] [blame]
Johannes Schindelin93fc05e2007-11-04 19:15:061#include "cache.h"
Brandon Williamsb2141fc2017-06-14 18:07:362#include "config.h"
Johannes Schindelin93fc05e2007-11-04 19:15:063#include "commit.h"
Johannes Schindelin93fc05e2007-11-04 19:15:064#include "utf8.h"
5#include "diff.h"
6#include "revision.h"
Johannes Schindelinc455c872008-07-21 18:03:497#include "string-list.h"
Johannes Schindeline0cbc392008-07-11 23:28:188#include "mailmap.h"
René Scharfe3b3d4432008-09-04 21:40:039#include "log-tree.h"
Johannes Schindelina97a7462009-10-09 10:21:5710#include "notes.h"
Jeff Kingc0029222009-01-17 15:38:4611#include "color.h"
Thomas Rast8f8f5472009-10-19 15:48:1012#include "reflog-walk.h"
Junio C Hamanof6667c52011-10-22 04:06:0213#include "gpg-interface.h"
Jacob Kellerd9f31fb2016-11-19 00:58:1414#include "trailer.h"
René Scharfe15ae82d2021-02-14 10:04:3415#include "run-command.h"
Johannes Schindelin93fc05e2007-11-04 19:15:0616
Patrick Steinhardt304a50a2022-12-01 14:47:2317/*
18 * The limit for formatting directives, which enable the caller to append
19 * arbitrarily many bytes to the formatted buffer. This includes padding
20 * and wrapping formatters.
21 */
22#define FORMATTING_LIMIT (16 * 1024)
23
Johannes Schindelin93fc05e2007-11-04 19:15:0624static char *user_format;
Will Palmer40957892010-05-02 11:00:4225static struct cmt_fmt_map {
26 const char *name;
27 enum cmit_fmt format;
28 int is_tformat;
Junio C Hamano0893eec2016-03-29 22:49:2429 int expand_tabs_in_log;
Will Palmer2d7671e2010-05-02 11:00:4330 int is_alias;
Denton Liu618a8552019-11-20 00:51:2331 enum date_mode_type default_date_mode_type;
Will Palmer2d7671e2010-05-02 11:00:4332 const char *user_format;
Will Palmer40957892010-05-02 11:00:4233} *commit_formats;
Will Palmer80281842010-05-02 11:00:4434static size_t builtin_formats_len;
Will Palmer40957892010-05-02 11:00:4235static size_t commit_formats_len;
Will Palmer80281842010-05-02 11:00:4436static size_t commit_formats_alloc;
Will Palmer40957892010-05-02 11:00:4237static struct cmt_fmt_map *find_commit_format(const char *sought);
Johannes Schindelin93fc05e2007-11-04 19:15:0638
Jeff Kingb9c7d6e2014-07-29 17:56:4839int commit_format_is_empty(enum cmit_fmt fmt)
40{
41 return fmt == CMIT_FMT_USERFORMAT && !*user_format;
42}
43
Nanako Shiraishi36407542009-02-24 09:59:1544static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
45{
46 free(user_format);
47 user_format = xstrdup(cp);
48 if (is_tformat)
49 rev->use_terminator = 1;
50 rev->commit_format = CMIT_FMT_USERFORMAT;
51}
52
Will Palmer80281842010-05-02 11:00:4453static int git_pretty_formats_config(const char *var, const char *value, void *cb)
54{
55 struct cmt_fmt_map *commit_format = NULL;
56 const char *name;
57 const char *fmt;
58 int i;
59
Jeff King95b567c2014-06-18 19:48:2960 if (!skip_prefix(var, "pretty.", &name))
Will Palmer80281842010-05-02 11:00:4461 return 0;
62
Will Palmer80281842010-05-02 11:00:4463 for (i = 0; i < builtin_formats_len; i++) {
64 if (!strcmp(commit_formats[i].name, name))
65 return 0;
66 }
67
68 for (i = builtin_formats_len; i < commit_formats_len; i++) {
69 if (!strcmp(commit_formats[i].name, name)) {
70 commit_format = &commit_formats[i];
71 break;
72 }
73 }
74
75 if (!commit_format) {
76 ALLOC_GROW(commit_formats, commit_formats_len+1,
77 commit_formats_alloc);
78 commit_format = &commit_formats[commit_formats_len];
Jonathan Nieder95a26182010-05-08 21:07:3979 memset(commit_format, 0, sizeof(*commit_format));
Will Palmer80281842010-05-02 11:00:4480 commit_formats_len++;
81 }
82
83 commit_format->name = xstrdup(name);
84 commit_format->format = CMIT_FMT_USERFORMAT;
Tanay Abhraa26bc612014-08-04 14:41:1585 if (git_config_string(&fmt, var, value))
86 return -1;
87
René Scharfee3f1da92014-10-04 18:54:5088 if (skip_prefix(fmt, "format:", &fmt))
89 commit_format->is_tformat = 0;
90 else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
Will Palmer80281842010-05-02 11:00:4491 commit_format->is_tformat = 1;
92 else
93 commit_format->is_alias = 1;
94 commit_format->user_format = fmt;
95
96 return 0;
97}
98
Will Palmer40957892010-05-02 11:00:4299static void setup_commit_formats(void)
100{
101 struct cmt_fmt_map builtin_formats[] = {
Junio C Hamano0893eec2016-03-29 22:49:24102 { "raw", CMIT_FMT_RAW, 0, 0 },
Junio C Hamanofe37a9c2016-03-29 23:05:39103 { "medium", CMIT_FMT_MEDIUM, 0, 8 },
Junio C Hamano0893eec2016-03-29 22:49:24104 { "short", CMIT_FMT_SHORT, 0, 0 },
105 { "email", CMIT_FMT_EMAIL, 0, 0 },
Eric Wong9f23e042016-06-05 04:46:39106 { "mboxrd", CMIT_FMT_MBOXRD, 0, 0 },
Junio C Hamanofe37a9c2016-03-29 23:05:39107 { "fuller", CMIT_FMT_FULLER, 0, 8 },
108 { "full", CMIT_FMT_FULL, 0, 8 },
Denton Liu1f0fc1d2019-11-20 00:51:25109 { "oneline", CMIT_FMT_ONELINE, 1, 0 },
110 { "reference", CMIT_FMT_USERFORMAT, 1, 0,
111 0, DATE_SHORT, "%C(auto)%h (%s, %ad)" },
Nguyễn Thái Ngọc Duy5a59a232019-02-16 11:24:41112 /*
113 * Please update $__git_log_pretty_formats in
114 * git-completion.bash when you add new formats.
115 */
Will Palmer40957892010-05-02 11:00:42116 };
117 commit_formats_len = ARRAY_SIZE(builtin_formats);
Will Palmer80281842010-05-02 11:00:44118 builtin_formats_len = commit_formats_len;
119 ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
René Scharfe921d49b2019-06-15 18:36:35120 COPY_ARRAY(commit_formats, builtin_formats,
121 ARRAY_SIZE(builtin_formats));
Will Palmer80281842010-05-02 11:00:44122
123 git_config(git_pretty_formats_config, NULL);
Will Palmer40957892010-05-02 11:00:42124}
125
Will Palmer2d7671e2010-05-02 11:00:43126static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
127 const char *original,
128 int num_redirections)
Will Palmer40957892010-05-02 11:00:42129{
130 struct cmt_fmt_map *found = NULL;
131 size_t found_match_len = 0;
132 int i;
133
Will Palmer2d7671e2010-05-02 11:00:43134 if (num_redirections >= commit_formats_len)
135 die("invalid --pretty format: "
136 "'%s' references an alias which points to itself",
137 original);
Will Palmer40957892010-05-02 11:00:42138
139 for (i = 0; i < commit_formats_len; i++) {
140 size_t match_len;
141
Christian Couder59556542013-11-30 20:55:40142 if (!starts_with(commit_formats[i].name, sought))
Will Palmer40957892010-05-02 11:00:42143 continue;
144
145 match_len = strlen(commit_formats[i].name);
146 if (found == NULL || found_match_len > match_len) {
147 found = &commit_formats[i];
148 found_match_len = match_len;
149 }
150 }
Will Palmer2d7671e2010-05-02 11:00:43151
152 if (found && found->is_alias) {
153 found = find_commit_format_recursive(found->user_format,
154 original,
155 num_redirections+1);
156 }
157
Will Palmer40957892010-05-02 11:00:42158 return found;
159}
160
Will Palmer2d7671e2010-05-02 11:00:43161static struct cmt_fmt_map *find_commit_format(const char *sought)
162{
163 if (!commit_formats)
164 setup_commit_formats();
165
166 return find_commit_format_recursive(sought, sought, 0);
167}
168
Junio C Hamano4da45be2008-04-08 00:11:34169void get_commit_format(const char *arg, struct rev_info *rev)
Johannes Schindelin93fc05e2007-11-04 19:15:06170{
Will Palmer40957892010-05-02 11:00:42171 struct cmt_fmt_map *commit_format;
Johannes Schindelin93fc05e2007-11-04 19:15:06172
Junio C Hamano4da45be2008-04-08 00:11:34173 rev->use_terminator = 0;
Jeff Kingc75e7ad2014-07-29 17:54:46174 if (!arg) {
Junio C Hamano4da45be2008-04-08 00:11:34175 rev->commit_format = CMIT_FMT_DEFAULT;
176 return;
177 }
René Scharfee3f1da92014-10-04 18:54:50178 if (skip_prefix(arg, "format:", &arg)) {
179 save_user_format(rev, arg, 0);
Junio C Hamano4da45be2008-04-08 00:11:34180 return;
Johannes Schindelin93fc05e2007-11-04 19:15:06181 }
Will Palmer40957892010-05-02 11:00:42182
René Scharfee3f1da92014-10-04 18:54:50183 if (!*arg || skip_prefix(arg, "tformat:", &arg) || strchr(arg, '%')) {
Nanako Shiraishi36407542009-02-24 09:59:15184 save_user_format(rev, arg, 1);
185 return;
186 }
Johannes Schindelin93fc05e2007-11-04 19:15:06187
Will Palmer40957892010-05-02 11:00:42188 commit_format = find_commit_format(arg);
189 if (!commit_format)
190 die("invalid --pretty format: %s", arg);
191
192 rev->commit_format = commit_format->format;
193 rev->use_terminator = commit_format->is_tformat;
Junio C Hamano0893eec2016-03-29 22:49:24194 rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log;
Denton Liu618a8552019-11-20 00:51:23195 if (!rev->date_mode_explicit && commit_format->default_date_mode_type)
196 rev->date_mode.type = commit_format->default_date_mode_type;
Will Palmer80281842010-05-02 11:00:44197 if (commit_format->format == CMIT_FMT_USERFORMAT) {
198 save_user_format(rev, commit_format->user_format,
199 commit_format->is_tformat);
200 }
Johannes Schindelin93fc05e2007-11-04 19:15:06201}
202
203/*
204 * Generic support for pretty-printing the header
205 */
206static int get_one_line(const char *msg)
207{
208 int ret = 0;
209
210 for (;;) {
211 char c = *msg++;
212 if (!c)
213 break;
214 ret++;
215 if (c == '\n')
216 break;
217 }
218 return ret;
219}
220
221/* High bit set, or ISO-2022-INT */
Junio C Hamanocc571142010-01-12 06:23:35222static int non_ascii(int ch)
Johannes Schindelin93fc05e2007-11-04 19:15:06223{
René Scharfec2e93642009-03-07 13:06:49224 return !isascii(ch) || ch == '\033';
Johannes Schindelin93fc05e2007-11-04 19:15:06225}
226
Johannes Schindelin28e9cf62009-08-10 16:22:18227int has_non_ascii(const char *s)
228{
229 int ch;
230 if (!s)
231 return 0;
232 while ((ch = *s++) != '\0') {
233 if (non_ascii(ch))
234 return 1;
235 }
236 return 0;
237}
238
Jeff King4d03c182011-04-08 22:40:36239static int is_rfc822_special(char ch)
240{
241 switch (ch) {
242 case '(':
243 case ')':
244 case '<':
245 case '>':
246 case '[':
247 case ']':
248 case ':':
249 case ';':
250 case '@':
251 case ',':
252 case '.':
253 case '"':
254 case '\\':
255 return 1;
256 default:
257 return 0;
258 }
259}
260
Jan H. Schönherr41dd00b2012-10-18 14:43:33261static int needs_rfc822_quoting(const char *s, int len)
Jeff King4d03c182011-04-08 22:40:36262{
263 int i;
264 for (i = 0; i < len; i++)
265 if (is_rfc822_special(s[i]))
266 return 1;
267 return 0;
268}
269
Jan H. Schönherrf9b72042012-10-18 14:43:31270static int last_line_length(struct strbuf *sb)
271{
272 int i;
273
274 /* How many bytes are already used on the last line? */
275 for (i = sb->len - 1; i >= 0; i--)
276 if (sb->buf[i] == '\n')
277 break;
278 return sb->len - (i + 1);
279}
280
Jeff King4d03c182011-04-08 22:40:36281static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
282{
283 int i;
284
285 /* just a guess, we may have to also backslash-quote */
286 strbuf_grow(out, len + 2);
287
288 strbuf_addch(out, '"');
289 for (i = 0; i < len; i++) {
290 switch (s[i]) {
291 case '"':
292 case '\\':
293 strbuf_addch(out, '\\');
294 /* fall through */
295 default:
296 strbuf_addch(out, s[i]);
297 }
298 }
299 strbuf_addch(out, '"');
300}
301
Jan H. Schönherr0fcec2c2012-10-18 14:43:32302enum rfc2047_type {
303 RFC2047_SUBJECT,
Ronnie Sahlberg78273522014-07-02 18:24:05304 RFC2047_ADDRESS
Jan H. Schönherr0fcec2c2012-10-18 14:43:32305};
306
307static int is_rfc2047_special(char ch, enum rfc2047_type type)
Johannes Schindelin93fc05e2007-11-04 19:15:06308{
Jan H. Schönherr0fcec2c2012-10-18 14:43:32309 /*
310 * rfc2047, section 4.2:
311 *
312 * 8-bit values which correspond to printable ASCII characters other
313 * than "=", "?", and "_" (underscore), MAY be represented as those
314 * characters. (But see section 5 for restrictions.) In
315 * particular, SPACE and TAB MUST NOT be represented as themselves
316 * within encoded words.
317 */
318
319 /*
320 * rule out non-ASCII characters and non-printable characters (the
321 * non-ASCII check should be redundant as isprint() is not localized
322 * and only knows about ASCII, but be defensive about that)
323 */
324 if (non_ascii(ch) || !isprint(ch))
Jan H. Schönherr94f6cdf2012-10-18 14:43:30325 return 1;
326
Jan H. Schönherr0fcec2c2012-10-18 14:43:32327 /*
328 * rule out special printable characters (' ' should be the only
329 * whitespace character considered printable, but be defensive and use
330 * isspace())
331 */
332 if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
333 return 1;
334
335 /*
336 * rfc2047, section 5.3:
337 *
338 * As a replacement for a 'word' entity within a 'phrase', for example,
339 * one that precedes an address in a From, To, or Cc header. The ABNF
340 * definition for 'phrase' from RFC 822 thus becomes:
341 *
342 * phrase = 1*( encoded-word / word )
343 *
344 * In this case the set of characters that may be used in a "Q"-encoded
345 * 'encoded-word' is restricted to: <upper and lower case ASCII
346 * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
347 * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
348 * 'phrase' MUST be separated from any adjacent 'word', 'text' or
349 * 'special' by 'linear-white-space'.
350 */
351
352 if (type != RFC2047_ADDRESS)
353 return 0;
354
355 /* '=' and '_' are special cases and have been checked above */
356 return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
Johannes Schindelin93fc05e2007-11-04 19:15:06357}
358
Jeff Kingda55ff32019-03-20 08:16:36359static int needs_rfc2047_encoding(const char *line, int len)
Johannes Schindelin93fc05e2007-11-04 19:15:06360{
Jeff Kinga1f6baa2011-02-23 09:58:41361 int i;
Johannes Schindelin93fc05e2007-11-04 19:15:06362
363 for (i = 0; i < len; i++) {
364 int ch = line[i];
Jeff Kingc22e7de2011-02-23 09:59:18365 if (non_ascii(ch) || ch == '\n')
Jan H. Schönherr41dd00b2012-10-18 14:43:33366 return 1;
Johannes Schindelin93fc05e2007-11-04 19:15:06367 if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
Jan H. Schönherr41dd00b2012-10-18 14:43:33368 return 1;
Johannes Schindelin93fc05e2007-11-04 19:15:06369 }
Johannes Schindelin93fc05e2007-11-04 19:15:06370
Jan H. Schönherr41dd00b2012-10-18 14:43:33371 return 0;
372}
373
Kirill Smelkov6cd3c052013-03-07 10:55:07374static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
Jan H. Schönherr41dd00b2012-10-18 14:43:33375 const char *encoding, enum rfc2047_type type)
376{
377 static const int max_encoded_length = 76; /* per rfc2047 */
378 int i;
379 int line_len = last_line_length(sb);
380
Johannes Schindelin93fc05e2007-11-04 19:15:06381 strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
382 strbuf_addf(sb, "=?%s?q?", encoding);
Jeff Kinga1f6baa2011-02-23 09:58:41383 line_len += strlen(encoding) + 5; /* 5 for =??q? */
Kirill Smelkov6cd3c052013-03-07 10:55:07384
385 while (len) {
386 /*
387 * RFC 2047, section 5 (3):
388 *
389 * Each 'encoded-word' MUST represent an integral number of
390 * characters. A multi-octet character may not be split across
391 * adjacent 'encoded- word's.
392 */
393 const unsigned char *p = (const unsigned char *)line;
394 int chrlen = mbs_chrlen(&line, &len, encoding);
395 int is_special = (chrlen > 1) || is_rfc2047_special(*p, type);
396
397 /* "=%02X" * chrlen, or the byte itself */
398 const char *encoded_fmt = is_special ? "=%02X" : "%c";
399 int encoded_len = is_special ? 3 * chrlen : 1;
Jeff Kinga1f6baa2011-02-23 09:58:41400
Jan H. Schönherr94f6cdf2012-10-18 14:43:30401 /*
402 * According to RFC 2047, we could encode the special character
403 * ' ' (space) with '_' (underscore) for readability. But many
404 * programs do not understand this and just leave the
405 * underscore in place. Thus, we do nothing special here, which
406 * causes ' ' to be encoded as '=20', avoiding this problem.
407 */
408
Kirill Smelkov6cd3c052013-03-07 10:55:07409 if (line_len + encoded_len + 2 > max_encoded_length) {
410 /* It won't fit with trailing "?=" --- break the line */
Jeff Kinga1f6baa2011-02-23 09:58:41411 strbuf_addf(sb, "?=\n =?%s?q?", encoding);
412 line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
413 }
414
Kirill Smelkov6cd3c052013-03-07 10:55:07415 for (i = 0; i < chrlen; i++)
416 strbuf_addf(sb, encoded_fmt, p[i]);
417 line_len += encoded_len;
Johannes Schindelin93fc05e2007-11-04 19:15:06418 }
Johannes Schindelin93fc05e2007-11-04 19:15:06419 strbuf_addstr(sb, "?=");
420}
421
Jeff Kingd1053242014-05-02 01:07:22422const char *show_ident_date(const struct ident_split *ident,
Jeff Kinga5481a62015-06-25 16:55:02423 const struct date_mode *mode)
René Scharfe9dbe7c32013-04-17 18:33:35424{
Johannes Schindelindddbad72017-04-26 19:29:31425 timestamp_t date = 0;
Jeff King3f419d42014-03-07 17:15:01426 long tz = 0;
René Scharfe9dbe7c32013-04-17 18:33:35427
428 if (ident->date_begin && ident->date_end)
Johannes Schindelin1aeb7e72017-04-21 10:45:44429 date = parse_timestamp(ident->date_begin, NULL, 10);
Jeff King1dca1552014-02-24 07:46:37430 if (date_overflows(date))
431 date = 0;
432 else {
433 if (ident->tz_begin && ident->tz_end)
434 tz = strtol(ident->tz_begin, NULL, 10);
Jeff King3f419d42014-03-07 17:15:01435 if (tz >= INT_MAX || tz <= INT_MIN)
Jeff King1dca1552014-02-24 07:46:37436 tz = 0;
437 }
René Scharfe9dbe7c32013-04-17 18:33:35438 return show_date(date, tz, mode);
439}
440
Hamza Mahfooz6a5c3372021-10-07 20:31:47441static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,
442 const char *buf, size_t buflen)
443{
444 strbuf_addstr(sb, color);
445 strbuf_add(sb, buf, buflen);
446 if (*color)
447 strbuf_addstr(sb, GIT_COLOR_RESET);
448}
449
450static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,
451 const char *line, size_t linelen,
452 int color, enum grep_context ctx,
453 enum grep_header_field field)
454{
455 const char *buf, *eol, *line_color, *match_color;
456 regmatch_t match;
457 int eflags = 0;
458
459 buf = line;
460 eol = buf + linelen;
461
462 if (!opt || !want_color(color) || opt->invert)
463 goto end;
464
465 line_color = opt->colors[GREP_COLOR_SELECTED];
466 match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
467
468 while (grep_next_match(opt, buf, eol, ctx, &match, field, eflags)) {
469 if (match.rm_so == match.rm_eo)
470 break;
471
472 strbuf_add_with_color(sb, line_color, buf, match.rm_so);
473 strbuf_add_with_color(sb, match_color, buf + match.rm_so,
474 match.rm_eo - match.rm_so);
475 buf += match.rm_eo;
476 eflags = REG_NOTBOL;
477 }
478
479 if (eflags)
480 strbuf_add_with_color(sb, line_color, buf, eol - buf);
481 else {
482end:
483 strbuf_add(sb, buf, eol - buf);
484 }
485}
486
Jeff King10f2fbf2013-07-03 07:07:48487void pp_user_info(struct pretty_print_context *pp,
Jeff King6bf13942011-05-26 22:27:49488 const char *what, struct strbuf *sb,
489 const char *line, const char *encoding)
Johannes Schindelin93fc05e2007-11-04 19:15:06490{
Antoine Pelisse3c020bd2013-01-05 21:26:38491 struct ident_split ident;
René Scharfe9dbe7c32013-04-17 18:33:35492 char *line_end;
Antoine Pelissedffd3252013-01-05 21:26:42493 const char *mailbuf, *namebuf;
494 size_t namelen, maillen;
Jan H. Schönherr41dd00b2012-10-18 14:43:33495 int max_length = 78; /* per rfc2822 */
Johannes Schindelin93fc05e2007-11-04 19:15:06496
Jeff King6bf13942011-05-26 22:27:49497 if (pp->fmt == CMIT_FMT_ONELINE)
Johannes Schindelin93fc05e2007-11-04 19:15:06498 return;
Antoine Pelisse3c020bd2013-01-05 21:26:38499
René Scharfe30e77bc2013-04-25 19:40:25500 line_end = strchrnul(line, '\n');
501 if (split_ident_line(&ident, line, line_end - line))
Johannes Schindelin93fc05e2007-11-04 19:15:06502 return;
Antoine Pelisse3c020bd2013-01-05 21:26:38503
Antoine Pelissedffd3252013-01-05 21:26:42504 mailbuf = ident.mail_begin;
505 maillen = ident.mail_end - ident.mail_begin;
506 namebuf = ident.name_begin;
507 namelen = ident.name_end - ident.name_begin;
508
509 if (pp->mailmap)
510 map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
511
Eric Wong9f23e042016-06-05 04:46:39512 if (cmit_fmt_is_mail(pp->fmt)) {
Jeff King662cc302013-09-20 10:16:28513 if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
Jeff Kinga9080472013-07-03 07:08:22514 struct strbuf buf = STRBUF_INIT;
515
516 strbuf_addstr(&buf, "From: ");
517 strbuf_add(&buf, namebuf, namelen);
518 strbuf_addstr(&buf, " <");
519 strbuf_add(&buf, mailbuf, maillen);
520 strbuf_addstr(&buf, ">\n");
521 string_list_append(&pp->in_body_headers,
522 strbuf_detach(&buf, NULL));
523
524 mailbuf = pp->from_ident->mail_begin;
525 maillen = pp->from_ident->mail_end - mailbuf;
526 namebuf = pp->from_ident->name_begin;
527 namelen = pp->from_ident->name_end - namebuf;
528 }
529
Johannes Schindelin93fc05e2007-11-04 19:15:06530 strbuf_addstr(sb, "From: ");
Emma Brooks19d097e2020-04-08 04:31:38531 if (pp->encode_email_headers &&
532 needs_rfc2047_encoding(namebuf, namelen)) {
René Scharfea0511b32013-04-25 19:43:56533 add_rfc2047(sb, namebuf, namelen,
Antoine Pelissedffd3252013-01-05 21:26:42534 encoding, RFC2047_ADDRESS);
Jan H. Schönherr41dd00b2012-10-18 14:43:33535 max_length = 76; /* per rfc2047 */
René Scharfea0511b32013-04-25 19:43:56536 } else if (needs_rfc822_quoting(namebuf, namelen)) {
Jeff King4d03c182011-04-08 22:40:36537 struct strbuf quoted = STRBUF_INIT;
René Scharfea0511b32013-04-25 19:43:56538 add_rfc822_quoted(&quoted, namebuf, namelen);
Jan H. Schönherr41dd00b2012-10-18 14:43:33539 strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
540 -6, 1, max_length);
Jeff King4d03c182011-04-08 22:40:36541 strbuf_release(&quoted);
Jan H. Schönherr41dd00b2012-10-18 14:43:33542 } else {
René Scharfea0511b32013-04-25 19:43:56543 strbuf_add_wrapped_bytes(sb, namebuf, namelen,
Antoine Pelissedffd3252013-01-05 21:26:42544 -6, 1, max_length);
Jeff King4d03c182011-04-08 22:40:36545 }
Antoine Pelissedffd3252013-01-05 21:26:42546
René Scharfe97a17e72013-04-25 19:41:57547 if (max_length <
548 last_line_length(sb) + strlen(" <") + maillen + strlen(">"))
Jeff King990f6e32011-04-14 22:18:09549 strbuf_addch(sb, '\n');
René Scharfea0511b32013-04-25 19:43:56550 strbuf_addf(sb, " <%.*s>\n", (int)maillen, mailbuf);
Johannes Schindelin93fc05e2007-11-04 19:15:06551 } else {
Hamza Mahfooz6a5c3372021-10-07 20:31:47552 struct strbuf id = STRBUF_INIT;
553 enum grep_header_field field = GREP_HEADER_FIELD_MAX;
554 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
555
556 if (!strcmp(what, "Author"))
557 field = GREP_HEADER_AUTHOR;
558 else if (!strcmp(what, "Commit"))
559 field = GREP_HEADER_COMMITTER;
560
561 strbuf_addf(sb, "%s: ", what);
562 if (pp->fmt == CMIT_FMT_FULLER)
563 strbuf_addchars(sb, ' ', 4);
564
565 strbuf_addf(&id, "%.*s <%.*s>", (int)namelen, namebuf,
566 (int)maillen, mailbuf);
567
568 append_line_with_color(sb, opt, id.buf, id.len, pp->color,
569 GREP_CONTEXT_HEAD, field);
570 strbuf_addch(sb, '\n');
571 strbuf_release(&id);
Johannes Schindelin93fc05e2007-11-04 19:15:06572 }
Antoine Pelissedffd3252013-01-05 21:26:42573
Jeff King6bf13942011-05-26 22:27:49574 switch (pp->fmt) {
Johannes Schindelin93fc05e2007-11-04 19:15:06575 case CMIT_FMT_MEDIUM:
René Scharfe9dbe7c32013-04-17 18:33:35576 strbuf_addf(sb, "Date: %s\n",
Jeff Kinga5481a62015-06-25 16:55:02577 show_ident_date(&ident, &pp->date_mode));
Johannes Schindelin93fc05e2007-11-04 19:15:06578 break;
579 case CMIT_FMT_EMAIL:
Eric Wong9f23e042016-06-05 04:46:39580 case CMIT_FMT_MBOXRD:
René Scharfe9dbe7c32013-04-17 18:33:35581 strbuf_addf(sb, "Date: %s\n",
Jeff Kinga5481a62015-06-25 16:55:02582 show_ident_date(&ident, DATE_MODE(RFC2822)));
Johannes Schindelin93fc05e2007-11-04 19:15:06583 break;
584 case CMIT_FMT_FULLER:
René Scharfe9dbe7c32013-04-17 18:33:35585 strbuf_addf(sb, "%sDate: %s\n", what,
Jeff Kinga5481a62015-06-25 16:55:02586 show_ident_date(&ident, &pp->date_mode));
Johannes Schindelin93fc05e2007-11-04 19:15:06587 break;
588 default:
589 /* notin' */
590 break;
591 }
592}
593
Johannes Schindelin77356122016-06-22 20:20:16594static int is_blank_line(const char *line, int *len_p)
Johannes Schindelin93fc05e2007-11-04 19:15:06595{
596 int len = *len_p;
Felipe Contreras35b2fa52013-10-31 09:25:42597 while (len && isspace(line[len - 1]))
Johannes Schindelin93fc05e2007-11-04 19:15:06598 len--;
599 *len_p = len;
600 return !len;
601}
602
Johannes Schindelin77356122016-06-22 20:20:16603const char *skip_blank_lines(const char *msg)
René Scharfea0109662008-12-27 00:32:49604{
605 for (;;) {
606 int linelen = get_one_line(msg);
607 int ll = linelen;
608 if (!linelen)
609 break;
Johannes Schindelin77356122016-06-22 20:20:16610 if (!is_blank_line(msg, &ll))
René Scharfea0109662008-12-27 00:32:49611 break;
612 msg += linelen;
613 }
614 return msg;
615}
616
Jeff King6bf13942011-05-26 22:27:49617static void add_merge_info(const struct pretty_print_context *pp,
618 struct strbuf *sb, const struct commit *commit)
Johannes Schindelin93fc05e2007-11-04 19:15:06619{
620 struct commit_list *parent = commit->parents;
621
Eric Wong9f23e042016-06-05 04:46:39622 if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) ||
Johannes Schindelin93fc05e2007-11-04 19:15:06623 !parent || !parent->next)
624 return;
625
626 strbuf_addstr(sb, "Merge:");
627
628 while (parent) {
René Scharfea94bb682016-10-08 15:38:47629 struct object_id *oidp = &parent->item->object.oid;
630 strbuf_addch(sb, ' ');
Jeff King6bf13942011-05-26 22:27:49631 if (pp->abbrev)
brian m. carlson30e677e2018-03-12 02:27:28632 strbuf_add_unique_abbrev(sb, oidp, pp->abbrev);
René Scharfea94bb682016-10-08 15:38:47633 else
634 strbuf_addstr(sb, oid_to_hex(oidp));
Johannes Schindelin93fc05e2007-11-04 19:15:06635 parent = parent->next;
Johannes Schindelin93fc05e2007-11-04 19:15:06636 }
637 strbuf_addch(sb, '\n');
638}
639
Jeff Kingfe6eb7f2014-08-27 07:56:01640static char *get_header(const char *msg, const char *key)
Johannes Schindelin93fc05e2007-11-04 19:15:06641{
Jeff Kingfe6eb7f2014-08-27 07:56:01642 size_t len;
643 const char *v = find_commit_header(msg, key, &len);
644 return v ? xmemdupz(v, len) : NULL;
Johannes Schindelin93fc05e2007-11-04 19:15:06645}
646
647static char *replace_encoding_header(char *buf, const char *encoding)
648{
Brandon Caseyf285a2d2008-10-09 19:12:12649 struct strbuf tmp = STRBUF_INIT;
Johannes Schindelin93fc05e2007-11-04 19:15:06650 size_t start, len;
651 char *cp = buf;
652
653 /* guess if there is an encoding header before a \n\n */
René Scharfe68d6d6e2015-02-21 19:53:09654 while (!starts_with(cp, "encoding ")) {
Johannes Schindelin93fc05e2007-11-04 19:15:06655 cp = strchr(cp, '\n');
656 if (!cp || *++cp == '\n')
657 return buf;
658 }
659 start = cp - buf;
660 cp = strchr(cp, '\n');
661 if (!cp)
662 return buf; /* should not happen but be defensive */
663 len = cp + 1 - (buf + start);
664
Johannes Schindelin93fc05e2007-11-04 19:15:06665 strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
666 if (is_encoding_utf8(encoding)) {
667 /* we have re-coded to UTF-8; drop the header */
668 strbuf_remove(&tmp, start, len);
669 } else {
670 /* just replaces XXXX in 'encoding XXXX\n' */
671 strbuf_splice(&tmp, start + strlen("encoding "),
672 len - strlen("encoding \n"),
673 encoding, strlen(encoding));
674 }
675 return strbuf_detach(&tmp, NULL);
676}
677
Stefan Beller424510e2018-11-14 00:12:59678const char *repo_logmsg_reencode(struct repository *r,
679 const struct commit *commit,
680 char **commit_encoding,
681 const char *output_encoding)
Johannes Schindelin93fc05e2007-11-04 19:15:06682{
Brandon Casey330db182009-05-18 23:44:39683 static const char *utf8 = "UTF-8";
Johannes Schindelin93fc05e2007-11-04 19:15:06684 const char *use_encoding;
685 char *encoding;
Stefan Beller424510e2018-11-14 00:12:59686 const char *msg = repo_get_commit_buffer(r, commit, NULL);
Johannes Schindelin93fc05e2007-11-04 19:15:06687 char *out;
688
Nguyễn Thái Ngọc Duy5a10d232013-04-18 23:08:40689 if (!output_encoding || !*output_encoding) {
690 if (commit_encoding)
Jeff Kingfe6eb7f2014-08-27 07:56:01691 *commit_encoding = get_header(msg, "encoding");
Jeff Kingdd0d3882013-01-26 09:44:06692 return msg;
Nguyễn Thái Ngọc Duy5a10d232013-04-18 23:08:40693 }
Jeff Kingfe6eb7f2014-08-27 07:56:01694 encoding = get_header(msg, "encoding");
Nguyễn Thái Ngọc Duy5a10d232013-04-18 23:08:40695 if (commit_encoding)
696 *commit_encoding = encoding;
Johannes Schindelin93fc05e2007-11-04 19:15:06697 use_encoding = encoding ? encoding : utf8;
Jeff Kingbe5c9fb2013-01-26 09:44:28698 if (same_encoding(use_encoding, output_encoding)) {
699 /*
700 * No encoding work to be done. If we have no encoding header
701 * at all, then there's nothing to do, and we can return the
702 * message verbatim (whether newly allocated or not).
703 */
704 if (!encoding)
705 return msg;
706
707 /*
708 * Otherwise, we still want to munge the encoding header in the
709 * result, which will be done by modifying the buffer. If we
710 * are using a fresh copy, we can reuse it. But if we are using
Jeff Kingb66103c2014-06-10 21:41:39711 * the cached copy from get_commit_buffer, we need to duplicate it
712 * to avoid munging the cached copy.
Jeff Kingbe5c9fb2013-01-26 09:44:28713 */
Stefan Beller424510e2018-11-14 00:12:59714 if (msg == get_cached_commit_buffer(r, commit, NULL))
Jeff Kingb66103c2014-06-10 21:41:39715 out = xstrdup(msg);
716 else
717 out = (char *)msg;
Jeff Kingbe5c9fb2013-01-26 09:44:28718 }
719 else {
720 /*
721 * There's actual encoding work to do. Do the reencoding, which
722 * still leaves the header to be replaced in the next step. At
723 * this point, we are done with msg. If we allocated a fresh
724 * copy, we can free it.
725 */
726 out = reencode_string(msg, output_encoding, use_encoding);
Jeff Kingb66103c2014-06-10 21:41:39727 if (out)
Stefan Beller424510e2018-11-14 00:12:59728 repo_unuse_commit_buffer(r, commit, msg);
Jeff Kingbe5c9fb2013-01-26 09:44:28729 }
730
731 /*
732 * This replacement actually consumes the buffer we hand it, so we do
733 * not have to worry about freeing the old "out" here.
734 */
Johannes Schindelin93fc05e2007-11-04 19:15:06735 if (out)
736 out = replace_encoding_header(out, output_encoding);
737
Nguyễn Thái Ngọc Duy5a10d232013-04-18 23:08:40738 if (!commit_encoding)
739 free(encoding);
Jeff Kingdd0d3882013-01-26 09:44:06740 /*
741 * If the re-encoding failed, out might be NULL here; in that
742 * case we just return the commit message verbatim.
743 */
Junio C Hamano0988e662021-10-29 20:48:58744 return out ? out : msg;
Jeff Kingdd0d3882013-01-26 09:44:06745}
746
Antoine Pelisseea02ffa2013-01-05 21:26:40747static int mailmap_name(const char **email, size_t *email_len,
748 const char **name, size_t *name_len)
Johannes Schindeline0cbc392008-07-11 23:28:18749{
Johannes Schindelinc455c872008-07-21 18:03:49750 static struct string_list *mail_map;
Johannes Schindeline0cbc392008-07-11 23:28:18751 if (!mail_map) {
René Scharfeca56dad2021-03-13 16:17:22752 CALLOC_ARRAY(mail_map, 1);
Ævar Arnfjörð Bjarmason4e168332021-01-12 20:18:06753 read_mailmap(mail_map);
Johannes Schindeline0cbc392008-07-11 23:28:18754 }
Marius Storm-Olsend20d6542009-02-08 14:34:30755 return mail_map->nr && map_user(mail_map, email, email_len, name, name_len);
Johannes Schindeline0cbc392008-07-11 23:28:18756}
757
Marco Costalbac3a670d2008-02-09 14:40:19758static size_t format_person_part(struct strbuf *sb, char part,
Jeff Kinga5481a62015-06-25 16:55:02759 const char *msg, int len,
760 const struct date_mode *dmode)
Johannes Schindelin93fc05e2007-11-04 19:15:06761{
Marco Costalbac3a670d2008-02-09 14:40:19762 /* currently all placeholders have same length */
763 const int placeholder_len = 2;
Junio C Hamano4b340cf2012-03-11 09:25:43764 struct ident_split s;
Antoine Pelisseea02ffa2013-01-05 21:26:40765 const char *name, *mail;
766 size_t maillen, namelen;
Johannes Schindelin93fc05e2007-11-04 19:15:06767
Junio C Hamano4b340cf2012-03-11 09:25:43768 if (split_ident_line(&s, msg, len) < 0)
Marco Costalbac3a670d2008-02-09 14:40:19769 goto skip;
770
Antoine Pelisseea02ffa2013-01-05 21:26:40771 name = s.name_begin;
772 namelen = s.name_end - s.name_begin;
773 mail = s.mail_begin;
774 maillen = s.mail_end - s.mail_begin;
Marius Storm-Olsend20d6542009-02-08 14:34:30775
Prarit Bhargavad8b82172019-10-29 12:09:14776 if (part == 'N' || part == 'E' || part == 'L') /* mailmap lookup */
Antoine Pelisseea02ffa2013-01-05 21:26:40777 mailmap_name(&mail, &maillen, &name, &namelen);
Johannes Schindeline0cbc392008-07-11 23:28:18778 if (part == 'n' || part == 'N') { /* name */
Antoine Pelisseea02ffa2013-01-05 21:26:40779 strbuf_add(sb, name, namelen);
Marco Costalbac3a670d2008-02-09 14:40:19780 return placeholder_len;
781 }
Marius Storm-Olsend20d6542009-02-08 14:34:30782 if (part == 'e' || part == 'E') { /* email */
Antoine Pelisseea02ffa2013-01-05 21:26:40783 strbuf_add(sb, mail, maillen);
Marco Costalbac3a670d2008-02-09 14:40:19784 return placeholder_len;
René Scharfecde75e52007-11-09 00:49:42785 }
Prarit Bhargavad8b82172019-10-29 12:09:14786 if (part == 'l' || part == 'L') { /* local-part */
787 const char *at = memchr(mail, '@', maillen);
788 if (at)
789 maillen = at - mail;
790 strbuf_add(sb, mail, maillen);
791 return placeholder_len;
792 }
Johannes Schindelin93fc05e2007-11-04 19:15:06793
Junio C Hamano4b340cf2012-03-11 09:25:43794 if (!s.date_begin)
Marco Costalbac3a670d2008-02-09 14:40:19795 goto skip;
Johannes Schindelin93fc05e2007-11-04 19:15:06796
René Scharfecde75e52007-11-09 00:49:42797 if (part == 't') { /* date, UNIX timestamp */
Junio C Hamano4b340cf2012-03-11 09:25:43798 strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
Marco Costalbac3a670d2008-02-09 14:40:19799 return placeholder_len;
René Scharfecde75e52007-11-09 00:49:42800 }
Johannes Schindelin93fc05e2007-11-04 19:15:06801
René Scharfecde75e52007-11-09 00:49:42802 switch (part) {
803 case 'd': /* date */
René Scharfe9dbe7c32013-04-17 18:33:35804 strbuf_addstr(sb, show_ident_date(&s, dmode));
Marco Costalbac3a670d2008-02-09 14:40:19805 return placeholder_len;
René Scharfecde75e52007-11-09 00:49:42806 case 'D': /* date, RFC2822 style */
Jeff Kinga5481a62015-06-25 16:55:02807 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RFC2822)));
Marco Costalbac3a670d2008-02-09 14:40:19808 return placeholder_len;
René Scharfecde75e52007-11-09 00:49:42809 case 'r': /* date, relative */
Jeff Kinga5481a62015-06-25 16:55:02810 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RELATIVE)));
Marco Costalbac3a670d2008-02-09 14:40:19811 return placeholder_len;
Beat Bolli466fb672014-08-29 16:58:42812 case 'i': /* date, ISO 8601-like */
Jeff Kinga5481a62015-06-25 16:55:02813 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601)));
Marco Costalbac3a670d2008-02-09 14:40:19814 return placeholder_len;
Beat Bolli466fb672014-08-29 16:58:42815 case 'I': /* date, ISO 8601 strict */
Jeff Kinga5481a62015-06-25 16:55:02816 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT)));
Beat Bolli466fb672014-08-29 16:58:42817 return placeholder_len;
ZheNing Hub722d452021-04-25 10:41:45818 case 'h': /* date, human */
819 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(HUMAN)));
820 return placeholder_len;
René Scharfe0df62112019-11-20 00:51:21821 case 's':
822 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(SHORT)));
823 return placeholder_len;
René Scharfecde75e52007-11-09 00:49:42824 }
Marco Costalbac3a670d2008-02-09 14:40:19825
826skip:
827 /*
Junio C Hamano4b340cf2012-03-11 09:25:43828 * reading from either a bogus commit, or a reflog entry with
829 * %gn, %ge, etc.; 'sb' cannot be updated, but we still need
830 * to compute a valid return value.
Marco Costalbac3a670d2008-02-09 14:40:19831 */
832 if (part == 'n' || part == 'e' || part == 't' || part == 'd'
833 || part == 'D' || part == 'r' || part == 'i')
834 return placeholder_len;
835
836 return 0; /* unknown placeholder */
Johannes Schindelin93fc05e2007-11-04 19:15:06837}
838
René Scharfef29d5952007-11-10 11:14:20839struct chunk {
840 size_t off;
841 size_t len;
842};
843
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:50844enum flush_type {
845 no_flush,
846 flush_right,
847 flush_left,
Nguyễn Thái Ngọc Duy16406322013-04-18 23:08:52848 flush_left_and_steal,
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:50849 flush_both
850};
851
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:51852enum trunc_type {
853 trunc_none,
854 trunc_left,
855 trunc_middle,
856 trunc_right
857};
858
René Scharfef29d5952007-11-10 11:14:20859struct format_commit_context {
Jeff King018b9de2021-01-28 19:57:39860 struct repository *repository;
René Scharfef29d5952007-11-10 11:14:20861 const struct commit *commit;
Thomas Rastdd2e7942009-10-19 15:48:08862 const struct pretty_print_context *pretty_ctx;
René Scharfef53bd742008-12-27 00:49:21863 unsigned commit_header_parsed:1;
864 unsigned commit_message_parsed:1;
Sebastian Götteffb6d7d2013-03-31 16:00:14865 struct signature_check signature_check;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:50866 enum flush_type flush_type;
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:51867 enum trunc_type truncate;
Jeff Kingb000c592014-06-10 21:39:30868 const char *message;
Nguyễn Thái Ngọc Duy0940a762013-04-18 23:08:41869 char *commit_encoding;
René Scharfe02edd562009-10-17 21:04:19870 size_t width, indent1, indent2;
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:49871 int auto_color;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:50872 int padding;
René Scharfef29d5952007-11-10 11:14:20873
874 /* These offsets are relative to the start of the commit message. */
René Scharfef29d5952007-11-10 11:14:20875 struct chunk author;
876 struct chunk committer;
René Scharfef53bd742008-12-27 00:49:21877 size_t message_off;
878 size_t subject_off;
René Scharfef29d5952007-11-10 11:14:20879 size_t body_off;
René Scharfeb9c62322007-11-10 11:18:26880
881 /* The following ones are relative to the result struct strbuf. */
René Scharfe02edd562009-10-17 21:04:19882 size_t wrap_start;
René Scharfef29d5952007-11-10 11:14:20883};
884
René Scharfef29d5952007-11-10 11:14:20885static void parse_commit_header(struct format_commit_context *context)
886{
Pat Notz177b29d2010-11-02 19:59:08887 const char *msg = context->message;
René Scharfef29d5952007-11-10 11:14:20888 int i;
René Scharfef29d5952007-11-10 11:14:20889
René Scharfef53bd742008-12-27 00:49:21890 for (i = 0; msg[i]; i++) {
René Scharfee3f1da92014-10-04 18:54:50891 const char *name;
René Scharfef29d5952007-11-10 11:14:20892 int eol;
893 for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
894 ; /* do nothing */
895
René Scharfef29d5952007-11-10 11:14:20896 if (i == eol) {
René Scharfef53bd742008-12-27 00:49:21897 break;
René Scharfee3f1da92014-10-04 18:54:50898 } else if (skip_prefix(msg + i, "author ", &name)) {
899 context->author.off = name - msg;
900 context->author.len = msg + eol - name;
901 } else if (skip_prefix(msg + i, "committer ", &name)) {
902 context->committer.off = name - msg;
903 context->committer.len = msg + eol - name;
René Scharfef29d5952007-11-10 11:14:20904 }
905 i = eol;
René Scharfef29d5952007-11-10 11:14:20906 }
René Scharfef53bd742008-12-27 00:49:21907 context->message_off = i;
René Scharfef29d5952007-11-10 11:14:20908 context->commit_header_parsed = 1;
909}
910
Stephen Boyd46d164b2009-03-23 02:14:01911static int istitlechar(char c)
912{
913 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
914 (c >= '0' && c <= '9') || c == '.' || c == '_';
915}
916
Hariom Verma47d46762020-08-21 21:41:49917void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len)
Stephen Boyd46d164b2009-03-23 02:14:01918{
919 size_t trimlen;
Stephen Boyd871d21d2009-03-31 23:24:38920 size_t start_len = sb->len;
Stephen Boyd46d164b2009-03-23 02:14:01921 int space = 2;
Hariom Verma47d46762020-08-21 21:41:49922 int i;
Stephen Boyd46d164b2009-03-23 02:14:01923
Hariom Verma47d46762020-08-21 21:41:49924 for (i = 0; i < len; i++) {
925 if (istitlechar(msg[i])) {
Stephen Boyd46d164b2009-03-23 02:14:01926 if (space == 1)
927 strbuf_addch(sb, '-');
928 space = 0;
Hariom Verma47d46762020-08-21 21:41:49929 strbuf_addch(sb, msg[i]);
930 if (msg[i] == '.')
931 while (msg[i+1] == '.')
932 i++;
Stephen Boyd46d164b2009-03-23 02:14:01933 } else
934 space |= 1;
935 }
936
937 /* trim any trailing '.' or '-' characters */
938 trimlen = 0;
Stephen Boyd871d21d2009-03-31 23:24:38939 while (sb->len - trimlen > start_len &&
940 (sb->buf[sb->len - 1 - trimlen] == '.'
941 || sb->buf[sb->len - 1 - trimlen] == '-'))
Stephen Boyd46d164b2009-03-23 02:14:01942 trimlen++;
943 strbuf_remove(sb, sb->len - trimlen, trimlen);
944}
945
René Scharfecec08712009-01-06 20:41:06946const char *format_subject(struct strbuf *sb, const char *msg,
947 const char *line_separator)
René Scharfe88c44732008-12-27 00:39:35948{
949 int first = 1;
950
951 for (;;) {
952 const char *line = msg;
953 int linelen = get_one_line(line);
954
955 msg += linelen;
Johannes Schindelin77356122016-06-22 20:20:16956 if (!linelen || is_blank_line(line, &linelen))
René Scharfe88c44732008-12-27 00:39:35957 break;
958
René Scharfef53bd742008-12-27 00:49:21959 if (!sb)
960 continue;
René Scharfe88c44732008-12-27 00:39:35961 strbuf_grow(sb, linelen + 2);
962 if (!first)
963 strbuf_addstr(sb, line_separator);
964 strbuf_add(sb, line, linelen);
965 first = 0;
966 }
967 return msg;
968}
969
René Scharfef53bd742008-12-27 00:49:21970static void parse_commit_message(struct format_commit_context *c)
971{
Pat Notz177b29d2010-11-02 19:59:08972 const char *msg = c->message + c->message_off;
973 const char *start = c->message;
René Scharfef53bd742008-12-27 00:49:21974
Johannes Schindelin77356122016-06-22 20:20:16975 msg = skip_blank_lines(msg);
René Scharfef53bd742008-12-27 00:49:21976 c->subject_off = msg - start;
977
978 msg = format_subject(NULL, msg, NULL);
Johannes Schindelin77356122016-06-22 20:20:16979 msg = skip_blank_lines(msg);
René Scharfef53bd742008-12-27 00:49:21980 c->body_off = msg - start;
981
982 c->commit_message_parsed = 1;
983}
984
René Scharfe02edd562009-10-17 21:04:19985static void strbuf_wrap(struct strbuf *sb, size_t pos,
986 size_t width, size_t indent1, size_t indent2)
987{
988 struct strbuf tmp = STRBUF_INIT;
989
990 if (pos)
991 strbuf_add(&tmp, sb->buf, pos);
992 strbuf_add_wrapped_text(&tmp, sb->buf + pos,
Patrick Steinhardt48050c42022-12-01 14:46:49993 cast_size_t_to_int(indent1),
994 cast_size_t_to_int(indent2),
995 cast_size_t_to_int(width));
René Scharfe02edd562009-10-17 21:04:19996 strbuf_swap(&tmp, sb);
997 strbuf_release(&tmp);
998}
999
1000static void rewrap_message_tail(struct strbuf *sb,
1001 struct format_commit_context *c,
1002 size_t new_width, size_t new_indent1,
1003 size_t new_indent2)
1004{
1005 if (c->width == new_width && c->indent1 == new_indent1 &&
1006 c->indent2 == new_indent2)
1007 return;
René Scharfe32ca4242009-11-08 01:04:211008 if (c->wrap_start < sb->len)
René Scharfe02edd562009-10-17 21:04:191009 strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
1010 c->wrap_start = sb->len;
1011 c->width = new_width;
1012 c->indent1 = new_indent1;
1013 c->indent2 = new_indent2;
1014}
1015
Jeff Kingcd1957f2011-12-16 11:40:241016static int format_reflog_person(struct strbuf *sb,
1017 char part,
1018 struct reflog_walk_info *log,
Jeff Kinga5481a62015-06-25 16:55:021019 const struct date_mode *dmode)
Jeff Kingcd1957f2011-12-16 11:40:241020{
1021 const char *ident;
1022
1023 if (!log)
1024 return 2;
1025
1026 ident = get_reflog_ident(log);
1027 if (!ident)
1028 return 2;
1029
1030 return format_person_part(sb, part, ident, strlen(ident), dmode);
1031}
1032
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481033static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
1034 const char *placeholder,
1035 struct format_commit_context *c)
1036{
René Scharfee3f1da92014-10-04 18:54:501037 const char *rest = placeholder;
Jeff King18fb7ff2017-07-13 15:08:461038 const char *basic_color = NULL;
René Scharfee3f1da92014-10-04 18:54:501039
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481040 if (placeholder[1] == '(') {
1041 const char *begin = placeholder + 2;
1042 const char *end = strchr(begin, ')');
1043 char color[COLOR_MAXLEN];
1044
1045 if (!end)
1046 return 0;
Jeff King18fb7ff2017-07-13 15:08:461047
René Scharfee3f1da92014-10-04 18:54:501048 if (skip_prefix(begin, "auto,", &begin)) {
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481049 if (!want_color(c->pretty_ctx->color))
1050 return end - placeholder + 1;
Jeff King18fb7ff2017-07-13 15:08:461051 } else if (skip_prefix(begin, "always,", &begin)) {
1052 /* nothing to do; we do not respect want_color at all */
1053 } else {
1054 /* the default is the same as "auto" */
1055 if (!want_color(c->pretty_ctx->color))
1056 return end - placeholder + 1;
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481057 }
Jeff King18fb7ff2017-07-13 15:08:461058
Jeff Kingf6c5a292014-10-07 19:33:091059 if (color_parse_mem(begin, end - begin, color) < 0)
1060 die(_("unable to parse --pretty format"));
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481061 strbuf_addstr(sb, color);
1062 return end - placeholder + 1;
1063 }
Jeff King18fb7ff2017-07-13 15:08:461064
1065 /*
1066 * We handle things like "%C(red)" above; for historical reasons, there
1067 * are a few colors that can be specified without parentheses (and
1068 * they cannot support things like "auto" or "always" at all).
1069 */
René Scharfee3f1da92014-10-04 18:54:501070 if (skip_prefix(placeholder + 1, "red", &rest))
Jeff King18fb7ff2017-07-13 15:08:461071 basic_color = GIT_COLOR_RED;
René Scharfee3f1da92014-10-04 18:54:501072 else if (skip_prefix(placeholder + 1, "green", &rest))
Jeff King18fb7ff2017-07-13 15:08:461073 basic_color = GIT_COLOR_GREEN;
René Scharfee3f1da92014-10-04 18:54:501074 else if (skip_prefix(placeholder + 1, "blue", &rest))
Jeff King18fb7ff2017-07-13 15:08:461075 basic_color = GIT_COLOR_BLUE;
René Scharfee3f1da92014-10-04 18:54:501076 else if (skip_prefix(placeholder + 1, "reset", &rest))
Jeff King18fb7ff2017-07-13 15:08:461077 basic_color = GIT_COLOR_RESET;
1078
1079 if (basic_color && want_color(c->pretty_ctx->color))
1080 strbuf_addstr(sb, basic_color);
1081
René Scharfee3f1da92014-10-04 18:54:501082 return rest - placeholder;
Nguyễn Thái Ngọc Duyfcabc2d2013-04-18 23:08:481083}
1084
Jeff King9a1180f2019-03-20 08:16:421085static size_t parse_padding_placeholder(const char *placeholder,
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501086 struct format_commit_context *c)
1087{
1088 const char *ch = placeholder;
1089 enum flush_type flush_type;
1090 int to_column = 0;
1091
1092 switch (*ch++) {
1093 case '<':
1094 flush_type = flush_right;
1095 break;
1096 case '>':
1097 if (*ch == '<') {
1098 flush_type = flush_both;
1099 ch++;
Nguyễn Thái Ngọc Duy16406322013-04-18 23:08:521100 } else if (*ch == '>') {
1101 flush_type = flush_left_and_steal;
1102 ch++;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501103 } else
1104 flush_type = flush_left;
1105 break;
1106 default:
1107 return 0;
1108 }
1109
1110 /* the next value means "wide enough to that column" */
1111 if (*ch == '|') {
1112 to_column = 1;
1113 ch++;
1114 }
1115
1116 if (*ch == '(') {
1117 const char *start = ch + 1;
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511118 const char *end = start + strcspn(start, ",)");
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501119 char *next;
1120 int width;
Patrick Steinhardtf6e0b9f2022-12-01 14:46:341121 if (!*end || end == start)
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501122 return 0;
Nguyễn Thái Ngọc Duy066790d2016-06-16 13:18:381123 width = strtol(start, &next, 10);
Patrick Steinhardt304a50a2022-12-01 14:47:231124
1125 /*
1126 * We need to limit the amount of padding, or otherwise this
1127 * would allow the user to pad the buffer by arbitrarily many
1128 * bytes and thus cause resource exhaustion.
1129 */
1130 if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
1131 return 0;
1132
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501133 if (next == start || width == 0)
1134 return 0;
Nguyễn Thái Ngọc Duy066790d2016-06-16 13:18:381135 if (width < 0) {
1136 if (to_column)
1137 width += term_columns();
1138 if (width < 0)
1139 return 0;
1140 }
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501141 c->padding = to_column ? -width : width;
1142 c->flush_type = flush_type;
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511143
1144 if (*end == ',') {
1145 start = end + 1;
1146 end = strchr(start, ')');
1147 if (!end || end == start)
1148 return 0;
Christian Couder59556542013-11-30 20:55:401149 if (starts_with(start, "trunc)"))
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511150 c->truncate = trunc_right;
Christian Couder59556542013-11-30 20:55:401151 else if (starts_with(start, "ltrunc)"))
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511152 c->truncate = trunc_left;
Christian Couder59556542013-11-30 20:55:401153 else if (starts_with(start, "mtrunc)"))
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511154 c->truncate = trunc_middle;
1155 else
1156 return 0;
1157 } else
1158 c->truncate = trunc_none;
1159
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501160 return end - placeholder + 1;
1161 }
1162 return 0;
1163}
1164
Anders Waldenborg4f732e02019-01-29 06:49:001165static int match_placeholder_arg_value(const char *to_parse, const char *candidate,
1166 const char **end, const char **valuestart,
1167 size_t *valuelen)
Taylor Blau84ff0532017-10-01 16:18:471168{
1169 const char *p;
1170
1171 if (!(skip_prefix(to_parse, candidate, &p)))
1172 return 0;
Anders Waldenborg4f732e02019-01-29 06:49:001173 if (valuestart) {
1174 if (*p == '=') {
1175 *valuestart = p + 1;
1176 *valuelen = strcspn(*valuestart, ",)");
1177 p = *valuestart + *valuelen;
1178 } else {
1179 if (*p != ',' && *p != ')')
1180 return 0;
1181 *valuestart = NULL;
1182 *valuelen = 0;
1183 }
1184 }
Taylor Blau84ff0532017-10-01 16:18:471185 if (*p == ',') {
1186 *end = p + 1;
1187 return 1;
1188 }
1189 if (*p == ')') {
1190 *end = p;
1191 return 1;
1192 }
1193 return 0;
1194}
1195
Anders Waldenborg4f732e02019-01-29 06:49:001196static int match_placeholder_bool_arg(const char *to_parse, const char *candidate,
1197 const char **end, int *val)
1198{
1199 const char *argval;
1200 char *strval;
1201 size_t arglen;
1202 int v;
1203
1204 if (!match_placeholder_arg_value(to_parse, candidate, end, &argval, &arglen))
1205 return 0;
1206
1207 if (!argval) {
1208 *val = 1;
1209 return 1;
1210 }
1211
1212 strval = xstrndup(argval, arglen);
1213 v = git_parse_maybe_bool(strval);
1214 free(strval);
1215
1216 if (v == -1)
1217 return 0;
1218
1219 *val = v;
1220
1221 return 1;
1222}
1223
Anders Waldenborg250bea02019-01-28 21:33:341224static int format_trailer_match_cb(const struct strbuf *key, void *ud)
1225{
1226 const struct string_list *list = ud;
1227 const struct string_list_item *item;
1228
1229 for_each_string_list_item (item, list) {
1230 if (key->len == (uintptr_t)item->util &&
1231 !strncasecmp(item->string, key->buf, key->len))
1232 return 1;
1233 }
1234 return 0;
1235}
1236
Hariom Verma90563ae2021-02-13 01:52:411237int format_set_trailers_options(struct process_trailer_options *opts,
1238 struct string_list *filter_list,
1239 struct strbuf *sepbuf,
1240 struct strbuf *kvsepbuf,
Hariom Verma636a0ae2021-02-13 01:52:421241 const char **arg,
1242 char **invalid_arg)
Hariom Verma90563ae2021-02-13 01:52:411243{
1244 for (;;) {
1245 const char *argval;
1246 size_t arglen;
1247
Hariom Verma636a0ae2021-02-13 01:52:421248 if (**arg == ')')
1249 break;
1250
Hariom Verma90563ae2021-02-13 01:52:411251 if (match_placeholder_arg_value(*arg, "key", arg, &argval, &arglen)) {
1252 uintptr_t len = arglen;
1253
1254 if (!argval)
1255 return -1;
1256
1257 if (len && argval[len - 1] == ':')
1258 len--;
1259 string_list_append(filter_list, argval)->util = (char *)len;
1260
1261 opts->filter = format_trailer_match_cb;
1262 opts->filter_data = filter_list;
1263 opts->only_trailers = 1;
1264 } else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
1265 char *fmt;
1266
1267 strbuf_reset(sepbuf);
1268 fmt = xstrndup(argval, arglen);
1269 strbuf_expand(sepbuf, fmt, strbuf_expand_literal_cb, NULL);
1270 free(fmt);
1271 opts->separator = sepbuf;
1272 } else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
1273 char *fmt;
1274
1275 strbuf_reset(kvsepbuf);
1276 fmt = xstrndup(argval, arglen);
1277 strbuf_expand(kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
1278 free(fmt);
1279 opts->key_value_separator = kvsepbuf;
1280 } else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
1281 !match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
1282 !match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
Hariom Verma636a0ae2021-02-13 01:52:421283 !match_placeholder_bool_arg(*arg, "valueonly", arg, &opts->value_only)) {
1284 if (invalid_arg) {
1285 size_t len = strcspn(*arg, ",)");
1286 *invalid_arg = xstrndup(*arg, len);
1287 }
1288 return -1;
1289 }
Hariom Verma90563ae2021-02-13 01:52:411290 }
1291 return 0;
1292}
1293
René Scharfeb0815472021-02-14 10:10:571294static size_t parse_describe_args(const char *start, struct strvec *args)
1295{
Eli Schwartz3c6eb4e2021-10-31 17:15:081296 struct {
1297 char *name;
1298 enum {
Eli Schwartz1d517ce2021-10-31 17:15:091299 DESCRIBE_ARG_BOOL,
Eli Schwartzeccd97d2021-10-31 17:15:101300 DESCRIBE_ARG_INTEGER,
Eli Schwartz3c6eb4e2021-10-31 17:15:081301 DESCRIBE_ARG_STRING,
1302 } type;
1303 } option[] = {
Eli Schwartz1d517ce2021-10-31 17:15:091304 { "tags", DESCRIBE_ARG_BOOL},
Eli Schwartzeccd97d2021-10-31 17:15:101305 { "abbrev", DESCRIBE_ARG_INTEGER },
Eli Schwartz3c6eb4e2021-10-31 17:15:081306 { "exclude", DESCRIBE_ARG_STRING },
1307 { "match", DESCRIBE_ARG_STRING },
1308 };
René Scharfeb0815472021-02-14 10:10:571309 const char *arg = start;
1310
1311 for (;;) {
Eli Schwartz3c6eb4e2021-10-31 17:15:081312 int found = 0;
René Scharfeb0815472021-02-14 10:10:571313 const char *argval;
1314 size_t arglen = 0;
Eli Schwartz1d517ce2021-10-31 17:15:091315 int optval = 0;
René Scharfeb0815472021-02-14 10:10:571316 int i;
1317
Eli Schwartz3c6eb4e2021-10-31 17:15:081318 for (i = 0; !found && i < ARRAY_SIZE(option); i++) {
1319 switch (option[i].type) {
Eli Schwartz1d517ce2021-10-31 17:15:091320 case DESCRIBE_ARG_BOOL:
1321 if (match_placeholder_bool_arg(arg, option[i].name, &arg, &optval)) {
1322 if (optval)
1323 strvec_pushf(args, "--%s", option[i].name);
1324 else
1325 strvec_pushf(args, "--no-%s", option[i].name);
1326 found = 1;
1327 }
1328 break;
Eli Schwartzeccd97d2021-10-31 17:15:101329 case DESCRIBE_ARG_INTEGER:
1330 if (match_placeholder_arg_value(arg, option[i].name, &arg,
1331 &argval, &arglen)) {
1332 char *endptr;
1333 if (!arglen)
1334 return 0;
1335 strtol(argval, &endptr, 10);
1336 if (endptr - argval != arglen)
1337 return 0;
1338 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval);
1339 found = 1;
1340 }
1341 break;
Eli Schwartz3c6eb4e2021-10-31 17:15:081342 case DESCRIBE_ARG_STRING:
1343 if (match_placeholder_arg_value(arg, option[i].name, &arg,
1344 &argval, &arglen)) {
1345 if (!arglen)
1346 return 0;
1347 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval);
1348 found = 1;
1349 }
René Scharfeb0815472021-02-14 10:10:571350 break;
1351 }
1352 }
Eli Schwartz3c6eb4e2021-10-31 17:15:081353 if (!found)
René Scharfeb0815472021-02-14 10:10:571354 break;
1355
René Scharfeb0815472021-02-14 10:10:571356 }
1357 return arg - start;
1358}
1359
Nguyễn Thái Ngọc Duy7e77df32013-04-18 23:08:471360static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
1361 const char *placeholder,
Junio C Hamano9fa708d2009-10-05 06:43:321362 void *context)
Johannes Schindelin93fc05e2007-11-04 19:15:061363{
René Scharfef29d5952007-11-10 11:14:201364 struct format_commit_context *c = context;
1365 const struct commit *commit = c->commit;
Pat Notz177b29d2010-11-02 19:59:081366 const char *msg = c->message;
René Scharfef29d5952007-11-10 11:14:201367 struct commit_list *p;
Hariom Verma47d46762020-08-21 21:41:491368 const char *arg, *eol;
Anders Waldenborgfd2015b2019-01-28 21:33:361369 size_t res;
Issac Trottsad6f0282019-01-11 06:30:461370 char **slot;
Johannes Schindelin93fc05e2007-11-04 19:15:061371
Johannes Schindelin93fc05e2007-11-04 19:15:061372 /* these are independent of the commit */
Anders Waldenborgfd2015b2019-01-28 21:33:361373 res = strbuf_expand_literal_cb(sb, placeholder, NULL);
1374 if (res)
1375 return res;
1376
René Scharfecde75e52007-11-09 00:49:421377 switch (placeholder[0]) {
1378 case 'C':
Christian Couder59556542013-11-30 20:55:401379 if (starts_with(placeholder + 1, "(auto)")) {
Edward Thomsonb15a3e02016-05-27 03:46:101380 c->auto_color = want_color(c->pretty_ctx->color);
René Scharfe82b83da2016-09-29 18:13:051381 if (c->auto_color && sb->len)
René Scharfec99ad272016-09-17 18:25:241382 strbuf_addstr(sb, GIT_COLOR_RESET);
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491383 return 7; /* consumed 7 bytes, "C(auto)" */
1384 } else {
1385 int ret = parse_color(sb, placeholder, c);
1386 if (ret)
1387 c->auto_color = 0;
1388 /*
1389 * Otherwise, we decided to treat %C<unknown>
1390 * as a literal string, and the previous
1391 * %C(auto) is still valid.
1392 */
1393 return ret;
Jeff Kingc0029222009-01-17 15:38:461394 }
René Scharfe02edd562009-10-17 21:04:191395 case 'w':
1396 if (placeholder[1] == '(') {
1397 unsigned long width = 0, indent1 = 0, indent2 = 0;
1398 char *next;
1399 const char *start = placeholder + 2;
1400 const char *end = strchr(start, ')');
1401 if (!end)
1402 return 0;
1403 if (end > start) {
1404 width = strtoul(start, &next, 10);
1405 if (*next == ',') {
1406 indent1 = strtoul(next + 1, &next, 10);
1407 if (*next == ',') {
1408 indent2 = strtoul(next + 1,
1409 &next, 10);
1410 }
1411 }
1412 if (*next != ')')
1413 return 0;
1414 }
Patrick Steinhardt304a50a2022-12-01 14:47:231415
1416 /*
1417 * We need to limit the format here as it allows the
1418 * user to prepend arbitrarily many bytes to the buffer
1419 * when rewrapping.
1420 */
1421 if (width > FORMATTING_LIMIT ||
1422 indent1 > FORMATTING_LIMIT ||
1423 indent2 > FORMATTING_LIMIT)
1424 return 0;
René Scharfe02edd562009-10-17 21:04:191425 rewrap_message_tail(sb, c, width, indent1, indent2);
1426 return end - placeholder + 1;
1427 } else
1428 return 0;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501429
1430 case '<':
1431 case '>':
Jeff King9a1180f2019-03-20 08:16:421432 return parse_padding_placeholder(placeholder, c);
René Scharfecde75e52007-11-09 00:49:421433 }
Johannes Schindelin93fc05e2007-11-04 19:15:061434
René Scharfeb0815472021-02-14 10:10:571435 if (skip_prefix(placeholder, "(describe", &arg)) {
René Scharfe15ae82d2021-02-14 10:04:341436 struct child_process cmd = CHILD_PROCESS_INIT;
1437 struct strbuf out = STRBUF_INIT;
1438 struct strbuf err = STRBUF_INIT;
René Scharfe96099722021-02-28 11:22:471439 struct pretty_print_describe_status *describe_status;
1440
1441 describe_status = c->pretty_ctx->describe_status;
1442 if (describe_status) {
1443 if (!describe_status->max_invocations)
1444 return 0;
1445 describe_status->max_invocations--;
1446 }
René Scharfe15ae82d2021-02-14 10:04:341447
1448 cmd.git_cmd = 1;
1449 strvec_push(&cmd.args, "describe");
René Scharfeb0815472021-02-14 10:10:571450
1451 if (*arg == ':') {
1452 arg++;
1453 arg += parse_describe_args(arg, &cmd.args);
1454 }
1455
1456 if (*arg != ')') {
1457 child_process_clear(&cmd);
1458 return 0;
1459 }
1460
René Scharfe15ae82d2021-02-14 10:04:341461 strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
1462 pipe_command(&cmd, NULL, 0, &out, 0, &err, 0);
1463 strbuf_rtrim(&out);
1464 strbuf_addbuf(sb, &out);
1465 strbuf_release(&out);
1466 strbuf_release(&err);
René Scharfeb0815472021-02-14 10:10:571467 return arg - placeholder + 1;
René Scharfe15ae82d2021-02-14 10:04:341468 }
1469
Johannes Schindelin93fc05e2007-11-04 19:15:061470 /* these depend on the commit */
1471 if (!commit->object.parsed)
Stefan Beller109cd762018-06-29 01:21:511472 parse_object(the_repository, &commit->object.oid);
Johannes Schindelin93fc05e2007-11-04 19:15:061473
René Scharfecde75e52007-11-09 00:49:421474 switch (placeholder[0]) {
1475 case 'H': /* commit hash */
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491476 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
brian m. carlsonf2fd0762015-11-10 02:22:281477 strbuf_addstr(sb, oid_to_hex(&commit->object.oid));
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491478 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
Marco Costalbac3a670d2008-02-09 14:40:191479 return 1;
René Scharfecde75e52007-11-09 00:49:421480 case 'h': /* abbreviated commit hash */
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491481 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
brian m. carlson30e677e2018-03-12 02:27:281482 strbuf_add_unique_abbrev(sb, &commit->object.oid,
René Scharfe1eb47f12016-08-06 15:41:011483 c->pretty_ctx->abbrev);
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491484 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
Marco Costalbac3a670d2008-02-09 14:40:191485 return 1;
René Scharfecde75e52007-11-09 00:49:421486 case 'T': /* tree hash */
Derrick Stolee2e27bd72018-04-06 19:09:381487 strbuf_addstr(sb, oid_to_hex(get_commit_tree_oid(commit)));
Marco Costalbac3a670d2008-02-09 14:40:191488 return 1;
René Scharfecde75e52007-11-09 00:49:421489 case 't': /* abbreviated tree hash */
Derrick Stolee2e27bd72018-04-06 19:09:381490 strbuf_add_unique_abbrev(sb,
Junio C Hamanoc89b6e12018-05-23 05:38:131491 get_commit_tree_oid(commit),
René Scharfe1eb47f12016-08-06 15:41:011492 c->pretty_ctx->abbrev);
Marco Costalbac3a670d2008-02-09 14:40:191493 return 1;
René Scharfecde75e52007-11-09 00:49:421494 case 'P': /* parent hashes */
1495 for (p = commit->parents; p; p = p->next) {
1496 if (p != commit->parents)
1497 strbuf_addch(sb, ' ');
brian m. carlsonf2fd0762015-11-10 02:22:281498 strbuf_addstr(sb, oid_to_hex(&p->item->object.oid));
René Scharfecde75e52007-11-09 00:49:421499 }
Marco Costalbac3a670d2008-02-09 14:40:191500 return 1;
René Scharfecde75e52007-11-09 00:49:421501 case 'p': /* abbreviated parent hashes */
René Scharfecde75e52007-11-09 00:49:421502 for (p = commit->parents; p; p = p->next) {
1503 if (p != commit->parents)
1504 strbuf_addch(sb, ' ');
brian m. carlson30e677e2018-03-12 02:27:281505 strbuf_add_unique_abbrev(sb, &p->item->object.oid,
René Scharfe1eb47f12016-08-06 15:41:011506 c->pretty_ctx->abbrev);
René Scharfecde75e52007-11-09 00:49:421507 }
Marco Costalbac3a670d2008-02-09 14:40:191508 return 1;
René Scharfecde75e52007-11-09 00:49:421509 case 'm': /* left/right/bottom */
Michael J Gruber1df2d652011-03-07 12:31:391510 strbuf_addstr(sb, get_revision_mark(NULL, commit));
Marco Costalbac3a670d2008-02-09 14:40:191511 return 1;
René Scharfe3b3d4432008-09-04 21:40:031512 case 'd':
Nguyễn Thái Ngọc Duya95f0672013-04-18 23:08:491513 format_decorations(sb, commit, c->auto_color);
René Scharfe3b3d4432008-09-04 21:40:031514 return 1;
Harry Jeffery92710952014-09-18 20:53:531515 case 'D':
Harry Jeffery92710952014-09-18 20:53:531516 format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
1517 return 1;
Issac Trottsad6f0282019-01-11 06:30:461518 case 'S': /* tag/branch like --source */
1519 if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
1520 return 0;
1521 slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
1522 if (!(slot && *slot))
1523 return 0;
1524 strbuf_addstr(sb, *slot);
1525 return 1;
Thomas Rast8f8f5472009-10-19 15:48:101526 case 'g': /* reflog info */
1527 switch(placeholder[1]) {
1528 case 'd': /* reflog selector */
1529 case 'D':
1530 if (c->pretty_ctx->reflog_info)
1531 get_reflog_selector(sb,
1532 c->pretty_ctx->reflog_info,
Jeff Kinga5481a62015-06-25 16:55:021533 &c->pretty_ctx->date_mode,
Junio C Hamano55ccf852012-05-07 21:11:321534 c->pretty_ctx->date_mode_explicit,
Thomas Rast8f8f5472009-10-19 15:48:101535 (placeholder[1] == 'd'));
1536 return 2;
1537 case 's': /* reflog message */
1538 if (c->pretty_ctx->reflog_info)
1539 get_reflog_message(sb, c->pretty_ctx->reflog_info);
1540 return 2;
Jeff Kingcd1957f2011-12-16 11:40:241541 case 'n':
1542 case 'N':
1543 case 'e':
1544 case 'E':
1545 return format_reflog_person(sb,
1546 placeholder[1],
1547 c->pretty_ctx->reflog_info,
Jeff Kinga5481a62015-06-25 16:55:021548 &c->pretty_ctx->date_mode);
Thomas Rast8f8f5472009-10-19 15:48:101549 }
1550 return 0; /* unknown %g placeholder */
Johannes Schindelin8b208f02009-10-09 10:22:051551 case 'N':
Junio C Hamanoddf333f2012-10-18 01:51:471552 if (c->pretty_ctx->notes_message) {
1553 strbuf_addstr(sb, c->pretty_ctx->notes_message);
Johannes Gilger5b163602010-04-13 20:31:121554 return 1;
1555 }
1556 return 0;
René Scharfecde75e52007-11-09 00:49:421557 }
Johannes Schindelin93fc05e2007-11-04 19:15:061558
Junio C Hamanof6667c52011-10-22 04:06:021559 if (placeholder[0] == 'G') {
Sebastian Götteffb6d7d2013-03-31 16:00:141560 if (!c->signature_check.result)
1561 check_commit_signature(c->commit, &(c->signature_check));
Junio C Hamanof6667c52011-10-22 04:06:021562 switch (placeholder[1]) {
1563 case 'G':
Fabian Stelzerb5726a52021-09-10 20:07:341564 if (c->signature_check.output)
1565 strbuf_addstr(sb, c->signature_check.output);
Junio C Hamanof6667c52011-10-22 04:06:021566 break;
1567 case '?':
Sebastian Götteffb6d7d2013-03-31 16:00:141568 switch (c->signature_check.result) {
Junio C Hamanof6667c52011-10-22 04:06:021569 case 'G':
Hans Jerry Illikainen54887b42019-12-27 13:55:571570 switch (c->signature_check.trust_level) {
1571 case TRUST_UNDEFINED:
1572 case TRUST_NEVER:
1573 strbuf_addch(sb, 'U');
1574 break;
1575 default:
1576 strbuf_addch(sb, 'G');
1577 break;
1578 }
1579 break;
Junio C Hamanof6667c52011-10-22 04:06:021580 case 'B':
Michael J Gruber661a1802016-10-12 13:04:151581 case 'E':
Sebastian Göttee290c4b2013-03-31 16:03:221582 case 'N':
Michael J Gruber661a1802016-10-12 13:04:151583 case 'X':
1584 case 'Y':
1585 case 'R':
Sebastian Götteffb6d7d2013-03-31 16:00:141586 strbuf_addch(sb, c->signature_check.result);
Junio C Hamanof6667c52011-10-22 04:06:021587 }
1588 break;
1589 case 'S':
Sebastian Götteffb6d7d2013-03-31 16:00:141590 if (c->signature_check.signer)
1591 strbuf_addstr(sb, c->signature_check.signer);
Junio C Hamanof6667c52011-10-22 04:06:021592 break;
Michael J Gruber0174eea2013-02-14 16:04:461593 case 'K':
Sebastian Götteffb6d7d2013-03-31 16:00:141594 if (c->signature_check.key)
1595 strbuf_addstr(sb, c->signature_check.key);
Michael J Gruber0174eea2013-02-14 16:04:461596 break;
Michał Górny3daaaab2018-10-22 16:38:201597 case 'F':
1598 if (c->signature_check.fingerprint)
1599 strbuf_addstr(sb, c->signature_check.fingerprint);
1600 break;
Michał Górny4de93942018-10-22 16:38:211601 case 'P':
1602 if (c->signature_check.primary_key_fingerprint)
1603 strbuf_addstr(sb, c->signature_check.primary_key_fingerprint);
1604 break;
Hans Jerry Illikainen54887b42019-12-27 13:55:571605 case 'T':
1606 switch (c->signature_check.trust_level) {
1607 case TRUST_UNDEFINED:
1608 strbuf_addstr(sb, "undefined");
1609 break;
1610 case TRUST_NEVER:
1611 strbuf_addstr(sb, "never");
1612 break;
1613 case TRUST_MARGINAL:
1614 strbuf_addstr(sb, "marginal");
1615 break;
1616 case TRUST_FULLY:
1617 strbuf_addstr(sb, "fully");
1618 break;
1619 case TRUST_ULTIMATE:
1620 strbuf_addstr(sb, "ultimate");
1621 break;
1622 }
1623 break;
Jeff Kingaa4b78d2014-06-17 00:07:071624 default:
1625 return 0;
Junio C Hamanof6667c52011-10-22 04:06:021626 }
1627 return 2;
1628 }
1629
René Scharfecde75e52007-11-09 00:49:421630 /* For the rest we have to parse the commit header. */
Jeff King018b9de2021-01-28 19:57:391631 if (!c->commit_header_parsed) {
1632 msg = c->message =
1633 repo_logmsg_reencode(c->repository, commit,
1634 &c->commit_encoding, "UTF-8");
René Scharfef29d5952007-11-10 11:14:201635 parse_commit_header(c);
Jeff King018b9de2021-01-28 19:57:391636 }
Johannes Schindelin93fc05e2007-11-04 19:15:061637
René Scharfef29d5952007-11-10 11:14:201638 switch (placeholder[0]) {
Marco Costalbac3a670d2008-02-09 14:40:191639 case 'a': /* author ... */
1640 return format_person_part(sb, placeholder[1],
Jeff Kingd36f8672008-08-29 00:54:591641 msg + c->author.off, c->author.len,
Jeff Kinga5481a62015-06-25 16:55:021642 &c->pretty_ctx->date_mode);
Marco Costalbac3a670d2008-02-09 14:40:191643 case 'c': /* committer ... */
1644 return format_person_part(sb, placeholder[1],
Jeff Kingd36f8672008-08-29 00:54:591645 msg + c->committer.off, c->committer.len,
Jeff Kinga5481a62015-06-25 16:55:021646 &c->pretty_ctx->date_mode);
Marco Costalbac3a670d2008-02-09 14:40:191647 case 'e': /* encoding */
Nguyễn Thái Ngọc Duy0940a762013-04-18 23:08:411648 if (c->commit_encoding)
1649 strbuf_addstr(sb, c->commit_encoding);
Marco Costalbac3a670d2008-02-09 14:40:191650 return 1;
Eli Barzilay1367b122010-03-25 02:51:521651 case 'B': /* raw body */
1652 /* message_off is always left at the initial newline */
1653 strbuf_addstr(sb, msg + c->message_off + 1);
1654 return 1;
René Scharfef53bd742008-12-27 00:49:211655 }
1656
1657 /* Now we need to parse the commit message. */
1658 if (!c->commit_message_parsed)
1659 parse_commit_message(c);
1660
1661 switch (placeholder[0]) {
1662 case 's': /* subject */
1663 format_subject(sb, msg + c->subject_off, " ");
1664 return 1;
Stephen Boyd46d164b2009-03-23 02:14:011665 case 'f': /* sanitized subject */
Hariom Verma47d46762020-08-21 21:41:491666 eol = strchrnul(msg + c->subject_off, '\n');
1667 format_sanitized_subject(sb, msg + c->subject_off, eol - (msg + c->subject_off));
Stephen Boyd46d164b2009-03-23 02:14:011668 return 1;
Marco Costalbac3a670d2008-02-09 14:40:191669 case 'b': /* body */
René Scharfef29d5952007-11-10 11:14:201670 strbuf_addstr(sb, msg + c->body_off);
Marco Costalbac3a670d2008-02-09 14:40:191671 return 1;
Johannes Schindelin93fc05e2007-11-04 19:15:061672 }
Jacob Kellerd9f31fb2016-11-19 00:58:141673
Jeff King58311c62017-08-15 10:25:271674 if (skip_prefix(placeholder, "(trailers", &arg)) {
Jeff Kinga388b102017-08-15 10:23:561675 struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
Anders Waldenborg250bea02019-01-28 21:33:341676 struct string_list filter_list = STRING_LIST_INIT_NODUP;
Anders Waldenborg0b691d82019-01-28 21:33:371677 struct strbuf sepbuf = STRBUF_INIT;
Ævar Arnfjörð Bjarmason058761f2020-12-09 15:52:081678 struct strbuf kvsepbuf = STRBUF_INIT;
Anders Waldenborg3e3f3472019-01-28 21:33:331679 size_t ret = 0;
Jeff Kinge5fba5d2018-08-23 00:50:171680
1681 opts.no_divider = 1;
1682
Taylor Blau84ff0532017-10-01 16:18:471683 if (*arg == ':') {
1684 arg++;
Hariom Verma636a0ae2021-02-13 01:52:421685 if (format_set_trailers_options(&opts, &filter_list, &sepbuf, &kvsepbuf, &arg, NULL))
Hariom Verma90563ae2021-02-13 01:52:411686 goto trailer_out;
Jeff King58311c62017-08-15 10:25:271687 }
1688 if (*arg == ')') {
1689 format_trailers_from_commit(sb, msg + c->subject_off, &opts);
Anders Waldenborg3e3f3472019-01-28 21:33:331690 ret = arg - placeholder + 1;
Jeff King58311c62017-08-15 10:25:271691 }
Anders Waldenborg250bea02019-01-28 21:33:341692 trailer_out:
1693 string_list_clear(&filter_list, 0);
Anders Waldenborg0b691d82019-01-28 21:33:371694 strbuf_release(&sepbuf);
Anders Waldenborg3e3f3472019-01-28 21:33:331695 return ret;
Jacob Kellerd9f31fb2016-11-19 00:58:141696 }
1697
Marco Costalbac3a670d2008-02-09 14:40:191698 return 0; /* unknown placeholder */
René Scharfecde75e52007-11-09 00:49:421699}
Johannes Schindelin93fc05e2007-11-04 19:15:061700
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501701static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
1702 const char *placeholder,
1703 struct format_commit_context *c)
1704{
1705 struct strbuf local_sb = STRBUF_INIT;
Patrick Steinhardt81dc8982022-12-01 14:46:251706 size_t total_consumed = 0;
1707 int len, padding = c->padding;
1708
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501709 if (padding < 0) {
1710 const char *start = strrchr(sb->buf, '\n');
1711 int occupied;
1712 if (!start)
1713 start = sb->buf;
Patrick Steinhardt522cc872022-12-01 14:46:531714 occupied = utf8_strnwidth(start, strlen(start), 1);
Josef Kufner3ad87c82016-06-16 13:18:371715 occupied += c->pretty_ctx->graph_width;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501716 padding = (-padding) - occupied;
1717 }
1718 while (1) {
1719 int modifier = *placeholder == 'C';
Patrick Steinhardt81dc8982022-12-01 14:46:251720 size_t consumed = format_commit_one(&local_sb, placeholder, c);
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501721 total_consumed += consumed;
1722
1723 if (!modifier)
1724 break;
1725
1726 placeholder += consumed;
1727 if (*placeholder != '%')
1728 break;
1729 placeholder++;
1730 total_consumed++;
1731 }
Patrick Steinhardt522cc872022-12-01 14:46:531732 len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
Nguyễn Thái Ngọc Duy16406322013-04-18 23:08:521733
1734 if (c->flush_type == flush_left_and_steal) {
1735 const char *ch = sb->buf + sb->len - 1;
1736 while (len > padding && ch > sb->buf) {
1737 const char *p;
1738 if (*ch == ' ') {
1739 ch--;
1740 padding++;
1741 continue;
1742 }
1743 /* check for trailing ansi sequences */
1744 if (*ch != 'm')
1745 break;
1746 p = ch - 1;
Patrick Steinhardtb49f3092022-12-01 14:46:301747 while (p > sb->buf && ch - p < 10 && *p != '\033')
Nguyễn Thái Ngọc Duy16406322013-04-18 23:08:521748 p--;
1749 if (*p != '\033' ||
1750 ch + 1 - p != display_mode_esc_sequence_len(p))
1751 break;
1752 /*
1753 * got a good ansi sequence, put it back to
1754 * local_sb as we're cutting sb
1755 */
1756 strbuf_insert(&local_sb, 0, p, ch + 1 - p);
1757 ch = p - 1;
1758 }
1759 strbuf_setlen(sb, ch + 1 - sb->buf);
1760 c->flush_type = flush_left;
1761 }
1762
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511763 if (len > padding) {
1764 switch (c->truncate) {
1765 case trunc_left:
1766 strbuf_utf8_replace(&local_sb,
1767 0, len - (padding - 2),
1768 "..");
1769 break;
1770 case trunc_middle:
1771 strbuf_utf8_replace(&local_sb,
1772 padding / 2 - 1,
1773 len - (padding - 2),
1774 "..");
1775 break;
1776 case trunc_right:
1777 strbuf_utf8_replace(&local_sb,
1778 padding - 2, len - (padding - 2),
1779 "..");
1780 break;
1781 case trunc_none:
1782 break;
1783 }
René Scharfee992d1e2014-07-10 08:52:211784 strbuf_addbuf(sb, &local_sb);
Nguyễn Thái Ngọc Duya7f01c62013-04-18 23:08:511785 } else {
Patrick Steinhardt81dc8982022-12-01 14:46:251786 size_t sb_len = sb->len, offset = 0;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501787 if (c->flush_type == flush_left)
1788 offset = padding - len;
1789 else if (c->flush_type == flush_both)
1790 offset = (padding - len) / 2;
1791 /*
1792 * we calculate padding in columns, now
1793 * convert it back to chars
1794 */
1795 padding = padding - len + local_sb.len;
René Scharfe415792e2014-09-07 07:06:421796 strbuf_addchars(sb, ' ', padding);
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501797 memcpy(sb->buf + sb_len + offset, local_sb.buf,
1798 local_sb.len);
1799 }
1800 strbuf_release(&local_sb);
1801 c->flush_type = no_flush;
1802 return total_consumed;
1803}
1804
Nguyễn Thái Ngọc Duy7e77df32013-04-18 23:08:471805static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
1806 const char *placeholder,
Junio C Hamano9fa708d2009-10-05 06:43:321807 void *context)
1808{
Patrick Steinhardt81dc8982022-12-01 14:46:251809 size_t consumed, orig_len;
Junio C Hamano9fa708d2009-10-05 06:43:321810 enum {
1811 NO_MAGIC,
1812 ADD_LF_BEFORE_NON_EMPTY,
1813 DEL_LF_BEFORE_EMPTY,
Junio C Hamano223a9232010-06-22 16:45:221814 ADD_SP_BEFORE_NON_EMPTY
Junio C Hamano9fa708d2009-10-05 06:43:321815 } magic = NO_MAGIC;
1816
1817 switch (placeholder[0]) {
1818 case '-':
1819 magic = DEL_LF_BEFORE_EMPTY;
1820 break;
1821 case '+':
1822 magic = ADD_LF_BEFORE_NON_EMPTY;
1823 break;
Michael J Gruber7b881762010-06-14 16:12:291824 case ' ':
1825 magic = ADD_SP_BEFORE_NON_EMPTY;
1826 break;
Junio C Hamano9fa708d2009-10-05 06:43:321827 default:
1828 break;
1829 }
Patrick Steinhardt1de69c02022-12-01 14:46:391830 if (magic != NO_MAGIC) {
Junio C Hamano9fa708d2009-10-05 06:43:321831 placeholder++;
1832
Patrick Steinhardt1de69c02022-12-01 14:46:391833 switch (placeholder[0]) {
1834 case 'w':
1835 /*
1836 * `%+w()` cannot ever expand to a non-empty string,
1837 * and it potentially changes the layout of preceding
1838 * contents. We're thus not able to handle the magic in
1839 * this combination and refuse the pattern.
1840 */
1841 return 0;
1842 };
1843 }
1844
Junio C Hamano9fa708d2009-10-05 06:43:321845 orig_len = sb->len;
Nguyễn Thái Ngọc Duya5752342013-04-18 23:08:501846 if (((struct format_commit_context *)context)->flush_type != no_flush)
1847 consumed = format_and_pad_commit(sb, placeholder, context);
1848 else
1849 consumed = format_commit_one(sb, placeholder, context);
Junio C Hamano9fa708d2009-10-05 06:43:321850 if (magic == NO_MAGIC)
1851 return consumed;
1852
1853 if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
1854 while (sb->len && sb->buf[sb->len - 1] == '\n')
1855 strbuf_setlen(sb, sb->len - 1);
Michael J Gruber7b881762010-06-14 16:12:291856 } else if (orig_len != sb->len) {
1857 if (magic == ADD_LF_BEFORE_NON_EMPTY)
René Scharfea91cc7f2020-02-09 13:44:231858 strbuf_insertstr(sb, orig_len, "\n");
Michael J Gruber7b881762010-06-14 16:12:291859 else if (magic == ADD_SP_BEFORE_NON_EMPTY)
René Scharfea91cc7f2020-02-09 13:44:231860 strbuf_insertstr(sb, orig_len, " ");
Junio C Hamano9fa708d2009-10-05 06:43:321861 }
1862 return consumed + 1;
1863}
1864
Johannes Gilger5b163602010-04-13 20:31:121865static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
1866 void *context)
1867{
1868 struct userformat_want *w = context;
1869
Michael J Gruber7b881762010-06-14 16:12:291870 if (*placeholder == '+' || *placeholder == '-' || *placeholder == ' ')
Johannes Gilger5b163602010-04-13 20:31:121871 placeholder++;
1872
1873 switch (*placeholder) {
1874 case 'N':
1875 w->notes = 1;
1876 break;
Issac Trottsad6f0282019-01-11 06:30:461877 case 'S':
1878 w->source = 1;
1879 break;
Jeff Kingb2086b52021-06-22 16:04:501880 case 'd':
1881 case 'D':
1882 w->decorate = 1;
1883 break;
Johannes Gilger5b163602010-04-13 20:31:121884 }
1885 return 0;
1886}
1887
1888void userformat_find_requirements(const char *fmt, struct userformat_want *w)
1889{
1890 struct strbuf dummy = STRBUF_INIT;
1891
1892 if (!fmt) {
1893 if (!user_format)
1894 return;
1895 fmt = user_format;
1896 }
Junio C Hamanoa6253d12011-05-25 19:23:441897 strbuf_expand(&dummy, fmt, userformat_want_item, w);
Johannes Gilger5b163602010-04-13 20:31:121898 strbuf_release(&dummy);
1899}
1900
Stefan Bellerf54fbf52018-11-14 00:13:001901void repo_format_commit_message(struct repository *r,
1902 const struct commit *commit,
1903 const char *format, struct strbuf *sb,
1904 const struct pretty_print_context *pretty_ctx)
René Scharfecde75e52007-11-09 00:49:421905{
Denton Liu3e8ed3b2019-11-20 00:51:161906 struct format_commit_context context = {
Jeff King018b9de2021-01-28 19:57:391907 .repository = r,
Denton Liu3e8ed3b2019-11-20 00:51:161908 .commit = commit,
1909 .pretty_ctx = pretty_ctx,
1910 .wrap_start = sb->len
1911 };
Pat Notz177b29d2010-11-02 19:59:081912 const char *output_enc = pretty_ctx->output_encoding;
Nguyễn Thái Ngọc Duy7e77df32013-04-18 23:08:471913 const char *utf8 = "UTF-8";
René Scharfef29d5952007-11-10 11:14:201914
Marco Costalbac3a670d2008-02-09 14:40:191915 strbuf_expand(sb, format, format_commit_item, &context);
René Scharfe02edd562009-10-17 21:04:191916 rewrap_message_tail(sb, &context, 0, 0, 0);
Pat Notz177b29d2010-11-02 19:59:081917
Jeff King018b9de2021-01-28 19:57:391918 /*
1919 * Convert output to an actual output encoding; note that
1920 * format_commit_item() will always use UTF-8, so we don't
1921 * have to bother if that's what the output wants.
1922 */
Nguyễn Thái Ngọc Duy7e77df32013-04-18 23:08:471923 if (output_enc) {
1924 if (same_encoding(utf8, output_enc))
1925 output_enc = NULL;
1926 } else {
1927 if (context.commit_encoding &&
1928 !same_encoding(context.commit_encoding, utf8))
1929 output_enc = context.commit_encoding;
1930 }
1931
1932 if (output_enc) {
Jeff Kingc7d017d2018-07-24 10:50:331933 size_t outsz;
Nguyễn Thái Ngọc Duy7e77df32013-04-18 23:08:471934 char *out = reencode_string_len(sb->buf, sb->len,
1935 output_enc, utf8, &outsz);
1936 if (out)
1937 strbuf_attach(sb, out, outsz, outsz + 1);
1938 }
1939
Nguyễn Thái Ngọc Duy0940a762013-04-18 23:08:411940 free(context.commit_encoding);
Stefan Bellerf54fbf52018-11-14 00:13:001941 repo_unuse_commit_buffer(r, commit, context.message);
Johannes Schindelin93fc05e2007-11-04 19:15:061942}
1943
Jeff King10f2fbf2013-07-03 07:07:481944static void pp_header(struct pretty_print_context *pp,
Johannes Schindelin93fc05e2007-11-04 19:15:061945 const char *encoding,
1946 const struct commit *commit,
1947 const char **msg_p,
1948 struct strbuf *sb)
1949{
1950 int parents_shown = 0;
1951
1952 for (;;) {
René Scharfee3f1da92014-10-04 18:54:501953 const char *name, *line = *msg_p;
Johannes Schindelin93fc05e2007-11-04 19:15:061954 int linelen = get_one_line(*msg_p);
1955
1956 if (!linelen)
1957 return;
1958 *msg_p += linelen;
1959
1960 if (linelen == 1)
1961 /* End of header */
1962 return;
1963
Jeff King6bf13942011-05-26 22:27:491964 if (pp->fmt == CMIT_FMT_RAW) {
Johannes Schindelin93fc05e2007-11-04 19:15:061965 strbuf_add(sb, line, linelen);
1966 continue;
1967 }
1968
Christian Couder59556542013-11-30 20:55:401969 if (starts_with(line, "parent ")) {
brian m. carlson580f0982018-07-16 01:28:081970 if (linelen != the_hash_algo->hexsz + 8)
Johannes Schindelin93fc05e2007-11-04 19:15:061971 die("bad parent line in commit");
1972 continue;
1973 }
1974
1975 if (!parents_shown) {
René Scharfe4bbaa1e2014-07-16 23:52:091976 unsigned num = commit_list_count(commit->parents);
Johannes Schindelin93fc05e2007-11-04 19:15:061977 /* with enough slop */
brian m. carlson580f0982018-07-16 01:28:081978 strbuf_grow(sb, num * (GIT_MAX_HEXSZ + 10) + 20);
Jeff King6bf13942011-05-26 22:27:491979 add_merge_info(pp, sb, commit);
Johannes Schindelin93fc05e2007-11-04 19:15:061980 parents_shown = 1;
1981 }
1982
1983 /*
1984 * MEDIUM == DEFAULT shows only author with dates.
1985 * FULL shows both authors but not dates.
1986 * FULLER shows both authors and dates.
1987 */
René Scharfee3f1da92014-10-04 18:54:501988 if (skip_prefix(line, "author ", &name)) {
Johannes Schindelin93fc05e2007-11-04 19:15:061989 strbuf_grow(sb, linelen + 80);
René Scharfee3f1da92014-10-04 18:54:501990 pp_user_info(pp, "Author", sb, name, encoding);
Johannes Schindelin93fc05e2007-11-04 19:15:061991 }
René Scharfee3f1da92014-10-04 18:54:501992 if (skip_prefix(line, "committer ", &name) &&
Jeff King6bf13942011-05-26 22:27:491993 (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
Johannes Schindelin93fc05e2007-11-04 19:15:061994 strbuf_grow(sb, linelen + 80);
René Scharfee3f1da92014-10-04 18:54:501995 pp_user_info(pp, "Commit", sb, name, encoding);
Johannes Schindelin93fc05e2007-11-04 19:15:061996 }
1997 }
1998}
1999
Jeff King10f2fbf2013-07-03 07:07:482000void pp_title_line(struct pretty_print_context *pp,
Daniel Barkalowb02bd652008-02-19 03:56:082001 const char **msg_p,
2002 struct strbuf *sb,
Daniel Barkalowb02bd652008-02-19 03:56:082003 const char *encoding,
Junio C Hamano267123b2008-03-15 07:09:202004 int need_8bit_cte)
Johannes Schindelin93fc05e2007-11-04 19:15:062005{
Jan H. Schönherr41dd00b2012-10-18 14:43:332006 static const int max_length = 78; /* per rfc2047 */
Johannes Schindelin93fc05e2007-11-04 19:15:062007 struct strbuf title;
2008
2009 strbuf_init(&title, 80);
Jeff King9553d2b2011-05-26 22:28:172010 *msg_p = format_subject(&title, *msg_p,
2011 pp->preserve_subject ? "\n" : " ");
Johannes Schindelin93fc05e2007-11-04 19:15:062012
2013 strbuf_grow(sb, title.len + 1024);
René Scharfe6d167fd2017-03-01 11:37:072014 if (pp->print_email_subject) {
2015 if (pp->rev)
2016 fmt_output_email_subject(sb, pp->rev);
Emma Brooks19d097e2020-04-08 04:31:382017 if (pp->encode_email_headers &&
2018 needs_rfc2047_encoding(title.buf, title.len))
Jan H. Schönherr41dd00b2012-10-18 14:43:332019 add_rfc2047(sb, title.buf, title.len,
2020 encoding, RFC2047_SUBJECT);
2021 else
2022 strbuf_add_wrapped_bytes(sb, title.buf, title.len,
2023 -last_line_length(sb), 1, max_length);
Johannes Schindelin93fc05e2007-11-04 19:15:062024 } else {
2025 strbuf_addbuf(sb, &title);
2026 }
2027 strbuf_addch(sb, '\n');
2028
Jeff Kinga9080472013-07-03 07:08:222029 if (need_8bit_cte == 0) {
2030 int i;
2031 for (i = 0; i < pp->in_body_headers.nr; i++) {
2032 if (has_non_ascii(pp->in_body_headers.items[i].string)) {
2033 need_8bit_cte = 1;
2034 break;
2035 }
2036 }
2037 }
2038
Junio C Hamano6bf4f1b2008-03-15 00:10:092039 if (need_8bit_cte > 0) {
Johannes Schindelin93fc05e2007-11-04 19:15:062040 const char *header_fmt =
2041 "MIME-Version: 1.0\n"
2042 "Content-Type: text/plain; charset=%s\n"
2043 "Content-Transfer-Encoding: 8bit\n";
2044 strbuf_addf(sb, header_fmt, encoding);
2045 }
Jeff King6bf13942011-05-26 22:27:492046 if (pp->after_subject) {
2047 strbuf_addstr(sb, pp->after_subject);
Johannes Schindelin93fc05e2007-11-04 19:15:062048 }
Eric Wong9f23e042016-06-05 04:46:392049 if (cmit_fmt_is_mail(pp->fmt)) {
Johannes Schindelin93fc05e2007-11-04 19:15:062050 strbuf_addch(sb, '\n');
2051 }
Jeff Kinga9080472013-07-03 07:08:222052
2053 if (pp->in_body_headers.nr) {
2054 int i;
2055 for (i = 0; i < pp->in_body_headers.nr; i++) {
2056 strbuf_addstr(sb, pp->in_body_headers.items[i].string);
2057 free(pp->in_body_headers.items[i].string);
2058 }
2059 string_list_clear(&pp->in_body_headers, 0);
2060 strbuf_addch(sb, '\n');
2061 }
2062
Johannes Schindelin93fc05e2007-11-04 19:15:062063 strbuf_release(&title);
2064}
2065
Linus Torvalds7cc13c72016-03-16 16:15:532066static int pp_utf8_width(const char *start, const char *end)
2067{
2068 int width = 0;
2069 size_t remain = end - start;
2070
2071 while (remain) {
2072 int n = utf8_width(&start, &remain);
2073 if (n < 0 || !start)
2074 return -1;
2075 width += n;
2076 }
2077 return width;
2078}
2079
Hamza Mahfooz6a5c3372021-10-07 20:31:472080static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,
2081 int color, int tabwidth, const char *line,
2082 int linelen)
Linus Torvalds7cc13c72016-03-16 16:15:532083{
2084 const char *tab;
2085
2086 while ((tab = memchr(line, '\t', linelen)) != NULL) {
2087 int width = pp_utf8_width(line, tab);
2088
2089 /*
2090 * If it wasn't well-formed utf8, or it
2091 * had characters with badly defined
2092 * width (control characters etc), just
2093 * give up on trying to align things.
2094 */
2095 if (width < 0)
2096 break;
2097
2098 /* Output the data .. */
Hamza Mahfooz6a5c3372021-10-07 20:31:472099 append_line_with_color(sb, opt, line, tab - line, color,
2100 GREP_CONTEXT_BODY,
2101 GREP_HEADER_FIELD_MAX);
Linus Torvalds7cc13c72016-03-16 16:15:532102
2103 /* .. and the de-tabified tab */
Junio C Hamanofe37a9c2016-03-29 23:05:392104 strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth));
Linus Torvalds7cc13c72016-03-16 16:15:532105
2106 /* Skip over the printed part .. */
2107 linelen -= tab + 1 - line;
2108 line = tab + 1;
2109 }
2110
2111 /*
2112 * Print out everything after the last tab without
2113 * worrying about width - there's nothing more to
2114 * align.
2115 */
Hamza Mahfooz6a5c3372021-10-07 20:31:472116 append_line_with_color(sb, opt, line, linelen, color, GREP_CONTEXT_BODY,
2117 GREP_HEADER_FIELD_MAX);
Linus Torvalds7cc13c72016-03-16 16:15:532118}
2119
2120/*
2121 * pp_handle_indent() prints out the intendation, and
2122 * the whole line (without the final newline), after
2123 * de-tabifying.
2124 */
2125static void pp_handle_indent(struct pretty_print_context *pp,
2126 struct strbuf *sb, int indent,
2127 const char *line, int linelen)
2128{
Hamza Mahfooz6a5c3372021-10-07 20:31:472129 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
2130
Linus Torvalds7cc13c72016-03-16 16:15:532131 strbuf_addchars(sb, ' ', indent);
2132 if (pp->expand_tabs_in_log)
Hamza Mahfooz6a5c3372021-10-07 20:31:472133 strbuf_add_tabexpand(sb, opt, pp->color, pp->expand_tabs_in_log,
2134 line, linelen);
Linus Torvalds7cc13c72016-03-16 16:15:532135 else
Hamza Mahfooz6a5c3372021-10-07 20:31:472136 append_line_with_color(sb, opt, line, linelen, pp->color,
2137 GREP_CONTEXT_BODY,
2138 GREP_HEADER_FIELD_MAX);
Linus Torvalds7cc13c72016-03-16 16:15:532139}
2140
Eric Wong9f23e042016-06-05 04:46:392141static int is_mboxrd_from(const char *line, int len)
2142{
2143 /*
2144 * a line matching /^From $/ here would only have len == 4
2145 * at this point because is_empty_line would've trimmed all
2146 * trailing space
2147 */
2148 return len > 4 && starts_with(line + strspn(line, ">"), "From ");
2149}
2150
Jeff King10f2fbf2013-07-03 07:07:482151void pp_remainder(struct pretty_print_context *pp,
Daniel Barkalowb02bd652008-02-19 03:56:082152 const char **msg_p,
2153 struct strbuf *sb,
2154 int indent)
Johannes Schindelin93fc05e2007-11-04 19:15:062155{
Hamza Mahfooz6a5c3372021-10-07 20:31:472156 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
Johannes Schindelin93fc05e2007-11-04 19:15:062157 int first = 1;
Hamza Mahfooz6a5c3372021-10-07 20:31:472158
Johannes Schindelin93fc05e2007-11-04 19:15:062159 for (;;) {
2160 const char *line = *msg_p;
2161 int linelen = get_one_line(line);
2162 *msg_p += linelen;
2163
2164 if (!linelen)
2165 break;
2166
Johannes Schindelin77356122016-06-22 20:20:162167 if (is_blank_line(line, &linelen)) {
Johannes Schindelin93fc05e2007-11-04 19:15:062168 if (first)
2169 continue;
Jeff King6bf13942011-05-26 22:27:492170 if (pp->fmt == CMIT_FMT_SHORT)
Johannes Schindelin93fc05e2007-11-04 19:15:062171 break;
2172 }
2173 first = 0;
2174
2175 strbuf_grow(sb, linelen + indent + 20);
René Scharfe415792e2014-09-07 07:06:422176 if (indent)
Linus Torvalds7cc13c72016-03-16 16:15:532177 pp_handle_indent(pp, sb, indent, line, linelen);
Junio C Hamano0893eec2016-03-29 22:49:242178 else if (pp->expand_tabs_in_log)
Hamza Mahfooz6a5c3372021-10-07 20:31:472179 strbuf_add_tabexpand(sb, opt, pp->color,
2180 pp->expand_tabs_in_log, line,
2181 linelen);
Eric Wong9f23e042016-06-05 04:46:392182 else {
2183 if (pp->fmt == CMIT_FMT_MBOXRD &&
2184 is_mboxrd_from(line, linelen))
2185 strbuf_addch(sb, '>');
2186
Hamza Mahfooz6a5c3372021-10-07 20:31:472187 append_line_with_color(sb, opt, line, linelen,
2188 pp->color, GREP_CONTEXT_BODY,
2189 GREP_HEADER_FIELD_MAX);
Eric Wong9f23e042016-06-05 04:46:392190 }
Johannes Schindelin93fc05e2007-11-04 19:15:062191 strbuf_addch(sb, '\n');
2192 }
2193}
2194
Jeff King10f2fbf2013-07-03 07:07:482195void pretty_print_commit(struct pretty_print_context *pp,
Jeff King6bf13942011-05-26 22:27:492196 const struct commit *commit,
2197 struct strbuf *sb)
Johannes Schindelin93fc05e2007-11-04 19:15:062198{
2199 unsigned long beginning_of_body;
2200 int indent = 4;
Jeff Kingdd0d3882013-01-26 09:44:062201 const char *msg;
Jeff Kingb000c592014-06-10 21:39:302202 const char *reencoded;
Johannes Schindelin93fc05e2007-11-04 19:15:062203 const char *encoding;
Jeff King6bf13942011-05-26 22:27:492204 int need_8bit_cte = pp->need_8bit_cte;
Johannes Schindelin93fc05e2007-11-04 19:15:062205
Jeff King6bf13942011-05-26 22:27:492206 if (pp->fmt == CMIT_FMT_USERFORMAT) {
2207 format_commit_message(commit, user_format, sb, pp);
Johannes Schindelin93fc05e2007-11-04 19:15:062208 return;
2209 }
2210
Junio C Hamanoe297cf52012-10-18 00:12:552211 encoding = get_log_output_encoding();
Nguyễn Thái Ngọc Duy5a10d232013-04-18 23:08:402212 msg = reencoded = logmsg_reencode(commit, NULL, encoding);
Johannes Schindelin93fc05e2007-11-04 19:15:062213
Eric Wong9f23e042016-06-05 04:46:392214 if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
Johannes Schindelin93fc05e2007-11-04 19:15:062215 indent = 0;
2216
Junio C Hamano6bf4f1b2008-03-15 00:10:092217 /*
2218 * We need to check and emit Content-type: to mark it
2219 * as 8-bit if we haven't done so.
Johannes Schindelin93fc05e2007-11-04 19:15:062220 */
Eric Wong9f23e042016-06-05 04:46:392221 if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {
Johannes Schindelin93fc05e2007-11-04 19:15:062222 int i, ch, in_body;
2223
2224 for (in_body = i = 0; (ch = msg[i]); i++) {
2225 if (!in_body) {
2226 /* author could be non 7-bit ASCII but
2227 * the log may be so; skip over the
2228 * header part first.
2229 */
2230 if (ch == '\n' && msg[i+1] == '\n')
2231 in_body = 1;
2232 }
2233 else if (non_ascii(ch)) {
Junio C Hamano6bf4f1b2008-03-15 00:10:092234 need_8bit_cte = 1;
Johannes Schindelin93fc05e2007-11-04 19:15:062235 break;
2236 }
2237 }
2238 }
2239
Jeff King6bf13942011-05-26 22:27:492240 pp_header(pp, encoding, commit, &msg, sb);
René Scharfe6d167fd2017-03-01 11:37:072241 if (pp->fmt != CMIT_FMT_ONELINE && !pp->print_email_subject) {
Johannes Schindelin93fc05e2007-11-04 19:15:062242 strbuf_addch(sb, '\n');
2243 }
2244
2245 /* Skip excess blank lines at the beginning of body, if any... */
Johannes Schindelin77356122016-06-22 20:20:162246 msg = skip_blank_lines(msg);
Johannes Schindelin93fc05e2007-11-04 19:15:062247
2248 /* These formats treat the title line specially. */
Eric Wong9f23e042016-06-05 04:46:392249 if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
Jeff King6bf13942011-05-26 22:27:492250 pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
Johannes Schindelin93fc05e2007-11-04 19:15:062251
2252 beginning_of_body = sb->len;
Jeff King6bf13942011-05-26 22:27:492253 if (pp->fmt != CMIT_FMT_ONELINE)
2254 pp_remainder(pp, &msg, sb, indent);
Johannes Schindelin93fc05e2007-11-04 19:15:062255 strbuf_rtrim(sb);
2256
2257 /* Make sure there is an EOLN for the non-oneline case */
Jeff King6bf13942011-05-26 22:27:492258 if (pp->fmt != CMIT_FMT_ONELINE)
Johannes Schindelin93fc05e2007-11-04 19:15:062259 strbuf_addch(sb, '\n');
2260
2261 /*
2262 * The caller may append additional body text in e-mail
2263 * format. Make sure we did not strip the blank line
2264 * between the header and the body.
2265 */
Eric Wong9f23e042016-06-05 04:46:392266 if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
Johannes Schindelin93fc05e2007-11-04 19:15:062267 strbuf_addch(sb, '\n');
Johannes Schindelina97a7462009-10-09 10:21:572268
Jeff Kingb66103c2014-06-10 21:41:392269 unuse_commit_buffer(commit, reencoded);
Johannes Schindelin93fc05e2007-11-04 19:15:062270}
Jeff King8b8a5372011-05-26 22:27:242271
2272void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
2273 struct strbuf *sb)
2274{
2275 struct pretty_print_context pp = {0};
Jeff King6bf13942011-05-26 22:27:492276 pp.fmt = fmt;
2277 pretty_print_commit(&pp, commit, sb);
Jeff King8b8a5372011-05-26 22:27:242278}