Index: src/diff.c ================================================================== --- src/diff.c +++ src/diff.c @@ -619,10 +619,24 @@ /************************************************************************** ** The basic difference engine is above. What follows is the annotation ** engine. Both are in the same file since they share many components. */ +/* +** Linked list of strings, labels used in the annotator code. +** The elements of the list and the pointed string (str) +** will be freed once they become totally unreferenced +** (nref == 0). +*/ +struct Label +{ + struct Label *prev; /* previous element */ + struct Label *next; /* next element */ + char *str; /* The label string */ + int nref; /* Number of references to the string */ +}; + /* ** The status of an annotation operation is recorded by an instance ** of the following structure. */ typedef struct Annotator Annotator; @@ -630,18 +644,19 @@ DContext c; /* The diff-engine context */ struct AnnLine { /* Lines of the original files... */ const char *z; /* The text of the line */ short int n; /* Number of bytes (omitting trailing space and \n) */ short int iLevel; /* Level at which tag was set */ - const char *zSrc; /* Tag showing origin of this line */ + struct Label *zSrc; /* Tag showing origin of this line */ } *aOrig; int nOrig; /* Number of elements in aOrig[] */ int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ int iLevel; /* Current level */ int nVers; /* Number of versions analyzed */ - char **azVers; /* Names of versions analyzed */ + struct Label **azVers; /* Names of versions analyzed */ Blob toAnnotate; + struct Label *firstLabel; }; /* ** Initialize the annotation process by specifying the file that is ** to be annotated. The annotator takes control of the input Blob and @@ -670,11 +685,11 @@ ** being annotated. Do another step of the annotation. Return true ** if additional annotation is required. zPName is the tag to insert ** on each line of the file being annotated that was contributed by ** pParent. Memory to hold zPName is leaked. */ -static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ +static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){ int i, j; int lnTo; int iPrevLevel; int iThisLevel; @@ -698,13 +713,22 @@ iThisLevel = p->iLevel; for(i=lnTo=0; ic.nEdit; i+=3){ struct AnnLine *x = &p->aOrig[lnTo]; for(j=0; jc.aEdit[i]; j++, lnTo++, x++){ if( x->zSrc==0 || x->iLevel==iPrevLevel ){ - /* TODO: handle zPName so we can free labels - * if they get totally unreferenced in the Annotator */ + if (x->zSrc!=0) + { + if(--x->zSrc->nref == 0) + { + free(x->zSrc->str); + x->zSrc->prev->next = x->zSrc->next; + x->zSrc->next->prev = x->zSrc->prev; + free(x->zSrc); + } + } x->zSrc = zPName; + ++zPName->nref; x->iLevel = iThisLevel; } } lnTo += p->c.aEdit[i+2]; } @@ -739,20 +763,36 @@ content_get(name_to_rid(g.argv[2]), &x.toAnnotate); if( annotation_start(&x) ){ fossil_fatal("binary file"); } for(i=3; istr = g.argv[i-1]; + l->nref = 0; + l->next = x.firstLabel; + if (x.firstLabel) + x.firstLabel->prev = l; + x.firstLabel = l; + if( annotation_step(&x, &b, l) ){ fossil_fatal("binary file"); } } for(i=0; istr; if( zSrc==0 ) zSrc = g.argv[g.argc-1]; fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); + } + while(x.firstLabel) { + struct Label *l; + l = x.firstLabel->next; + assert(x.firstLabel->nref > 0); + free(x.firstLabel->str); + free(x.firstLabel); + x.firstLabel = l; } } /* Annotation flags */ #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ @@ -770,11 +810,10 @@ int iLimit, /* Limit the number of levels if greater than zero */ int annFlags /* Flags to alter the annotation */ ){ Blob step = empty_blob; /* Text of previous revision */ int rid; /* Artifact ID of the file being annotated */ - char *zLabel; /* Label to apply to a line */ Stmt q; /* Query returning all ancestor versions */ /* Initialize the annotation */ rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); if( rid==0 ){ @@ -808,23 +847,31 @@ while( db_step(&q)==SQLITE_ROW ){ int pid = db_column_int(&q, 0); const char *zUuid = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); const char *zUser = db_column_text(&q, 3); + struct Label *l = fossil_malloc(sizeof(*l)); + l->nref = 0; + l->next = p->firstLabel; + if (p->firstLabel) + p->firstLabel->prev = l; if( webLabel ){ - zLabel = mprintf( + l->str = mprintf( "%.10s %s %9.9s", g.zTop, zUuid, zUuid, zDate, zUser ); }else{ - zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); + l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); } + p->firstLabel = l; p->nVers++; p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); - p->azVers[p->nVers-1] = zLabel; + p->azVers[p->nVers-1] = l; content_get(pid, &step); - annotation_step(p, &step, zLabel); + annotation_step(p, &step, l); + if (l->nref == 0) + free(l->str); blob_reset(&step); } db_finalize(&q); free(p->c.aTo); } @@ -860,20 +907,20 @@ if( P("log") ){ int i; @

Versions analyzed:

@
    for(i=0; i%s(ann.azVers[i]) + @
  1. %s(ann.azVers[i]->str)
  2. } @
@
@

Annotation:

} @
   for(i=0; istr): %h(ann.aOrig[i].z)
   }
   @ 
style_footer(); } @@ -930,17 +977,25 @@ } if( fileVers ) annFlags |= ANN_FILE_VERS; annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); if( showLog ){ for(i=0; istr); } printf("---------------------------------------------------\n"); } for(i=0; istr, ann.aOrig[i].n, ann.aOrig[i].z); } free(ann.azVers); free(ann.aOrig); blob_reset(&ann.toAnnotate); + while(ann.firstLabel) { + struct Label *l; + l = ann.firstLabel->next; + assert(ann.firstLabel->nref > 0); + free(ann.firstLabel->str); + free(ann.firstLabel); + ann.firstLabel = l; + } }