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