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