1*68496fbfSotto /* $OpenBSD: diff3prog.c,v 1.7 2005/08/01 08:17:57 otto 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*68496fbfSotto static const char rcsid[] = "$OpenBSD: diff3prog.c,v 1.7 2005/08/01 08:17:57 otto 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 108*68496fbfSotto size_t szchanges; 109*68496fbfSotto 110*68496fbfSotto struct diff *d13; 111*68496fbfSotto 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 */ 119*68496fbfSotto struct diff *de; 120*68496fbfSotto 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 **); 139*68496fbfSotto 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); 149*68496fbfSotto 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 192*68496fbfSotto increase(); 193*68496fbfSotto m = readin(argv[0], &d13); 194*68496fbfSotto n = readin(argv[1], &d23); 195d407ca27Smillert for (i = 0; i <= 2; i++) { 196d407ca27Smillert if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) { 197d407ca27Smillert printf("diff3: can't open %s\n", argv[i + 2]); 198d407ca27Smillert exit(EXIT_FAILURE); 199d407ca27Smillert } 200d407ca27Smillert } 201d407ca27Smillert merge(m, n); 202d407ca27Smillert exit(EXIT_SUCCESS); 203d407ca27Smillert } 204d407ca27Smillert 205d407ca27Smillert /* 2068fa21293Sotto * Pick up the line numbers of all changes from one change file. 207d407ca27Smillert * (This puts the numbers in a vector, which is not strictly necessary, 208d407ca27Smillert * since the vector is processed in one sequential pass. 209d407ca27Smillert * The vector could be optimized out of existence) 210d407ca27Smillert */ 211d407ca27Smillert int 212*68496fbfSotto readin(char *name, struct diff **dd) 213d407ca27Smillert { 214ad7191bdSmillert int a, b, c, d, i; 215ad7191bdSmillert char kind, *p; 216ad7191bdSmillert 217d407ca27Smillert fp[0] = fopen(name, "r"); 218ad7191bdSmillert for (i=0; (p = getchange(fp[0])); i++) { 219*68496fbfSotto if (i >= szchanges - 1) 220*68496fbfSotto 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++; 238*68496fbfSotto (*dd)[i].old.from = a; 239*68496fbfSotto (*dd)[i].old.to = b; 240*68496fbfSotto (*dd)[i].new.from = c; 241*68496fbfSotto (*dd)[i].new.to = d; 242d407ca27Smillert } 243*68496fbfSotto (*dd)[i].old.from = (*dd)[i-1].old.to; 244*68496fbfSotto (*dd)[i].new.from = (*dd)[i-1].new.to; 245d407ca27Smillert (void)fclose(fp[0]); 246d407ca27Smillert return (i); 247d407ca27Smillert } 248d407ca27Smillert 249d407ca27Smillert int 250d407ca27Smillert number(char **lc) 251d407ca27Smillert { 252d407ca27Smillert int nn; 253d407ca27Smillert nn = 0; 254d407ca27Smillert while (isdigit((unsigned char)(**lc))) 255d407ca27Smillert nn = nn*10 + *(*lc)++ - '0'; 256d407ca27Smillert return (nn); 257d407ca27Smillert } 258d407ca27Smillert 259ad7191bdSmillert char * 260d407ca27Smillert getchange(FILE *b) 261d407ca27Smillert { 262ad7191bdSmillert char *line; 263ad7191bdSmillert 264ad7191bdSmillert while ((line = getline(b, NULL))) { 265d407ca27Smillert if (isdigit((unsigned char)line[0])) 266ad7191bdSmillert return (line); 267d407ca27Smillert } 268ad7191bdSmillert return (NULL); 269d407ca27Smillert } 270d407ca27Smillert 271ad7191bdSmillert char * 272ad7191bdSmillert getline(FILE *b, size_t *n) 273d407ca27Smillert { 274ad7191bdSmillert char *cp; 275ad7191bdSmillert size_t len; 276ad7191bdSmillert static char *buf; 277ad7191bdSmillert static size_t bufsize; 278d407ca27Smillert 279ad7191bdSmillert if ((cp = fgetln(b, &len)) == NULL) 280ad7191bdSmillert return (NULL); 281ad7191bdSmillert 282ad7191bdSmillert if (cp[len - 1] != '\n') 283ad7191bdSmillert len++; 284ad7191bdSmillert if (len + 1 > bufsize) { 285ad7191bdSmillert do { 286ad7191bdSmillert bufsize += 1024; 287ad7191bdSmillert } while (len + 1 > bufsize); 288ad7191bdSmillert if ((buf = realloc(buf, bufsize)) == NULL) 289ad7191bdSmillert err(EXIT_FAILURE, NULL); 290d407ca27Smillert } 291ad7191bdSmillert memcpy(buf, cp, len - 1); 292ad7191bdSmillert buf[len - 1] = '\n'; 293ad7191bdSmillert buf[len] = '\0'; 294ad7191bdSmillert if (n != NULL) 295ad7191bdSmillert *n = len; 296ad7191bdSmillert return (buf); 297d407ca27Smillert } 298d407ca27Smillert 299d407ca27Smillert void 300d407ca27Smillert merge(int m1, int m2) 301d407ca27Smillert { 302d407ca27Smillert struct diff *d1, *d2, *d3; 303d407ca27Smillert int dup, j, t1, t2; 304d407ca27Smillert 305d407ca27Smillert d1 = d13; 306d407ca27Smillert d2 = d23; 307d407ca27Smillert j = 0; 308d407ca27Smillert while ((t1 = d1 < d13 + m1) | (t2 = d2 < d23 + m2)) { 309d407ca27Smillert if (debug) { 310d407ca27Smillert printf("%d,%d=%d,%d %d,%d=%d,%d\n", 311d407ca27Smillert d1->old.from,d1->old.to, 312d407ca27Smillert d1->new.from,d1->new.to, 313d407ca27Smillert d2->old.from,d2->old.to, 314d407ca27Smillert d2->new.from,d2->new.to); 315d407ca27Smillert } 316d407ca27Smillert /* first file is different from others */ 3170b1c43dfScanacar if (!t2 || (t1 && d1->new.to < d2->new.from)) { 318d407ca27Smillert /* stuff peculiar to 1st file */ 319d407ca27Smillert if (eflag==0) { 320d407ca27Smillert separate("1"); 321d407ca27Smillert change(1, &d1->old, 0); 322d407ca27Smillert keep(2, &d1->new); 323d407ca27Smillert change(3, &d1->new, 0); 324d407ca27Smillert } 325d407ca27Smillert d1++; 326d407ca27Smillert continue; 327d407ca27Smillert } 328d407ca27Smillert /* second file is different from others */ 3290b1c43dfScanacar if (!t1 || (t2 && d2->new.to < d1->new.from)) { 330d407ca27Smillert if (eflag==0) { 331d407ca27Smillert separate("2"); 332d407ca27Smillert keep(1, &d2->new); 333d407ca27Smillert change(2, &d2->old, 0); 334d407ca27Smillert change(3, &d2->new, 0); 335d407ca27Smillert } 336d407ca27Smillert d2++; 337d407ca27Smillert continue; 338d407ca27Smillert } 339d407ca27Smillert /* 340d407ca27Smillert * Merge overlapping changes in first file 341d407ca27Smillert * this happens after extension (see below). 342d407ca27Smillert */ 343d407ca27Smillert if (d1 + 1 < d13 + m1 && d1->new.to >= d1[1].new.from) { 344d407ca27Smillert d1[1].old.from = d1->old.from; 345d407ca27Smillert d1[1].new.from = d1->new.from; 346d407ca27Smillert d1++; 347d407ca27Smillert continue; 348d407ca27Smillert } 349d407ca27Smillert 350d407ca27Smillert /* merge overlapping changes in second */ 351d407ca27Smillert if (d2 + 1 < d23 + m2 && d2->new.to >= d2[1].new.from) { 352d407ca27Smillert d2[1].old.from = d2->old.from; 353d407ca27Smillert d2[1].new.from = d2->new.from; 354d407ca27Smillert d2++; 355d407ca27Smillert continue; 356d407ca27Smillert } 357d407ca27Smillert /* stuff peculiar to third file or different in all */ 358d407ca27Smillert if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) { 359d407ca27Smillert dup = duplicate(&d1->old,&d2->old); 360d407ca27Smillert /* 361d407ca27Smillert * dup = 0 means all files differ 3628fa21293Sotto * dup = 1 means files 1 and 2 identical 363d407ca27Smillert */ 364d407ca27Smillert if (eflag==0) { 365d407ca27Smillert separate(dup ? "3" : ""); 366d407ca27Smillert change(1, &d1->old, dup); 367d407ca27Smillert change(2, &d2->old, 0); 368d407ca27Smillert d3 = d1->old.to > d1->old.from ? d1 : d2; 369d407ca27Smillert change(3, &d3->new, 0); 370d407ca27Smillert } else 371d407ca27Smillert j = edit(d1, dup, j); 372d407ca27Smillert d1++; 373d407ca27Smillert d2++; 374d407ca27Smillert continue; 375d407ca27Smillert } 376d407ca27Smillert /* 377d407ca27Smillert * Overlapping changes from file 1 and 2; extend changes 378d407ca27Smillert * appropriately to make them coincide. 379d407ca27Smillert */ 380d407ca27Smillert if (d1->new.from < d2->new.from) { 381d407ca27Smillert d2->old.from -= d2->new.from-d1->new.from; 382d407ca27Smillert d2->new.from = d1->new.from; 383d407ca27Smillert } else if (d2->new.from < d1->new.from) { 384d407ca27Smillert d1->old.from -= d1->new.from-d2->new.from; 385d407ca27Smillert d1->new.from = d2->new.from; 386d407ca27Smillert } 387d407ca27Smillert if (d1->new.to > d2->new.to) { 388d407ca27Smillert d2->old.to += d1->new.to - d2->new.to; 389d407ca27Smillert d2->new.to = d1->new.to; 390d407ca27Smillert } else if (d2->new.to > d1->new.to) { 391d407ca27Smillert d1->old.to += d2->new.to - d1->new.to; 392d407ca27Smillert d1->new.to = d2->new.to; 393d407ca27Smillert } 394d407ca27Smillert } 395d407ca27Smillert if (eflag) 396d407ca27Smillert edscript(j); 397d407ca27Smillert } 398d407ca27Smillert 399d407ca27Smillert void 400d407ca27Smillert separate(const char *s) 401d407ca27Smillert { 402d407ca27Smillert printf("====%s\n", s); 403d407ca27Smillert } 404d407ca27Smillert 405d407ca27Smillert /* 406d407ca27Smillert * The range of lines rold.from thru rold.to in file i is to be changed. 407d407ca27Smillert * It is to be printed only if it does not duplicate something to be 408d407ca27Smillert * printed later. 409d407ca27Smillert */ 410d407ca27Smillert void 411d407ca27Smillert change(int i, struct range *rold, int dup) 412d407ca27Smillert { 413d407ca27Smillert printf("%d:", i); 414d407ca27Smillert last[i] = rold->to; 415d407ca27Smillert prange(rold); 416d407ca27Smillert if (dup || debug) 417d407ca27Smillert return; 418d407ca27Smillert i--; 419d407ca27Smillert (void)skip(i, rold->from, NULL); 420d407ca27Smillert (void)skip(i, rold->to, " "); 421d407ca27Smillert } 422d407ca27Smillert 423d407ca27Smillert /* 424d407ca27Smillert * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1 425d407ca27Smillert */ 426d407ca27Smillert void 427d407ca27Smillert prange(struct range *rold) 428d407ca27Smillert { 429d407ca27Smillert if (rold->to <= rold->from) 430d407ca27Smillert printf("%da\n", rold->from - 1); 431d407ca27Smillert else { 432d407ca27Smillert printf("%d", rold->from); 433d407ca27Smillert if (rold->to > rold->from+1) 434d407ca27Smillert printf(",%d", rold->to - 1); 435d407ca27Smillert printf("c\n"); 436d407ca27Smillert } 437d407ca27Smillert } 438d407ca27Smillert 439d407ca27Smillert /* 440d407ca27Smillert * No difference was reported by diff between file 1 (or 2) and file 3, 441d407ca27Smillert * and an artificial dummy difference (trange) must be ginned up to 442d407ca27Smillert * correspond to the change reported in the other file. 443d407ca27Smillert */ 444d407ca27Smillert void 445d407ca27Smillert keep(int i, struct range *rnew) 446d407ca27Smillert { 447d407ca27Smillert int delta; 448d407ca27Smillert struct range trange; 449d407ca27Smillert 450d407ca27Smillert delta = last[3] - last[i]; 451d407ca27Smillert trange.from = rnew->from - delta; 452d407ca27Smillert trange.to = rnew->to - delta; 453d407ca27Smillert change(i, &trange, 1); 454d407ca27Smillert } 455d407ca27Smillert 456d407ca27Smillert /* 4578fa21293Sotto * skip to just before line number from in file "i". If "pr" is non-NULL, 458d407ca27Smillert * print all skipped stuff with string pr as a prefix. 459d407ca27Smillert */ 460d407ca27Smillert int 461d407ca27Smillert skip(int i, int from, char *pr) 462d407ca27Smillert { 463ad7191bdSmillert size_t j, n; 464ad7191bdSmillert char *line; 465d407ca27Smillert 466d407ca27Smillert for (n = 0; cline[i] < from - 1; n += j) { 467ad7191bdSmillert if ((line = getline(fp[i], &j)) == NULL) 468d407ca27Smillert trouble(); 469d407ca27Smillert if (pr != NULL) 470d407ca27Smillert printf("%s%s", pr, line); 471d407ca27Smillert cline[i]++; 472d407ca27Smillert } 473ad7191bdSmillert return ((int) n); 474d407ca27Smillert } 475d407ca27Smillert 476d407ca27Smillert /* 477d407ca27Smillert * Return 1 or 0 according as the old range (in file 1) contains exactly 478d407ca27Smillert * the same data as the new range (in file 2). 479d407ca27Smillert */ 480d407ca27Smillert int 481d407ca27Smillert duplicate(struct range *r1, struct range *r2) 482d407ca27Smillert { 483d407ca27Smillert int c,d; 484d407ca27Smillert int nchar; 485d407ca27Smillert int nline; 486d407ca27Smillert 487d407ca27Smillert if (r1->to-r1->from != r2->to-r2->from) 488d407ca27Smillert return (0); 489d407ca27Smillert (void)skip(0, r1->from, NULL); 490d407ca27Smillert (void)skip(1, r2->from, NULL); 491d407ca27Smillert nchar = 0; 492d407ca27Smillert for (nline=0; nline < r1->to - r1->from; nline++) { 493d407ca27Smillert do { 494d407ca27Smillert c = getc(fp[0]); 495d407ca27Smillert d = getc(fp[1]); 496d407ca27Smillert if (c == -1 || d== -1) 497d407ca27Smillert trouble(); 498d407ca27Smillert nchar++; 499d407ca27Smillert if (c != d) { 500d407ca27Smillert repos(nchar); 501d407ca27Smillert return (0); 502d407ca27Smillert } 503d407ca27Smillert } while (c != '\n'); 504d407ca27Smillert } 505d407ca27Smillert repos(nchar); 506d407ca27Smillert return (1); 507d407ca27Smillert } 508d407ca27Smillert 509d407ca27Smillert void 510d407ca27Smillert repos(int nchar) 511d407ca27Smillert { 512d407ca27Smillert int i; 513d407ca27Smillert 514d407ca27Smillert for (i = 0; i < 2; i++) 515d407ca27Smillert (void)fseek(fp[i], (long)-nchar, 1); 516d407ca27Smillert } 517d407ca27Smillert 518d407ca27Smillert __dead void 519d407ca27Smillert trouble(void) 520d407ca27Smillert { 521d407ca27Smillert errx(EXIT_FAILURE, "logic error"); 522d407ca27Smillert } 523d407ca27Smillert 524d407ca27Smillert /* 525d407ca27Smillert * collect an editing script for later regurgitation 526d407ca27Smillert */ 527d407ca27Smillert int 528d407ca27Smillert edit(struct diff *diff, int dup, int j) 529d407ca27Smillert { 530d407ca27Smillert if (((dup + 1) & eflag) == 0) 531d407ca27Smillert return (j); 532d407ca27Smillert j++; 533d407ca27Smillert overlap[j] = !dup; 534d407ca27Smillert if (!dup) 535d407ca27Smillert overlapcnt++; 536d407ca27Smillert de[j].old.from = diff->old.from; 537d407ca27Smillert de[j].old.to = diff->old.to; 538d407ca27Smillert de[j].new.from = de[j-1].new.to + skip(2, diff->new.from, NULL); 539d407ca27Smillert de[j].new.to = de[j].new.from + skip(2, diff->new.to, NULL); 540d407ca27Smillert return (j); 541d407ca27Smillert } 542d407ca27Smillert 543d407ca27Smillert /* regurgitate */ 544d407ca27Smillert __dead void 545d407ca27Smillert edscript(int n) 546d407ca27Smillert { 547d407ca27Smillert int j,k; 548d407ca27Smillert char block[BUFSIZ]; 549d407ca27Smillert 550d407ca27Smillert for (n = n; n > 0; n--) { 551d407ca27Smillert if (!oflag || !overlap[n]) 552d407ca27Smillert prange(&de[n].old); 553d407ca27Smillert else 554d407ca27Smillert printf("%da\n=======\n", de[n].old.to -1); 555d407ca27Smillert (void)fseek(fp[2], (long)de[n].new.from, 0); 556d407ca27Smillert for (k = de[n].new.to-de[n].new.from; k > 0; k-= j) { 557d407ca27Smillert j = k > BUFSIZ ? BUFSIZ : k; 558d407ca27Smillert if (fread(block, 1, j, fp[2]) != j) 559d407ca27Smillert trouble(); 560d407ca27Smillert (void)fwrite(block, 1, j, stdout); 561d407ca27Smillert } 562d407ca27Smillert if (!oflag || !overlap[n]) 563d407ca27Smillert printf(".\n"); 564d407ca27Smillert else { 565d407ca27Smillert printf("%s\n.\n", f3mark); 566d407ca27Smillert printf("%da\n%s\n.\n", de[n].old.from - 1, f1mark); 567d407ca27Smillert } 568d407ca27Smillert } 569d407ca27Smillert exit(overlapcnt); 570d407ca27Smillert } 571d407ca27Smillert 572*68496fbfSotto void 573*68496fbfSotto increase(void) 574*68496fbfSotto { 575*68496fbfSotto struct diff *p; 576*68496fbfSotto char *q; 577*68496fbfSotto size_t newsz, incr; 578*68496fbfSotto 579*68496fbfSotto /* are the memset(3) calls needed? */ 580*68496fbfSotto newsz = szchanges == 0 ? 64 : 2 * szchanges; 581*68496fbfSotto incr = newsz - szchanges; 582*68496fbfSotto 583*68496fbfSotto p = realloc(d13, newsz * sizeof(struct diff)); 584*68496fbfSotto if (p == NULL) 585*68496fbfSotto err(1, NULL); 586*68496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 587*68496fbfSotto d13 = p; 588*68496fbfSotto p = realloc(d23, newsz * sizeof(struct diff)); 589*68496fbfSotto if (p == NULL) 590*68496fbfSotto err(1, NULL); 591*68496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 592*68496fbfSotto d23 = p; 593*68496fbfSotto p = realloc(de, newsz * sizeof(struct diff)); 594*68496fbfSotto if (p == NULL) 595*68496fbfSotto err(1, NULL); 596*68496fbfSotto memset(p + szchanges, 0, incr * sizeof(struct diff)); 597*68496fbfSotto de = p; 598*68496fbfSotto q = realloc(overlap, newsz * sizeof(char)); 599*68496fbfSotto if (q == NULL) 600*68496fbfSotto err(1, NULL); 601*68496fbfSotto memset(q + szchanges, 0, incr * sizeof(char)); 602*68496fbfSotto overlap = q; 603*68496fbfSotto szchanges = newsz; 604*68496fbfSotto } 605*68496fbfSotto 606*68496fbfSotto 607d407ca27Smillert __dead void 608d407ca27Smillert usage(void) 609d407ca27Smillert { 610d407ca27Smillert extern char *__progname; 611d407ca27Smillert 612d407ca27Smillert fprintf(stderr, "usage: %s [-exEX3] /tmp/d3a.?????????? " 613d407ca27Smillert "/tmp/d3b.?????????? file1 file2 file3\n", __progname); 614d407ca27Smillert exit(EXIT_FAILURE); 615d407ca27Smillert } 616