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