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