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