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