]> asedeno.scripts.mit.edu Git - git.git/blob - graph.c
Add history graph API
[git.git] / graph.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "graph.h"
4 #include "diff.h"
5 #include "revision.h"
6
7 /*
8  * TODO:
9  * - Add colors to the graph.
10  *   Pick a color for each column, and print all characters
11  *   in that column with the specified color.
12  *
13  * - Limit the number of columns, similar to the way gitk does.
14  *   If we reach more than a specified number of columns, omit
15  *   sections of some columns.
16  *
17  * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states
18  *   could be made more compact by printing horizontal lines, instead of
19  *   long diagonal lines.  For example, during collapsing, something like
20  *   this:          instead of this:
21  *   | | | | |      | | | | |
22  *   | |_|_|/       | | | |/
23  *   |/| | |        | | |/|
24  *   | | | |        | |/| |
25  *                  |/| | |
26  *                  | | | |
27  *
28  *   If there are several parallel diagonal lines, they will need to be
29  *   replaced with horizontal lines on subsequent rows.
30  */
31
32 struct column {
33         /*
34          * The parent commit of this column.
35          */
36         struct commit *commit;
37         /*
38          * XXX: Once we add support for colors, struct column could also
39          * contain the color of its branch line.
40          */
41 };
42
43 enum graph_state {
44         GRAPH_PADDING,
45         GRAPH_SKIP,
46         GRAPH_PRE_COMMIT,
47         GRAPH_COMMIT,
48         GRAPH_POST_MERGE,
49         GRAPH_COLLAPSING
50 };
51
52 struct git_graph {
53         /*
54          * The commit currently being processed
55          */
56         struct commit *commit;
57         /*
58          * The number of parents this commit has.
59          * (Stored so we don't have to walk over them each time we need
60          * this number)
61          */
62         int num_parents;
63         /*
64          * The next expansion row to print
65          * when state is GRAPH_PRE_COMMIT
66          */
67         int expansion_row;
68         /*
69          * The current output state.
70          * This tells us what kind of line graph_next_line() should output.
71          */
72         enum graph_state state;
73         /*
74          * The maximum number of columns that can be stored in the columns
75          * and new_columns arrays.  This is also half the number of entries
76          * that can be stored in the mapping and new_mapping arrays.
77          */
78         int column_capacity;
79         /*
80          * The number of columns (also called "branch lines" in some places)
81          */
82         int num_columns;
83         /*
84          * The number of columns in the new_columns array
85          */
86         int num_new_columns;
87         /*
88          * The number of entries in the mapping array
89          */
90         int mapping_size;
91         /*
92          * The column state before we output the current commit.
93          */
94         struct column *columns;
95         /*
96          * The new column state after we output the current commit.
97          * Only valid when state is GRAPH_COLLAPSING.
98          */
99         struct column *new_columns;
100         /*
101          * An array that tracks the current state of each
102          * character in the output line during state GRAPH_COLLAPSING.
103          * Each entry is -1 if this character is empty, or a non-negative
104          * integer if the character contains a branch line.  The value of
105          * the integer indicates the target position for this branch line.
106          * (I.e., this array maps the current column positions to their
107          * desired positions.)
108          *
109          * The maximum capacity of this array is always
110          * sizeof(int) * 2 * column_capacity.
111          */
112         int *mapping;
113         /*
114          * A temporary array for computing the next mapping state
115          * while we are outputting a mapping line.  This is stored as part
116          * of the git_graph simply so we don't have to allocate a new
117          * temporary array each time we have to output a collapsing line.
118          */
119         int *new_mapping;
120 };
121
122 struct git_graph *graph_init(void)
123 {
124         struct git_graph *graph = xmalloc(sizeof(struct git_graph));
125         graph->commit = NULL;
126         graph->num_parents = 0;
127         graph->expansion_row = 0;
128         graph->state = GRAPH_PADDING;
129         graph->num_columns = 0;
130         graph->num_new_columns = 0;
131         graph->mapping_size = 0;
132
133         /*
134          * Allocate a reasonably large default number of columns
135          * We'll automatically grow columns later if we need more room.
136          */
137         graph->column_capacity = 30;
138         graph->columns = xmalloc(sizeof(struct column) *
139                                  graph->column_capacity);
140         graph->new_columns = xmalloc(sizeof(struct column) *
141                                      graph->column_capacity);
142         graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
143         graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
144
145         return graph;
146 }
147
148 void graph_release(struct git_graph *graph)
149 {
150         free(graph->columns);
151         free(graph->new_columns);
152         free(graph->mapping);
153         free(graph);
154 }
155
156 static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
157 {
158         if (graph->column_capacity >= num_columns)
159                 return;
160
161         do {
162                 graph->column_capacity *= 2;
163         } while (graph->column_capacity < num_columns);
164
165         graph->columns = xrealloc(graph->columns,
166                                   sizeof(struct column) *
167                                   graph->column_capacity);
168         graph->new_columns = xrealloc(graph->new_columns,
169                                       sizeof(struct column) *
170                                       graph->column_capacity);
171         graph->mapping = xrealloc(graph->mapping,
172                                   sizeof(int) * 2 * graph->column_capacity);
173         graph->new_mapping = xrealloc(graph->new_mapping,
174                                       sizeof(int) * 2 * graph->column_capacity);
175 }
176
177 static void graph_insert_into_new_columns(struct git_graph *graph,
178                                           struct commit *commit,
179                                           int *mapping_index)
180 {
181         int i;
182
183         /*
184          * Ignore uinteresting and pruned commits
185          */
186         if (commit->object.flags & (UNINTERESTING | TREESAME))
187                 return;
188
189         /*
190          * If the commit is already in the new_columns list, we don't need to
191          * add it.  Just update the mapping correctly.
192          */
193         for (i = 0; i < graph->num_new_columns; i++) {
194                 if (graph->new_columns[i].commit == commit) {
195                         graph->mapping[*mapping_index] = i;
196                         *mapping_index += 2;
197                         return;
198                 }
199         }
200
201         /*
202          * This commit isn't already in new_columns.  Add it.
203          */
204         graph->new_columns[graph->num_new_columns].commit = commit;
205         graph->mapping[*mapping_index] = graph->num_new_columns;
206         *mapping_index += 2;
207         graph->num_new_columns++;
208 }
209
210 static void graph_update_columns(struct git_graph *graph)
211 {
212         struct commit_list *parent;
213         struct column *tmp_columns;
214         int max_new_columns;
215         int mapping_idx;
216         int i, seen_this;
217
218         /*
219          * Swap graph->columns with graph->new_columns
220          * graph->columns contains the state for the previous commit,
221          * and new_columns now contains the state for our commit.
222          *
223          * We'll re-use the old columns array as storage to compute the new
224          * columns list for the commit after this one.
225          */
226         tmp_columns = graph->columns;
227         graph->columns = graph->new_columns;
228         graph->num_columns = graph->num_new_columns;
229
230         graph->new_columns = tmp_columns;
231         graph->num_new_columns = 0;
232
233         /*
234          * Now update new_columns and mapping with the information for the
235          * commit after this one.
236          *
237          * First, make sure we have enough room.  At most, there will
238          * be graph->num_columns + graph->num_parents columns for the next
239          * commit.
240          */
241         max_new_columns = graph->num_columns + graph->num_parents;
242         graph_ensure_capacity(graph, max_new_columns);
243
244         /*
245          * Clear out graph->mapping
246          */
247         graph->mapping_size = 2 * max_new_columns;
248         for (i = 0; i < graph->mapping_size; i++)
249                 graph->mapping[i] = -1;
250
251         /*
252          * Populate graph->new_columns and graph->mapping
253          *
254          * Some of the parents of this commit may already be in
255          * graph->columns.  If so, graph->new_columns should only contain a
256          * single entry for each such commit.  graph->mapping should
257          * contain information about where each current branch line is
258          * supposed to end up after the collapsing is performed.
259          */
260         seen_this = 0;
261         mapping_idx = 0;
262         for (i = 0; i <= graph->num_columns; i++) {
263                 struct commit *col_commit;
264                 if (i == graph->num_columns) {
265                         if (seen_this)
266                                 break;
267                         col_commit = graph->commit;
268                 } else {
269                         col_commit = graph->columns[i].commit;
270                 }
271
272                 if (col_commit == graph->commit) {
273                         seen_this = 1;
274                         for (parent = graph->commit->parents;
275                              parent;
276                              parent = parent->next) {
277                                 graph_insert_into_new_columns(graph,
278                                                               parent->item,
279                                                               &mapping_idx);
280                         }
281                 } else {
282                         graph_insert_into_new_columns(graph, col_commit,
283                                                       &mapping_idx);
284                 }
285         }
286
287         /*
288          * Shrink mapping_size to be the minimum necessary
289          */
290         while (graph->mapping_size > 1 &&
291                graph->mapping[graph->mapping_size - 1] < 0)
292                 graph->mapping_size--;
293 }
294
295 void graph_update(struct git_graph *graph, struct commit *commit)
296 {
297         struct commit_list *parent;
298
299         /*
300          * Set the new commit
301          */
302         graph->commit = commit;
303
304         /*
305          * Count how many parents this commit has
306          */
307         graph->num_parents = 0;
308         for (parent = commit->parents; parent; parent = parent->next)
309                 graph->num_parents++;
310
311         /*
312          * Call graph_update_columns() to update
313          * columns, new_columns, and mapping.
314          */
315         graph_update_columns(graph);
316
317         graph->expansion_row = 0;
318
319         /*
320          * Update graph->state.
321          *
322          * If the previous commit didn't get to the GRAPH_PADDING state,
323          * it never finished its output.  Goto GRAPH_SKIP, to print out
324          * a line to indicate that portion of the graph is missing.
325          *
326          * Otherwise, if there are 3 or more parents, we need to print
327          * extra rows before the commit, to expand the branch lines around
328          * it and make room for it.
329          *
330          * If there are less than 3 parents, we can immediately print the
331          * commit line.
332          */
333         if (graph->state != GRAPH_PADDING)
334                 graph->state = GRAPH_SKIP;
335         else if (graph->num_parents >= 3)
336                 graph->state = GRAPH_PRE_COMMIT;
337         else
338                 graph->state = GRAPH_COMMIT;
339 }
340
341 static int graph_is_mapping_correct(struct git_graph *graph)
342 {
343         int i;
344
345         /*
346          * The mapping is up to date if each entry is at its target,
347          * or is 1 greater than its target.
348          * (If it is 1 greater than the target, '/' will be printed, so it
349          * will look correct on the next row.)
350          */
351         for (i = 0; i < graph->mapping_size; i++) {
352                 int target = graph->mapping[i];
353                 if (target < 0)
354                         continue;
355                 if (target == (i / 2))
356                         continue;
357                 return 0;
358         }
359
360         return 1;
361 }
362
363 static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
364 {
365         /*
366          * Add additional spaces to the end of the strbuf, so that all
367          * lines for a particular commit have the same width.
368          *
369          * This way, fields printed to the right of the graph will remain
370          * aligned for the entire commit.
371          *
372          * This computation results in 3 extra space to the right in most
373          * cases, but only 1 extra space if the commit doesn't have any
374          * children that have already been displayed in the graph (i.e.,
375          * if the current commit isn't in graph->columns).
376          */
377         size_t extra;
378         size_t final_width = graph->num_columns + graph->num_parents;
379         if (graph->num_parents < 1)
380                 final_width++;
381         final_width *= 2;
382
383         if (sb->len >= final_width)
384                 return;
385
386         extra = final_width - sb->len;
387         strbuf_addf(sb, "%*s", (int) extra, "");
388 }
389
390 static void graph_output_padding_line(struct git_graph *graph,
391                                       struct strbuf *sb)
392 {
393         int i;
394
395         /*
396          * We could conceivable be called with a NULL commit
397          * if our caller has a bug, and invokes graph_next_line()
398          * immediately after graph_init(), without first calling
399          * graph_update().  Return without outputting anything in this
400          * case.
401          */
402         if (!graph->commit)
403                 return;
404
405         /*
406          * Output a padding row, that leaves all branch lines unchanged
407          */
408         for (i = 0; i < graph->num_new_columns; i++) {
409                 strbuf_addstr(sb, "| ");
410         }
411
412         graph_pad_horizontally(graph, sb);
413 }
414
415 static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
416 {
417         /*
418          * Output an ellipsis to indicate that a portion
419          * of the graph is missing.
420          */
421         strbuf_addstr(sb, "...");
422         graph_pad_horizontally(graph, sb);
423
424         if (graph->num_parents >= 3)
425                 graph->state = GRAPH_PRE_COMMIT;
426         else
427                 graph->state = GRAPH_COMMIT;
428 }
429
430 static void graph_output_pre_commit_line(struct git_graph *graph,
431                                          struct strbuf *sb)
432 {
433         int num_expansion_rows;
434         int i, seen_this;
435
436         /*
437          * This function formats a row that increases the space around a commit
438          * with multiple parents, to make room for it.  It should only be
439          * called when there are 3 or more parents.
440          *
441          * We need 2 extra rows for every parent over 2.
442          */
443         assert(graph->num_parents >= 3);
444         num_expansion_rows = (graph->num_parents - 2) * 2;
445
446         /*
447          * graph->expansion_row tracks the current expansion row we are on.
448          * It should be in the range [0, num_expansion_rows - 1]
449          */
450         assert(0 <= graph->expansion_row &&
451                graph->expansion_row < num_expansion_rows);
452
453         /*
454          * Output the row
455          */
456         seen_this = 0;
457         for (i = 0; i < graph->num_columns; i++) {
458                 struct column *col = &graph->columns[i];
459                 if (col->commit == graph->commit) {
460                         seen_this = 1;
461                         strbuf_addf(sb, "| %*s", graph->expansion_row, "");
462                 } else if (seen_this) {
463                         strbuf_addstr(sb, "\\ ");
464                 } else {
465                         strbuf_addstr(sb, "| ");
466                 }
467         }
468
469         graph_pad_horizontally(graph, sb);
470
471         /*
472          * Increment graph->expansion_row,
473          * and move to state GRAPH_COMMIT if necessary
474          */
475         graph->expansion_row++;
476         if (graph->expansion_row >= num_expansion_rows)
477                 graph->state = GRAPH_COMMIT;
478 }
479
480 void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
481 {
482         int seen_this = 0;
483         int i, j;
484
485         /*
486          * Output the row containing this commit
487          * Iterate up to and including graph->num_columns,
488          * since the current commit may not be in any of the existing
489          * columns.  (This happens when the current commit doesn't have any
490          * children that we have already processed.)
491          */
492         seen_this = 0;
493         for (i = 0; i <= graph->num_columns; i++) {
494                 struct commit *col_commit;
495                 if (i == graph->num_columns) {
496                         if (seen_this)
497                                 break;
498                         col_commit = graph->commit;
499                 } else {
500                         col_commit = graph->columns[i].commit;
501                 }
502
503                 if (col_commit == graph->commit) {
504                         seen_this = 1;
505                         if (graph->num_parents > 1)
506                                 strbuf_addch(sb, 'M');
507                         else
508                                 strbuf_addch(sb, '*');
509
510                         if (graph->num_parents < 2)
511                                 strbuf_addch(sb, ' ');
512                         else if (graph->num_parents == 2)
513                                 strbuf_addstr(sb, "  ");
514                         else {
515                                 int num_dashes =
516                                         ((graph->num_parents - 2) * 2) - 1;
517                                 for (j = 0; j < num_dashes; j++)
518                                         strbuf_addch(sb, '-');
519                                 strbuf_addstr(sb, ". ");
520                         }
521                 } else if (seen_this && (graph->num_parents > 1)) {
522                         strbuf_addstr(sb, "\\ ");
523                 } else {
524                         strbuf_addstr(sb, "| ");
525                 }
526         }
527
528         graph_pad_horizontally(graph, sb);
529
530         /*
531          * Update graph->state
532          */
533         if (graph->num_parents > 1)
534                 graph->state = GRAPH_POST_MERGE;
535         else if (graph_is_mapping_correct(graph))
536                 graph->state = GRAPH_PADDING;
537         else
538                 graph->state = GRAPH_COLLAPSING;
539 }
540
541 void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
542 {
543         int seen_this = 0;
544         int i, j;
545
546         /*
547          * Output the post-merge row
548          */
549         for (i = 0; i <= graph->num_columns; i++) {
550                 struct commit *col_commit;
551                 if (i == graph->num_columns) {
552                         if (seen_this)
553                                 break;
554                         col_commit = graph->commit;
555                 } else {
556                         col_commit = graph->columns[i].commit;
557                 }
558
559                 if (col_commit == graph->commit) {
560                         seen_this = 1;
561                         strbuf_addch(sb, '|');
562                         for (j = 0; j < graph->num_parents - 1; j++)
563                                 strbuf_addstr(sb, "\\ ");
564                         if (graph->num_parents == 2)
565                                 strbuf_addch(sb, ' ');
566                 } else if (seen_this && (graph->num_parents > 2)) {
567                         strbuf_addstr(sb, "\\ ");
568                 } else {
569                         strbuf_addstr(sb, "| ");
570                 }
571         }
572
573         graph_pad_horizontally(graph, sb);
574
575         /*
576          * Update graph->state
577          */
578         if (graph_is_mapping_correct(graph))
579                 graph->state = GRAPH_PADDING;
580         else
581                 graph->state = GRAPH_COLLAPSING;
582 }
583
584 void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
585 {
586         int i;
587         int *tmp_mapping;
588
589         /*
590          * Clear out the new_mapping array
591          */
592         for (i = 0; i < graph->mapping_size; i++)
593                 graph->new_mapping[i] = -1;
594
595         for (i = 0; i < graph->mapping_size; i++) {
596                 int target = graph->mapping[i];
597                 if (target < 0)
598                         continue;
599
600                 /*
601                  * Since update_columns() always inserts the leftmost
602                  * column first, each branch's target location should
603                  * always be either its current location or to the left of
604                  * its current location.
605                  *
606                  * We never have to move branches to the right.  This makes
607                  * the graph much more legible, since whenever branches
608                  * cross, only one is moving directions.
609                  */
610                 assert(target * 2 <= i);
611
612                 if (target * 2 == i) {
613                         /*
614                          * This column is already in the
615                          * correct place
616                          */
617                         assert(graph->new_mapping[i] == -1);
618                         graph->new_mapping[i] = target;
619                 } else if (graph->new_mapping[i - 1] < 0) {
620                         /*
621                          * Nothing is to the left.
622                          * Move to the left by one
623                          */
624                         graph->new_mapping[i - 1] = target;
625                 } else if (graph->new_mapping[i - 1] == target) {
626                         /*
627                          * There is a branch line to our left
628                          * already, and it is our target.  We
629                          * combine with this line, since we share
630                          * the same parent commit.
631                          *
632                          * We don't have to add anything to the
633                          * output or new_mapping, since the
634                          * existing branch line has already taken
635                          * care of it.
636                          */
637                 } else {
638                         /*
639                          * There is a branch line to our left,
640                          * but it isn't our target.  We need to
641                          * cross over it.
642                          *
643                          * The space just to the left of this
644                          * branch should always be empty.
645                          */
646                         assert(graph->new_mapping[i - 1] > target);
647                         assert(graph->new_mapping[i - 2] < 0);
648                         graph->new_mapping[i - 2] = target;
649                 }
650         }
651
652         /*
653          * The new mapping may be 1 smaller than the old mapping
654          */
655         if (graph->new_mapping[graph->mapping_size - 1] < 0)
656                 graph->mapping_size--;
657
658         /*
659          * Output out a line based on the new mapping info
660          */
661         for (i = 0; i < graph->mapping_size; i++) {
662                 int target = graph->new_mapping[i];
663                 if (target < 0)
664                         strbuf_addch(sb, ' ');
665                 else if (target * 2 == i)
666                         strbuf_addch(sb, '|');
667                 else
668                         strbuf_addch(sb, '/');
669         }
670
671         graph_pad_horizontally(graph, sb);
672
673         /*
674          * Swap mapping and new_mapping
675          */
676         tmp_mapping = graph->mapping;
677         graph->mapping = graph->new_mapping;
678         graph->new_mapping = tmp_mapping;
679
680         /*
681          * If graph->mapping indicates that all of the branch lines
682          * are already in the correct positions, we are done.
683          * Otherwise, we need to collapse some branch lines together.
684          */
685         if (graph_is_mapping_correct(graph))
686                 graph->state = GRAPH_PADDING;
687 }
688
689 int graph_next_line(struct git_graph *graph, struct strbuf *sb)
690 {
691         switch (graph->state) {
692         case GRAPH_PADDING:
693                 graph_output_padding_line(graph, sb);
694                 return 0;
695         case GRAPH_SKIP:
696                 graph_output_skip_line(graph, sb);
697                 return 0;
698         case GRAPH_PRE_COMMIT:
699                 graph_output_pre_commit_line(graph, sb);
700                 return 0;
701         case GRAPH_COMMIT:
702                 graph_output_commit_line(graph, sb);
703                 return 1;
704         case GRAPH_POST_MERGE:
705                 graph_output_post_merge_line(graph, sb);
706                 return 0;
707         case GRAPH_COLLAPSING:
708                 graph_output_collapsing_line(graph, sb);
709                 return 0;
710         }
711
712         assert(0);
713         return 0;
714 }
715
716 void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
717 {
718         int i, j;
719
720         if (graph->state != GRAPH_COMMIT) {
721                 graph_next_line(graph, sb);
722                 return;
723         }
724
725         /*
726          * Output the row containing this commit
727          * Iterate up to and including graph->num_columns,
728          * since the current commit may not be in any of the existing
729          * columns.  (This happens when the current commit doesn't have any
730          * children that we have already processed.)
731          */
732         for (i = 0; i < graph->num_columns; i++) {
733                 struct commit *col_commit = graph->columns[i].commit;
734                 if (col_commit == graph->commit) {
735                         strbuf_addch(sb, '|');
736
737                         if (graph->num_parents < 3)
738                                 strbuf_addch(sb, ' ');
739                         else {
740                                 int num_spaces = ((graph->num_parents - 2) * 2);
741                                 for (j = 0; j < num_spaces; j++)
742                                         strbuf_addch(sb, ' ');
743                         }
744                 } else {
745                         strbuf_addstr(sb, "| ");
746                 }
747         }
748
749         graph_pad_horizontally(graph, sb);
750 }
751
752 int graph_is_commit_finished(struct git_graph const *graph)
753 {
754         return (graph->state == GRAPH_PADDING);
755 }
756
757 void graph_show_commit(struct git_graph *graph)
758 {
759         struct strbuf msgbuf;
760         int shown_commit_line = 0;
761
762         if (!graph)
763                 return;
764
765         strbuf_init(&msgbuf, 0);
766
767         while (!shown_commit_line) {
768                 shown_commit_line = graph_next_line(graph, &msgbuf);
769                 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
770                 if (!shown_commit_line)
771                         putchar('\n');
772                 strbuf_setlen(&msgbuf, 0);
773         }
774
775         strbuf_release(&msgbuf);
776 }
777
778 void graph_show_oneline(struct git_graph *graph)
779 {
780         struct strbuf msgbuf;
781
782         if (!graph)
783                 return;
784
785         strbuf_init(&msgbuf, 0);
786         graph_next_line(graph, &msgbuf);
787         fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
788         strbuf_release(&msgbuf);
789 }
790
791 void graph_show_padding(struct git_graph *graph)
792 {
793         struct strbuf msgbuf;
794
795         if (!graph)
796                 return;
797
798         strbuf_init(&msgbuf, 0);
799         graph_padding_line(graph, &msgbuf);
800         fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
801         strbuf_release(&msgbuf);
802 }
803
804 int graph_show_remainder(struct git_graph *graph)
805 {
806         struct strbuf msgbuf;
807         int shown = 0;
808
809         if (!graph)
810                 return 0;
811
812         if (graph_is_commit_finished(graph))
813                 return 0;
814
815         strbuf_init(&msgbuf, 0);
816         for (;;) {
817                 graph_next_line(graph, &msgbuf);
818                 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
819                 strbuf_setlen(&msgbuf, 0);
820                 shown = 1;
821
822                 if (!graph_is_commit_finished(graph))
823                         putchar('\n');
824                 else
825                         break;
826         }
827         strbuf_release(&msgbuf);
828
829         return shown;
830 }
831
832
833 void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
834 {
835         char *p;
836
837         if (!graph) {
838                 fwrite(sb->buf, sizeof(char), sb->len, stdout);
839                 return;
840         }
841
842         /*
843          * Print the strbuf line by line,
844          * and display the graph info before each line but the first.
845          */
846         p = sb->buf;
847         while (p) {
848                 size_t len;
849                 char *next_p = strchr(p, '\n');
850                 if (next_p) {
851                         next_p++;
852                         len = next_p - p;
853                 } else {
854                         len = (sb->buf + sb->len) - p;
855                 }
856                 fwrite(p, sizeof(char), len, stdout);
857                 if (next_p && *next_p != '\0')
858                         graph_show_oneline(graph);
859                 p = next_p;
860         }
861 }
862
863 void graph_show_commit_msg(struct git_graph *graph,
864                            struct strbuf const *sb)
865 {
866         int newline_terminated;
867
868         if (!graph) {
869                 /*
870                  * If there's no graph, just print the message buffer.
871                  *
872                  * The message buffer for CMIT_FMT_ONELINE and
873                  * CMIT_FMT_USERFORMAT are already missing a terminating
874                  * newline.  All of the other formats should have it.
875                  */
876                 fwrite(sb->buf, sizeof(char), sb->len, stdout);
877                 return;
878         }
879
880         newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
881
882         /*
883          * Show the commit message
884          */
885         graph_show_strbuf(graph, sb);
886
887         /*
888          * If there is more output needed for this commit, show it now
889          */
890         if (!graph_is_commit_finished(graph)) {
891                 /*
892                  * If sb doesn't have a terminating newline, print one now,
893                  * so we can start the remainder of the graph output on a
894                  * new line.
895                  */
896                 if (!newline_terminated)
897                         putchar('\n');
898
899                 graph_show_remainder(graph);
900
901                 /*
902                  * If sb ends with a newline, our output should too.
903                  */
904                 if (newline_terminated)
905                         putchar('\n');
906         }
907 }