Coverage Report

Created: 2024-09-08 06:23

/src/git/pretty.c
Line
Count
Source (jump to first uncovered line)
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "config.h"
5
#include "commit.h"
6
#include "environment.h"
7
#include "gettext.h"
8
#include "hash.h"
9
#include "hex.h"
10
#include "utf8.h"
11
#include "diff.h"
12
#include "pager.h"
13
#include "revision.h"
14
#include "string-list.h"
15
#include "mailmap.h"
16
#include "log-tree.h"
17
#include "notes.h"
18
#include "color.h"
19
#include "reflog-walk.h"
20
#include "gpg-interface.h"
21
#include "trailer.h"
22
#include "run-command.h"
23
#include "object-name.h"
24
25
/*
26
 * The limit for formatting directives, which enable the caller to append
27
 * arbitrarily many bytes to the formatted buffer. This includes padding
28
 * and wrapping formatters.
29
 */
30
0
#define FORMATTING_LIMIT (16 * 1024)
31
32
static char *user_format;
33
static struct cmt_fmt_map {
34
  const char *name;
35
  enum cmit_fmt format;
36
  int is_tformat;
37
  int expand_tabs_in_log;
38
  int is_alias;
39
  enum date_mode_type default_date_mode_type;
40
  const char *user_format;
41
} *commit_formats;
42
static size_t builtin_formats_len;
43
static size_t commit_formats_len;
44
static size_t commit_formats_alloc;
45
static struct cmt_fmt_map *find_commit_format(const char *sought);
46
47
int commit_format_is_empty(enum cmit_fmt fmt)
48
0
{
49
0
  return fmt == CMIT_FMT_USERFORMAT && !*user_format;
50
0
}
51
52
static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
53
0
{
54
0
  free(user_format);
55
0
  user_format = xstrdup(cp);
56
0
  if (is_tformat)
57
0
    rev->use_terminator = 1;
58
0
  rev->commit_format = CMIT_FMT_USERFORMAT;
59
0
}
60
61
static int git_pretty_formats_config(const char *var, const char *value,
62
             const struct config_context *ctx UNUSED,
63
             void *cb UNUSED)
64
0
{
65
0
  struct cmt_fmt_map *commit_format = NULL;
66
0
  const char *name, *stripped;
67
0
  char *fmt;
68
0
  int i;
69
70
0
  if (!skip_prefix(var, "pretty.", &name))
71
0
    return 0;
72
73
0
  for (i = 0; i < builtin_formats_len; i++) {
74
0
    if (!strcmp(commit_formats[i].name, name))
75
0
      return 0;
76
0
  }
77
78
0
  for (i = builtin_formats_len; i < commit_formats_len; i++) {
79
0
    if (!strcmp(commit_formats[i].name, name)) {
80
0
      commit_format = &commit_formats[i];
81
0
      break;
82
0
    }
83
0
  }
84
85
0
  if (!commit_format) {
86
0
    ALLOC_GROW(commit_formats, commit_formats_len+1,
87
0
         commit_formats_alloc);
88
0
    commit_format = &commit_formats[commit_formats_len];
89
0
    memset(commit_format, 0, sizeof(*commit_format));
90
0
    commit_formats_len++;
91
0
  }
92
93
0
  free((char *)commit_format->name);
94
0
  commit_format->name = xstrdup(name);
95
0
  commit_format->format = CMIT_FMT_USERFORMAT;
96
0
  if (git_config_string(&fmt, var, value))
97
0
    return -1;
98
99
0
  free((char *)commit_format->user_format);
100
0
  if (skip_prefix(fmt, "format:", &stripped)) {
101
0
    commit_format->is_tformat = 0;
102
0
    commit_format->user_format = xstrdup(stripped);
103
0
    free(fmt);
104
0
  } else if (skip_prefix(fmt, "tformat:", &stripped)) {
105
0
    commit_format->is_tformat = 1;
106
0
    commit_format->user_format = xstrdup(stripped);
107
0
    free(fmt);
108
0
  } else if (strchr(fmt, '%')) {
109
0
    commit_format->is_tformat = 1;
110
0
    commit_format->user_format = fmt;
111
0
  } else {
112
0
    commit_format->is_alias = 1;
113
0
    commit_format->user_format = fmt;
114
0
  }
115
116
0
  return 0;
117
0
}
118
119
static void setup_commit_formats(void)
120
0
{
121
0
  struct cmt_fmt_map builtin_formats[] = {
122
0
    { "raw",  CMIT_FMT_RAW,   0,  0 },
123
0
    { "medium", CMIT_FMT_MEDIUM,  0,  8 },
124
0
    { "short",  CMIT_FMT_SHORT,   0,  0 },
125
0
    { "email",  CMIT_FMT_EMAIL,   0,  0 },
126
0
    { "mboxrd", CMIT_FMT_MBOXRD,  0,  0 },
127
0
    { "fuller", CMIT_FMT_FULLER,  0,  8 },
128
0
    { "full", CMIT_FMT_FULL,    0,  8 },
129
0
    { "oneline",  CMIT_FMT_ONELINE, 1,  0 },
130
0
    { "reference",  CMIT_FMT_USERFORMAT,  1,  0,
131
0
      0, DATE_SHORT, "%C(auto)%h (%s, %ad)" },
132
    /*
133
     * Please update $__git_log_pretty_formats in
134
     * git-completion.bash when you add new formats.
135
     */
136
0
  };
137
0
  commit_formats_len = ARRAY_SIZE(builtin_formats);
138
0
  builtin_formats_len = commit_formats_len;
139
0
  ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
140
0
  COPY_ARRAY(commit_formats, builtin_formats,
141
0
       ARRAY_SIZE(builtin_formats));
142
143
0
  git_config(git_pretty_formats_config, NULL);
144
0
}
145
146
static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
147
              const char *original,
148
              int num_redirections)
149
0
{
150
0
  struct cmt_fmt_map *found = NULL;
151
0
  size_t found_match_len = 0;
152
0
  int i;
153
154
0
  if (num_redirections >= commit_formats_len)
155
0
    die("invalid --pretty format: "
156
0
        "'%s' references an alias which points to itself",
157
0
        original);
158
159
0
  for (i = 0; i < commit_formats_len; i++) {
160
0
    size_t match_len;
161
162
0
    if (!istarts_with(commit_formats[i].name, sought))
163
0
      continue;
164
165
0
    match_len = strlen(commit_formats[i].name);
166
0
    if (found == NULL || found_match_len > match_len) {
167
0
      found = &commit_formats[i];
168
0
      found_match_len = match_len;
169
0
    }
170
0
  }
171
172
0
  if (found && found->is_alias) {
173
0
    found = find_commit_format_recursive(found->user_format,
174
0
                 original,
175
0
                 num_redirections+1);
176
0
  }
177
178
0
  return found;
179
0
}
180
181
static struct cmt_fmt_map *find_commit_format(const char *sought)
182
0
{
183
0
  if (!commit_formats)
184
0
    setup_commit_formats();
185
186
0
  return find_commit_format_recursive(sought, sought, 0);
187
0
}
188
189
void get_commit_format(const char *arg, struct rev_info *rev)
190
0
{
191
0
  struct cmt_fmt_map *commit_format;
192
193
0
  rev->use_terminator = 0;
194
0
  if (!arg) {
195
0
    rev->commit_format = CMIT_FMT_DEFAULT;
196
0
    return;
197
0
  }
198
0
  if (skip_prefix(arg, "format:", &arg)) {
199
0
    save_user_format(rev, arg, 0);
200
0
    return;
201
0
  }
202
203
0
  if (!*arg || skip_prefix(arg, "tformat:", &arg) || strchr(arg, '%')) {
204
0
    save_user_format(rev, arg, 1);
205
0
    return;
206
0
  }
207
208
0
  commit_format = find_commit_format(arg);
209
0
  if (!commit_format)
210
0
    die("invalid --pretty format: %s", arg);
211
212
0
  rev->commit_format = commit_format->format;
213
0
  rev->use_terminator = commit_format->is_tformat;
214
0
  rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log;
215
0
  if (!rev->date_mode_explicit && commit_format->default_date_mode_type)
216
0
    rev->date_mode.type = commit_format->default_date_mode_type;
217
0
  if (commit_format->format == CMIT_FMT_USERFORMAT) {
218
0
    save_user_format(rev, commit_format->user_format,
219
0
         commit_format->is_tformat);
220
0
  }
221
0
}
222
223
/*
224
 * Generic support for pretty-printing the header
225
 */
226
static int get_one_line(const char *msg)
227
0
{
228
0
  int ret = 0;
229
230
0
  for (;;) {
231
0
    char c = *msg++;
232
0
    if (!c)
233
0
      break;
234
0
    ret++;
235
0
    if (c == '\n')
236
0
      break;
237
0
  }
238
0
  return ret;
239
0
}
240
241
/* High bit set, or ISO-2022-INT */
242
static int non_ascii(int ch)
243
0
{
244
0
  return !isascii(ch) || ch == '\033';
245
0
}
246
247
int has_non_ascii(const char *s)
248
0
{
249
0
  int ch;
250
0
  if (!s)
251
0
    return 0;
252
0
  while ((ch = *s++) != '\0') {
253
0
    if (non_ascii(ch))
254
0
      return 1;
255
0
  }
256
0
  return 0;
257
0
}
258
259
static int is_rfc822_special(char ch)
260
0
{
261
0
  switch (ch) {
262
0
  case '(':
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
    return 1;
276
0
  default:
277
0
    return 0;
278
0
  }
279
0
}
280
281
static int needs_rfc822_quoting(const char *s, int len)
282
0
{
283
0
  int i;
284
0
  for (i = 0; i < len; i++)
285
0
    if (is_rfc822_special(s[i]))
286
0
      return 1;
287
0
  return 0;
288
0
}
289
290
static int last_line_length(struct strbuf *sb)
291
0
{
292
0
  int i;
293
294
  /* How many bytes are already used on the last line? */
295
0
  for (i = sb->len - 1; i >= 0; i--)
296
0
    if (sb->buf[i] == '\n')
297
0
      break;
298
0
  return sb->len - (i + 1);
299
0
}
300
301
static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
302
0
{
303
0
  int i;
304
305
  /* just a guess, we may have to also backslash-quote */
306
0
  strbuf_grow(out, len + 2);
307
308
0
  strbuf_addch(out, '"');
309
0
  for (i = 0; i < len; i++) {
310
0
    switch (s[i]) {
311
0
    case '"':
312
0
    case '\\':
313
0
      strbuf_addch(out, '\\');
314
      /* fall through */
315
0
    default:
316
0
      strbuf_addch(out, s[i]);
317
0
    }
318
0
  }
319
0
  strbuf_addch(out, '"');
320
0
}
321
322
enum rfc2047_type {
323
  RFC2047_SUBJECT,
324
  RFC2047_ADDRESS
325
};
326
327
static int is_rfc2047_special(char ch, enum rfc2047_type type)
328
0
{
329
  /*
330
   * rfc2047, section 4.2:
331
   *
332
   *    8-bit values which correspond to printable ASCII characters other
333
   *    than "=", "?", and "_" (underscore), MAY be represented as those
334
   *    characters.  (But see section 5 for restrictions.)  In
335
   *    particular, SPACE and TAB MUST NOT be represented as themselves
336
   *    within encoded words.
337
   */
338
339
  /*
340
   * rule out non-ASCII characters and non-printable characters (the
341
   * non-ASCII check should be redundant as isprint() is not localized
342
   * and only knows about ASCII, but be defensive about that)
343
   */
344
0
  if (non_ascii(ch) || !isprint(ch))
345
0
    return 1;
346
347
  /*
348
   * rule out special printable characters (' ' should be the only
349
   * whitespace character considered printable, but be defensive and use
350
   * isspace())
351
   */
352
0
  if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
353
0
    return 1;
354
355
  /*
356
   * rfc2047, section 5.3:
357
   *
358
   *    As a replacement for a 'word' entity within a 'phrase', for example,
359
   *    one that precedes an address in a From, To, or Cc header.  The ABNF
360
   *    definition for 'phrase' from RFC 822 thus becomes:
361
   *
362
   *    phrase = 1*( encoded-word / word )
363
   *
364
   *    In this case the set of characters that may be used in a "Q"-encoded
365
   *    'encoded-word' is restricted to: <upper and lower case ASCII
366
   *    letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
367
   *    (underscore, ASCII 95.)>.  An 'encoded-word' that appears within a
368
   *    'phrase' MUST be separated from any adjacent 'word', 'text' or
369
   *    'special' by 'linear-white-space'.
370
   */
371
372
0
  if (type != RFC2047_ADDRESS)
373
0
    return 0;
374
375
  /* '=' and '_' are special cases and have been checked above */
376
0
  return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
377
0
}
378
379
static int needs_rfc2047_encoding(const char *line, int len)
380
0
{
381
0
  int i;
382
383
0
  for (i = 0; i < len; i++) {
384
0
    int ch = line[i];
385
0
    if (non_ascii(ch) || ch == '\n')
386
0
      return 1;
387
0
    if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
388
0
      return 1;
389
0
  }
390
391
0
  return 0;
392
0
}
393
394
static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
395
           const char *encoding, enum rfc2047_type type)
396
0
{
397
0
  static const int max_encoded_length = 76; /* per rfc2047 */
398
0
  int i;
399
0
  int line_len = last_line_length(sb);
400
401
0
  strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
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
           int 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_addstr(sb, oid_to_hex(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(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
  int 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 = want_color(c->pretty_ctx->color);
1458
0
      if (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 = 0;
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
  switch (placeholder[0]) {
1552
0
  case 'H':   /* commit hash */
1553
0
    strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
1554
0
    strbuf_addstr(sb, oid_to_hex(&commit->object.oid));
1555
0
    strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
1556
0
    return 1;
1557
0
  case 'h':   /* abbreviated commit hash */
1558
0
    strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
1559
0
    strbuf_add_unique_abbrev(sb, &commit->object.oid,
1560
0
           c->pretty_ctx->abbrev);
1561
0
    strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
1562
0
    return 1;
1563
0
  case 'T':   /* tree hash */
1564
0
    strbuf_addstr(sb, oid_to_hex(get_commit_tree_oid(commit)));
1565
0
    return 1;
1566
0
  case 't':   /* abbreviated tree hash */
1567
0
    strbuf_add_unique_abbrev(sb,
1568
0
           get_commit_tree_oid(commit),
1569
0
           c->pretty_ctx->abbrev);
1570
0
    return 1;
1571
0
  case 'P':   /* parent hashes */
1572
0
    for (p = commit->parents; p; p = p->next) {
1573
0
      if (p != commit->parents)
1574
0
        strbuf_addch(sb, ' ');
1575
0
      strbuf_addstr(sb, oid_to_hex(&p->item->object.oid));
1576
0
    }
1577
0
    return 1;
1578
0
  case 'p':   /* abbreviated parent hashes */
1579
0
    for (p = commit->parents; p; p = p->next) {
1580
0
      if (p != commit->parents)
1581
0
        strbuf_addch(sb, ' ');
1582
0
      strbuf_add_unique_abbrev(sb, &p->item->object.oid,
1583
0
             c->pretty_ctx->abbrev);
1584
0
    }
1585
0
    return 1;
1586
0
  case 'm':   /* left/right/bottom */
1587
0
    strbuf_addstr(sb, get_revision_mark(NULL, commit));
1588
0
    return 1;
1589
0
  case 'd':
1590
0
    format_decorations(sb, commit, c->auto_color, NULL);
1591
0
    return 1;
1592
0
  case 'D':
1593
0
    {
1594
0
      const struct decoration_options opts = {
1595
0
        .prefix = (char *) "",
1596
0
        .suffix = (char *) "",
1597
0
      };
1598
1599
0
      format_decorations(sb, commit, c->auto_color, &opts);
1600
0
      return 1;
1601
0
    }
1602
0
  case 'S':   /* tag/branch like --source */
1603
0
    if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
1604
0
      return 0;
1605
0
    slot = revision_sources_at(c->pretty_ctx->rev->sources, commit);
1606
0
    if (!(slot && *slot))
1607
0
      return 0;
1608
0
    strbuf_addstr(sb, *slot);
1609
0
    return 1;
1610
0
  case 'g':   /* reflog info */
1611
0
    switch(placeholder[1]) {
1612
0
    case 'd': /* reflog selector */
1613
0
    case 'D':
1614
0
      if (c->pretty_ctx->reflog_info)
1615
0
        get_reflog_selector(sb,
1616
0
                c->pretty_ctx->reflog_info,
1617
0
                c->pretty_ctx->date_mode,
1618
0
                c->pretty_ctx->date_mode_explicit,
1619
0
                (placeholder[1] == 'd'));
1620
0
      return 2;
1621
0
    case 's': /* reflog message */
1622
0
      if (c->pretty_ctx->reflog_info)
1623
0
        get_reflog_message(sb, c->pretty_ctx->reflog_info);
1624
0
      return 2;
1625
0
    case 'n':
1626
0
    case 'N':
1627
0
    case 'e':
1628
0
    case 'E':
1629
0
      return format_reflog_person(sb,
1630
0
                placeholder[1],
1631
0
                c->pretty_ctx->reflog_info,
1632
0
                c->pretty_ctx->date_mode);
1633
0
    }
1634
0
    return 0; /* unknown %g placeholder */
1635
0
  case 'N':
1636
0
    if (c->pretty_ctx->notes_message) {
1637
0
      strbuf_addstr(sb, c->pretty_ctx->notes_message);
1638
0
      return 1;
1639
0
    }
1640
0
    return 0;
1641
0
  }
1642
1643
0
  if (placeholder[0] == 'G') {
1644
0
    if (!c->signature_check.result)
1645
0
      check_commit_signature(c->commit, &(c->signature_check));
1646
0
    switch (placeholder[1]) {
1647
0
    case 'G':
1648
0
      if (c->signature_check.output)
1649
0
        strbuf_addstr(sb, c->signature_check.output);
1650
0
      break;
1651
0
    case '?':
1652
0
      switch (c->signature_check.result) {
1653
0
      case 'G':
1654
0
        switch (c->signature_check.trust_level) {
1655
0
        case TRUST_UNDEFINED:
1656
0
        case TRUST_NEVER:
1657
0
          strbuf_addch(sb, 'U');
1658
0
          break;
1659
0
        default:
1660
0
          strbuf_addch(sb, 'G');
1661
0
          break;
1662
0
        }
1663
0
        break;
1664
0
      case 'B':
1665
0
      case 'E':
1666
0
      case 'N':
1667
0
      case 'X':
1668
0
      case 'Y':
1669
0
      case 'R':
1670
0
        strbuf_addch(sb, c->signature_check.result);
1671
0
      }
1672
0
      break;
1673
0
    case 'S':
1674
0
      if (c->signature_check.signer)
1675
0
        strbuf_addstr(sb, c->signature_check.signer);
1676
0
      break;
1677
0
    case 'K':
1678
0
      if (c->signature_check.key)
1679
0
        strbuf_addstr(sb, c->signature_check.key);
1680
0
      break;
1681
0
    case 'F':
1682
0
      if (c->signature_check.fingerprint)
1683
0
        strbuf_addstr(sb, c->signature_check.fingerprint);
1684
0
      break;
1685
0
    case 'P':
1686
0
      if (c->signature_check.primary_key_fingerprint)
1687
0
        strbuf_addstr(sb, c->signature_check.primary_key_fingerprint);
1688
0
      break;
1689
0
    case 'T':
1690
0
      strbuf_addstr(sb, gpg_trust_level_to_str(c->signature_check.trust_level));
1691
0
      break;
1692
0
    default:
1693
0
      return 0;
1694
0
    }
1695
0
    return 2;
1696
0
  }
1697
1698
0
  if (skip_prefix(placeholder, "(decorate", &arg)) {
1699
0
    struct decoration_options opts = { NULL };
1700
0
    size_t ret = 0;
1701
1702
0
    if (*arg == ':') {
1703
0
      arg++;
1704
0
      parse_decoration_options(&arg, &opts);
1705
0
    }
1706
0
    if (*arg == ')') {
1707
0
      format_decorations(sb, commit, c->auto_color, &opts);
1708
0
      ret = arg - placeholder + 1;
1709
0
    }
1710
1711
0
    free_decoration_options(&opts);
1712
0
    return ret;
1713
0
  }
1714
1715
  /* For the rest we have to parse the commit header. */
1716
0
  if (!c->commit_header_parsed) {
1717
0
    msg = c->message =
1718
0
      repo_logmsg_reencode(c->repository, commit,
1719
0
               &c->commit_encoding, "UTF-8");
1720
0
    parse_commit_header(c);
1721
0
  }
1722
1723
0
  switch (placeholder[0]) {
1724
0
  case 'a': /* author ... */
1725
0
    return format_person_part(sb, placeholder[1],
1726
0
           msg + c->author.off, c->author.len,
1727
0
           c->pretty_ctx->date_mode);
1728
0
  case 'c': /* committer ... */
1729
0
    return format_person_part(sb, placeholder[1],
1730
0
           msg + c->committer.off, c->committer.len,
1731
0
           c->pretty_ctx->date_mode);
1732
0
  case 'e': /* encoding */
1733
0
    if (c->commit_encoding)
1734
0
      strbuf_addstr(sb, c->commit_encoding);
1735
0
    return 1;
1736
0
  case 'B': /* raw body */
1737
    /* message_off is always left at the initial newline */
1738
0
    strbuf_addstr(sb, msg + c->message_off + 1);
1739
0
    return 1;
1740
0
  }
1741
1742
  /* Now we need to parse the commit message. */
1743
0
  if (!c->commit_message_parsed)
1744
0
    parse_commit_message(c);
1745
1746
0
  switch (placeholder[0]) {
1747
0
  case 's': /* subject */
1748
0
    format_subject(sb, msg + c->subject_off, " ");
1749
0
    return 1;
1750
0
  case 'f': /* sanitized subject */
1751
0
    eol = strchrnul(msg + c->subject_off, '\n');
1752
0
    format_sanitized_subject(sb, msg + c->subject_off, eol - (msg + c->subject_off));
1753
0
    return 1;
1754
0
  case 'b': /* body */
1755
0
    strbuf_addstr(sb, msg + c->body_off);
1756
0
    return 1;
1757
0
  }
1758
1759
0
  if (skip_prefix(placeholder, "(trailers", &arg)) {
1760
0
    struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1761
0
    struct string_list filter_list = STRING_LIST_INIT_NODUP;
1762
0
    struct strbuf sepbuf = STRBUF_INIT;
1763
0
    struct strbuf kvsepbuf = STRBUF_INIT;
1764
0
    size_t ret = 0;
1765
1766
0
    opts.no_divider = 1;
1767
1768
0
    if (*arg == ':') {
1769
0
      arg++;
1770
0
      if (format_set_trailers_options(&opts, &filter_list, &sepbuf, &kvsepbuf, &arg, NULL))
1771
0
        goto trailer_out;
1772
0
    }
1773
0
    if (*arg == ')') {
1774
0
      format_trailers_from_commit(&opts, msg + c->subject_off, sb);
1775
0
      ret = arg - placeholder + 1;
1776
0
    }
1777
0
  trailer_out:
1778
0
    string_list_clear(&filter_list, 0);
1779
0
    strbuf_release(&kvsepbuf);
1780
0
    strbuf_release(&sepbuf);
1781
0
    return ret;
1782
0
  }
1783
1784
0
  return 0; /* unknown placeholder */
1785
0
}
1786
1787
static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
1788
            const char *placeholder,
1789
            struct format_commit_context *c)
1790
0
{
1791
0
  struct strbuf local_sb = STRBUF_INIT;
1792
0
  size_t total_consumed = 0;
1793
0
  int len, padding = c->padding;
1794
1795
0
  if (padding < 0) {
1796
0
    const char *start = strrchr(sb->buf, '\n');
1797
0
    int occupied;
1798
0
    if (!start)
1799
0
      start = sb->buf;
1800
0
    occupied = utf8_strnwidth(start, strlen(start), 1);
1801
0
    occupied += c->pretty_ctx->graph_width;
1802
0
    padding = (-padding) - occupied;
1803
0
  }
1804
0
  while (1) {
1805
0
    int modifier = *placeholder == 'C';
1806
0
    size_t consumed = format_commit_one(&local_sb, placeholder, c);
1807
0
    total_consumed += consumed;
1808
1809
0
    if (!modifier)
1810
0
      break;
1811
1812
0
    placeholder += consumed;
1813
0
    if (*placeholder != '%')
1814
0
      break;
1815
0
    placeholder++;
1816
0
    total_consumed++;
1817
0
  }
1818
0
  len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
1819
1820
0
  if (c->flush_type == flush_left_and_steal) {
1821
0
    const char *ch = sb->buf + sb->len - 1;
1822
0
    while (len > padding && ch > sb->buf) {
1823
0
      const char *p;
1824
0
      if (*ch == ' ') {
1825
0
        ch--;
1826
0
        padding++;
1827
0
        continue;
1828
0
      }
1829
      /* check for trailing ansi sequences */
1830
0
      if (*ch != 'm')
1831
0
        break;
1832
0
      p = ch - 1;
1833
0
      while (p > sb->buf && ch - p < 10 && *p != '\033')
1834
0
        p--;
1835
0
      if (*p != '\033' ||
1836
0
          ch + 1 - p != display_mode_esc_sequence_len(p))
1837
0
        break;
1838
      /*
1839
       * got a good ansi sequence, put it back to
1840
       * local_sb as we're cutting sb
1841
       */
1842
0
      strbuf_insert(&local_sb, 0, p, ch + 1 - p);
1843
0
      ch = p - 1;
1844
0
    }
1845
0
    strbuf_setlen(sb, ch + 1 - sb->buf);
1846
0
    c->flush_type = flush_left;
1847
0
  }
1848
1849
0
  if (len > padding) {
1850
0
    switch (c->truncate) {
1851
0
    case trunc_left:
1852
0
      strbuf_utf8_replace(&local_sb,
1853
0
              0, len - (padding - 2),
1854
0
              "..");
1855
0
      break;
1856
0
    case trunc_middle:
1857
0
      strbuf_utf8_replace(&local_sb,
1858
0
              padding / 2 - 1,
1859
0
              len - (padding - 2),
1860
0
              "..");
1861
0
      break;
1862
0
    case trunc_right:
1863
0
      strbuf_utf8_replace(&local_sb,
1864
0
              padding - 2, len - (padding - 2),
1865
0
              "..");
1866
0
      break;
1867
0
    case trunc_none:
1868
0
      break;
1869
0
    }
1870
0
    strbuf_addbuf(sb, &local_sb);
1871
0
  } else {
1872
0
    size_t sb_len = sb->len, offset = 0;
1873
0
    if (c->flush_type == flush_left)
1874
0
      offset = padding - len;
1875
0
    else if (c->flush_type == flush_both)
1876
0
      offset = (padding - len) / 2;
1877
    /*
1878
     * we calculate padding in columns, now
1879
     * convert it back to chars
1880
     */
1881
0
    padding = padding - len + local_sb.len;
1882
0
    strbuf_addchars(sb, ' ', padding);
1883
0
    memcpy(sb->buf + sb_len + offset, local_sb.buf,
1884
0
           local_sb.len);
1885
0
  }
1886
0
  strbuf_release(&local_sb);
1887
0
  c->flush_type = no_flush;
1888
0
  return total_consumed;
1889
0
}
1890
1891
static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
1892
         const char *placeholder,
1893
         struct format_commit_context *context)
1894
0
{
1895
0
  size_t consumed, orig_len;
1896
0
  enum {
1897
0
    NO_MAGIC,
1898
0
    ADD_LF_BEFORE_NON_EMPTY,
1899
0
    DEL_LF_BEFORE_EMPTY,
1900
0
    ADD_SP_BEFORE_NON_EMPTY
1901
0
  } magic = NO_MAGIC;
1902
1903
0
  switch (placeholder[0]) {
1904
0
  case '-':
1905
0
    magic = DEL_LF_BEFORE_EMPTY;
1906
0
    break;
1907
0
  case '+':
1908
0
    magic = ADD_LF_BEFORE_NON_EMPTY;
1909
0
    break;
1910
0
  case ' ':
1911
0
    magic = ADD_SP_BEFORE_NON_EMPTY;
1912
0
    break;
1913
0
  default:
1914
0
    break;
1915
0
  }
1916
0
  if (magic != NO_MAGIC) {
1917
0
    placeholder++;
1918
1919
0
    switch (placeholder[0]) {
1920
0
    case 'w':
1921
      /*
1922
       * `%+w()` cannot ever expand to a non-empty string,
1923
       * and it potentially changes the layout of preceding
1924
       * contents. We're thus not able to handle the magic in
1925
       * this combination and refuse the pattern.
1926
       */
1927
0
      return 0;
1928
0
    };
1929
0
  }
1930
1931
0
  orig_len = sb->len;
1932
0
  if (context->flush_type == no_flush)
1933
0
    consumed = format_commit_one(sb, placeholder, context);
1934
0
  else
1935
0
    consumed = format_and_pad_commit(sb, placeholder, context);
1936
0
  if (magic == NO_MAGIC)
1937
0
    return consumed;
1938
1939
0
  if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
1940
0
    while (sb->len && sb->buf[sb->len - 1] == '\n')
1941
0
      strbuf_setlen(sb, sb->len - 1);
1942
0
  } else if (orig_len != sb->len) {
1943
0
    if (magic == ADD_LF_BEFORE_NON_EMPTY)
1944
0
      strbuf_insertstr(sb, orig_len, "\n");
1945
0
    else if (magic == ADD_SP_BEFORE_NON_EMPTY)
1946
0
      strbuf_insertstr(sb, orig_len, " ");
1947
0
  }
1948
0
  return consumed + 1;
1949
0
}
1950
1951
void userformat_find_requirements(const char *fmt, struct userformat_want *w)
1952
0
{
1953
0
  if (!fmt) {
1954
0
    if (!user_format)
1955
0
      return;
1956
0
    fmt = user_format;
1957
0
  }
1958
0
  while ((fmt = strchr(fmt, '%'))) {
1959
0
    fmt++;
1960
0
    if (skip_prefix(fmt, "%", &fmt))
1961
0
      continue;
1962
1963
0
    if (*fmt == '+' || *fmt == '-' || *fmt == ' ')
1964
0
      fmt++;
1965
1966
0
    switch (*fmt) {
1967
0
    case 'N':
1968
0
      w->notes = 1;
1969
0
      break;
1970
0
    case 'S':
1971
0
      w->source = 1;
1972
0
      break;
1973
0
    case 'd':
1974
0
    case 'D':
1975
0
      w->decorate = 1;
1976
0
      break;
1977
0
    case '(':
1978
0
      if (starts_with(fmt + 1, "decorate"))
1979
0
        w->decorate = 1;
1980
0
      break;
1981
0
    }
1982
0
  }
1983
0
}
1984
1985
void repo_format_commit_message(struct repository *r,
1986
        const struct commit *commit,
1987
        const char *format, struct strbuf *sb,
1988
        const struct pretty_print_context *pretty_ctx)
1989
0
{
1990
0
  struct format_commit_context context = {
1991
0
    .repository = r,
1992
0
    .commit = commit,
1993
0
    .pretty_ctx = pretty_ctx,
1994
0
    .wrap_start = sb->len
1995
0
  };
1996
0
  const char *output_enc = pretty_ctx->output_encoding;
1997
0
  const char *utf8 = "UTF-8";
1998
1999
0
  while (strbuf_expand_step(sb, &format)) {
2000
0
    size_t len;
2001
2002
0
    if (skip_prefix(format, "%", &format))
2003
0
      strbuf_addch(sb, '%');
2004
0
    else if ((len = format_commit_item(sb, format, &context)))
2005
0
      format += len;
2006
0
    else
2007
0
      strbuf_addch(sb, '%');
2008
0
  }
2009
0
  rewrap_message_tail(sb, &context, 0, 0, 0);
2010
2011
  /*
2012
   * Convert output to an actual output encoding; note that
2013
   * format_commit_item() will always use UTF-8, so we don't
2014
   * have to bother if that's what the output wants.
2015
   */
2016
0
  if (output_enc) {
2017
0
    if (same_encoding(utf8, output_enc))
2018
0
      output_enc = NULL;
2019
0
  } else {
2020
0
    if (context.commit_encoding &&
2021
0
        !same_encoding(context.commit_encoding, utf8))
2022
0
      output_enc = context.commit_encoding;
2023
0
  }
2024
2025
0
  if (output_enc) {
2026
0
    size_t outsz;
2027
0
    char *out = reencode_string_len(sb->buf, sb->len,
2028
0
            output_enc, utf8, &outsz);
2029
0
    if (out)
2030
0
      strbuf_attach(sb, out, outsz, outsz + 1);
2031
0
  }
2032
2033
0
  free(context.commit_encoding);
2034
0
  repo_unuse_commit_buffer(r, commit, context.message);
2035
0
}
2036
2037
static void pp_header(struct pretty_print_context *pp,
2038
          const char *encoding,
2039
          const struct commit *commit,
2040
          const char **msg_p,
2041
          struct strbuf *sb)
2042
0
{
2043
0
  int parents_shown = 0;
2044
2045
0
  for (;;) {
2046
0
    const char *name, *line = *msg_p;
2047
0
    int linelen = get_one_line(*msg_p);
2048
2049
0
    if (!linelen)
2050
0
      return;
2051
0
    *msg_p += linelen;
2052
2053
0
    if (linelen == 1)
2054
      /* End of header */
2055
0
      return;
2056
2057
0
    if (pp->fmt == CMIT_FMT_RAW) {
2058
0
      strbuf_add(sb, line, linelen);
2059
0
      continue;
2060
0
    }
2061
2062
0
    if (starts_with(line, "parent ")) {
2063
0
      if (linelen != the_hash_algo->hexsz + 8)
2064
0
        die("bad parent line in commit");
2065
0
      continue;
2066
0
    }
2067
2068
0
    if (!parents_shown) {
2069
0
      unsigned num = commit_list_count(commit->parents);
2070
      /* with enough slop */
2071
0
      strbuf_grow(sb, num * (GIT_MAX_HEXSZ + 10) + 20);
2072
0
      add_merge_info(pp, sb, commit);
2073
0
      parents_shown = 1;
2074
0
    }
2075
2076
    /*
2077
     * MEDIUM == DEFAULT shows only author with dates.
2078
     * FULL shows both authors but not dates.
2079
     * FULLER shows both authors and dates.
2080
     */
2081
0
    if (skip_prefix(line, "author ", &name)) {
2082
0
      strbuf_grow(sb, linelen + 80);
2083
0
      pp_user_info(pp, "Author", sb, name, encoding);
2084
0
    }
2085
0
    if (skip_prefix(line, "committer ", &name) &&
2086
0
        (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
2087
0
      strbuf_grow(sb, linelen + 80);
2088
0
      pp_user_info(pp, "Commit", sb, name, encoding);
2089
0
    }
2090
0
  }
2091
0
}
2092
2093
void pp_email_subject(struct pretty_print_context *pp,
2094
          const char **msg_p,
2095
          struct strbuf *sb,
2096
          const char *encoding,
2097
          int need_8bit_cte)
2098
0
{
2099
0
  static const int max_length = 78; /* per rfc2047 */
2100
0
  struct strbuf title;
2101
2102
0
  strbuf_init(&title, 80);
2103
0
  *msg_p = format_subject(&title, *msg_p,
2104
0
        pp->preserve_subject ? "\n" : " ");
2105
2106
0
  strbuf_grow(sb, title.len + 1024);
2107
0
  fmt_output_email_subject(sb, pp->rev);
2108
0
  if (pp->encode_email_headers &&
2109
0
      needs_rfc2047_encoding(title.buf, title.len))
2110
0
    add_rfc2047(sb, title.buf, title.len,
2111
0
          encoding, RFC2047_SUBJECT);
2112
0
  else
2113
0
    strbuf_add_wrapped_bytes(sb, title.buf, title.len,
2114
0
           -last_line_length(sb), 1, max_length);
2115
0
  strbuf_addch(sb, '\n');
2116
2117
0
  if (need_8bit_cte == 0) {
2118
0
    int i;
2119
0
    for (i = 0; i < pp->in_body_headers.nr; i++) {
2120
0
      if (has_non_ascii(pp->in_body_headers.items[i].string)) {
2121
0
        need_8bit_cte = 1;
2122
0
        break;
2123
0
      }
2124
0
    }
2125
0
  }
2126
2127
0
  if (need_8bit_cte > 0) {
2128
0
    const char *header_fmt =
2129
0
      "MIME-Version: 1.0\n"
2130
0
      "Content-Type: text/plain; charset=%s\n"
2131
0
      "Content-Transfer-Encoding: 8bit\n";
2132
0
    strbuf_addf(sb, header_fmt, encoding);
2133
0
  }
2134
0
  if (pp->after_subject) {
2135
0
    strbuf_addstr(sb, pp->after_subject);
2136
0
  }
2137
2138
0
  strbuf_addch(sb, '\n');
2139
2140
0
  if (pp->in_body_headers.nr) {
2141
0
    int i;
2142
0
    for (i = 0; i < pp->in_body_headers.nr; i++) {
2143
0
      strbuf_addstr(sb, pp->in_body_headers.items[i].string);
2144
0
      free(pp->in_body_headers.items[i].string);
2145
0
    }
2146
0
    string_list_clear(&pp->in_body_headers, 0);
2147
0
    strbuf_addch(sb, '\n');
2148
0
  }
2149
2150
0
  strbuf_release(&title);
2151
0
}
2152
2153
static int pp_utf8_width(const char *start, const char *end)
2154
0
{
2155
0
  int width = 0;
2156
0
  size_t remain = end - start;
2157
2158
0
  while (remain) {
2159
0
    int n = utf8_width(&start, &remain);
2160
0
    if (n < 0 || !start)
2161
0
      return -1;
2162
0
    width += n;
2163
0
  }
2164
0
  return width;
2165
0
}
2166
2167
static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,
2168
         int color, int tabwidth, const char *line,
2169
         int linelen)
2170
0
{
2171
0
  const char *tab;
2172
2173
0
  while ((tab = memchr(line, '\t', linelen)) != NULL) {
2174
0
    int width = pp_utf8_width(line, tab);
2175
2176
    /*
2177
     * If it wasn't well-formed utf8, or it
2178
     * had characters with badly defined
2179
     * width (control characters etc), just
2180
     * give up on trying to align things.
2181
     */
2182
0
    if (width < 0)
2183
0
      break;
2184
2185
    /* Output the data .. */
2186
0
    append_line_with_color(sb, opt, line, tab - line, color,
2187
0
               GREP_CONTEXT_BODY,
2188
0
               GREP_HEADER_FIELD_MAX);
2189
2190
    /* .. and the de-tabified tab */
2191
0
    strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth));
2192
2193
    /* Skip over the printed part .. */
2194
0
    linelen -= tab + 1 - line;
2195
0
    line = tab + 1;
2196
0
  }
2197
2198
  /*
2199
   * Print out everything after the last tab without
2200
   * worrying about width - there's nothing more to
2201
   * align.
2202
   */
2203
0
  append_line_with_color(sb, opt, line, linelen, color, GREP_CONTEXT_BODY,
2204
0
             GREP_HEADER_FIELD_MAX);
2205
0
}
2206
2207
/*
2208
 * pp_handle_indent() prints out the intendation, and
2209
 * the whole line (without the final newline), after
2210
 * de-tabifying.
2211
 */
2212
static void pp_handle_indent(struct pretty_print_context *pp,
2213
           struct strbuf *sb, int indent,
2214
           const char *line, int linelen)
2215
0
{
2216
0
  struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
2217
2218
0
  strbuf_addchars(sb, ' ', indent);
2219
0
  if (pp->expand_tabs_in_log)
2220
0
    strbuf_add_tabexpand(sb, opt, pp->color, pp->expand_tabs_in_log,
2221
0
             line, linelen);
2222
0
  else
2223
0
    append_line_with_color(sb, opt, line, linelen, pp->color,
2224
0
               GREP_CONTEXT_BODY,
2225
0
               GREP_HEADER_FIELD_MAX);
2226
0
}
2227
2228
static int is_mboxrd_from(const char *line, int len)
2229
0
{
2230
  /*
2231
   * a line matching /^From $/ here would only have len == 4
2232
   * at this point because is_empty_line would've trimmed all
2233
   * trailing space
2234
   */
2235
0
  return len > 4 && starts_with(line + strspn(line, ">"), "From ");
2236
0
}
2237
2238
void pp_remainder(struct pretty_print_context *pp,
2239
      const char **msg_p,
2240
      struct strbuf *sb,
2241
      int indent)
2242
0
{
2243
0
  struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL;
2244
0
  int first = 1;
2245
2246
0
  for (;;) {
2247
0
    const char *line = *msg_p;
2248
0
    int linelen = get_one_line(line);
2249
0
    *msg_p += linelen;
2250
2251
0
    if (!linelen)
2252
0
      break;
2253
2254
0
    if (is_blank_line(line, &linelen)) {
2255
0
      if (first)
2256
0
        continue;
2257
0
      if (pp->fmt == CMIT_FMT_SHORT)
2258
0
        break;
2259
0
    }
2260
0
    first = 0;
2261
2262
0
    strbuf_grow(sb, linelen + indent + 20);
2263
0
    if (indent)
2264
0
      pp_handle_indent(pp, sb, indent, line, linelen);
2265
0
    else if (pp->expand_tabs_in_log)
2266
0
      strbuf_add_tabexpand(sb, opt, pp->color,
2267
0
               pp->expand_tabs_in_log, line,
2268
0
               linelen);
2269
0
    else {
2270
0
      if (pp->fmt == CMIT_FMT_MBOXRD &&
2271
0
          is_mboxrd_from(line, linelen))
2272
0
        strbuf_addch(sb, '>');
2273
2274
0
      append_line_with_color(sb, opt, line, linelen,
2275
0
                 pp->color, GREP_CONTEXT_BODY,
2276
0
                 GREP_HEADER_FIELD_MAX);
2277
0
    }
2278
0
    strbuf_addch(sb, '\n');
2279
0
  }
2280
0
}
2281
2282
void pretty_print_commit(struct pretty_print_context *pp,
2283
       const struct commit *commit,
2284
       struct strbuf *sb)
2285
0
{
2286
0
  unsigned long beginning_of_body;
2287
0
  int indent = 4;
2288
0
  const char *msg;
2289
0
  const char *reencoded;
2290
0
  const char *encoding;
2291
0
  int need_8bit_cte = pp->need_8bit_cte;
2292
2293
0
  if (pp->fmt == CMIT_FMT_USERFORMAT) {
2294
0
    repo_format_commit_message(the_repository, commit,
2295
0
             user_format, sb, pp);
2296
0
    return;
2297
0
  }
2298
2299
0
  encoding = get_log_output_encoding();
2300
0
  msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL,
2301
0
                 encoding);
2302
2303
0
  if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
2304
0
    indent = 0;
2305
2306
  /*
2307
   * We need to check and emit Content-type: to mark it
2308
   * as 8-bit if we haven't done so.
2309
   */
2310
0
  if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {
2311
0
    int i, ch, in_body;
2312
2313
0
    for (in_body = i = 0; (ch = msg[i]); i++) {
2314
0
      if (!in_body) {
2315
        /* author could be non 7-bit ASCII but
2316
         * the log may be so; skip over the
2317
         * header part first.
2318
         */
2319
0
        if (ch == '\n' && msg[i+1] == '\n')
2320
0
          in_body = 1;
2321
0
      }
2322
0
      else if (non_ascii(ch)) {
2323
0
        need_8bit_cte = 1;
2324
0
        break;
2325
0
      }
2326
0
    }
2327
0
  }
2328
2329
0
  pp_header(pp, encoding, commit, &msg, sb);
2330
0
  if (pp->fmt != CMIT_FMT_ONELINE && !cmit_fmt_is_mail(pp->fmt)) {
2331
0
    strbuf_addch(sb, '\n');
2332
0
  }
2333
2334
  /* Skip excess blank lines at the beginning of body, if any... */
2335
0
  msg = skip_blank_lines(msg);
2336
2337
  /* These formats treat the title line specially. */
2338
0
  if (pp->fmt == CMIT_FMT_ONELINE) {
2339
0
    msg = format_subject(sb, msg, " ");
2340
0
    strbuf_addch(sb, '\n');
2341
0
  } else if (cmit_fmt_is_mail(pp->fmt))
2342
0
    pp_email_subject(pp, &msg, sb, encoding, need_8bit_cte);
2343
2344
0
  beginning_of_body = sb->len;
2345
0
  if (pp->fmt != CMIT_FMT_ONELINE)
2346
0
    pp_remainder(pp, &msg, sb, indent);
2347
0
  strbuf_rtrim(sb);
2348
2349
  /* Make sure there is an EOLN for the non-oneline case */
2350
0
  if (pp->fmt != CMIT_FMT_ONELINE)
2351
0
    strbuf_addch(sb, '\n');
2352
2353
  /*
2354
   * The caller may append additional body text in e-mail
2355
   * format.  Make sure we did not strip the blank line
2356
   * between the header and the body.
2357
   */
2358
0
  if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
2359
0
    strbuf_addch(sb, '\n');
2360
2361
0
  repo_unuse_commit_buffer(the_repository, commit, reencoded);
2362
0
}
2363
2364
void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
2365
        struct strbuf *sb)
2366
0
{
2367
0
  struct pretty_print_context pp = {0};
2368
0
  pp.fmt = fmt;
2369
0
  pretty_print_commit(&pp, commit, sb);
2370
0
}