xref: /freebsd/usr.bin/diff3/diff3.c (revision cb350ba7bf7ca7c4cb97ed2c20ab45af60382cfb)
1  /*	$OpenBSD: diff3prog.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $	*/
2  
3  /*
4   * Copyright (C) Caldera International Inc.  2001-2002.
5   * All rights reserved.
6   *
7   * Redistribution and use in source and binary forms, with or without
8   * modification, are permitted provided that the following conditions
9   * are met:
10   * 1. Redistributions of source code and documentation must retain the above
11   *    copyright notice, this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in the
14   *    documentation and/or other materials provided with the distribution.
15   * 3. All advertising materials mentioning features or use of this software
16   *    must display the following acknowledgement:
17   *	This product includes software developed or owned by Caldera
18   *	International, Inc.
19   * 4. Neither the name of Caldera International, Inc. nor the names of other
20   *    contributors may be used to endorse or promote products derived from
21   *    this software without specific prior written permission.
22   *
23   * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
24   * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
25   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27   * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
28   * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34   * POSSIBILITY OF SUCH DAMAGE.
35   */
36  /*-
37   * Copyright (c) 1991, 1993
38   *	The Regents of the University of California.  All rights reserved.
39   *
40   * Redistribution and use in source and binary forms, with or without
41   * modification, are permitted provided that the following conditions
42   * are met:
43   * 1. Redistributions of source code must retain the above copyright
44   *    notice, this list of conditions and the following disclaimer.
45   * 2. Redistributions in binary form must reproduce the above copyright
46   *    notice, this list of conditions and the following disclaimer in the
47   *    documentation and/or other materials provided with the distribution.
48   * 3. Neither the name of the University nor the names of its contributors
49   *    may be used to endorse or promote products derived from this software
50   *    without specific prior written permission.
51   *
52   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62   * SUCH DAMAGE.
63   */
64  
65  #include <sys/capsicum.h>
66  #include <sys/procdesc.h>
67  #include <sys/types.h>
68  #include <sys/event.h>
69  #include <sys/wait.h>
70  
71  #include <capsicum_helpers.h>
72  #include <ctype.h>
73  #include <err.h>
74  #include <getopt.h>
75  #include <stdio.h>
76  #include <stdlib.h>
77  #include <limits.h>
78  #include <inttypes.h>
79  #include <string.h>
80  #include <unistd.h>
81  
82  
83  /*
84   * "from" is first in range of changed lines; "to" is last+1
85   * from=to=line after point of insertion for added lines.
86   */
87  struct range {
88  	int from;
89  	int to;
90  };
91  
92  struct diff {
93  #define DIFF_TYPE2 2
94  #define DIFF_TYPE3 3
95  	int type;
96  #if DEBUG
97  	char *line;
98  #endif	/* DEBUG */
99  
100  	/* Ranges as lines */
101  	struct range old;
102  	struct range new;
103  };
104  
105  #define EFLAG_NONE 	0
106  #define EFLAG_OVERLAP 	1
107  #define EFLAG_NOOVERLAP	2
108  #define EFLAG_UNMERGED	3
109  
110  static size_t szchanges;
111  
112  static struct diff *d13;
113  static struct diff *d23;
114  /*
115   * "de" is used to gather editing scripts.  These are later spewed out in
116   * reverse order.  Its first element must be all zero, the "old" and "new"
117   * components of "de" contain line positions. Array overlap indicates which
118   * sections in "de" correspond to lines that are different in all three files.
119   */
120  static struct diff *de;
121  static char *overlap;
122  static int  overlapcnt;
123  static FILE *fp[3];
124  static int cline[3];		/* # of the last-read line in each file (0-2) */
125  /*
126   * The latest known correspondence between line numbers of the 3 files
127   * is stored in last[1-3];
128   */
129  static int last[4];
130  static int Aflag, eflag, iflag, mflag, Tflag;
131  static int oflag;		/* indicates whether to mark overlaps (-E or -X) */
132  static int strip_cr;
133  static char *f1mark, *f2mark, *f3mark;
134  static const char *oldmark = "<<<<<<<";
135  static const char *orgmark = "|||||||";
136  static const char *newmark = ">>>>>>>";
137  static const char *divider = "=======";
138  
139  static bool duplicate(struct range *, struct range *);
140  static int edit(struct diff *, bool, int, int);
141  static char *getchange(FILE *);
142  static char *get_line(FILE *, size_t *);
143  static int readin(int fd, struct diff **);
144  static int skip(int, int, const char *);
145  static void change(int, struct range *, bool);
146  static void keep(int, struct range *);
147  static void merge(int, int);
148  static void prange(struct range *, bool);
149  static void repos(int);
150  static void edscript(int) __dead2;
151  static void Ascript(int) __dead2;
152  static void mergescript(int) __dead2;
153  static void increase(void);
154  static void usage(void);
155  static void printrange(FILE *, struct range *);
156  
157  static const char diff3_version[] = "FreeBSD diff3 20220517";
158  
159  enum {
160  	DIFFPROG_OPT,
161  	STRIPCR_OPT,
162  	HELP_OPT,
163  	VERSION_OPT
164  };
165  
166  #define DIFF_PATH "/usr/bin/diff"
167  
168  #define OPTIONS "3aAeEiL:mTxX"
169  static struct option longopts[] = {
170  	{ "ed",			no_argument,		NULL,	'e' },
171  	{ "show-overlap",	no_argument,		NULL,	'E' },
172  	{ "overlap-only",	no_argument,		NULL,	'x' },
173  	{ "initial-tab",	no_argument,		NULL,	'T' },
174  	{ "text",		no_argument,		NULL,	'a' },
175  	{ "strip-trailing-cr",	no_argument,		NULL,	STRIPCR_OPT },
176  	{ "show-all",		no_argument,		NULL,	'A' },
177  	{ "easy-only",		no_argument,		NULL,	'3' },
178  	{ "merge",		no_argument,		NULL,	'm' },
179  	{ "label",		required_argument,	NULL,	'L' },
180  	{ "diff-program",	required_argument,	NULL,	DIFFPROG_OPT },
181  	{ "help",		no_argument,		NULL,	HELP_OPT},
182  	{ "version",		no_argument,		NULL,	VERSION_OPT}
183  };
184  
185  static void
186  usage(void)
187  {
188  	fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L label1] [-L label2] "
189  	    "[-L label3] file1 file2 file3\n");
190  }
191  
192  static int
193  readin(int fd, struct diff **dd)
194  {
195  	int a, b, c, d;
196  	size_t i;
197  	char kind, *p;
198  	FILE *f;
199  
200  	f = fdopen(fd, "r");
201  	if (f == NULL)
202  		err(2, "fdopen");
203  	for (i = 0; (p = getchange(f)); i++) {
204  #if DEBUG
205  		(*dd)[i].line = strdup(p);
206  #endif	/* DEBUG */
207  
208  		if (i >= szchanges - 1)
209  			increase();
210  		a = b = (int)strtoimax(p, &p, 10);
211  		if (*p == ',') {
212  			p++;
213  			b = (int)strtoimax(p, &p, 10);
214  		}
215  		kind = *p++;
216  		c = d = (int)strtoimax(p, &p, 10);
217  		if (*p == ',') {
218  			p++;
219  			d = (int)strtoimax(p, &p, 10);
220  		}
221  		if (kind == 'a')
222  			a++;
223  		if (kind == 'd')
224  			c++;
225  		b++;
226  		d++;
227  		(*dd)[i].old.from = a;
228  		(*dd)[i].old.to = b;
229  		(*dd)[i].new.from = c;
230  		(*dd)[i].new.to = d;
231  	}
232  	if (i) {
233  		(*dd)[i].old.from = (*dd)[i - 1].old.to;
234  		(*dd)[i].new.from = (*dd)[i - 1].new.to;
235  	}
236  	fclose(f);
237  	return (i);
238  }
239  
240  static int
241  diffexec(const char *diffprog, char **diffargv, int fd[])
242  {
243  	int pd;
244  
245  	switch (pdfork(&pd, PD_CLOEXEC)) {
246  	case 0:
247  		close(fd[0]);
248  		if (dup2(fd[1], STDOUT_FILENO) == -1)
249  			err(2, "child could not duplicate descriptor");
250  		close(fd[1]);
251  		execvp(diffprog, diffargv);
252  		err(2, "could not execute diff: %s", diffprog);
253  		break;
254  	case -1:
255  		err(2, "could not fork");
256  		break;
257  	}
258  	close(fd[1]);
259  	return (pd);
260  }
261  
262  static char *
263  getchange(FILE *b)
264  {
265  	char *line;
266  
267  	while ((line = get_line(b, NULL))) {
268  		if (isdigit((unsigned char)line[0]))
269  			return (line);
270  	}
271  	return (NULL);
272  }
273  
274  
275  static char *
276  get_line(FILE *b, size_t *n)
277  {
278  	ssize_t len;
279  	static char *buf = NULL;
280  	static size_t bufsize = 0;
281  
282  	if ((len = getline(&buf, &bufsize, b)) < 0)
283  		return (NULL);
284  
285  	if (strip_cr && len >= 2 && strcmp("\r\n", &(buf[len - 2])) == 0) {
286  		buf[len - 2] = '\n';
287  		buf[len - 1] = '\0';
288  		len--;
289  	}
290  
291  	if (n != NULL)
292  		*n = len;
293  
294  	return (buf);
295  }
296  
297  static void
298  merge(int m1, int m2)
299  {
300  	struct diff *d1, *d2, *d3;
301  	int j, t1, t2;
302  	bool dup = false;
303  
304  	d1 = d13;
305  	d2 = d23;
306  	j = 0;
307  
308  	while (t1 = d1 < d13 + m1, t2 = d2 < d23 + m2, t1 || t2) {
309  		/* first file is different from the others */
310  		if (!t2 || (t1 && d1->new.to < d2->new.from)) {
311  			/* stuff peculiar to 1st file */
312  			if (eflag == EFLAG_NONE) {
313  				printf("====1\n");
314  				change(1, &d1->old, false);
315  				keep(2, &d1->new);
316  				change(3, &d1->new, false);
317  			}
318  			d1++;
319  			continue;
320  		}
321  		/* second file is different from others */
322  		if (!t1 || (t2 && d2->new.to < d1->new.from)) {
323  			if (eflag == EFLAG_NONE) {
324  				printf("====2\n");
325  				keep(1, &d2->new);
326  				change(3, &d2->new, false);
327  				change(2, &d2->old, false);
328  			} else if (Aflag || mflag) {
329  				// XXX-THJ: What does it mean for the second file to differ?
330  				if (eflag == EFLAG_UNMERGED)
331  					j = edit(d2, dup, j, DIFF_TYPE2);
332  			}
333  			d2++;
334  			continue;
335  		}
336  		/*
337  		 * Merge overlapping changes in first file
338  		 * this happens after extension (see below).
339  		 */
340  		if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) {
341  			d1[1].old.from = d1->old.from;
342  			d1[1].new.from = d1->new.from;
343  			d1++;
344  			continue;
345  		}
346  
347  		/* merge overlapping changes in second */
348  		if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) {
349  			d2[1].old.from = d2->old.from;
350  			d2[1].new.from = d2->new.from;
351  			d2++;
352  			continue;
353  		}
354  		/* stuff peculiar to third file or different in all */
355  		if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) {
356  			dup = duplicate(&d1->old, &d2->old);
357  			/*
358  			 * dup = 0 means all files differ
359  			 * dup = 1 means files 1 and 2 identical
360  			 */
361  			if (eflag == EFLAG_NONE) {
362  				printf("====%s\n", dup ? "3" : "");
363  				change(1, &d1->old, dup);
364  				change(2, &d2->old, false);
365  				d3 = d1->old.to > d1->old.from ? d1 : d2;
366  				change(3, &d3->new, false);
367  			} else {
368  				j = edit(d1, dup, j, DIFF_TYPE3);
369  			}
370  			dup = false;
371  			d1++;
372  			d2++;
373  			continue;
374  		}
375  		/*
376  		 * Overlapping changes from file 1 and 2; extend changes
377  		 * appropriately to make them coincide.
378  		 */
379  		if (d1->new.from < d2->new.from) {
380  			d2->old.from -= d2->new.from - d1->new.from;
381  			d2->new.from = d1->new.from;
382  		} else if (d2->new.from < d1->new.from) {
383  			d1->old.from -= d1->new.from - d2->new.from;
384  			d1->new.from = d2->new.from;
385  		}
386  		if (d1->new.to > d2->new.to) {
387  			d2->old.to += d1->new.to - d2->new.to;
388  			d2->new.to = d1->new.to;
389  		} else if (d2->new.to > d1->new.to) {
390  			d1->old.to += d2->new.to - d1->new.to;
391  			d1->new.to = d2->new.to;
392  		}
393  	}
394  
395  	if (mflag)
396  		mergescript(j);
397  	else if (Aflag)
398  		Ascript(j);
399  	else if (eflag)
400  		edscript(j);
401  }
402  
403  /*
404   * The range of lines rold.from thru rold.to in file i is to be changed.
405   * It is to be printed only if it does not duplicate something to be
406   * printed later.
407   */
408  static void
409  change(int i, struct range *rold, bool dup)
410  {
411  
412  	printf("%d:", i);
413  	last[i] = rold->to;
414  	prange(rold, false);
415  	if (dup)
416  		return;
417  	i--;
418  	skip(i, rold->from, NULL);
419  	skip(i, rold->to, "  ");
420  }
421  
422  /*
423   * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or
424   * n1.
425   */
426  static void
427  prange(struct range *rold, bool delete)
428  {
429  
430  	if (rold->to <= rold->from)
431  		printf("%da\n", rold->from - 1);
432  	else {
433  		printf("%d", rold->from);
434  		if (rold->to > rold->from + 1)
435  			printf(",%d", rold->to - 1);
436  		if (delete)
437  			printf("d\n");
438  		else
439  			printf("c\n");
440  	}
441  }
442  
443  /*
444   * No difference was reported by diff between file 1 (or 2) and file 3,
445   * and an artificial dummy difference (trange) must be ginned up to
446   * correspond to the change reported in the other file.
447   */
448  static void
449  keep(int i, struct range *rnew)
450  {
451  	int delta;
452  	struct range trange;
453  
454  	delta = last[3] - last[i];
455  	trange.from = rnew->from - delta;
456  	trange.to = rnew->to - delta;
457  	change(i, &trange, true);
458  }
459  
460  /*
461   * skip to just before line number from in file "i".  If "pr" is non-NULL,
462   * print all skipped stuff with string pr as a prefix.
463   */
464  static int
465  skip(int i, int from, const char *pr)
466  {
467  	size_t j, n;
468  	char *line;
469  
470  	for (n = 0; cline[i] < from - 1; n += j) {
471  		if ((line = get_line(fp[i], &j)) == NULL)
472  			errx(EXIT_FAILURE, "logic error");
473  		if (pr != NULL)
474  			printf("%s%s", Tflag == 1 ? "\t" : pr, line);
475  		cline[i]++;
476  	}
477  	return ((int) n);
478  }
479  
480  /*
481   * Return 1 or 0 according as the old range (in file 1) contains exactly
482   * the same data as the new range (in file 2).
483   */
484  static bool
485  duplicate(struct range *r1, struct range *r2)
486  {
487  	int c, d;
488  	int nchar;
489  	int nline;
490  
491  	if (r1->to-r1->from != r2->to-r2->from)
492  		return (0);
493  	skip(0, r1->from, NULL);
494  	skip(1, r2->from, NULL);
495  	nchar = 0;
496  	for (nline = 0; nline < r1->to - r1->from; nline++) {
497  		do {
498  			c = getc(fp[0]);
499  			d = getc(fp[1]);
500  			if (c == -1 && d == -1)
501  				break;
502  			if (c == -1 || d == -1)
503  				errx(EXIT_FAILURE, "logic error");
504  			nchar++;
505  			if (c != d) {
506  				repos(nchar);
507  				return (0);
508  			}
509  		} while (c != '\n');
510  	}
511  	repos(nchar);
512  	return (1);
513  }
514  
515  static void
516  repos(int nchar)
517  {
518  	int i;
519  
520  	for (i = 0; i < 2; i++)
521  		(void)fseek(fp[i], (long)-nchar, SEEK_CUR);
522  }
523  
524  /*
525   * collect an editing script for later regurgitation
526   */
527  static int
528  edit(struct diff *diff, bool dup, int j, int difftype)
529  {
530  	if (!(eflag == EFLAG_UNMERGED ||
531  		(!dup && eflag == EFLAG_OVERLAP ) ||
532  		(dup && eflag == EFLAG_NOOVERLAP))) {
533  		return (j);
534  	}
535  	j++;
536  	overlap[j] = !dup;
537  	if (!dup)
538  		overlapcnt++;
539  
540  	de[j].type = difftype;
541  #if DEBUG
542  	de[j].line = strdup(diff->line);
543  #endif	/* DEBUG */
544  
545  	de[j].old.from = diff->old.from;
546  	de[j].old.to = diff->old.to;
547  	de[j].new.from = diff->new.from;
548  	de[j].new.to = diff->new.to;
549  	return (j);
550  }
551  
552  static void
553  printrange(FILE *p, struct range *r)
554  {
555  	char *line = NULL;
556  	size_t len = 0;
557  	int i = 1;
558  	ssize_t rlen = 0;
559  
560  	/* We haven't been asked to print anything */
561  	if (r->from == r->to)
562  		return;
563  
564  	if (r->from > r->to)
565  		errx(EXIT_FAILURE, "invalid print range");
566  
567  	/*
568  	 * XXX-THJ: We read through all of the file for each range printed.
569  	 * This duplicates work and will probably impact performance on large
570  	 * files with lots of ranges.
571  	 */
572  	fseek(p, 0L, SEEK_SET);
573  	while ((rlen = getline(&line, &len, p)) > 0) {
574  		if (i >= r->from)
575  			printf("%s", line);
576  		if (++i > r->to - 1)
577  			break;
578  	}
579  	free(line);
580  }
581  
582  /* regurgitate */
583  static void
584  edscript(int n)
585  {
586  	bool delete;
587  	struct range *new, *old;
588  
589  	for (; n > 0; n--) {
590  		new = &de[n].new;
591  		old = &de[n].old;
592  
593  		delete = (new->from == new->to);
594  		if (!oflag || !overlap[n]) {
595  			prange(old, delete);
596  		} else {
597  			printf("%da\n", old->to - 1);
598  			printf("%s\n", divider);
599  		}
600  		printrange(fp[2], new);
601  		if (!oflag || !overlap[n]) {
602  			if (!delete)
603  				printf(".\n");
604  		} else {
605  			printf("%s %s\n.\n", newmark, f3mark);
606  			printf("%da\n%s %s\n.\n", old->from - 1,
607  				oldmark, f1mark);
608  		}
609  	}
610  	if (iflag)
611  		printf("w\nq\n");
612  
613  	exit(eflag == EFLAG_NONE ? overlapcnt : 0);
614  }
615  
616  /*
617   * Output an edit script to turn mine into yours, when there is a conflict
618   * between the 3 files bracket the changes. Regurgitate the diffs in reverse
619   * order to allow the ed script to track down where the lines are as changes
620   * are made.
621   */
622  static void
623  Ascript(int n)
624  {
625  	int startmark;
626  	bool deletenew;
627  	bool deleteold;
628  
629  	struct range *new, *old;
630  
631  	for (; n > 0; n--) {
632  		new = &de[n].new;
633  		old = &de[n].old;
634  		deletenew = (new->from == new->to);
635  		deleteold = (old->from == old->to);
636  
637  		if (de[n].type == DIFF_TYPE2) {
638  			if (!oflag || !overlap[n]) {
639  				prange(old, deletenew);
640  				printrange(fp[2], new);
641  			} else {
642  				startmark = new->to;
643  
644  				if (!deletenew)
645  					startmark--;
646  
647  				printf("%da\n", startmark);
648  				printf("%s %s\n", newmark, f3mark);
649  
650  				printf(".\n");
651  
652  				printf("%da\n", startmark -
653  					(new->to - new->from));
654  				printf("%s %s\n", oldmark, f2mark);
655  				if (!deleteold)
656  					printrange(fp[1], old);
657  				printf("%s\n.\n", divider);
658  			}
659  
660  		} else if (de[n].type == DIFF_TYPE3) {
661  			startmark = old->to - 1;
662  
663  			if (!oflag || !overlap[n]) {
664  				prange(old, deletenew);
665  				printrange(fp[2], new);
666  			} else {
667  				printf("%da\n", startmark);
668  				printf("%s %s\n", orgmark, f2mark);
669  
670  				if (deleteold) {
671  					struct range r;
672  					r.from = old->from-1;
673  					r.to = new->to;
674  					printrange(fp[1], &r);
675  				} else
676  					printrange(fp[1], old);
677  
678  				printf("%s\n", divider);
679  				printrange(fp[2], new);
680  			}
681  
682  			if (!oflag || !overlap[n]) {
683  				if (!deletenew)
684  					printf(".\n");
685  			} else {
686  				printf("%s %s\n.\n", newmark, f3mark);
687  
688  				/*
689  				 * Go to the start of the conflict in original
690  				 * file and append lines
691  				 */
692  				printf("%da\n%s %s\n.\n",
693  					startmark - (old->to - old->from),
694  					oldmark, f1mark);
695  			}
696  		}
697  	}
698  	if (iflag)
699  		printf("w\nq\n");
700  
701  	exit(overlapcnt > 0);
702  }
703  
704  /*
705   * Output the merged file directly (don't generate an ed script). When
706   * regurgitating diffs we need to walk forward through the file and print any
707   * inbetween lines.
708   */
709  static void
710  mergescript(int i)
711  {
712  	struct range r, *new, *old;
713  	int n;
714  
715  	r.from = 1;
716  	r.to = 1;
717  
718  	for (n = 1; n < i+1; n++) {
719  		new = &de[n].new;
720  		old = &de[n].old;
721  
722  		/* print any lines leading up to here */
723  		r.to = old->from;
724  		printrange(fp[0], &r);
725  
726  		if (de[n].type == DIFF_TYPE2) {
727  			printf("%s %s\n", oldmark, f2mark);
728  			printrange(fp[1], old);
729  			printf("%s\n", divider);
730  			printrange(fp[2], new);
731  			printf("%s %s\n", newmark, f3mark);
732  		} else if (de[n].type == DIFF_TYPE3) {
733  			if (!oflag || !overlap[n]) {
734  				printrange(fp[2], new);
735  			} else {
736  
737  				printf("%s %s\n", oldmark, f1mark);
738  				printrange(fp[0], old);
739  
740  				printf("%s %s\n", orgmark, f2mark);
741  				if (old->from == old->to) {
742  					struct range or;
743  					or.from = old->from - 1;
744  					or.to = new->to;
745  					printrange(fp[1], &or);
746  				} else
747  					printrange(fp[1], old);
748  
749  				printf("%s\n", divider);
750  
751  				printrange(fp[2], new);
752  				printf("%s %s\n", newmark, f3mark);
753  			}
754  		}
755  
756  		if (old->from == old->to)
757  			r.from = new->to;
758  		else
759  			r.from = old->to;
760  	}
761  	/*
762  	 * Print from the final range to the end of 'myfile'. Any deletions or
763  	 * additions to this file should have been handled by now.
764  	 *
765  	 * If the ranges are the same we need to rewind a line.
766  	 * If the new range is 0 length (from == to), we need to use the old
767  	 * range.
768  	 */
769  	new = &de[n-1].new;
770  	old = &de[n-1].old;
771  	if ((old->from == new->from) &&
772  		(old->to == new->to))
773  		r.from--;
774  	else if (new->from == new->to)
775  		r.from = old->from;
776  
777  	/*
778  	 * If the range is a 3 way merge then we need to skip a line in the
779  	 * trailing output.
780  	 */
781  	if (de[n-1].type == DIFF_TYPE3)
782  		r.from++;
783  
784  	r.to = INT_MAX;
785  	printrange(fp[0], &r);
786  	exit(overlapcnt > 0);
787  }
788  
789  static void
790  increase(void)
791  {
792  	struct diff *p;
793  	char *q;
794  	size_t newsz, incr;
795  
796  	/* are the memset(3) calls needed? */
797  	newsz = szchanges == 0 ? 64 : 2 * szchanges;
798  	incr = newsz - szchanges;
799  
800  	p = reallocarray(d13, newsz, sizeof(struct diff));
801  	if (p == NULL)
802  		err(1, NULL);
803  	memset(p + szchanges, 0, incr * sizeof(struct diff));
804  	d13 = p;
805  	p = reallocarray(d23, newsz, sizeof(struct diff));
806  	if (p == NULL)
807  		err(1, NULL);
808  	memset(p + szchanges, 0, incr * sizeof(struct diff));
809  	d23 = p;
810  	p = reallocarray(de, newsz, sizeof(struct diff));
811  	if (p == NULL)
812  		err(1, NULL);
813  	memset(p + szchanges, 0, incr * sizeof(struct diff));
814  	de = p;
815  	q = reallocarray(overlap, newsz, sizeof(char));
816  	if (q == NULL)
817  		err(1, NULL);
818  	memset(q + szchanges, 0, incr * sizeof(char));
819  	overlap = q;
820  	szchanges = newsz;
821  }
822  
823  
824  int
825  main(int argc, char **argv)
826  {
827  	int ch, nblabels, status, m, n, kq, nke, nleft, i;
828  	char *labels[] = { NULL, NULL, NULL };
829  	const char *diffprog = DIFF_PATH;
830  	char *file1, *file2, *file3;
831  	char *diffargv[7];
832  	int diffargc = 0;
833  	int fd13[2], fd23[2];
834  	int pd13, pd23;
835  	cap_rights_t rights_ro;
836  	struct kevent *e;
837  
838  	nblabels = 0;
839  	eflag = EFLAG_NONE;
840  	oflag = 0;
841  	diffargv[diffargc++] = __DECONST(char *, diffprog);
842  	while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
843  		switch (ch) {
844  		case '3':
845  			eflag = EFLAG_NOOVERLAP;
846  			break;
847  		case 'a':
848  			diffargv[diffargc++] = __DECONST(char *, "-a");
849  			break;
850  		case 'A':
851  			Aflag = 1;
852  			break;
853  		case 'e':
854  			eflag = EFLAG_UNMERGED;
855  			break;
856  		case 'E':
857  			eflag = EFLAG_OVERLAP;
858  			oflag = 1;
859  			break;
860  		case 'i':
861  			iflag = 1;
862  			break;
863  		case 'L':
864  			oflag = 1;
865  			if (nblabels >= 3)
866  				errx(2, "too many file label options");
867  			labels[nblabels++] = optarg;
868  			break;
869  		case 'm':
870  			Aflag = 1;
871  			oflag = 1;
872  			mflag = 1;
873  			break;
874  		case 'T':
875  			Tflag = 1;
876  			break;
877  		case 'x':
878  			eflag = EFLAG_OVERLAP;
879  			break;
880  		case 'X':
881  			oflag = 1;
882  			eflag = EFLAG_OVERLAP;
883  			break;
884  		case DIFFPROG_OPT:
885  			diffprog = optarg;
886  			break;
887  		case STRIPCR_OPT:
888  			strip_cr = 1;
889  			diffargv[diffargc++] = __DECONST(char *, "--strip-trailing-cr");
890  			break;
891  		case HELP_OPT:
892  			usage();
893  			exit(0);
894  		case VERSION_OPT:
895  			printf("%s\n", diff3_version);
896  			exit(0);
897  		}
898  	}
899  	argc -= optind;
900  	argv += optind;
901  
902  	if (Aflag) {
903  		if (eflag == EFLAG_NONE)
904  			eflag = EFLAG_UNMERGED;
905  		oflag = 1;
906  	}
907  
908  	if (argc != 3) {
909  		usage();
910  		exit(2);
911  	}
912  
913  	if (caph_limit_stdio() == -1)
914  		err(2, "unable to limit stdio");
915  
916  	cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK);
917  
918  	kq = kqueue();
919  	if (kq == -1)
920  		err(2, "kqueue");
921  
922  	e = malloc(2 * sizeof(struct kevent));
923  	if (e == NULL)
924  		err(2, "malloc");
925  
926  	/* TODO stdio */
927  	file1 = argv[0];
928  	file2 = argv[1];
929  	file3 = argv[2];
930  
931  	if (oflag) {
932  		asprintf(&f1mark, "%s",
933  		    labels[0] != NULL ? labels[0] : file1);
934  		if (f1mark == NULL)
935  			err(2, "asprintf");
936  		asprintf(&f2mark, "%s",
937  		    labels[1] != NULL ? labels[1] : file2);
938  		if (f2mark == NULL)
939  			err(2, "asprintf");
940  		asprintf(&f3mark, "%s",
941  		    labels[2] != NULL ? labels[2] : file3);
942  		if (f3mark == NULL)
943  			err(2, "asprintf");
944  	}
945  	fp[0] = fopen(file1, "r");
946  	if (fp[0] == NULL)
947  		err(2, "Can't open %s", file1);
948  	if (caph_rights_limit(fileno(fp[0]), &rights_ro) < 0)
949  		err(2, "unable to limit rights on: %s", file1);
950  
951  	fp[1] = fopen(file2, "r");
952  	if (fp[1] == NULL)
953  		err(2, "Can't open %s", file2);
954  	if (caph_rights_limit(fileno(fp[1]), &rights_ro) < 0)
955  		err(2, "unable to limit rights on: %s", file2);
956  
957  	fp[2] = fopen(file3, "r");
958  	if (fp[2] == NULL)
959  		err(2, "Can't open %s", file3);
960  	if (caph_rights_limit(fileno(fp[2]), &rights_ro) < 0)
961  		err(2, "unable to limit rights on: %s", file3);
962  
963  	if (pipe(fd13))
964  		err(2, "pipe");
965  	if (pipe(fd23))
966  		err(2, "pipe");
967  
968  	diffargv[diffargc] = file1;
969  	diffargv[diffargc + 1] = file3;
970  	diffargv[diffargc + 2] = NULL;
971  
972  	nleft = 0;
973  	pd13 = diffexec(diffprog, diffargv, fd13);
974  	EV_SET(e + nleft , pd13, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL);
975  	if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
976  		err(2, "kevent1");
977  	nleft++;
978  
979  	diffargv[diffargc] = file2;
980  	pd23 = diffexec(diffprog, diffargv, fd23);
981  	EV_SET(e + nleft , pd23, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL);
982  	if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
983  		err(2, "kevent2");
984  	nleft++;
985  
986  	caph_cache_catpages();
987  	if (caph_enter() < 0)
988  		err(2, "unable to enter capability mode");
989  
990  	/* parse diffs */
991  	increase();
992  	m = readin(fd13[0], &d13);
993  	n = readin(fd23[0], &d23);
994  
995  	/* waitpid cooked over pdforks */
996  	while (nleft > 0) {
997  		nke = kevent(kq, NULL, 0, e, nleft, NULL);
998  		if (nke == -1)
999  			err(2, "kevent");
1000  		for (i = 0; i < nke; i++) {
1001  			status = e[i].data;
1002  			if (WIFEXITED(status) && WEXITSTATUS(status) >= 2)
1003  				errx(2, "diff exited abnormally");
1004  			else if (WIFSIGNALED(status))
1005  				errx(2, "diff killed by signal %d",
1006  				    WTERMSIG(status));
1007  		}
1008  		nleft -= nke;
1009  	}
1010  	merge(m, n);
1011  
1012  	return (EXIT_SUCCESS);
1013  }
1014