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