1*14484Ssam #ifndef lint 2*14484Ssam static char sccsid[] = "@(#)diff3.c 4.2 (Berkeley) 08/11/83"; 3*14484Ssam #endif 410880Sshannon 510880Sshannon #include <stdio.h> 610880Sshannon # 710880Sshannon 810880Sshannon /* diff3 - 3-way differential file comparison*/ 910880Sshannon 1010880Sshannon /* diff3 [-e] d13 d23 f1 f2 f3 1110880Sshannon * 1210880Sshannon * d13 = diff report on f1 vs f3 1310880Sshannon * d23 = diff report on f2 vs f3 1410880Sshannon * f1, f2, f3 the 3 files 1510880Sshannon */ 1610880Sshannon 1710880Sshannon struct range {int from,to; }; 1810880Sshannon /* from is first in range of changed lines 1910880Sshannon * to is last+1 2010880Sshannon * from=to=line after point of insertion 2110880Sshannon * for added lines 2210880Sshannon */ 2310880Sshannon struct diff {struct range old, new;}; 2410880Sshannon 2510880Sshannon #define NC 200 2610880Sshannon /* de is used to gather editing scripts, 2710880Sshannon * that are later spewed out in reverse order. 2810880Sshannon * its first element must be all zero 2910880Sshannon * the "new" component of de contains line positions 3010880Sshannon * or byte positions depending on when you look(!?) 3110880Sshannon */ 3210880Sshannon struct diff d13[NC]; 3310880Sshannon struct diff d23[NC]; 3410880Sshannon struct diff de[NC]; 3510880Sshannon char line[256]; 3610880Sshannon FILE *fp[3]; 3710880Sshannon int linct[3] = {0,0,0}; 3810880Sshannon /* the number of the last-read line in each file 3910880Sshannon * is kept in cline[0-2] 4010880Sshannon */ 4110880Sshannon int cline[3]; 4210880Sshannon /* the latest known correspondence between line 4310880Sshannon * numbers of the 3 files is stored in last[1-3] 4410880Sshannon */ 4510880Sshannon int last[4]; 4610880Sshannon int eflag; 4710880Sshannon int debug = 0; 4810880Sshannon 4910880Sshannon main(argc,argv) 5010880Sshannon char **argv; 5110880Sshannon { 5210880Sshannon register i,m,n; 5310880Sshannon if(*argv[1]=='-') { 5410880Sshannon switch(argv[1][1]) { 5510880Sshannon default: 5610880Sshannon eflag = 3; 5710880Sshannon break; 5810880Sshannon case '3': 5910880Sshannon eflag = 2; 6010880Sshannon break; 6110880Sshannon case 'x': 6210880Sshannon eflag = 1; 6310880Sshannon } 6410880Sshannon argv++; 6510880Sshannon argc--; 6610880Sshannon } 6710880Sshannon if(argc<6) { 6810880Sshannon fprintf(stderr,"diff3: arg count\n"); 6910880Sshannon exit(1); 7010880Sshannon } 7110880Sshannon m = readin(argv[1],d13); 7210880Sshannon n = readin(argv[2],d23); 7310880Sshannon for(i=0;i<=2;i++) 7410880Sshannon if((fp[i] = fopen(argv[i+3],"r")) == NULL) { 7510880Sshannon printf("diff3: can't open %s\n",argv[i+3]); 7610880Sshannon exit(1); 7710880Sshannon } 7810880Sshannon merge(m,n); 7910880Sshannon } 8010880Sshannon 8110880Sshannon /*pick up the line numbers of allcahnges from 8210880Sshannon * one change file 8310880Sshannon * (this puts the numbers in a vector, which is not 8410880Sshannon * strictly necessary, since the vector is processed 8510880Sshannon * in one sequential pass. The vector could be optimized 8610880Sshannon * out of existence) 8710880Sshannon */ 8810880Sshannon 8910880Sshannon readin(name,dd) 9010880Sshannon char *name; 9110880Sshannon struct diff *dd; 9210880Sshannon { 9310880Sshannon register i; 9410880Sshannon int a,b,c,d; 9510880Sshannon char kind; 9610880Sshannon char *p; 9710880Sshannon fp[0] = fopen(name,"r"); 9810880Sshannon for(i=0;getchange(fp[0]);i++) { 9910880Sshannon if(i>=NC) { 10010880Sshannon fprintf(stderr,"diff3: too many changes\n"); 10110880Sshannon exit(0); 10210880Sshannon } 10310880Sshannon p = line; 10410880Sshannon a = b = number(&p); 10510880Sshannon if(*p==',') { 10610880Sshannon p++; 10710880Sshannon b = number(&p); 10810880Sshannon } 10910880Sshannon kind = *p++; 11010880Sshannon c = d = number(&p); 11110880Sshannon if(*p==',') { 11210880Sshannon p++; 11310880Sshannon d = number(&p); 11410880Sshannon } 11510880Sshannon if(kind=='a') 11610880Sshannon a++; 11710880Sshannon if(kind=='d') 11810880Sshannon c++; 11910880Sshannon b++; 12010880Sshannon d++; 12110880Sshannon dd[i].old.from = a; 12210880Sshannon dd[i].old.to = b; 12310880Sshannon dd[i].new.from = c; 12410880Sshannon dd[i].new.to = d; 12510880Sshannon } 12610880Sshannon dd[i].old.from = dd[i-1].old.to; 12710880Sshannon dd[i].new.from = dd[i-1].new.to; 12810880Sshannon fclose(fp[0]); 12910880Sshannon return(i); 13010880Sshannon } 13110880Sshannon 13210880Sshannon number(lc) 13310880Sshannon char **lc; 13410880Sshannon { 13510880Sshannon register nn; 13610880Sshannon nn = 0; 13710880Sshannon while(digit(**lc)) 13810880Sshannon nn = nn*10 + *(*lc)++ - '0'; 13910880Sshannon return(nn); 14010880Sshannon } 14110880Sshannon 14210880Sshannon digit(c) 14310880Sshannon { 14410880Sshannon return(c>='0'&&c<='9'); 14510880Sshannon } 14610880Sshannon 14710880Sshannon getchange(b) 14810880Sshannon FILE *b; 14910880Sshannon { 15010880Sshannon while(getline(b)) 15110880Sshannon if(digit(line[0])) 15210880Sshannon return(1); 15310880Sshannon return(0); 15410880Sshannon } 15510880Sshannon 15610880Sshannon getline(b) 15710880Sshannon FILE *b; 15810880Sshannon { 15910880Sshannon register i, c; 16010880Sshannon for(i=0;i<sizeof(line)-1;i++) { 16110880Sshannon c = getc(b); 16210880Sshannon if(c==EOF) 16310880Sshannon break; 16410880Sshannon line[i] = c; 16510880Sshannon if(c=='\n') { 16610880Sshannon line[++i] = 0; 16710880Sshannon return(i); 16810880Sshannon } 16910880Sshannon } 17010880Sshannon return(0); 17110880Sshannon } 17210880Sshannon 17310880Sshannon merge(m1,m2) 17410880Sshannon { 17510880Sshannon register struct diff *d1, *d2, *d3; 17610880Sshannon int dup; 17710880Sshannon int j; 17810880Sshannon int t1,t2; 17910880Sshannon d1 = d13; 18010880Sshannon d2 = d23; 18110880Sshannon j = 0; 18210880Sshannon for(;(t1 = d1<d13+m1) | (t2 = d2<d23+m2);) { 18310880Sshannon if(debug) { 18410880Sshannon printf("%d,%d=%d,%d %d,%d=%d,%d\n", 18510880Sshannon d1->old.from,d1->old.to, 18610880Sshannon d1->new.from,d1->new.to, 18710880Sshannon d2->old.from,d2->old.to, 18810880Sshannon d2->new.from,d2->new.to); 18910880Sshannon } 19010880Sshannon /* first file is different from others*/ 19110880Sshannon if(!t2||t1&&d1->new.to < d2->new.from) { 19210880Sshannon /* stuff peculiar to 1st file */ 19310880Sshannon if(eflag==0) { 19410880Sshannon separate("1"); 19510880Sshannon change(1,&d1->old,0); 19610880Sshannon keep(2,&d1->old,&d1->new); 19710880Sshannon change(3,&d1->new,0); 19810880Sshannon } 19910880Sshannon d1++; 20010880Sshannon continue; 20110880Sshannon } 20210880Sshannon /* second file is different from others*/ 20310880Sshannon if(!t1||t2&&d2->new.to < d1->new.from) { 20410880Sshannon if(eflag==0) { 20510880Sshannon separate("2"); 20610880Sshannon keep(1,&d2->old,&d2->new); 20710880Sshannon change(2,&d2->old,0); 20810880Sshannon change(3,&d2->new,0); 20910880Sshannon } 21010880Sshannon d2++; 21110880Sshannon continue; 21210880Sshannon } 21310880Sshannon /* merge overlapping changes in first file 21410880Sshannon * this happens after extension see below*/ 21510880Sshannon if(d1+1<d13+m1 && 21610880Sshannon d1->new.to>=d1[1].new.from) { 21710880Sshannon d1[1].old.from = d1->old.from; 21810880Sshannon d1[1].new.from = d1->new.from; 21910880Sshannon d1++; 22010880Sshannon continue; 22110880Sshannon } 22210880Sshannon /* merge overlapping changes in second*/ 22310880Sshannon if(d2+1<d23+m2 && 22410880Sshannon d2->new.to>=d2[1].new.from) { 22510880Sshannon d2[1].old.from = d2->old.from; 22610880Sshannon d2[1].new.from = d2->new.from; 22710880Sshannon d2++; 22810880Sshannon continue; 22910880Sshannon } 23010880Sshannon /* stuff peculiar to third file or different in all*/ 23110880Sshannon if(d1->new.from==d2->new.from&& 23210880Sshannon d1->new.to==d2->new.to) { 23310880Sshannon dup = duplicate(&d1->old,&d2->old); 23410880Sshannon /* dup=0 means all files differ 23510880Sshannon * dup =1 meands files 1&2 identical*/ 23610880Sshannon if(eflag==0) { 23710880Sshannon separate(dup?"3":""); 23810880Sshannon change(1,&d1->old,dup); 23910880Sshannon change(2,&d2->old,0); 24010880Sshannon d3 = d1->old.to>d1->old.from?d1:d2; 24110880Sshannon change(3,&d3->new,0); 24210880Sshannon } else 24310880Sshannon j = edit(d1,dup,j); 24410880Sshannon d1++; 24510880Sshannon d2++; 24610880Sshannon continue; 24710880Sshannon } 24810880Sshannon /* overlapping changes from file1 & 2 24910880Sshannon * extend changes appropriately to 25010880Sshannon * make them coincide*/ 25110880Sshannon if(d1->new.from<d2->new.from) { 25210880Sshannon d2->old.from -= d2->new.from-d1->new.from; 25310880Sshannon d2->new.from = d1->new.from; 25410880Sshannon } 25510880Sshannon else if(d2->new.from<d1->new.from) { 25610880Sshannon d1->old.from -= d1->new.from-d2->new.from; 25710880Sshannon d1->new.from = d2->new.from; 25810880Sshannon } 25910880Sshannon if(d1->new.to >d2->new.to) { 26010880Sshannon d2->old.to += d1->new.to - d2->new.to; 26110880Sshannon d2->new.to = d1->new.to; 26210880Sshannon } 26310880Sshannon else if(d2->new.to >d1->new.to) { 26410880Sshannon d1->old.to += d2->new.to - d1->new.to; 26510880Sshannon d1->new.to = d2->new.to; 26610880Sshannon } 26710880Sshannon } 26810880Sshannon if(eflag) 26910880Sshannon edscript(j); 27010880Sshannon } 27110880Sshannon 27210880Sshannon separate(s) 27310880Sshannon char *s; 27410880Sshannon { 27510880Sshannon printf("====%s\n",s); 27610880Sshannon } 27710880Sshannon 27810880Sshannon /* the range of ines rold.from thru rold.to in file i 27910880Sshannon * is to be changed. it is to be printed only if 28010880Sshannon * it does not duplicate something to be printed later 28110880Sshannon */ 28210880Sshannon change(i,rold,dup) 28310880Sshannon struct range *rold; 28410880Sshannon { 28510880Sshannon printf("%d:",i); 28610880Sshannon last[i] = rold->to; 28710880Sshannon prange(rold); 28810880Sshannon if(dup) 28910880Sshannon return; 29010880Sshannon if(debug) 29110880Sshannon return; 29210880Sshannon i--; 29310880Sshannon skip(i,rold->from,(char *)0); 29410880Sshannon skip(i,rold->to," "); 29510880Sshannon } 29610880Sshannon 29710880Sshannon /* print the range of line numbers, rold.from thru rold.to 29810880Sshannon * as n1,n2 or n1 29910880Sshannon */ 30010880Sshannon prange(rold) 30110880Sshannon struct range *rold; 30210880Sshannon { 30310880Sshannon if(rold->to<=rold->from) 30410880Sshannon printf("%da\n",rold->from-1); 30510880Sshannon else { 30610880Sshannon printf("%d",rold->from); 30710880Sshannon if(rold->to > rold->from+1) 30810880Sshannon printf(",%d",rold->to-1); 30910880Sshannon printf("c\n"); 31010880Sshannon } 31110880Sshannon } 31210880Sshannon 31310880Sshannon /* no difference was reported by diff between file 1(or 2) 31410880Sshannon * and file 3, and an artificial dummy difference (trange) 31510880Sshannon * must be ginned up to correspond to the change reported 31610880Sshannon * in the other file 31710880Sshannon */ 31810880Sshannon keep(i,rold,rnew) 31910880Sshannon struct range *rold, *rnew; 32010880Sshannon { 32110880Sshannon register delta; 32210880Sshannon struct range trange; 32310880Sshannon delta = last[3] - last[i]; 32410880Sshannon trange.from = rnew->from - delta; 32510880Sshannon trange.to = rnew->to - delta; 32610880Sshannon change(i,&trange,1); 32710880Sshannon } 32810880Sshannon 32910880Sshannon /* skip to just befor line number from in file i 33010880Sshannon * if "pr" is nonzero, print all skipped stuff 33110880Sshannon * w with string pr as a prefix 33210880Sshannon */ 33310880Sshannon skip(i,from,pr) 33410880Sshannon char *pr; 33510880Sshannon { 33610880Sshannon register j,n; 33710880Sshannon for(n=0;cline[i]<from-1;n+=j) { 33810880Sshannon if((j=getline(fp[i]))==0) 33910880Sshannon trouble(); 34010880Sshannon if(pr) 34110880Sshannon printf("%s%s",pr,line); 34210880Sshannon cline[i]++; 34310880Sshannon } 34410880Sshannon return(n); 34510880Sshannon } 34610880Sshannon 34710880Sshannon /* return 1 or 0 according as the old range 34810880Sshannon * (in file 1) contains exactly the same data 34910880Sshannon * as the new range (in file 2) 35010880Sshannon */ 35110880Sshannon duplicate(r1,r2) 35210880Sshannon struct range *r1, *r2; 35310880Sshannon { 35410880Sshannon register c,d; 35510880Sshannon register nchar; 35610880Sshannon int nline; 35710880Sshannon if(r1->to-r1->from != r2->to-r2->from) 35810880Sshannon return(0); 35910880Sshannon skip(0,r1->from,(char *)0); 36010880Sshannon skip(1,r2->from,(char *)0); 36110880Sshannon nchar = 0; 36210880Sshannon for(nline=0;nline<r1->to-r1->from;nline++) { 36310880Sshannon do { 36410880Sshannon c = getc(fp[0]); 36510880Sshannon d = getc(fp[1]); 36610880Sshannon if(c== -1||d== -1) 36710880Sshannon trouble(); 36810880Sshannon nchar++; 36910880Sshannon if(c!=d) { 37010880Sshannon repos(nchar); 37110880Sshannon return; 37210880Sshannon } 37310880Sshannon } while(c!= '\n'); 37410880Sshannon } 37510880Sshannon repos(nchar); 37610880Sshannon return(1); 37710880Sshannon } 37810880Sshannon 37910880Sshannon repos(nchar) 38010880Sshannon { 38110880Sshannon register i; 38210880Sshannon for(i=0;i<2;i++) 38310880Sshannon fseek(fp[i], (long)-nchar, 1); 38410880Sshannon } 38510880Sshannon 38610880Sshannon trouble() 38710880Sshannon { 38810880Sshannon fprintf(stderr,"diff3: logic error\n"); 38910880Sshannon abort(); 39010880Sshannon } 39110880Sshannon 39210880Sshannon /* collect an editing script for later regurgitation 39310880Sshannon */ 39410880Sshannon edit(diff,dup,j) 39510880Sshannon struct diff *diff; 39610880Sshannon { 39710880Sshannon if(((dup+1)&eflag)==0) 39810880Sshannon return(j); 39910880Sshannon j++; 40010880Sshannon de[j].old.from = diff->old.from; 40110880Sshannon de[j].old.to = diff->old.to; 40210880Sshannon de[j].new.from = de[j-1].new.to 40310880Sshannon +skip(2,diff->new.from,(char *)0); 40410880Sshannon de[j].new.to = de[j].new.from 40510880Sshannon +skip(2,diff->new.to,(char *)0); 40610880Sshannon return(j); 40710880Sshannon } 40810880Sshannon 40910880Sshannon /* regurgitate */ 41010880Sshannon edscript(n) 41110880Sshannon { 41210880Sshannon register j,k; 41310880Sshannon char block[BUFSIZ]; 41410880Sshannon for(n=n;n>0;n--) { 41510880Sshannon prange(&de[n].old); 41610880Sshannon fseek(fp[2], (long)de[n].new.from, 0); 41710880Sshannon for(k=de[n].new.to-de[n].new.from;k>0;k-= j) { 41810880Sshannon j = k>BUFSIZ?BUFSIZ:k; 41910880Sshannon if(fread(block,1,j,fp[2])!=j) 42010880Sshannon trouble(); 42110880Sshannon fwrite(block, 1, j, stdout); 42210880Sshannon } 42310880Sshannon printf(".\n"); 42410880Sshannon } 42510880Sshannon } 426