Check-in [9b68bc33bd]
Not logged in
Overview

SHA1 Hash:9b68bc33bd40d979bd762fff98b3257d9cdf5ab8
Date: 2008-02-04 16:39:09
User: drh
Comment:Begin inserting code to implement an "annotate" command.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/diff.c from [06ee9b8f1e] to [f5f8837cf7].

@@ -548,6 +548,161 @@
   blob_read_from_file(&a, g.argv[2]);
   blob_read_from_file(&b, g.argv[3]);
   blob_zero(&out);
   text_diff(&a, &b, &out, 3);
   blob_write_to_file(&out, "-");
+}
+
+/**************************************************************************
+** The basic difference engine is above.  What follows is the annotation
+** engine.  Both are in the same file since they share many components.
+*/
+
+/*
+** The status of an annotation operation is recorded by an instance
+** of the following structure.
+*/
+typedef struct Annotator Annotator;
+struct Annotator {
+  DContext c;       /* The diff-engine context */
+  Blob blobTo;      /* Blob to free at next step */
+  int nOrig;        /* Number of lines in original file */
+  int nNoSrc;       /* Number of uncompleted aOrig[].zSrc entries */
+  struct {          /* Lines of the original files... */
+    const char *z;       /* The text of the line */
+    int n;               /* Number of bytes (omitting trailing space and \n) */
+    const char *zSrc;    /* Tag showing origin of this line */
+  } *aOrig;
+  int *aMap;        /* Map lines for c.aTo into aOrig */
+};
+
+/*
+** 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){
+  int i;
+
+  memset(p, 0, sizeof(*p));
+  p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
+  if( p->c.aTo==0 ){
+    return 1;
+  }
+  p->aMap = malloc( sizeof(int)*p->c.nTo );
+  if( p->aMap==0 ) fossil_panic("out of memory");
+  for(i=0; i<p->c.nTo; i++) p->aMap[i] = i;
+  p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
+  if( p->aOrig==0 ) fossil_panic("out of memory");
+  for(i=0; i<p->c.nTo; i++){
+    p->aOrig[i].z = p->c.aTo[i].z;
+    p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
+    p->aOrig[i].zSrc = 0;
+  }
+  p->nOrig = p->c.nTo;
+  p->nNoSrc = p->c.nTo;
+  return 0;
+}
+
+/*
+** The input pParent is the next most recent ancestor of the file
+** 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){
+  int i, j;
+  int lnTo, lnFrom;
+  int *aFromMap;
+
+  /* Prepare the parent file to be diffed */
+  p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
+  if( p->c.aFrom==0 ){
+    return 1;
+  }
+
+  /* Compute the differences going from pParent to the last file
+  ** processed */
+  diff_all(&p->c);
+
+  /* Where new lines are inserted on this difference, record the
+  ** zPName as the source of the new line.
+  */
+  for(i=lnTo=0; i<p->c.nEdit; i+=3){
+    lnTo += p->c.aEdit[i];
+    for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){
+      int x = p->aMap[lnTo];
+      if( x>=0 && p->aOrig[x].zSrc==0 ){
+        p->aOrig[x].zSrc = zPName;
+        p->nNoSrc--;
+      }
+    }
+  }
+
+  /* We will be converting aFrom into aTo for the next step.  Compute
+  ** a map from the aFrom into the original file being annotated.
+  */
+  aFromMap = malloc( sizeof(int)*p->c.nFrom );
+  if( aFromMap==0 ){
+    fossil_panic("out of memory");
+  }
+  for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){
+    for(j=0; j<p->c.aEdit[i]; j++){
+      aFromMap[lnFrom++] = p->aMap[lnTo++];
+    }
+    for(j=0; j<p->c.aEdit[i+1]; j++){
+      aFromMap[lnFrom++] = -1;
+    }
+    lnTo += p->c.aEdit[i+2];
+  }
+  assert( lnFrom==p->c.nFrom );
+  free(p->aMap);
+  p->aMap = aFromMap;
+
+  /* Clear out the diff results */
+  free(p->c.aEdit);
+  p->c.aEdit = 0;
+  p->c.nEdit = 0;
+  p->c.nEditAlloc = 0;
+
+  /* Move aFrom over to aTo in preparation for the next step */
+  free(p->c.aTo);
+  if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo);
+  p->blobTo = *pParent;
+  blob_zero(pParent);
+  p->c.aTo = p->c.aFrom;
+  p->c.nTo = p->c.nFrom;
+
+  /* Return no errors */
+  return 0;
+}
+
+
+/*
+** COMMAND: test-annotate-step
+*/
+void test_annotate_step_cmd(void){
+  Blob orig, b;
+  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) ){
+    fossil_fatal("binary file");
+  }
+  for(i=3; i<g.argc; i++){
+    blob_zero(&b);
+    content_get(name_to_rid(g.argv[i]), &b);
+    if( annotation_step(&x, &b, g.argv[i-1]) ){
+      fossil_fatal("binary file");
+    }
+  }
+  for(i=0; i<x.nOrig; i++){
+    const char *zSrc = x.aOrig[i].zSrc;
+    if( zSrc==0 ) zSrc = g.argv[g.argc-1];
+    printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
+  }
 }