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