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