Index: src/blob.c ================================================================== --- src/blob.c +++ src/blob.c @@ -894,11 +894,11 @@ */ int blob_uncompress(Blob *pIn, Blob *pOut){ unsigned int nOut; unsigned char *inBuf; unsigned int nIn = blob_size(pIn); - Blob temp; + Blob temp = empty_blob; int rc; unsigned long int nOut2; if( nIn<=4 ){ return 0; } Index: src/content.c ================================================================== --- src/content.c +++ src/content.c @@ -95,11 +95,11 @@ p = &contentCache.a[contentCache.n++]; p->rid = rid; p->age = contentCache.nextAge++; contentCache.szTotal += blob_size(pBlob); p->content = *pBlob; - blob_zero(pBlob); + *pBlob = empty_blob; bag_insert(&contentCache.inCache, rid); } /* ** Clear the content cache. @@ -259,11 +259,11 @@ }else{ int n = 1; int nAlloc = 10; int *a = 0; int mx; - Blob delta, next; + Blob delta = empty_blob, next = empty_blob; a = fossil_malloc( sizeof(a[0])*nAlloc ); a[0] = rid; a[1] = nextRid; n = 1; Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -211,11 +211,11 @@ ** one is processed. All statements beyond the first are silently ignored. */ int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){ int rc; char *zSql; - blob_zero(&pStmt->sql); + pStmt->sql = empty_blob; blob_vappendf(&pStmt->sql, zFormat, ap); va_end(ap); zSql = blob_str(&pStmt->sql); nPrepare++; rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0); Index: src/deltacmd.c ================================================================== --- src/deltacmd.c +++ src/deltacmd.c @@ -77,11 +77,11 @@ ** ** Return the length of the target. Return -1 if there is an error. */ int blob_delta_apply(Blob *pOriginal, Blob *pDelta, Blob *pTarget){ int len, n; - Blob out; + Blob out = empty_blob; n = delta_output_size(blob_buffer(pDelta), blob_size(pDelta)); blob_zero(&out); if( n<0 ) return -1; blob_resize(&out, n); 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,29 +644,31 @@ 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 ** will release it when it is finished with it. */ -static int annotation_start(Annotator *p, Blob *pInput){ +static int annotation_start(Annotator *p){ int i; - memset(p, 0, sizeof(*p)); - p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1); + p->c.aTo = break_into_lines(blob_str(&p->toAnnotate), + blob_size(&p->toAnnotate),&p->c.nTo,1); if( p->c.aTo==0 ){ return 1; } p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo ); for(i=0; ic.nTo; i++){ @@ -669,20 +685,21 @@ ** 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; /* Prepare the parent file to be diffed */ p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), &p->c.nFrom, 1); if( p->c.aFrom==0 ){ + free(p->c.aFrom); return 1; } /* Compute the differences going from pParent to the file being ** annotated. */ @@ -696,11 +713,24 @@ 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 ){ + if (x->zSrc!=0) + { + if(--x->zSrc->nref == 0) + { + free(x->zSrc->str); + if (x->zSrc->prev) + x->zSrc->prev->next = x->zSrc->next; + if (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]; } @@ -711,11 +741,11 @@ p->c.nEdit = 0; p->c.nEditAlloc = 0; /* Clear out the from file */ free(p->c.aFrom); - blob_zero(pParent); + blob_reset(pParent); /* Return no errors */ return 0; } @@ -722,32 +752,49 @@ /* ** COMMAND: test-annotate-step */ void test_annotate_step_cmd(void){ - Blob orig, b; + Blob b = empty_blob; Annotator x; int i; if( g.argc<4 ) usage("RID1 RID2 ..."); db_must_be_within_tree(); - blob_zero(&b); - content_get(name_to_rid(g.argv[2]), &orig); - if( annotation_start(&x, &orig) ){ + memset(&x, 0, sizeof(x)); + x.toAnnotate = empty_blob; + 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 */ @@ -763,28 +810,28 @@ int mid, /* Use the version of the file in this check-in */ int webLabel, /* Use web-style annotations if true */ int iLimit, /* Limit the number of levels if greater than zero */ int annFlags /* Flags to alter the annotation */ ){ - Blob toAnnotate; /* Text of the final (mid) version of the file */ - Blob step; /* Text of previous revision */ + 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 ){ fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); } - if( !content_get(rid, &toAnnotate) ){ + memset(p, 0, sizeof(*p)); + p->toAnnotate = empty_blob; + if( !content_get(rid, &p->toAnnotate) ){ fossil_panic("unable to retrieve content of artifact #%d", rid); } db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); if( iLimit<=0 ) iLimit = 1000000000; compute_direct_ancestors(mid, iLimit); - annotation_start(p, &toAnnotate); + annotation_start(p); db_prepare(&q, "SELECT mlink.fid," " (SELECT uuid FROM blob WHERE rid=mlink.%s)," " date(event.mtime), " @@ -802,26 +849,42 @@ 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; + l->prev = 0; + 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); + p->firstLabel = l->next; + if (l->next) + l->next->prev = 0; + free(l); + } blob_reset(&step); } db_finalize(&q); + free(p->c.aTo); } /* ** WEBPAGE: annotate ** @@ -853,23 +916,35 @@ 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(); + + 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; + } } /* ** COMMAND: annotate ** @@ -885,11 +960,11 @@ */ void annotate_cmd(void){ int fnid; /* Filename ID */ int fid; /* File instance ID */ int mid; /* Manifest where file was checked in */ - Blob treename; /* FILENAME translated to canonical form */ + Blob treename = empty_blob; /* FILENAME translated to canonical form */ char *zFilename; /* Cannonical filename */ Annotator ann; /* The annotation of the file */ int i; /* Loop counter */ const char *zLimit; /* The value to the --limit option */ int iLimit; /* How far back in time to look */ @@ -914,22 +989,34 @@ } fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename); if( fid==0 ){ fossil_fatal("not part of current checkout: %s", zFilename); } + blob_reset(&treename); mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); if( mid==0 ){ fossil_panic("unable to find manifest"); } 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; } } Index: src/file.c ================================================================== --- src/file.c +++ src/file.c @@ -701,11 +701,11 @@ ** ** The root of the tree is defined by the g.zLocalRoot variable. */ int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){ int n; - Blob full; + Blob full = empty_blob; int nFull; char *zFull; blob_zero(pOut); db_must_be_within_tree();