Fossil SCM
Getting in the changes reducing the leak on annotate.
Commit
7870a89b103a37b0038436153b91d74f6c5000ed
Parent
e2ebb1f5cae83e8…
1 file changed
+71
-16
+71
-16
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -619,10 +619,24 @@ | ||
| 619 | 619 | /************************************************************************** |
| 620 | 620 | ** The basic difference engine is above. What follows is the annotation |
| 621 | 621 | ** engine. Both are in the same file since they share many components. |
| 622 | 622 | */ |
| 623 | 623 | |
| 624 | +/* | |
| 625 | +** Linked list of strings, labels used in the annotator code. | |
| 626 | +** The elements of the list and the pointed string (str) | |
| 627 | +** will be freed once they become totally unreferenced | |
| 628 | +** (nref == 0). | |
| 629 | +*/ | |
| 630 | +struct Label | |
| 631 | +{ | |
| 632 | + struct Label *prev; /* previous element */ | |
| 633 | + struct Label *next; /* next element */ | |
| 634 | + char *str; /* The label string */ | |
| 635 | + int nref; /* Number of references to the string */ | |
| 636 | +}; | |
| 637 | + | |
| 624 | 638 | /* |
| 625 | 639 | ** The status of an annotation operation is recorded by an instance |
| 626 | 640 | ** of the following structure. |
| 627 | 641 | */ |
| 628 | 642 | typedef struct Annotator Annotator; |
| @@ -630,18 +644,19 @@ | ||
| 630 | 644 | DContext c; /* The diff-engine context */ |
| 631 | 645 | struct AnnLine { /* Lines of the original files... */ |
| 632 | 646 | const char *z; /* The text of the line */ |
| 633 | 647 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | 648 | short int iLevel; /* Level at which tag was set */ |
| 635 | - const char *zSrc; /* Tag showing origin of this line */ | |
| 649 | + struct Label *zSrc; /* Tag showing origin of this line */ | |
| 636 | 650 | } *aOrig; |
| 637 | 651 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | 652 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | 653 | int iLevel; /* Current level */ |
| 640 | 654 | int nVers; /* Number of versions analyzed */ |
| 641 | - char **azVers; /* Names of versions analyzed */ | |
| 655 | + struct Label **azVers; /* Names of versions analyzed */ | |
| 642 | 656 | Blob toAnnotate; |
| 657 | + struct Label *firstLabel; | |
| 643 | 658 | }; |
| 644 | 659 | |
| 645 | 660 | /* |
| 646 | 661 | ** Initialize the annotation process by specifying the file that is |
| 647 | 662 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -670,11 +685,11 @@ | ||
| 670 | 685 | ** being annotated. Do another step of the annotation. Return true |
| 671 | 686 | ** if additional annotation is required. zPName is the tag to insert |
| 672 | 687 | ** on each line of the file being annotated that was contributed by |
| 673 | 688 | ** pParent. Memory to hold zPName is leaked. |
| 674 | 689 | */ |
| 675 | -static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ | |
| 690 | +static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){ | |
| 676 | 691 | int i, j; |
| 677 | 692 | int lnTo; |
| 678 | 693 | int iPrevLevel; |
| 679 | 694 | int iThisLevel; |
| 680 | 695 | |
| @@ -698,13 +713,22 @@ | ||
| 698 | 713 | iThisLevel = p->iLevel; |
| 699 | 714 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 700 | 715 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 701 | 716 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 702 | 717 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 703 | - /* TODO: handle zPName so we can free labels | |
| 704 | - * if they get totally unreferenced in the Annotator */ | |
| 718 | + if (x->zSrc!=0) | |
| 719 | + { | |
| 720 | + if(--x->zSrc->nref == 0) | |
| 721 | + { | |
| 722 | + free(x->zSrc->str); | |
| 723 | + x->zSrc->prev->next = x->zSrc->next; | |
| 724 | + x->zSrc->next->prev = x->zSrc->prev; | |
| 725 | + free(x->zSrc); | |
| 726 | + } | |
| 727 | + } | |
| 705 | 728 | x->zSrc = zPName; |
| 729 | + ++zPName->nref; | |
| 706 | 730 | x->iLevel = iThisLevel; |
| 707 | 731 | } |
| 708 | 732 | } |
| 709 | 733 | lnTo += p->c.aEdit[i+2]; |
| 710 | 734 | } |
| @@ -739,20 +763,36 @@ | ||
| 739 | 763 | content_get(name_to_rid(g.argv[2]), &x.toAnnotate); |
| 740 | 764 | if( annotation_start(&x) ){ |
| 741 | 765 | fossil_fatal("binary file"); |
| 742 | 766 | } |
| 743 | 767 | for(i=3; i<g.argc; i++){ |
| 768 | + struct Label *l; | |
| 744 | 769 | blob_zero(&b); |
| 745 | 770 | content_get(name_to_rid(g.argv[i]), &b); |
| 746 | - if( annotation_step(&x, &b, g.argv[i-1]) ){ | |
| 771 | + l = fossil_malloc(sizeof(*l)); | |
| 772 | + l->str = g.argv[i-1]; | |
| 773 | + l->nref = 0; | |
| 774 | + l->next = x.firstLabel; | |
| 775 | + if (x.firstLabel) | |
| 776 | + x.firstLabel->prev = l; | |
| 777 | + x.firstLabel = l; | |
| 778 | + if( annotation_step(&x, &b, l) ){ | |
| 747 | 779 | fossil_fatal("binary file"); |
| 748 | 780 | } |
| 749 | 781 | } |
| 750 | 782 | for(i=0; i<x.nOrig; i++){ |
| 751 | - const char *zSrc = x.aOrig[i].zSrc; | |
| 783 | + const char *zSrc = x.aOrig[i].zSrc->str; | |
| 752 | 784 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 753 | 785 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 786 | + } | |
| 787 | + while(x.firstLabel) { | |
| 788 | + struct Label *l; | |
| 789 | + l = x.firstLabel->next; | |
| 790 | + assert(x.firstLabel->nref > 0); | |
| 791 | + free(x.firstLabel->str); | |
| 792 | + free(x.firstLabel); | |
| 793 | + x.firstLabel = l; | |
| 754 | 794 | } |
| 755 | 795 | } |
| 756 | 796 | |
| 757 | 797 | /* Annotation flags */ |
| 758 | 798 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| @@ -770,11 +810,10 @@ | ||
| 770 | 810 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 771 | 811 | int annFlags /* Flags to alter the annotation */ |
| 772 | 812 | ){ |
| 773 | 813 | Blob step = empty_blob; /* Text of previous revision */ |
| 774 | 814 | int rid; /* Artifact ID of the file being annotated */ |
| 775 | - char *zLabel; /* Label to apply to a line */ | |
| 776 | 815 | Stmt q; /* Query returning all ancestor versions */ |
| 777 | 816 | |
| 778 | 817 | /* Initialize the annotation */ |
| 779 | 818 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 780 | 819 | if( rid==0 ){ |
| @@ -808,23 +847,31 @@ | ||
| 808 | 847 | while( db_step(&q)==SQLITE_ROW ){ |
| 809 | 848 | int pid = db_column_int(&q, 0); |
| 810 | 849 | const char *zUuid = db_column_text(&q, 1); |
| 811 | 850 | const char *zDate = db_column_text(&q, 2); |
| 812 | 851 | const char *zUser = db_column_text(&q, 3); |
| 852 | + struct Label *l = fossil_malloc(sizeof(*l)); | |
| 853 | + l->nref = 0; | |
| 854 | + l->next = p->firstLabel; | |
| 855 | + if (p->firstLabel) | |
| 856 | + p->firstLabel->prev = l; | |
| 813 | 857 | if( webLabel ){ |
| 814 | - zLabel = mprintf( | |
| 858 | + l->str = mprintf( | |
| 815 | 859 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 816 | 860 | g.zTop, zUuid, zUuid, zDate, zUser |
| 817 | 861 | ); |
| 818 | 862 | }else{ |
| 819 | - zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); | |
| 863 | + l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); | |
| 820 | 864 | } |
| 865 | + p->firstLabel = l; | |
| 821 | 866 | p->nVers++; |
| 822 | 867 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 823 | - p->azVers[p->nVers-1] = zLabel; | |
| 868 | + p->azVers[p->nVers-1] = l; | |
| 824 | 869 | content_get(pid, &step); |
| 825 | - annotation_step(p, &step, zLabel); | |
| 870 | + annotation_step(p, &step, l); | |
| 871 | + if (l->nref == 0) | |
| 872 | + free(l->str); | |
| 826 | 873 | blob_reset(&step); |
| 827 | 874 | } |
| 828 | 875 | db_finalize(&q); |
| 829 | 876 | free(p->c.aTo); |
| 830 | 877 | } |
| @@ -860,20 +907,20 @@ | ||
| 860 | 907 | if( P("log") ){ |
| 861 | 908 | int i; |
| 862 | 909 | @ <h2>Versions analyzed:</h2> |
| 863 | 910 | @ <ol> |
| 864 | 911 | for(i=0; i<ann.nVers; i++){ |
| 865 | - @ <li><tt>%s(ann.azVers[i])</tt></li> | |
| 912 | + @ <li><tt>%s(ann.azVers[i]->str)</tt></li> | |
| 866 | 913 | } |
| 867 | 914 | @ </ol> |
| 868 | 915 | @ <hr> |
| 869 | 916 | @ <h2>Annotation:</h2> |
| 870 | 917 | } |
| 871 | 918 | @ <pre> |
| 872 | 919 | for(i=0; i<ann.nOrig; i++){ |
| 873 | 920 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 874 | - @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) | |
| 921 | + @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z) | |
| 875 | 922 | } |
| 876 | 923 | @ </pre> |
| 877 | 924 | style_footer(); |
| 878 | 925 | } |
| 879 | 926 | |
| @@ -930,17 +977,25 @@ | ||
| 930 | 977 | } |
| 931 | 978 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 932 | 979 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 933 | 980 | if( showLog ){ |
| 934 | 981 | for(i=0; i<ann.nVers; i++){ |
| 935 | - printf("version %3d: %s\n", i+1, ann.azVers[i]); | |
| 982 | + printf("version %3d: %s\n", i+1, ann.azVers[i]->str); | |
| 936 | 983 | } |
| 937 | 984 | printf("---------------------------------------------------\n"); |
| 938 | 985 | } |
| 939 | 986 | for(i=0; i<ann.nOrig; i++){ |
| 940 | 987 | fossil_print("%s: %.*s\n", |
| 941 | - ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 988 | + ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 942 | 989 | } |
| 943 | 990 | free(ann.azVers); |
| 944 | 991 | free(ann.aOrig); |
| 945 | 992 | blob_reset(&ann.toAnnotate); |
| 993 | + while(ann.firstLabel) { | |
| 994 | + struct Label *l; | |
| 995 | + l = ann.firstLabel->next; | |
| 996 | + assert(ann.firstLabel->nref > 0); | |
| 997 | + free(ann.firstLabel->str); | |
| 998 | + free(ann.firstLabel); | |
| 999 | + ann.firstLabel = l; | |
| 1000 | + } | |
| 946 | 1001 | } |
| 947 | 1002 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -619,10 +619,24 @@ | |
| 619 | /************************************************************************** |
| 620 | ** The basic difference engine is above. What follows is the annotation |
| 621 | ** engine. Both are in the same file since they share many components. |
| 622 | */ |
| 623 | |
| 624 | /* |
| 625 | ** The status of an annotation operation is recorded by an instance |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| @@ -630,18 +644,19 @@ | |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct AnnLine { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | short int iLevel; /* Level at which tag was set */ |
| 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 636 | } *aOrig; |
| 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | int iLevel; /* Current level */ |
| 640 | int nVers; /* Number of versions analyzed */ |
| 641 | char **azVers; /* Names of versions analyzed */ |
| 642 | Blob toAnnotate; |
| 643 | }; |
| 644 | |
| 645 | /* |
| 646 | ** Initialize the annotation process by specifying the file that is |
| 647 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -670,11 +685,11 @@ | |
| 670 | ** being annotated. Do another step of the annotation. Return true |
| 671 | ** if additional annotation is required. zPName is the tag to insert |
| 672 | ** on each line of the file being annotated that was contributed by |
| 673 | ** pParent. Memory to hold zPName is leaked. |
| 674 | */ |
| 675 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 676 | int i, j; |
| 677 | int lnTo; |
| 678 | int iPrevLevel; |
| 679 | int iThisLevel; |
| 680 | |
| @@ -698,13 +713,22 @@ | |
| 698 | iThisLevel = p->iLevel; |
| 699 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 700 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 701 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 702 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 703 | /* TODO: handle zPName so we can free labels |
| 704 | * if they get totally unreferenced in the Annotator */ |
| 705 | x->zSrc = zPName; |
| 706 | x->iLevel = iThisLevel; |
| 707 | } |
| 708 | } |
| 709 | lnTo += p->c.aEdit[i+2]; |
| 710 | } |
| @@ -739,20 +763,36 @@ | |
| 739 | content_get(name_to_rid(g.argv[2]), &x.toAnnotate); |
| 740 | if( annotation_start(&x) ){ |
| 741 | fossil_fatal("binary file"); |
| 742 | } |
| 743 | for(i=3; i<g.argc; i++){ |
| 744 | blob_zero(&b); |
| 745 | content_get(name_to_rid(g.argv[i]), &b); |
| 746 | if( annotation_step(&x, &b, g.argv[i-1]) ){ |
| 747 | fossil_fatal("binary file"); |
| 748 | } |
| 749 | } |
| 750 | for(i=0; i<x.nOrig; i++){ |
| 751 | const char *zSrc = x.aOrig[i].zSrc; |
| 752 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 753 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 754 | } |
| 755 | } |
| 756 | |
| 757 | /* Annotation flags */ |
| 758 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| @@ -770,11 +810,10 @@ | |
| 770 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 771 | int annFlags /* Flags to alter the annotation */ |
| 772 | ){ |
| 773 | Blob step = empty_blob; /* Text of previous revision */ |
| 774 | int rid; /* Artifact ID of the file being annotated */ |
| 775 | char *zLabel; /* Label to apply to a line */ |
| 776 | Stmt q; /* Query returning all ancestor versions */ |
| 777 | |
| 778 | /* Initialize the annotation */ |
| 779 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 780 | if( rid==0 ){ |
| @@ -808,23 +847,31 @@ | |
| 808 | while( db_step(&q)==SQLITE_ROW ){ |
| 809 | int pid = db_column_int(&q, 0); |
| 810 | const char *zUuid = db_column_text(&q, 1); |
| 811 | const char *zDate = db_column_text(&q, 2); |
| 812 | const char *zUser = db_column_text(&q, 3); |
| 813 | if( webLabel ){ |
| 814 | zLabel = mprintf( |
| 815 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 816 | g.zTop, zUuid, zUuid, zDate, zUser |
| 817 | ); |
| 818 | }else{ |
| 819 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 820 | } |
| 821 | p->nVers++; |
| 822 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 823 | p->azVers[p->nVers-1] = zLabel; |
| 824 | content_get(pid, &step); |
| 825 | annotation_step(p, &step, zLabel); |
| 826 | blob_reset(&step); |
| 827 | } |
| 828 | db_finalize(&q); |
| 829 | free(p->c.aTo); |
| 830 | } |
| @@ -860,20 +907,20 @@ | |
| 860 | if( P("log") ){ |
| 861 | int i; |
| 862 | @ <h2>Versions analyzed:</h2> |
| 863 | @ <ol> |
| 864 | for(i=0; i<ann.nVers; i++){ |
| 865 | @ <li><tt>%s(ann.azVers[i])</tt></li> |
| 866 | } |
| 867 | @ </ol> |
| 868 | @ <hr> |
| 869 | @ <h2>Annotation:</h2> |
| 870 | } |
| 871 | @ <pre> |
| 872 | for(i=0; i<ann.nOrig; i++){ |
| 873 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 874 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 875 | } |
| 876 | @ </pre> |
| 877 | style_footer(); |
| 878 | } |
| 879 | |
| @@ -930,17 +977,25 @@ | |
| 930 | } |
| 931 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 932 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 933 | if( showLog ){ |
| 934 | for(i=0; i<ann.nVers; i++){ |
| 935 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 936 | } |
| 937 | printf("---------------------------------------------------\n"); |
| 938 | } |
| 939 | for(i=0; i<ann.nOrig; i++){ |
| 940 | fossil_print("%s: %.*s\n", |
| 941 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 942 | } |
| 943 | free(ann.azVers); |
| 944 | free(ann.aOrig); |
| 945 | blob_reset(&ann.toAnnotate); |
| 946 | } |
| 947 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -619,10 +619,24 @@ | |
| 619 | /************************************************************************** |
| 620 | ** The basic difference engine is above. What follows is the annotation |
| 621 | ** engine. Both are in the same file since they share many components. |
| 622 | */ |
| 623 | |
| 624 | /* |
| 625 | ** Linked list of strings, labels used in the annotator code. |
| 626 | ** The elements of the list and the pointed string (str) |
| 627 | ** will be freed once they become totally unreferenced |
| 628 | ** (nref == 0). |
| 629 | */ |
| 630 | struct Label |
| 631 | { |
| 632 | struct Label *prev; /* previous element */ |
| 633 | struct Label *next; /* next element */ |
| 634 | char *str; /* The label string */ |
| 635 | int nref; /* Number of references to the string */ |
| 636 | }; |
| 637 | |
| 638 | /* |
| 639 | ** The status of an annotation operation is recorded by an instance |
| 640 | ** of the following structure. |
| 641 | */ |
| 642 | typedef struct Annotator Annotator; |
| @@ -630,18 +644,19 @@ | |
| 644 | DContext c; /* The diff-engine context */ |
| 645 | struct AnnLine { /* Lines of the original files... */ |
| 646 | const char *z; /* The text of the line */ |
| 647 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 648 | short int iLevel; /* Level at which tag was set */ |
| 649 | struct Label *zSrc; /* Tag showing origin of this line */ |
| 650 | } *aOrig; |
| 651 | int nOrig; /* Number of elements in aOrig[] */ |
| 652 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 653 | int iLevel; /* Current level */ |
| 654 | int nVers; /* Number of versions analyzed */ |
| 655 | struct Label **azVers; /* Names of versions analyzed */ |
| 656 | Blob toAnnotate; |
| 657 | struct Label *firstLabel; |
| 658 | }; |
| 659 | |
| 660 | /* |
| 661 | ** Initialize the annotation process by specifying the file that is |
| 662 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -670,11 +685,11 @@ | |
| 685 | ** being annotated. Do another step of the annotation. Return true |
| 686 | ** if additional annotation is required. zPName is the tag to insert |
| 687 | ** on each line of the file being annotated that was contributed by |
| 688 | ** pParent. Memory to hold zPName is leaked. |
| 689 | */ |
| 690 | static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){ |
| 691 | int i, j; |
| 692 | int lnTo; |
| 693 | int iPrevLevel; |
| 694 | int iThisLevel; |
| 695 | |
| @@ -698,13 +713,22 @@ | |
| 713 | iThisLevel = p->iLevel; |
| 714 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 715 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 716 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 717 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 718 | if (x->zSrc!=0) |
| 719 | { |
| 720 | if(--x->zSrc->nref == 0) |
| 721 | { |
| 722 | free(x->zSrc->str); |
| 723 | x->zSrc->prev->next = x->zSrc->next; |
| 724 | x->zSrc->next->prev = x->zSrc->prev; |
| 725 | free(x->zSrc); |
| 726 | } |
| 727 | } |
| 728 | x->zSrc = zPName; |
| 729 | ++zPName->nref; |
| 730 | x->iLevel = iThisLevel; |
| 731 | } |
| 732 | } |
| 733 | lnTo += p->c.aEdit[i+2]; |
| 734 | } |
| @@ -739,20 +763,36 @@ | |
| 763 | content_get(name_to_rid(g.argv[2]), &x.toAnnotate); |
| 764 | if( annotation_start(&x) ){ |
| 765 | fossil_fatal("binary file"); |
| 766 | } |
| 767 | for(i=3; i<g.argc; i++){ |
| 768 | struct Label *l; |
| 769 | blob_zero(&b); |
| 770 | content_get(name_to_rid(g.argv[i]), &b); |
| 771 | l = fossil_malloc(sizeof(*l)); |
| 772 | l->str = g.argv[i-1]; |
| 773 | l->nref = 0; |
| 774 | l->next = x.firstLabel; |
| 775 | if (x.firstLabel) |
| 776 | x.firstLabel->prev = l; |
| 777 | x.firstLabel = l; |
| 778 | if( annotation_step(&x, &b, l) ){ |
| 779 | fossil_fatal("binary file"); |
| 780 | } |
| 781 | } |
| 782 | for(i=0; i<x.nOrig; i++){ |
| 783 | const char *zSrc = x.aOrig[i].zSrc->str; |
| 784 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 785 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 786 | } |
| 787 | while(x.firstLabel) { |
| 788 | struct Label *l; |
| 789 | l = x.firstLabel->next; |
| 790 | assert(x.firstLabel->nref > 0); |
| 791 | free(x.firstLabel->str); |
| 792 | free(x.firstLabel); |
| 793 | x.firstLabel = l; |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | /* Annotation flags */ |
| 798 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| @@ -770,11 +810,10 @@ | |
| 810 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 811 | int annFlags /* Flags to alter the annotation */ |
| 812 | ){ |
| 813 | Blob step = empty_blob; /* Text of previous revision */ |
| 814 | int rid; /* Artifact ID of the file being annotated */ |
| 815 | Stmt q; /* Query returning all ancestor versions */ |
| 816 | |
| 817 | /* Initialize the annotation */ |
| 818 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 819 | if( rid==0 ){ |
| @@ -808,23 +847,31 @@ | |
| 847 | while( db_step(&q)==SQLITE_ROW ){ |
| 848 | int pid = db_column_int(&q, 0); |
| 849 | const char *zUuid = db_column_text(&q, 1); |
| 850 | const char *zDate = db_column_text(&q, 2); |
| 851 | const char *zUser = db_column_text(&q, 3); |
| 852 | struct Label *l = fossil_malloc(sizeof(*l)); |
| 853 | l->nref = 0; |
| 854 | l->next = p->firstLabel; |
| 855 | if (p->firstLabel) |
| 856 | p->firstLabel->prev = l; |
| 857 | if( webLabel ){ |
| 858 | l->str = mprintf( |
| 859 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 860 | g.zTop, zUuid, zUuid, zDate, zUser |
| 861 | ); |
| 862 | }else{ |
| 863 | l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 864 | } |
| 865 | p->firstLabel = l; |
| 866 | p->nVers++; |
| 867 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 868 | p->azVers[p->nVers-1] = l; |
| 869 | content_get(pid, &step); |
| 870 | annotation_step(p, &step, l); |
| 871 | if (l->nref == 0) |
| 872 | free(l->str); |
| 873 | blob_reset(&step); |
| 874 | } |
| 875 | db_finalize(&q); |
| 876 | free(p->c.aTo); |
| 877 | } |
| @@ -860,20 +907,20 @@ | |
| 907 | if( P("log") ){ |
| 908 | int i; |
| 909 | @ <h2>Versions analyzed:</h2> |
| 910 | @ <ol> |
| 911 | for(i=0; i<ann.nVers; i++){ |
| 912 | @ <li><tt>%s(ann.azVers[i]->str)</tt></li> |
| 913 | } |
| 914 | @ </ol> |
| 915 | @ <hr> |
| 916 | @ <h2>Annotation:</h2> |
| 917 | } |
| 918 | @ <pre> |
| 919 | for(i=0; i<ann.nOrig; i++){ |
| 920 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 921 | @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z) |
| 922 | } |
| 923 | @ </pre> |
| 924 | style_footer(); |
| 925 | } |
| 926 | |
| @@ -930,17 +977,25 @@ | |
| 977 | } |
| 978 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 979 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 980 | if( showLog ){ |
| 981 | for(i=0; i<ann.nVers; i++){ |
| 982 | printf("version %3d: %s\n", i+1, ann.azVers[i]->str); |
| 983 | } |
| 984 | printf("---------------------------------------------------\n"); |
| 985 | } |
| 986 | for(i=0; i<ann.nOrig; i++){ |
| 987 | fossil_print("%s: %.*s\n", |
| 988 | ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z); |
| 989 | } |
| 990 | free(ann.azVers); |
| 991 | free(ann.aOrig); |
| 992 | blob_reset(&ann.toAnnotate); |
| 993 | while(ann.firstLabel) { |
| 994 | struct Label *l; |
| 995 | l = ann.firstLabel->next; |
| 996 | assert(ann.firstLabel->nref > 0); |
| 997 | free(ann.firstLabel->str); |
| 998 | free(ann.firstLabel); |
| 999 | ann.firstLabel = l; |
| 1000 | } |
| 1001 | } |
| 1002 |