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