| | @@ -163,10 +163,11 @@ |
| 163 | 163 | unsigned int lnPivot; /* Lines read from pivot */ |
| 164 | 164 | unsigned int lnV1; /* Lines read from v1 */ |
| 165 | 165 | unsigned int lnV2; /* Lines read from v2 */ |
| 166 | 166 | unsigned int lnOut; /* Lines written to out */ |
| 167 | 167 | unsigned int nConflict; /* Number of conflicts seen */ |
| 168 | + u64 diffFlags; /* Flags for difference engine */ |
| 168 | 169 | }; |
| 169 | 170 | #endif /* INTERFACE */ |
| 170 | 171 | |
| 171 | 172 | |
| 172 | 173 | /************************* Generic MergeBuilder ******************************/ |
| | @@ -308,10 +309,11 @@ |
| 308 | 309 | p->xSame = tokenSame; |
| 309 | 310 | p->xChngV1 = tokenChngV1; |
| 310 | 311 | p->xChngV2 = tokenChngV2; |
| 311 | 312 | p->xChngBoth = tokenChngBoth; |
| 312 | 313 | p->xConflict = tokenConflict; |
| 314 | + p->diffFlags = DIFF_BY_TOKEN; |
| 313 | 315 | } |
| 314 | 316 | |
| 315 | 317 | /* |
| 316 | 318 | ** Attempt to do a low-level merge on a conflict. The conflict is |
| 317 | 319 | ** described by the first four parameters, which are the same as the |
| | @@ -336,17 +338,21 @@ |
| 336 | 338 | mergebuilder_init_token(&mb); |
| 337 | 339 | blob_extract_lines(pMB->pPivot, nPivot, &pv); |
| 338 | 340 | blob_extract_lines(pMB->pV1, nV1, &v1); |
| 339 | 341 | blob_extract_lines(pMB->pV2, nV2, &v2); |
| 340 | 342 | blob_zero(pOut); |
| 343 | + blob_materialize(&pv); |
| 344 | + blob_materialize(&v1); |
| 345 | + blob_materialize(&v2); |
| 341 | 346 | mb.pPivot = &pv; |
| 342 | 347 | mb.pV1 = &v1; |
| 343 | 348 | mb.pV2 = &v2; |
| 344 | 349 | mb.pOut = pOut; |
| 345 | 350 | nConflict = merge_three_blobs(&mb); |
| 346 | | - /* pv, v1, and v2 should all be ephemeral blobs, so they do not |
| 347 | | - ** need to be freed. */ |
| 351 | + blob_reset(&pv); |
| 352 | + blob_reset(&v1); |
| 353 | + blob_reset(&v2); |
| 348 | 354 | /* mb has not allocated any resources, so we do not need to invoke |
| 349 | 355 | ** the xDestroy method. */ |
| 350 | 356 | blob_add_final_newline(pOut); |
| 351 | 357 | return nConflict; |
| 352 | 358 | } |
| | @@ -426,11 +432,11 @@ |
| 426 | 432 | ** |
| 427 | 433 | ** . This line is omitted. |
| 428 | 434 | ** N Name of the file. |
| 429 | 435 | ** T Literal text follows that should have a \n terminator. |
| 430 | 436 | ** R Literal text follows that needs a \r\n terminator. |
| 431 | | -** X Merge conflict. (Column 4 only) |
| 437 | +** X Merge conflict. |
| 432 | 438 | ** Z Literal text without a line terminator. |
| 433 | 439 | ** S Skipped lines in all 4 files. |
| 434 | 440 | ** 1 Text is a copy of token 1 |
| 435 | 441 | ** 2 Use data from data-token 2 |
| 436 | 442 | ** 3 Use data from data-token 3 |
| | @@ -458,22 +464,25 @@ |
| 458 | 464 | } |
| 459 | 465 | } |
| 460 | 466 | } |
| 461 | 467 | |
| 462 | 468 | /* Copy one line of text from pIn and append to pOut, encoded as TCL */ |
| 463 | | -static void tclLineOfText(Blob *pOut, Blob *pIn){ |
| 469 | +static void tclLineOfText(Blob *pOut, Blob *pIn, char cType){ |
| 464 | 470 | int i, k; |
| 465 | 471 | for(i=pIn->iCursor; i<pIn->nUsed && pIn->aData[i]!='\n'; i++){} |
| 466 | 472 | if( i==pIn->nUsed ){ |
| 467 | | - blob_append(pOut, "\"Z", 2); |
| 473 | + blob_append_char(pOut, '"'); |
| 474 | + blob_append_char(pOut, cType ? cType : 'Z'); |
| 468 | 475 | k = i; |
| 469 | 476 | }else if( i>pIn->iCursor && pIn->aData[i-1]=='\r' ){ |
| 470 | | - blob_append(pOut, "\"R", 2); |
| 477 | + blob_append_char(pOut, '"'); |
| 478 | + blob_append_char(pOut, cType ? cType : 'R'); |
| 471 | 479 | k = i-1; |
| 472 | 480 | i++; |
| 473 | 481 | }else{ |
| 474 | | - blob_append(pOut, "\"T", 2); |
| 482 | + blob_append_char(pOut, '"'); |
| 483 | + blob_append_char(pOut, cType ? cType : 'T'); |
| 475 | 484 | k = i; |
| 476 | 485 | i++; |
| 477 | 486 | } |
| 478 | 487 | tclWriteQuotedText(pOut, pIn->aData+pIn->iCursor, k-pIn->iCursor); |
| 479 | 488 | pIn->iCursor = i; |
| | @@ -499,11 +508,11 @@ |
| 499 | 508 | int i = 0; |
| 500 | 509 | int nSkip; |
| 501 | 510 | |
| 502 | 511 | if( p->lnPivot>=2 || p->lnV1>2 || p->lnV2>2 ){ |
| 503 | 512 | while( i<N && i<p->nContext ){ |
| 504 | | - tclLineOfText(p->pOut, p->pPivot); |
| 513 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 505 | 514 | blob_append(p->pOut, " 1 1 1\n", 7); |
| 506 | 515 | i++; |
| 507 | 516 | } |
| 508 | 517 | nSkip = N - p->nContext*2; |
| 509 | 518 | }else{ |
| | @@ -519,11 +528,11 @@ |
| 519 | 528 | p->lnV1 += N; |
| 520 | 529 | p->lnV2 += N; |
| 521 | 530 | |
| 522 | 531 | if( p->lnPivot<p->mxPivot || p->lnV1<p->mxV1 || p->lnV2<p->mxV2 ){ |
| 523 | 532 | while( i<N ){ |
| 524 | | - tclLineOfText(p->pOut, p->pPivot); |
| 533 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 525 | 534 | blob_append(p->pOut, " 1 1 1\n", 7); |
| 526 | 535 | i++; |
| 527 | 536 | } |
| 528 | 537 | } |
| 529 | 538 | |
| | @@ -531,23 +540,23 @@ |
| 531 | 540 | blob_copy_lines(0, p->pV2, N); |
| 532 | 541 | } |
| 533 | 542 | static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){ |
| 534 | 543 | int i; |
| 535 | 544 | for(i=0; i<nPivot && i<nV1; i++){ |
| 536 | | - tclLineOfText(p->pOut, p->pPivot); |
| 545 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 537 | 546 | blob_append_char(p->pOut, ' '); |
| 538 | | - tclLineOfText(p->pOut, p->pV1); |
| 547 | + tclLineOfText(p->pOut, p->pV1, 0); |
| 539 | 548 | blob_append(p->pOut, " 1 2\n", 5); |
| 540 | 549 | } |
| 541 | 550 | while( i<nPivot ){ |
| 542 | | - tclLineOfText(p->pOut, p->pPivot); |
| 551 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 543 | 552 | blob_append(p->pOut, " . 1 .\n", 7); |
| 544 | 553 | i++; |
| 545 | 554 | } |
| 546 | 555 | while( i<nV1 ){ |
| 547 | 556 | blob_append(p->pOut, ". ", 2); |
| 548 | | - tclLineOfText(p->pOut, p->pV1); |
| 557 | + tclLineOfText(p->pOut, p->pV1, 0); |
| 549 | 558 | blob_append(p->pOut, " . 2\n", 5); |
| 550 | 559 | i++; |
| 551 | 560 | } |
| 552 | 561 | p->lnPivot += nPivot; |
| 553 | 562 | p->lnV1 += nV1; |
| | @@ -555,23 +564,23 @@ |
| 555 | 564 | blob_copy_lines(0, p->pV2, nPivot); |
| 556 | 565 | } |
| 557 | 566 | static void tclChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){ |
| 558 | 567 | int i; |
| 559 | 568 | for(i=0; i<nPivot && i<nV2; i++){ |
| 560 | | - tclLineOfText(p->pOut, p->pPivot); |
| 569 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 561 | 570 | blob_append(p->pOut, " 1 ", 3); |
| 562 | | - tclLineOfText(p->pOut, p->pV2); |
| 571 | + tclLineOfText(p->pOut, p->pV2, 0); |
| 563 | 572 | blob_append(p->pOut, " 3\n", 3); |
| 564 | 573 | } |
| 565 | 574 | while( i<nPivot ){ |
| 566 | | - tclLineOfText(p->pOut, p->pPivot); |
| 575 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 567 | 576 | blob_append(p->pOut, " 1 . .\n", 7); |
| 568 | 577 | i++; |
| 569 | 578 | } |
| 570 | 579 | while( i<nV2 ){ |
| 571 | 580 | blob_append(p->pOut, ". . ", 4); |
| 572 | | - tclLineOfText(p->pOut, p->pV2); |
| 581 | + tclLineOfText(p->pOut, p->pV2, 0); |
| 573 | 582 | blob_append(p->pOut, " 3\n", 3); |
| 574 | 583 | i++; |
| 575 | 584 | } |
| 576 | 585 | p->lnPivot += nPivot; |
| 577 | 586 | p->lnV1 += nPivot; |
| | @@ -579,23 +588,23 @@ |
| 579 | 588 | blob_copy_lines(0, p->pV1, nPivot); |
| 580 | 589 | } |
| 581 | 590 | static void tclChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){ |
| 582 | 591 | int i; |
| 583 | 592 | for(i=0; i<nPivot && i<nV; i++){ |
| 584 | | - tclLineOfText(p->pOut, p->pPivot); |
| 593 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 585 | 594 | blob_append_char(p->pOut, ' '); |
| 586 | | - tclLineOfText(p->pOut, p->pV1); |
| 595 | + tclLineOfText(p->pOut, p->pV1, 0); |
| 587 | 596 | blob_append(p->pOut, " 2 2\n", 5); |
| 588 | 597 | } |
| 589 | 598 | while( i<nPivot ){ |
| 590 | | - tclLineOfText(p->pOut, p->pPivot); |
| 599 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 591 | 600 | blob_append(p->pOut, " . . .\n", 7); |
| 592 | 601 | i++; |
| 593 | 602 | } |
| 594 | 603 | while( i<nV ){ |
| 595 | 604 | blob_append(p->pOut, ". ", 2); |
| 596 | | - tclLineOfText(p->pOut, p->pV1); |
| 605 | + tclLineOfText(p->pOut, p->pV1, 0); |
| 597 | 606 | blob_append(p->pOut, " 2 2\n", 5); |
| 598 | 607 | i++; |
| 599 | 608 | } |
| 600 | 609 | p->lnPivot += nPivot; |
| 601 | 610 | p->lnV1 += nV; |
| | @@ -618,28 +627,30 @@ |
| 618 | 627 | if( nV1>mx ) mx = nV1; |
| 619 | 628 | if( nV2>mx ) mx = nV2; |
| 620 | 629 | if( nOut>mx ) mx = nOut; |
| 621 | 630 | for(i=0; i<mx; i++){ |
| 622 | 631 | if( i<nPivot ){ |
| 623 | | - tclLineOfText(p->pOut, p->pPivot); |
| 632 | + tclLineOfText(p->pOut, p->pPivot, 0); |
| 624 | 633 | }else{ |
| 625 | 634 | blob_append_char(p->pOut, '.'); |
| 626 | 635 | } |
| 627 | 636 | blob_append_char(p->pOut, ' '); |
| 628 | 637 | if( i<nV1 ){ |
| 629 | | - tclLineOfText(p->pOut, p->pV1); |
| 638 | + tclLineOfText(p->pOut, p->pV1, 0); |
| 630 | 639 | }else{ |
| 631 | 640 | blob_append_char(p->pOut, '.'); |
| 632 | 641 | } |
| 633 | 642 | blob_append_char(p->pOut, ' '); |
| 634 | 643 | if( i<nV2 ){ |
| 635 | | - tclLineOfText(p->pOut, p->pV2); |
| 644 | + tclLineOfText(p->pOut, p->pV2, 0); |
| 636 | 645 | }else{ |
| 637 | 646 | blob_append_char(p->pOut, '.'); |
| 638 | 647 | } |
| 639 | 648 | if( i<nOut ){ |
| 640 | | - tclLineOfText(p->pOut, &out); |
| 649 | + blob_append_char(p->pOut, ' '); |
| 650 | + tclLineOfText(p->pOut, &out, 'X'); |
| 651 | + blob_append_char(p->pOut, '\n'); |
| 641 | 652 | }else{ |
| 642 | 653 | blob_append(p->pOut, " X\n", 3); |
| 643 | 654 | } |
| 644 | 655 | } |
| 645 | 656 | blob_reset(&out); |
| | @@ -736,10 +747,11 @@ |
| 736 | 747 | ** the second integer is the number of lines of text to omit from the |
| 737 | 748 | ** pivot, and the third integer is the number of lines of text that are |
| 738 | 749 | ** inserted. The edit array ends with a triple of 0,0,0. |
| 739 | 750 | */ |
| 740 | 751 | diff_config_init(&DCfg, 0); |
| 752 | + DCfg.diffFlags = p->diffFlags; |
| 741 | 753 | aC1 = text_diff(p->pPivot, p->pV1, 0, &DCfg); |
| 742 | 754 | aC2 = text_diff(p->pPivot, p->pV2, 0, &DCfg); |
| 743 | 755 | if( aC1==0 || aC2==0 ){ |
| 744 | 756 | free(aC1); |
| 745 | 757 | free(aC2); |
| 746 | 758 | |