1*f9bbbf45Sfgsch /* $OpenBSD: diff3prog.c,v 1.12 2012/03/04 04:05:15 fgsch Exp $ */ 2d407ca27Smillert 3d407ca27Smillert /* 4d407ca27Smillert * Copyright (C) Caldera International Inc. 2001-2002. 5d407ca27Smillert * All rights reserved. 6d407ca27Smillert * 7d407ca27Smillert * Redistribution and use in source and binary forms, with or without 8d407ca27Smillert * modification, are permitted provided that the following conditions 9d407ca27Smillert * are met: 10d407ca27Smillert * 1. Redistributions of source code and documentation must retain the above 11d407ca27Smillert * copyright notice, this list of conditions and the following disclaimer. 12d407ca27Smillert * 2. Redistributions in binary form must reproduce the above copyright 13d407ca27Smillert * notice, this list of conditions and the following disclaimer in the 14d407ca27Smillert * documentation and/or other materials provided with the distribution. 15d407ca27Smillert * 3. All advertising materials mentioning features or use of this software 16d407ca27Smillert * must display the following acknowledgement: 17d407ca27Smillert * This product includes software developed or owned by Caldera 18d407ca27Smillert * International, Inc. 19d407ca27Smillert * 4. Neither the name of Caldera International, Inc. nor the names of other 20d407ca27Smillert * contributors may be used to endorse or promote products derived from 21d407ca27Smillert * this software without specific prior written permission. 22d407ca27Smillert * 23d407ca27Smillert * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24d407ca27Smillert * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25d407ca27Smillert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26d407ca27Smillert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27d407ca27Smillert * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28d407ca27Smillert * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29d407ca27Smillert * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30d407ca27Smillert * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31d407ca27Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32d407ca27Smillert * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33d407ca27Smillert * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34d407ca27Smillert * POSSIBILITY OF SUCH DAMAGE. 35d407ca27Smillert */ 36d407ca27Smillert /*- 37d407ca27Smillert * Copyright (c) 1991, 1993 38d407ca27Smillert * The Regents of the University of California. All rights reserved. 39d407ca27Smillert * 40d407ca27Smillert * Redistribution and use in source and binary forms, with or without 41d407ca27Smillert * modification, are permitted provided that the following conditions 42d407ca27Smillert * are met: 43d407ca27Smillert * 1. Redistributions of source code must retain the above copyright 44d407ca27Smillert * notice, this list of conditions and the following disclaimer. 45d407ca27Smillert * 2. Redistributions in binary form must reproduce the above copyright 46d407ca27Smillert * notice, this list of conditions and the following disclaimer in the 47d407ca27Smillert * documentation and/or other materials provided with the distribution. 48d407ca27Smillert * 3. Neither the name of the University nor the names of its contributors 49d407ca27Smillert * may be used to endorse or promote products derived from this software 50d407ca27Smillert * without specific prior written permission. 51d407ca27Smillert * 52d407ca27Smillert * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53d407ca27Smillert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54d407ca27Smillert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55d407ca27Smillert * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56d407ca27Smillert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57d407ca27Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58d407ca27Smillert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59d407ca27Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60d407ca27Smillert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61d407ca27Smillert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62d407ca27Smillert * SUCH DAMAGE. 63d407ca27Smillert * 64d407ca27Smillert * @(#)diff3.c 8.1 (Berkeley) 6/6/93 65d407ca27Smillert */ 66d407ca27Smillert 67d407ca27Smillert #include <stdio.h> 68d407ca27Smillert #include <stdlib.h> 69ad7191bdSmillert #include <string.h> 70d407ca27Smillert #include <ctype.h> 71d407ca27Smillert #include <err.h> 72d407ca27Smillert 73d407ca27Smillert /* diff3 - 3-way differential file comparison */ 74d407ca27Smillert 75d407ca27Smillert /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] 76d407ca27Smillert * 77d407ca27Smillert * d13 = diff report on f1 vs f3 78d407ca27Smillert * d23 = diff report on f2 vs f3 79d407ca27Smillert * f1, f2, f3 the 3 files 80d407ca27Smillert * if changes in f1 overlap with changes in f3, m1 and m3 are used 81d407ca27Smillert * to mark the overlaps; otherwise, the file names f1 and f3 are used 82d407ca27Smillert * (only for options E and X). 83d407ca27Smillert */ 84d407ca27Smillert 85d407ca27Smillert /* 86d407ca27Smillert * "from" is first in range of changed lines; "to" is last+1 87d407ca27Smillert * from=to=line after point of insertion for added lines. 88d407ca27Smillert */ 89d407ca27Smillert struct range { 90d407ca27Smillert int from; 91d407ca27Smillert int to; 92d407ca27Smillert }; 93d407ca27Smillert struct diff { 94d407ca27Smillert struct range old; 95d407ca27Smillert struct range new; 96d407ca27Smillert }; 97d407ca27Smillert 9868496fbfSotto size_t szchanges; 9968496fbfSotto 10068496fbfSotto struct diff *d13; 10168496fbfSotto struct diff *d23; 102d407ca27Smillert /* 103d407ca27Smillert * "de" is used to gather editing scripts. These are later spewed out in 104d407ca27Smillert * reverse order. Its first element must be all zero, the "new" component 105d407ca27Smillert * of "de" contains line positions or byte positions depending on when you 106d407ca27Smillert * look (!?). Array overlap indicates which sections in "de" correspond to 107d407ca27Smillert * lines that are different in all three files. 108d407ca27Smillert */ 10968496fbfSotto struct diff *de; 11068496fbfSotto char *overlap; 111d407ca27Smillert int overlapcnt; 112d407ca27Smillert FILE *fp[3]; 113d407ca27Smillert int cline[3]; /* # of the last-read line in each file (0-2) */ 114d407ca27Smillert /* 115d407ca27Smillert * the latest known correspondence between line numbers of the 3 files 116d407ca27Smillert * is stored in last[1-3]; 117d407ca27Smillert */ 118d407ca27Smillert int last[4]; 119d407ca27Smillert int eflag; 120d407ca27Smillert int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 121d407ca27Smillert int debug = 0; 122d407ca27Smillert char f1mark[40], f3mark[40]; /* markers for -E and -X */ 123d407ca27Smillert 124d407ca27Smillert int duplicate(struct range *, struct range *); 125d407ca27Smillert int edit(struct diff *, int, int); 126ad7191bdSmillert char *getchange(FILE *); 127*f9bbbf45Sfgsch char *get_line(FILE *, size_t *); 128d407ca27Smillert int number(char **); 12968496fbfSotto int readin(char *, struct diff **); 130d407ca27Smillert int skip(int, int, char *); 131d407ca27Smillert void change(int, struct range *, int); 132d407ca27Smillert void keep(int, struct range *); 133d407ca27Smillert void merge(int, int); 134d407ca27Smillert void prange(struct range *); 135d407ca27Smillert void repos(int); 136d407ca27Smillert void separate(const char *); 137d407ca27Smillert __dead void edscript(int); 138d407ca27Smillert __dead void trouble(void); 13968496fbfSotto void increase(void); 140d407ca27Smillert __dead void usage(void); 141d407ca27Smillert 142d407ca27Smillert int 143d407ca27Smillert main(int argc, char **argv) 144d407ca27Smillert { 145d407ca27Smillert int ch, i, m, n; 146d407ca27Smillert 147d407ca27Smillert eflag = 0; 148d407ca27Smillert oflag = 0; 149d407ca27Smillert while ((ch = getopt(argc, argv, "EeXx3")) != -1) { 150d407ca27Smillert switch (ch) { 151d407ca27Smillert case 'E': 152d407ca27Smillert eflag = 3; 153d407ca27Smillert oflag = 1; 154d407ca27Smillert break; 155d407ca27Smillert case 'e': 156d407ca27Smillert eflag = 3; 157d407ca27Smillert break; 158d407ca27Smillert case 'X': 159d407ca27Smillert oflag = eflag = 1; 160d407ca27Smillert break; 161d407ca27Smillert case 'x': 162d407ca27Smillert eflag = 1; 163d407ca27Smillert break; 164d407ca27Smillert case '3': 165d407ca27Smillert eflag = 2; 166d407ca27Smillert break; 167d407ca27Smillert } 168d407ca27Smillert } 169d407ca27Smillert argc -= optind; 170d407ca27Smillert argv += optind; 171d407ca27Smillert /* XXX - argc usage seems wrong here */ 172d407ca27Smillert if (argc < 5) 173d407ca27Smillert usage(); 174d407ca27Smillert 175d407ca27Smillert if (oflag) { 176d407ca27Smillert (void)snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", 177d407ca27Smillert argc >= 6 ? argv[5] : argv[2]); 178d407ca27Smillert (void)snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", 179d407ca27Smillert argc >= 7 ? argv[6] : argv[4]); 180d407ca27Smillert } 181d407ca27Smillert 18268496fbfSotto increase(); 18368496fbfSotto m = readin(argv[0], &d13); 18468496fbfSotto n = readin(argv[1], &d23); 185d407ca27Smillert for (i = 0; i <= 2; i++) { 1862e6633a8Stobias if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) 1872e6633a8Stobias err(EXIT_FAILURE, "can't open %s", argv[i + 2]); 188d407ca27Smillert } 189d407ca27Smillert merge(m, n); 190d407ca27Smillert exit(EXIT_SUCCESS); 191d407ca27Smillert } 192d407ca27Smillert 193d407ca27Smillert /* 1948fa21293Sotto * Pick up the line numbers of all changes from one change file. 195d407ca27Smillert * (This puts the numbers in a vector, which is not strictly necessary, 196d407ca27Smillert * since the vector is processed in one sequential pass. 197d407ca27Smillert * The vector could be optimized out of existence) 198d407ca27Smillert */ 199d407ca27Smillert int 20068496fbfSotto readin(char *name, struct diff **dd) 201d407ca27Smillert { 202ad7191bdSmillert int a, b, c, d, i; 203ad7191bdSmillert char kind, *p; 204ad7191bdSmillert 205d407ca27Smillert fp[0] = fopen(name, "r"); 2062e6633a8Stobias if (fp[0] == NULL) 2072e6633a8Stobias err(EXIT_FAILURE, "can't open %s", name); 208ad7191bdSmillert for (i=0; (p = getchange(fp[0])); i++) { 20968496fbfSotto if (i >= szchanges - 1) 21068496fbfSotto increase(); 211d407ca27Smillert a = b = number(&p); 212d407ca27Smillert if (*p == ',') { 213d407ca27Smillert p++; 214d407ca27Smillert b = number(&p); 215d407ca27Smillert } 216d407ca27Smillert kind = *p++; 217d407ca27Smillert c = d = number(&p); 218d407ca27Smillert if (*p==',') { 219d407ca27Smillert p++; 220d407ca27Smillert d = number(&p); 221d407ca27Smillert } 222d407ca27Smillert if (kind == 'a') 223d407ca27Smillert a++; 224d407ca27Smillert if (kind == 'd') 225d407ca27Smillert c++; 226d407ca27Smillert b++; 227d407ca27Smillert d++; 22868496fbfSotto (*dd)[i].old.from = a; 22968496fbfSotto (*dd)[i].old.to = b; 23068496fbfSotto (*dd)[i].new.from = c; 23168496fbfSotto (*dd)[i].new.to = d; 232d407ca27Smillert } 2336daeeae1Smarkus if (i) { 23468496fbfSotto (*dd)[i].old.from = (*dd)[i-1].old.to; 23568496fbfSotto (*dd)[i].new.from = (*dd)[i-1].new.to; 2366daeeae1Smarkus } 237d407ca27Smillert (void)fclose(fp[0]); 238d407ca27Smillert return (i); 239d407ca27Smillert } 240d407ca27Smillert 241d407ca27Smillert int 242d407ca27Smillert number(char **lc) 243d407ca27Smillert { 244d407ca27Smillert int nn; 245d407ca27Smillert nn = 0; 246d407ca27Smillert while (isdigit((unsigned char)(**lc))) 247d407ca27Smillert nn = nn*10 + *(*lc)++ - '0'; 248d407ca27Smillert return (nn); 249d407ca27Smillert } 250d407ca27Smillert 251ad7191bdSmillert char * 252d407ca27Smillert getchange(FILE *b) 253d407ca27Smillert { 254ad7191bdSmillert char *line; 255ad7191bdSmillert 256*f9bbbf45Sfgsch while ((line = get_line(b, NULL))) { 257d407ca27Smillert if (isdigit((unsigned char)line[0])) 258ad7191bdSmillert return (line); 259d407ca27Smillert } 260ad7191bdSmillert return (NULL); 261d407ca27Smillert } 262d407ca27Smillert 263ad7191bdSmillert char * 264*f9bbbf45Sfgsch get_line(FILE *b, size_t *n) 265d407ca27Smillert { 266ad7191bdSmillert char *cp; 267ad7191bdSmillert size_t len; 268ad7191bdSmillert static char *buf; 269ad7191bdSmillert static size_t bufsize; 270d407ca27Smillert 271ad7191bdSmillert if ((cp = fgetln(b, &len)) == NULL) 272ad7191bdSmillert return (NULL); 273ad7191bdSmillert 274ad7191bdSmillert if (cp[len - 1] != '\n') 275ad7191bdSmillert len++; 276ad7191bdSmillert if (len + 1 > bufsize) { 277ad7191bdSmillert do { 278ad7191bdSmillert bufsize += 1024; 279ad7191bdSmillert } while (len + 1 > bufsize); 280ad7191bdSmillert if ((buf = realloc(buf, bufsize)) == NULL) 281ad7191bdSmillert err(EXIT_FAILURE, NULL); 282d407ca27Smillert } 283ad7191bdSmillert memcpy(buf, cp, len - 1); 284ad7191bdSmillert buf[len - 1] = '\n'; 285ad7191bdSmillert buf[len] = '\0'; 286ad7191bdSmillert if (n != NULL) 287ad7191bdSmillert *n = len; 288ad7191bdSmillert return (buf); 289d407ca27Smillert } 290d407ca27Smillert 291d407ca27Smillert void 292d407ca27Smillert merge(int m1, int m2) 293d407ca27Smillert { 294d407ca27Smillert struct diff *d1, *d2, *d3; 295d407ca27Smillert int dup, j, t1, t2; 296d407ca27Smillert 297d407ca27Smillert d1 = d13; 298d407ca27Smillert d2 = d23; 299d407ca27Smillert j = 0; 300d407ca27Smillert while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 301d407ca27Smillert if (debug) { 302d407ca27Smillert printf("%d,%d=%d,%d %d,%d=%d,%d\n", 303d407ca27Smillert d1->old.from,d1->old.to, 304d407ca27Smillert d1->new.from,d1->new.to, 305d407ca27Smillert d2->old.from,d2->old.to, 306d407ca27Smillert d2->new.from,d2->new.to); 307d407ca27Smillert } 308d407ca27Smillert /* first file is different from others */ 3090b1c43dfScanacar if (!t2 || (t1 && d1->new.to < d2->new.from)) { 310d407ca27Smillert /* stuff peculiar to 1st file */ 311d407ca27Smillert if (eflag==0) { 312d407ca27Smillert separate("1"); 313d407ca27Smillert change(1, &d1->old, 0); 314d407ca27Smillert keep(2, &d1->new); 315d407ca27Smillert change(3, &d1->new, 0); 316d407ca27Smillert } 317d407ca27Smillert d1++; 318d407ca27Smillert continue; 319d407ca27Smillert } 320d407ca27Smillert /* second file is different from others */ 3210b1c43dfScanacar if (!t1 || (t2 && d2->new.to < d1->new.from)) { 322d407ca27Smillert if (eflag==0) { 323d407ca27Smillert separate("2"); 324d407ca27Smillert keep(1, &d2->new); 325d407ca27Smillert change(2, &d2->old, 0); 326d407ca27Smillert change(3, &d2->new, 0); 327d407ca27Smillert } 328d407ca27Smillert d2++; 329d407ca27Smillert continue; 330d407ca27Smillert } 331d407ca27Smillert /* 332d407ca27Smillert * Merge overlapping changes in first file 333d407ca27Smillert * this happens after extension (see below). 334d407ca27Smillert */ 335d407ca27Smillert if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 336d407ca27Smillert d1[1].old.from = d1->old.from; 337d407ca27Smillert d1[1].new.from = d1->new.from; 338d407ca27Smillert d1++; 339d407ca27Smillert continue; 340d407ca27Smillert } 341d407ca27Smillert 342d407ca27Smillert /* merge overlapping changes in second */ 343d407ca27Smillert if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 344d407ca27Smillert d2[1].old.from = d2->old.from; 345d407ca27Smillert d2[1].new.from = d2->new.from; 346d407ca27Smillert d2++; 347d407ca27Smillert continue; 348d407ca27Smillert } 349d407ca27Smillert /* stuff peculiar to third file or different in all */ 350d407ca27Smillert if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 351d407ca27Smillert dup = duplicate(&d1->old,&d2->old); 352d407ca27Smillert /* 353d407ca27Smillert * dup = 0 means all files differ 3548fa21293Sotto * dup = 1 means files 1 and 2 identical 355d407ca27Smillert */ 356d407ca27Smillert if (eflag==0) { 357d407ca27Smillert separate(dup ? "3" : ""); 358d407ca27Smillert change(1, &d1->old, dup); 359d407ca27Smillert change(2, &d2->old, 0); 360d407ca27Smillert d3 = d1->old.to > d1->old.from ? d1 : d2; 361d407ca27Smillert change(3, &d3->new, 0); 362d407ca27Smillert } else 363d407ca27Smillert j = edit(d1, dup, j); 364d407ca27Smillert d1++; 365d407ca27Smillert d2++; 366d407ca27Smillert continue; 367d407ca27Smillert } 368d407ca27Smillert /* 369d407ca27Smillert * Overlapping changes from file 1 and 2; extend changes 370d407ca27Smillert * appropriately to make them coincide. 371d407ca27Smillert */ 372d407ca27Smillert if (d1->new.from < d2->new.from) { 373d407ca27Smillert d2->old.from -= d2->new.from-d1->new.from; 374d407ca27Smillert d2->new.from = d1->new.from; 375d407ca27Smillert } else if (d2->new.from < d1->new.from) { 376d407ca27Smillert d1->old.from -= d1->new.from-d2->new.from; 377d407ca27Smillert d1->new.from = d2->new.from; 378d407ca27Smillert } 379d407ca27Smillert if (d1->new.to > d2->new.to) { 380d407ca27Smillert d2->old.to += d1->new.to - d2->new.to; 381d407ca27Smillert d2->new.to = d1->new.to; 382d407ca27Smillert } else if (d2->new.to > d1->new.to) { 383d407ca27Smillert d1->old.to += d2->new.to - d1->new.to; 384d407ca27Smillert d1->new.to = d2->new.to; 385d407ca27Smillert } 386d407ca27Smillert } 387d407ca27Smillert if (eflag) 388d407ca27Smillert edscript(j); 389d407ca27Smillert } 390d407ca27Smillert 391d407ca27Smillert void 392d407ca27Smillert separate(const char *s) 393d407ca27Smillert { 394d407ca27Smillert printf("====%s\n", s); 395d407ca27Smillert } 396d407ca27Smillert 397d407ca27Smillert /* 398d407ca27Smillert * The range of lines rold.from thru rold.to in file i is to be changed. 399d407ca27Smillert * It is to be printed only if it does not duplicate something to be 400d407ca27Smillert * printed later. 401d407ca27Smillert */ 402d407ca27Smillert void 403d407ca27Smillert change(int i, struct range *rold, int dup) 404d407ca27Smillert { 405d407ca27Smillert printf("%d:", i); 406d407ca27Smillert last[i] = rold->to; 407d407ca27Smillert prange(rold); 408d407ca27Smillert if (dup || debug) 409d407ca27Smillert return; 410d407ca27Smillert i--; 411d407ca27Smillert (void)skip(i, rold->from, NULL); 412d407ca27Smillert (void)skip(i, rold->to, " "); 413d407ca27Smillert } 414d407ca27Smillert 415d407ca27Smillert /* 416d407ca27Smillert * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 417d407ca27Smillert */ 418d407ca27Smillert void 419d407ca27Smillert prange(struct range *rold) 420d407ca27Smillert { 421d407ca27Smillert if (rold->to <= rold->from) 422d407ca27Smillert printf("%da\n", rold->from - 1); 423d407ca27Smillert else { 424d407ca27Smillert printf("%d", rold->from); 425d407ca27Smillert if (rold->to > rold->from+1) 426d407ca27Smillert printf(",%d", rold->to - 1); 427d407ca27Smillert printf("c\n"); 428d407ca27Smillert } 429d407ca27Smillert } 430d407ca27Smillert 431d407ca27Smillert /* 432d407ca27Smillert * No difference was reported by diff between file 1 (or 2) and file 3, 433d407ca27Smillert * and an artificial dummy difference (trange) must be ginned up to 434d407ca27Smillert * correspond to the change reported in the other file. 435d407ca27Smillert */ 436d407ca27Smillert void 437d407ca27Smillert keep(int i, struct range *rnew) 438d407ca27Smillert { 439d407ca27Smillert int delta; 440d407ca27Smillert struct range trange; 441d407ca27Smillert 442d407ca27Smillert delta = last[3] - last[i]; 443d407ca27Smillert trange.from = rnew->from - delta; 444d407ca27Smillert trange.to = rnew->to - delta; 445d407ca27Smillert change(i, &trange, 1); 446d407ca27Smillert } 447d407ca27Smillert 448d407ca27Smillert /* 4498fa21293Sotto * skip to just before line number from in file "i". If "pr" is non-NULL, 450d407ca27Smillert * print all skipped stuff with string pr as a prefix. 451d407ca27Smillert */ 452d407ca27Smillert int 453d407ca27Smillert skip(int i, int from, char *pr) 454d407ca27Smillert { 455ad7191bdSmillert size_t j, n; 456ad7191bdSmillert char *line; 457d407ca27Smillert 458d407ca27Smillert for (n = 0; cline[i] < from - 1; n += j) { 459*f9bbbf45Sfgsch if ((line = get_line(fp[i], &j)) == NULL) 460d407ca27Smillert trouble(); 461d407ca27Smillert if (pr != NULL) 462d407ca27Smillert printf("%s%s", pr, line); 463d407ca27Smillert cline[i]++; 464d407ca27Smillert } 465ad7191bdSmillert return ((int) n); 466d407ca27Smillert } 467d407ca27Smillert 468d407ca27Smillert /* 469d407ca27Smillert * Return 1 or 0 according as the old range (in file 1) contains exactly 470d407ca27Smillert * the same data as the new range (in file 2). 471d407ca27Smillert */ 472d407ca27Smillert int 473d407ca27Smillert duplicate(struct range *r1, struct range *r2) 474d407ca27Smillert { 475d407ca27Smillert int c,d; 476d407ca27Smillert int nchar; 477d407ca27Smillert int nline; 478d407ca27Smillert 479d407ca27Smillert if (r1->to-r1->from != r2->to-r2->from) 480d407ca27Smillert return (0); 481d407ca27Smillert (void)skip(0, r1->from, NULL); 482d407ca27Smillert (void)skip(1, r2->from, NULL); 483d407ca27Smillert nchar = 0; 484d407ca27Smillert for (nline=0; nline < r1->to - r1->from; nline++) { 485d407ca27Smillert do { 486d407ca27Smillert c = getc(fp[0]); 487d407ca27Smillert d = getc(fp[1]); 488d407ca27Smillert if (c == -1 || d== -1) 489d407ca27Smillert trouble(); 490d407ca27Smillert nchar++; 491d407ca27Smillert if (c != d) { 492d407ca27Smillert repos(nchar); 493d407ca27Smillert return (0); 494d407ca27Smillert } 495d407ca27Smillert } while (c != '\n'); 496d407ca27Smillert } 497d407ca27Smillert repos(nchar); 498d407ca27Smillert return (1); 499d407ca27Smillert } 500d407ca27Smillert 501d407ca27Smillert void 502d407ca27Smillert repos(int nchar) 503d407ca27Smillert { 504d407ca27Smillert int i; 505d407ca27Smillert 506d407ca27Smillert for (i = 0; i < 2; i++) 507a52c79cdStobias (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 508d407ca27Smillert } 509d407ca27Smillert 510d407ca27Smillert __dead void 511d407ca27Smillert trouble(void) 512d407ca27Smillert { 513d407ca27Smillert errx(EXIT_FAILURE, "logic error"); 514d407ca27Smillert } 515d407ca27Smillert 516d407ca27Smillert /* 517d407ca27Smillert * collect an editing script for later regurgitation 518d407ca27Smillert */ 519d407ca27Smillert int 520d407ca27Smillert edit(struct diff *diff, int dup, int j) 521d407ca27Smillert { 522d407ca27Smillert if (((dup + 1) & eflag) == 0) 523d407ca27Smillert return (j); 524d407ca27Smillert j++; 525d407ca27Smillert overlap[j] = !dup; 526d407ca27Smillert if (!dup) 527d407ca27Smillert overlapcnt++; 528d407ca27Smillert de[j].old.from = diff->old.from; 529d407ca27Smillert de[j].old.to = diff->old.to; 530d407ca27Smillert de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 531d407ca27Smillert de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 532d407ca27Smillert return (j); 533d407ca27Smillert } 534d407ca27Smillert 535d407ca27Smillert /* regurgitate */ 536d407ca27Smillert __dead void 537d407ca27Smillert edscript(int n) 538d407ca27Smillert { 539d407ca27Smillert int j,k; 540d407ca27Smillert char block[BUFSIZ]; 541d407ca27Smillert 542d407ca27Smillert for (n = n; n > 0; n--) { 543d407ca27Smillert if (!oflag || !overlap[n]) 544d407ca27Smillert prange(&de[n].old); 545d407ca27Smillert else 546d407ca27Smillert printf("%da\n=======\n", de[n].old.to -1); 547a52c79cdStobias (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET); 548d407ca27Smillert for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 549d407ca27Smillert j = k > BUFSIZ ? BUFSIZ : k; 550d407ca27Smillert if (fread(block, 1, j, fp[2]) != j) 551d407ca27Smillert trouble(); 552d407ca27Smillert (void)fwrite(block, 1, j, stdout); 553d407ca27Smillert } 554d407ca27Smillert if (!oflag || !overlap[n]) 555d407ca27Smillert printf(".\n"); 556d407ca27Smillert else { 557d407ca27Smillert printf("%s\n.\n", f3mark); 558d407ca27Smillert printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 559d407ca27Smillert } 560d407ca27Smillert } 561d407ca27Smillert exit(overlapcnt); 562d407ca27Smillert } 563d407ca27Smillert 56468496fbfSotto void 56568496fbfSotto increase(void) 56668496fbfSotto { 56768496fbfSotto struct diff *p; 56868496fbfSotto char *q; 56968496fbfSotto size_t newsz, incr; 57068496fbfSotto 57168496fbfSotto /* are the memset(3) calls needed? */ 57268496fbfSotto newsz = szchanges == 0 ? 64 : 2 * szchanges; 57368496fbfSotto incr = newsz - szchanges; 57468496fbfSotto 57568496fbfSotto p = realloc(d13, newsz * sizeof(struct diff)); 57668496fbfSotto if (p == NULL) 57768496fbfSotto err(1, NULL); 57868496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 57968496fbfSotto d13 = p; 58068496fbfSotto p = realloc(d23, newsz * sizeof(struct diff)); 58168496fbfSotto if (p == NULL) 58268496fbfSotto err(1, NULL); 58368496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58468496fbfSotto d23 = p; 58568496fbfSotto p = realloc(de, newsz * sizeof(struct diff)); 58668496fbfSotto if (p == NULL) 58768496fbfSotto err(1, NULL); 58868496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58968496fbfSotto de = p; 59068496fbfSotto q = realloc(overlap, newsz * sizeof(char)); 59168496fbfSotto if (q == NULL) 59268496fbfSotto err(1, NULL); 59368496fbfSotto memset(q + szchanges, 0, incr * sizeof(char)); 59468496fbfSotto overlap = q; 59568496fbfSotto szchanges = newsz; 59668496fbfSotto } 59768496fbfSotto 59868496fbfSotto 599d407ca27Smillert __dead void 600d407ca27Smillert usage(void) 601d407ca27Smillert { 602d407ca27Smillert extern char *__progname; 603d407ca27Smillert 604d407ca27Smillert fprintf(stderr, "usage: %s [-exEX3] /tmp/d3a.?????????? " 605d407ca27Smillert "/tmp/d3b.?????????? file1 file2 file3\n", __progname); 606d407ca27Smillert exit(EXIT_FAILURE); 607d407ca27Smillert } 608