1*bd1f1994Smillert /* $OpenBSD: diff3prog.c,v 1.18 2016/10/16 13:03:40 millert 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 1480bd1216cSderaadt if (pledge("stdio rpath", NULL) == -1) 1490bd1216cSderaadt err(1, "pledge"); 15018cdc269Sderaadt 151d407ca27Smillert eflag = 0; 152d407ca27Smillert oflag = 0; 153d407ca27Smillert while ((ch = getopt(argc, argv, "EeXx3")) != -1) { 154d407ca27Smillert switch (ch) { 155d407ca27Smillert case 'E': 156d407ca27Smillert eflag = 3; 157d407ca27Smillert oflag = 1; 158d407ca27Smillert break; 159d407ca27Smillert case 'e': 160d407ca27Smillert eflag = 3; 161d407ca27Smillert break; 162d407ca27Smillert case 'X': 163d407ca27Smillert oflag = eflag = 1; 164d407ca27Smillert break; 165d407ca27Smillert case 'x': 166d407ca27Smillert eflag = 1; 167d407ca27Smillert break; 168d407ca27Smillert case '3': 169d407ca27Smillert eflag = 2; 170d407ca27Smillert break; 171d407ca27Smillert } 172d407ca27Smillert } 173d407ca27Smillert argc -= optind; 174d407ca27Smillert argv += optind; 175d407ca27Smillert /* XXX - argc usage seems wrong here */ 176d407ca27Smillert if (argc < 5) 177d407ca27Smillert usage(); 178d407ca27Smillert 179d407ca27Smillert if (oflag) { 180d407ca27Smillert (void)snprintf(f1mark, sizeof(f1mark), "<<<<<<< %s", 181d407ca27Smillert argc >= 6 ? argv[5] : argv[2]); 182d407ca27Smillert (void)snprintf(f3mark, sizeof(f3mark), ">>>>>>> %s", 183d407ca27Smillert argc >= 7 ? argv[6] : argv[4]); 184d407ca27Smillert } 185d407ca27Smillert 18668496fbfSotto increase(); 18768496fbfSotto m = readin(argv[0], &d13); 18868496fbfSotto n = readin(argv[1], &d23); 189d407ca27Smillert for (i = 0; i <= 2; i++) { 1902e6633a8Stobias if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) 1912e6633a8Stobias err(EXIT_FAILURE, "can't open %s", argv[i + 2]); 192d407ca27Smillert } 193d407ca27Smillert merge(m, n); 194d407ca27Smillert exit(EXIT_SUCCESS); 195d407ca27Smillert } 196d407ca27Smillert 197d407ca27Smillert /* 1988fa21293Sotto * Pick up the line numbers of all changes from one change file. 199d407ca27Smillert * (This puts the numbers in a vector, which is not strictly necessary, 200d407ca27Smillert * since the vector is processed in one sequential pass. 201d407ca27Smillert * The vector could be optimized out of existence) 202d407ca27Smillert */ 203d407ca27Smillert int 20468496fbfSotto readin(char *name, struct diff **dd) 205d407ca27Smillert { 206ad7191bdSmillert int a, b, c, d, i; 207ad7191bdSmillert char kind, *p; 208ad7191bdSmillert 209d407ca27Smillert fp[0] = fopen(name, "r"); 2102e6633a8Stobias if (fp[0] == NULL) 2112e6633a8Stobias err(EXIT_FAILURE, "can't open %s", name); 212ad7191bdSmillert for (i=0; (p = getchange(fp[0])); i++) { 21368496fbfSotto if (i >= szchanges - 1) 21468496fbfSotto increase(); 215d407ca27Smillert a = b = number(&p); 216d407ca27Smillert if (*p == ',') { 217d407ca27Smillert p++; 218d407ca27Smillert b = number(&p); 219d407ca27Smillert } 220d407ca27Smillert kind = *p++; 221d407ca27Smillert c = d = number(&p); 222d407ca27Smillert if (*p==',') { 223d407ca27Smillert p++; 224d407ca27Smillert d = number(&p); 225d407ca27Smillert } 226d407ca27Smillert if (kind == 'a') 227d407ca27Smillert a++; 228d407ca27Smillert if (kind == 'd') 229d407ca27Smillert c++; 230d407ca27Smillert b++; 231d407ca27Smillert d++; 23268496fbfSotto (*dd)[i].old.from = a; 23368496fbfSotto (*dd)[i].old.to = b; 23468496fbfSotto (*dd)[i].new.from = c; 23568496fbfSotto (*dd)[i].new.to = d; 236d407ca27Smillert } 2376daeeae1Smarkus if (i) { 23868496fbfSotto (*dd)[i].old.from = (*dd)[i-1].old.to; 23968496fbfSotto (*dd)[i].new.from = (*dd)[i-1].new.to; 2406daeeae1Smarkus } 241d407ca27Smillert (void)fclose(fp[0]); 242d407ca27Smillert return (i); 243d407ca27Smillert } 244d407ca27Smillert 245d407ca27Smillert int 246d407ca27Smillert number(char **lc) 247d407ca27Smillert { 248d407ca27Smillert int nn; 249d407ca27Smillert nn = 0; 250d407ca27Smillert while (isdigit((unsigned char)(**lc))) 251d407ca27Smillert nn = nn*10 + *(*lc)++ - '0'; 252d407ca27Smillert return (nn); 253d407ca27Smillert } 254d407ca27Smillert 255ad7191bdSmillert char * 256d407ca27Smillert getchange(FILE *b) 257d407ca27Smillert { 258ad7191bdSmillert char *line; 259ad7191bdSmillert 260f9bbbf45Sfgsch while ((line = get_line(b, NULL))) { 261d407ca27Smillert if (isdigit((unsigned char)line[0])) 262ad7191bdSmillert return (line); 263d407ca27Smillert } 264ad7191bdSmillert return (NULL); 265d407ca27Smillert } 266d407ca27Smillert 267ad7191bdSmillert char * 268f9bbbf45Sfgsch get_line(FILE *b, size_t *n) 269d407ca27Smillert { 270ad7191bdSmillert char *cp; 271ad7191bdSmillert size_t len; 272ad7191bdSmillert static char *buf; 273ad7191bdSmillert static size_t bufsize; 274d407ca27Smillert 275ad7191bdSmillert if ((cp = fgetln(b, &len)) == NULL) 276ad7191bdSmillert return (NULL); 277ad7191bdSmillert 278ad7191bdSmillert if (cp[len - 1] != '\n') 279ad7191bdSmillert len++; 280ad7191bdSmillert if (len + 1 > bufsize) { 281ad7191bdSmillert do { 282ad7191bdSmillert bufsize += 1024; 283ad7191bdSmillert } while (len + 1 > bufsize); 284ad7191bdSmillert if ((buf = realloc(buf, bufsize)) == NULL) 285ad7191bdSmillert err(EXIT_FAILURE, NULL); 286d407ca27Smillert } 287ad7191bdSmillert memcpy(buf, cp, len - 1); 288ad7191bdSmillert buf[len - 1] = '\n'; 289ad7191bdSmillert buf[len] = '\0'; 290ad7191bdSmillert if (n != NULL) 291ad7191bdSmillert *n = len; 292ad7191bdSmillert return (buf); 293d407ca27Smillert } 294d407ca27Smillert 295d407ca27Smillert void 296d407ca27Smillert merge(int m1, int m2) 297d407ca27Smillert { 298d407ca27Smillert struct diff *d1, *d2, *d3; 299d407ca27Smillert int dup, j, t1, t2; 300d407ca27Smillert 301d407ca27Smillert d1 = d13; 302d407ca27Smillert d2 = d23; 303d407ca27Smillert j = 0; 304d927f21fSjsg while ((t1 = (d1 < d13 + m1)) | (t2 = (d2 < d23 + m2))) { 305d407ca27Smillert if (debug) { 306d407ca27Smillert printf("%d,%d=%d,%d %d,%d=%d,%d\n", 307d407ca27Smillert d1->old.from,d1->old.to, 308d407ca27Smillert d1->new.from,d1->new.to, 309d407ca27Smillert d2->old.from,d2->old.to, 310d407ca27Smillert d2->new.from,d2->new.to); 311d407ca27Smillert } 312d407ca27Smillert /* first file is different from others */ 3130b1c43dfScanacar if (!t2 || (t1 && d1->new.to < d2->new.from)) { 314d407ca27Smillert /* stuff peculiar to 1st file */ 315d407ca27Smillert if (eflag==0) { 316d407ca27Smillert separate("1"); 317d407ca27Smillert change(1, &d1->old, 0); 318d407ca27Smillert keep(2, &d1->new); 319d407ca27Smillert change(3, &d1->new, 0); 320d407ca27Smillert } 321d407ca27Smillert d1++; 322d407ca27Smillert continue; 323d407ca27Smillert } 324d407ca27Smillert /* second file is different from others */ 3250b1c43dfScanacar if (!t1 || (t2 && d2->new.to < d1->new.from)) { 326d407ca27Smillert if (eflag==0) { 327d407ca27Smillert separate("2"); 328d407ca27Smillert keep(1, &d2->new); 329d407ca27Smillert change(2, &d2->old, 0); 330d407ca27Smillert change(3, &d2->new, 0); 331d407ca27Smillert } 332d407ca27Smillert d2++; 333d407ca27Smillert continue; 334d407ca27Smillert } 335d407ca27Smillert /* 336d407ca27Smillert * Merge overlapping changes in first file 337d407ca27Smillert * this happens after extension (see below). 338d407ca27Smillert */ 339d407ca27Smillert if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 340d407ca27Smillert d1[1].old.from = d1->old.from; 341d407ca27Smillert d1[1].new.from = d1->new.from; 342d407ca27Smillert d1++; 343d407ca27Smillert continue; 344d407ca27Smillert } 345d407ca27Smillert 346d407ca27Smillert /* merge overlapping changes in second */ 347d407ca27Smillert if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 348d407ca27Smillert d2[1].old.from = d2->old.from; 349d407ca27Smillert d2[1].new.from = d2->new.from; 350d407ca27Smillert d2++; 351d407ca27Smillert continue; 352d407ca27Smillert } 353d407ca27Smillert /* stuff peculiar to third file or different in all */ 354d407ca27Smillert if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 355d407ca27Smillert dup = duplicate(&d1->old,&d2->old); 356d407ca27Smillert /* 357d407ca27Smillert * dup = 0 means all files differ 3588fa21293Sotto * dup = 1 means files 1 and 2 identical 359d407ca27Smillert */ 360d407ca27Smillert if (eflag==0) { 361d407ca27Smillert separate(dup ? "3" : ""); 362d407ca27Smillert change(1, &d1->old, dup); 363d407ca27Smillert change(2, &d2->old, 0); 364d407ca27Smillert d3 = d1->old.to > d1->old.from ? d1 : d2; 365d407ca27Smillert change(3, &d3->new, 0); 366d407ca27Smillert } else 367d407ca27Smillert j = edit(d1, dup, j); 368d407ca27Smillert d1++; 369d407ca27Smillert d2++; 370d407ca27Smillert continue; 371d407ca27Smillert } 372d407ca27Smillert /* 373d407ca27Smillert * Overlapping changes from file 1 and 2; extend changes 374d407ca27Smillert * appropriately to make them coincide. 375d407ca27Smillert */ 376d407ca27Smillert if (d1->new.from < d2->new.from) { 377d407ca27Smillert d2->old.from -= d2->new.from-d1->new.from; 378d407ca27Smillert d2->new.from = d1->new.from; 379d407ca27Smillert } else if (d2->new.from < d1->new.from) { 380d407ca27Smillert d1->old.from -= d1->new.from-d2->new.from; 381d407ca27Smillert d1->new.from = d2->new.from; 382d407ca27Smillert } 383d407ca27Smillert if (d1->new.to > d2->new.to) { 384d407ca27Smillert d2->old.to += d1->new.to - d2->new.to; 385d407ca27Smillert d2->new.to = d1->new.to; 386d407ca27Smillert } else if (d2->new.to > d1->new.to) { 387d407ca27Smillert d1->old.to += d2->new.to - d1->new.to; 388d407ca27Smillert d1->new.to = d2->new.to; 389d407ca27Smillert } 390d407ca27Smillert } 391d407ca27Smillert if (eflag) 392d407ca27Smillert edscript(j); 393d407ca27Smillert } 394d407ca27Smillert 395d407ca27Smillert void 396d407ca27Smillert separate(const char *s) 397d407ca27Smillert { 398d407ca27Smillert printf("====%s\n", s); 399d407ca27Smillert } 400d407ca27Smillert 401d407ca27Smillert /* 402d407ca27Smillert * The range of lines rold.from thru rold.to in file i is to be changed. 403d407ca27Smillert * It is to be printed only if it does not duplicate something to be 404d407ca27Smillert * printed later. 405d407ca27Smillert */ 406d407ca27Smillert void 407d407ca27Smillert change(int i, struct range *rold, int dup) 408d407ca27Smillert { 409d407ca27Smillert printf("%d:", i); 410d407ca27Smillert last[i] = rold->to; 411d407ca27Smillert prange(rold); 412d407ca27Smillert if (dup || debug) 413d407ca27Smillert return; 414d407ca27Smillert i--; 415d407ca27Smillert (void)skip(i, rold->from, NULL); 416d407ca27Smillert (void)skip(i, rold->to, " "); 417d407ca27Smillert } 418d407ca27Smillert 419d407ca27Smillert /* 420d407ca27Smillert * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 421d407ca27Smillert */ 422d407ca27Smillert void 423d407ca27Smillert prange(struct range *rold) 424d407ca27Smillert { 425d407ca27Smillert if (rold->to <= rold->from) 426d407ca27Smillert printf("%da\n", rold->from - 1); 427d407ca27Smillert else { 428d407ca27Smillert printf("%d", rold->from); 429d407ca27Smillert if (rold->to > rold->from+1) 430d407ca27Smillert printf(",%d", rold->to - 1); 431d407ca27Smillert printf("c\n"); 432d407ca27Smillert } 433d407ca27Smillert } 434d407ca27Smillert 435d407ca27Smillert /* 436d407ca27Smillert * No difference was reported by diff between file 1 (or 2) and file 3, 437d407ca27Smillert * and an artificial dummy difference (trange) must be ginned up to 438d407ca27Smillert * correspond to the change reported in the other file. 439d407ca27Smillert */ 440d407ca27Smillert void 441d407ca27Smillert keep(int i, struct range *rnew) 442d407ca27Smillert { 443d407ca27Smillert int delta; 444d407ca27Smillert struct range trange; 445d407ca27Smillert 446d407ca27Smillert delta = last[3] - last[i]; 447d407ca27Smillert trange.from = rnew->from - delta; 448d407ca27Smillert trange.to = rnew->to - delta; 449d407ca27Smillert change(i, &trange, 1); 450d407ca27Smillert } 451d407ca27Smillert 452d407ca27Smillert /* 4538fa21293Sotto * skip to just before line number from in file "i". If "pr" is non-NULL, 454d407ca27Smillert * print all skipped stuff with string pr as a prefix. 455d407ca27Smillert */ 456d407ca27Smillert int 457d407ca27Smillert skip(int i, int from, char *pr) 458d407ca27Smillert { 459ad7191bdSmillert size_t j, n; 460ad7191bdSmillert char *line; 461d407ca27Smillert 462d407ca27Smillert for (n = 0; cline[i] < from - 1; n += j) { 463f9bbbf45Sfgsch if ((line = get_line(fp[i], &j)) == NULL) 464d407ca27Smillert trouble(); 465d407ca27Smillert if (pr != NULL) 466d407ca27Smillert printf("%s%s", pr, line); 467d407ca27Smillert cline[i]++; 468d407ca27Smillert } 469ad7191bdSmillert return ((int) n); 470d407ca27Smillert } 471d407ca27Smillert 472d407ca27Smillert /* 473d407ca27Smillert * Return 1 or 0 according as the old range (in file 1) contains exactly 474d407ca27Smillert * the same data as the new range (in file 2). 475d407ca27Smillert */ 476d407ca27Smillert int 477d407ca27Smillert duplicate(struct range *r1, struct range *r2) 478d407ca27Smillert { 479d407ca27Smillert int c,d; 480d407ca27Smillert int nchar; 481d407ca27Smillert int nline; 482d407ca27Smillert 483d407ca27Smillert if (r1->to-r1->from != r2->to-r2->from) 484d407ca27Smillert return (0); 485d407ca27Smillert (void)skip(0, r1->from, NULL); 486d407ca27Smillert (void)skip(1, r2->from, NULL); 487d407ca27Smillert nchar = 0; 488d407ca27Smillert for (nline=0; nline < r1->to - r1->from; nline++) { 489d407ca27Smillert do { 490d407ca27Smillert c = getc(fp[0]); 491d407ca27Smillert d = getc(fp[1]); 492d407ca27Smillert if (c == -1 || d== -1) 493d407ca27Smillert trouble(); 494d407ca27Smillert nchar++; 495d407ca27Smillert if (c != d) { 496d407ca27Smillert repos(nchar); 497d407ca27Smillert return (0); 498d407ca27Smillert } 499d407ca27Smillert } while (c != '\n'); 500d407ca27Smillert } 501d407ca27Smillert repos(nchar); 502d407ca27Smillert return (1); 503d407ca27Smillert } 504d407ca27Smillert 505d407ca27Smillert void 506d407ca27Smillert repos(int nchar) 507d407ca27Smillert { 508d407ca27Smillert int i; 509d407ca27Smillert 510d407ca27Smillert for (i = 0; i < 2; i++) 511a52c79cdStobias (void)fseek(fp[i], (long)-nchar, SEEK_CUR); 512d407ca27Smillert } 513d407ca27Smillert 514d407ca27Smillert __dead void 515d407ca27Smillert trouble(void) 516d407ca27Smillert { 517d407ca27Smillert errx(EXIT_FAILURE, "logic error"); 518d407ca27Smillert } 519d407ca27Smillert 520d407ca27Smillert /* 521d407ca27Smillert * collect an editing script for later regurgitation 522d407ca27Smillert */ 523d407ca27Smillert int 524d407ca27Smillert edit(struct diff *diff, int dup, int j) 525d407ca27Smillert { 526d407ca27Smillert if (((dup + 1) & eflag) == 0) 527d407ca27Smillert return (j); 528d407ca27Smillert j++; 529d407ca27Smillert overlap[j] = !dup; 530d407ca27Smillert if (!dup) 531d407ca27Smillert overlapcnt++; 532d407ca27Smillert de[j].old.from = diff->old.from; 533d407ca27Smillert de[j].old.to = diff->old.to; 534d407ca27Smillert de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 535d407ca27Smillert de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 536d407ca27Smillert return (j); 537d407ca27Smillert } 538d407ca27Smillert 539d407ca27Smillert /* regurgitate */ 540d407ca27Smillert __dead void 541d407ca27Smillert edscript(int n) 542d407ca27Smillert { 543d407ca27Smillert int j,k; 544d407ca27Smillert char block[BUFSIZ]; 545d407ca27Smillert 546*bd1f1994Smillert for (; n > 0; n--) { 547d407ca27Smillert if (!oflag || !overlap[n]) 548d407ca27Smillert prange(&de[n].old); 549d407ca27Smillert else 550d407ca27Smillert printf("%da\n=======\n", de[n].old.to -1); 551a52c79cdStobias (void)fseek(fp[2], (long)de[n].new.from, SEEK_SET); 552d407ca27Smillert for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 553d407ca27Smillert j = k > BUFSIZ ? BUFSIZ : k; 554d407ca27Smillert if (fread(block, 1, j, fp[2]) != j) 555d407ca27Smillert trouble(); 556d407ca27Smillert (void)fwrite(block, 1, j, stdout); 557d407ca27Smillert } 558d407ca27Smillert if (!oflag || !overlap[n]) 559d407ca27Smillert printf(".\n"); 560d407ca27Smillert else { 561d407ca27Smillert printf("%s\n.\n", f3mark); 562d407ca27Smillert printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 563d407ca27Smillert } 564d407ca27Smillert } 565d407ca27Smillert exit(overlapcnt); 566d407ca27Smillert } 567d407ca27Smillert 56868496fbfSotto void 56968496fbfSotto increase(void) 57068496fbfSotto { 57168496fbfSotto struct diff *p; 57268496fbfSotto char *q; 57368496fbfSotto size_t newsz, incr; 57468496fbfSotto 57568496fbfSotto /* are the memset(3) calls needed? */ 57668496fbfSotto newsz = szchanges == 0 ? 64 : 2 * szchanges; 57768496fbfSotto incr = newsz - szchanges; 57868496fbfSotto 5795302ee64Sderaadt p = reallocarray(d13, newsz, sizeof(struct diff)); 58068496fbfSotto if (p == NULL) 58168496fbfSotto err(1, NULL); 58268496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58368496fbfSotto d13 = p; 5845302ee64Sderaadt p = reallocarray(d23, newsz, sizeof(struct diff)); 58568496fbfSotto if (p == NULL) 58668496fbfSotto err(1, NULL); 58768496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 58868496fbfSotto d23 = p; 5895302ee64Sderaadt p = reallocarray(de, newsz, sizeof(struct diff)); 59068496fbfSotto if (p == NULL) 59168496fbfSotto err(1, NULL); 59268496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 59368496fbfSotto de = p; 5945302ee64Sderaadt q = reallocarray(overlap, newsz, sizeof(char)); 59568496fbfSotto if (q == NULL) 59668496fbfSotto err(1, NULL); 59768496fbfSotto memset(q + szchanges, 0, incr * sizeof(char)); 59868496fbfSotto overlap = q; 59968496fbfSotto szchanges = newsz; 60068496fbfSotto } 60168496fbfSotto 60268496fbfSotto 603d407ca27Smillert __dead void 604d407ca27Smillert usage(void) 605d407ca27Smillert { 606d407ca27Smillert extern char *__progname; 607d407ca27Smillert 608d407ca27Smillert fprintf(stderr, "usage: %s [-exEX3] /tmp/d3a.?????????? " 609d407ca27Smillert "/tmp/d3b.?????????? file1 file2 file3\n", __progname); 610d407ca27Smillert exit(EXIT_FAILURE); 611d407ca27Smillert } 612