xref: /freebsd/usr.bin/diff3/diff3.c (revision 4ff291ebe80a226295351936d99fc6e3e7fce48a)
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   * "from" is first in range of changed lines; "to" is last+1
84   * from=to=line after point of insertion for added lines.
85   */
86  struct range {
87  	int from;
88  	int to;
89  };
90  
91  struct diff {
92  #define DIFF_TYPE1 1
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 separate(const char *);
151  static void edscript(int) __dead2;
152  static void Ascript(int) __dead2;
153  static void mergescript(int) __dead2;
154  static void increase(void);
155  static void usage(void);
156  static void printrange(FILE *, struct range *);
157  
158  static const char diff3_version[] = "FreeBSD diff3 20240925";
159  
160  enum {
161  	DIFFPROG_OPT,
162  	STRIPCR_OPT,
163  	HELP_OPT,
164  	VERSION_OPT
165  };
166  
167  #define DIFF_PATH "/usr/bin/diff"
168  
169  #define OPTIONS "3aAeEiL:mTxX"
170  static struct option longopts[] = {
171  	{ "ed",			no_argument,		NULL,	'e' },
172  	{ "show-overlap",	no_argument,		NULL,	'E' },
173  	{ "overlap-only",	no_argument,		NULL,	'x' },
174  	{ "initial-tab",	no_argument,		NULL,	'T' },
175  	{ "text",		no_argument,		NULL,	'a' },
176  	{ "strip-trailing-cr",	no_argument,		NULL,	STRIPCR_OPT },
177  	{ "show-all",		no_argument,		NULL,	'A' },
178  	{ "easy-only",		no_argument,		NULL,	'3' },
179  	{ "merge",		no_argument,		NULL,	'm' },
180  	{ "label",		required_argument,	NULL,	'L' },
181  	{ "diff-program",	required_argument,	NULL,	DIFFPROG_OPT },
182  	{ "help",		no_argument,		NULL,	HELP_OPT},
183  	{ "version",		no_argument,		NULL,	VERSION_OPT}
184  };
185  
186  static void
187  usage(void)
188  {
189  	fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L label1] [-L label2] "
190  	    "[-L label3] file1 file2 file3\n");
191  }
192  
193  static int
194  strtoi(char *str, char **end)
195  {
196  	intmax_t num;
197  
198  	errno = 0;
199  	num = strtoimax(str, end, 10);
200  	if ((end != NULL && *end == str) ||
201  	    num < 0 || num > INT_MAX ||
202  	    errno == EINVAL || errno == ERANGE)
203  		err(1, "error in diff output");
204  	return (int)num;
205  }
206  
207  /*
208   * Read diff hunks into the array pointed to by *dd.
209   *
210   * The output from `diff foo bar` consists of a series of hunks describing
211   * an addition (lines in bar not present in foo), change (lines in bar
212   * different from lines in foo), or deletion (lines in foo not present in
213   * bar).  Each record starts with a line of the form:
214   *
215   * a[,b]xc[,d]
216   *
217   * where a, b, c, and d are nonnegative integers (b and d are printed only
218   * if they differ from a and c, respectively), and x is either 'a' for an
219   * addition, 'c' for a change, or 'd' for a deletion.  This is then
220   * followed by a series of lines (which we ignore) giving the added,
221   * changed, or deleted text.
222   *
223   * For an addition, a == b is the last line in 'foo' before the addition,
224   * while c through d is the range of lines in 'bar' to be added to 'foo'.
225   *
226   * For a change, a through b is the range of lines in 'foo' to be replaced
227   * and c through d is the range of lines in 'bar' to replace them with.
228   *
229   * For a deletion, a through b is the range of lines in 'foo' to remove
230   * and c == d is the line in 'bar' which corresponds to the last line
231   * before the deletion.
232   *
233   * The observant reader will have noticed that x is not really needed and
234   * that we can fully describe any hunk using only a, b, c, and d:
235   *
236   * - an addition replaces a zero-length range in one file with a
237   *   non-zero-length range from the other
238   *
239   * - a change replaces a non-zero-length range in one file with a
240   *   non-zero-length range from the other
241   *
242   * - a deletion replaces a non-zero-length range in one file with a
243   *   zero-length range from the other
244   */
245  static int
246  readin(int fd, struct diff **dd)
247  {
248  	int a, b, c, d;
249  	int i;
250  	char kind, *p;
251  	FILE *f;
252  
253  	f = fdopen(fd, "r");
254  	if (f == NULL)
255  		err(2, "fdopen");
256  	for (i = 0; (p = getchange(f)) != NULL; i++) {
257  		if ((size_t)i >= szchanges - 1)
258  			increase();
259  #if DEBUG
260  		(*dd)[i].line = strdup(p);
261  #endif	/* DEBUG */
262  
263  		a = b = strtoi(p, &p);
264  		if (*p == ',')
265  			b = strtoi(p + 1, &p);
266  		kind = *p++;
267  		c = d = strtoi(p, &p);
268  		if (*p == ',')
269  			d = strtoi(p + 1, &p);
270  		if (*p != '\n')
271  			errx(1, "error in diff output");
272  		if (kind == 'a')
273  			a++;
274  		else if (kind == 'c')
275  			/* nothing */ ;
276  		else if (kind == 'd')
277  			c++;
278  		else
279  			errx(1, "error in diff output");
280  		b++;
281  		d++;
282  		if (b < a || d < c)
283  			errx(1, "error in diff output");
284  		(*dd)[i].old.from = a;
285  		(*dd)[i].old.to = b;
286  		(*dd)[i].new.from = c;
287  		(*dd)[i].new.to = d;
288  		if (i > 0) {
289  			if ((*dd)[i].old.from < (*dd)[i - 1].old.to ||
290  			    (*dd)[i].new.from < (*dd)[i - 1].new.to)
291  				errx(1, "diff output out of order");
292  		}
293  	}
294  	if (i > 0) {
295  		(*dd)[i].old.from = (*dd)[i].old.to = (*dd)[i - 1].old.to;
296  		(*dd)[i].new.from = (*dd)[i].new.to = (*dd)[i - 1].new.to;
297  	}
298  	fclose(f);
299  	return (i);
300  }
301  
302  static int
303  diffexec(const char *diffprog, char **diffargv, int fd[])
304  {
305  	int pd;
306  
307  	switch (pdfork(&pd, PD_CLOEXEC)) {
308  	case 0:
309  		close(fd[0]);
310  		if (dup2(fd[1], STDOUT_FILENO) == -1)
311  			err(2, "child could not duplicate descriptor");
312  		close(fd[1]);
313  		execvp(diffprog, diffargv);
314  		err(2, "could not execute diff: %s", diffprog);
315  		break;
316  	case -1:
317  		err(2, "could not fork");
318  		break;
319  	}
320  	close(fd[1]);
321  	return (pd);
322  }
323  
324  static char *
325  getchange(FILE *b)
326  {
327  	char *line;
328  
329  	while ((line = get_line(b, NULL)) != NULL) {
330  		if (isdigit((unsigned char)line[0]))
331  			return (line);
332  	}
333  	return (NULL);
334  }
335  
336  
337  static char *
338  get_line(FILE *b, size_t *n)
339  {
340  	ssize_t len;
341  	static char *buf = NULL;
342  	static size_t bufsize = 0;
343  
344  	if ((len = getline(&buf, &bufsize, b)) < 0)
345  		return (NULL);
346  
347  	if (strip_cr && len >= 2 && strcmp("\r\n", &(buf[len - 2])) == 0) {
348  		buf[len - 2] = '\n';
349  		buf[len - 1] = '\0';
350  		len--;
351  	}
352  
353  	if (n != NULL)
354  		*n = len;
355  
356  	return (buf);
357  }
358  
359  static void
360  merge(int m1, int m2)
361  {
362  	struct diff *d1, *d2, *d3;
363  	int j, t1, t2;
364  	bool dup = false;
365  
366  	d1 = d13;
367  	d2 = d23;
368  	j = 0;
369  
370  	for (;;) {
371  		t1 = (d1 < d13 + m1);
372  		t2 = (d2 < d23 + m2);
373  		if (!t1 && !t2)
374  			break;
375  
376  		/* first file is different from the others */
377  		if (!t2 || (t1 && d1->new.to < d2->new.from)) {
378  			/* stuff peculiar to 1st file */
379  			if (eflag == EFLAG_NONE) {
380  				separate("1");
381  				change(1, &d1->old, false);
382  				keep(2, &d1->new);
383  				change(3, &d1->new, false);
384  			} else if (eflag == EFLAG_OVERLAP) {
385  				j = edit(d2, dup, j, DIFF_TYPE1);
386  			}
387  			d1++;
388  			continue;
389  		}
390  		/* second file is different from others */
391  		if (!t1 || (t2 && d2->new.to < d1->new.from)) {
392  			if (eflag == EFLAG_NONE) {
393  				separate("2");
394  				keep(1, &d2->new);
395  				change(3, &d2->new, false);
396  				change(2, &d2->old, false);
397  			} else if (Aflag || mflag) {
398  				// XXX-THJ: What does it mean for the second file to differ?
399  				if (eflag == EFLAG_UNMERGED)
400  					j = edit(d2, dup, j, DIFF_TYPE2);
401  			}
402  			d2++;
403  			continue;
404  		}
405  		/*
406  		 * Merge overlapping changes in first file
407  		 * this happens after extension (see below).
408  		 */
409  		if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) {
410  			d1[1].old.from = d1->old.from;
411  			d1[1].new.from = d1->new.from;
412  			d1++;
413  			continue;
414  		}
415  
416  		/* merge overlapping changes in second */
417  		if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) {
418  			d2[1].old.from = d2->old.from;
419  			d2[1].new.from = d2->new.from;
420  			d2++;
421  			continue;
422  		}
423  		/* stuff peculiar to third file or different in all */
424  		if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) {
425  			dup = duplicate(&d1->old, &d2->old);
426  			/*
427  			 * dup = 0 means all files differ
428  			 * dup = 1 means files 1 and 2 identical
429  			 */
430  			if (eflag == EFLAG_NONE) {
431  				separate(dup ? "3" : "");
432  				change(1, &d1->old, dup);
433  				change(2, &d2->old, false);
434  				d3 = d1->old.to > d1->old.from ? d1 : d2;
435  				change(3, &d3->new, false);
436  			} else {
437  				j = edit(d1, dup, j, DIFF_TYPE3);
438  			}
439  			dup = false;
440  			d1++;
441  			d2++;
442  			continue;
443  		}
444  		/*
445  		 * Overlapping changes from file 1 and 2; extend changes
446  		 * appropriately to make them coincide.
447  		 */
448  		if (d1->new.from < d2->new.from) {
449  			d2->old.from -= d2->new.from - d1->new.from;
450  			d2->new.from = d1->new.from;
451  		} else if (d2->new.from < d1->new.from) {
452  			d1->old.from -= d1->new.from - d2->new.from;
453  			d1->new.from = d2->new.from;
454  		}
455  		if (d1->new.to > d2->new.to) {
456  			d2->old.to += d1->new.to - d2->new.to;
457  			d2->new.to = d1->new.to;
458  		} else if (d2->new.to > d1->new.to) {
459  			d1->old.to += d2->new.to - d1->new.to;
460  			d1->new.to = d2->new.to;
461  		}
462  	}
463  
464  	if (mflag)
465  		mergescript(j);
466  	else if (Aflag)
467  		Ascript(j);
468  	else if (eflag)
469  		edscript(j);
470  }
471  
472  static void
473  separate(const char *s)
474  {
475  	printf("====%s\n", s);
476  }
477  
478  /*
479   * The range of lines rold.from thru rold.to in file i is to be changed.
480   * It is to be printed only if it does not duplicate something to be
481   * printed later.
482   */
483  static void
484  change(int i, struct range *rold, bool dup)
485  {
486  
487  	printf("%d:", i);
488  	last[i] = rold->to;
489  	prange(rold, false);
490  	if (dup)
491  		return;
492  	i--;
493  	skip(i, rold->from, NULL);
494  	skip(i, rold->to, "  ");
495  }
496  
497  /*
498   * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or
499   * n1.
500   */
501  static void
502  prange(struct range *rold, bool delete)
503  {
504  
505  	if (rold->to <= rold->from)
506  		printf("%da\n", rold->from - 1);
507  	else {
508  		printf("%d", rold->from);
509  		if (rold->to > rold->from + 1)
510  			printf(",%d", rold->to - 1);
511  		if (delete)
512  			printf("d\n");
513  		else
514  			printf("c\n");
515  	}
516  }
517  
518  /*
519   * No difference was reported by diff between file 1 (or 2) and file 3,
520   * and an artificial dummy difference (trange) must be ginned up to
521   * correspond to the change reported in the other file.
522   */
523  static void
524  keep(int i, struct range *rnew)
525  {
526  	int delta;
527  	struct range trange;
528  
529  	delta = last[3] - last[i];
530  	trange.from = rnew->from - delta;
531  	trange.to = rnew->to - delta;
532  	change(i, &trange, true);
533  }
534  
535  /*
536   * skip to just before line number from in file "i".  If "pr" is non-NULL,
537   * print all skipped stuff with string pr as a prefix.
538   */
539  static int
540  skip(int i, int from, const char *pr)
541  {
542  	size_t j, n;
543  	char *line;
544  
545  	for (n = 0; cline[i] < from - 1; n += j) {
546  		if ((line = get_line(fp[i], &j)) == NULL)
547  			errx(EXIT_FAILURE, "logic error");
548  		if (pr != NULL)
549  			printf("%s%s", Tflag == 1 ? "\t" : pr, line);
550  		cline[i]++;
551  	}
552  	return ((int) n);
553  }
554  
555  /*
556   * Return 1 or 0 according as the old range (in file 1) contains exactly
557   * the same data as the new range (in file 2).
558   */
559  static bool
560  duplicate(struct range *r1, struct range *r2)
561  {
562  	int c, d;
563  	int nchar;
564  	int nline;
565  
566  	if (r1->to-r1->from != r2->to-r2->from)
567  		return (0);
568  	skip(0, r1->from, NULL);
569  	skip(1, r2->from, NULL);
570  	nchar = 0;
571  	for (nline = 0; nline < r1->to - r1->from; nline++) {
572  		do {
573  			c = getc(fp[0]);
574  			d = getc(fp[1]);
575  			if (c == -1 && d == -1)
576  				break;
577  			if (c == -1 || d == -1)
578  				errx(EXIT_FAILURE, "logic error");
579  			nchar++;
580  			if (c != d) {
581  				repos(nchar);
582  				return (0);
583  			}
584  		} while (c != '\n');
585  	}
586  	repos(nchar);
587  	return (1);
588  }
589  
590  static void
591  repos(int nchar)
592  {
593  	int i;
594  
595  	for (i = 0; i < 2; i++)
596  		(void)fseek(fp[i], (long)-nchar, SEEK_CUR);
597  }
598  
599  /*
600   * collect an editing script for later regurgitation
601   */
602  static int
603  edit(struct diff *diff, bool dup, int j, int difftype)
604  {
605  	if (!(eflag == EFLAG_UNMERGED ||
606  		(!dup && eflag == EFLAG_OVERLAP ) ||
607  		(dup && eflag == EFLAG_NOOVERLAP))) {
608  		return (j);
609  	}
610  	j++;
611  	overlap[j] = !dup;
612  	if (!dup)
613  		overlapcnt++;
614  
615  	de[j].type = difftype;
616  #if DEBUG
617  	de[j].line = strdup(diff->line);
618  #endif	/* DEBUG */
619  
620  	de[j].old.from = diff->old.from;
621  	de[j].old.to = diff->old.to;
622  	de[j].new.from = diff->new.from;
623  	de[j].new.to = diff->new.to;
624  	return (j);
625  }
626  
627  static void
628  printrange(FILE *p, struct range *r)
629  {
630  	char *line = NULL;
631  	size_t len = 0;
632  	int i = 1;
633  
634  	/* We haven't been asked to print anything */
635  	if (r->from == r->to)
636  		return;
637  
638  	if (r->from > r->to)
639  		errx(EXIT_FAILURE, "invalid print range");
640  
641  	/*
642  	 * XXX-THJ: We read through all of the file for each range printed.
643  	 * This duplicates work and will probably impact performance on large
644  	 * files with lots of ranges.
645  	 */
646  	fseek(p, 0L, SEEK_SET);
647  	while (getline(&line, &len, p) > 0) {
648  		if (i >= r->from)
649  			printf("%s", line);
650  		if (++i > r->to - 1)
651  			break;
652  	}
653  	free(line);
654  }
655  
656  /* regurgitate */
657  static void
658  edscript(int n)
659  {
660  	bool delete;
661  	struct range *new, *old;
662  
663  	for (; n > 0; n--) {
664  		new = &de[n].new;
665  		old = &de[n].old;
666  
667  		delete = (new->from == new->to);
668  		if (de[n].type == DIFF_TYPE1) {
669  			if (delete)
670  				printf("%dd\n", new->from - 1);
671  			else if (old->from == new->from && old->to == new->to) {
672  				printf("%dc\n", old->from);
673  				printrange(fp[2], old);
674  				printf(".\n");
675  			}
676  			continue;
677  		} else {
678  			if (!oflag || !overlap[n]) {
679  				prange(old, delete);
680  			} else {
681  				printf("%da\n", old->to - 1);
682  				printf("%s\n", divider);
683  			}
684  			printrange(fp[2], new);
685  			if (!oflag || !overlap[n]) {
686  				if (!delete)
687  					printf(".\n");
688  			} else {
689  				printf("%s %s\n.\n", newmark, f3mark);
690  				printf("%da\n%s %s\n.\n", old->from - 1,
691  					oldmark, f1mark);
692  			}
693  		}
694  	}
695  	if (iflag)
696  		printf("w\nq\n");
697  
698  	exit(eflag == EFLAG_NONE ? overlapcnt : 0);
699  }
700  
701  /*
702   * Output an edit script to turn mine into yours, when there is a conflict
703   * between the 3 files bracket the changes. Regurgitate the diffs in reverse
704   * order to allow the ed script to track down where the lines are as changes
705   * are made.
706   */
707  static void
708  Ascript(int n)
709  {
710  	int startmark;
711  	bool deletenew;
712  	bool deleteold;
713  
714  	struct range *new, *old;
715  
716  	for (; n > 0; n--) {
717  		new = &de[n].new;
718  		old = &de[n].old;
719  		deletenew = (new->from == new->to);
720  		deleteold = (old->from == old->to);
721  
722  		if (de[n].type == DIFF_TYPE2) {
723  			if (!oflag || !overlap[n]) {
724  				prange(old, deletenew);
725  				printrange(fp[2], new);
726  			} else {
727  				startmark = new->to - 1;
728  
729  				printf("%da\n", startmark);
730  				printf("%s %s\n", newmark, f3mark);
731  
732  				printf(".\n");
733  
734  				printf("%da\n", startmark -
735  					(new->to - new->from));
736  				printf("%s %s\n", oldmark, f2mark);
737  				if (!deleteold)
738  					printrange(fp[1], old);
739  				printf("%s\n.\n", divider);
740  			}
741  
742  		} else if (de[n].type == DIFF_TYPE3) {
743  			startmark = old->to - 1;
744  
745  			if (!oflag || !overlap[n]) {
746  				prange(old, deletenew);
747  				printrange(fp[2], new);
748  			} else {
749  				printf("%da\n", startmark);
750  				printf("%s %s\n", orgmark, f2mark);
751  
752  				if (deleteold) {
753  					struct range r;
754  					r.from = old->from-1;
755  					r.to = new->to;
756  					printrange(fp[1], &r);
757  				} else
758  					printrange(fp[1], old);
759  
760  				printf("%s\n", divider);
761  				printrange(fp[2], new);
762  			}
763  
764  			if (!oflag || !overlap[n]) {
765  				if (!deletenew)
766  					printf(".\n");
767  			} else {
768  				printf("%s %s\n.\n", newmark, f3mark);
769  
770  				/*
771  				 * Go to the start of the conflict in original
772  				 * file and append lines
773  				 */
774  				printf("%da\n%s %s\n.\n",
775  					startmark - (old->to - old->from),
776  					oldmark, f1mark);
777  			}
778  		}
779  	}
780  	if (iflag)
781  		printf("w\nq\n");
782  
783  	exit(overlapcnt > 0);
784  }
785  
786  /*
787   * Output the merged file directly (don't generate an ed script). When
788   * regurgitating diffs we need to walk forward through the file and print any
789   * inbetween lines.
790   */
791  static void
792  mergescript(int i)
793  {
794  	struct range r, *new, *old;
795  	int n;
796  	bool delete = false;
797  
798  	r.from = 1;
799  	r.to = 1;
800  
801  	for (n = 1; n <= i; n++) {
802  		new = &de[n].new;
803  		old = &de[n].old;
804  
805  		/*
806  		 * Print any lines leading up to here. If we are merging don't
807  		 * print deleted ranges.
808  		 */
809  		delete = (new->from == new->to);
810  		if (de[n].type == DIFF_TYPE1 && delete)
811  			r.to = new->from - 1;
812  		else if (de[n].type == DIFF_TYPE3 && (old->from == old->to)) {
813  			r.from = old->from - 1;
814  			r.to = new->from;
815  		} else
816  			r.to = old->from;
817  
818  		printrange(fp[0], &r);
819  		switch (de[n].type) {
820  		case DIFF_TYPE1:
821  			/* If this isn't a delete print it */
822  			if (!delete)
823  				printrange(fp[2], new);
824  			break;
825  		case DIFF_TYPE2:
826  			printf("%s %s\n", oldmark, f2mark);
827  			printrange(fp[1], old);
828  			printf("%s\n", divider);
829  			printrange(fp[2], new);
830  			printf("%s %s\n", newmark, f3mark);
831  			break;
832  		case DIFF_TYPE3:
833  			if (!oflag || !overlap[n]) {
834  				printrange(fp[2], new);
835  			} else {
836  
837  				printf("%s %s\n", oldmark, f1mark);
838  				printrange(fp[0], old);
839  
840  				if (eflag != EFLAG_OVERLAP) {
841  					printf("%s %s\n", orgmark, f2mark);
842  					if (old->from == old->to) {
843  						struct range or;
844  						or.from = old->from - 1;
845  						or.to = new->to;
846  						printrange(fp[1], &or);
847  					} else {
848  						printrange(fp[1], old);
849  					}
850  				}
851  
852  				printf("%s\n", divider);
853  
854  				printrange(fp[2], new);
855  				printf("%s %s\n", newmark, f3mark);
856  			}
857  			break;
858  		default:
859  			printf("Error: Unhandled diff type - exiting\n");
860  			exit(EXIT_FAILURE);
861  		}
862  
863  		if (old->from == old->to)
864  			r.from = new->to;
865  		else
866  			r.from = old->to;
867  	}
868  
869  	/*
870  	 * Print from the final range to the end of 'myfile'. Any deletions or
871  	 * additions to this file should have been handled by now.
872  	 *
873  	 * If the ranges are the same we need to rewind a line.
874  	 * If the new range is 0 length (from == to), we need to use the old
875  	 * range.
876  	 */
877  	new = &de[n-1].new;
878  	old = &de[n-1].old;
879  
880  	if (old->from == new->from && old->to == new->to)
881  		r.from--;
882  	else if (new->from == new->to)
883  		r.from = old->from;
884  
885  	r.to = INT_MAX;
886  	printrange(fp[2], &r);
887  	exit(overlapcnt > 0);
888  }
889  
890  static void
891  increase(void)
892  {
893  	struct diff *p;
894  	char *q;
895  	size_t newsz, incr;
896  
897  	/* are the memset(3) calls needed? */
898  	newsz = szchanges == 0 ? 64 : 2 * szchanges;
899  	incr = newsz - szchanges;
900  
901  	p = reallocarray(d13, newsz, sizeof(*p));
902  	if (p == NULL)
903  		err(1, NULL);
904  	memset(p + szchanges, 0, incr * sizeof(*p));
905  	d13 = p;
906  	p = reallocarray(d23, newsz, sizeof(*p));
907  	if (p == NULL)
908  		err(1, NULL);
909  	memset(p + szchanges, 0, incr * sizeof(*p));
910  	d23 = p;
911  	p = reallocarray(de, newsz, sizeof(*p));
912  	if (p == NULL)
913  		err(1, NULL);
914  	memset(p + szchanges, 0, incr * sizeof(*p));
915  	de = p;
916  	q = reallocarray(overlap, newsz, 1);
917  	if (q == NULL)
918  		err(1, NULL);
919  	memset(q + szchanges, 0, incr * 1);
920  	overlap = q;
921  	szchanges = newsz;
922  }
923  
924  
925  int
926  main(int argc, char **argv)
927  {
928  	int ch, nblabels, status, m, n, kq, nke, nleft, i;
929  	char *labels[] = { NULL, NULL, NULL };
930  	const char *diffprog = DIFF_PATH;
931  	char *file1, *file2, *file3;
932  	char *diffargv[7];
933  	int diffargc = 0;
934  	int fd13[2], fd23[2];
935  	int pd13, pd23;
936  	cap_rights_t rights_ro;
937  	struct kevent *e;
938  
939  	nblabels = 0;
940  	eflag = EFLAG_NONE;
941  	oflag = 0;
942  	diffargv[diffargc++] = __DECONST(char *, diffprog);
943  	while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
944  		switch (ch) {
945  		case '3':
946  			eflag = EFLAG_NOOVERLAP;
947  			break;
948  		case 'a':
949  			diffargv[diffargc++] = __DECONST(char *, "-a");
950  			break;
951  		case 'A':
952  			Aflag = 1;
953  			break;
954  		case 'e':
955  			eflag = EFLAG_UNMERGED;
956  			break;
957  		case 'E':
958  			eflag = EFLAG_OVERLAP;
959  			oflag = 1;
960  			break;
961  		case 'i':
962  			iflag = 1;
963  			break;
964  		case 'L':
965  			oflag = 1;
966  			if (nblabels >= 3)
967  				errx(2, "too many file label options");
968  			labels[nblabels++] = optarg;
969  			break;
970  		case 'm':
971  			Aflag = 1;
972  			oflag = 1;
973  			mflag = 1;
974  			break;
975  		case 'T':
976  			Tflag = 1;
977  			break;
978  		case 'x':
979  			eflag = EFLAG_OVERLAP;
980  			break;
981  		case 'X':
982  			oflag = 1;
983  			eflag = EFLAG_OVERLAP;
984  			break;
985  		case DIFFPROG_OPT:
986  			diffprog = optarg;
987  			break;
988  		case STRIPCR_OPT:
989  			strip_cr = 1;
990  			diffargv[diffargc++] = __DECONST(char *, "--strip-trailing-cr");
991  			break;
992  		case HELP_OPT:
993  			usage();
994  			exit(0);
995  		case VERSION_OPT:
996  			printf("%s\n", diff3_version);
997  			exit(0);
998  		}
999  	}
1000  	argc -= optind;
1001  	argv += optind;
1002  
1003  	if (Aflag) {
1004  		if (eflag == EFLAG_NONE)
1005  			eflag = EFLAG_UNMERGED;
1006  		oflag = 1;
1007  	}
1008  
1009  	if (argc != 3) {
1010  		usage();
1011  		exit(2);
1012  	}
1013  
1014  	if (caph_limit_stdio() == -1)
1015  		err(2, "unable to limit stdio");
1016  
1017  	cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK);
1018  
1019  	kq = kqueue();
1020  	if (kq == -1)
1021  		err(2, "kqueue");
1022  
1023  	e = malloc(2 * sizeof(*e));
1024  	if (e == NULL)
1025  		err(2, "malloc");
1026  
1027  	/* TODO stdio */
1028  	file1 = argv[0];
1029  	file2 = argv[1];
1030  	file3 = argv[2];
1031  
1032  	if (oflag) {
1033  		asprintf(&f1mark, "%s",
1034  		    labels[0] != NULL ? labels[0] : file1);
1035  		if (f1mark == NULL)
1036  			err(2, "asprintf");
1037  		asprintf(&f2mark, "%s",
1038  		    labels[1] != NULL ? labels[1] : file2);
1039  		if (f2mark == NULL)
1040  			err(2, "asprintf");
1041  		asprintf(&f3mark, "%s",
1042  		    labels[2] != NULL ? labels[2] : file3);
1043  		if (f3mark == NULL)
1044  			err(2, "asprintf");
1045  	}
1046  	fp[0] = fopen(file1, "r");
1047  	if (fp[0] == NULL)
1048  		err(2, "Can't open %s", file1);
1049  	if (caph_rights_limit(fileno(fp[0]), &rights_ro) < 0)
1050  		err(2, "unable to limit rights on: %s", file1);
1051  
1052  	fp[1] = fopen(file2, "r");
1053  	if (fp[1] == NULL)
1054  		err(2, "Can't open %s", file2);
1055  	if (caph_rights_limit(fileno(fp[1]), &rights_ro) < 0)
1056  		err(2, "unable to limit rights on: %s", file2);
1057  
1058  	fp[2] = fopen(file3, "r");
1059  	if (fp[2] == NULL)
1060  		err(2, "Can't open %s", file3);
1061  	if (caph_rights_limit(fileno(fp[2]), &rights_ro) < 0)
1062  		err(2, "unable to limit rights on: %s", file3);
1063  
1064  	if (pipe(fd13))
1065  		err(2, "pipe");
1066  	if (pipe(fd23))
1067  		err(2, "pipe");
1068  
1069  	diffargv[diffargc] = file1;
1070  	diffargv[diffargc + 1] = file3;
1071  	diffargv[diffargc + 2] = NULL;
1072  
1073  	nleft = 0;
1074  	pd13 = diffexec(diffprog, diffargv, fd13);
1075  	EV_SET(e + nleft , pd13, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL);
1076  	if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
1077  		err(2, "kevent1");
1078  	nleft++;
1079  
1080  	diffargv[diffargc] = file2;
1081  	pd23 = diffexec(diffprog, diffargv, fd23);
1082  	EV_SET(e + nleft , pd23, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, NULL);
1083  	if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
1084  		err(2, "kevent2");
1085  	nleft++;
1086  
1087  	caph_cache_catpages();
1088  	if (caph_enter() < 0)
1089  		err(2, "unable to enter capability mode");
1090  
1091  	/* parse diffs */
1092  	increase();
1093  	m = readin(fd13[0], &d13);
1094  	n = readin(fd23[0], &d23);
1095  
1096  	/* waitpid cooked over pdforks */
1097  	while (nleft > 0) {
1098  		nke = kevent(kq, NULL, 0, e, nleft, NULL);
1099  		if (nke == -1)
1100  			err(2, "kevent");
1101  		for (i = 0; i < nke; i++) {
1102  			status = e[i].data;
1103  			if (WIFEXITED(status) && WEXITSTATUS(status) >= 2)
1104  				errx(2, "diff exited abnormally");
1105  			else if (WIFSIGNALED(status))
1106  				errx(2, "diff killed by signal %d",
1107  				    WTERMSIG(status));
1108  		}
1109  		nleft -= nke;
1110  	}
1111  	free(e);
1112  	merge(m, n);
1113  
1114  	return (EXIT_SUCCESS);
1115  }
1116