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