home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / diff3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  7.8 KB  |  422 lines

  1. #include <stdio.h>
  2. #
  3.  
  4. /* diff3 - 3-way differential file comparison*/
  5.  
  6. /* diff3 [-e] d13 d23 f1 f2 f3 
  7.  *
  8.  * d13 = diff report on f1 vs f3
  9.  * d23 = diff report on f2 vs f3
  10.  * f1, f2, f3 the 3 files
  11. */
  12.  
  13. struct  range {int from,to; };
  14.     /* from is first in range of changed lines
  15.      * to is last+1
  16.      * from=to=line after point of insertion
  17.     * for added lines
  18.     */
  19. struct diff {struct range old, new;};
  20.  
  21. #define NC 200
  22. /* de is used to gather editing scripts,
  23.  * that are later spewed out in reverse order.
  24.  * its first element must be all zero
  25.  * the "new" component of de contains line positions
  26.  * or byte positions depending on when you look(!?)
  27. */
  28. struct diff d13[NC];
  29. struct diff d23[NC];
  30. struct diff de[NC];
  31. char line[256];
  32. FILE *fp[3];
  33. int linct[3] = {0,0,0};
  34. /*    the number of the last-read line in each file
  35.  *    is kept in cline[0-2]
  36. */
  37. int cline[3];
  38. /*    the latest known correspondence between line
  39.  *    numbers of the 3 files is stored in last[1-3]
  40. */
  41. int last[4];
  42. int eflag;
  43. int debug  = 0;
  44.  
  45. main(argc,argv)
  46. char **argv;
  47. {
  48.     register i,m,n;
  49.     if(*argv[1]=='-') {
  50.         switch(argv[1][1]) {
  51.         default:
  52.             eflag = 3;
  53.             break;
  54.         case '3':
  55.             eflag = 2;
  56.             break;
  57.         case 'x':
  58.             eflag = 1;
  59.         }
  60.         argv++;
  61.         argc--;
  62.     }
  63.     if(argc<6) {
  64.         fprintf(stderr,"diff3: arg count\n");
  65.         exit(1);
  66.     }
  67.     m = readin(argv[1],d13);
  68.     n = readin(argv[2],d23);
  69.     for(i=0;i<=2;i++)
  70.         if((fp[i] = fopen(argv[i+3],"r")) == NULL) {
  71.             printf("diff3: can't open %s\n",argv[i+3]);
  72.             exit(1);
  73.         }
  74.     merge(m,n);
  75. }
  76.  
  77. /*pick up the line numbers of allcahnges from
  78.  * one change file
  79.  * (this puts the numbers in a vector, which is not
  80.  * strictly necessary, since the vector is processed
  81.  * in one sequential pass. The vector could be optimized
  82.  * out of existence)
  83. */
  84.  
  85. readin(name,dd)
  86. char *name;
  87. struct diff *dd;
  88. {
  89.     register i;
  90.     int a,b,c,d;
  91.     char kind;
  92.     char *p;
  93.     fp[0] = fopen(name,"r");
  94.     for(i=0;getchange(fp[0]);i++) {
  95.         if(i>=NC) {
  96.             fprintf(stderr,"diff3: too many changes\n");
  97.             exit(0);
  98.         }
  99.         p = line;
  100.         a = b = number(&p);
  101.         if(*p==',') {
  102.             p++;
  103.             b = number(&p);
  104.         }
  105.         kind = *p++;
  106.         c = d = number(&p);
  107.         if(*p==',') {
  108.             p++;
  109.             d = number(&p);
  110.         }
  111.         if(kind=='a')
  112.             a++;
  113.         if(kind=='d')
  114.             c++;
  115.         b++;
  116.         d++;
  117.         dd[i].old.from = a;
  118.         dd[i].old.to = b;
  119.         dd[i].new.from = c;
  120.         dd[i].new.to = d;
  121.     }
  122.     dd[i].old.from = dd[i-1].old.to;
  123.     dd[i].new.from = dd[i-1].new.to;
  124.     fclose(fp[0]);
  125.     return(i);
  126. }
  127.  
  128. number(lc)
  129. char **lc;
  130. {
  131.     register nn;
  132.     nn = 0;
  133.     while(digit(**lc))
  134.         nn = nn*10 + *(*lc)++ - '0';
  135.     return(nn);
  136. }
  137.  
  138. digit(c)
  139. {
  140.     return(c>='0'&&c<='9');
  141. }
  142.  
  143. getchange(b)
  144. FILE *b;
  145. {
  146.     while(getline(b))
  147.         if(digit(line[0]))
  148.             return(1);
  149.     return(0);
  150. }
  151.  
  152. getline(b)
  153. FILE *b;
  154. {
  155.     register i, c;
  156.     for(i=0;i<sizeof(line)-1;i++) {
  157.         c = getc(b);
  158.         if(c==EOF)
  159.             break;
  160.         line[i] = c;
  161.         if(c=='\n') {
  162.             line[++i] = 0;
  163.             return(i);
  164.         }
  165.     }
  166.     return(0);
  167. }
  168.  
  169. merge(m1,m2)
  170. {
  171.     register struct diff *d1, *d2, *d3;
  172.     int dup;
  173.     int j;
  174.     int t1,t2;
  175.     d1 = d13;
  176.     d2 = d23;
  177.     j = 0;
  178.     for(;(t1 = d1<d13+m1) | (t2 = d2<d23+m2);) {
  179.         if(debug) {
  180.             printf("%d,%d=%d,%d %d,%d=%d,%d\n",
  181.             d1->old.from,d1->old.to,
  182.             d1->new.from,d1->new.to,
  183.             d2->old.from,d2->old.to,
  184.             d2->new.from,d2->new.to);
  185.         }
  186. /*            first file is different from others*/
  187.         if(!t2||t1&&d1->new.to < d2->new.from) {
  188. /*            stuff peculiar to 1st file */
  189.             if(eflag==0) {
  190.                 separate("1");
  191.                 change(1,&d1->old,0);
  192.                 keep(2,&d1->old,&d1->new);
  193.                 change(3,&d1->new,0);
  194.             }
  195.             d1++;
  196.             continue;
  197.         }
  198. /*            second file is different from others*/
  199.         if(!t1||t2&&d2->new.to < d1->new.from) {
  200.             if(eflag==0) {
  201.                 separate("2");
  202.                 keep(1,&d2->old,&d2->new);
  203.                 change(2,&d2->old,0);
  204.                 change(3,&d2->new,0);
  205.             }
  206.             d2++;
  207.             continue;
  208.         }
  209. /*            merge overlapping changes in first file
  210.  *            this happens after extension see below*/
  211.         if(d1+1<d13+m1 &&
  212.            d1->new.to>=d1[1].new.from) {
  213.             d1[1].old.from = d1->old.from;
  214.             d1[1].new.from = d1->new.from;
  215.             d1++;
  216.             continue;
  217.         }
  218. /*            merge overlapping changes in second*/
  219.         if(d2+1<d23+m2 &&
  220.            d2->new.to>=d2[1].new.from) {
  221.             d2[1].old.from = d2->old.from;
  222.             d2[1].new.from = d2->new.from;
  223.             d2++;
  224.             continue;
  225.         }
  226. /*            stuff peculiar to third file or different in all*/
  227.         if(d1->new.from==d2->new.from&&
  228.            d1->new.to==d2->new.to) {
  229.             dup = duplicate(&d1->old,&d2->old);
  230. /*                dup=0 means all files differ
  231.  *                dup =1 meands files 1&2 identical*/
  232.             if(eflag==0) {
  233.                 separate(dup?"3":"");
  234.                 change(1,&d1->old,dup);
  235.                 change(2,&d2->old,0);
  236.                 d3 = d1->old.to>d1->old.from?d1:d2;
  237.                 change(3,&d3->new,0);
  238.             } else
  239.                 j = edit(d1,dup,j);
  240.             d1++;
  241.             d2++;
  242.             continue;
  243.         }
  244. /*            overlapping changes from file1 & 2
  245.  *            extend changes appropriately to
  246.  *            make them coincide*/
  247.          if(d1->new.from<d2->new.from) {
  248.             d2->old.from -= d2->new.from-d1->new.from;
  249.             d2->new.from = d1->new.from;
  250.         }
  251.         else if(d2->new.from<d1->new.from) {
  252.             d1->old.from -= d1->new.from-d2->new.from;
  253.             d1->new.from = d2->new.from;
  254.         }
  255.         if(d1->new.to >d2->new.to) {
  256.             d2->old.to += d1->new.to - d2->new.to;
  257.             d2->new.to = d1->new.to;
  258.         }
  259.         else if(d2->new.to >d1->new.to) {
  260.             d1->old.to += d2->new.to - d1->new.to;
  261.             d1->new.to = d2->new.to;
  262.         }
  263.     }
  264.     if(eflag)
  265.         edscript(j);
  266. }
  267.  
  268. separate(s)
  269. char *s;
  270. {
  271.     printf("====%s\n",s);
  272. }
  273.  
  274. /*    the range of ines rold.from thru rold.to in file i
  275.  *    is to be changed. it is to be printed only if
  276.  *    it does not duplicate something to be printed later
  277. */
  278. change(i,rold,dup)
  279. struct range *rold;
  280. {
  281.     printf("%d:",i);
  282.     last[i] = rold->to;
  283.     prange(rold);
  284.     if(dup)
  285.         return;
  286.     if(debug)
  287.         return;
  288.     i--;
  289.     skip(i,rold->from,(char *)0);
  290.     skip(i,rold->to,"  ");
  291. }
  292.  
  293. /*    print the range of line numbers, rold.from  thru rold.to
  294.  *    as n1,n2 or n1
  295. */
  296. prange(rold)
  297. struct range *rold;
  298. {
  299.     if(rold->to<=rold->from)
  300.         printf("%da\n",rold->from-1);
  301.     else {
  302.         printf("%d",rold->from);
  303.         if(rold->to > rold->from+1)
  304.             printf(",%d",rold->to-1);
  305.         printf("c\n");
  306.     }
  307. }
  308.  
  309. /*    no difference was reported by diff between file 1(or 2)
  310.  *    and file 3, and an artificial dummy difference (trange)
  311.  *    must be ginned up to correspond to the change reported
  312.  *    in the other file
  313. */
  314. keep(i,rold,rnew)
  315. struct range *rold, *rnew;
  316. {
  317.     register delta;
  318.     struct range trange;
  319.     delta = last[3] - last[i];
  320.     trange.from = rnew->from - delta;
  321.     trange.to = rnew->to - delta;
  322.     change(i,&trange,1);
  323. }
  324.  
  325. /*    skip to just befor line number from in file i
  326.  *    if "pr" is nonzero, print all skipped stuff
  327.  * w    with string pr as a prefix
  328. */
  329. skip(i,from,pr)
  330. char *pr;
  331. {
  332.     register j,n;
  333.     for(n=0;cline[i]<from-1;n+=j) {
  334.         if((j=getline(fp[i]))==0)
  335.             trouble();
  336.         if(pr)
  337.             printf("%s%s",pr,line);
  338.         cline[i]++;
  339.     }
  340.     return(n);
  341. }
  342.  
  343. /*    return 1 or 0 according as the old range
  344.  *    (in file 1) contains exactly the same data
  345.  *    as the new range (in file 2)
  346. */
  347. duplicate(r1,r2)
  348. struct range *r1, *r2;
  349. {
  350.     register c,d;
  351.     register nchar;
  352.     int nline;
  353.     if(r1->to-r1->from != r2->to-r2->from)
  354.         return(0);
  355.     skip(0,r1->from,(char *)0);
  356.     skip(1,r2->from,(char *)0);
  357.     nchar = 0;
  358.     for(nline=0;nline<r1->to-r1->from;nline++) {
  359.         do {
  360.             c = getc(fp[0]);
  361.             d = getc(fp[1]);
  362.             if(c== -1||d== -1)
  363.                 trouble();
  364.             nchar++;
  365.             if(c!=d) {
  366.                 repos(nchar);
  367.                 return;
  368.             }
  369.         } while(c!= '\n');
  370.     }
  371.     repos(nchar);
  372.     return(1);
  373. }
  374.  
  375. repos(nchar)
  376. {
  377.     register i;
  378.     for(i=0;i<2;i++) 
  379.         fseek(fp[i], (long)-nchar, 1);
  380. }
  381.  
  382. trouble()
  383. {
  384.     fprintf(stderr,"diff3: logic error\n");
  385.     abort();
  386. }
  387.  
  388. /*    collect an editing script for later regurgitation
  389. */
  390. edit(diff,dup,j)
  391. struct diff *diff;
  392. {
  393.     if(((dup+1)&eflag)==0)
  394.         return(j);
  395.     j++;
  396.     de[j].old.from = diff->old.from;
  397.     de[j].old.to = diff->old.to;
  398.     de[j].new.from = de[j-1].new.to
  399.         +skip(2,diff->new.from,(char *)0);
  400.     de[j].new.to = de[j].new.from
  401.         +skip(2,diff->new.to,(char *)0);
  402.     return(j);
  403. }
  404.  
  405. /*        regurgitate */
  406. edscript(n)
  407. {
  408.     register j,k;
  409.     char block[512];
  410.     for(n=n;n>0;n--) {
  411.         prange(&de[n].old);
  412.         fseek(fp[2], (long)de[n].new.from, 0);
  413.         for(k=de[n].new.to-de[n].new.from;k>0;k-= j) {
  414.             j = k>512?512:k;
  415.             if(fread(block,1,j,fp[2])!=j)
  416.                 trouble();
  417.             fwrite(block, 1, j, stdout);
  418.         }
  419.         printf(".\n");
  420.     }
  421. }
  422.