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