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; i<p->c.nEdit; i+=3){ struct AnnLine *x = &p->aOrig[lnTo]; for(j=0; j<p->c.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; i<g.argc; i++){ + struct Label *l; blob_zero(&b); content_get(name_to_rid(g.argv[i]), &b); - if( annotation_step(&x, &b, g.argv[i-1]) ){ + l = fossil_malloc(sizeof(*l)); + l->str = 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; i<x.nOrig; i++){ - const char *zSrc = x.aOrig[i].zSrc; + const char *zSrc = x.aOrig[i].zSrc->str; 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( "<a href='%s/info/%s' target='infowindow'>%.10s</a> %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; @ <h2>Versions analyzed:</h2> @ <ol> for(i=0; i<ann.nVers; i++){ - @ <li><tt>%s(ann.azVers[i])</tt></li> + @ <li><tt>%s(ann.azVers[i]->str)</tt></li> } @ </ol> @ <hr> @ <h2>Annotation:</h2> } @ <pre> for(i=0; i<ann.nOrig; i++){ ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; - @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) + @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z) } @ </pre> 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; i<ann.nVers; i++){ - printf("version %3d: %s\n", i+1, ann.azVers[i]); + printf("version %3d: %s\n", i+1, ann.azVers[i]->str); } printf("---------------------------------------------------\n"); } for(i=0; i<ann.nOrig; i++){ fossil_print("%s: %.*s\n", - ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); + ann.aOrig[i].zSrc->str, 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; + } }