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