1*d407ca27Smillert /* $OpenBSD: diff3prog.c,v 1.1 2003/07/10 16:06:07 millert Exp $ */ 2*d407ca27Smillert 3*d407ca27Smillert /* 4*d407ca27Smillert * Copyright (C) Caldera International Inc. 2001-2002. 5*d407ca27Smillert * All rights reserved. 6*d407ca27Smillert * 7*d407ca27Smillert * Redistribution and use in source and binary forms, with or without 8*d407ca27Smillert * modification, are permitted provided that the following conditions 9*d407ca27Smillert * are met: 10*d407ca27Smillert * 1. Redistributions of source code and documentation must retain the above 11*d407ca27Smillert * copyright notice, this list of conditions and the following disclaimer. 12*d407ca27Smillert * 2. Redistributions in binary form must reproduce the above copyright 13*d407ca27Smillert * notice, this list of conditions and the following disclaimer in the 14*d407ca27Smillert * documentation and/or other materials provided with the distribution. 15*d407ca27Smillert * 3. All advertising materials mentioning features or use of this software 16*d407ca27Smillert * must display the following acknowledgement: 17*d407ca27Smillert * This product includes software developed or owned by Caldera 18*d407ca27Smillert * International, Inc. 19*d407ca27Smillert * 4. Neither the name of Caldera International, Inc. nor the names of other 20*d407ca27Smillert * contributors may be used to endorse or promote products derived from 21*d407ca27Smillert * this software without specific prior written permission. 22*d407ca27Smillert * 23*d407ca27Smillert * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24*d407ca27Smillert * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25*d407ca27Smillert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26*d407ca27Smillert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27*d407ca27Smillert * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28*d407ca27Smillert * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29*d407ca27Smillert * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30*d407ca27Smillert * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*d407ca27Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32*d407ca27Smillert * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33*d407ca27Smillert * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34*d407ca27Smillert * POSSIBILITY OF SUCH DAMAGE. 35*d407ca27Smillert */ 36*d407ca27Smillert /*- 37*d407ca27Smillert * Copyright (c) 1991, 1993 38*d407ca27Smillert * The Regents of the University of California. All rights reserved. 39*d407ca27Smillert * 40*d407ca27Smillert * Redistribution and use in source and binary forms, with or without 41*d407ca27Smillert * modification, are permitted provided that the following conditions 42*d407ca27Smillert * are met: 43*d407ca27Smillert * 1. Redistributions of source code must retain the above copyright 44*d407ca27Smillert * notice, this list of conditions and the following disclaimer. 45*d407ca27Smillert * 2. Redistributions in binary form must reproduce the above copyright 46*d407ca27Smillert * notice, this list of conditions and the following disclaimer in the 47*d407ca27Smillert * documentation and/or other materials provided with the distribution. 48*d407ca27Smillert * 3. Neither the name of the University nor the names of its contributors 49*d407ca27Smillert * may be used to endorse or promote products derived from this software 50*d407ca27Smillert * without specific prior written permission. 51*d407ca27Smillert * 52*d407ca27Smillert * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53*d407ca27Smillert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54*d407ca27Smillert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55*d407ca27Smillert * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56*d407ca27Smillert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57*d407ca27Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58*d407ca27Smillert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59*d407ca27Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60*d407ca27Smillert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61*d407ca27Smillert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62*d407ca27Smillert * SUCH DAMAGE. 63*d407ca27Smillert * 64*d407ca27Smillert * @(#)diff3.c 8.1 (Berkeley) 6/6/93 65*d407ca27Smillert */ 66*d407ca27Smillert 67*d407ca27Smillert #ifndef lint 68*d407ca27Smillert static const char copyright[] = 69*d407ca27Smillert "@(#) Copyright (c) 1991, 1993\n\ 70*d407ca27Smillert The Regents of the University of California. All rights reserved.\n"; 71*d407ca27Smillert #endif /* not lint */ 72*d407ca27Smillert 73*d407ca27Smillert #ifndef lint 74*d407ca27Smillert static const char rcsid[] = "$OpenBSD: diff3prog.c,v 1.1 2003/07/10 16:06:07 millert Exp $"; 75*d407ca27Smillert #endif /* not lint */ 76*d407ca27Smillert 77*d407ca27Smillert #include <stdio.h> 78*d407ca27Smillert #include <stdlib.h> 79*d407ca27Smillert #include <ctype.h> 80*d407ca27Smillert #include <err.h> 81*d407ca27Smillert 82*d407ca27Smillert /* diff3 - 3-way differential file comparison */ 83*d407ca27Smillert 84*d407ca27Smillert /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] 85*d407ca27Smillert * 86*d407ca27Smillert * d13 = diff report on f1 vs f3 87*d407ca27Smillert * d23 = diff report on f2 vs f3 88*d407ca27Smillert * f1, f2, f3 the 3 files 89*d407ca27Smillert * if changes in f1 overlap with changes in f3, m1 and m3 are used 90*d407ca27Smillert * to mark the overlaps; otherwise, the file names f1 and f3 are used 91*d407ca27Smillert * (only for options E and X). 92*d407ca27Smillert */ 93*d407ca27Smillert 94*d407ca27Smillert /* 95*d407ca27Smillert * "from" is first in range of changed lines; "to" is last+1 96*d407ca27Smillert * from=to=line after point of insertion for added lines. 97*d407ca27Smillert */ 98*d407ca27Smillert struct range { 99*d407ca27Smillert int from; 100*d407ca27Smillert int to; 101*d407ca27Smillert }; 102*d407ca27Smillert struct diff { 103*d407ca27Smillert struct range old; 104*d407ca27Smillert struct range new; 105*d407ca27Smillert }; 106*d407ca27Smillert 107*d407ca27Smillert #define NC 200 108*d407ca27Smillert struct diff d13[NC]; 109*d407ca27Smillert struct diff d23[NC]; 110*d407ca27Smillert /* 111*d407ca27Smillert * "de" is used to gather editing scripts. These are later spewed out in 112*d407ca27Smillert * reverse order. Its first element must be all zero, the "new" component 113*d407ca27Smillert * of "de" contains line positions or byte positions depending on when you 114*d407ca27Smillert * look (!?). Array overlap indicates which sections in "de" correspond to 115*d407ca27Smillert * lines that are different in all three files. 116*d407ca27Smillert */ 117*d407ca27Smillert struct diff de[NC]; 118*d407ca27Smillert char overlap[NC]; 119*d407ca27Smillert int overlapcnt; 120*d407ca27Smillert char line[256]; 121*d407ca27Smillert FILE *fp[3]; 122*d407ca27Smillert int cline[3]; /* # of the last-read line in each file (0-2) */ 123*d407ca27Smillert /* 124*d407ca27Smillert * the latest known correspondence between line numbers of the 3 files 125*d407ca27Smillert * is stored in last[1-3]; 126*d407ca27Smillert */ 127*d407ca27Smillert int last[4]; 128*d407ca27Smillert int eflag; 129*d407ca27Smillert int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 130*d407ca27Smillert int debug = 0; 131*d407ca27Smillert char f1mark[40], f3mark[40]; /* markers for -E and -X */ 132*d407ca27Smillert 133*d407ca27Smillert int duplicate(struct range *, struct range *); 134*d407ca27Smillert int edit(struct diff *, int, int); 135*d407ca27Smillert int getchange(FILE *); 136*d407ca27Smillert int getline(FILE *); 137*d407ca27Smillert int number(char **); 138*d407ca27Smillert int readin(char *, struct diff *); 139*d407ca27Smillert int skip(int, int, char *); 140*d407ca27Smillert void change(int, struct range *, int); 141*d407ca27Smillert void keep(int, struct range *); 142*d407ca27Smillert void merge(int, int); 143*d407ca27Smillert void prange(struct range *); 144*d407ca27Smillert void repos(int); 145*d407ca27Smillert void separate(const char *); 146*d407ca27Smillert __dead void edscript(int); 147*d407ca27Smillert __dead void trouble(void); 148*d407ca27Smillert __dead void usage(void); 149*d407ca27Smillert 150*d407ca27Smillert int 151*d407ca27Smillert main(int argc, char **argv) 152*d407ca27Smillert { 153*d407ca27Smillert int ch, i, m, n; 154*d407ca27Smillert 155*d407ca27Smillert eflag = 0; 156*d407ca27Smillert oflag = 0; 157*d407ca27Smillert while ((ch = getopt(argc, argv, "EeXx3")) != -1) { 158*d407ca27Smillert switch (ch) { 159*d407ca27Smillert case 'E': 160*d407ca27Smillert eflag = 3; 161*d407ca27Smillert oflag = 1; 162*d407ca27Smillert break; 163*d407ca27Smillert case 'e': 164*d407ca27Smillert eflag = 3; 165*d407ca27Smillert break; 166*d407ca27Smillert case 'X': 167*d407ca27Smillert oflag = eflag = 1; 168*d407ca27Smillert break; 169*d407ca27Smillert case 'x': 170*d407ca27Smillert eflag = 1; 171*d407ca27Smillert break; 172*d407ca27Smillert case '3': 173*d407ca27Smillert eflag = 2; 174*d407ca27Smillert break; 175*d407ca27Smillert } 176*d407ca27Smillert } 177*d407ca27Smillert argc -= optind; 178*d407ca27Smillert argv += optind; 179*d407ca27Smillert /* XXX - argc usage seems wrong here */ 180*d407ca27Smillert if (argc < 5) 181*d407ca27Smillert usage(); 182*d407ca27Smillert 183*d407ca27Smillert if (oflag) { 184*d407ca27Smillert (void)snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", 185*d407ca27Smillert argc >= 6 ? argv[5] : argv[2]); 186*d407ca27Smillert (void)snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", 187*d407ca27Smillert argc >= 7 ? argv[6] : argv[4]); 188*d407ca27Smillert } 189*d407ca27Smillert 190*d407ca27Smillert m = readin(argv[0], d13); 191*d407ca27Smillert n = readin(argv[1], d23); 192*d407ca27Smillert for (i = 0; i <= 2; i++) { 193*d407ca27Smillert if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) { 194*d407ca27Smillert printf("diff3: can't open %s\n", argv[i + 2]); 195*d407ca27Smillert exit(EXIT_FAILURE); 196*d407ca27Smillert } 197*d407ca27Smillert } 198*d407ca27Smillert merge(m, n); 199*d407ca27Smillert exit(EXIT_SUCCESS); 200*d407ca27Smillert } 201*d407ca27Smillert 202*d407ca27Smillert /* 203*d407ca27Smillert * Pick up the line numbers of allcahnges from one change file. 204*d407ca27Smillert * (This puts the numbers in a vector, which is not strictly necessary, 205*d407ca27Smillert * since the vector is processed in one sequential pass. 206*d407ca27Smillert * The vector could be optimized out of existence) 207*d407ca27Smillert */ 208*d407ca27Smillert int 209*d407ca27Smillert readin(char *name, struct diff *dd) 210*d407ca27Smillert { 211*d407ca27Smillert int i; 212*d407ca27Smillert int a,b,c,d; 213*d407ca27Smillert char kind; 214*d407ca27Smillert char *p; 215*d407ca27Smillert fp[0] = fopen(name, "r"); 216*d407ca27Smillert for (i=0; getchange(fp[0]); i++) { 217*d407ca27Smillert if (i >= NC) 218*d407ca27Smillert err(EXIT_FAILURE, "too many changes"); 219*d407ca27Smillert p = line; 220*d407ca27Smillert a = b = number(&p); 221*d407ca27Smillert if (*p == ',') { 222*d407ca27Smillert p++; 223*d407ca27Smillert b = number(&p); 224*d407ca27Smillert } 225*d407ca27Smillert kind = *p++; 226*d407ca27Smillert c = d = number(&p); 227*d407ca27Smillert if (*p==',') { 228*d407ca27Smillert p++; 229*d407ca27Smillert d = number(&p); 230*d407ca27Smillert } 231*d407ca27Smillert if (kind == 'a') 232*d407ca27Smillert a++; 233*d407ca27Smillert if (kind == 'd') 234*d407ca27Smillert c++; 235*d407ca27Smillert b++; 236*d407ca27Smillert d++; 237*d407ca27Smillert dd[i].old.from = a; 238*d407ca27Smillert dd[i].old.to = b; 239*d407ca27Smillert dd[i].new.from = c; 240*d407ca27Smillert dd[i].new.to = d; 241*d407ca27Smillert } 242*d407ca27Smillert dd[i].old.from = dd[i-1].old.to; 243*d407ca27Smillert dd[i].new.from = dd[i-1].new.to; 244*d407ca27Smillert (void)fclose(fp[0]); 245*d407ca27Smillert return (i); 246*d407ca27Smillert } 247*d407ca27Smillert 248*d407ca27Smillert int 249*d407ca27Smillert number(char **lc) 250*d407ca27Smillert { 251*d407ca27Smillert int nn; 252*d407ca27Smillert nn = 0; 253*d407ca27Smillert while (isdigit((unsigned char)(**lc))) 254*d407ca27Smillert nn = nn*10 + *(*lc)++ - '0'; 255*d407ca27Smillert return (nn); 256*d407ca27Smillert } 257*d407ca27Smillert 258*d407ca27Smillert int 259*d407ca27Smillert getchange(FILE *b) 260*d407ca27Smillert { 261*d407ca27Smillert while (getline(b)) { 262*d407ca27Smillert if (isdigit((unsigned char)line[0])) 263*d407ca27Smillert return (1); 264*d407ca27Smillert } 265*d407ca27Smillert return (0); 266*d407ca27Smillert } 267*d407ca27Smillert 268*d407ca27Smillert int 269*d407ca27Smillert getline(FILE *b) 270*d407ca27Smillert { 271*d407ca27Smillert int i, c; 272*d407ca27Smillert 273*d407ca27Smillert for (i = 0; i < sizeof(line) - 1; i++) { 274*d407ca27Smillert c = getc(b); 275*d407ca27Smillert if (c == EOF) 276*d407ca27Smillert break; 277*d407ca27Smillert line[i] = c; 278*d407ca27Smillert if (c == '\n') { 279*d407ca27Smillert line[++i] = 0; 280*d407ca27Smillert return (i); 281*d407ca27Smillert } 282*d407ca27Smillert } 283*d407ca27Smillert return (0); 284*d407ca27Smillert } 285*d407ca27Smillert 286*d407ca27Smillert void 287*d407ca27Smillert merge(int m1, int m2) 288*d407ca27Smillert { 289*d407ca27Smillert struct diff *d1, *d2, *d3; 290*d407ca27Smillert int dup, j, t1, t2; 291*d407ca27Smillert 292*d407ca27Smillert d1 = d13; 293*d407ca27Smillert d2 = d23; 294*d407ca27Smillert j = 0; 295*d407ca27Smillert while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 296*d407ca27Smillert if (debug) { 297*d407ca27Smillert printf("%d,%d=%d,%d %d,%d=%d,%d\n", 298*d407ca27Smillert d1->old.from,d1->old.to, 299*d407ca27Smillert d1->new.from,d1->new.to, 300*d407ca27Smillert d2->old.from,d2->old.to, 301*d407ca27Smillert d2->new.from,d2->new.to); 302*d407ca27Smillert } 303*d407ca27Smillert /* first file is different from others */ 304*d407ca27Smillert if ((!t2 || t1) && d1->new.to < d2->new.from) { 305*d407ca27Smillert /* stuff peculiar to 1st file */ 306*d407ca27Smillert if (eflag==0) { 307*d407ca27Smillert separate("1"); 308*d407ca27Smillert change(1, &d1->old, 0); 309*d407ca27Smillert keep(2, &d1->new); 310*d407ca27Smillert change(3, &d1->new, 0); 311*d407ca27Smillert } 312*d407ca27Smillert d1++; 313*d407ca27Smillert continue; 314*d407ca27Smillert } 315*d407ca27Smillert /* second file is different from others */ 316*d407ca27Smillert if ((!t1 || t2) && d2->new.to < d1->new.from) { 317*d407ca27Smillert if (eflag==0) { 318*d407ca27Smillert separate("2"); 319*d407ca27Smillert keep(1, &d2->new); 320*d407ca27Smillert change(2, &d2->old, 0); 321*d407ca27Smillert change(3, &d2->new, 0); 322*d407ca27Smillert } 323*d407ca27Smillert d2++; 324*d407ca27Smillert continue; 325*d407ca27Smillert } 326*d407ca27Smillert /* 327*d407ca27Smillert * Merge overlapping changes in first file 328*d407ca27Smillert * this happens after extension (see below). 329*d407ca27Smillert */ 330*d407ca27Smillert if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 331*d407ca27Smillert d1[1].old.from = d1->old.from; 332*d407ca27Smillert d1[1].new.from = d1->new.from; 333*d407ca27Smillert d1++; 334*d407ca27Smillert continue; 335*d407ca27Smillert } 336*d407ca27Smillert 337*d407ca27Smillert /* merge overlapping changes in second */ 338*d407ca27Smillert if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 339*d407ca27Smillert d2[1].old.from = d2->old.from; 340*d407ca27Smillert d2[1].new.from = d2->new.from; 341*d407ca27Smillert d2++; 342*d407ca27Smillert continue; 343*d407ca27Smillert } 344*d407ca27Smillert /* stuff peculiar to third file or different in all */ 345*d407ca27Smillert if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 346*d407ca27Smillert dup = duplicate(&d1->old,&d2->old); 347*d407ca27Smillert /* 348*d407ca27Smillert * dup = 0 means all files differ 349*d407ca27Smillert * dup = 1 meands files 1 and 2 identical 350*d407ca27Smillert */ 351*d407ca27Smillert if (eflag==0) { 352*d407ca27Smillert separate(dup ? "3" : ""); 353*d407ca27Smillert change(1, &d1->old, dup); 354*d407ca27Smillert change(2, &d2->old, 0); 355*d407ca27Smillert d3 = d1->old.to > d1->old.from ? d1 : d2; 356*d407ca27Smillert change(3, &d3->new, 0); 357*d407ca27Smillert } else 358*d407ca27Smillert j = edit(d1, dup, j); 359*d407ca27Smillert d1++; 360*d407ca27Smillert d2++; 361*d407ca27Smillert continue; 362*d407ca27Smillert } 363*d407ca27Smillert /* 364*d407ca27Smillert * Overlapping changes from file 1 and 2; extend changes 365*d407ca27Smillert * appropriately to make them coincide. 366*d407ca27Smillert */ 367*d407ca27Smillert if (d1->new.from < d2->new.from) { 368*d407ca27Smillert d2->old.from -= d2->new.from-d1->new.from; 369*d407ca27Smillert d2->new.from = d1->new.from; 370*d407ca27Smillert } else if (d2->new.from < d1->new.from) { 371*d407ca27Smillert d1->old.from -= d1->new.from-d2->new.from; 372*d407ca27Smillert d1->new.from = d2->new.from; 373*d407ca27Smillert } 374*d407ca27Smillert if (d1->new.to > d2->new.to) { 375*d407ca27Smillert d2->old.to += d1->new.to - d2->new.to; 376*d407ca27Smillert d2->new.to = d1->new.to; 377*d407ca27Smillert } else if (d2->new.to > d1->new.to) { 378*d407ca27Smillert d1->old.to += d2->new.to - d1->new.to; 379*d407ca27Smillert d1->new.to = d2->new.to; 380*d407ca27Smillert } 381*d407ca27Smillert } 382*d407ca27Smillert if (eflag) 383*d407ca27Smillert edscript(j); 384*d407ca27Smillert } 385*d407ca27Smillert 386*d407ca27Smillert void 387*d407ca27Smillert separate(const char *s) 388*d407ca27Smillert { 389*d407ca27Smillert printf("====%s\n", s); 390*d407ca27Smillert } 391*d407ca27Smillert 392*d407ca27Smillert /* 393*d407ca27Smillert * The range of lines rold.from thru rold.to in file i is to be changed. 394*d407ca27Smillert * It is to be printed only if it does not duplicate something to be 395*d407ca27Smillert * printed later. 396*d407ca27Smillert */ 397*d407ca27Smillert void 398*d407ca27Smillert change(int i, struct range *rold, int dup) 399*d407ca27Smillert { 400*d407ca27Smillert printf("%d:", i); 401*d407ca27Smillert last[i] = rold->to; 402*d407ca27Smillert prange(rold); 403*d407ca27Smillert if (dup || debug) 404*d407ca27Smillert return; 405*d407ca27Smillert i--; 406*d407ca27Smillert (void)skip(i, rold->from, NULL); 407*d407ca27Smillert (void)skip(i, rold->to, " "); 408*d407ca27Smillert } 409*d407ca27Smillert 410*d407ca27Smillert /* 411*d407ca27Smillert * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 412*d407ca27Smillert */ 413*d407ca27Smillert void 414*d407ca27Smillert prange(struct range *rold) 415*d407ca27Smillert { 416*d407ca27Smillert if (rold->to <= rold->from) 417*d407ca27Smillert printf("%da\n", rold->from - 1); 418*d407ca27Smillert else { 419*d407ca27Smillert printf("%d", rold->from); 420*d407ca27Smillert if (rold->to > rold->from+1) 421*d407ca27Smillert printf(",%d", rold->to - 1); 422*d407ca27Smillert printf("c\n"); 423*d407ca27Smillert } 424*d407ca27Smillert } 425*d407ca27Smillert 426*d407ca27Smillert /* 427*d407ca27Smillert * No difference was reported by diff between file 1 (or 2) and file 3, 428*d407ca27Smillert * and an artificial dummy difference (trange) must be ginned up to 429*d407ca27Smillert * correspond to the change reported in the other file. 430*d407ca27Smillert */ 431*d407ca27Smillert void 432*d407ca27Smillert keep(int i, struct range *rnew) 433*d407ca27Smillert { 434*d407ca27Smillert int delta; 435*d407ca27Smillert struct range trange; 436*d407ca27Smillert 437*d407ca27Smillert delta = last[3] - last[i]; 438*d407ca27Smillert trange.from = rnew->from - delta; 439*d407ca27Smillert trange.to = rnew->to - delta; 440*d407ca27Smillert change(i, &trange, 1); 441*d407ca27Smillert } 442*d407ca27Smillert 443*d407ca27Smillert /* 444*d407ca27Smillert * skip to just befor line number from in file "i". If "pr" is non-NULL, 445*d407ca27Smillert * print all skipped stuff with string pr as a prefix. 446*d407ca27Smillert */ 447*d407ca27Smillert int 448*d407ca27Smillert skip(int i, int from, char *pr) 449*d407ca27Smillert { 450*d407ca27Smillert int j, n; 451*d407ca27Smillert 452*d407ca27Smillert for (n = 0; cline[i] < from - 1; n += j) { 453*d407ca27Smillert if ((j = getline(fp[i])) == NULL) 454*d407ca27Smillert trouble(); 455*d407ca27Smillert if (pr != NULL) 456*d407ca27Smillert printf("%s%s", pr, line); 457*d407ca27Smillert cline[i]++; 458*d407ca27Smillert } 459*d407ca27Smillert return (n); 460*d407ca27Smillert } 461*d407ca27Smillert 462*d407ca27Smillert /* 463*d407ca27Smillert * Return 1 or 0 according as the old range (in file 1) contains exactly 464*d407ca27Smillert * the same data as the new range (in file 2). 465*d407ca27Smillert */ 466*d407ca27Smillert int 467*d407ca27Smillert duplicate(struct range *r1, struct range *r2) 468*d407ca27Smillert { 469*d407ca27Smillert int c,d; 470*d407ca27Smillert int nchar; 471*d407ca27Smillert int nline; 472*d407ca27Smillert 473*d407ca27Smillert if (r1->to-r1->from != r2->to-r2->from) 474*d407ca27Smillert return (0); 475*d407ca27Smillert (void)skip(0, r1->from, NULL); 476*d407ca27Smillert (void)skip(1, r2->from, NULL); 477*d407ca27Smillert nchar = 0; 478*d407ca27Smillert for (nline=0; nline < r1->to - r1->from; nline++) { 479*d407ca27Smillert do { 480*d407ca27Smillert c = getc(fp[0]); 481*d407ca27Smillert d = getc(fp[1]); 482*d407ca27Smillert if (c == -1 || d== -1) 483*d407ca27Smillert trouble(); 484*d407ca27Smillert nchar++; 485*d407ca27Smillert if (c != d) { 486*d407ca27Smillert repos(nchar); 487*d407ca27Smillert return (0); 488*d407ca27Smillert } 489*d407ca27Smillert } while (c != '\n'); 490*d407ca27Smillert } 491*d407ca27Smillert repos(nchar); 492*d407ca27Smillert return (1); 493*d407ca27Smillert } 494*d407ca27Smillert 495*d407ca27Smillert void 496*d407ca27Smillert repos(int nchar) 497*d407ca27Smillert { 498*d407ca27Smillert int i; 499*d407ca27Smillert 500*d407ca27Smillert for (i = 0; i < 2; i++) 501*d407ca27Smillert (void)fseek(fp[i], (long)-nchar, 1); 502*d407ca27Smillert } 503*d407ca27Smillert 504*d407ca27Smillert __dead void 505*d407ca27Smillert trouble(void) 506*d407ca27Smillert { 507*d407ca27Smillert errx(EXIT_FAILURE, "logic error"); 508*d407ca27Smillert } 509*d407ca27Smillert 510*d407ca27Smillert /* 511*d407ca27Smillert * collect an editing script for later regurgitation 512*d407ca27Smillert */ 513*d407ca27Smillert int 514*d407ca27Smillert edit(struct diff *diff, int dup, int j) 515*d407ca27Smillert { 516*d407ca27Smillert if (((dup + 1) & eflag) == 0) 517*d407ca27Smillert return (j); 518*d407ca27Smillert j++; 519*d407ca27Smillert overlap[j] = !dup; 520*d407ca27Smillert if (!dup) 521*d407ca27Smillert overlapcnt++; 522*d407ca27Smillert de[j].old.from = diff->old.from; 523*d407ca27Smillert de[j].old.to = diff->old.to; 524*d407ca27Smillert de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 525*d407ca27Smillert de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 526*d407ca27Smillert return (j); 527*d407ca27Smillert } 528*d407ca27Smillert 529*d407ca27Smillert /* regurgitate */ 530*d407ca27Smillert __dead void 531*d407ca27Smillert edscript(int n) 532*d407ca27Smillert { 533*d407ca27Smillert int j,k; 534*d407ca27Smillert char block[BUFSIZ]; 535*d407ca27Smillert 536*d407ca27Smillert for (n = n; n > 0; n--) { 537*d407ca27Smillert if (!oflag || !overlap[n]) 538*d407ca27Smillert prange(&de[n].old); 539*d407ca27Smillert else 540*d407ca27Smillert printf("%da\n=======\n", de[n].old.to -1); 541*d407ca27Smillert (void)fseek(fp[2], (long)de[n].new.from, 0); 542*d407ca27Smillert for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 543*d407ca27Smillert j = k > BUFSIZ ? BUFSIZ : k; 544*d407ca27Smillert if (fread(block, 1, j, fp[2]) != j) 545*d407ca27Smillert trouble(); 546*d407ca27Smillert (void)fwrite(block, 1, j, stdout); 547*d407ca27Smillert } 548*d407ca27Smillert if (!oflag || !overlap[n]) 549*d407ca27Smillert printf(".\n"); 550*d407ca27Smillert else { 551*d407ca27Smillert printf("%s\n.\n", f3mark); 552*d407ca27Smillert printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 553*d407ca27Smillert } 554*d407ca27Smillert } 555*d407ca27Smillert exit(overlapcnt); 556*d407ca27Smillert } 557*d407ca27Smillert 558*d407ca27Smillert __dead void 559*d407ca27Smillert usage(void) 560*d407ca27Smillert { 561*d407ca27Smillert extern char *__progname; 562*d407ca27Smillert 563*d407ca27Smillert fprintf(stderr, "usage: %s [-exEX3] /tmp/d3a.?????????? " 564*d407ca27Smillert "/tmp/d3b.?????????? file1 file2 file3\n", __progname); 565*d407ca27Smillert exit(EXIT_FAILURE); 566*d407ca27Smillert } 567