Fossil SCM
Implementation of a linked list to solve the memory leak described in a TODO in [e2ebb1f5cae8]
Commit
ef8266b710505ed189f1d016aff319fabcbd8acf
Parent
e2ebb1f5cae83e8…
1 file changed
+64
-16
+64
-16
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -624,24 +624,32 @@ | ||
| 624 | 624 | /* |
| 625 | 625 | ** The status of an annotation operation is recorded by an instance |
| 626 | 626 | ** of the following structure. |
| 627 | 627 | */ |
| 628 | 628 | typedef struct Annotator Annotator; |
| 629 | +struct Label | |
| 630 | +{ | |
| 631 | + struct Label *prev; | |
| 632 | + struct Label *next; | |
| 633 | + char *str; | |
| 634 | + int nref; | |
| 635 | +}; | |
| 629 | 636 | struct Annotator { |
| 630 | 637 | DContext c; /* The diff-engine context */ |
| 631 | 638 | struct AnnLine { /* Lines of the original files... */ |
| 632 | 639 | const char *z; /* The text of the line */ |
| 633 | 640 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | 641 | short int iLevel; /* Level at which tag was set */ |
| 635 | - const char *zSrc; /* Tag showing origin of this line */ | |
| 642 | + struct Label *zSrc; /* Tag showing origin of this line */ | |
| 636 | 643 | } *aOrig; |
| 637 | 644 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | 645 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | 646 | int iLevel; /* Current level */ |
| 640 | 647 | int nVers; /* Number of versions analyzed */ |
| 641 | - char **azVers; /* Names of versions analyzed */ | |
| 648 | + struct Label **azVers; /* Names of versions analyzed */ | |
| 642 | 649 | Blob toAnnotate; |
| 650 | + struct Label *firstLabel; | |
| 643 | 651 | }; |
| 644 | 652 | |
| 645 | 653 | /* |
| 646 | 654 | ** Initialize the annotation process by specifying the file that is |
| 647 | 655 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -670,11 +678,11 @@ | ||
| 670 | 678 | ** being annotated. Do another step of the annotation. Return true |
| 671 | 679 | ** if additional annotation is required. zPName is the tag to insert |
| 672 | 680 | ** on each line of the file being annotated that was contributed by |
| 673 | 681 | ** pParent. Memory to hold zPName is leaked. |
| 674 | 682 | */ |
| 675 | -static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ | |
| 683 | +static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){ | |
| 676 | 684 | int i, j; |
| 677 | 685 | int lnTo; |
| 678 | 686 | int iPrevLevel; |
| 679 | 687 | int iThisLevel; |
| 680 | 688 | |
| @@ -698,13 +706,22 @@ | ||
| 698 | 706 | iThisLevel = p->iLevel; |
| 699 | 707 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 700 | 708 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 701 | 709 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 702 | 710 | 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 */ | |
| 711 | + if (x->zSrc!=0) | |
| 712 | + { | |
| 713 | + if(--x->zSrc->nref == 0) | |
| 714 | + { | |
| 715 | + free(x->zSrc->str); | |
| 716 | + x->zSrc->prev->next = x->zSrc->next; | |
| 717 | + x->zSrc->next->prev = x->zSrc->prev; | |
| 718 | + free(x->zSrc); | |
| 719 | + } | |
| 720 | + } | |
| 705 | 721 | x->zSrc = zPName; |
| 722 | + ++zPName->nref; | |
| 706 | 723 | x->iLevel = iThisLevel; |
| 707 | 724 | } |
| 708 | 725 | } |
| 709 | 726 | lnTo += p->c.aEdit[i+2]; |
| 710 | 727 | } |
| @@ -739,20 +756,36 @@ | ||
| 739 | 756 | content_get(name_to_rid(g.argv[2]), &x.toAnnotate); |
| 740 | 757 | if( annotation_start(&x) ){ |
| 741 | 758 | fossil_fatal("binary file"); |
| 742 | 759 | } |
| 743 | 760 | for(i=3; i<g.argc; i++){ |
| 761 | + struct Label *l; | |
| 744 | 762 | blob_zero(&b); |
| 745 | 763 | content_get(name_to_rid(g.argv[i]), &b); |
| 746 | - if( annotation_step(&x, &b, g.argv[i-1]) ){ | |
| 764 | + l = fossil_malloc(sizeof(*l)); | |
| 765 | + l->str = g.argv[i-1]; | |
| 766 | + l->nref = 0; | |
| 767 | + l->next = x.firstLabel; | |
| 768 | + if (x.firstLabel) | |
| 769 | + x.firstLabel->prev = l; | |
| 770 | + x.firstLabel = l; | |
| 771 | + if( annotation_step(&x, &b, l) ){ | |
| 747 | 772 | fossil_fatal("binary file"); |
| 748 | 773 | } |
| 749 | 774 | } |
| 750 | 775 | for(i=0; i<x.nOrig; i++){ |
| 751 | - const char *zSrc = x.aOrig[i].zSrc; | |
| 776 | + const char *zSrc = x.aOrig[i].zSrc->str; | |
| 752 | 777 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 753 | 778 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 779 | + } | |
| 780 | + while(x.firstLabel) { | |
| 781 | + struct Label *l; | |
| 782 | + l = x.firstLabel->next; | |
| 783 | + assert(x.firstLabel->nref > 0); | |
| 784 | + free(x.firstLabel->str); | |
| 785 | + free(x.firstLabel); | |
| 786 | + x.firstLabel = l; | |
| 754 | 787 | } |
| 755 | 788 | } |
| 756 | 789 | |
| 757 | 790 | /* Annotation flags */ |
| 758 | 791 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| @@ -770,11 +803,10 @@ | ||
| 770 | 803 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 771 | 804 | int annFlags /* Flags to alter the annotation */ |
| 772 | 805 | ){ |
| 773 | 806 | Blob step = empty_blob; /* Text of previous revision */ |
| 774 | 807 | int rid; /* Artifact ID of the file being annotated */ |
| 775 | - char *zLabel; /* Label to apply to a line */ | |
| 776 | 808 | Stmt q; /* Query returning all ancestor versions */ |
| 777 | 809 | |
| 778 | 810 | /* Initialize the annotation */ |
| 779 | 811 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 780 | 812 | if( rid==0 ){ |
| @@ -808,23 +840,31 @@ | ||
| 808 | 840 | while( db_step(&q)==SQLITE_ROW ){ |
| 809 | 841 | int pid = db_column_int(&q, 0); |
| 810 | 842 | const char *zUuid = db_column_text(&q, 1); |
| 811 | 843 | const char *zDate = db_column_text(&q, 2); |
| 812 | 844 | const char *zUser = db_column_text(&q, 3); |
| 845 | + struct Label *l = fossil_malloc(sizeof(*l)); | |
| 846 | + l->nref = 0; | |
| 847 | + l->next = p->firstLabel; | |
| 848 | + if (p->firstLabel) | |
| 849 | + p->firstLabel->prev = l; | |
| 813 | 850 | if( webLabel ){ |
| 814 | - zLabel = mprintf( | |
| 851 | + l->str = mprintf( | |
| 815 | 852 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 816 | 853 | g.zTop, zUuid, zUuid, zDate, zUser |
| 817 | 854 | ); |
| 818 | 855 | }else{ |
| 819 | - zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); | |
| 856 | + l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); | |
| 820 | 857 | } |
| 858 | + p->firstLabel = l; | |
| 821 | 859 | p->nVers++; |
| 822 | 860 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 823 | - p->azVers[p->nVers-1] = zLabel; | |
| 861 | + p->azVers[p->nVers-1] = l; | |
| 824 | 862 | content_get(pid, &step); |
| 825 | - annotation_step(p, &step, zLabel); | |
| 863 | + annotation_step(p, &step, l); | |
| 864 | + if (l->nref == 0) | |
| 865 | + free(l->str); | |
| 826 | 866 | blob_reset(&step); |
| 827 | 867 | } |
| 828 | 868 | db_finalize(&q); |
| 829 | 869 | free(p->c.aTo); |
| 830 | 870 | } |
| @@ -860,20 +900,20 @@ | ||
| 860 | 900 | if( P("log") ){ |
| 861 | 901 | int i; |
| 862 | 902 | @ <h2>Versions analyzed:</h2> |
| 863 | 903 | @ <ol> |
| 864 | 904 | for(i=0; i<ann.nVers; i++){ |
| 865 | - @ <li><tt>%s(ann.azVers[i])</tt></li> | |
| 905 | + @ <li><tt>%s(ann.azVers[i]->str)</tt></li> | |
| 866 | 906 | } |
| 867 | 907 | @ </ol> |
| 868 | 908 | @ <hr> |
| 869 | 909 | @ <h2>Annotation:</h2> |
| 870 | 910 | } |
| 871 | 911 | @ <pre> |
| 872 | 912 | for(i=0; i<ann.nOrig; i++){ |
| 873 | 913 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 874 | - @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) | |
| 914 | + @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z) | |
| 875 | 915 | } |
| 876 | 916 | @ </pre> |
| 877 | 917 | style_footer(); |
| 878 | 918 | } |
| 879 | 919 | |
| @@ -930,17 +970,25 @@ | ||
| 930 | 970 | } |
| 931 | 971 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 932 | 972 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 933 | 973 | if( showLog ){ |
| 934 | 974 | for(i=0; i<ann.nVers; i++){ |
| 935 | - printf("version %3d: %s\n", i+1, ann.azVers[i]); | |
| 975 | + printf("version %3d: %s\n", i+1, ann.azVers[i]->str); | |
| 936 | 976 | } |
| 937 | 977 | printf("---------------------------------------------------\n"); |
| 938 | 978 | } |
| 939 | 979 | for(i=0; i<ann.nOrig; i++){ |
| 940 | 980 | fossil_print("%s: %.*s\n", |
| 941 | - ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 981 | + ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 942 | 982 | } |
| 943 | 983 | free(ann.azVers); |
| 944 | 984 | free(ann.aOrig); |
| 945 | 985 | blob_reset(&ann.toAnnotate); |
| 986 | + while(ann.firstLabel) { | |
| 987 | + struct Label *l; | |
| 988 | + l = ann.firstLabel->next; | |
| 989 | + assert(ann.firstLabel->nref > 0); | |
| 990 | + free(ann.firstLabel->str); | |
| 991 | + free(ann.firstLabel); | |
| 992 | + ann.firstLabel = l; | |
| 993 | + } | |
| 946 | 994 | } |
| 947 | 995 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -624,24 +624,32 @@ | |
| 624 | /* |
| 625 | ** The status of an annotation operation is recorded by an instance |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 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 +678,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 +706,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 +756,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 +803,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 +840,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 +900,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 +970,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 | |
| @@ -624,24 +624,32 @@ | |
| 624 | /* |
| 625 | ** The status of an annotation operation is recorded by an instance |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Label |
| 630 | { |
| 631 | struct Label *prev; |
| 632 | struct Label *next; |
| 633 | char *str; |
| 634 | int nref; |
| 635 | }; |
| 636 | struct Annotator { |
| 637 | DContext c; /* The diff-engine context */ |
| 638 | struct AnnLine { /* Lines of the original files... */ |
| 639 | const char *z; /* The text of the line */ |
| 640 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 641 | short int iLevel; /* Level at which tag was set */ |
| 642 | struct Label *zSrc; /* Tag showing origin of this line */ |
| 643 | } *aOrig; |
| 644 | int nOrig; /* Number of elements in aOrig[] */ |
| 645 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 646 | int iLevel; /* Current level */ |
| 647 | int nVers; /* Number of versions analyzed */ |
| 648 | struct Label **azVers; /* Names of versions analyzed */ |
| 649 | Blob toAnnotate; |
| 650 | struct Label *firstLabel; |
| 651 | }; |
| 652 | |
| 653 | /* |
| 654 | ** Initialize the annotation process by specifying the file that is |
| 655 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -670,11 +678,11 @@ | |
| 678 | ** being annotated. Do another step of the annotation. Return true |
| 679 | ** if additional annotation is required. zPName is the tag to insert |
| 680 | ** on each line of the file being annotated that was contributed by |
| 681 | ** pParent. Memory to hold zPName is leaked. |
| 682 | */ |
| 683 | static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){ |
| 684 | int i, j; |
| 685 | int lnTo; |
| 686 | int iPrevLevel; |
| 687 | int iThisLevel; |
| 688 | |
| @@ -698,13 +706,22 @@ | |
| 706 | iThisLevel = p->iLevel; |
| 707 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 708 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 709 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 710 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 711 | if (x->zSrc!=0) |
| 712 | { |
| 713 | if(--x->zSrc->nref == 0) |
| 714 | { |
| 715 | free(x->zSrc->str); |
| 716 | x->zSrc->prev->next = x->zSrc->next; |
| 717 | x->zSrc->next->prev = x->zSrc->prev; |
| 718 | free(x->zSrc); |
| 719 | } |
| 720 | } |
| 721 | x->zSrc = zPName; |
| 722 | ++zPName->nref; |
| 723 | x->iLevel = iThisLevel; |
| 724 | } |
| 725 | } |
| 726 | lnTo += p->c.aEdit[i+2]; |
| 727 | } |
| @@ -739,20 +756,36 @@ | |
| 756 | content_get(name_to_rid(g.argv[2]), &x.toAnnotate); |
| 757 | if( annotation_start(&x) ){ |
| 758 | fossil_fatal("binary file"); |
| 759 | } |
| 760 | for(i=3; i<g.argc; i++){ |
| 761 | struct Label *l; |
| 762 | blob_zero(&b); |
| 763 | content_get(name_to_rid(g.argv[i]), &b); |
| 764 | l = fossil_malloc(sizeof(*l)); |
| 765 | l->str = g.argv[i-1]; |
| 766 | l->nref = 0; |
| 767 | l->next = x.firstLabel; |
| 768 | if (x.firstLabel) |
| 769 | x.firstLabel->prev = l; |
| 770 | x.firstLabel = l; |
| 771 | if( annotation_step(&x, &b, l) ){ |
| 772 | fossil_fatal("binary file"); |
| 773 | } |
| 774 | } |
| 775 | for(i=0; i<x.nOrig; i++){ |
| 776 | const char *zSrc = x.aOrig[i].zSrc->str; |
| 777 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 778 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 779 | } |
| 780 | while(x.firstLabel) { |
| 781 | struct Label *l; |
| 782 | l = x.firstLabel->next; |
| 783 | assert(x.firstLabel->nref > 0); |
| 784 | free(x.firstLabel->str); |
| 785 | free(x.firstLabel); |
| 786 | x.firstLabel = l; |
| 787 | } |
| 788 | } |
| 789 | |
| 790 | /* Annotation flags */ |
| 791 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| @@ -770,11 +803,10 @@ | |
| 803 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 804 | int annFlags /* Flags to alter the annotation */ |
| 805 | ){ |
| 806 | Blob step = empty_blob; /* Text of previous revision */ |
| 807 | int rid; /* Artifact ID of the file being annotated */ |
| 808 | Stmt q; /* Query returning all ancestor versions */ |
| 809 | |
| 810 | /* Initialize the annotation */ |
| 811 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 812 | if( rid==0 ){ |
| @@ -808,23 +840,31 @@ | |
| 840 | while( db_step(&q)==SQLITE_ROW ){ |
| 841 | int pid = db_column_int(&q, 0); |
| 842 | const char *zUuid = db_column_text(&q, 1); |
| 843 | const char *zDate = db_column_text(&q, 2); |
| 844 | const char *zUser = db_column_text(&q, 3); |
| 845 | struct Label *l = fossil_malloc(sizeof(*l)); |
| 846 | l->nref = 0; |
| 847 | l->next = p->firstLabel; |
| 848 | if (p->firstLabel) |
| 849 | p->firstLabel->prev = l; |
| 850 | if( webLabel ){ |
| 851 | l->str = mprintf( |
| 852 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 853 | g.zTop, zUuid, zUuid, zDate, zUser |
| 854 | ); |
| 855 | }else{ |
| 856 | l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 857 | } |
| 858 | p->firstLabel = l; |
| 859 | p->nVers++; |
| 860 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 861 | p->azVers[p->nVers-1] = l; |
| 862 | content_get(pid, &step); |
| 863 | annotation_step(p, &step, l); |
| 864 | if (l->nref == 0) |
| 865 | free(l->str); |
| 866 | blob_reset(&step); |
| 867 | } |
| 868 | db_finalize(&q); |
| 869 | free(p->c.aTo); |
| 870 | } |
| @@ -860,20 +900,20 @@ | |
| 900 | if( P("log") ){ |
| 901 | int i; |
| 902 | @ <h2>Versions analyzed:</h2> |
| 903 | @ <ol> |
| 904 | for(i=0; i<ann.nVers; i++){ |
| 905 | @ <li><tt>%s(ann.azVers[i]->str)</tt></li> |
| 906 | } |
| 907 | @ </ol> |
| 908 | @ <hr> |
| 909 | @ <h2>Annotation:</h2> |
| 910 | } |
| 911 | @ <pre> |
| 912 | for(i=0; i<ann.nOrig; i++){ |
| 913 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 914 | @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z) |
| 915 | } |
| 916 | @ </pre> |
| 917 | style_footer(); |
| 918 | } |
| 919 | |
| @@ -930,17 +970,25 @@ | |
| 970 | } |
| 971 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 972 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 973 | if( showLog ){ |
| 974 | for(i=0; i<ann.nVers; i++){ |
| 975 | printf("version %3d: %s\n", i+1, ann.azVers[i]->str); |
| 976 | } |
| 977 | printf("---------------------------------------------------\n"); |
| 978 | } |
| 979 | for(i=0; i<ann.nOrig; i++){ |
| 980 | fossil_print("%s: %.*s\n", |
| 981 | ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z); |
| 982 | } |
| 983 | free(ann.azVers); |
| 984 | free(ann.aOrig); |
| 985 | blob_reset(&ann.toAnnotate); |
| 986 | while(ann.firstLabel) { |
| 987 | struct Label *l; |
| 988 | l = ann.firstLabel->next; |
| 989 | assert(ann.firstLabel->nref > 0); |
| 990 | free(ann.firstLabel->str); |
| 991 | free(ann.firstLabel); |
| 992 | ann.firstLabel = l; |
| 993 | } |
| 994 | } |
| 995 |