Fossil SCM

Merging the annotate_noleak changes, about removing an important memory leak in the annotate operation. It also fixes some blob behaviour in blob.c and content.c.

viriketo 2011-10-14 16:11 UTC trunk merge
Commit 409f370a6db42088e046ae32cd9728900e1f7da6
+1 -1
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920920
*/
921921
int blob_uncompress(Blob *pIn, Blob *pOut){
922922
unsigned int nOut;
923923
unsigned char *inBuf;
924924
unsigned int nIn = blob_size(pIn);
925
- Blob temp;
925
+ Blob temp = empty_blob;
926926
int rc;
927927
unsigned long int nOut2;
928928
if( nIn<=4 ){
929929
return 0;
930930
}
931931
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920 */
921 int blob_uncompress(Blob *pIn, Blob *pOut){
922 unsigned int nOut;
923 unsigned char *inBuf;
924 unsigned int nIn = blob_size(pIn);
925 Blob temp;
926 int rc;
927 unsigned long int nOut2;
928 if( nIn<=4 ){
929 return 0;
930 }
931
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920 */
921 int blob_uncompress(Blob *pIn, Blob *pOut){
922 unsigned int nOut;
923 unsigned char *inBuf;
924 unsigned int nIn = blob_size(pIn);
925 Blob temp = empty_blob;
926 int rc;
927 unsigned long int nOut2;
928 if( nIn<=4 ){
929 return 0;
930 }
931
+1 -1
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920920
*/
921921
int blob_uncompress(Blob *pIn, Blob *pOut){
922922
unsigned int nOut;
923923
unsigned char *inBuf;
924924
unsigned int nIn = blob_size(pIn);
925
- Blob temp;
925
+ Blob temp = empty_blob;
926926
int rc;
927927
unsigned long int nOut2;
928928
if( nIn<=4 ){
929929
return 0;
930930
}
931931
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920 */
921 int blob_uncompress(Blob *pIn, Blob *pOut){
922 unsigned int nOut;
923 unsigned char *inBuf;
924 unsigned int nIn = blob_size(pIn);
925 Blob temp;
926 int rc;
927 unsigned long int nOut2;
928 if( nIn<=4 ){
929 return 0;
930 }
931
--- src/blob.c
+++ src/blob.c
@@ -920,11 +920,11 @@
920 */
921 int blob_uncompress(Blob *pIn, Blob *pOut){
922 unsigned int nOut;
923 unsigned char *inBuf;
924 unsigned int nIn = blob_size(pIn);
925 Blob temp = empty_blob;
926 int rc;
927 unsigned long int nOut2;
928 if( nIn<=4 ){
929 return 0;
930 }
931
+2 -2
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
9595
p = &contentCache.a[contentCache.n++];
9696
p->rid = rid;
9797
p->age = contentCache.nextAge++;
9898
contentCache.szTotal += blob_size(pBlob);
9999
p->content = *pBlob;
100
- blob_zero(pBlob);
100
+ *pBlob = empty_blob;
101101
bag_insert(&contentCache.inCache, rid);
102102
}
103103
104104
/*
105105
** Clear the content cache.
@@ -259,11 +259,11 @@
259259
}else{
260260
int n = 1;
261261
int nAlloc = 10;
262262
int *a = 0;
263263
int mx;
264
- Blob delta, next;
264
+ Blob delta = empty_blob, next = empty_blob;
265265
266266
a = fossil_malloc( sizeof(a[0])*nAlloc );
267267
a[0] = rid;
268268
a[1] = nextRid;
269269
n = 1;
270270
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
95 p = &contentCache.a[contentCache.n++];
96 p->rid = rid;
97 p->age = contentCache.nextAge++;
98 contentCache.szTotal += blob_size(pBlob);
99 p->content = *pBlob;
100 blob_zero(pBlob);
101 bag_insert(&contentCache.inCache, rid);
102 }
103
104 /*
105 ** Clear the content cache.
@@ -259,11 +259,11 @@
259 }else{
260 int n = 1;
261 int nAlloc = 10;
262 int *a = 0;
263 int mx;
264 Blob delta, next;
265
266 a = fossil_malloc( sizeof(a[0])*nAlloc );
267 a[0] = rid;
268 a[1] = nextRid;
269 n = 1;
270
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
95 p = &contentCache.a[contentCache.n++];
96 p->rid = rid;
97 p->age = contentCache.nextAge++;
98 contentCache.szTotal += blob_size(pBlob);
99 p->content = *pBlob;
100 *pBlob = empty_blob;
101 bag_insert(&contentCache.inCache, rid);
102 }
103
104 /*
105 ** Clear the content cache.
@@ -259,11 +259,11 @@
259 }else{
260 int n = 1;
261 int nAlloc = 10;
262 int *a = 0;
263 int mx;
264 Blob delta = empty_blob, next = empty_blob;
265
266 a = fossil_malloc( sizeof(a[0])*nAlloc );
267 a[0] = rid;
268 a[1] = nextRid;
269 n = 1;
270
+2 -2
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
9595
p = &contentCache.a[contentCache.n++];
9696
p->rid = rid;
9797
p->age = contentCache.nextAge++;
9898
contentCache.szTotal += blob_size(pBlob);
9999
p->content = *pBlob;
100
- blob_zero(pBlob);
100
+ *pBlob = empty_blob;
101101
bag_insert(&contentCache.inCache, rid);
102102
}
103103
104104
/*
105105
** Clear the content cache.
@@ -259,11 +259,11 @@
259259
}else{
260260
int n = 1;
261261
int nAlloc = 10;
262262
int *a = 0;
263263
int mx;
264
- Blob delta, next;
264
+ Blob delta = empty_blob, next = empty_blob;
265265
266266
a = fossil_malloc( sizeof(a[0])*nAlloc );
267267
a[0] = rid;
268268
a[1] = nextRid;
269269
n = 1;
270270
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
95 p = &contentCache.a[contentCache.n++];
96 p->rid = rid;
97 p->age = contentCache.nextAge++;
98 contentCache.szTotal += blob_size(pBlob);
99 p->content = *pBlob;
100 blob_zero(pBlob);
101 bag_insert(&contentCache.inCache, rid);
102 }
103
104 /*
105 ** Clear the content cache.
@@ -259,11 +259,11 @@
259 }else{
260 int n = 1;
261 int nAlloc = 10;
262 int *a = 0;
263 int mx;
264 Blob delta, next;
265
266 a = fossil_malloc( sizeof(a[0])*nAlloc );
267 a[0] = rid;
268 a[1] = nextRid;
269 n = 1;
270
--- src/content.c
+++ src/content.c
@@ -95,11 +95,11 @@
95 p = &contentCache.a[contentCache.n++];
96 p->rid = rid;
97 p->age = contentCache.nextAge++;
98 contentCache.szTotal += blob_size(pBlob);
99 p->content = *pBlob;
100 *pBlob = empty_blob;
101 bag_insert(&contentCache.inCache, rid);
102 }
103
104 /*
105 ** Clear the content cache.
@@ -259,11 +259,11 @@
259 }else{
260 int n = 1;
261 int nAlloc = 10;
262 int *a = 0;
263 int mx;
264 Blob delta = empty_blob, next = empty_blob;
265
266 a = fossil_malloc( sizeof(a[0])*nAlloc );
267 a[0] = rid;
268 a[1] = nextRid;
269 n = 1;
270
+1 -1
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211211
** one is processed. All statements beyond the first are silently ignored.
212212
*/
213213
int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214214
int rc;
215215
char *zSql;
216
- blob_zero(&pStmt->sql);
216
+ pStmt->sql = empty_blob;
217217
blob_vappendf(&pStmt->sql, zFormat, ap);
218218
va_end(ap);
219219
zSql = blob_str(&pStmt->sql);
220220
nPrepare++;
221221
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222222
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211 ** one is processed. All statements beyond the first are silently ignored.
212 */
213 int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214 int rc;
215 char *zSql;
216 blob_zero(&pStmt->sql);
217 blob_vappendf(&pStmt->sql, zFormat, ap);
218 va_end(ap);
219 zSql = blob_str(&pStmt->sql);
220 nPrepare++;
221 rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211 ** one is processed. All statements beyond the first are silently ignored.
212 */
213 int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214 int rc;
215 char *zSql;
216 pStmt->sql = empty_blob;
217 blob_vappendf(&pStmt->sql, zFormat, ap);
218 va_end(ap);
219 zSql = blob_str(&pStmt->sql);
220 nPrepare++;
221 rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222
+1 -1
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211211
** one is processed. All statements beyond the first are silently ignored.
212212
*/
213213
int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214214
int rc;
215215
char *zSql;
216
- blob_zero(&pStmt->sql);
216
+ pStmt->sql = empty_blob;
217217
blob_vappendf(&pStmt->sql, zFormat, ap);
218218
va_end(ap);
219219
zSql = blob_str(&pStmt->sql);
220220
nPrepare++;
221221
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222222
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211 ** one is processed. All statements beyond the first are silently ignored.
212 */
213 int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214 int rc;
215 char *zSql;
216 blob_zero(&pStmt->sql);
217 blob_vappendf(&pStmt->sql, zFormat, ap);
218 va_end(ap);
219 zSql = blob_str(&pStmt->sql);
220 nPrepare++;
221 rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222
--- src/db.c
+++ src/db.c
@@ -211,11 +211,11 @@
211 ** one is processed. All statements beyond the first are silently ignored.
212 */
213 int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
214 int rc;
215 char *zSql;
216 pStmt->sql = empty_blob;
217 blob_vappendf(&pStmt->sql, zFormat, ap);
218 va_end(ap);
219 zSql = blob_str(&pStmt->sql);
220 nPrepare++;
221 rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
222
+1 -1
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -77,11 +77,11 @@
7777
**
7878
** Return the length of the target. Return -1 if there is an error.
7979
*/
8080
int blob_delta_apply(Blob *pOriginal, Blob *pDelta, Blob *pTarget){
8181
int len, n;
82
- Blob out;
82
+ Blob out = empty_blob;
8383
8484
n = delta_output_size(blob_buffer(pDelta), blob_size(pDelta));
8585
blob_zero(&out);
8686
if( n<0 ) return -1;
8787
blob_resize(&out, n);
8888
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -77,11 +77,11 @@
77 **
78 ** Return the length of the target. Return -1 if there is an error.
79 */
80 int blob_delta_apply(Blob *pOriginal, Blob *pDelta, Blob *pTarget){
81 int len, n;
82 Blob out;
83
84 n = delta_output_size(blob_buffer(pDelta), blob_size(pDelta));
85 blob_zero(&out);
86 if( n<0 ) return -1;
87 blob_resize(&out, n);
88
--- src/deltacmd.c
+++ src/deltacmd.c
@@ -77,11 +77,11 @@
77 **
78 ** Return the length of the target. Return -1 if there is an error.
79 */
80 int blob_delta_apply(Blob *pOriginal, Blob *pDelta, Blob *pTarget){
81 int len, n;
82 Blob out = empty_blob;
83
84 n = delta_output_size(blob_buffer(pDelta), blob_size(pDelta));
85 blob_zero(&out);
86 if( n<0 ) return -1;
87 blob_resize(&out, n);
88
+114 -27
--- src/diff.c
+++ src/diff.c
@@ -619,10 +619,24 @@
619619
/**************************************************************************
620620
** The basic difference engine is above. What follows is the annotation
621621
** engine. Both are in the same file since they share many components.
622622
*/
623623
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
+
624638
/*
625639
** The status of an annotation operation is recorded by an instance
626640
** of the following structure.
627641
*/
628642
typedef struct Annotator Annotator;
@@ -630,29 +644,31 @@
630644
DContext c; /* The diff-engine context */
631645
struct AnnLine { /* Lines of the original files... */
632646
const char *z; /* The text of the line */
633647
short int n; /* Number of bytes (omitting trailing space and \n) */
634648
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 */
636650
} *aOrig;
637651
int nOrig; /* Number of elements in aOrig[] */
638652
int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */
639653
int iLevel; /* Current level */
640654
int nVers; /* Number of versions analyzed */
641
- char **azVers; /* Names of versions analyzed */
655
+ struct Label **azVers; /* Names of versions analyzed */
656
+ Blob toAnnotate;
657
+ struct Label *firstLabel;
642658
};
643659
644660
/*
645661
** Initialize the annotation process by specifying the file that is
646662
** to be annotated. The annotator takes control of the input Blob and
647663
** will release it when it is finished with it.
648664
*/
649
-static int annotation_start(Annotator *p, Blob *pInput){
665
+static int annotation_start(Annotator *p){
650666
int i;
651667
652
- memset(p, 0, sizeof(*p));
653
- p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1);
668
+ p->c.aTo = break_into_lines(blob_str(&p->toAnnotate),
669
+ blob_size(&p->toAnnotate),&p->c.nTo,1);
654670
if( p->c.aTo==0 ){
655671
return 1;
656672
}
657673
p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
658674
for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
669685
** being annotated. Do another step of the annotation. Return true
670686
** if additional annotation is required. zPName is the tag to insert
671687
** on each line of the file being annotated that was contributed by
672688
** pParent. Memory to hold zPName is leaked.
673689
*/
674
-static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
690
+static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){
675691
int i, j;
676692
int lnTo;
677693
int iPrevLevel;
678694
int iThisLevel;
679695
680696
/* Prepare the parent file to be diffed */
681697
p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
682698
&p->c.nFrom, 1);
683699
if( p->c.aFrom==0 ){
700
+ free(p->c.aFrom);
684701
return 1;
685702
}
686703
687704
/* Compute the differences going from pParent to the file being
688705
** annotated. */
@@ -696,11 +713,24 @@
696713
iThisLevel = p->iLevel;
697714
for(i=lnTo=0; i<p->c.nEdit; i+=3){
698715
struct AnnLine *x = &p->aOrig[lnTo];
699716
for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
700717
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
+ if (x->zSrc->prev)
724
+ x->zSrc->prev->next = x->zSrc->next;
725
+ if (x->zSrc->next)
726
+ x->zSrc->next->prev = x->zSrc->prev;
727
+ free(x->zSrc);
728
+ }
729
+ }
701730
x->zSrc = zPName;
731
+ ++zPName->nref;
702732
x->iLevel = iThisLevel;
703733
}
704734
}
705735
lnTo += p->c.aEdit[i+2];
706736
}
@@ -711,11 +741,11 @@
711741
p->c.nEdit = 0;
712742
p->c.nEditAlloc = 0;
713743
714744
/* Clear out the from file */
715745
free(p->c.aFrom);
716
- blob_zero(pParent);
746
+ blob_reset(pParent);
717747
718748
/* Return no errors */
719749
return 0;
720750
}
721751
@@ -722,32 +752,49 @@
722752
723753
/*
724754
** COMMAND: test-annotate-step
725755
*/
726756
void test_annotate_step_cmd(void){
727
- Blob orig, b;
757
+ Blob b = empty_blob;
728758
Annotator x;
729759
int i;
730760
731761
if( g.argc<4 ) usage("RID1 RID2 ...");
732762
db_must_be_within_tree();
733
- blob_zero(&b);
734
- content_get(name_to_rid(g.argv[2]), &orig);
735
- if( annotation_start(&x, &orig) ){
763
+ memset(&x, 0, sizeof(x));
764
+ x.toAnnotate = empty_blob;
765
+ content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
766
+ if( annotation_start(&x) ){
736767
fossil_fatal("binary file");
737768
}
738769
for(i=3; i<g.argc; i++){
770
+ struct Label *l;
739771
blob_zero(&b);
740772
content_get(name_to_rid(g.argv[i]), &b);
741
- if( annotation_step(&x, &b, g.argv[i-1]) ){
773
+ l = fossil_malloc(sizeof(*l));
774
+ l->str = g.argv[i-1];
775
+ l->nref = 0;
776
+ l->next = x.firstLabel;
777
+ if (x.firstLabel)
778
+ x.firstLabel->prev = l;
779
+ x.firstLabel = l;
780
+ if( annotation_step(&x, &b, l) ){
742781
fossil_fatal("binary file");
743782
}
744783
}
745784
for(i=0; i<x.nOrig; i++){
746
- const char *zSrc = x.aOrig[i].zSrc;
785
+ const char *zSrc = x.aOrig[i].zSrc->str;
747786
if( zSrc==0 ) zSrc = g.argv[g.argc-1];
748787
fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
788
+ }
789
+ while(x.firstLabel) {
790
+ struct Label *l;
791
+ l = x.firstLabel->next;
792
+ assert(x.firstLabel->nref > 0);
793
+ free(x.firstLabel->str);
794
+ free(x.firstLabel);
795
+ x.firstLabel = l;
749796
}
750797
}
751798
752799
/* Annotation flags */
753800
#define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
763810
int mid, /* Use the version of the file in this check-in */
764811
int webLabel, /* Use web-style annotations if true */
765812
int iLimit, /* Limit the number of levels if greater than zero */
766813
int annFlags /* Flags to alter the annotation */
767814
){
768
- Blob toAnnotate; /* Text of the final (mid) version of the file */
769
- Blob step; /* Text of previous revision */
815
+ Blob step = empty_blob; /* Text of previous revision */
770816
int rid; /* Artifact ID of the file being annotated */
771
- char *zLabel; /* Label to apply to a line */
772817
Stmt q; /* Query returning all ancestor versions */
773818
774819
/* Initialize the annotation */
775820
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
776821
if( rid==0 ){
777822
fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
778823
}
779
- if( !content_get(rid, &toAnnotate) ){
824
+ memset(p, 0, sizeof(*p));
825
+ p->toAnnotate = empty_blob;
826
+ if( !content_get(rid, &p->toAnnotate) ){
780827
fossil_panic("unable to retrieve content of artifact #%d", rid);
781828
}
782829
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
783830
if( iLimit<=0 ) iLimit = 1000000000;
784831
compute_direct_ancestors(mid, iLimit);
785
- annotation_start(p, &toAnnotate);
832
+ annotation_start(p);
786833
787834
db_prepare(&q,
788835
"SELECT mlink.fid,"
789836
" (SELECT uuid FROM blob WHERE rid=mlink.%s),"
790837
" date(event.mtime), "
@@ -802,26 +849,42 @@
802849
while( db_step(&q)==SQLITE_ROW ){
803850
int pid = db_column_int(&q, 0);
804851
const char *zUuid = db_column_text(&q, 1);
805852
const char *zDate = db_column_text(&q, 2);
806853
const char *zUser = db_column_text(&q, 3);
854
+ struct Label *l = fossil_malloc(sizeof(*l));
855
+ l->nref = 0;
856
+ l->next = p->firstLabel;
857
+ l->prev = 0;
858
+ if (p->firstLabel)
859
+ p->firstLabel->prev = l;
807860
if( webLabel ){
808
- zLabel = mprintf(
861
+ l->str = mprintf(
809862
"<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
810863
g.zTop, zUuid, zUuid, zDate, zUser
811864
);
812865
}else{
813
- zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
866
+ l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
814867
}
868
+ p->firstLabel = l;
815869
p->nVers++;
816870
p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
817
- p->azVers[p->nVers-1] = zLabel;
871
+ p->azVers[p->nVers-1] = l;
818872
content_get(pid, &step);
819
- annotation_step(p, &step, zLabel);
873
+ annotation_step(p, &step, l);
874
+ if (l->nref == 0)
875
+ {
876
+ free(l->str);
877
+ p->firstLabel = l->next;
878
+ if (l->next)
879
+ l->next->prev = 0;
880
+ free(l);
881
+ }
820882
blob_reset(&step);
821883
}
822884
db_finalize(&q);
885
+ free(p->c.aTo);
823886
}
824887
825888
/*
826889
** WEBPAGE: annotate
827890
**
@@ -853,23 +916,35 @@
853916
if( P("log") ){
854917
int i;
855918
@ <h2>Versions analyzed:</h2>
856919
@ <ol>
857920
for(i=0; i<ann.nVers; i++){
858
- @ <li><tt>%s(ann.azVers[i])</tt></li>
921
+ @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
859922
}
860923
@ </ol>
861924
@ <hr>
862925
@ <h2>Annotation:</h2>
863926
}
864927
@ <pre>
865928
for(i=0; i<ann.nOrig; i++){
866929
((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
867
- @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
930
+ @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
868931
}
869932
@ </pre>
870933
style_footer();
934
+
935
+ free(ann.azVers);
936
+ free(ann.aOrig);
937
+ blob_reset(&ann.toAnnotate);
938
+ while(ann.firstLabel) {
939
+ struct Label *l;
940
+ l = ann.firstLabel->next;
941
+ assert(ann.firstLabel->nref > 0);
942
+ free(ann.firstLabel->str);
943
+ free(ann.firstLabel);
944
+ ann.firstLabel = l;
945
+ }
871946
}
872947
873948
/*
874949
** COMMAND: annotate
875950
**
@@ -885,11 +960,11 @@
885960
*/
886961
void annotate_cmd(void){
887962
int fnid; /* Filename ID */
888963
int fid; /* File instance ID */
889964
int mid; /* Manifest where file was checked in */
890
- Blob treename; /* FILENAME translated to canonical form */
965
+ Blob treename = empty_blob; /* FILENAME translated to canonical form */
891966
char *zFilename; /* Cannonical filename */
892967
Annotator ann; /* The annotation of the file */
893968
int i; /* Loop counter */
894969
const char *zLimit; /* The value to the --limit option */
895970
int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
914989
}
915990
fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
916991
if( fid==0 ){
917992
fossil_fatal("not part of current checkout: %s", zFilename);
918993
}
994
+ blob_reset(&treename);
919995
mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
920996
if( mid==0 ){
921997
fossil_panic("unable to find manifest");
922998
}
923999
if( fileVers ) annFlags |= ANN_FILE_VERS;
9241000
annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
9251001
if( showLog ){
9261002
for(i=0; i<ann.nVers; i++){
927
- printf("version %3d: %s\n", i+1, ann.azVers[i]);
1003
+ printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
9281004
}
9291005
printf("---------------------------------------------------\n");
9301006
}
9311007
for(i=0; i<ann.nOrig; i++){
9321008
fossil_print("%s: %.*s\n",
933
- ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
1009
+ ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
1010
+ }
1011
+ free(ann.azVers);
1012
+ free(ann.aOrig);
1013
+ blob_reset(&ann.toAnnotate);
1014
+ while(ann.firstLabel) {
1015
+ struct Label *l;
1016
+ l = ann.firstLabel->next;
1017
+ assert(ann.firstLabel->nref > 0);
1018
+ free(ann.firstLabel->str);
1019
+ free(ann.firstLabel);
1020
+ ann.firstLabel = l;
9341021
}
9351022
}
9361023
--- 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,29 +644,31 @@
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 };
643
644 /*
645 ** Initialize the annotation process by specifying the file that is
646 ** to be annotated. The annotator takes control of the input Blob and
647 ** will release it when it is finished with it.
648 */
649 static int annotation_start(Annotator *p, Blob *pInput){
650 int i;
651
652 memset(p, 0, sizeof(*p));
653 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1);
654 if( p->c.aTo==0 ){
655 return 1;
656 }
657 p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
658 for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
669 ** being annotated. Do another step of the annotation. Return true
670 ** if additional annotation is required. zPName is the tag to insert
671 ** on each line of the file being annotated that was contributed by
672 ** pParent. Memory to hold zPName is leaked.
673 */
674 static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
675 int i, j;
676 int lnTo;
677 int iPrevLevel;
678 int iThisLevel;
679
680 /* Prepare the parent file to be diffed */
681 p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
682 &p->c.nFrom, 1);
683 if( p->c.aFrom==0 ){
 
684 return 1;
685 }
686
687 /* Compute the differences going from pParent to the file being
688 ** annotated. */
@@ -696,11 +713,24 @@
696 iThisLevel = p->iLevel;
697 for(i=lnTo=0; i<p->c.nEdit; i+=3){
698 struct AnnLine *x = &p->aOrig[lnTo];
699 for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
700 if( x->zSrc==0 || x->iLevel==iPrevLevel ){
 
 
 
 
 
 
 
 
 
 
 
 
701 x->zSrc = zPName;
 
702 x->iLevel = iThisLevel;
703 }
704 }
705 lnTo += p->c.aEdit[i+2];
706 }
@@ -711,11 +741,11 @@
711 p->c.nEdit = 0;
712 p->c.nEditAlloc = 0;
713
714 /* Clear out the from file */
715 free(p->c.aFrom);
716 blob_zero(pParent);
717
718 /* Return no errors */
719 return 0;
720 }
721
@@ -722,32 +752,49 @@
722
723 /*
724 ** COMMAND: test-annotate-step
725 */
726 void test_annotate_step_cmd(void){
727 Blob orig, b;
728 Annotator x;
729 int i;
730
731 if( g.argc<4 ) usage("RID1 RID2 ...");
732 db_must_be_within_tree();
733 blob_zero(&b);
734 content_get(name_to_rid(g.argv[2]), &orig);
735 if( annotation_start(&x, &orig) ){
 
736 fossil_fatal("binary file");
737 }
738 for(i=3; i<g.argc; i++){
 
739 blob_zero(&b);
740 content_get(name_to_rid(g.argv[i]), &b);
741 if( annotation_step(&x, &b, g.argv[i-1]) ){
 
 
 
 
 
 
 
742 fossil_fatal("binary file");
743 }
744 }
745 for(i=0; i<x.nOrig; i++){
746 const char *zSrc = x.aOrig[i].zSrc;
747 if( zSrc==0 ) zSrc = g.argv[g.argc-1];
748 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
 
 
 
 
 
 
 
 
749 }
750 }
751
752 /* Annotation flags */
753 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
763 int mid, /* Use the version of the file in this check-in */
764 int webLabel, /* Use web-style annotations if true */
765 int iLimit, /* Limit the number of levels if greater than zero */
766 int annFlags /* Flags to alter the annotation */
767 ){
768 Blob toAnnotate; /* Text of the final (mid) version of the file */
769 Blob step; /* Text of previous revision */
770 int rid; /* Artifact ID of the file being annotated */
771 char *zLabel; /* Label to apply to a line */
772 Stmt q; /* Query returning all ancestor versions */
773
774 /* Initialize the annotation */
775 rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
776 if( rid==0 ){
777 fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
778 }
779 if( !content_get(rid, &toAnnotate) ){
 
 
780 fossil_panic("unable to retrieve content of artifact #%d", rid);
781 }
782 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
783 if( iLimit<=0 ) iLimit = 1000000000;
784 compute_direct_ancestors(mid, iLimit);
785 annotation_start(p, &toAnnotate);
786
787 db_prepare(&q,
788 "SELECT mlink.fid,"
789 " (SELECT uuid FROM blob WHERE rid=mlink.%s),"
790 " date(event.mtime), "
@@ -802,26 +849,42 @@
802 while( db_step(&q)==SQLITE_ROW ){
803 int pid = db_column_int(&q, 0);
804 const char *zUuid = db_column_text(&q, 1);
805 const char *zDate = db_column_text(&q, 2);
806 const char *zUser = db_column_text(&q, 3);
 
 
 
 
 
 
807 if( webLabel ){
808 zLabel = mprintf(
809 "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
810 g.zTop, zUuid, zUuid, zDate, zUser
811 );
812 }else{
813 zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
814 }
 
815 p->nVers++;
816 p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
817 p->azVers[p->nVers-1] = zLabel;
818 content_get(pid, &step);
819 annotation_step(p, &step, zLabel);
 
 
 
 
 
 
 
 
820 blob_reset(&step);
821 }
822 db_finalize(&q);
 
823 }
824
825 /*
826 ** WEBPAGE: annotate
827 **
@@ -853,23 +916,35 @@
853 if( P("log") ){
854 int i;
855 @ <h2>Versions analyzed:</h2>
856 @ <ol>
857 for(i=0; i<ann.nVers; i++){
858 @ <li><tt>%s(ann.azVers[i])</tt></li>
859 }
860 @ </ol>
861 @ <hr>
862 @ <h2>Annotation:</h2>
863 }
864 @ <pre>
865 for(i=0; i<ann.nOrig; i++){
866 ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
867 @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
868 }
869 @ </pre>
870 style_footer();
 
 
 
 
 
 
 
 
 
 
 
 
871 }
872
873 /*
874 ** COMMAND: annotate
875 **
@@ -885,11 +960,11 @@
885 */
886 void annotate_cmd(void){
887 int fnid; /* Filename ID */
888 int fid; /* File instance ID */
889 int mid; /* Manifest where file was checked in */
890 Blob treename; /* FILENAME translated to canonical form */
891 char *zFilename; /* Cannonical filename */
892 Annotator ann; /* The annotation of the file */
893 int i; /* Loop counter */
894 const char *zLimit; /* The value to the --limit option */
895 int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
914 }
915 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
916 if( fid==0 ){
917 fossil_fatal("not part of current checkout: %s", zFilename);
918 }
 
919 mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
920 if( mid==0 ){
921 fossil_panic("unable to find manifest");
922 }
923 if( fileVers ) annFlags |= ANN_FILE_VERS;
924 annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
925 if( showLog ){
926 for(i=0; i<ann.nVers; i++){
927 printf("version %3d: %s\n", i+1, ann.azVers[i]);
928 }
929 printf("---------------------------------------------------\n");
930 }
931 for(i=0; i<ann.nOrig; i++){
932 fossil_print("%s: %.*s\n",
933 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
 
 
 
 
 
 
 
 
 
 
 
934 }
935 }
936
--- 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,29 +644,31 @@
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
663 ** will release it when it is finished with it.
664 */
665 static int annotation_start(Annotator *p){
666 int i;
667
668 p->c.aTo = break_into_lines(blob_str(&p->toAnnotate),
669 blob_size(&p->toAnnotate),&p->c.nTo,1);
670 if( p->c.aTo==0 ){
671 return 1;
672 }
673 p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
674 for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
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
696 /* Prepare the parent file to be diffed */
697 p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
698 &p->c.nFrom, 1);
699 if( p->c.aFrom==0 ){
700 free(p->c.aFrom);
701 return 1;
702 }
703
704 /* Compute the differences going from pParent to the file being
705 ** annotated. */
@@ -696,11 +713,24 @@
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 if (x->zSrc->prev)
724 x->zSrc->prev->next = x->zSrc->next;
725 if (x->zSrc->next)
726 x->zSrc->next->prev = x->zSrc->prev;
727 free(x->zSrc);
728 }
729 }
730 x->zSrc = zPName;
731 ++zPName->nref;
732 x->iLevel = iThisLevel;
733 }
734 }
735 lnTo += p->c.aEdit[i+2];
736 }
@@ -711,11 +741,11 @@
741 p->c.nEdit = 0;
742 p->c.nEditAlloc = 0;
743
744 /* Clear out the from file */
745 free(p->c.aFrom);
746 blob_reset(pParent);
747
748 /* Return no errors */
749 return 0;
750 }
751
@@ -722,32 +752,49 @@
752
753 /*
754 ** COMMAND: test-annotate-step
755 */
756 void test_annotate_step_cmd(void){
757 Blob b = empty_blob;
758 Annotator x;
759 int i;
760
761 if( g.argc<4 ) usage("RID1 RID2 ...");
762 db_must_be_within_tree();
763 memset(&x, 0, sizeof(x));
764 x.toAnnotate = empty_blob;
765 content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
766 if( annotation_start(&x) ){
767 fossil_fatal("binary file");
768 }
769 for(i=3; i<g.argc; i++){
770 struct Label *l;
771 blob_zero(&b);
772 content_get(name_to_rid(g.argv[i]), &b);
773 l = fossil_malloc(sizeof(*l));
774 l->str = g.argv[i-1];
775 l->nref = 0;
776 l->next = x.firstLabel;
777 if (x.firstLabel)
778 x.firstLabel->prev = l;
779 x.firstLabel = l;
780 if( annotation_step(&x, &b, l) ){
781 fossil_fatal("binary file");
782 }
783 }
784 for(i=0; i<x.nOrig; i++){
785 const char *zSrc = x.aOrig[i].zSrc->str;
786 if( zSrc==0 ) zSrc = g.argv[g.argc-1];
787 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
788 }
789 while(x.firstLabel) {
790 struct Label *l;
791 l = x.firstLabel->next;
792 assert(x.firstLabel->nref > 0);
793 free(x.firstLabel->str);
794 free(x.firstLabel);
795 x.firstLabel = l;
796 }
797 }
798
799 /* Annotation flags */
800 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
810 int mid, /* Use the version of the file in this check-in */
811 int webLabel, /* Use web-style annotations if true */
812 int iLimit, /* Limit the number of levels if greater than zero */
813 int annFlags /* Flags to alter the annotation */
814 ){
815 Blob step = empty_blob; /* Text of previous revision */
 
816 int rid; /* Artifact ID of the file being annotated */
 
817 Stmt q; /* Query returning all ancestor versions */
818
819 /* Initialize the annotation */
820 rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
821 if( rid==0 ){
822 fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
823 }
824 memset(p, 0, sizeof(*p));
825 p->toAnnotate = empty_blob;
826 if( !content_get(rid, &p->toAnnotate) ){
827 fossil_panic("unable to retrieve content of artifact #%d", rid);
828 }
829 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
830 if( iLimit<=0 ) iLimit = 1000000000;
831 compute_direct_ancestors(mid, iLimit);
832 annotation_start(p);
833
834 db_prepare(&q,
835 "SELECT mlink.fid,"
836 " (SELECT uuid FROM blob WHERE rid=mlink.%s),"
837 " date(event.mtime), "
@@ -802,26 +849,42 @@
849 while( db_step(&q)==SQLITE_ROW ){
850 int pid = db_column_int(&q, 0);
851 const char *zUuid = db_column_text(&q, 1);
852 const char *zDate = db_column_text(&q, 2);
853 const char *zUser = db_column_text(&q, 3);
854 struct Label *l = fossil_malloc(sizeof(*l));
855 l->nref = 0;
856 l->next = p->firstLabel;
857 l->prev = 0;
858 if (p->firstLabel)
859 p->firstLabel->prev = l;
860 if( webLabel ){
861 l->str = mprintf(
862 "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
863 g.zTop, zUuid, zUuid, zDate, zUser
864 );
865 }else{
866 l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
867 }
868 p->firstLabel = l;
869 p->nVers++;
870 p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
871 p->azVers[p->nVers-1] = l;
872 content_get(pid, &step);
873 annotation_step(p, &step, l);
874 if (l->nref == 0)
875 {
876 free(l->str);
877 p->firstLabel = l->next;
878 if (l->next)
879 l->next->prev = 0;
880 free(l);
881 }
882 blob_reset(&step);
883 }
884 db_finalize(&q);
885 free(p->c.aTo);
886 }
887
888 /*
889 ** WEBPAGE: annotate
890 **
@@ -853,23 +916,35 @@
916 if( P("log") ){
917 int i;
918 @ <h2>Versions analyzed:</h2>
919 @ <ol>
920 for(i=0; i<ann.nVers; i++){
921 @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
922 }
923 @ </ol>
924 @ <hr>
925 @ <h2>Annotation:</h2>
926 }
927 @ <pre>
928 for(i=0; i<ann.nOrig; i++){
929 ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
930 @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
931 }
932 @ </pre>
933 style_footer();
934
935 free(ann.azVers);
936 free(ann.aOrig);
937 blob_reset(&ann.toAnnotate);
938 while(ann.firstLabel) {
939 struct Label *l;
940 l = ann.firstLabel->next;
941 assert(ann.firstLabel->nref > 0);
942 free(ann.firstLabel->str);
943 free(ann.firstLabel);
944 ann.firstLabel = l;
945 }
946 }
947
948 /*
949 ** COMMAND: annotate
950 **
@@ -885,11 +960,11 @@
960 */
961 void annotate_cmd(void){
962 int fnid; /* Filename ID */
963 int fid; /* File instance ID */
964 int mid; /* Manifest where file was checked in */
965 Blob treename = empty_blob; /* FILENAME translated to canonical form */
966 char *zFilename; /* Cannonical filename */
967 Annotator ann; /* The annotation of the file */
968 int i; /* Loop counter */
969 const char *zLimit; /* The value to the --limit option */
970 int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
989 }
990 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
991 if( fid==0 ){
992 fossil_fatal("not part of current checkout: %s", zFilename);
993 }
994 blob_reset(&treename);
995 mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
996 if( mid==0 ){
997 fossil_panic("unable to find manifest");
998 }
999 if( fileVers ) annFlags |= ANN_FILE_VERS;
1000 annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
1001 if( showLog ){
1002 for(i=0; i<ann.nVers; i++){
1003 printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
1004 }
1005 printf("---------------------------------------------------\n");
1006 }
1007 for(i=0; i<ann.nOrig; i++){
1008 fossil_print("%s: %.*s\n",
1009 ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
1010 }
1011 free(ann.azVers);
1012 free(ann.aOrig);
1013 blob_reset(&ann.toAnnotate);
1014 while(ann.firstLabel) {
1015 struct Label *l;
1016 l = ann.firstLabel->next;
1017 assert(ann.firstLabel->nref > 0);
1018 free(ann.firstLabel->str);
1019 free(ann.firstLabel);
1020 ann.firstLabel = l;
1021 }
1022 }
1023
+114 -27
--- src/diff.c
+++ src/diff.c
@@ -619,10 +619,24 @@
619619
/**************************************************************************
620620
** The basic difference engine is above. What follows is the annotation
621621
** engine. Both are in the same file since they share many components.
622622
*/
623623
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
+
624638
/*
625639
** The status of an annotation operation is recorded by an instance
626640
** of the following structure.
627641
*/
628642
typedef struct Annotator Annotator;
@@ -630,29 +644,31 @@
630644
DContext c; /* The diff-engine context */
631645
struct AnnLine { /* Lines of the original files... */
632646
const char *z; /* The text of the line */
633647
short int n; /* Number of bytes (omitting trailing space and \n) */
634648
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 */
636650
} *aOrig;
637651
int nOrig; /* Number of elements in aOrig[] */
638652
int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */
639653
int iLevel; /* Current level */
640654
int nVers; /* Number of versions analyzed */
641
- char **azVers; /* Names of versions analyzed */
655
+ struct Label **azVers; /* Names of versions analyzed */
656
+ Blob toAnnotate;
657
+ struct Label *firstLabel;
642658
};
643659
644660
/*
645661
** Initialize the annotation process by specifying the file that is
646662
** to be annotated. The annotator takes control of the input Blob and
647663
** will release it when it is finished with it.
648664
*/
649
-static int annotation_start(Annotator *p, Blob *pInput){
665
+static int annotation_start(Annotator *p){
650666
int i;
651667
652
- memset(p, 0, sizeof(*p));
653
- p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1);
668
+ p->c.aTo = break_into_lines(blob_str(&p->toAnnotate),
669
+ blob_size(&p->toAnnotate),&p->c.nTo,1);
654670
if( p->c.aTo==0 ){
655671
return 1;
656672
}
657673
p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
658674
for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
669685
** being annotated. Do another step of the annotation. Return true
670686
** if additional annotation is required. zPName is the tag to insert
671687
** on each line of the file being annotated that was contributed by
672688
** pParent. Memory to hold zPName is leaked.
673689
*/
674
-static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
690
+static int annotation_step(Annotator *p, Blob *pParent, struct Label *zPName){
675691
int i, j;
676692
int lnTo;
677693
int iPrevLevel;
678694
int iThisLevel;
679695
680696
/* Prepare the parent file to be diffed */
681697
p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
682698
&p->c.nFrom, 1);
683699
if( p->c.aFrom==0 ){
700
+ free(p->c.aFrom);
684701
return 1;
685702
}
686703
687704
/* Compute the differences going from pParent to the file being
688705
** annotated. */
@@ -696,11 +713,24 @@
696713
iThisLevel = p->iLevel;
697714
for(i=lnTo=0; i<p->c.nEdit; i+=3){
698715
struct AnnLine *x = &p->aOrig[lnTo];
699716
for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
700717
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
+ if (x->zSrc->prev)
724
+ x->zSrc->prev->next = x->zSrc->next;
725
+ if (x->zSrc->next)
726
+ x->zSrc->next->prev = x->zSrc->prev;
727
+ free(x->zSrc);
728
+ }
729
+ }
701730
x->zSrc = zPName;
731
+ ++zPName->nref;
702732
x->iLevel = iThisLevel;
703733
}
704734
}
705735
lnTo += p->c.aEdit[i+2];
706736
}
@@ -711,11 +741,11 @@
711741
p->c.nEdit = 0;
712742
p->c.nEditAlloc = 0;
713743
714744
/* Clear out the from file */
715745
free(p->c.aFrom);
716
- blob_zero(pParent);
746
+ blob_reset(pParent);
717747
718748
/* Return no errors */
719749
return 0;
720750
}
721751
@@ -722,32 +752,49 @@
722752
723753
/*
724754
** COMMAND: test-annotate-step
725755
*/
726756
void test_annotate_step_cmd(void){
727
- Blob orig, b;
757
+ Blob b = empty_blob;
728758
Annotator x;
729759
int i;
730760
731761
if( g.argc<4 ) usage("RID1 RID2 ...");
732762
db_must_be_within_tree();
733
- blob_zero(&b);
734
- content_get(name_to_rid(g.argv[2]), &orig);
735
- if( annotation_start(&x, &orig) ){
763
+ memset(&x, 0, sizeof(x));
764
+ x.toAnnotate = empty_blob;
765
+ content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
766
+ if( annotation_start(&x) ){
736767
fossil_fatal("binary file");
737768
}
738769
for(i=3; i<g.argc; i++){
770
+ struct Label *l;
739771
blob_zero(&b);
740772
content_get(name_to_rid(g.argv[i]), &b);
741
- if( annotation_step(&x, &b, g.argv[i-1]) ){
773
+ l = fossil_malloc(sizeof(*l));
774
+ l->str = g.argv[i-1];
775
+ l->nref = 0;
776
+ l->next = x.firstLabel;
777
+ if (x.firstLabel)
778
+ x.firstLabel->prev = l;
779
+ x.firstLabel = l;
780
+ if( annotation_step(&x, &b, l) ){
742781
fossil_fatal("binary file");
743782
}
744783
}
745784
for(i=0; i<x.nOrig; i++){
746
- const char *zSrc = x.aOrig[i].zSrc;
785
+ const char *zSrc = x.aOrig[i].zSrc->str;
747786
if( zSrc==0 ) zSrc = g.argv[g.argc-1];
748787
fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
788
+ }
789
+ while(x.firstLabel) {
790
+ struct Label *l;
791
+ l = x.firstLabel->next;
792
+ assert(x.firstLabel->nref > 0);
793
+ free(x.firstLabel->str);
794
+ free(x.firstLabel);
795
+ x.firstLabel = l;
749796
}
750797
}
751798
752799
/* Annotation flags */
753800
#define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
763810
int mid, /* Use the version of the file in this check-in */
764811
int webLabel, /* Use web-style annotations if true */
765812
int iLimit, /* Limit the number of levels if greater than zero */
766813
int annFlags /* Flags to alter the annotation */
767814
){
768
- Blob toAnnotate; /* Text of the final (mid) version of the file */
769
- Blob step; /* Text of previous revision */
815
+ Blob step = empty_blob; /* Text of previous revision */
770816
int rid; /* Artifact ID of the file being annotated */
771
- char *zLabel; /* Label to apply to a line */
772817
Stmt q; /* Query returning all ancestor versions */
773818
774819
/* Initialize the annotation */
775820
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
776821
if( rid==0 ){
777822
fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
778823
}
779
- if( !content_get(rid, &toAnnotate) ){
824
+ memset(p, 0, sizeof(*p));
825
+ p->toAnnotate = empty_blob;
826
+ if( !content_get(rid, &p->toAnnotate) ){
780827
fossil_panic("unable to retrieve content of artifact #%d", rid);
781828
}
782829
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
783830
if( iLimit<=0 ) iLimit = 1000000000;
784831
compute_direct_ancestors(mid, iLimit);
785
- annotation_start(p, &toAnnotate);
832
+ annotation_start(p);
786833
787834
db_prepare(&q,
788835
"SELECT mlink.fid,"
789836
" (SELECT uuid FROM blob WHERE rid=mlink.%s),"
790837
" date(event.mtime), "
@@ -802,26 +849,42 @@
802849
while( db_step(&q)==SQLITE_ROW ){
803850
int pid = db_column_int(&q, 0);
804851
const char *zUuid = db_column_text(&q, 1);
805852
const char *zDate = db_column_text(&q, 2);
806853
const char *zUser = db_column_text(&q, 3);
854
+ struct Label *l = fossil_malloc(sizeof(*l));
855
+ l->nref = 0;
856
+ l->next = p->firstLabel;
857
+ l->prev = 0;
858
+ if (p->firstLabel)
859
+ p->firstLabel->prev = l;
807860
if( webLabel ){
808
- zLabel = mprintf(
861
+ l->str = mprintf(
809862
"<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
810863
g.zTop, zUuid, zUuid, zDate, zUser
811864
);
812865
}else{
813
- zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
866
+ l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
814867
}
868
+ p->firstLabel = l;
815869
p->nVers++;
816870
p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
817
- p->azVers[p->nVers-1] = zLabel;
871
+ p->azVers[p->nVers-1] = l;
818872
content_get(pid, &step);
819
- annotation_step(p, &step, zLabel);
873
+ annotation_step(p, &step, l);
874
+ if (l->nref == 0)
875
+ {
876
+ free(l->str);
877
+ p->firstLabel = l->next;
878
+ if (l->next)
879
+ l->next->prev = 0;
880
+ free(l);
881
+ }
820882
blob_reset(&step);
821883
}
822884
db_finalize(&q);
885
+ free(p->c.aTo);
823886
}
824887
825888
/*
826889
** WEBPAGE: annotate
827890
**
@@ -853,23 +916,35 @@
853916
if( P("log") ){
854917
int i;
855918
@ <h2>Versions analyzed:</h2>
856919
@ <ol>
857920
for(i=0; i<ann.nVers; i++){
858
- @ <li><tt>%s(ann.azVers[i])</tt></li>
921
+ @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
859922
}
860923
@ </ol>
861924
@ <hr>
862925
@ <h2>Annotation:</h2>
863926
}
864927
@ <pre>
865928
for(i=0; i<ann.nOrig; i++){
866929
((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
867
- @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
930
+ @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
868931
}
869932
@ </pre>
870933
style_footer();
934
+
935
+ free(ann.azVers);
936
+ free(ann.aOrig);
937
+ blob_reset(&ann.toAnnotate);
938
+ while(ann.firstLabel) {
939
+ struct Label *l;
940
+ l = ann.firstLabel->next;
941
+ assert(ann.firstLabel->nref > 0);
942
+ free(ann.firstLabel->str);
943
+ free(ann.firstLabel);
944
+ ann.firstLabel = l;
945
+ }
871946
}
872947
873948
/*
874949
** COMMAND: annotate
875950
**
@@ -885,11 +960,11 @@
885960
*/
886961
void annotate_cmd(void){
887962
int fnid; /* Filename ID */
888963
int fid; /* File instance ID */
889964
int mid; /* Manifest where file was checked in */
890
- Blob treename; /* FILENAME translated to canonical form */
965
+ Blob treename = empty_blob; /* FILENAME translated to canonical form */
891966
char *zFilename; /* Cannonical filename */
892967
Annotator ann; /* The annotation of the file */
893968
int i; /* Loop counter */
894969
const char *zLimit; /* The value to the --limit option */
895970
int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
914989
}
915990
fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
916991
if( fid==0 ){
917992
fossil_fatal("not part of current checkout: %s", zFilename);
918993
}
994
+ blob_reset(&treename);
919995
mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
920996
if( mid==0 ){
921997
fossil_panic("unable to find manifest");
922998
}
923999
if( fileVers ) annFlags |= ANN_FILE_VERS;
9241000
annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
9251001
if( showLog ){
9261002
for(i=0; i<ann.nVers; i++){
927
- printf("version %3d: %s\n", i+1, ann.azVers[i]);
1003
+ printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
9281004
}
9291005
printf("---------------------------------------------------\n");
9301006
}
9311007
for(i=0; i<ann.nOrig; i++){
9321008
fossil_print("%s: %.*s\n",
933
- ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
1009
+ ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
1010
+ }
1011
+ free(ann.azVers);
1012
+ free(ann.aOrig);
1013
+ blob_reset(&ann.toAnnotate);
1014
+ while(ann.firstLabel) {
1015
+ struct Label *l;
1016
+ l = ann.firstLabel->next;
1017
+ assert(ann.firstLabel->nref > 0);
1018
+ free(ann.firstLabel->str);
1019
+ free(ann.firstLabel);
1020
+ ann.firstLabel = l;
9341021
}
9351022
}
9361023
--- 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,29 +644,31 @@
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 };
643
644 /*
645 ** Initialize the annotation process by specifying the file that is
646 ** to be annotated. The annotator takes control of the input Blob and
647 ** will release it when it is finished with it.
648 */
649 static int annotation_start(Annotator *p, Blob *pInput){
650 int i;
651
652 memset(p, 0, sizeof(*p));
653 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,1);
654 if( p->c.aTo==0 ){
655 return 1;
656 }
657 p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
658 for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
669 ** being annotated. Do another step of the annotation. Return true
670 ** if additional annotation is required. zPName is the tag to insert
671 ** on each line of the file being annotated that was contributed by
672 ** pParent. Memory to hold zPName is leaked.
673 */
674 static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
675 int i, j;
676 int lnTo;
677 int iPrevLevel;
678 int iThisLevel;
679
680 /* Prepare the parent file to be diffed */
681 p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
682 &p->c.nFrom, 1);
683 if( p->c.aFrom==0 ){
 
684 return 1;
685 }
686
687 /* Compute the differences going from pParent to the file being
688 ** annotated. */
@@ -696,11 +713,24 @@
696 iThisLevel = p->iLevel;
697 for(i=lnTo=0; i<p->c.nEdit; i+=3){
698 struct AnnLine *x = &p->aOrig[lnTo];
699 for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){
700 if( x->zSrc==0 || x->iLevel==iPrevLevel ){
 
 
 
 
 
 
 
 
 
 
 
 
701 x->zSrc = zPName;
 
702 x->iLevel = iThisLevel;
703 }
704 }
705 lnTo += p->c.aEdit[i+2];
706 }
@@ -711,11 +741,11 @@
711 p->c.nEdit = 0;
712 p->c.nEditAlloc = 0;
713
714 /* Clear out the from file */
715 free(p->c.aFrom);
716 blob_zero(pParent);
717
718 /* Return no errors */
719 return 0;
720 }
721
@@ -722,32 +752,49 @@
722
723 /*
724 ** COMMAND: test-annotate-step
725 */
726 void test_annotate_step_cmd(void){
727 Blob orig, b;
728 Annotator x;
729 int i;
730
731 if( g.argc<4 ) usage("RID1 RID2 ...");
732 db_must_be_within_tree();
733 blob_zero(&b);
734 content_get(name_to_rid(g.argv[2]), &orig);
735 if( annotation_start(&x, &orig) ){
 
736 fossil_fatal("binary file");
737 }
738 for(i=3; i<g.argc; i++){
 
739 blob_zero(&b);
740 content_get(name_to_rid(g.argv[i]), &b);
741 if( annotation_step(&x, &b, g.argv[i-1]) ){
 
 
 
 
 
 
 
742 fossil_fatal("binary file");
743 }
744 }
745 for(i=0; i<x.nOrig; i++){
746 const char *zSrc = x.aOrig[i].zSrc;
747 if( zSrc==0 ) zSrc = g.argv[g.argc-1];
748 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
 
 
 
 
 
 
 
 
749 }
750 }
751
752 /* Annotation flags */
753 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
763 int mid, /* Use the version of the file in this check-in */
764 int webLabel, /* Use web-style annotations if true */
765 int iLimit, /* Limit the number of levels if greater than zero */
766 int annFlags /* Flags to alter the annotation */
767 ){
768 Blob toAnnotate; /* Text of the final (mid) version of the file */
769 Blob step; /* Text of previous revision */
770 int rid; /* Artifact ID of the file being annotated */
771 char *zLabel; /* Label to apply to a line */
772 Stmt q; /* Query returning all ancestor versions */
773
774 /* Initialize the annotation */
775 rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
776 if( rid==0 ){
777 fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
778 }
779 if( !content_get(rid, &toAnnotate) ){
 
 
780 fossil_panic("unable to retrieve content of artifact #%d", rid);
781 }
782 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
783 if( iLimit<=0 ) iLimit = 1000000000;
784 compute_direct_ancestors(mid, iLimit);
785 annotation_start(p, &toAnnotate);
786
787 db_prepare(&q,
788 "SELECT mlink.fid,"
789 " (SELECT uuid FROM blob WHERE rid=mlink.%s),"
790 " date(event.mtime), "
@@ -802,26 +849,42 @@
802 while( db_step(&q)==SQLITE_ROW ){
803 int pid = db_column_int(&q, 0);
804 const char *zUuid = db_column_text(&q, 1);
805 const char *zDate = db_column_text(&q, 2);
806 const char *zUser = db_column_text(&q, 3);
 
 
 
 
 
 
807 if( webLabel ){
808 zLabel = mprintf(
809 "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
810 g.zTop, zUuid, zUuid, zDate, zUser
811 );
812 }else{
813 zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
814 }
 
815 p->nVers++;
816 p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
817 p->azVers[p->nVers-1] = zLabel;
818 content_get(pid, &step);
819 annotation_step(p, &step, zLabel);
 
 
 
 
 
 
 
 
820 blob_reset(&step);
821 }
822 db_finalize(&q);
 
823 }
824
825 /*
826 ** WEBPAGE: annotate
827 **
@@ -853,23 +916,35 @@
853 if( P("log") ){
854 int i;
855 @ <h2>Versions analyzed:</h2>
856 @ <ol>
857 for(i=0; i<ann.nVers; i++){
858 @ <li><tt>%s(ann.azVers[i])</tt></li>
859 }
860 @ </ol>
861 @ <hr>
862 @ <h2>Annotation:</h2>
863 }
864 @ <pre>
865 for(i=0; i<ann.nOrig; i++){
866 ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
867 @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z)
868 }
869 @ </pre>
870 style_footer();
 
 
 
 
 
 
 
 
 
 
 
 
871 }
872
873 /*
874 ** COMMAND: annotate
875 **
@@ -885,11 +960,11 @@
885 */
886 void annotate_cmd(void){
887 int fnid; /* Filename ID */
888 int fid; /* File instance ID */
889 int mid; /* Manifest where file was checked in */
890 Blob treename; /* FILENAME translated to canonical form */
891 char *zFilename; /* Cannonical filename */
892 Annotator ann; /* The annotation of the file */
893 int i; /* Loop counter */
894 const char *zLimit; /* The value to the --limit option */
895 int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
914 }
915 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
916 if( fid==0 ){
917 fossil_fatal("not part of current checkout: %s", zFilename);
918 }
 
919 mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
920 if( mid==0 ){
921 fossil_panic("unable to find manifest");
922 }
923 if( fileVers ) annFlags |= ANN_FILE_VERS;
924 annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
925 if( showLog ){
926 for(i=0; i<ann.nVers; i++){
927 printf("version %3d: %s\n", i+1, ann.azVers[i]);
928 }
929 printf("---------------------------------------------------\n");
930 }
931 for(i=0; i<ann.nOrig; i++){
932 fossil_print("%s: %.*s\n",
933 ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z);
 
 
 
 
 
 
 
 
 
 
 
934 }
935 }
936
--- 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,29 +644,31 @@
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
663 ** will release it when it is finished with it.
664 */
665 static int annotation_start(Annotator *p){
666 int i;
667
668 p->c.aTo = break_into_lines(blob_str(&p->toAnnotate),
669 blob_size(&p->toAnnotate),&p->c.nTo,1);
670 if( p->c.aTo==0 ){
671 return 1;
672 }
673 p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
674 for(i=0; i<p->c.nTo; i++){
@@ -669,20 +685,21 @@
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
696 /* Prepare the parent file to be diffed */
697 p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent),
698 &p->c.nFrom, 1);
699 if( p->c.aFrom==0 ){
700 free(p->c.aFrom);
701 return 1;
702 }
703
704 /* Compute the differences going from pParent to the file being
705 ** annotated. */
@@ -696,11 +713,24 @@
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 if (x->zSrc->prev)
724 x->zSrc->prev->next = x->zSrc->next;
725 if (x->zSrc->next)
726 x->zSrc->next->prev = x->zSrc->prev;
727 free(x->zSrc);
728 }
729 }
730 x->zSrc = zPName;
731 ++zPName->nref;
732 x->iLevel = iThisLevel;
733 }
734 }
735 lnTo += p->c.aEdit[i+2];
736 }
@@ -711,11 +741,11 @@
741 p->c.nEdit = 0;
742 p->c.nEditAlloc = 0;
743
744 /* Clear out the from file */
745 free(p->c.aFrom);
746 blob_reset(pParent);
747
748 /* Return no errors */
749 return 0;
750 }
751
@@ -722,32 +752,49 @@
752
753 /*
754 ** COMMAND: test-annotate-step
755 */
756 void test_annotate_step_cmd(void){
757 Blob b = empty_blob;
758 Annotator x;
759 int i;
760
761 if( g.argc<4 ) usage("RID1 RID2 ...");
762 db_must_be_within_tree();
763 memset(&x, 0, sizeof(x));
764 x.toAnnotate = empty_blob;
765 content_get(name_to_rid(g.argv[2]), &x.toAnnotate);
766 if( annotation_start(&x) ){
767 fossil_fatal("binary file");
768 }
769 for(i=3; i<g.argc; i++){
770 struct Label *l;
771 blob_zero(&b);
772 content_get(name_to_rid(g.argv[i]), &b);
773 l = fossil_malloc(sizeof(*l));
774 l->str = g.argv[i-1];
775 l->nref = 0;
776 l->next = x.firstLabel;
777 if (x.firstLabel)
778 x.firstLabel->prev = l;
779 x.firstLabel = l;
780 if( annotation_step(&x, &b, l) ){
781 fossil_fatal("binary file");
782 }
783 }
784 for(i=0; i<x.nOrig; i++){
785 const char *zSrc = x.aOrig[i].zSrc->str;
786 if( zSrc==0 ) zSrc = g.argv[g.argc-1];
787 fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
788 }
789 while(x.firstLabel) {
790 struct Label *l;
791 l = x.firstLabel->next;
792 assert(x.firstLabel->nref > 0);
793 free(x.firstLabel->str);
794 free(x.firstLabel);
795 x.firstLabel = l;
796 }
797 }
798
799 /* Annotation flags */
800 #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */
@@ -763,28 +810,28 @@
810 int mid, /* Use the version of the file in this check-in */
811 int webLabel, /* Use web-style annotations if true */
812 int iLimit, /* Limit the number of levels if greater than zero */
813 int annFlags /* Flags to alter the annotation */
814 ){
815 Blob step = empty_blob; /* Text of previous revision */
 
816 int rid; /* Artifact ID of the file being annotated */
 
817 Stmt q; /* Query returning all ancestor versions */
818
819 /* Initialize the annotation */
820 rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
821 if( rid==0 ){
822 fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
823 }
824 memset(p, 0, sizeof(*p));
825 p->toAnnotate = empty_blob;
826 if( !content_get(rid, &p->toAnnotate) ){
827 fossil_panic("unable to retrieve content of artifact #%d", rid);
828 }
829 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
830 if( iLimit<=0 ) iLimit = 1000000000;
831 compute_direct_ancestors(mid, iLimit);
832 annotation_start(p);
833
834 db_prepare(&q,
835 "SELECT mlink.fid,"
836 " (SELECT uuid FROM blob WHERE rid=mlink.%s),"
837 " date(event.mtime), "
@@ -802,26 +849,42 @@
849 while( db_step(&q)==SQLITE_ROW ){
850 int pid = db_column_int(&q, 0);
851 const char *zUuid = db_column_text(&q, 1);
852 const char *zDate = db_column_text(&q, 2);
853 const char *zUser = db_column_text(&q, 3);
854 struct Label *l = fossil_malloc(sizeof(*l));
855 l->nref = 0;
856 l->next = p->firstLabel;
857 l->prev = 0;
858 if (p->firstLabel)
859 p->firstLabel->prev = l;
860 if( webLabel ){
861 l->str = mprintf(
862 "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s",
863 g.zTop, zUuid, zUuid, zDate, zUser
864 );
865 }else{
866 l->str = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
867 }
868 p->firstLabel = l;
869 p->nVers++;
870 p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
871 p->azVers[p->nVers-1] = l;
872 content_get(pid, &step);
873 annotation_step(p, &step, l);
874 if (l->nref == 0)
875 {
876 free(l->str);
877 p->firstLabel = l->next;
878 if (l->next)
879 l->next->prev = 0;
880 free(l);
881 }
882 blob_reset(&step);
883 }
884 db_finalize(&q);
885 free(p->c.aTo);
886 }
887
888 /*
889 ** WEBPAGE: annotate
890 **
@@ -853,23 +916,35 @@
916 if( P("log") ){
917 int i;
918 @ <h2>Versions analyzed:</h2>
919 @ <ol>
920 for(i=0; i<ann.nVers; i++){
921 @ <li><tt>%s(ann.azVers[i]->str)</tt></li>
922 }
923 @ </ol>
924 @ <hr>
925 @ <h2>Annotation:</h2>
926 }
927 @ <pre>
928 for(i=0; i<ann.nOrig; i++){
929 ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0;
930 @ %s(ann.aOrig[i].zSrc->str): %h(ann.aOrig[i].z)
931 }
932 @ </pre>
933 style_footer();
934
935 free(ann.azVers);
936 free(ann.aOrig);
937 blob_reset(&ann.toAnnotate);
938 while(ann.firstLabel) {
939 struct Label *l;
940 l = ann.firstLabel->next;
941 assert(ann.firstLabel->nref > 0);
942 free(ann.firstLabel->str);
943 free(ann.firstLabel);
944 ann.firstLabel = l;
945 }
946 }
947
948 /*
949 ** COMMAND: annotate
950 **
@@ -885,11 +960,11 @@
960 */
961 void annotate_cmd(void){
962 int fnid; /* Filename ID */
963 int fid; /* File instance ID */
964 int mid; /* Manifest where file was checked in */
965 Blob treename = empty_blob; /* FILENAME translated to canonical form */
966 char *zFilename; /* Cannonical filename */
967 Annotator ann; /* The annotation of the file */
968 int i; /* Loop counter */
969 const char *zLimit; /* The value to the --limit option */
970 int iLimit; /* How far back in time to look */
@@ -914,22 +989,34 @@
989 }
990 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
991 if( fid==0 ){
992 fossil_fatal("not part of current checkout: %s", zFilename);
993 }
994 blob_reset(&treename);
995 mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid);
996 if( mid==0 ){
997 fossil_panic("unable to find manifest");
998 }
999 if( fileVers ) annFlags |= ANN_FILE_VERS;
1000 annotate_file(&ann, fnid, mid, 0, iLimit, annFlags);
1001 if( showLog ){
1002 for(i=0; i<ann.nVers; i++){
1003 printf("version %3d: %s\n", i+1, ann.azVers[i]->str);
1004 }
1005 printf("---------------------------------------------------\n");
1006 }
1007 for(i=0; i<ann.nOrig; i++){
1008 fossil_print("%s: %.*s\n",
1009 ann.aOrig[i].zSrc->str, ann.aOrig[i].n, ann.aOrig[i].z);
1010 }
1011 free(ann.azVers);
1012 free(ann.aOrig);
1013 blob_reset(&ann.toAnnotate);
1014 while(ann.firstLabel) {
1015 struct Label *l;
1016 l = ann.firstLabel->next;
1017 assert(ann.firstLabel->nref > 0);
1018 free(ann.firstLabel->str);
1019 free(ann.firstLabel);
1020 ann.firstLabel = l;
1021 }
1022 }
1023
+1 -1
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757757
**
758758
** The root of the tree is defined by the g.zLocalRoot variable.
759759
*/
760760
int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761761
int n;
762
- Blob full;
762
+ Blob full = empty_blob;
763763
int nFull;
764764
char *zFull;
765765
766766
blob_zero(pOut);
767767
db_must_be_within_tree();
768768
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757 **
758 ** The root of the tree is defined by the g.zLocalRoot variable.
759 */
760 int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761 int n;
762 Blob full;
763 int nFull;
764 char *zFull;
765
766 blob_zero(pOut);
767 db_must_be_within_tree();
768
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757 **
758 ** The root of the tree is defined by the g.zLocalRoot variable.
759 */
760 int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761 int n;
762 Blob full = empty_blob;
763 int nFull;
764 char *zFull;
765
766 blob_zero(pOut);
767 db_must_be_within_tree();
768
+1 -1
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757757
**
758758
** The root of the tree is defined by the g.zLocalRoot variable.
759759
*/
760760
int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761761
int n;
762
- Blob full;
762
+ Blob full = empty_blob;
763763
int nFull;
764764
char *zFull;
765765
766766
blob_zero(pOut);
767767
db_must_be_within_tree();
768768
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757 **
758 ** The root of the tree is defined by the g.zLocalRoot variable.
759 */
760 int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761 int n;
762 Blob full;
763 int nFull;
764 char *zFull;
765
766 blob_zero(pOut);
767 db_must_be_within_tree();
768
--- src/file.c
+++ src/file.c
@@ -757,11 +757,11 @@
757 **
758 ** The root of the tree is defined by the g.zLocalRoot variable.
759 */
760 int file_tree_name(const char *zOrigName, Blob *pOut, int errFatal){
761 int n;
762 Blob full = empty_blob;
763 int nFull;
764 char *zFull;
765
766 blob_zero(pOut);
767 db_must_be_within_tree();
768

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button