|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.