| | @@ -578,10 +578,178 @@ |
| 578 | 578 | free(c.aFrom); |
| 579 | 579 | free(c.aTo); |
| 580 | 580 | return c.aEdit; |
| 581 | 581 | } |
| 582 | 582 | } |
| 583 | + |
| 584 | + |
| 585 | +/* |
| 586 | + * References in the fossil repository: |
| 587 | + * /vdiff?from=080d27a&to=4b0f813&detail=1 |
| 588 | + * /vdiff?from=636804745b&to=c1d78e0556&detail=1 |
| 589 | + * /vdiff?from=c0b6c28d29&to=25169506b7&detail=1 |
| 590 | + * /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1 |
| 591 | + */ |
| 592 | +int *html_sbsdiff( |
| 593 | + Blob *pA_Blob, /* FROM file */ |
| 594 | + Blob *pB_Blob, /* TO file */ |
| 595 | + int nContext, /* Amount of context to unified diff */ |
| 596 | + int ignoreEolWs /* Ignore whitespace at the end of lines */ |
| 597 | +){ |
| 598 | + DContext c; |
| 599 | + int i; |
| 600 | + int iFrom, iTo; |
| 601 | + char *linebuf; |
| 602 | + |
| 603 | + /* Prepare the input files */ |
| 604 | + memset(&c, 0, sizeof(c)); |
| 605 | + c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 606 | + &c.nFrom, ignoreEolWs); |
| 607 | + c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), |
| 608 | + &c.nTo, ignoreEolWs); |
| 609 | + if( c.aFrom==0 || c.aTo==0 ){ |
| 610 | + free(c.aFrom); |
| 611 | + free(c.aTo); |
| 612 | + /* TODO Error handling */ |
| 613 | + return 0; |
| 614 | + } |
| 615 | + |
| 616 | + /* Compute the difference */ |
| 617 | + diff_all(&c); |
| 618 | + |
| 619 | + linebuf = fossil_malloc(LENGTH_MASK+1); |
| 620 | + if( !linebuf ){ |
| 621 | + /* TODO Handle error */ |
| 622 | + } |
| 623 | + |
| 624 | + iFrom=iTo=0; |
| 625 | + i=0; |
| 626 | + while( i<c.nEdit ){ |
| 627 | + int j; |
| 628 | + /* Copied lines */ |
| 629 | + for( j=0; j<c.aEdit[i]; j++){ |
| 630 | + int len; |
| 631 | + int dist; |
| 632 | + |
| 633 | + /* Hide lines which are copied and are further away from block boundaries |
| 634 | + ** then nConext lines. For each block with hidden lines, show a row |
| 635 | + ** notifying the user about the hidden rows. |
| 636 | + */ |
| 637 | + if( j<nContext || j>c.aEdit[i]-nContext-1 ){ |
| 638 | + @ <tr> |
| 639 | + }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){ |
| 640 | + @ <tr> |
| 641 | + @ <td class="meta" colspan="5" style="white-space: nowrap;"> |
| 642 | + @ %d(c.aEdit[i]-2*nContext) hidden line(s).</td> |
| 643 | + @ </tr> |
| 644 | + continue; |
| 645 | + }else{ |
| 646 | + @ <tr style="display:none;"> |
| 647 | + } |
| 648 | + |
| 649 | + len = c.aFrom[iFrom+j].h & LENGTH_MASK; |
| 650 | + memcpy(linebuf, c.aFrom[iFrom+j].z, len); |
| 651 | + linebuf[len] = '\0'; |
| 652 | + @ <td class="lineno">%d(iFrom+j+1)</td><td>%s(linebuf)</td> |
| 653 | + |
| 654 | + @ <td> </td> |
| 655 | + |
| 656 | + len = c.aTo[iTo+j].h & LENGTH_MASK; |
| 657 | + memcpy(linebuf, c.aTo[iTo+j].z, len); |
| 658 | + linebuf[len] = '\0'; |
| 659 | + @ <td class="lineno">%d(iTo+j+1)</td><td>%s(linebuf)</td> |
| 660 | + |
| 661 | + @ </tr> |
| 662 | + } |
| 663 | + iFrom+=c.aEdit[i]; |
| 664 | + iTo+=c.aEdit[i]; |
| 665 | + |
| 666 | + if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){ |
| 667 | + int lim; |
| 668 | + lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2]; |
| 669 | + |
| 670 | + /* Assume changed lines */ |
| 671 | + for( j=0; j<lim; j++ ){ |
| 672 | + int len; |
| 673 | + @ <tr> |
| 674 | + |
| 675 | + if( j<c.aEdit[i+1] ){ |
| 676 | + len = c.aFrom[iFrom+j].h & LENGTH_MASK; |
| 677 | + memcpy(linebuf, c.aFrom[iFrom+j].z, len); |
| 678 | + linebuf[len] = '\0'; |
| 679 | + @ <td class="changed lineno">%d(iFrom+j+1)</td> |
| 680 | + @ <td class="changed">%s(linebuf)</td> |
| 681 | + }else{ |
| 682 | + @ <td colspan="2"/> |
| 683 | + } |
| 684 | + |
| 685 | + @ <td class="changed">|</td> |
| 686 | + |
| 687 | + if( j<c.aEdit[i+2] ){ |
| 688 | + len = c.aTo[iTo+j].h & LENGTH_MASK; |
| 689 | + memcpy(linebuf, c.aTo[iTo+j].z, len); |
| 690 | + linebuf[len] = '\0'; |
| 691 | + @ <td class="changed lineno">%d(iTo+j+1)</td> |
| 692 | + @ <td class="changed">%s(linebuf)</td> |
| 693 | + }else{ |
| 694 | + @ <td colspan="2"/> |
| 695 | + } |
| 696 | + |
| 697 | + @ </tr> |
| 698 | + } |
| 699 | + iFrom+=c.aEdit[i+1]; |
| 700 | + iTo+=c.aEdit[i+2]; |
| 701 | + }else{ |
| 702 | + |
| 703 | + /* Process deleted lines */ |
| 704 | + for( j=0; j<c.aEdit[i+1]; j++ ){ |
| 705 | + int len; |
| 706 | + @ <tr> |
| 707 | + |
| 708 | + len = c.aFrom[iFrom+j].h & LENGTH_MASK; |
| 709 | + memcpy(linebuf, c.aFrom[iFrom+j].z, len); |
| 710 | + linebuf[len] = '\0'; |
| 711 | + @ <td class="removed lineno">%d(iFrom+j+1)</td> |
| 712 | + @ <td class="removed">%s(linebuf)</td> |
| 713 | + |
| 714 | + @ <td><</td> |
| 715 | + |
| 716 | + @ <td colspan="2"/> |
| 717 | + |
| 718 | + @ </tr> |
| 719 | + } |
| 720 | + iFrom+=c.aEdit[i+1]; |
| 721 | + |
| 722 | + /* Process inserted lines */ |
| 723 | + for( j=0; j<c.aEdit[i+2]; j++ ){ |
| 724 | + int len; |
| 725 | + @ <tr> |
| 726 | + @ <td colspan="2"/> |
| 727 | + |
| 728 | + @ <td>></td> |
| 729 | + |
| 730 | + len = c.aTo[iTo+j].h & LENGTH_MASK; |
| 731 | + memcpy(linebuf, c.aTo[iTo+j].z, len); |
| 732 | + linebuf[len] = '\0'; |
| 733 | + @ <td class="added lineno">%d(iTo+j+1)</td> |
| 734 | + @ <td class="added">%s(linebuf)</td> |
| 735 | + |
| 736 | + @ </tr> |
| 737 | + } |
| 738 | + iTo+=c.aEdit[i+2]; |
| 739 | + } |
| 740 | + |
| 741 | + i+=3; |
| 742 | + } |
| 743 | + |
| 744 | + free(linebuf); |
| 745 | + free(c.aFrom); |
| 746 | + free(c.aTo); |
| 747 | + free(c.aEdit); |
| 748 | + return 0; |
| 749 | +} |
| 750 | + |
| 583 | 751 | |
| 584 | 752 | /* |
| 585 | 753 | ** COMMAND: test-rawdiff |
| 586 | 754 | */ |
| 587 | 755 | void test_rawdiff_cmd(void){ |
| 588 | 756 | |