@@ -181,6 +181,20 @@ static int is_empty_line(const char *line, int *len_p)
181181 return !len ;
182182}
183183
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+
184198static void add_merge_info (enum cmit_fmt fmt , struct strbuf * sb ,
185199 const struct commit * commit , int abbrev )
186200{
@@ -410,13 +424,15 @@ struct chunk {
410424struct format_commit_context {
411425 const struct commit * commit ;
412426 enum date_mode dmode ;
427+ unsigned commit_header_parsed :1 ;
428+ unsigned commit_message_parsed :1 ;
413429
414430 /* These offsets are relative to the start of the commit message. */
415- int commit_header_parsed ;
416- struct chunk subject ;
417431 struct chunk author ;
418432 struct chunk committer ;
419433 struct chunk encoding ;
434+ size_t message_off ;
435+ size_t subject_off ;
420436 size_t body_off ;
421437
422438 /* The following ones are relative to the result struct strbuf. */
@@ -446,23 +462,14 @@ static void parse_commit_header(struct format_commit_context *context)
446462{
447463 const char * msg = context -> commit -> buffer ;
448464 int i ;
449- enum { HEADER , SUBJECT , BODY } state ;
450465
451- for (i = 0 , state = HEADER ; msg [i ] && state < BODY ; i ++ ) {
466+ for (i = 0 ; msg [i ]; i ++ ) {
452467 int eol ;
453468 for (eol = i ; msg [eol ] && msg [eol ] != '\n' ; eol ++ )
454469 ; /* do nothing */
455470
456- if (state == SUBJECT ) {
457- context -> subject .off = i ;
458- context -> subject .len = eol - i ;
459- i = eol ;
460- }
461471 if (i == eol ) {
462- state ++ ;
463- /* strip empty lines */
464- while (msg [eol ] == '\n' && msg [eol + 1 ] == '\n' )
465- eol ++ ;
472+ break ;
466473 } else if (!prefixcmp (msg + i , "author " )) {
467474 context -> author .off = i + 7 ;
468475 context -> author .len = eol - i - 7 ;
@@ -474,13 +481,50 @@ static void parse_commit_header(struct format_commit_context *context)
474481 context -> encoding .len = eol - i - 9 ;
475482 }
476483 i = eol ;
477- if (!msg [i ])
478- break ;
479484 }
480- context -> body_off = i ;
485+ context -> message_off = i ;
481486 context -> commit_header_parsed = 1 ;
482487}
483488
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+
484528static void format_decoration (struct strbuf * sb , const struct commit * commit )
485529{
486530 struct name_decoration * d ;
@@ -600,9 +644,6 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
600644 parse_commit_header (c );
601645
602646 switch (placeholder [0 ]) {
603- case 's' : /* subject */
604- strbuf_add (sb , msg + c -> subject .off , c -> subject .len );
605- return 1 ;
606647 case 'a' : /* author ... */
607648 return format_person_part (sb , placeholder [1 ],
608649 msg + c -> author .off , c -> author .len ,
@@ -614,6 +655,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
614655 case 'e' : /* encoding */
615656 strbuf_add (sb , msg + c -> encoding .off , c -> encoding .len );
616657 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 ;
617668 case 'b' : /* body */
618669 strbuf_addstr (sb , msg + c -> body_off );
619670 return 1 ;
@@ -704,27 +755,11 @@ void pp_title_line(enum cmit_fmt fmt,
704755 const char * encoding ,
705756 int need_8bit_cte )
706757{
758+ const char * line_separator = (fmt == CMIT_FMT_EMAIL ) ? "\n " : " " ;
707759 struct strbuf title ;
708760
709761 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 );
728763
729764 strbuf_grow (sb , title .len + 1024 );
730765 if (subject ) {
@@ -850,15 +885,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
850885 }
851886
852887 /* 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 );
862889
863890 /* These formats treat the title line specially. */
864891 if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL )
0 commit comments