Merge branch 'bc/filter-branch'
[git] / pretty.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "utf8.h"
4 #include "diff.h"
5 #include "revision.h"
6
7 static char *user_format;
8
9 void get_commit_format(const char *arg, struct rev_info *rev)
10 {
11         int i;
12         static struct cmt_fmt_map {
13                 const char *n;
14                 size_t cmp_len;
15                 enum cmit_fmt v;
16         } cmt_fmts[] = {
17                 { "raw",        1,      CMIT_FMT_RAW },
18                 { "medium",     1,      CMIT_FMT_MEDIUM },
19                 { "short",      1,      CMIT_FMT_SHORT },
20                 { "email",      1,      CMIT_FMT_EMAIL },
21                 { "full",       5,      CMIT_FMT_FULL },
22                 { "fuller",     5,      CMIT_FMT_FULLER },
23                 { "oneline",    1,      CMIT_FMT_ONELINE },
24         };
25
26         rev->use_terminator = 0;
27         if (!arg || !*arg) {
28                 rev->commit_format = CMIT_FMT_DEFAULT;
29                 return;
30         }
31         if (*arg == '=')
32                 arg++;
33         if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
34                 const char *cp = strchr(arg, ':') + 1;
35                 free(user_format);
36                 user_format = xstrdup(cp);
37                 if (arg[0] == 't')
38                         rev->use_terminator = 1;
39                 rev->commit_format = CMIT_FMT_USERFORMAT;
40                 return;
41         }
42         for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
43                 if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
44                     !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
45                         if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
46                                 rev->use_terminator = 1;
47                         rev->commit_format = cmt_fmts[i].v;
48                         return;
49                 }
50         }
51
52         die("invalid --pretty format: %s", arg);
53 }
54
55 /*
56  * Generic support for pretty-printing the header
57  */
58 static int get_one_line(const char *msg)
59 {
60         int ret = 0;
61
62         for (;;) {
63                 char c = *msg++;
64                 if (!c)
65                         break;
66                 ret++;
67                 if (c == '\n')
68                         break;
69         }
70         return ret;
71 }
72
73 /* High bit set, or ISO-2022-INT */
74 int non_ascii(int ch)
75 {
76         ch = (ch & 0xff);
77         return ((ch & 0x80) || (ch == 0x1b));
78 }
79
80 static int is_rfc2047_special(char ch)
81 {
82         return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
83 }
84
85 static void add_rfc2047(struct strbuf *sb, const char *line, int len,
86                        const char *encoding)
87 {
88         int i, last;
89
90         for (i = 0; i < len; i++) {
91                 int ch = line[i];
92                 if (non_ascii(ch))
93                         goto needquote;
94                 if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
95                         goto needquote;
96         }
97         strbuf_add(sb, line, len);
98         return;
99
100 needquote:
101         strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
102         strbuf_addf(sb, "=?%s?q?", encoding);
103         for (i = last = 0; i < len; i++) {
104                 unsigned ch = line[i] & 0xFF;
105                 /*
106                  * We encode ' ' using '=20' even though rfc2047
107                  * allows using '_' for readability.  Unfortunately,
108                  * many programs do not understand this and just
109                  * leave the underscore in place.
110                  */
111                 if (is_rfc2047_special(ch) || ch == ' ') {
112                         strbuf_add(sb, line + last, i - last);
113                         strbuf_addf(sb, "=%02X", ch);
114                         last = i + 1;
115                 }
116         }
117         strbuf_add(sb, line + last, len - last);
118         strbuf_addstr(sb, "?=");
119 }
120
121 void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
122                   const char *line, enum date_mode dmode,
123                   const char *encoding)
124 {
125         char *date;
126         int namelen;
127         unsigned long time;
128         int tz;
129         const char *filler = "    ";
130
131         if (fmt == CMIT_FMT_ONELINE)
132                 return;
133         date = strchr(line, '>');
134         if (!date)
135                 return;
136         namelen = ++date - line;
137         time = strtoul(date, &date, 10);
138         tz = strtol(date, NULL, 10);
139
140         if (fmt == CMIT_FMT_EMAIL) {
141                 char *name_tail = strchr(line, '<');
142                 int display_name_length;
143                 if (!name_tail)
144                         return;
145                 while (line < name_tail && isspace(name_tail[-1]))
146                         name_tail--;
147                 display_name_length = name_tail - line;
148                 filler = "";
149                 strbuf_addstr(sb, "From: ");
150                 add_rfc2047(sb, line, display_name_length, encoding);
151                 strbuf_add(sb, name_tail, namelen - display_name_length);
152                 strbuf_addch(sb, '\n');
153         } else {
154                 strbuf_addf(sb, "%s: %.*s%.*s\n", what,
155                               (fmt == CMIT_FMT_FULLER) ? 4 : 0,
156                               filler, namelen, line);
157         }
158         switch (fmt) {
159         case CMIT_FMT_MEDIUM:
160                 strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, dmode));
161                 break;
162         case CMIT_FMT_EMAIL:
163                 strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
164                 break;
165         case CMIT_FMT_FULLER:
166                 strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
167                 break;
168         default:
169                 /* notin' */
170                 break;
171         }
172 }
173
174 static int is_empty_line(const char *line, int *len_p)
175 {
176         int len = *len_p;
177         while (len && isspace(line[len-1]))
178                 len--;
179         *len_p = len;
180         return !len;
181 }
182
183 static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
184                         const struct commit *commit, int abbrev)
185 {
186         struct commit_list *parent = commit->parents;
187
188         if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
189             !parent || !parent->next)
190                 return;
191
192         strbuf_addstr(sb, "Merge:");
193
194         while (parent) {
195                 struct commit *p = parent->item;
196                 const char *hex = NULL;
197                 const char *dots;
198                 if (abbrev)
199                         hex = find_unique_abbrev(p->object.sha1, abbrev);
200                 if (!hex)
201                         hex = sha1_to_hex(p->object.sha1);
202                 dots = (abbrev && strlen(hex) != 40) ?  "..." : "";
203                 parent = parent->next;
204
205                 strbuf_addf(sb, " %s%s", hex, dots);
206         }
207         strbuf_addch(sb, '\n');
208 }
209
210 static char *get_header(const struct commit *commit, const char *key)
211 {
212         int key_len = strlen(key);
213         const char *line = commit->buffer;
214
215         for (;;) {
216                 const char *eol = strchr(line, '\n'), *next;
217
218                 if (line == eol)
219                         return NULL;
220                 if (!eol) {
221                         eol = line + strlen(line);
222                         next = NULL;
223                 } else
224                         next = eol + 1;
225                 if (eol - line > key_len &&
226                     !strncmp(line, key, key_len) &&
227                     line[key_len] == ' ') {
228                         return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
229                 }
230                 line = next;
231         }
232 }
233
234 static char *replace_encoding_header(char *buf, const char *encoding)
235 {
236         struct strbuf tmp;
237         size_t start, len;
238         char *cp = buf;
239
240         /* guess if there is an encoding header before a \n\n */
241         while (strncmp(cp, "encoding ", strlen("encoding "))) {
242                 cp = strchr(cp, '\n');
243                 if (!cp || *++cp == '\n')
244                         return buf;
245         }
246         start = cp - buf;
247         cp = strchr(cp, '\n');
248         if (!cp)
249                 return buf; /* should not happen but be defensive */
250         len = cp + 1 - (buf + start);
251
252         strbuf_init(&tmp, 0);
253         strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
254         if (is_encoding_utf8(encoding)) {
255                 /* we have re-coded to UTF-8; drop the header */
256                 strbuf_remove(&tmp, start, len);
257         } else {
258                 /* just replaces XXXX in 'encoding XXXX\n' */
259                 strbuf_splice(&tmp, start + strlen("encoding "),
260                                           len - strlen("encoding \n"),
261                                           encoding, strlen(encoding));
262         }
263         return strbuf_detach(&tmp, NULL);
264 }
265
266 static char *logmsg_reencode(const struct commit *commit,
267                              const char *output_encoding)
268 {
269         static const char *utf8 = "utf-8";
270         const char *use_encoding;
271         char *encoding;
272         char *out;
273
274         if (!*output_encoding)
275                 return NULL;
276         encoding = get_header(commit, "encoding");
277         use_encoding = encoding ? encoding : utf8;
278         if (!strcmp(use_encoding, output_encoding))
279                 if (encoding) /* we'll strip encoding header later */
280                         out = xstrdup(commit->buffer);
281                 else
282                         return NULL; /* nothing to do */
283         else
284                 out = reencode_string(commit->buffer,
285                                       output_encoding, use_encoding);
286         if (out)
287                 out = replace_encoding_header(out, output_encoding);
288
289         free(encoding);
290         return out;
291 }
292
293 static size_t format_person_part(struct strbuf *sb, char part,
294                                const char *msg, int len)
295 {
296         /* currently all placeholders have same length */
297         const int placeholder_len = 2;
298         int start, end, tz = 0;
299         unsigned long date = 0;
300         char *ep;
301
302         /* advance 'end' to point to email start delimiter */
303         for (end = 0; end < len && msg[end] != '<'; end++)
304                 ; /* do nothing */
305
306         /*
307          * When end points at the '<' that we found, it should have
308          * matching '>' later, which means 'end' must be strictly
309          * below len - 1.
310          */
311         if (end >= len - 2)
312                 goto skip;
313
314         if (part == 'n') {      /* name */
315                 while (end > 0 && isspace(msg[end - 1]))
316                         end--;
317                 strbuf_add(sb, msg, end);
318                 return placeholder_len;
319         }
320         start = ++end; /* save email start position */
321
322         /* advance 'end' to point to email end delimiter */
323         for ( ; end < len && msg[end] != '>'; end++)
324                 ; /* do nothing */
325
326         if (end >= len)
327                 goto skip;
328
329         if (part == 'e') {      /* email */
330                 strbuf_add(sb, msg + start, end - start);
331                 return placeholder_len;
332         }
333
334         /* advance 'start' to point to date start delimiter */
335         for (start = end + 1; start < len && isspace(msg[start]); start++)
336                 ; /* do nothing */
337         if (start >= len)
338                 goto skip;
339         date = strtoul(msg + start, &ep, 10);
340         if (msg + start == ep)
341                 goto skip;
342
343         if (part == 't') {      /* date, UNIX timestamp */
344                 strbuf_add(sb, msg + start, ep - (msg + start));
345                 return placeholder_len;
346         }
347
348         /* parse tz */
349         for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
350                 ; /* do nothing */
351         if (start + 1 < len) {
352                 tz = strtoul(msg + start + 1, NULL, 10);
353                 if (msg[start] == '-')
354                         tz = -tz;
355         }
356
357         switch (part) {
358         case 'd':       /* date */
359                 strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
360                 return placeholder_len;
361         case 'D':       /* date, RFC2822 style */
362                 strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
363                 return placeholder_len;
364         case 'r':       /* date, relative */
365                 strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
366                 return placeholder_len;
367         case 'i':       /* date, ISO 8601 */
368                 strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
369                 return placeholder_len;
370         }
371
372 skip:
373         /*
374          * bogus commit, 'sb' cannot be updated, but we still need to
375          * compute a valid return value.
376          */
377         if (part == 'n' || part == 'e' || part == 't' || part == 'd'
378             || part == 'D' || part == 'r' || part == 'i')
379                 return placeholder_len;
380
381         return 0; /* unknown placeholder */
382 }
383
384 struct chunk {
385         size_t off;
386         size_t len;
387 };
388
389 struct format_commit_context {
390         const struct commit *commit;
391
392         /* These offsets are relative to the start of the commit message. */
393         int commit_header_parsed;
394         struct chunk subject;
395         struct chunk author;
396         struct chunk committer;
397         struct chunk encoding;
398         size_t body_off;
399
400         /* The following ones are relative to the result struct strbuf. */
401         struct chunk abbrev_commit_hash;
402         struct chunk abbrev_tree_hash;
403         struct chunk abbrev_parent_hashes;
404 };
405
406 static int add_again(struct strbuf *sb, struct chunk *chunk)
407 {
408         if (chunk->len) {
409                 strbuf_adddup(sb, chunk->off, chunk->len);
410                 return 1;
411         }
412
413         /*
414          * We haven't seen this chunk before.  Our caller is surely
415          * going to add it the hard way now.  Remember the most likely
416          * start of the to-be-added chunk: the current end of the
417          * struct strbuf.
418          */
419         chunk->off = sb->len;
420         return 0;
421 }
422
423 static void parse_commit_header(struct format_commit_context *context)
424 {
425         const char *msg = context->commit->buffer;
426         int i;
427         enum { HEADER, SUBJECT, BODY } state;
428
429         for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
430                 int eol;
431                 for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
432                         ; /* do nothing */
433
434                 if (state == SUBJECT) {
435                         context->subject.off = i;
436                         context->subject.len = eol - i;
437                         i = eol;
438                 }
439                 if (i == eol) {
440                         state++;
441                         /* strip empty lines */
442                         while (msg[eol] == '\n' && msg[eol + 1] == '\n')
443                                 eol++;
444                 } else if (!prefixcmp(msg + i, "author ")) {
445                         context->author.off = i + 7;
446                         context->author.len = eol - i - 7;
447                 } else if (!prefixcmp(msg + i, "committer ")) {
448                         context->committer.off = i + 10;
449                         context->committer.len = eol - i - 10;
450                 } else if (!prefixcmp(msg + i, "encoding ")) {
451                         context->encoding.off = i + 9;
452                         context->encoding.len = eol - i - 9;
453                 }
454                 i = eol;
455                 if (!msg[i])
456                         break;
457         }
458         context->body_off = i;
459         context->commit_header_parsed = 1;
460 }
461
462 static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
463                                void *context)
464 {
465         struct format_commit_context *c = context;
466         const struct commit *commit = c->commit;
467         const char *msg = commit->buffer;
468         struct commit_list *p;
469         int h1, h2;
470
471         /* these are independent of the commit */
472         switch (placeholder[0]) {
473         case 'C':
474                 if (!prefixcmp(placeholder + 1, "red")) {
475                         strbuf_addstr(sb, "\033[31m");
476                         return 4;
477                 } else if (!prefixcmp(placeholder + 1, "green")) {
478                         strbuf_addstr(sb, "\033[32m");
479                         return 6;
480                 } else if (!prefixcmp(placeholder + 1, "blue")) {
481                         strbuf_addstr(sb, "\033[34m");
482                         return 5;
483                 } else if (!prefixcmp(placeholder + 1, "reset")) {
484                         strbuf_addstr(sb, "\033[m");
485                         return 6;
486                 } else
487                         return 0;
488         case 'n':               /* newline */
489                 strbuf_addch(sb, '\n');
490                 return 1;
491         case 'x':
492                 /* %x00 == NUL, %x0a == LF, etc. */
493                 if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
494                     h1 <= 16 &&
495                     0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
496                     h2 <= 16) {
497                         strbuf_addch(sb, (h1<<4)|h2);
498                         return 3;
499                 } else
500                         return 0;
501         }
502
503         /* these depend on the commit */
504         if (!commit->object.parsed)
505                 parse_object(commit->object.sha1);
506
507         switch (placeholder[0]) {
508         case 'H':               /* commit hash */
509                 strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
510                 return 1;
511         case 'h':               /* abbreviated commit hash */
512                 if (add_again(sb, &c->abbrev_commit_hash))
513                         return 1;
514                 strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
515                                                      DEFAULT_ABBREV));
516                 c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
517                 return 1;
518         case 'T':               /* tree hash */
519                 strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
520                 return 1;
521         case 't':               /* abbreviated tree hash */
522                 if (add_again(sb, &c->abbrev_tree_hash))
523                         return 1;
524                 strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
525                                                      DEFAULT_ABBREV));
526                 c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
527                 return 1;
528         case 'P':               /* parent hashes */
529                 for (p = commit->parents; p; p = p->next) {
530                         if (p != commit->parents)
531                                 strbuf_addch(sb, ' ');
532                         strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
533                 }
534                 return 1;
535         case 'p':               /* abbreviated parent hashes */
536                 if (add_again(sb, &c->abbrev_parent_hashes))
537                         return 1;
538                 for (p = commit->parents; p; p = p->next) {
539                         if (p != commit->parents)
540                                 strbuf_addch(sb, ' ');
541                         strbuf_addstr(sb, find_unique_abbrev(
542                                         p->item->object.sha1, DEFAULT_ABBREV));
543                 }
544                 c->abbrev_parent_hashes.len = sb->len -
545                                               c->abbrev_parent_hashes.off;
546                 return 1;
547         case 'm':               /* left/right/bottom */
548                 strbuf_addch(sb, (commit->object.flags & BOUNDARY)
549                                  ? '-'
550                                  : (commit->object.flags & SYMMETRIC_LEFT)
551                                  ? '<'
552                                  : '>');
553                 return 1;
554         }
555
556         /* For the rest we have to parse the commit header. */
557         if (!c->commit_header_parsed)
558                 parse_commit_header(c);
559
560         switch (placeholder[0]) {
561         case 's':       /* subject */
562                 strbuf_add(sb, msg + c->subject.off, c->subject.len);
563                 return 1;
564         case 'a':       /* author ... */
565                 return format_person_part(sb, placeholder[1],
566                                    msg + c->author.off, c->author.len);
567         case 'c':       /* committer ... */
568                 return format_person_part(sb, placeholder[1],
569                                    msg + c->committer.off, c->committer.len);
570         case 'e':       /* encoding */
571                 strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
572                 return 1;
573         case 'b':       /* body */
574                 strbuf_addstr(sb, msg + c->body_off);
575                 return 1;
576         }
577         return 0;       /* unknown placeholder */
578 }
579
580 void format_commit_message(const struct commit *commit,
581                            const void *format, struct strbuf *sb)
582 {
583         struct format_commit_context context;
584
585         memset(&context, 0, sizeof(context));
586         context.commit = commit;
587         strbuf_expand(sb, format, format_commit_item, &context);
588 }
589
590 static void pp_header(enum cmit_fmt fmt,
591                       int abbrev,
592                       enum date_mode dmode,
593                       const char *encoding,
594                       const struct commit *commit,
595                       const char **msg_p,
596                       struct strbuf *sb)
597 {
598         int parents_shown = 0;
599
600         for (;;) {
601                 const char *line = *msg_p;
602                 int linelen = get_one_line(*msg_p);
603
604                 if (!linelen)
605                         return;
606                 *msg_p += linelen;
607
608                 if (linelen == 1)
609                         /* End of header */
610                         return;
611
612                 if (fmt == CMIT_FMT_RAW) {
613                         strbuf_add(sb, line, linelen);
614                         continue;
615                 }
616
617                 if (!memcmp(line, "parent ", 7)) {
618                         if (linelen != 48)
619                                 die("bad parent line in commit");
620                         continue;
621                 }
622
623                 if (!parents_shown) {
624                         struct commit_list *parent;
625                         int num;
626                         for (parent = commit->parents, num = 0;
627                              parent;
628                              parent = parent->next, num++)
629                                 ;
630                         /* with enough slop */
631                         strbuf_grow(sb, num * 50 + 20);
632                         add_merge_info(fmt, sb, commit, abbrev);
633                         parents_shown = 1;
634                 }
635
636                 /*
637                  * MEDIUM == DEFAULT shows only author with dates.
638                  * FULL shows both authors but not dates.
639                  * FULLER shows both authors and dates.
640                  */
641                 if (!memcmp(line, "author ", 7)) {
642                         strbuf_grow(sb, linelen + 80);
643                         pp_user_info("Author", fmt, sb, line + 7, dmode, encoding);
644                 }
645                 if (!memcmp(line, "committer ", 10) &&
646                     (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
647                         strbuf_grow(sb, linelen + 80);
648                         pp_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
649                 }
650         }
651 }
652
653 void pp_title_line(enum cmit_fmt fmt,
654                    const char **msg_p,
655                    struct strbuf *sb,
656                    const char *subject,
657                    const char *after_subject,
658                    const char *encoding,
659                    int need_8bit_cte)
660 {
661         struct strbuf title;
662
663         strbuf_init(&title, 80);
664
665         for (;;) {
666                 const char *line = *msg_p;
667                 int linelen = get_one_line(line);
668
669                 *msg_p += linelen;
670                 if (!linelen || is_empty_line(line, &linelen))
671                         break;
672
673                 strbuf_grow(&title, linelen + 2);
674                 if (title.len) {
675                         if (fmt == CMIT_FMT_EMAIL) {
676                                 strbuf_addch(&title, '\n');
677                         }
678                         strbuf_addch(&title, ' ');
679                 }
680                 strbuf_add(&title, line, linelen);
681         }
682
683         strbuf_grow(sb, title.len + 1024);
684         if (subject) {
685                 strbuf_addstr(sb, subject);
686                 add_rfc2047(sb, title.buf, title.len, encoding);
687         } else {
688                 strbuf_addbuf(sb, &title);
689         }
690         strbuf_addch(sb, '\n');
691
692         if (need_8bit_cte > 0) {
693                 const char *header_fmt =
694                         "MIME-Version: 1.0\n"
695                         "Content-Type: text/plain; charset=%s\n"
696                         "Content-Transfer-Encoding: 8bit\n";
697                 strbuf_addf(sb, header_fmt, encoding);
698         }
699         if (after_subject) {
700                 strbuf_addstr(sb, after_subject);
701         }
702         if (fmt == CMIT_FMT_EMAIL) {
703                 strbuf_addch(sb, '\n');
704         }
705         strbuf_release(&title);
706 }
707
708 void pp_remainder(enum cmit_fmt fmt,
709                   const char **msg_p,
710                   struct strbuf *sb,
711                   int indent)
712 {
713         int first = 1;
714         for (;;) {
715                 const char *line = *msg_p;
716                 int linelen = get_one_line(line);
717                 *msg_p += linelen;
718
719                 if (!linelen)
720                         break;
721
722                 if (is_empty_line(line, &linelen)) {
723                         if (first)
724                                 continue;
725                         if (fmt == CMIT_FMT_SHORT)
726                                 break;
727                 }
728                 first = 0;
729
730                 strbuf_grow(sb, linelen + indent + 20);
731                 if (indent) {
732                         memset(sb->buf + sb->len, ' ', indent);
733                         strbuf_setlen(sb, sb->len + indent);
734                 }
735                 strbuf_add(sb, line, linelen);
736                 strbuf_addch(sb, '\n');
737         }
738 }
739
740 void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
741                          struct strbuf *sb, int abbrev,
742                          const char *subject, const char *after_subject,
743                          enum date_mode dmode, int need_8bit_cte)
744 {
745         unsigned long beginning_of_body;
746         int indent = 4;
747         const char *msg = commit->buffer;
748         char *reencoded;
749         const char *encoding;
750
751         if (fmt == CMIT_FMT_USERFORMAT) {
752                 format_commit_message(commit, user_format, sb);
753                 return;
754         }
755
756         encoding = (git_log_output_encoding
757                     ? git_log_output_encoding
758                     : git_commit_encoding);
759         if (!encoding)
760                 encoding = "utf-8";
761         reencoded = logmsg_reencode(commit, encoding);
762         if (reencoded) {
763                 msg = reencoded;
764         }
765
766         if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
767                 indent = 0;
768
769         /*
770          * We need to check and emit Content-type: to mark it
771          * as 8-bit if we haven't done so.
772          */
773         if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
774                 int i, ch, in_body;
775
776                 for (in_body = i = 0; (ch = msg[i]); i++) {
777                         if (!in_body) {
778                                 /* author could be non 7-bit ASCII but
779                                  * the log may be so; skip over the
780                                  * header part first.
781                                  */
782                                 if (ch == '\n' && msg[i+1] == '\n')
783                                         in_body = 1;
784                         }
785                         else if (non_ascii(ch)) {
786                                 need_8bit_cte = 1;
787                                 break;
788                         }
789                 }
790         }
791
792         pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
793         if (fmt != CMIT_FMT_ONELINE && !subject) {
794                 strbuf_addch(sb, '\n');
795         }
796
797         /* Skip excess blank lines at the beginning of body, if any... */
798         for (;;) {
799                 int linelen = get_one_line(msg);
800                 int ll = linelen;
801                 if (!linelen)
802                         break;
803                 if (!is_empty_line(msg, &ll))
804                         break;
805                 msg += linelen;
806         }
807
808         /* These formats treat the title line specially. */
809         if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
810                 pp_title_line(fmt, &msg, sb, subject,
811                               after_subject, encoding, need_8bit_cte);
812
813         beginning_of_body = sb->len;
814         if (fmt != CMIT_FMT_ONELINE)
815                 pp_remainder(fmt, &msg, sb, indent);
816         strbuf_rtrim(sb);
817
818         /* Make sure there is an EOLN for the non-oneline case */
819         if (fmt != CMIT_FMT_ONELINE)
820                 strbuf_addch(sb, '\n');
821
822         /*
823          * The caller may append additional body text in e-mail
824          * format.  Make sure we did not strip the blank line
825          * between the header and the body.
826          */
827         if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
828                 strbuf_addch(sb, '\n');
829         free(reencoded);
830 }