Fossil SCM

Begin inserting code to implement an "annotate" command.

drh 2008-02-04 16:39 trunk
Commit 9b68bc33bd40d979bd762fff98b3257d9cdf5ab8
1 file changed +155
+155
--- src/diff.c
+++ src/diff.c
@@ -549,5 +549,160 @@
549549
blob_read_from_file(&b, g.argv[3]);
550550
blob_zero(&out);
551551
text_diff(&a, &b, &out, 3);
552552
blob_write_to_file(&out, "-");
553553
}
554
+
555
+/**************************************************************************
556
+** The basic difference engine is above. What follows is the annotation
557
+** engine. Both are in the same file since they share many components.
558
+*/
559
+
560
+/*
561
+** The status of an annotation operation is recorded by an instance
562
+** of the following structure.
563
+*/
564
+typedef struct Annotator Annotator;
565
+struct Annotator {
566
+ DContext c; /* The diff-engine context */
567
+ Blob blobTo; /* Blob to free at next step */
568
+ int nOrig; /* Number of lines in original file */
569
+ int nNoSrc; /* Number of uncompleted aOrig[].zSrc entries */
570
+ struct { /* Lines of the original files... */
571
+ const char *z; /* The text of the line */
572
+ int n; /* Number of bytes (omitting trailing space and \n) */
573
+ const char *zSrc; /* Tag showing origin of this line */
574
+ } *aOrig;
575
+ int *aMap; /* Map lines for c.aTo into aOrig */
576
+};
577
+
578
+/*
579
+** Initialize the annotation process by specifying the file that is
580
+** to be annotated. The annotator takes control of the input Blob and
581
+** will release it when it is finished with it.
582
+*/
583
+static int annotation_start(Annotator *p, Blob *pInput){
584
+ int i;
585
+
586
+ memset(p, 0, sizeof(*p));
587
+ p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
588
+ if( p->c.aTo==0 ){
589
+ return 1;
590
+ }
591
+ p->aMap = malloc( sizeof(int)*p->c.nTo );
592
+ if( p->aMap==0 ) fossil_panic("out of memory");
593
+ for(i=0; i<p->c.nTo; i++) p->aMap[i] = i;
594
+ p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
595
+ if( p->aOrig==0 ) fossil_panic("out of memory");
596
+ for(i=0; i<p->c.nTo; i++){
597
+ p->aOrig[i].z = p->c.aTo[i].z;
598
+ p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
599
+ p->aOrig[i].zSrc = 0;
600
+ }
601
+ p->nOrig = p->c.nTo;
602
+ p->nNoSrc = p->c.nTo;
603
+ return 0;
604
+}
605
+
606
+/*
607
+** The input pParent is the next most recent ancestor of the file
608
+** being annotated. Do another step of the annotation. Return true
609
+** if additional annotation is required. zPName is the tag to insert
610
+** on each line of the file being annotated that was contributed by
611
+** pParent. Memory to hold zPName is leaked.
612
+*/
613
+static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
614
+ int i, j;
615
+ int lnTo, lnFrom;
616
+ int *aFromMap;
617
+
618
+ /* Prepare the parent file to be diffed */
619
+ p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
620
+ if( p->c.aFrom==0 ){
621
+ return 1;
622
+ }
623
+
624
+ /* Compute the differences going from pParent to the last file
625
+ ** processed */
626
+ diff_all(&p->c);
627
+
628
+ /* Where new lines are inserted on this difference, record the
629
+ ** zPName as the source of the new line.
630
+ */
631
+ for(i=lnTo=0; i<p->c.nEdit; i+=3){
632
+ lnTo += p->c.aEdit[i];
633
+ for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){
634
+ int x = p->aMap[lnTo];
635
+ if( x>=0 && p->aOrig[x].zSrc==0 ){
636
+ p->aOrig[x].zSrc = zPName;
637
+ p->nNoSrc--;
638
+ }
639
+ }
640
+ }
641
+
642
+ /* We will be converting aFrom into aTo for the next step. Compute
643
+ ** a map from the aFrom into the original file being annotated.
644
+ */
645
+ aFromMap = malloc( sizeof(int)*p->c.nFrom );
646
+ if( aFromMap==0 ){
647
+ fossil_panic("out of memory");
648
+ }
649
+ for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){
650
+ for(j=0; j<p->c.aEdit[i]; j++){
651
+ aFromMap[lnFrom++] = p->aMap[lnTo++];
652
+ }
653
+ for(j=0; j<p->c.aEdit[i+1]; j++){
654
+ aFromMap[lnFrom++] = -1;
655
+ }
656
+ lnTo += p->c.aEdit[i+2];
657
+ }
658
+ assert( lnFrom==p->c.nFrom );
659
+ free(p->aMap);
660
+ p->aMap = aFromMap;
661
+
662
+ /* Clear out the diff results */
663
+ free(p->c.aEdit);
664
+ p->c.aEdit = 0;
665
+ p->c.nEdit = 0;
666
+ p->c.nEditAlloc = 0;
667
+
668
+ /* Move aFrom over to aTo in preparation for the next step */
669
+ free(p->c.aTo);
670
+ if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo);
671
+ p->blobTo = *pParent;
672
+ blob_zero(pParent);
673
+ p->c.aTo = p->c.aFrom;
674
+ p->c.nTo = p->c.nFrom;
675
+
676
+ /* Return no errors */
677
+ return 0;
678
+}
679
+
680
+
681
+/*
682
+** COMMAND: test-annotate-step
683
+*/
684
+void test_annotate_step_cmd(void){
685
+ Blob orig, b;
686
+ Annotator x;
687
+ int i;
688
+
689
+ if( g.argc<4 ) usage("RID1 RID2 ...");
690
+ db_must_be_within_tree();
691
+ blob_zero(&b);
692
+ content_get(name_to_rid(g.argv[2]), &orig);
693
+ if( annotation_start(&x, &orig) ){
694
+ fossil_fatal("binary file");
695
+ }
696
+ for(i=3; i<g.argc; i++){
697
+ blob_zero(&b);
698
+ content_get(name_to_rid(g.argv[i]), &b);
699
+ if( annotation_step(&x, &b, g.argv[i-1]) ){
700
+ fossil_fatal("binary file");
701
+ }
702
+ }
703
+ for(i=0; i<x.nOrig; i++){
704
+ const char *zSrc = x.aOrig[i].zSrc;
705
+ if( zSrc==0 ) zSrc = g.argv[g.argc-1];
706
+ printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
707
+ }
708
+}
554709
--- src/diff.c
+++ src/diff.c
@@ -549,5 +549,160 @@
549 blob_read_from_file(&b, g.argv[3]);
550 blob_zero(&out);
551 text_diff(&a, &b, &out, 3);
552 blob_write_to_file(&out, "-");
553 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
--- src/diff.c
+++ src/diff.c
@@ -549,5 +549,160 @@
549 blob_read_from_file(&b, g.argv[3]);
550 blob_zero(&out);
551 text_diff(&a, &b, &out, 3);
552 blob_write_to_file(&out, "-");
553 }
554
555 /**************************************************************************
556 ** The basic difference engine is above. What follows is the annotation
557 ** engine. Both are in the same file since they share many components.
558 */
559
560 /*
561 ** The status of an annotation operation is recorded by an instance
562 ** of the following structure.
563 */
564 typedef struct Annotator Annotator;
565 struct Annotator {
566 DContext c; /* The diff-engine context */
567 Blob blobTo; /* Blob to free at next step */
568 int nOrig; /* Number of lines in original file */
569 int nNoSrc; /* Number of uncompleted aOrig[].zSrc entries */
570 struct { /* Lines of the original files... */
571 const char *z; /* The text of the line */
572 int n; /* Number of bytes (omitting trailing space and \n) */
573 const char *zSrc; /* Tag showing origin of this line */
574 } *aOrig;
575 int *aMap; /* Map lines for c.aTo into aOrig */
576 };
577
578 /*
579 ** Initialize the annotation process by specifying the file that is
580 ** to be annotated. The annotator takes control of the input Blob and
581 ** will release it when it is finished with it.
582 */
583 static int annotation_start(Annotator *p, Blob *pInput){
584 int i;
585
586 memset(p, 0, sizeof(*p));
587 p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
588 if( p->c.aTo==0 ){
589 return 1;
590 }
591 p->aMap = malloc( sizeof(int)*p->c.nTo );
592 if( p->aMap==0 ) fossil_panic("out of memory");
593 for(i=0; i<p->c.nTo; i++) p->aMap[i] = i;
594 p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
595 if( p->aOrig==0 ) fossil_panic("out of memory");
596 for(i=0; i<p->c.nTo; i++){
597 p->aOrig[i].z = p->c.aTo[i].z;
598 p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
599 p->aOrig[i].zSrc = 0;
600 }
601 p->nOrig = p->c.nTo;
602 p->nNoSrc = p->c.nTo;
603 return 0;
604 }
605
606 /*
607 ** The input pParent is the next most recent ancestor of the file
608 ** being annotated. Do another step of the annotation. Return true
609 ** if additional annotation is required. zPName is the tag to insert
610 ** on each line of the file being annotated that was contributed by
611 ** pParent. Memory to hold zPName is leaked.
612 */
613 static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
614 int i, j;
615 int lnTo, lnFrom;
616 int *aFromMap;
617
618 /* Prepare the parent file to be diffed */
619 p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
620 if( p->c.aFrom==0 ){
621 return 1;
622 }
623
624 /* Compute the differences going from pParent to the last file
625 ** processed */
626 diff_all(&p->c);
627
628 /* Where new lines are inserted on this difference, record the
629 ** zPName as the source of the new line.
630 */
631 for(i=lnTo=0; i<p->c.nEdit; i+=3){
632 lnTo += p->c.aEdit[i];
633 for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){
634 int x = p->aMap[lnTo];
635 if( x>=0 && p->aOrig[x].zSrc==0 ){
636 p->aOrig[x].zSrc = zPName;
637 p->nNoSrc--;
638 }
639 }
640 }
641
642 /* We will be converting aFrom into aTo for the next step. Compute
643 ** a map from the aFrom into the original file being annotated.
644 */
645 aFromMap = malloc( sizeof(int)*p->c.nFrom );
646 if( aFromMap==0 ){
647 fossil_panic("out of memory");
648 }
649 for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){
650 for(j=0; j<p->c.aEdit[i]; j++){
651 aFromMap[lnFrom++] = p->aMap[lnTo++];
652 }
653 for(j=0; j<p->c.aEdit[i+1]; j++){
654 aFromMap[lnFrom++] = -1;
655 }
656 lnTo += p->c.aEdit[i+2];
657 }
658 assert( lnFrom==p->c.nFrom );
659 free(p->aMap);
660 p->aMap = aFromMap;
661
662 /* Clear out the diff results */
663 free(p->c.aEdit);
664 p->c.aEdit = 0;
665 p->c.nEdit = 0;
666 p->c.nEditAlloc = 0;
667
668 /* Move aFrom over to aTo in preparation for the next step */
669 free(p->c.aTo);
670 if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo);
671 p->blobTo = *pParent;
672 blob_zero(pParent);
673 p->c.aTo = p->c.aFrom;
674 p->c.nTo = p->c.nFrom;
675
676 /* Return no errors */
677 return 0;
678 }
679
680
681 /*
682 ** COMMAND: test-annotate-step
683 */
684 void test_annotate_step_cmd(void){
685 Blob orig, b;
686 Annotator x;
687 int i;
688
689 if( g.argc<4 ) usage("RID1 RID2 ...");
690 db_must_be_within_tree();
691 blob_zero(&b);
692 content_get(name_to_rid(g.argv[2]), &orig);
693 if( annotation_start(&x, &orig) ){
694 fossil_fatal("binary file");
695 }
696 for(i=3; i<g.argc; i++){
697 blob_zero(&b);
698 content_get(name_to_rid(g.argv[i]), &b);
699 if( annotation_step(&x, &b, g.argv[i-1]) ){
700 fossil_fatal("binary file");
701 }
702 }
703 for(i=0; i<x.nOrig; i++){
704 const char *zSrc = x.aOrig[i].zSrc;
705 if( zSrc==0 ) zSrc = g.argv[g.argc-1];
706 printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
707 }
708 }
709

Keyboard Shortcuts

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