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