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 191 usage(void) 192 { 193 fprintf(stderr, "usage: diff3 [-3aAeEimTxX] [-L label1] [-L label2] " 194 "[-L label3] file1 file2 file3\n"); 195 } 196 197 static int 198 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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