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