1 /* $OpenBSD: diff3.c,v 1.48 2008/03/09 01:52:55 joris 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 #ifndef lint 68 static const char copyright[] = 69 "@(#) Copyright (c) 1991, 1993\n\ 70 The Regents of the University of California. All rights reserved.\n"; 71 #endif /* not lint */ 72 73 #ifndef lint 74 static const char rcsid[] = 75 "$OpenBSD: diff3.c,v 1.48 2008/03/09 01:52:55 joris Exp $"; 76 #endif /* not lint */ 77 78 #include <ctype.h> 79 #include <errno.h> 80 #include <fcntl.h> 81 #include <stdio.h> 82 #include <stdlib.h> 83 #include <string.h> 84 #include <unistd.h> 85 86 #include "atomicio.h" 87 #include "cvs.h" 88 #include "diff.h" 89 90 /* diff3 - 3-way differential file comparison */ 91 92 /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] 93 * 94 * d13 = diff report on f1 vs f3 95 * d23 = diff report on f2 vs f3 96 * f1, f2, f3 the 3 files 97 * if changes in f1 overlap with changes in f3, m1 and m3 are used 98 * to mark the overlaps; otherwise, the file names f1 and f3 are used 99 * (only for options E and X). 100 */ 101 102 /* 103 * "from" is first in range of changed lines; "to" is last+1 104 * from=to=line after point of insertion for added lines. 105 */ 106 struct range { 107 int from; 108 int to; 109 }; 110 111 struct diff { 112 struct range old; 113 struct range new; 114 }; 115 116 static size_t szchanges; 117 118 static struct diff *d13 = NULL; 119 static struct diff *d23 = NULL; 120 121 /* 122 * "de" is used to gather editing scripts. These are later spewed out in 123 * reverse order. Its first element must be all zero, the "new" component 124 * of "de" contains line positions or byte positions depending on when you 125 * look (!?). Array overlap indicates which sections in "de" correspond to 126 * lines that are different in all three files. 127 */ 128 static struct diff *de = NULL; 129 static char *overlap = NULL; 130 static int overlapcnt = 0; 131 static FILE *fp[3]; 132 static int cline[3]; /* # of the last-read line in each file (0-2) */ 133 134 /* 135 * the latest known correspondence between line numbers of the 3 files 136 * is stored in last[1-3]; 137 */ 138 static int last[4]; 139 static int eflag; 140 static int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 141 static int debug = 0; 142 static char f1mark[MAXPATHLEN], f3mark[MAXPATHLEN]; /* markers for -E and -X */ 143 144 static int duplicate(struct range *, struct range *); 145 static int edit(struct diff *, int, int); 146 static char *getchange(FILE *); 147 static char *getline(FILE *, size_t *); 148 static int number(char **); 149 static size_t readin(int, struct diff **); 150 static int skip(int, int, char *); 151 static int edscript(int); 152 static int merge(size_t, size_t); 153 static void change(int, struct range *, int); 154 static void keep(int, struct range *); 155 static void prange(struct range *); 156 static void repos(int); 157 static void separate(const char *); 158 static void increase(void); 159 static int diff3_internal(int, char **, const char *, const char *); 160 161 int diff3_conflicts = 0; 162 RCSNUM *d3rev1 = NULL; 163 RCSNUM *d3rev2 = NULL; 164 165 static int fds[5]; 166 167 void 168 cvs_merge_file(struct cvs_file *cf, int verbose) 169 { 170 int i, argc; 171 char *data, *patch; 172 char *argv[5], r1[CVS_REV_BUFSZ], r2[CVS_REV_BUFSZ]; 173 char *dp13, *dp23, *path1, *path2, *path3; 174 BUF *b1, *b2, *b3, *d1, *d2, *diffb; 175 size_t dlen, plen; 176 struct cvs_line *lp; 177 struct cvs_lines *dlines, *plines; 178 179 overlapcnt = 0; 180 b1 = b2 = b3 = d1 = d2 = diffb = NULL; 181 182 rcsnum_tostr(d3rev1, r1, sizeof(r1)); 183 rcsnum_tostr(d3rev2, r2, sizeof(r2)); 184 185 b1 = cvs_buf_load_fd(cf->fd); 186 d1 = cvs_buf_alloc(128); 187 d2 = cvs_buf_alloc(128); 188 diffb = cvs_buf_alloc(128); 189 190 (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 191 (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 192 (void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", cvs_tmpdir); 193 194 fds[2] = cvs_buf_write_stmp(b1, path1, NULL); 195 if (verbose == 1) 196 cvs_printf("Retrieving revision %s\n", r1); 197 fds[3] = rcs_rev_write_stmp(cf->file_rcs, d3rev1, path2, 0); 198 if (verbose == 1) 199 cvs_printf("Retrieving revision %s\n", r2); 200 fds[4] = rcs_rev_write_stmp(cf->file_rcs, d3rev2, path3, 0); 201 202 cvs_diffreg(path1, path3, fds[2], fds[4], d1); 203 cvs_diffreg(path2, path3, fds[3], fds[4], d2); 204 205 (void)xasprintf(&dp13, "%s/d13.XXXXXXXXXX", cvs_tmpdir); 206 fds[0] = cvs_buf_write_stmp(d1, dp13, NULL); 207 cvs_buf_free(d1); 208 209 (void)xasprintf(&dp23, "%s/d23.XXXXXXXXXX", cvs_tmpdir); 210 fds[1] = cvs_buf_write_stmp(d2, dp23, NULL); 211 cvs_buf_free(d2); 212 213 argc = 0; 214 diffbuf = diffb; 215 argv[argc++] = dp13; 216 argv[argc++] = dp23; 217 argv[argc++] = path1; 218 argv[argc++] = path2; 219 argv[argc++] = path3; 220 221 if (lseek(fds[2], 0, SEEK_SET) < 0) 222 fatal("cvs_merge_file: lseek fds[2]: %s", strerror(errno)); 223 if (lseek(fds[3], 0, SEEK_SET) < 0) 224 fatal("cvs_merge_file: lseek fds[3]: %s", strerror(errno)); 225 if (lseek(fds[4], 0, SEEK_SET) < 0) 226 fatal("cvs_merge_file: lseek fds[4]: %s", strerror(errno)); 227 228 diff3_conflicts = diff3_internal(argc, argv, cf->file_path, r2); 229 if (diff3_conflicts < 0) 230 fatal("cvs_merge_file: merging failed for an unknown reason"); 231 232 plen = cvs_buf_len(diffb); 233 patch = cvs_buf_release(diffb); 234 dlen = cvs_buf_len(b1); 235 data = cvs_buf_release(b1); 236 237 if (verbose == 1) 238 cvs_printf("Merging differences between %s and %s into `%s'\n", 239 r1, r2, cf->file_path); 240 241 dlines = cvs_splitlines(data, dlen); 242 plines = cvs_splitlines(patch, plen); 243 244 ed_patch_lines(dlines, plines); 245 cvs_freelines(plines); 246 247 if (verbose == 1 && diff3_conflicts != 0) { 248 cvs_log(LP_ERR, "%d conflict%s found during merge, " 249 "please correct.", diff3_conflicts, 250 (diff3_conflicts > 1) ? "s" : ""); 251 } 252 253 (void)close(cf->fd); 254 cf->fd = open(cf->file_path, O_CREAT | O_RDWR | O_TRUNC, 0644); 255 if (cf->fd == -1) { 256 fatal("cvs_merge_file: failed to reopen fd for writing: %s", 257 strerror(errno)); 258 } 259 260 TAILQ_FOREACH(lp, &(dlines->l_lines), l_list) { 261 if (lp->l_line == NULL) 262 continue; 263 264 if (atomicio(vwrite, cf->fd, lp->l_line, lp->l_len) != 265 lp->l_len) 266 fatal("cvs_merge_file: %s", strerror(errno)); 267 } 268 269 cvs_freelines(dlines); 270 271 if (data != NULL) 272 xfree(data); 273 xfree(patch); 274 275 for (i = 0; i < 3; i++) 276 fclose(fp[i]); 277 278 cvs_worklist_run(&temp_files, cvs_worklist_unlink); 279 280 xfree(path1); 281 xfree(path2); 282 xfree(path3); 283 xfree(dp13); 284 xfree(dp23); 285 } 286 287 static int 288 diff3_internal(int argc, char **argv, const char *fmark, const char *rmark) 289 { 290 size_t m, n; 291 int i; 292 293 eflag = 3; 294 oflag = 1; 295 296 if (argc < 5) 297 return (-1); 298 299 (void)xsnprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", fmark); 300 (void)xsnprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", rmark); 301 302 szchanges = 0; 303 memset(last, 0, sizeof(last)); 304 memset(cline, 0, sizeof(cline)); 305 if (d13 != NULL) 306 xfree(d13); 307 if (d23 != NULL) 308 xfree(d23); 309 if (overlap != NULL) 310 xfree(overlap); 311 if (de != NULL) 312 xfree(de); 313 314 overlap = NULL; 315 de = d13 = d23 = NULL; 316 317 increase(); 318 319 /* fds[0] and fds[1] are closed in readin() */ 320 m = readin(fds[0], &d13); 321 n = readin(fds[1], &d23); 322 323 for (i = 0; i <= 2; i++) { 324 if ((fp[i] = fdopen(fds[i + 2], "r")) == NULL) { 325 cvs_log(LP_ERR, "%s", argv[i + 2]); 326 return (-1); 327 } 328 } 329 330 return (merge(m, n)); 331 } 332 333 int 334 ed_patch_lines(struct cvs_lines *dlines, struct cvs_lines *plines) 335 { 336 char op, *ep; 337 struct cvs_line *sort, *lp, *dlp, *ndlp, *insert_after; 338 int start, end, i, lineno; 339 u_char tmp; 340 341 dlp = TAILQ_FIRST(&(dlines->l_lines)); 342 lp = TAILQ_FIRST(&(plines->l_lines)); 343 344 end = 0; 345 for (lp = TAILQ_NEXT(lp, l_list); lp != NULL; 346 lp = TAILQ_NEXT(lp, l_list)) { 347 /* Skip blank lines */ 348 if (lp->l_len < 2) 349 continue; 350 351 /* NUL-terminate line buffer for strtol() safety. */ 352 tmp = lp->l_line[lp->l_len - 1]; 353 lp->l_line[lp->l_len - 1] = '\0'; 354 355 op = lp->l_line[strlen(lp->l_line) - 1]; 356 start = (int)strtol(lp->l_line, &ep, 10); 357 358 /* Restore the last byte of the buffer */ 359 lp->l_line[lp->l_len - 1] = tmp; 360 361 if (op == 'a') { 362 if (start > dlines->l_nblines || 363 start < 0 || *ep != 'a') 364 fatal("ed_patch_lines %d", start); 365 } else if (op == 'c') { 366 if (start > dlines->l_nblines || 367 start < 0 || (*ep != ',' && *ep != 'c')) 368 fatal("ed_patch_lines"); 369 370 if (*ep == ',') { 371 ep++; 372 end = (int)strtol(ep, &ep, 10); 373 if (end < 0 || *ep != 'c') 374 fatal("ed_patch_lines"); 375 } else { 376 end = start; 377 } 378 } else { 379 fatal("invalid op %c found while merging", op); 380 } 381 382 383 for (;;) { 384 if (dlp == NULL) 385 break; 386 if (dlp->l_lineno == start) 387 break; 388 if (dlp->l_lineno > start) { 389 dlp = TAILQ_PREV(dlp, cvs_tqh, l_list); 390 } else if (dlp->l_lineno < start) { 391 ndlp = TAILQ_NEXT(dlp, l_list); 392 if (ndlp->l_lineno > start) 393 break; 394 dlp = ndlp; 395 } 396 } 397 398 if (dlp == NULL) 399 fatal("ed_patch_lines"); 400 401 402 if (op == 'c') { 403 insert_after = TAILQ_PREV(dlp, cvs_tqh, l_list); 404 for (i = 0; i <= (end - start); i++) { 405 ndlp = TAILQ_NEXT(dlp, l_list); 406 TAILQ_REMOVE(&(dlines->l_lines), dlp, l_list); 407 dlp = ndlp; 408 } 409 dlp = insert_after; 410 } 411 412 if (op == 'a' || op == 'c') { 413 for (;;) { 414 ndlp = lp; 415 lp = TAILQ_NEXT(lp, l_list); 416 if (lp == NULL) 417 fatal("ed_patch_lines"); 418 419 if (lp->l_len == 2 && 420 lp->l_line[0] == '.' && 421 lp->l_line[1] == '\n') 422 break; 423 424 TAILQ_REMOVE(&(plines->l_lines), lp, l_list); 425 TAILQ_INSERT_AFTER(&(dlines->l_lines), dlp, 426 lp, l_list); 427 dlp = lp; 428 429 lp->l_lineno = start; 430 lp = ndlp; 431 } 432 } 433 434 /* 435 * always resort lines as the markers might be put at the 436 * same line as we first started editing. 437 */ 438 lineno = 0; 439 TAILQ_FOREACH(sort, &(dlines->l_lines), l_list) 440 sort->l_lineno = lineno++; 441 dlines->l_nblines = lineno - 1; 442 } 443 444 return (0); 445 } 446 447 /* 448 * Pick up the line numbers of all changes from one change file. 449 * (This puts the numbers in a vector, which is not strictly necessary, 450 * since the vector is processed in one sequential pass. 451 * The vector could be optimized out of existence) 452 */ 453 static size_t 454 readin(int fd, struct diff **dd) 455 { 456 int a, b, c, d; 457 char kind, *p; 458 size_t i; 459 460 fp[0] = fdopen(fd, "r"); 461 if (fp[0] == NULL) 462 fatal("readin: fdopen: %s", strerror(errno)); 463 464 for (i = 0; (p = getchange(fp[0])); i++) { 465 if (i >= szchanges - 1) 466 increase(); 467 a = b = number(&p); 468 if (*p == ',') { 469 p++; 470 b = number(&p); 471 } 472 kind = *p++; 473 c = d = number(&p); 474 if (*p==',') { 475 p++; 476 d = number(&p); 477 } 478 if (kind == 'a') 479 a++; 480 if (kind == 'd') 481 c++; 482 b++; 483 d++; 484 (*dd)[i].old.from = a; 485 (*dd)[i].old.to = b; 486 (*dd)[i].new.from = c; 487 (*dd)[i].new.to = d; 488 } 489 490 if (i) { 491 (*dd)[i].old.from = (*dd)[i-1].old.to; 492 (*dd)[i].new.from = (*dd)[i-1].new.to; 493 } 494 495 (void)fclose(fp[0]); 496 497 return (i); 498 } 499 500 static int 501 number(char **lc) 502 { 503 int nn; 504 505 nn = 0; 506 while (isdigit((unsigned char)(**lc))) 507 nn = nn*10 + *(*lc)++ - '0'; 508 509 return (nn); 510 } 511 512 static char * 513 getchange(FILE *b) 514 { 515 char *line; 516 517 while ((line = getline(b, NULL))) { 518 if (isdigit((unsigned char)line[0])) 519 return (line); 520 } 521 522 return (NULL); 523 } 524 525 static char * 526 getline(FILE *b, size_t *n) 527 { 528 char *cp; 529 size_t len; 530 static char *buf; 531 static size_t bufsize; 532 533 if ((cp = fgetln(b, &len)) == NULL) 534 return (NULL); 535 536 if (cp[len - 1] != '\n') 537 len++; 538 if (len + 1 > bufsize) { 539 do { 540 bufsize += 1024; 541 } while (len + 1 > bufsize); 542 buf = xrealloc(buf, 1, bufsize); 543 } 544 memcpy(buf, cp, len - 1); 545 buf[len - 1] = '\n'; 546 buf[len] = '\0'; 547 if (n != NULL) 548 *n = len; 549 550 return (buf); 551 } 552 553 static int 554 merge(size_t m1, size_t m2) 555 { 556 struct diff *d1, *d2, *d3; 557 int dpl, j, t1, t2; 558 559 d1 = d13; 560 d2 = d23; 561 j = 0; 562 while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 563 if (debug) { 564 printf("%d,%d=%d,%d %d,%d=%d,%d\n", 565 d1->old.from, d1->old.to, 566 d1->new.from, d1->new.to, 567 d2->old.from, d2->old.to, 568 d2->new.from, d2->new.to); 569 } 570 571 /* first file is different from others */ 572 if (!t2 || (t1 && d1->new.to < d2->new.from)) { 573 /* stuff peculiar to 1st file */ 574 if (eflag==0) { 575 separate("1"); 576 change(1, &d1->old, 0); 577 keep(2, &d1->new); 578 change(3, &d1->new, 0); 579 } 580 d1++; 581 continue; 582 } 583 584 /* second file is different from others */ 585 if (!t1 || (t2 && d2->new.to < d1->new.from)) { 586 if (eflag==0) { 587 separate("2"); 588 keep(1, &d2->new); 589 change(2, &d2->old, 0); 590 change(3, &d2->new, 0); 591 } 592 d2++; 593 continue; 594 } 595 596 /* 597 * Merge overlapping changes in first file 598 * this happens after extension (see below). 599 */ 600 if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 601 d1[1].old.from = d1->old.from; 602 d1[1].new.from = d1->new.from; 603 d1++; 604 continue; 605 } 606 607 /* merge overlapping changes in second */ 608 if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 609 d2[1].old.from = d2->old.from; 610 d2[1].new.from = d2->new.from; 611 d2++; 612 continue; 613 } 614 /* stuff peculiar to third file or different in all */ 615 if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 616 dpl = duplicate(&d1->old,&d2->old); 617 if (dpl == -1) 618 return (-1); 619 620 /* 621 * dpl = 0 means all files differ 622 * dpl = 1 means files 1 and 2 identical 623 */ 624 if (eflag==0) { 625 separate(dpl ? "3" : ""); 626 change(1, &d1->old, dpl); 627 change(2, &d2->old, 0); 628 d3 = d1->old.to > d1->old.from ? d1 : d2; 629 change(3, &d3->new, 0); 630 } else 631 j = edit(d1, dpl, j); 632 d1++; 633 d2++; 634 continue; 635 } 636 637 /* 638 * Overlapping changes from file 1 and 2; extend changes 639 * appropriately to make them coincide. 640 */ 641 if (d1->new.from < d2->new.from) { 642 d2->old.from -= d2->new.from-d1->new.from; 643 d2->new.from = d1->new.from; 644 } else if (d2->new.from < d1->new.from) { 645 d1->old.from -= d1->new.from-d2->new.from; 646 d1->new.from = d2->new.from; 647 } 648 if (d1->new.to > d2->new.to) { 649 d2->old.to += d1->new.to - d2->new.to; 650 d2->new.to = d1->new.to; 651 } else if (d2->new.to > d1->new.to) { 652 d1->old.to += d2->new.to - d1->new.to; 653 d1->new.to = d2->new.to; 654 } 655 } 656 657 return (edscript(j)); 658 } 659 660 static void 661 separate(const char *s) 662 { 663 diff_output("====%s\n", s); 664 } 665 666 /* 667 * The range of lines rold.from thru rold.to in file i is to be changed. 668 * It is to be printed only if it does not duplicate something to be 669 * printed later. 670 */ 671 static void 672 change(int i, struct range *rold, int fdup) 673 { 674 diff_output("%d:", i); 675 last[i] = rold->to; 676 prange(rold); 677 if (fdup || debug) 678 return; 679 i--; 680 (void)skip(i, rold->from, NULL); 681 (void)skip(i, rold->to, " "); 682 } 683 684 /* 685 * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 686 */ 687 static void 688 prange(struct range *rold) 689 { 690 if (rold->to <= rold->from) 691 diff_output("%da\n", rold->from - 1); 692 else { 693 diff_output("%d", rold->from); 694 if (rold->to > rold->from+1) 695 diff_output(",%d", rold->to - 1); 696 diff_output("c\n"); 697 } 698 } 699 700 /* 701 * No difference was reported by diff between file 1 (or 2) and file 3, 702 * and an artificial dummy difference (trange) must be ginned up to 703 * correspond to the change reported in the other file. 704 */ 705 static void 706 keep(int i, struct range *rnew) 707 { 708 int delta; 709 struct range trange; 710 711 delta = last[3] - last[i]; 712 trange.from = rnew->from - delta; 713 trange.to = rnew->to - delta; 714 change(i, &trange, 1); 715 } 716 717 /* 718 * skip to just before line number from in file "i". If "pr" is non-NULL, 719 * print all skipped stuff with string pr as a prefix. 720 */ 721 static int 722 skip(int i, int from, char *pr) 723 { 724 size_t j, n; 725 char *line; 726 727 for (n = 0; cline[i] < from - 1; n += j) { 728 if ((line = getline(fp[i], &j)) == NULL) 729 return (-1); 730 if (pr != NULL) 731 diff_output("%s%s", pr, line); 732 cline[i]++; 733 } 734 return ((int) n); 735 } 736 737 /* 738 * Return 1 or 0 according as the old range (in file 1) contains exactly 739 * the same data as the new range (in file 2). 740 */ 741 static int 742 duplicate(struct range *r1, struct range *r2) 743 { 744 int c,d; 745 int nchar; 746 int nline; 747 748 if (r1->to-r1->from != r2->to-r2->from) 749 return (0); 750 (void)skip(0, r1->from, NULL); 751 (void)skip(1, r2->from, NULL); 752 nchar = 0; 753 for (nline=0; nline < r1->to - r1->from; nline++) { 754 do { 755 c = getc(fp[0]); 756 d = getc(fp[1]); 757 if (c == -1 || d== -1) 758 return (-1); 759 nchar++; 760 if (c != d) { 761 repos(nchar); 762 return (0); 763 } 764 } while (c != '\n'); 765 } 766 repos(nchar); 767 return (1); 768 } 769 770 static void 771 repos(int nchar) 772 { 773 int i; 774 775 for (i = 0; i < 2; i++) 776 (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 777 } 778 779 /* 780 * collect an editing script for later regurgitation 781 */ 782 static int 783 edit(struct diff *diff, int fdup, int j) 784 { 785 if (((fdup + 1) & eflag) == 0) 786 return (j); 787 j++; 788 overlap[j] = !fdup; 789 if (!fdup) 790 overlapcnt++; 791 de[j].old.from = diff->old.from; 792 de[j].old.to = diff->old.to; 793 de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 794 de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 795 return (j); 796 } 797 798 /* regurgitate */ 799 static int 800 edscript(int n) 801 { 802 int j, k; 803 char block[BUFSIZ+1]; 804 805 for (n = n; n > 0; n--) { 806 if (!oflag || !overlap[n]) 807 prange(&de[n].old); 808 else 809 diff_output("%da\n=======\n", de[n].old.to -1); 810 (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET); 811 for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 812 j = k > BUFSIZ ? BUFSIZ : k; 813 if (fread(block, (size_t)1, (size_t)j, 814 fp[2]) != (size_t)j) 815 return (-1); 816 block[j] = '\0'; 817 diff_output("%s", block); 818 } 819 820 if (!oflag || !overlap[n]) 821 diff_output(".\n"); 822 else { 823 diff_output("%s\n.\n", f3mark); 824 diff_output("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 825 } 826 } 827 828 return (overlapcnt); 829 } 830 831 static void 832 increase(void) 833 { 834 size_t newsz, incr; 835 836 /* are the memset(3) calls needed? */ 837 newsz = szchanges == 0 ? 64 : 2 * szchanges; 838 incr = newsz - szchanges; 839 840 d13 = xrealloc(d13, newsz, sizeof(*d13)); 841 memset(d13 + szchanges, 0, incr * sizeof(*d13)); 842 d23 = xrealloc(d23, newsz, sizeof(*d23)); 843 memset(d23 + szchanges, 0, incr * sizeof(*d23)); 844 de = xrealloc(de, newsz, sizeof(*de)); 845 memset(de + szchanges, 0, incr * sizeof(*de)); 846 overlap = xrealloc(overlap, newsz, sizeof(*overlap)); 847 memset(overlap + szchanges, 0, incr * sizeof(*overlap)); 848 szchanges = newsz; 849 } 850