Coverage Report

Created: 2026-01-09 07:10

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