Fossil

Check-in [9b68bc33bd]
Login

Check-in [9b68bc33bd]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Begin inserting code to implement an "annotate" command.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9b68bc33bd40d979bd762fff98b3257d9cdf5ab8
User & Date: drh 2008-02-04 16:39:09.000
Context
2008-02-04
17:26
Added 'achtung' class. See the code comments. ... (check-in: b5b04dcf85 user: stephan tags: trunk)
16:39
Begin inserting code to implement an "annotate" command. ... (check-in: 9b68bc33bd user: drh tags: trunk)
14:24
Additional cleanup in the differencing engine. The new "dir" webpage now uses name= instead of the d= for the query parameter. ... (check-in: e81cc91aa4 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/diff.c.
547
548
549
550
551
552
553



























































































































































  if( g.argc!=4 ) usage("FILE1 FILE2");
  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, "-");
}


































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  if( g.argc!=4 ) usage("FILE1 FILE2");
  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);
  }
}