1 /* $OpenBSD: diff3prog.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $ */
2
3 /*
4 * SPDX-License-Identifier: Caldera-no-preamble AND BSD-3-Clause
5 *
6 * Copyright (C) Caldera International Inc. 2001-2002.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code and documentation must retain the above
13 * copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed or owned by Caldera
20 * International, Inc.
21 * 4. Neither the name of Caldera International, Inc. nor the names of other
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
26 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
30 * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*-
39 * Copyright (c) 1991, 1993
40 * The Regents of the University of California. All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 */
66
67 #include <sys/types.h>
68 #include <sys/capsicum.h>
69 #include <sys/procdesc.h>
70 #include <sys/wait.h>
71
72 #include <assert.h>
73 #include <capsicum_helpers.h>
74 #include <ctype.h>
75 #include <err.h>
76 #include <getopt.h>
77 #include <inttypes.h>
78 #include <limits.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <unistd.h>
83
84 /*
85 * "from" is first in range of changed lines; "to" is last+1
86 * from=to=line after point of insertion for added lines.
87 */
88 struct range {
89 int from;
90 int to;
91 };
92
93 enum difftype {
94 DIFF_NONE,
95 DIFF_TYPE1,
96 DIFF_TYPE2,
97 DIFF_TYPE3,
98 };
99
100 struct diff {
101 enum difftype type;
102
103 /* Ranges as lines */
104 struct range old;
105 struct range new;
106 };
107
108 #define EFLAG_NONE 0
109 #define EFLAG_OVERLAP 1
110 #define EFLAG_NOOVERLAP 2
111 #define EFLAG_UNMERGED 3
112
113 static size_t szchanges;
114
115 static struct diff *d13;
116 static struct diff *d23;
117 /*
118 * "de" is used to gather editing scripts. These are later spewed out in
119 * reverse order. Its first element must be all zero, the "old" and "new"
120 * components of "de" contain line positions. Array overlap indicates which
121 * sections in "de" correspond to lines that are different in all three files.
122 */
123 static struct diff *de;
124 static char *overlap;
125 static int *de_delta; /* file1-file3 line number delta per edit */
126 static int overlapcnt;
127 static FILE *fp[3];
128 static int cline[3]; /* # of the last-read line in each file (0-2) */
129 /*
130 * The latest known correspondence between line numbers of the 3 files
131 * is stored in last[1-3];
132 */
133 static int last[4];
134 static int Aflag, eflag, iflag, mflag, Tflag;
135 static int oflag; /* indicates whether to mark overlaps (-E or -X) */
136 static int strip_cr;
137 static char *f1mark, *f2mark, *f3mark;
138 static const char *oldmark = "<<<<<<<";
139 static const char *orgmark = "|||||||";
140 static const char *newmark = ">>>>>>>";
141 static const char *divider = "=======";
142
143 static bool duplicate(struct range *, struct range *);
144 static int edit(struct diff *, bool, int, enum difftype);
145 static char *getchange(FILE *);
146 static char *get_line(FILE *, size_t *);
147 static int readin(int fd, struct diff **);
148 static int skip(int, int, const char *);
149 static void change(int, struct range *, bool);
150 static void keep(int, struct range *);
151 static void merge(int, int);
152 static void prange(struct range *, bool);
153 static void repos(int);
154 static void separate(const char *);
155 static void edscript(int) __dead2;
156 static void Ascript(int) __dead2;
157 static void mergescript(int, int) __dead2;
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 20260213";
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
usage(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
strtoi(char * str,char ** end)198 strtoi(char *str, char **end)
199 {
200 intmax_t num;
201
202 errno = 0;
203 num = strtoimax(str, end, 10);
204 if ((end != NULL && *end == str) ||
205 num < 0 || num > INT_MAX ||
206 errno == EINVAL || errno == ERANGE)
207 err(2, "error in diff output");
208 return (int)num;
209 }
210
211 /*
212 * Read diff hunks into the array pointed to by *dd.
213 *
214 * The output from `diff foo bar` consists of a series of hunks describing
215 * an addition (lines in bar not present in foo), change (lines in bar
216 * different from lines in foo), or deletion (lines in foo not present in
217 * bar). Each record starts with a line of the form:
218 *
219 * a[,b]xc[,d]
220 *
221 * where a, b, c, and d are nonnegative integers (b and d are printed only
222 * if they differ from a and c, respectively), and x is either 'a' for an
223 * addition, 'c' for a change, or 'd' for a deletion. This is then
224 * followed by a series of lines (which we ignore) giving the added,
225 * changed, or deleted text.
226 *
227 * For an addition, a == b is the last line in 'foo' before the addition,
228 * while c through d is the range of lines in 'bar' to be added to 'foo'.
229 *
230 * For a change, a through b is the range of lines in 'foo' to be replaced
231 * and c through d is the range of lines in 'bar' to replace them with.
232 *
233 * For a deletion, a through b is the range of lines in 'foo' to remove
234 * and c == d is the line in 'bar' which corresponds to the last line
235 * before the deletion.
236 *
237 * The observant reader will have noticed that x is not really needed and
238 * that we can fully describe any hunk using only a, b, c, and d:
239 *
240 * - an addition replaces a zero-length range in one file with a
241 * non-zero-length range from the other
242 *
243 * - a change replaces a non-zero-length range in one file with a
244 * non-zero-length range from the other
245 *
246 * - a deletion replaces a non-zero-length range in one file with a
247 * zero-length range from the other
248 */
249 static int
readin(int fd,struct diff ** dd)250 readin(int fd, struct diff **dd)
251 {
252 int a, b, c, d;
253 int i;
254 char kind, *p;
255 FILE *f;
256
257 f = fdopen(fd, "r");
258 if (f == NULL)
259 err(2, "fdopen");
260 for (i = 0; (p = getchange(f)) != NULL; i++) {
261 if ((size_t)i >= szchanges - 1)
262 increase();
263
264 a = b = strtoi(p, &p);
265 if (*p == ',')
266 b = strtoi(p + 1, &p);
267 kind = *p++;
268 c = d = strtoi(p, &p);
269 if (*p == ',')
270 d = strtoi(p + 1, &p);
271 if (*p != '\n')
272 errx(2, "error in diff output");
273 if (kind == 'a')
274 a++;
275 else if (kind == 'c')
276 /* nothing */ ;
277 else if (kind == 'd')
278 c++;
279 else
280 errx(2, "error in diff output");
281 b++;
282 d++;
283 if (b < a || d < c)
284 errx(2, "error in diff output");
285 (*dd)[i].old.from = a;
286 (*dd)[i].old.to = b;
287 (*dd)[i].new.from = c;
288 (*dd)[i].new.to = d;
289 if (i > 0) {
290 if ((*dd)[i].old.from < (*dd)[i - 1].old.to ||
291 (*dd)[i].new.from < (*dd)[i - 1].new.to)
292 errx(2, "diff output out of order");
293 }
294 }
295 if (i > 0) {
296 (*dd)[i].old.from = (*dd)[i].old.to = (*dd)[i - 1].old.to;
297 (*dd)[i].new.from = (*dd)[i].new.to = (*dd)[i - 1].new.to;
298 }
299 fclose(f);
300 return (i);
301 }
302
303 static int
diffexec(const char * diffprog,char ** diffargv,int fd[])304 diffexec(const char *diffprog, char **diffargv, int fd[])
305 {
306 int pd;
307
308 switch (pdfork(&pd, PD_CLOEXEC)) {
309 case 0:
310 close(fd[0]);
311 if (dup2(fd[1], STDOUT_FILENO) == -1)
312 err(2, "child could not duplicate descriptor");
313 close(fd[1]);
314 execvp(diffprog, diffargv);
315 err(2, "could not execute diff: %s", diffprog);
316 break;
317 case -1:
318 err(2, "could not fork");
319 break;
320 }
321 close(fd[1]);
322 return (pd);
323 }
324
325 static char *
getchange(FILE * b)326 getchange(FILE *b)
327 {
328 char *line;
329
330 while ((line = get_line(b, NULL)) != NULL) {
331 if (isdigit((unsigned char)line[0]))
332 return (line);
333 }
334 return (NULL);
335 }
336
337
338 static char *
get_line(FILE * b,size_t * n)339 get_line(FILE *b, size_t *n)
340 {
341 ssize_t len;
342 static char *buf = NULL;
343 static size_t bufsize = 0;
344
345 if ((len = getline(&buf, &bufsize, b)) < 0)
346 return (NULL);
347
348 if (strip_cr && len >= 2 && strcmp("\r\n", &(buf[len - 2])) == 0) {
349 buf[len - 2] = '\n';
350 buf[len - 1] = '\0';
351 len--;
352 }
353
354 if (n != NULL)
355 *n = len;
356
357 return (buf);
358 }
359
360 static void
merge(int m1,int m2)361 merge(int m1, int m2)
362 {
363 struct diff *d1, *d2, *d3;
364 int j, t1, t2;
365 int f1f3delta;
366 bool dup = false;
367
368 d1 = d13;
369 d2 = d23;
370 j = 0;
371 f1f3delta = 0;
372
373 for (;;) {
374 t1 = (d1 < d13 + m1);
375 t2 = (d2 < d23 + m2);
376 if (!t1 && !t2)
377 break;
378
379 /* first file is different from the others */
380 if (!t2 || (t1 && d1->new.to < d2->new.from)) {
381 /* stuff peculiar to 1st file */
382 if (eflag == EFLAG_NONE) {
383 separate("1");
384 change(1, &d1->old, false);
385 keep(2, &d1->new);
386 change(3, &d1->new, false);
387 } else if (mflag) {
388 j++;
389 de[j].type = DIFF_TYPE1;
390 de[j].old = d1->old;
391 de[j].new = d1->new;
392 overlap[j] = 0;
393 } else if (eflag == EFLAG_OVERLAP) {
394 j = edit(d2, dup, j, DIFF_TYPE1);
395 }
396 f1f3delta += (d1->old.to - d1->old.from) -
397 (d1->new.to - d1->new.from);
398 d1++;
399 continue;
400 }
401 /* second file is different from others */
402 if (!t1 || (t2 && d2->new.to < d1->new.from)) {
403 if (eflag == EFLAG_NONE) {
404 separate("2");
405 keep(1, &d2->new);
406 change(3, &d2->new, false);
407 change(2, &d2->old, false);
408 } else if (Aflag || mflag) {
409 if (eflag == EFLAG_UNMERGED) {
410 j = edit(d2, dup, j, DIFF_TYPE2);
411 de_delta[j] = f1f3delta;
412 }
413 }
414 d2++;
415 continue;
416 }
417 /*
418 * Merge overlapping changes in first file
419 * this happens after extension (see below).
420 */
421 if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) {
422 d1[1].old.from = d1->old.from;
423 d1[1].new.from = d1->new.from;
424 d1++;
425 continue;
426 }
427
428 /* merge overlapping changes in second */
429 if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) {
430 d2[1].old.from = d2->old.from;
431 d2[1].new.from = d2->new.from;
432 d2++;
433 continue;
434 }
435 /* stuff peculiar to third file or different in all */
436 if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) {
437 dup = duplicate(&d1->old, &d2->old);
438 /*
439 * dup = 0 means all files differ
440 * dup = 1 means files 1 and 2 identical
441 */
442 if (eflag == EFLAG_NONE) {
443 separate(dup ? "3" : "");
444 change(1, &d1->old, dup);
445 change(2, &d2->old, false);
446 d3 = d1->old.to > d1->old.from ? d1 : d2;
447 change(3, &d3->new, false);
448 } else if (mflag) {
449 j++;
450 de[j].type = DIFF_TYPE3;
451 de[j].old = d1->old;
452 de[j].new = d1->new;
453 overlap[j] = !dup;
454 if (!dup)
455 overlapcnt++;
456 } else {
457 j = edit(d1, dup, j, DIFF_TYPE3);
458 }
459 dup = false;
460 f1f3delta += (d1->old.to - d1->old.from) -
461 (d1->new.to - d1->new.from);
462 d1++;
463 d2++;
464 continue;
465 }
466 /*
467 * Overlapping changes from file 1 and 2; extend changes
468 * appropriately to make them coincide.
469 */
470 if (d1->new.from < d2->new.from) {
471 d2->old.from -= d2->new.from - d1->new.from;
472 d2->new.from = d1->new.from;
473 } else if (d2->new.from < d1->new.from) {
474 d1->old.from -= d1->new.from - d2->new.from;
475 d1->new.from = d2->new.from;
476 }
477 if (d1->new.to > d2->new.to) {
478 d2->old.to += d1->new.to - d2->new.to;
479 d2->new.to = d1->new.to;
480 } else if (d2->new.to > d1->new.to) {
481 d1->old.to += d2->new.to - d1->new.to;
482 d1->new.to = d2->new.to;
483 }
484 }
485
486 if (mflag)
487 mergescript(j, f1f3delta);
488 else if (Aflag)
489 Ascript(j);
490 else if (eflag)
491 edscript(j);
492 }
493
494 static void
separate(const char * s)495 separate(const char *s)
496 {
497 printf("====%s\n", s);
498 }
499
500 /*
501 * The range of lines rold.from thru rold.to in file i is to be changed.
502 * It is to be printed only if it does not duplicate something to be
503 * printed later.
504 */
505 static void
change(int i,struct range * rold,bool dup)506 change(int i, struct range *rold, bool dup)
507 {
508
509 printf("%d:", i);
510 last[i] = rold->to;
511 prange(rold, false);
512 if (dup)
513 return;
514 i--;
515 skip(i, rold->from, NULL);
516 skip(i, rold->to, " ");
517 }
518
519 /*
520 * Print the range of line numbers, rold.from thru rold.to, as n1,n2 or
521 * n1.
522 */
523 static void
prange(struct range * rold,bool delete)524 prange(struct range *rold, bool delete)
525 {
526
527 if (rold->to <= rold->from)
528 printf("%da\n", rold->from - 1);
529 else {
530 printf("%d", rold->from);
531 if (rold->to > rold->from + 1)
532 printf(",%d", rold->to - 1);
533 if (delete)
534 printf("d\n");
535 else
536 printf("c\n");
537 }
538 }
539
540 /*
541 * No difference was reported by diff between file 1 (or 2) and file 3,
542 * and an artificial dummy difference (trange) must be ginned up to
543 * correspond to the change reported in the other file.
544 */
545 static void
keep(int i,struct range * rnew)546 keep(int i, struct range *rnew)
547 {
548 int delta;
549 struct range trange;
550
551 delta = last[3] - last[i];
552 trange.from = rnew->from - delta;
553 trange.to = rnew->to - delta;
554 change(i, &trange, true);
555 }
556
557 /*
558 * skip to just before line number from in file "i". If "pr" is non-NULL,
559 * print all skipped stuff with string pr as a prefix.
560 */
561 static int
skip(int i,int from,const char * pr)562 skip(int i, int from, const char *pr)
563 {
564 size_t j, n;
565 char *line;
566
567 for (n = 0; cline[i] < from - 1; n += j) {
568 if ((line = get_line(fp[i], &j)) == NULL)
569 errx(2, "logic error");
570 if (pr != NULL)
571 printf("%s%s", Tflag == 1 ? "\t" : pr, line);
572 cline[i]++;
573 }
574 return ((int) n);
575 }
576
577 /*
578 * Return 1 or 0 according as the old range (in file 1) contains exactly
579 * the same data as the new range (in file 2).
580 */
581 static bool
duplicate(struct range * r1,struct range * r2)582 duplicate(struct range *r1, struct range *r2)
583 {
584 int c, d;
585 int nchar;
586 int nline;
587
588 if (r1->to-r1->from != r2->to-r2->from)
589 return (0);
590 skip(0, r1->from, NULL);
591 skip(1, r2->from, NULL);
592 nchar = 0;
593 for (nline = 0; nline < r1->to - r1->from; nline++) {
594 do {
595 c = getc(fp[0]);
596 d = getc(fp[1]);
597 if (c == -1 && d == -1)
598 break;
599 if (c == -1 || d == -1)
600 errx(2, "logic error");
601 nchar++;
602 if (c != d) {
603 repos(nchar);
604 return (0);
605 }
606 } while (c != '\n');
607 }
608 repos(nchar);
609 return (1);
610 }
611
612 static void
repos(int nchar)613 repos(int nchar)
614 {
615 int i;
616
617 for (i = 0; i < 2; i++)
618 (void)fseek(fp[i], (long)-nchar, SEEK_CUR);
619 }
620
621 /*
622 * collect an editing script for later regurgitation
623 */
624 static int
edit(struct diff * diff,bool dup,int j,enum difftype difftype)625 edit(struct diff *diff, bool dup, int j, enum difftype difftype)
626 {
627 if (!(eflag == EFLAG_UNMERGED ||
628 (!dup && eflag == EFLAG_OVERLAP ) ||
629 (dup && eflag == EFLAG_NOOVERLAP))) {
630 return (j);
631 }
632 j++;
633 overlap[j] = !dup;
634 if (!dup)
635 overlapcnt++;
636
637 de[j].type = difftype;
638 de[j].old.from = diff->old.from;
639 de[j].old.to = diff->old.to;
640 de[j].new.from = diff->new.from;
641 de[j].new.to = diff->new.to;
642 return (j);
643 }
644
645 static void
printrange(FILE * p,struct range * r)646 printrange(FILE *p, struct range *r)
647 {
648 char *line = NULL;
649 size_t len = 0;
650 int i = 1;
651
652 /* We haven't been asked to print anything */
653 if (r->from == r->to)
654 return;
655
656 if (r->from > r->to)
657 errx(2, "invalid print range");
658
659 /*
660 * XXX-THJ: We read through all of the file for each range printed.
661 * This duplicates work and will probably impact performance on large
662 * files with lots of ranges.
663 */
664 fseek(p, 0L, SEEK_SET);
665 while (getline(&line, &len, p) > 0) {
666 if (i >= r->from)
667 printf("%s", line);
668 if (++i > r->to - 1)
669 break;
670 }
671 free(line);
672 }
673
674 /* regurgitate */
675 static void
edscript(int n)676 edscript(int n)
677 {
678 bool delete;
679 struct range *new, *old;
680
681 for (; n > 0; n--) {
682 new = &de[n].new;
683 old = &de[n].old;
684
685 delete = (new->from == new->to);
686 if (de[n].type == DIFF_TYPE1) {
687 if (delete)
688 printf("%dd\n", new->from - 1);
689 else if (old->from == new->from && old->to == new->to) {
690 printf("%dc\n", old->from);
691 printrange(fp[2], old);
692 printf(".\n");
693 }
694 continue;
695 } else {
696 if (!oflag || !overlap[n]) {
697 prange(old, delete);
698 } else {
699 printf("%da\n", old->to - 1);
700 printf("%s\n", divider);
701 }
702 printrange(fp[2], new);
703 if (!oflag || !overlap[n]) {
704 if (!delete)
705 printf(".\n");
706 } else {
707 printf("%s %s\n.\n", newmark, f3mark);
708 printf("%da\n%s %s\n.\n", old->from - 1,
709 oldmark, f1mark);
710 }
711 }
712 }
713 if (iflag)
714 printf("w\nq\n");
715
716 exit(oflag ? overlapcnt > 0 : 0);
717 }
718
719 /*
720 * Output an edit script to turn mine into yours, when there is a conflict
721 * between the 3 files bracket the changes. Regurgitate the diffs in reverse
722 * order to allow the ed script to track down where the lines are as changes
723 * are made.
724 */
725 static void
Ascript(int n)726 Ascript(int n)
727 {
728 int startmark;
729 bool deletenew;
730 bool deleteold;
731
732 struct range *new, *old;
733
734 for (; n > 0; n--) {
735 new = &de[n].new;
736 old = &de[n].old;
737 deletenew = (new->from == new->to);
738 deleteold = (old->from == old->to);
739
740 if (de[n].type == DIFF_TYPE2) {
741 if (!oflag || !overlap[n]) {
742 prange(old, deletenew);
743 printrange(fp[2], new);
744 } else {
745 startmark = new->to - 1 + de_delta[n];
746
747 printf("%da\n", startmark);
748 printf("%s %s\n", newmark, f3mark);
749
750 printf(".\n");
751
752 printf("%da\n", startmark -
753 (new->to - new->from));
754 printf("%s %s\n", oldmark, f2mark);
755 if (!deleteold)
756 printrange(fp[1], old);
757 printf("%s\n.\n", divider);
758 }
759
760 } else if (de[n].type == DIFF_TYPE3) {
761 startmark = old->to - 1;
762
763 if (!oflag || !overlap[n]) {
764 prange(old, deletenew);
765 printrange(fp[2], new);
766 } else {
767 printf("%da\n", startmark);
768 printf("%s %s\n", orgmark, f2mark);
769
770 if (deleteold) {
771 struct range r;
772 r.from = old->from-1;
773 r.to = new->to;
774 printrange(fp[1], &r);
775 } else
776 printrange(fp[1], old);
777
778 printf("%s\n", divider);
779 printrange(fp[2], new);
780 }
781
782 if (!oflag || !overlap[n]) {
783 if (!deletenew)
784 printf(".\n");
785 } else {
786 printf("%s %s\n.\n", newmark, f3mark);
787
788 /*
789 * Go to the start of the conflict in original
790 * file and append lines
791 */
792 printf("%da\n%s %s\n.\n",
793 startmark - (old->to - old->from),
794 oldmark, f1mark);
795 }
796 }
797 }
798 if (iflag)
799 printf("w\nq\n");
800
801 exit(overlapcnt > 0);
802 }
803
804 /*
805 * Output the merged file directly (don't generate an ed script). When
806 * regurgitating diffs we need to walk forward through the file and print any
807 * inbetween lines.
808 */
809 static void
mergescript(int i,int f1f3delta)810 mergescript(int i, int f1f3delta)
811 {
812 struct range r, *new, *old;
813 int n;
814
815 r.from = 1;
816 r.to = 1;
817
818 for (n = 1; n <= i; n++) {
819 new = &de[n].new;
820 old = &de[n].old;
821
822 /*
823 * Print any lines leading up to here. If we are merging don't
824 * print deleted ranges.
825 */
826 if (de[n].type == DIFF_TYPE1)
827 r.to = old->to;
828 else if (de[n].type == DIFF_TYPE2)
829 r.to = new->from + de_delta[n];
830 else
831 r.to = old->from;
832
833 printrange(fp[0], &r);
834 switch (de[n].type) {
835 case DIFF_TYPE1:
836 /* Content included in "between" printing from fp[0] */
837 break;
838 case DIFF_TYPE2:
839 printf("%s %s\n", oldmark, f2mark);
840 printrange(fp[1], old);
841 printf("%s\n", divider);
842 printrange(fp[2], new);
843 printf("%s %s\n", newmark, f3mark);
844 break;
845 case DIFF_TYPE3:
846 if (!oflag || !overlap[n]) {
847 printrange(fp[2], new);
848 } else {
849
850 printf("%s %s\n", oldmark, f1mark);
851 printrange(fp[0], old);
852
853 if (eflag != EFLAG_OVERLAP) {
854 printf("%s %s\n", orgmark, f2mark);
855 if (old->from == old->to) {
856 struct range or;
857 or.from = old->from - 1;
858 or.to = new->to;
859 printrange(fp[1], &or);
860 } else {
861 printrange(fp[1], old);
862 }
863 }
864
865 printf("%s\n", divider);
866
867 printrange(fp[2], new);
868 printf("%s %s\n", newmark, f3mark);
869 }
870 break;
871 default:
872 __assert_unreachable();
873 }
874
875 if (de[n].type == DIFF_TYPE2)
876 r.from = new->to + de_delta[n];
877 else
878 r.from = old->to;
879 }
880
881 /*
882 * Print from the final range to the end of 'myfile'. Any deletions or
883 * additions to this file should have been handled by now.
884 */
885 r.from -= f1f3delta;
886 r.to = INT_MAX;
887 printrange(fp[2], &r);
888 exit(overlapcnt > 0);
889 }
890
891 static void
increase(void)892 increase(void)
893 {
894 struct diff *p;
895 char *q;
896 int *s;
897 size_t newsz, incr;
898
899 /* are the memset(3) calls needed? */
900 newsz = szchanges == 0 ? 64 : 2 * szchanges;
901 incr = newsz - szchanges;
902
903 p = reallocarray(d13, newsz, sizeof(*p));
904 if (p == NULL)
905 err(2, NULL);
906 memset(p + szchanges, 0, incr * sizeof(*p));
907 d13 = p;
908 p = reallocarray(d23, newsz, sizeof(*p));
909 if (p == NULL)
910 err(2, NULL);
911 memset(p + szchanges, 0, incr * sizeof(*p));
912 d23 = p;
913 p = reallocarray(de, newsz, sizeof(*p));
914 if (p == NULL)
915 err(2, NULL);
916 memset(p + szchanges, 0, incr * sizeof(*p));
917 de = p;
918 q = reallocarray(overlap, newsz, 1);
919 if (q == NULL)
920 err(2, NULL);
921 memset(q + szchanges, 0, incr * 1);
922 overlap = q;
923 s = reallocarray(de_delta, newsz, sizeof(*s));
924 if (s == NULL)
925 err(2, NULL);
926 memset(s + szchanges, 0, incr * sizeof(*s));
927 de_delta = s;
928 szchanges = newsz;
929 }
930
931 static void
wait_and_check(int pd)932 wait_and_check(int pd)
933 {
934 int status;
935
936 while (pdwait(pd, &status, WEXITED, NULL, NULL) == -1) {
937 if (errno != EINTR)
938 err(2, "pdwait");
939 }
940
941 if (WIFEXITED(status) && WEXITSTATUS(status) >= 2)
942 errx(2, "diff exited abnormally");
943 if (WIFSIGNALED(status))
944 errx(2, "diff killed by signal %d", WTERMSIG(status));
945 }
946
947 int
main(int argc,char ** argv)948 main(int argc, char **argv)
949 {
950 int ch, nblabels, m, n;
951 char *labels[] = { NULL, NULL, NULL };
952 const char *diffprog = DIFF_PATH;
953 char *file1, *file2, *file3;
954 char *diffargv[7];
955 int diffargc = 0;
956 int fd13[2], fd23[2];
957 int pd13, pd23;
958 cap_rights_t rights_ro;
959
960 nblabels = 0;
961 eflag = EFLAG_NONE;
962 oflag = 0;
963 diffargv[diffargc++] = __DECONST(char *, diffprog);
964 while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
965 switch (ch) {
966 case '3':
967 eflag = EFLAG_NOOVERLAP;
968 break;
969 case 'a':
970 diffargv[diffargc++] = __DECONST(char *, "-a");
971 break;
972 case 'A':
973 Aflag = 1;
974 break;
975 case 'e':
976 eflag = EFLAG_UNMERGED;
977 break;
978 case 'E':
979 eflag = EFLAG_OVERLAP;
980 oflag = 1;
981 break;
982 case 'i':
983 iflag = 1;
984 break;
985 case 'L':
986 oflag = 1;
987 if (nblabels >= 3)
988 errx(2, "too many file label options");
989 labels[nblabels++] = optarg;
990 break;
991 case 'm':
992 Aflag = 1;
993 oflag = 1;
994 mflag = 1;
995 break;
996 case 'T':
997 Tflag = 1;
998 break;
999 case 'x':
1000 eflag = EFLAG_OVERLAP;
1001 break;
1002 case 'X':
1003 oflag = 1;
1004 eflag = EFLAG_OVERLAP;
1005 break;
1006 case DIFFPROG_OPT:
1007 diffprog = optarg;
1008 break;
1009 case STRIPCR_OPT:
1010 strip_cr = 1;
1011 diffargv[diffargc++] = __DECONST(char *, "--strip-trailing-cr");
1012 break;
1013 case HELP_OPT:
1014 usage();
1015 exit(0);
1016 case VERSION_OPT:
1017 printf("%s\n", diff3_version);
1018 exit(0);
1019 }
1020 }
1021 argc -= optind;
1022 argv += optind;
1023
1024 if (Aflag) {
1025 if (eflag == EFLAG_NONE)
1026 eflag = EFLAG_UNMERGED;
1027 oflag = 1;
1028 }
1029
1030 if (argc != 3) {
1031 usage();
1032 exit(2);
1033 }
1034
1035 if (caph_limit_stdio() == -1)
1036 err(2, "unable to limit stdio");
1037
1038 cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK);
1039
1040 /* TODO stdio */
1041 file1 = argv[0];
1042 file2 = argv[1];
1043 file3 = argv[2];
1044
1045 if (oflag) {
1046 asprintf(&f1mark, "%s",
1047 labels[0] != NULL ? labels[0] : file1);
1048 if (f1mark == NULL)
1049 err(2, "asprintf");
1050 asprintf(&f2mark, "%s",
1051 labels[1] != NULL ? labels[1] : file2);
1052 if (f2mark == NULL)
1053 err(2, "asprintf");
1054 asprintf(&f3mark, "%s",
1055 labels[2] != NULL ? labels[2] : file3);
1056 if (f3mark == NULL)
1057 err(2, "asprintf");
1058 }
1059 fp[0] = fopen(file1, "r");
1060 if (fp[0] == NULL)
1061 err(2, "Can't open %s", file1);
1062 if (caph_rights_limit(fileno(fp[0]), &rights_ro) < 0)
1063 err(2, "unable to limit rights on: %s", file1);
1064
1065 fp[1] = fopen(file2, "r");
1066 if (fp[1] == NULL)
1067 err(2, "Can't open %s", file2);
1068 if (caph_rights_limit(fileno(fp[1]), &rights_ro) < 0)
1069 err(2, "unable to limit rights on: %s", file2);
1070
1071 fp[2] = fopen(file3, "r");
1072 if (fp[2] == NULL)
1073 err(2, "Can't open %s", file3);
1074 if (caph_rights_limit(fileno(fp[2]), &rights_ro) < 0)
1075 err(2, "unable to limit rights on: %s", file3);
1076
1077 if (pipe(fd13))
1078 err(2, "pipe");
1079 if (pipe(fd23))
1080 err(2, "pipe");
1081
1082 diffargv[diffargc] = file1;
1083 diffargv[diffargc + 1] = file3;
1084 diffargv[diffargc + 2] = NULL;
1085 pd13 = diffexec(diffprog, diffargv, fd13);
1086
1087 diffargv[diffargc] = file2;
1088 pd23 = diffexec(diffprog, diffargv, fd23);
1089
1090 caph_cache_catpages();
1091 if (caph_enter() < 0)
1092 err(2, "unable to enter capability mode");
1093
1094 /* parse diffs */
1095 increase();
1096 m = readin(fd13[0], &d13);
1097 n = readin(fd23[0], &d23);
1098
1099 wait_and_check(pd13);
1100 wait_and_check(pd23);
1101
1102 merge(m, n);
1103
1104 exit(0);
1105 }
1106