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 32struct 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 43enum graph_state { 44 GRAPH_PADDING, 45 GRAPH_SKIP, 46 GRAPH_PRE_COMMIT, 47 GRAPH_COMMIT, 48 GRAPH_POST_MERGE, 49 GRAPH_COLLAPSING 50}; 51 52struct 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 122struct 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 148void 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 156static 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 177static 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 210static 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 295void 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 341static 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 363static 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 390static 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 415static 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 430static 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 480void 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 541void 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 584void 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 689int 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 716void 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 752int graph_is_commit_finished(struct git_graph const *graph) 753{ 754 return (graph->state == GRAPH_PADDING); 755} 756 757void 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 778void 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 791void 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 804int 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 833void 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 863void 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}