1*48249Sbostic /*- 2*48249Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*48249Sbostic * All rights reserved. 4*48249Sbostic * 5*48249Sbostic * %sccs.include.proprietary.c% 6*48249Sbostic */ 7*48249Sbostic 814484Ssam #ifndef lint 9*48249Sbostic char copyright[] = 10*48249Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11*48249Sbostic All rights reserved.\n"; 12*48249Sbostic #endif /* not lint */ 1310880Sshannon 14*48249Sbostic #ifndef lint 15*48249Sbostic static char sccsid[] = "@(#)diff3.c 4.5 (Berkeley) 04/17/91"; 16*48249Sbostic #endif /* not lint */ 17*48249Sbostic 1810880Sshannon #include <stdio.h> 1910880Sshannon 2010880Sshannon /* diff3 - 3-way differential file comparison*/ 2110880Sshannon 2224331Svan /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] 2310880Sshannon * 2410880Sshannon * d13 = diff report on f1 vs f3 2510880Sshannon * d23 = diff report on f2 vs f3 2610880Sshannon * f1, f2, f3 the 3 files 2724331Svan * if changes in f1 overlap with changes in f3, m1 and m3 are used 2824331Svan * to mark the overlaps; otherwise, the file names f1 and f3 are used 2924331Svan * (only for options E and X). 3010880Sshannon */ 3110880Sshannon 3210880Sshannon struct range {int from,to; }; 3310880Sshannon /* from is first in range of changed lines 3410880Sshannon * to is last+1 3510880Sshannon * from=to=line after point of insertion 3610880Sshannon * for added lines 3710880Sshannon */ 3810880Sshannon struct diff {struct range old, new;}; 3910880Sshannon 4010880Sshannon #define NC 200 4124331Svan struct diff d13[NC]; 4224331Svan struct diff d23[NC]; 4310880Sshannon /* de is used to gather editing scripts, 4410880Sshannon * that are later spewed out in reverse order. 4510880Sshannon * its first element must be all zero 4610880Sshannon * the "new" component of de contains line positions 4710880Sshannon * or byte positions depending on when you look(!?) 4824331Svan * array overlap indicates which sections in de correspond to 4924331Svan * lines that are different in all three files. 5010880Sshannon */ 5110880Sshannon struct diff de[NC]; 5224331Svan char overlap[NC]; 5324331Svan int overlapcnt =0; 5424331Svan 5510880Sshannon char line[256]; 5610880Sshannon FILE *fp[3]; 5710880Sshannon /* the number of the last-read line in each file 5810880Sshannon * is kept in cline[0-2] 5910880Sshannon */ 6010880Sshannon int cline[3]; 6110880Sshannon /* the latest known correspondence between line 6210880Sshannon * numbers of the 3 files is stored in last[1-3] 6310880Sshannon */ 6410880Sshannon int last[4]; 6510880Sshannon int eflag; 6624331Svan int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 6710880Sshannon int debug = 0; 6824331Svan char f1mark[40], f3mark[40]; /*markers for -E and -X*/ 6910880Sshannon 7024331Svan 7110880Sshannon main(argc,argv) 7210880Sshannon char **argv; 7310880Sshannon { 7410880Sshannon register i,m,n; 7524331Svan eflag=0; oflag=0; 7610880Sshannon if(*argv[1]=='-') { 7710880Sshannon switch(argv[1][1]) { 7810880Sshannon default: 7910880Sshannon eflag = 3; 8010880Sshannon break; 8110880Sshannon case '3': 8210880Sshannon eflag = 2; 8310880Sshannon break; 8410880Sshannon case 'x': 8510880Sshannon eflag = 1; 8624331Svan break; 8724331Svan case 'E': 8824331Svan eflag = 3; 8924331Svan oflag = 1; 9024331Svan break; 9124331Svan case 'X': 9224331Svan oflag = eflag = 1; 9324331Svan break; 9410880Sshannon } 9510880Sshannon argv++; 9610880Sshannon argc--; 9710880Sshannon } 9810880Sshannon if(argc<6) { 9910880Sshannon fprintf(stderr,"diff3: arg count\n"); 10010880Sshannon exit(1); 10110880Sshannon } 10224331Svan if (oflag) { 10324444Svan (void)sprintf(f1mark,"<<<<<<< %s",argc>=7?argv[6]:argv[3]); 10424444Svan (void)sprintf(f3mark,">>>>>>> %s",argc>=8?argv[7]:argv[5]); 10524331Svan } 10624331Svan 10710880Sshannon m = readin(argv[1],d13); 10810880Sshannon n = readin(argv[2],d23); 10910880Sshannon for(i=0;i<=2;i++) 11010880Sshannon if((fp[i] = fopen(argv[i+3],"r")) == NULL) { 11110880Sshannon printf("diff3: can't open %s\n",argv[i+3]); 11210880Sshannon exit(1); 11310880Sshannon } 11410880Sshannon merge(m,n); 11510880Sshannon } 11610880Sshannon 11710880Sshannon /*pick up the line numbers of allcahnges from 11810880Sshannon * one change file 11910880Sshannon * (this puts the numbers in a vector, which is not 12010880Sshannon * strictly necessary, since the vector is processed 12110880Sshannon * in one sequential pass. The vector could be optimized 12210880Sshannon * out of existence) 12310880Sshannon */ 12410880Sshannon 12510880Sshannon readin(name,dd) 12610880Sshannon char *name; 12710880Sshannon struct diff *dd; 12810880Sshannon { 12910880Sshannon register i; 13010880Sshannon int a,b,c,d; 13110880Sshannon char kind; 13210880Sshannon char *p; 13310880Sshannon fp[0] = fopen(name,"r"); 13410880Sshannon for(i=0;getchange(fp[0]);i++) { 13510880Sshannon if(i>=NC) { 13610880Sshannon fprintf(stderr,"diff3: too many changes\n"); 13710880Sshannon exit(0); 13810880Sshannon } 13910880Sshannon p = line; 14010880Sshannon a = b = number(&p); 14110880Sshannon if(*p==',') { 14210880Sshannon p++; 14310880Sshannon b = number(&p); 14410880Sshannon } 14510880Sshannon kind = *p++; 14610880Sshannon c = d = number(&p); 14710880Sshannon if(*p==',') { 14810880Sshannon p++; 14910880Sshannon d = number(&p); 15010880Sshannon } 15110880Sshannon if(kind=='a') 15210880Sshannon a++; 15310880Sshannon if(kind=='d') 15410880Sshannon c++; 15510880Sshannon b++; 15610880Sshannon d++; 15710880Sshannon dd[i].old.from = a; 15810880Sshannon dd[i].old.to = b; 15910880Sshannon dd[i].new.from = c; 16010880Sshannon dd[i].new.to = d; 16110880Sshannon } 16210880Sshannon dd[i].old.from = dd[i-1].old.to; 16310880Sshannon dd[i].new.from = dd[i-1].new.to; 16424444Svan (void)fclose(fp[0]); 16510880Sshannon return(i); 16610880Sshannon } 16710880Sshannon 16810880Sshannon number(lc) 16910880Sshannon char **lc; 17010880Sshannon { 17110880Sshannon register nn; 17210880Sshannon nn = 0; 17310880Sshannon while(digit(**lc)) 17410880Sshannon nn = nn*10 + *(*lc)++ - '0'; 17510880Sshannon return(nn); 17610880Sshannon } 17710880Sshannon 17810880Sshannon digit(c) 17910880Sshannon { 18010880Sshannon return(c>='0'&&c<='9'); 18110880Sshannon } 18210880Sshannon 18310880Sshannon getchange(b) 18410880Sshannon FILE *b; 18510880Sshannon { 18610880Sshannon while(getline(b)) 18710880Sshannon if(digit(line[0])) 18810880Sshannon return(1); 18910880Sshannon return(0); 19010880Sshannon } 19110880Sshannon 19210880Sshannon getline(b) 19310880Sshannon FILE *b; 19410880Sshannon { 19510880Sshannon register i, c; 19610880Sshannon for(i=0;i<sizeof(line)-1;i++) { 19710880Sshannon c = getc(b); 19810880Sshannon if(c==EOF) 19910880Sshannon break; 20010880Sshannon line[i] = c; 20110880Sshannon if(c=='\n') { 20210880Sshannon line[++i] = 0; 20310880Sshannon return(i); 20410880Sshannon } 20510880Sshannon } 20610880Sshannon return(0); 20710880Sshannon } 20810880Sshannon 20910880Sshannon merge(m1,m2) 21010880Sshannon { 21110880Sshannon register struct diff *d1, *d2, *d3; 21210880Sshannon int dup; 21310880Sshannon int j; 21410880Sshannon int t1,t2; 21510880Sshannon d1 = d13; 21610880Sshannon d2 = d23; 21710880Sshannon j = 0; 21810880Sshannon for(;(t1 = d1<d13+m1) | (t2 = d2<d23+m2);) { 21910880Sshannon if(debug) { 22010880Sshannon printf("%d,%d=%d,%d %d,%d=%d,%d\n", 22110880Sshannon d1->old.from,d1->old.to, 22210880Sshannon d1->new.from,d1->new.to, 22310880Sshannon d2->old.from,d2->old.to, 22410880Sshannon d2->new.from,d2->new.to); 22510880Sshannon } 22610880Sshannon /* first file is different from others*/ 22710880Sshannon if(!t2||t1&&d1->new.to < d2->new.from) { 22810880Sshannon /* stuff peculiar to 1st file */ 22910880Sshannon if(eflag==0) { 23010880Sshannon separate("1"); 23110880Sshannon change(1,&d1->old,0); 23224444Svan keep(2,&d1->new); 23310880Sshannon change(3,&d1->new,0); 23410880Sshannon } 23510880Sshannon d1++; 23610880Sshannon continue; 23710880Sshannon } 23810880Sshannon /* second file is different from others*/ 23910880Sshannon if(!t1||t2&&d2->new.to < d1->new.from) { 24010880Sshannon if(eflag==0) { 24110880Sshannon separate("2"); 24224444Svan keep(1,&d2->new); 24310880Sshannon change(2,&d2->old,0); 24410880Sshannon change(3,&d2->new,0); 24510880Sshannon } 24610880Sshannon d2++; 24710880Sshannon continue; 24810880Sshannon } 24910880Sshannon /* merge overlapping changes in first file 25010880Sshannon * this happens after extension see below*/ 25110880Sshannon if(d1+1<d13+m1 && 25210880Sshannon d1->new.to>=d1[1].new.from) { 25310880Sshannon d1[1].old.from = d1->old.from; 25410880Sshannon d1[1].new.from = d1->new.from; 25510880Sshannon d1++; 25610880Sshannon continue; 25710880Sshannon } 25810880Sshannon /* merge overlapping changes in second*/ 25910880Sshannon if(d2+1<d23+m2 && 26010880Sshannon d2->new.to>=d2[1].new.from) { 26110880Sshannon d2[1].old.from = d2->old.from; 26210880Sshannon d2[1].new.from = d2->new.from; 26310880Sshannon d2++; 26410880Sshannon continue; 26510880Sshannon } 26610880Sshannon /* stuff peculiar to third file or different in all*/ 26710880Sshannon if(d1->new.from==d2->new.from&& 26810880Sshannon d1->new.to==d2->new.to) { 26910880Sshannon dup = duplicate(&d1->old,&d2->old); 27010880Sshannon /* dup=0 means all files differ 27110880Sshannon * dup =1 meands files 1&2 identical*/ 27210880Sshannon if(eflag==0) { 27310880Sshannon separate(dup?"3":""); 27410880Sshannon change(1,&d1->old,dup); 27510880Sshannon change(2,&d2->old,0); 27610880Sshannon d3 = d1->old.to>d1->old.from?d1:d2; 27710880Sshannon change(3,&d3->new,0); 27810880Sshannon } else 27910880Sshannon j = edit(d1,dup,j); 28010880Sshannon d1++; 28110880Sshannon d2++; 28210880Sshannon continue; 28310880Sshannon } 28410880Sshannon /* overlapping changes from file1 & 2 28510880Sshannon * extend changes appropriately to 28610880Sshannon * make them coincide*/ 28710880Sshannon if(d1->new.from<d2->new.from) { 28810880Sshannon d2->old.from -= d2->new.from-d1->new.from; 28910880Sshannon d2->new.from = d1->new.from; 29010880Sshannon } 29110880Sshannon else if(d2->new.from<d1->new.from) { 29210880Sshannon d1->old.from -= d1->new.from-d2->new.from; 29310880Sshannon d1->new.from = d2->new.from; 29410880Sshannon } 29510880Sshannon if(d1->new.to >d2->new.to) { 29610880Sshannon d2->old.to += d1->new.to - d2->new.to; 29710880Sshannon d2->new.to = d1->new.to; 29810880Sshannon } 29910880Sshannon else if(d2->new.to >d1->new.to) { 30010880Sshannon d1->old.to += d2->new.to - d1->new.to; 30110880Sshannon d1->new.to = d2->new.to; 30210880Sshannon } 30310880Sshannon } 30410880Sshannon if(eflag) 30510880Sshannon edscript(j); 30610880Sshannon } 30710880Sshannon 30810880Sshannon separate(s) 30910880Sshannon char *s; 31010880Sshannon { 31110880Sshannon printf("====%s\n",s); 31210880Sshannon } 31310880Sshannon 31410880Sshannon /* the range of ines rold.from thru rold.to in file i 31510880Sshannon * is to be changed. it is to be printed only if 31610880Sshannon * it does not duplicate something to be printed later 31710880Sshannon */ 31810880Sshannon change(i,rold,dup) 31910880Sshannon struct range *rold; 32010880Sshannon { 32110880Sshannon printf("%d:",i); 32210880Sshannon last[i] = rold->to; 32310880Sshannon prange(rold); 32410880Sshannon if(dup) 32510880Sshannon return; 32610880Sshannon if(debug) 32710880Sshannon return; 32810880Sshannon i--; 32924444Svan (void)skip(i,rold->from,(char *)0); 33024444Svan (void)skip(i,rold->to," "); 33110880Sshannon } 33210880Sshannon 33310880Sshannon /* print the range of line numbers, rold.from thru rold.to 33410880Sshannon * as n1,n2 or n1 33510880Sshannon */ 33610880Sshannon prange(rold) 33710880Sshannon struct range *rold; 33810880Sshannon { 33910880Sshannon if(rold->to<=rold->from) 34010880Sshannon printf("%da\n",rold->from-1); 34110880Sshannon else { 34210880Sshannon printf("%d",rold->from); 34310880Sshannon if(rold->to > rold->from+1) 34410880Sshannon printf(",%d",rold->to-1); 34510880Sshannon printf("c\n"); 34610880Sshannon } 34710880Sshannon } 34810880Sshannon 34910880Sshannon /* no difference was reported by diff between file 1(or 2) 35010880Sshannon * and file 3, and an artificial dummy difference (trange) 35110880Sshannon * must be ginned up to correspond to the change reported 35210880Sshannon * in the other file 35310880Sshannon */ 35424444Svan keep(i,rnew) 35524444Svan struct range *rnew; 35610880Sshannon { 35710880Sshannon register delta; 35810880Sshannon struct range trange; 35910880Sshannon delta = last[3] - last[i]; 36010880Sshannon trange.from = rnew->from - delta; 36110880Sshannon trange.to = rnew->to - delta; 36210880Sshannon change(i,&trange,1); 36310880Sshannon } 36410880Sshannon 36510880Sshannon /* skip to just befor line number from in file i 36610880Sshannon * if "pr" is nonzero, print all skipped stuff 36710880Sshannon * w with string pr as a prefix 36810880Sshannon */ 36910880Sshannon skip(i,from,pr) 37010880Sshannon char *pr; 37110880Sshannon { 37210880Sshannon register j,n; 37310880Sshannon for(n=0;cline[i]<from-1;n+=j) { 37410880Sshannon if((j=getline(fp[i]))==0) 37510880Sshannon trouble(); 37610880Sshannon if(pr) 37710880Sshannon printf("%s%s",pr,line); 37810880Sshannon cline[i]++; 37910880Sshannon } 38010880Sshannon return(n); 38110880Sshannon } 38210880Sshannon 38310880Sshannon /* return 1 or 0 according as the old range 38410880Sshannon * (in file 1) contains exactly the same data 38510880Sshannon * as the new range (in file 2) 38610880Sshannon */ 38710880Sshannon duplicate(r1,r2) 38810880Sshannon struct range *r1, *r2; 38910880Sshannon { 39010880Sshannon register c,d; 39110880Sshannon register nchar; 39210880Sshannon int nline; 39310880Sshannon if(r1->to-r1->from != r2->to-r2->from) 39410880Sshannon return(0); 39524444Svan (void)skip(0,r1->from,(char *)0); 39624444Svan (void)skip(1,r2->from,(char *)0); 39710880Sshannon nchar = 0; 39810880Sshannon for(nline=0;nline<r1->to-r1->from;nline++) { 39910880Sshannon do { 40010880Sshannon c = getc(fp[0]); 40110880Sshannon d = getc(fp[1]); 40210880Sshannon if(c== -1||d== -1) 40310880Sshannon trouble(); 40410880Sshannon nchar++; 40510880Sshannon if(c!=d) { 40610880Sshannon repos(nchar); 40724444Svan return(0); 40810880Sshannon } 40910880Sshannon } while(c!= '\n'); 41010880Sshannon } 41110880Sshannon repos(nchar); 41210880Sshannon return(1); 41310880Sshannon } 41410880Sshannon 41510880Sshannon repos(nchar) 41610880Sshannon { 41710880Sshannon register i; 41810880Sshannon for(i=0;i<2;i++) 41924444Svan (void)fseek(fp[i], (long)-nchar, 1); 42010880Sshannon } 42110880Sshannon 42210880Sshannon trouble() 42310880Sshannon { 42410880Sshannon fprintf(stderr,"diff3: logic error\n"); 42510880Sshannon abort(); 42610880Sshannon } 42710880Sshannon 42810880Sshannon /* collect an editing script for later regurgitation 42910880Sshannon */ 43010880Sshannon edit(diff,dup,j) 43110880Sshannon struct diff *diff; 43210880Sshannon { 43310880Sshannon if(((dup+1)&eflag)==0) 43410880Sshannon return(j); 43510880Sshannon j++; 43624331Svan overlap[j] = !dup; 43724331Svan if (!dup) overlapcnt++; 43810880Sshannon de[j].old.from = diff->old.from; 43910880Sshannon de[j].old.to = diff->old.to; 44010880Sshannon de[j].new.from = de[j-1].new.to 44110880Sshannon +skip(2,diff->new.from,(char *)0); 44210880Sshannon de[j].new.to = de[j].new.from 44310880Sshannon +skip(2,diff->new.to,(char *)0); 44410880Sshannon return(j); 44510880Sshannon } 44610880Sshannon 44710880Sshannon /* regurgitate */ 44810880Sshannon edscript(n) 44910880Sshannon { 45010880Sshannon register j,k; 45110880Sshannon char block[BUFSIZ]; 45210880Sshannon for(n=n;n>0;n--) { 45324331Svan if (!oflag || !overlap[n]) 45424331Svan prange(&de[n].old); 45524331Svan else 45624331Svan printf("%da\n=======\n", de[n].old.to -1); 45724444Svan (void)fseek(fp[2], (long)de[n].new.from, 0); 45810880Sshannon for(k=de[n].new.to-de[n].new.from;k>0;k-= j) { 45910880Sshannon j = k>BUFSIZ?BUFSIZ:k; 46010880Sshannon if(fread(block,1,j,fp[2])!=j) 46110880Sshannon trouble(); 46224444Svan (void)fwrite(block, 1, j, stdout); 46310880Sshannon } 46424331Svan if (!oflag || !overlap[n]) 46524331Svan printf(".\n"); 46624331Svan else { 46724331Svan printf("%s\n.\n",f3mark); 46824331Svan printf("%da\n%s\n.\n",de[n].old.from-1,f1mark); 46924331Svan } 47010880Sshannon } 47124331Svan exit(overlapcnt); 47210880Sshannon } 473