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