xref: /freebsd/usr.bin/diff3/diff3.c (revision 5e3934b1)
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
usage(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
readin(int fd,struct diff ** dd)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
diffexec(const char * diffprog,char ** diffargv,int fd[])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 *
getchange(FILE * b)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 *
get_line(FILE * b,size_t * n)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
merge(int m1,int m2)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
change(int i,struct range * rold,bool dup)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
prange(struct range * rold,bool delete)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
keep(int i,struct range * rnew)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
skip(int i,int from,const char * pr)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
duplicate(struct range * r1,struct range * r2)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
repos(int nchar)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
edit(struct diff * diff,bool dup,int j,int difftype)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
printrange(FILE * p,struct range * r)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
edscript(int n)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
Ascript(int n)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
mergescript(int i)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
increase(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
main(int argc,char ** argv)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