@@ -181,6 +181,20 @@ static int is_empty_line(const char *line, int *len_p)
181
181
return !len ;
182
182
}
183
183
184
+ static const char * skip_empty_lines (const char * msg )
185
+ {
186
+ for (;;) {
187
+ int linelen = get_one_line (msg );
188
+ int ll = linelen ;
189
+ if (!linelen )
190
+ break ;
191
+ if (!is_empty_line (msg , & ll ))
192
+ break ;
193
+ msg += linelen ;
194
+ }
195
+ return msg ;
196
+ }
197
+
184
198
static void add_merge_info (enum cmit_fmt fmt , struct strbuf * sb ,
185
199
const struct commit * commit , int abbrev )
186
200
{
@@ -410,13 +424,15 @@ struct chunk {
410
424
struct format_commit_context {
411
425
const struct commit * commit ;
412
426
enum date_mode dmode ;
427
+ unsigned commit_header_parsed :1 ;
428
+ unsigned commit_message_parsed :1 ;
413
429
414
430
/* These offsets are relative to the start of the commit message. */
415
- int commit_header_parsed ;
416
- struct chunk subject ;
417
431
struct chunk author ;
418
432
struct chunk committer ;
419
433
struct chunk encoding ;
434
+ size_t message_off ;
435
+ size_t subject_off ;
420
436
size_t body_off ;
421
437
422
438
/* The following ones are relative to the result struct strbuf. */
@@ -446,23 +462,14 @@ static void parse_commit_header(struct format_commit_context *context)
446
462
{
447
463
const char * msg = context -> commit -> buffer ;
448
464
int i ;
449
- enum { HEADER , SUBJECT , BODY } state ;
450
465
451
- for (i = 0 , state = HEADER ; msg [i ] && state < BODY ; i ++ ) {
466
+ for (i = 0 ; msg [i ]; i ++ ) {
452
467
int eol ;
453
468
for (eol = i ; msg [eol ] && msg [eol ] != '\n' ; eol ++ )
454
469
; /* do nothing */
455
470
456
- if (state == SUBJECT ) {
457
- context -> subject .off = i ;
458
- context -> subject .len = eol - i ;
459
- i = eol ;
460
- }
461
471
if (i == eol ) {
462
- state ++ ;
463
- /* strip empty lines */
464
- while (msg [eol ] == '\n' && msg [eol + 1 ] == '\n' )
465
- eol ++ ;
472
+ break ;
466
473
} else if (!prefixcmp (msg + i , "author " )) {
467
474
context -> author .off = i + 7 ;
468
475
context -> author .len = eol - i - 7 ;
@@ -474,13 +481,50 @@ static void parse_commit_header(struct format_commit_context *context)
474
481
context -> encoding .len = eol - i - 9 ;
475
482
}
476
483
i = eol ;
477
- if (!msg [i ])
478
- break ;
479
484
}
480
- context -> body_off = i ;
485
+ context -> message_off = i ;
481
486
context -> commit_header_parsed = 1 ;
482
487
}
483
488
489
+ static const char * format_subject (struct strbuf * sb , const char * msg ,
490
+ const char * line_separator )
491
+ {
492
+ int first = 1 ;
493
+
494
+ for (;;) {
495
+ const char * line = msg ;
496
+ int linelen = get_one_line (line );
497
+
498
+ msg += linelen ;
499
+ if (!linelen || is_empty_line (line , & linelen ))
500
+ break ;
501
+
502
+ if (!sb )
503
+ continue ;
504
+ strbuf_grow (sb , linelen + 2 );
505
+ if (!first )
506
+ strbuf_addstr (sb , line_separator );
507
+ strbuf_add (sb , line , linelen );
508
+ first = 0 ;
509
+ }
510
+ return msg ;
511
+ }
512
+
513
+ static void parse_commit_message (struct format_commit_context * c )
514
+ {
515
+ const char * msg = c -> commit -> buffer + c -> message_off ;
516
+ const char * start = c -> commit -> buffer ;
517
+
518
+ msg = skip_empty_lines (msg );
519
+ c -> subject_off = msg - start ;
520
+
521
+ msg = format_subject (NULL , msg , NULL );
522
+ msg = skip_empty_lines (msg );
523
+ c -> body_off = msg - start ;
524
+
525
+ c -> commit_message_parsed = 1 ;
526
+ }
527
+
484
528
static void format_decoration (struct strbuf * sb , const struct commit * commit )
485
529
{
486
530
struct name_decoration * d ;
@@ -600,9 +644,6 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
600
644
parse_commit_header (c );
601
645
602
646
switch (placeholder [0 ]) {
603
- case 's' : /* subject */
604
- strbuf_add (sb , msg + c -> subject .off , c -> subject .len );
605
- return 1 ;
606
647
case 'a' : /* author ... */
607
648
return format_person_part (sb , placeholder [1 ],
608
649
msg + c -> author .off , c -> author .len ,
@@ -614,6 +655,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
614
655
case 'e' : /* encoding */
615
656
strbuf_add (sb , msg + c -> encoding .off , c -> encoding .len );
616
657
return 1 ;
658
+ }
659
+
660
+ /* Now we need to parse the commit message. */
661
+ if (!c -> commit_message_parsed )
662
+ parse_commit_message (c );
663
+
664
+ switch (placeholder [0 ]) {
665
+ case 's' : /* subject */
666
+ format_subject (sb , msg + c -> subject_off , " " );
667
+ return 1 ;
617
668
case 'b' : /* body */
618
669
strbuf_addstr (sb , msg + c -> body_off );
619
670
return 1 ;
@@ -704,27 +755,11 @@ void pp_title_line(enum cmit_fmt fmt,
704
755
const char * encoding ,
705
756
int need_8bit_cte )
706
757
{
758
+ const char * line_separator = (fmt == CMIT_FMT_EMAIL ) ? "\n " : " " ;
707
759
struct strbuf title ;
708
760
709
761
strbuf_init (& title , 80 );
710
-
711
- for (;;) {
712
- const char * line = * msg_p ;
713
- int linelen = get_one_line (line );
714
-
715
- * msg_p += linelen ;
716
- if (!linelen || is_empty_line (line , & linelen ))
717
- break ;
718
-
719
- strbuf_grow (& title , linelen + 2 );
720
- if (title .len ) {
721
- if (fmt == CMIT_FMT_EMAIL ) {
722
- strbuf_addch (& title , '\n' );
723
- }
724
- strbuf_addch (& title , ' ' );
725
- }
726
- strbuf_add (& title , line , linelen );
727
- }
762
+ * msg_p = format_subject (& title , * msg_p , line_separator );
728
763
729
764
strbuf_grow (sb , title .len + 1024 );
730
765
if (subject ) {
@@ -850,15 +885,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
850
885
}
851
886
852
887
/* Skip excess blank lines at the beginning of body, if any... */
853
- for (;;) {
854
- int linelen = get_one_line (msg );
855
- int ll = linelen ;
856
- if (!linelen )
857
- break ;
858
- if (!is_empty_line (msg , & ll ))
859
- break ;
860
- msg += linelen ;
861
- }
888
+ msg = skip_empty_lines (msg );
862
889
863
890
/* These formats treat the title line specially. */
864
891
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL )
0 commit comments