1 #ifndef lint 2 static char sccsid[] = "@(#)diff3.c 4.4 (Berkeley) 08/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 } 460