xref: /openbsd-src/usr.bin/diff3/diff3prog.c (revision d407ca27a76d17dcb9524af8c510c420d22b10e7)
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