1*5302ee64Sderaadt /* $OpenBSD: diff3prog.c,v 1.14 2014/12/01 06:36:32 deraadt 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 678929f197Smillert #include <ctype.h> 688929f197Smillert #include <err.h> 69d407ca27Smillert #include <stdio.h> 70d407ca27Smillert #include <stdlib.h> 71ad7191bdSmillert #include <string.h> 728929f197Smillert #include <unistd.h> 73d407ca27Smillert 74d407ca27Smillert /* diff3 - 3-way differential file comparison */ 75d407ca27Smillert 76d407ca27Smillert /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3] 77d407ca27Smillert * 78d407ca27Smillert * d13 = diff report on f1 vs f3 79d407ca27Smillert * d23 = diff report on f2 vs f3 80d407ca27Smillert * f1, f2, f3 the 3 files 81d407ca27Smillert * if changes in f1 overlap with changes in f3, m1 and m3 are used 82d407ca27Smillert * to mark the overlaps; otherwise, the file names f1 and f3 are used 83d407ca27Smillert * (only for options E and X). 84d407ca27Smillert */ 85d407ca27Smillert 86d407ca27Smillert /* 87d407ca27Smillert * "from" is first in range of changed lines; "to" is last+1 88d407ca27Smillert * from=to=line after point of insertion for added lines. 89d407ca27Smillert */ 90d407ca27Smillert struct range { 91d407ca27Smillert int from; 92d407ca27Smillert int to; 93d407ca27Smillert }; 94d407ca27Smillert struct diff { 95d407ca27Smillert struct range old; 96d407ca27Smillert struct range new; 97d407ca27Smillert }; 98d407ca27Smillert 9968496fbfSotto size_t szchanges; 10068496fbfSotto 10168496fbfSotto struct diff *d13; 10268496fbfSotto struct diff *d23; 103d407ca27Smillert /* 104d407ca27Smillert * "de" is used to gather editing scripts. These are later spewed out in 105d407ca27Smillert * reverse order. Its first element must be all zero, the "new" component 106d407ca27Smillert * of "de" contains line positions or byte positions depending on when you 107d407ca27Smillert * look (!?). Array overlap indicates which sections in "de" correspond to 108d407ca27Smillert * lines that are different in all three files. 109d407ca27Smillert */ 11068496fbfSotto struct diff *de; 11168496fbfSotto char *overlap; 112d407ca27Smillert int overlapcnt; 113d407ca27Smillert FILE *fp[3]; 114d407ca27Smillert int cline[3]; /* # of the last-read line in each file (0-2) */ 115d407ca27Smillert /* 116d407ca27Smillert * the latest known correspondence between line numbers of the 3 files 117d407ca27Smillert * is stored in last[1-3]; 118d407ca27Smillert */ 119d407ca27Smillert int last[4]; 120d407ca27Smillert int eflag; 121d407ca27Smillert int oflag; /* indicates whether to mark overlaps (-E or -X)*/ 122d407ca27Smillert int debug = 0; 123d407ca27Smillert char f1mark[40], f3mark[40]; /* markers for -E and -X */ 124d407ca27Smillert 125d407ca27Smillert int duplicate(struct range *, struct range *); 126d407ca27Smillert int edit(struct diff *, int, int); 127ad7191bdSmillert char *getchange(FILE *); 128f9bbbf45Sfgsch char *get_line(FILE *, size_t *); 129d407ca27Smillert int number(char **); 13068496fbfSotto int readin(char *, struct diff **); 131d407ca27Smillert int skip(int, int, char *); 132d407ca27Smillert void change(int, struct range *, int); 133d407ca27Smillert void keep(int, struct range *); 134d407ca27Smillert void merge(int, int); 135d407ca27Smillert void prange(struct range *); 136d407ca27Smillert void repos(int); 137d407ca27Smillert void separate(const char *); 138d407ca27Smillert __dead void edscript(int); 139d407ca27Smillert __dead void trouble(void); 14068496fbfSotto void increase(void); 141d407ca27Smillert __dead void usage(void); 142d407ca27Smillert 143d407ca27Smillert int 144d407ca27Smillert main(int argc, char **argv) 145d407ca27Smillert { 146d407ca27Smillert int ch, i, m, n; 147d407ca27Smillert 148d407ca27Smillert eflag = 0; 149d407ca27Smillert oflag = 0; 150d407ca27Smillert while ((ch = getopt(argc, argv, "EeXx3")) != -1) { 151d407ca27Smillert switch (ch) { 152d407ca27Smillert case 'E': 153d407ca27Smillert eflag = 3; 154d407ca27Smillert oflag = 1; 155d407ca27Smillert break; 156d407ca27Smillert case 'e': 157d407ca27Smillert eflag = 3; 158d407ca27Smillert break; 159d407ca27Smillert case 'X': 160d407ca27Smillert oflag = eflag = 1; 161d407ca27Smillert break; 162d407ca27Smillert case 'x': 163d407ca27Smillert eflag = 1; 164d407ca27Smillert break; 165d407ca27Smillert case '3': 166d407ca27Smillert eflag = 2; 167d407ca27Smillert break; 168d407ca27Smillert } 169d407ca27Smillert } 170d407ca27Smillert argc -= optind; 171d407ca27Smillert argv += optind; 172d407ca27Smillert /* XXX - argc usage seems wrong here */ 173d407ca27Smillert if (argc < 5) 174d407ca27Smillert usage(); 175d407ca27Smillert 176d407ca27Smillert if (oflag) { 177d407ca27Smillert (void)snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", 178d407ca27Smillert argc >= 6 ? argv[5] : argv[2]); 179d407ca27Smillert (void)snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", 180d407ca27Smillert argc >= 7 ? argv[6] : argv[4]); 181d407ca27Smillert } 182d407ca27Smillert 18368496fbfSotto increase(); 18468496fbfSotto m = readin(argv[0], &d13); 18568496fbfSotto n = readin(argv[1], &d23); 186d407ca27Smillert for (i = 0; i <= 2; i++) { 1872e6633a8Stobias if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) 1882e6633a8Stobias err(EXIT_FAILURE, "can't open %s", argv[i + 2]); 189d407ca27Smillert } 190d407ca27Smillert merge(m, n); 191d407ca27Smillert exit(EXIT_SUCCESS); 192d407ca27Smillert } 193d407ca27Smillert 194d407ca27Smillert /* 1958fa21293Sotto * Pick up the line numbers of all changes from one change file. 196d407ca27Smillert * (This puts the numbers in a vector, which is not strictly necessary, 197d407ca27Smillert * since the vector is processed in one sequential pass. 198d407ca27Smillert * The vector could be optimized out of existence) 199d407ca27Smillert */ 200d407ca27Smillert int 20168496fbfSotto readin(char *name, struct diff **dd) 202d407ca27Smillert { 203ad7191bdSmillert int a, b, c, d, i; 204ad7191bdSmillert char kind, *p; 205ad7191bdSmillert 206d407ca27Smillert fp[0] = fopen(name, "r"); 2072e6633a8Stobias if (fp[0] == NULL) 2082e6633a8Stobias err(EXIT_FAILURE, "can't open %s", name); 209ad7191bdSmillert for (i=0; (p = getchange(fp[0])); i++) { 21068496fbfSotto if (i >= szchanges - 1) 21168496fbfSotto increase(); 212d407ca27Smillert a = b = number(&p); 213d407ca27Smillert if (*p == ',') { 214d407ca27Smillert p++; 215d407ca27Smillert b = number(&p); 216d407ca27Smillert } 217d407ca27Smillert kind = *p++; 218d407ca27Smillert c = d = number(&p); 219d407ca27Smillert if (*p==',') { 220d407ca27Smillert p++; 221d407ca27Smillert d = number(&p); 222d407ca27Smillert } 223d407ca27Smillert if (kind == 'a') 224d407ca27Smillert a++; 225d407ca27Smillert if (kind == 'd') 226d407ca27Smillert c++; 227d407ca27Smillert b++; 228d407ca27Smillert d++; 22968496fbfSotto (*dd)[i].old.from = a; 23068496fbfSotto (*dd)[i].old.to = b; 23168496fbfSotto (*dd)[i].new.from = c; 23268496fbfSotto (*dd)[i].new.to = d; 233d407ca27Smillert } 2346daeeae1Smarkus if (i) { 23568496fbfSotto (*dd)[i].old.from = (*dd)[i-1].old.to; 23668496fbfSotto (*dd)[i].new.from = (*dd)[i-1].new.to; 2376daeeae1Smarkus } 238d407ca27Smillert (void)fclose(fp[0]); 239d407ca27Smillert return (i); 240d407ca27Smillert } 241d407ca27Smillert 242d407ca27Smillert int 243d407ca27Smillert number(char **lc) 244d407ca27Smillert { 245d407ca27Smillert int nn; 246d407ca27Smillert nn = 0; 247d407ca27Smillert while (isdigit((unsigned char)(**lc))) 248d407ca27Smillert nn = nn*10 + *(*lc)++ - '0'; 249d407ca27Smillert return (nn); 250d407ca27Smillert } 251d407ca27Smillert 252ad7191bdSmillert char * 253d407ca27Smillert getchange(FILE *b) 254d407ca27Smillert { 255ad7191bdSmillert char *line; 256ad7191bdSmillert 257f9bbbf45Sfgsch while ((line = get_line(b, NULL))) { 258d407ca27Smillert if (isdigit((unsigned char)line[0])) 259ad7191bdSmillert return (line); 260d407ca27Smillert } 261ad7191bdSmillert return (NULL); 262d407ca27Smillert } 263d407ca27Smillert 264ad7191bdSmillert char * 265f9bbbf45Sfgsch get_line(FILE *b, size_t *n) 266d407ca27Smillert { 267ad7191bdSmillert char *cp; 268ad7191bdSmillert size_t len; 269ad7191bdSmillert static char *buf; 270ad7191bdSmillert static size_t bufsize; 271d407ca27Smillert 272ad7191bdSmillert if ((cp = fgetln(b, &len)) == NULL) 273ad7191bdSmillert return (NULL); 274ad7191bdSmillert 275ad7191bdSmillert if (cp[len - 1] != '\n') 276ad7191bdSmillert len++; 277ad7191bdSmillert if (len + 1 > bufsize) { 278ad7191bdSmillert do { 279ad7191bdSmillert bufsize += 1024; 280ad7191bdSmillert } while (len + 1 > bufsize); 281ad7191bdSmillert if ((buf = realloc(buf, bufsize)) == NULL) 282ad7191bdSmillert err(EXIT_FAILURE, NULL); 283d407ca27Smillert } 284ad7191bdSmillert memcpy(buf, cp, len - 1); 285ad7191bdSmillert buf[len - 1] = '\n'; 286ad7191bdSmillert buf[len] = '\0'; 287ad7191bdSmillert if (n != NULL) 288ad7191bdSmillert *n = len; 289ad7191bdSmillert return (buf); 290d407ca27Smillert } 291d407ca27Smillert 292d407ca27Smillert void 293d407ca27Smillert merge(int m1, int m2) 294d407ca27Smillert { 295d407ca27Smillert struct diff *d1, *d2, *d3; 296d407ca27Smillert int dup, j, t1, t2; 297d407ca27Smillert 298d407ca27Smillert d1 = d13; 299d407ca27Smillert d2 = d23; 300d407ca27Smillert j = 0; 301d407ca27Smillert while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 302d407ca27Smillert if (debug) { 303d407ca27Smillert printf("%d,%d=%d,%d %d,%d=%d,%d\n", 304d407ca27Smillert d1->old.from,d1->old.to, 305d407ca27Smillert d1->new.from,d1->new.to, 306d407ca27Smillert d2->old.from,d2->old.to, 307d407ca27Smillert d2->new.from,d2->new.to); 308d407ca27Smillert } 309d407ca27Smillert /* first file is different from others */ 3100b1c43dfScanacar if (!t2 || (t1 && d1->new.to < d2->new.from)) { 311d407ca27Smillert /* stuff peculiar to 1st file */ 312d407ca27Smillert if (eflag==0) { 313d407ca27Smillert separate("1"); 314d407ca27Smillert change(1, &d1->old, 0); 315d407ca27Smillert keep(2, &d1->new); 316d407ca27Smillert change(3, &d1->new, 0); 317d407ca27Smillert } 318d407ca27Smillert d1++; 319d407ca27Smillert continue; 320d407ca27Smillert } 321d407ca27Smillert /* second file is different from others */ 3220b1c43dfScanacar if (!t1 || (t2 && d2->new.to < d1->new.from)) { 323d407ca27Smillert if (eflag==0) { 324d407ca27Smillert separate("2"); 325d407ca27Smillert keep(1, &d2->new); 326d407ca27Smillert change(2, &d2->old, 0); 327d407ca27Smillert change(3, &d2->new, 0); 328d407ca27Smillert } 329d407ca27Smillert d2++; 330d407ca27Smillert continue; 331d407ca27Smillert } 332d407ca27Smillert /* 333d407ca27Smillert * Merge overlapping changes in first file 334d407ca27Smillert * this happens after extension (see below). 335d407ca27Smillert */ 336d407ca27Smillert if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 337d407ca27Smillert d1[1].old.from = d1->old.from; 338d407ca27Smillert d1[1].new.from = d1->new.from; 339d407ca27Smillert d1++; 340d407ca27Smillert continue; 341d407ca27Smillert } 342d407ca27Smillert 343d407ca27Smillert /* merge overlapping changes in second */ 344d407ca27Smillert if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 345d407ca27Smillert d2[1].old.from = d2->old.from; 346d407ca27Smillert d2[1].new.from = d2->new.from; 347d407ca27Smillert d2++; 348d407ca27Smillert continue; 349d407ca27Smillert } 350d407ca27Smillert /* stuff peculiar to third file or different in all */ 351d407ca27Smillert if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 352d407ca27Smillert dup = duplicate(&d1->old,&d2->old); 353d407ca27Smillert /* 354d407ca27Smillert * dup = 0 means all files differ 3558fa21293Sotto * dup = 1 means files 1 and 2 identical 356d407ca27Smillert */ 357d407ca27Smillert if (eflag==0) { 358d407ca27Smillert separate(dup ? "3" : ""); 359d407ca27Smillert change(1, &d1->old, dup); 360d407ca27Smillert change(2, &d2->old, 0); 361d407ca27Smillert d3 = d1->old.to > d1->old.from ? d1 : d2; 362d407ca27Smillert change(3, &d3->new, 0); 363d407ca27Smillert } else 364d407ca27Smillert j = edit(d1, dup, j); 365d407ca27Smillert d1++; 366d407ca27Smillert d2++; 367d407ca27Smillert continue; 368d407ca27Smillert } 369d407ca27Smillert /* 370d407ca27Smillert * Overlapping changes from file 1 and 2; extend changes 371d407ca27Smillert * appropriately to make them coincide. 372d407ca27Smillert */ 373d407ca27Smillert if (d1->new.from < d2->new.from) { 374d407ca27Smillert d2->old.from -= d2->new.from-d1->new.from; 375d407ca27Smillert d2->new.from = d1->new.from; 376d407ca27Smillert } else if (d2->new.from < d1->new.from) { 377d407ca27Smillert d1->old.from -= d1->new.from-d2->new.from; 378d407ca27Smillert d1->new.from = d2->new.from; 379d407ca27Smillert } 380d407ca27Smillert if (d1->new.to > d2->new.to) { 381d407ca27Smillert d2->old.to += d1->new.to - d2->new.to; 382d407ca27Smillert d2->new.to = d1->new.to; 383d407ca27Smillert } else if (d2->new.to > d1->new.to) { 384d407ca27Smillert d1->old.to += d2->new.to - d1->new.to; 385d407ca27Smillert d1->new.to = d2->new.to; 386d407ca27Smillert } 387d407ca27Smillert } 388d407ca27Smillert if (eflag) 389d407ca27Smillert edscript(j); 390d407ca27Smillert } 391d407ca27Smillert 392d407ca27Smillert void 393d407ca27Smillert separate(const char *s) 394d407ca27Smillert { 395d407ca27Smillert printf("====%s\n", s); 396d407ca27Smillert } 397d407ca27Smillert 398d407ca27Smillert /* 399d407ca27Smillert * The range of lines rold.from thru rold.to in file i is to be changed. 400d407ca27Smillert * It is to be printed only if it does not duplicate something to be 401d407ca27Smillert * printed later. 402d407ca27Smillert */ 403d407ca27Smillert void 404d407ca27Smillert change(int i, struct range *rold, int dup) 405d407ca27Smillert { 406d407ca27Smillert printf("%d:", i); 407d407ca27Smillert last[i] = rold->to; 408d407ca27Smillert prange(rold); 409d407ca27Smillert if (dup || debug) 410d407ca27Smillert return; 411d407ca27Smillert i--; 412d407ca27Smillert (void)skip(i, rold->from, NULL); 413d407ca27Smillert (void)skip(i, rold->to, " "); 414d407ca27Smillert } 415d407ca27Smillert 416d407ca27Smillert /* 417d407ca27Smillert * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 418d407ca27Smillert */ 419d407ca27Smillert void 420d407ca27Smillert prange(struct range *rold) 421d407ca27Smillert { 422d407ca27Smillert if (rold->to <= rold->from) 423d407ca27Smillert printf("%da\n", rold->from - 1); 424d407ca27Smillert else { 425d407ca27Smillert printf("%d", rold->from); 426d407ca27Smillert if (rold->to > rold->from+1) 427d407ca27Smillert printf(",%d", rold->to - 1); 428d407ca27Smillert printf("c\n"); 429d407ca27Smillert } 430d407ca27Smillert } 431d407ca27Smillert 432d407ca27Smillert /* 433d407ca27Smillert * No difference was reported by diff between file 1 (or 2) and file 3, 434d407ca27Smillert * and an artificial dummy difference (trange) must be ginned up to 435d407ca27Smillert * correspond to the change reported in the other file. 436d407ca27Smillert */ 437d407ca27Smillert void 438d407ca27Smillert keep(int i, struct range *rnew) 439d407ca27Smillert { 440d407ca27Smillert int delta; 441d407ca27Smillert struct range trange; 442d407ca27Smillert 443d407ca27Smillert delta = last[3] - last[i]; 444d407ca27Smillert trange.from = rnew->from - delta; 445d407ca27Smillert trange.to = rnew->to - delta; 446d407ca27Smillert change(i, &trange, 1); 447d407ca27Smillert } 448d407ca27Smillert 449d407ca27Smillert /* 4508fa21293Sotto * skip to just before line number from in file "i". If "pr" is non-NULL, 451d407ca27Smillert * print all skipped stuff with string pr as a prefix. 452d407ca27Smillert */ 453d407ca27Smillert int 454d407ca27Smillert skip(int i, int from, char *pr) 455d407ca27Smillert { 456ad7191bdSmillert size_t j, n; 457ad7191bdSmillert char *line; 458d407ca27Smillert 459d407ca27Smillert for (n = 0; cline[i] < from - 1; n += j) { 460f9bbbf45Sfgsch if ((line = get_line(fp[i], &j)) == NULL) 461d407ca27Smillert trouble(); 462d407ca27Smillert if (pr != NULL) 463d407ca27Smillert printf("%s%s", pr, line); 464d407ca27Smillert cline[i]++; 465d407ca27Smillert } 466ad7191bdSmillert return ((int) n); 467d407ca27Smillert } 468d407ca27Smillert 469d407ca27Smillert /* 470d407ca27Smillert * Return 1 or 0 according as the old range (in file 1) contains exactly 471d407ca27Smillert * the same data as the new range (in file 2). 472d407ca27Smillert */ 473d407ca27Smillert int 474d407ca27Smillert duplicate(struct range *r1, struct range *r2) 475d407ca27Smillert { 476d407ca27Smillert int c,d; 477d407ca27Smillert int nchar; 478d407ca27Smillert int nline; 479d407ca27Smillert 480d407ca27Smillert if (r1->to-r1->from != r2->to-r2->from) 481d407ca27Smillert return (0); 482d407ca27Smillert (void)skip(0, r1->from, NULL); 483d407ca27Smillert (void)skip(1, r2->from, NULL); 484d407ca27Smillert nchar = 0; 485d407ca27Smillert for (nline=0; nline < r1->to - r1->from; nline++) { 486d407ca27Smillert do { 487d407ca27Smillert c = getc(fp[0]); 488d407ca27Smillert d = getc(fp[1]); 489d407ca27Smillert if (c == -1 || d== -1) 490d407ca27Smillert trouble(); 491d407ca27Smillert nchar++; 492d407ca27Smillert if (c != d) { 493d407ca27Smillert repos(nchar); 494d407ca27Smillert return (0); 495d407ca27Smillert } 496d407ca27Smillert } while (c != '\n'); 497d407ca27Smillert } 498d407ca27Smillert repos(nchar); 499d407ca27Smillert return (1); 500d407ca27Smillert } 501d407ca27Smillert 502d407ca27Smillert void 503d407ca27Smillert repos(int nchar) 504d407ca27Smillert { 505d407ca27Smillert int i; 506d407ca27Smillert 507d407ca27Smillert for (i = 0; i < 2; i++) 508a52c79cdStobias (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 509d407ca27Smillert } 510d407ca27Smillert 511d407ca27Smillert __dead void 512d407ca27Smillert trouble(void) 513d407ca27Smillert { 514d407ca27Smillert errx(EXIT_FAILURE, "logic error"); 515d407ca27Smillert } 516d407ca27Smillert 517d407ca27Smillert /* 518d407ca27Smillert * collect an editing script for later regurgitation 519d407ca27Smillert */ 520d407ca27Smillert int 521d407ca27Smillert edit(struct diff *diff, int dup, int j) 522d407ca27Smillert { 523d407ca27Smillert if (((dup + 1) & eflag) == 0) 524d407ca27Smillert return (j); 525d407ca27Smillert j++; 526d407ca27Smillert overlap[j] = !dup; 527d407ca27Smillert if (!dup) 528d407ca27Smillert overlapcnt++; 529d407ca27Smillert de[j].old.from = diff->old.from; 530d407ca27Smillert de[j].old.to = diff->old.to; 531d407ca27Smillert de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 532d407ca27Smillert de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 533d407ca27Smillert return (j); 534d407ca27Smillert } 535d407ca27Smillert 536d407ca27Smillert /* regurgitate */ 537d407ca27Smillert __dead void 538d407ca27Smillert edscript(int n) 539d407ca27Smillert { 540d407ca27Smillert int j,k; 541d407ca27Smillert char block[BUFSIZ]; 542d407ca27Smillert 543d407ca27Smillert for (n = n; n > 0; n--) { 544d407ca27Smillert if (!oflag || !overlap[n]) 545d407ca27Smillert prange(&de[n].old); 546d407ca27Smillert else 547d407ca27Smillert printf("%da\n=======\n", de[n].old.to -1); 548a52c79cdStobias (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET); 549d407ca27Smillert for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 550d407ca27Smillert j = k > BUFSIZ ? BUFSIZ : k; 551d407ca27Smillert if (fread(block, 1, j, fp[2]) != j) 552d407ca27Smillert trouble(); 553d407ca27Smillert (void)fwrite(block, 1, j, stdout); 554d407ca27Smillert } 555d407ca27Smillert if (!oflag || !overlap[n]) 556d407ca27Smillert printf(".\n"); 557d407ca27Smillert else { 558d407ca27Smillert printf("%s\n.\n", f3mark); 559d407ca27Smillert printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 560d407ca27Smillert } 561d407ca27Smillert } 562d407ca27Smillert exit(overlapcnt); 563d407ca27Smillert } 564d407ca27Smillert 56568496fbfSotto void 56668496fbfSotto increase(void) 56768496fbfSotto { 56868496fbfSotto struct diff *p; 56968496fbfSotto char *q; 57068496fbfSotto size_t newsz, incr; 57168496fbfSotto 57268496fbfSotto /* are the memset(3) calls needed? */ 57368496fbfSotto newsz = szchanges == 0 ? 64 : 2 * szchanges; 57468496fbfSotto incr = newsz - szchanges; 57568496fbfSotto 576*5302ee64Sderaadt p = reallocarray(d13, newsz, sizeof(struct diff)); 57768496fbfSotto if (p == NULL) 57868496fbfSotto err(1, NULL); 57968496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58068496fbfSotto d13 = p; 581*5302ee64Sderaadt p = reallocarray(d23, newsz, sizeof(struct diff)); 58268496fbfSotto if (p == NULL) 58368496fbfSotto err(1, NULL); 58468496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58568496fbfSotto d23 = p; 586*5302ee64Sderaadt p = reallocarray(de, newsz, sizeof(struct diff)); 58768496fbfSotto if (p == NULL) 58868496fbfSotto err(1, NULL); 58968496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 59068496fbfSotto de = p; 591*5302ee64Sderaadt q = reallocarray(overlap, newsz, sizeof(char)); 59268496fbfSotto if (q == NULL) 59368496fbfSotto err(1, NULL); 59468496fbfSotto memset(q + szchanges, 0, incr * sizeof(char)); 59568496fbfSotto overlap = q; 59668496fbfSotto szchanges = newsz; 59768496fbfSotto } 59868496fbfSotto 59968496fbfSotto 600d407ca27Smillert __dead void 601d407ca27Smillert usage(void) 602d407ca27Smillert { 603d407ca27Smillert extern char *__progname; 604d407ca27Smillert 605d407ca27Smillert fprintf(stderr, "usage: %s [-exEX3] /tmp/d3a.?????????? " 606d407ca27Smillert "/tmp/d3b.?????????? file1 file2 file3\n", __progname); 607d407ca27Smillert exit(EXIT_FAILURE); 608d407ca27Smillert } 609