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