Coverage Report

Created: 2026-10-17 07:15

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