1*0c9f493eStedu /* $OpenBSD: diffreg.c,v 1.4 2003/06/25 03:25:29 tedu Exp $ */ 2d0c3f575Sderaadt 3d0c3f575Sderaadt /* 4d0c3f575Sderaadt * Copyright (C) Caldera International Inc. 2001-2002. 5d0c3f575Sderaadt * All rights reserved. 6d0c3f575Sderaadt * 7d0c3f575Sderaadt * Redistribution and use in source and binary forms, with or without 8d0c3f575Sderaadt * modification, are permitted provided that the following conditions 9d0c3f575Sderaadt * are met: 10d0c3f575Sderaadt * 1. Redistributions of source code and documentation must retain the above 11d0c3f575Sderaadt * copyright notice, this list of conditions and the following disclaimer. 12d0c3f575Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 13d0c3f575Sderaadt * notice, this list of conditions and the following disclaimer in the 14d0c3f575Sderaadt * documentation and/or other materials provided with the distribution. 15d0c3f575Sderaadt * 3. All advertising materials mentioning features or use of this software 16d0c3f575Sderaadt * must display the following acknowledgement: 17d0c3f575Sderaadt * This product includes software developed or owned by Caldera 18d0c3f575Sderaadt * International, Inc. 19d0c3f575Sderaadt * 4. Neither the name of Caldera International, Inc. nor the names of other 20d0c3f575Sderaadt * contributors may be used to endorse or promote products derived from 21d0c3f575Sderaadt * this software without specific prior written permission. 22d0c3f575Sderaadt * 23d0c3f575Sderaadt * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 24d0c3f575Sderaadt * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 25d0c3f575Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26d0c3f575Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27d0c3f575Sderaadt * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 28d0c3f575Sderaadt * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29d0c3f575Sderaadt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30d0c3f575Sderaadt * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31d0c3f575Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32d0c3f575Sderaadt * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33d0c3f575Sderaadt * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34d0c3f575Sderaadt * POSSIBILITY OF SUCH DAMAGE. 35d0c3f575Sderaadt */ 36d0c3f575Sderaadt 3726da422aStedu #include <sys/types.h> 3826da422aStedu 3926da422aStedu #include <stdlib.h> 4026da422aStedu #include <unistd.h> 4126da422aStedu #include <fcntl.h> 4226da422aStedu #include <string.h> 43ae8d569bSderaadt 44ae8d569bSderaadt #include "diff.h" 45ae8d569bSderaadt #include "pathnames.h" 4626da422aStedu 4726da422aStedu #if 0 4826da422aStedu static char const sccsid[] = "@(#)diffreg.c 4.21 4/6/90"; 4926da422aStedu #endif 5026da422aStedu 51ae8d569bSderaadt /* 52ae8d569bSderaadt * diff - compare two files. 53ae8d569bSderaadt */ 54ae8d569bSderaadt 55ae8d569bSderaadt /* 56ae8d569bSderaadt * Uses an algorithm due to Harold Stone, which finds 57ae8d569bSderaadt * a pair of longest identical subsequences in the two 58ae8d569bSderaadt * files. 59ae8d569bSderaadt * 60ae8d569bSderaadt * The major goal is to generate the match vector J. 61ae8d569bSderaadt * J[i] is the index of the line in file1 corresponding 62ae8d569bSderaadt * to line i file0. J[i] = 0 if there is no 63ae8d569bSderaadt * such line in file1. 64ae8d569bSderaadt * 65ae8d569bSderaadt * Lines are hashed so as to work in core. All potential 66ae8d569bSderaadt * matches are located by sorting the lines of each file 67ae8d569bSderaadt * on the hash (called ``value''). In particular, this 68ae8d569bSderaadt * collects the equivalence classes in file1 together. 69ae8d569bSderaadt * Subroutine equiv replaces the value of each line in 70ae8d569bSderaadt * file0 by the index of the first element of its 71ae8d569bSderaadt * matching equivalence in (the reordered) file1. 72ae8d569bSderaadt * To save space equiv squeezes file1 into a single 73ae8d569bSderaadt * array member in which the equivalence classes 74ae8d569bSderaadt * are simply concatenated, except that their first 75ae8d569bSderaadt * members are flagged by changing sign. 76ae8d569bSderaadt * 77ae8d569bSderaadt * Next the indices that point into member are unsorted into 78ae8d569bSderaadt * array class according to the original order of file0. 79ae8d569bSderaadt * 80ae8d569bSderaadt * The cleverness lies in routine stone. This marches 81ae8d569bSderaadt * through the lines of file0, developing a vector klist 82ae8d569bSderaadt * of "k-candidates". At step i a k-candidate is a matched 83ae8d569bSderaadt * pair of lines x,y (x in file0 y in file1) such that 84ae8d569bSderaadt * there is a common subsequence of length k 85ae8d569bSderaadt * between the first i lines of file0 and the first y 86ae8d569bSderaadt * lines of file1, but there is no such subsequence for 87ae8d569bSderaadt * any smaller y. x is the earliest possible mate to y 88ae8d569bSderaadt * that occurs in such a subsequence. 89ae8d569bSderaadt * 90ae8d569bSderaadt * Whenever any of the members of the equivalence class of 91ae8d569bSderaadt * lines in file1 matable to a line in file0 has serial number 92ae8d569bSderaadt * less than the y of some k-candidate, that k-candidate 93ae8d569bSderaadt * with the smallest such y is replaced. The new 94ae8d569bSderaadt * k-candidate is chained (via pred) to the current 95ae8d569bSderaadt * k-1 candidate so that the actual subsequence can 96ae8d569bSderaadt * be recovered. When a member has serial number greater 97ae8d569bSderaadt * that the y of all k-candidates, the klist is extended. 98ae8d569bSderaadt * At the end, the longest subsequence is pulled out 99ae8d569bSderaadt * and placed in the array J by unravel 100ae8d569bSderaadt * 101ae8d569bSderaadt * With J in hand, the matches there recorded are 102ae8d569bSderaadt * check'ed against reality to assure that no spurious 103ae8d569bSderaadt * matches have crept in due to hashing. If they have, 104ae8d569bSderaadt * they are broken, and "jackpot" is recorded--a harmless 105ae8d569bSderaadt * matter except that a true match for a spuriously 106ae8d569bSderaadt * mated line may now be unnecessarily reported as a change. 107ae8d569bSderaadt * 108ae8d569bSderaadt * Much of the complexity of the program comes simply 109ae8d569bSderaadt * from trying to minimize core utilization and 110ae8d569bSderaadt * maximize the range of doable problems by dynamically 111ae8d569bSderaadt * allocating what is needed and reusing what is not. 112ae8d569bSderaadt * The core requirements for problems larger than somewhat 113ae8d569bSderaadt * are (in words) 2*length(file0) + length(file1) + 114ae8d569bSderaadt * 3*(number of k-candidates installed), typically about 115ae8d569bSderaadt * 6n words for files of length n. 116ae8d569bSderaadt */ 117ae8d569bSderaadt 118ae8d569bSderaadt #define prints(s) fputs(s,stdout) 119ae8d569bSderaadt 120ae8d569bSderaadt FILE *input[2]; 121ae8d569bSderaadt FILE *fopen(); 122ae8d569bSderaadt 123ae8d569bSderaadt struct cand { 124ae8d569bSderaadt int x; 125ae8d569bSderaadt int y; 126ae8d569bSderaadt int pred; 127ae8d569bSderaadt } cand; 12826da422aStedu 129ae8d569bSderaadt struct line { 130ae8d569bSderaadt int serial; 131ae8d569bSderaadt int value; 132ae8d569bSderaadt } *file[2], line; 13326da422aStedu 134ae8d569bSderaadt int len[2]; 135*0c9f493eStedu struct line *sfile[2]; /* shortened by pruning common prefix and suffix */ 136ae8d569bSderaadt int slen[2]; 137ae8d569bSderaadt int pref, suff; /* length of prefix and suffix */ 138ae8d569bSderaadt int *class; /* will be overlaid on file[0] */ 139ae8d569bSderaadt int *member; /* will be overlaid on file[1] */ 140ae8d569bSderaadt int *klist; /* will be overlaid on file[0] after class */ 141ae8d569bSderaadt struct cand *clist; /* merely a free storage pot for candidates */ 142ae8d569bSderaadt int clen = 0; 143ae8d569bSderaadt int *J; /* will be overlaid on class */ 144ae8d569bSderaadt long *ixold; /* will be overlaid on klist */ 145ae8d569bSderaadt long *ixnew; /* will be overlaid on file[1] */ 146ae8d569bSderaadt char *chrtran; /* translation table for case-folding */ 147ae8d569bSderaadt 14826da422aStedu static void fetch(long *, int, int, FILE *, char *, int); 14926da422aStedu static void output(void); 15026da422aStedu static void check(void); 15126da422aStedu static void range(int, int, char *); 15226da422aStedu static void dump_context_vec(void); 15326da422aStedu static void prepare(int, FILE *); 15426da422aStedu static void prune(void); 15526da422aStedu static void equiv(struct line *, int, struct line *, int, int *); 15626da422aStedu static void unravel(int); 15726da422aStedu static void unsort(struct line *, int, int *); 15826da422aStedu static void change(int, int, int, int); 15926da422aStedu static void sort(struct line *, int); 16026da422aStedu static int newcand(int, int, int); 16126da422aStedu static int search(int *, int, int); 16226da422aStedu static int skipline(int); 16326da422aStedu static int asciifile(FILE *); 16426da422aStedu static int stone(int *, int, int *, int *); 16526da422aStedu static int readhash(FILE *); 16626da422aStedu 16726da422aStedu /* 16826da422aStedu * chrtran points to one of 2 translation tables: cup2low if folding upper to 16926da422aStedu * lower case clow2low if not folding case 170ae8d569bSderaadt */ 171ae8d569bSderaadt char clow2low[256] = { 17226da422aStedu 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 17326da422aStedu 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 17426da422aStedu 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 17526da422aStedu 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 17626da422aStedu 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 17726da422aStedu 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 17826da422aStedu 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 17926da422aStedu 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 18026da422aStedu 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 18126da422aStedu 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 18226da422aStedu 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 18326da422aStedu 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 18426da422aStedu 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 18526da422aStedu 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 18626da422aStedu 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 18726da422aStedu 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 18826da422aStedu 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 18926da422aStedu 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 19026da422aStedu 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 19126da422aStedu 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 19226da422aStedu 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 19326da422aStedu 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 19426da422aStedu 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 19526da422aStedu 0xfd, 0xfe, 0xff 196ae8d569bSderaadt }; 197ae8d569bSderaadt 198ae8d569bSderaadt char cup2low[256] = { 19926da422aStedu 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 20026da422aStedu 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 20126da422aStedu 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 20226da422aStedu 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 20326da422aStedu 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 20426da422aStedu 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 20526da422aStedu 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 20626da422aStedu 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 20726da422aStedu 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 20826da422aStedu 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 20926da422aStedu 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 21026da422aStedu 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 21126da422aStedu 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 21226da422aStedu 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 21326da422aStedu 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 21426da422aStedu 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 21526da422aStedu 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 21626da422aStedu 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 21726da422aStedu 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 21826da422aStedu 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 21926da422aStedu 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 22026da422aStedu 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 22126da422aStedu 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 22226da422aStedu 0xfd, 0xfe, 0xff 223ae8d569bSderaadt }; 224ae8d569bSderaadt 22526da422aStedu void 22626da422aStedu diffreg(void) 227ae8d569bSderaadt { 22826da422aStedu int i, j; 229ae8d569bSderaadt FILE *f1, *f2; 230ae8d569bSderaadt char buf1[BUFSIZ], buf2[BUFSIZ]; 231ae8d569bSderaadt 232ae8d569bSderaadt if (hflag) { 233ae8d569bSderaadt diffargv[0] = "diffh"; 234ae8d569bSderaadt execv(diffh, diffargv); 235ae8d569bSderaadt fprintf(stderr, "diff: "); 236ae8d569bSderaadt perror(diffh); 237ae8d569bSderaadt done(); 238ae8d569bSderaadt } 239ae8d569bSderaadt chrtran = (iflag ? cup2low : clow2low); 240ae8d569bSderaadt if ((stb1.st_mode & S_IFMT) == S_IFDIR) { 241ae8d569bSderaadt file1 = splice(file1, file2); 242ae8d569bSderaadt if (stat(file1, &stb1) < 0) { 243ae8d569bSderaadt fprintf(stderr, "diff: "); 244ae8d569bSderaadt perror(file1); 245ae8d569bSderaadt done(); 246ae8d569bSderaadt } 247ae8d569bSderaadt } else if ((stb2.st_mode & S_IFMT) == S_IFDIR) { 248ae8d569bSderaadt file2 = splice(file2, file1); 249ae8d569bSderaadt if (stat(file2, &stb2) < 0) { 250ae8d569bSderaadt fprintf(stderr, "diff: "); 251ae8d569bSderaadt perror(file2); 252ae8d569bSderaadt done(); 253ae8d569bSderaadt } 254ae8d569bSderaadt } else if ((stb1.st_mode & S_IFMT) != S_IFREG || !strcmp(file1, "-")) { 255ae8d569bSderaadt if (!strcmp(file2, "-")) { 256ae8d569bSderaadt fprintf(stderr, "diff: can't specify - -\n"); 257ae8d569bSderaadt done(); 258ae8d569bSderaadt } 259ae8d569bSderaadt file1 = copytemp(); 260ae8d569bSderaadt if (stat(file1, &stb1) < 0) { 261ae8d569bSderaadt fprintf(stderr, "diff: "); 262ae8d569bSderaadt perror(file1); 263ae8d569bSderaadt done(); 264ae8d569bSderaadt } 265ae8d569bSderaadt } else if ((stb2.st_mode & S_IFMT) != S_IFREG || !strcmp(file2, "-")) { 266ae8d569bSderaadt file2 = copytemp(); 267ae8d569bSderaadt if (stat(file2, &stb2) < 0) { 268ae8d569bSderaadt fprintf(stderr, "diff: "); 269ae8d569bSderaadt perror(file2); 270ae8d569bSderaadt done(); 271ae8d569bSderaadt } 272ae8d569bSderaadt } 273ae8d569bSderaadt if ((f1 = fopen(file1, "r")) == NULL) { 274ae8d569bSderaadt fprintf(stderr, "diff: "); 275ae8d569bSderaadt perror(file1); 276ae8d569bSderaadt done(); 277ae8d569bSderaadt } 278ae8d569bSderaadt if ((f2 = fopen(file2, "r")) == NULL) { 279ae8d569bSderaadt fprintf(stderr, "diff: "); 280ae8d569bSderaadt perror(file2); 281ae8d569bSderaadt fclose(f1); 282ae8d569bSderaadt done(); 283ae8d569bSderaadt } 284ae8d569bSderaadt if (stb1.st_size != stb2.st_size) 285ae8d569bSderaadt goto notsame; 286ae8d569bSderaadt for (;;) { 287ae8d569bSderaadt i = fread(buf1, 1, BUFSIZ, f1); 288ae8d569bSderaadt j = fread(buf2, 1, BUFSIZ, f2); 289ae8d569bSderaadt if (i < 0 || j < 0 || i != j) 290ae8d569bSderaadt goto notsame; 291ae8d569bSderaadt if (i == 0 && j == 0) { 292ae8d569bSderaadt fclose(f1); 293ae8d569bSderaadt fclose(f2); 294ae8d569bSderaadt status = 0; /* files don't differ */ 295ae8d569bSderaadt goto same; 296ae8d569bSderaadt } 297ae8d569bSderaadt for (j = 0; j < i; j++) 298ae8d569bSderaadt if (buf1[j] != buf2[j]) 299ae8d569bSderaadt goto notsame; 300ae8d569bSderaadt } 301ae8d569bSderaadt notsame: 302ae8d569bSderaadt /* 303ae8d569bSderaadt * Files certainly differ at this point; set status accordingly 304ae8d569bSderaadt */ 305ae8d569bSderaadt status = 1; 306ae8d569bSderaadt if (!asciifile(f1) || !asciifile(f2)) { 307ae8d569bSderaadt printf("Binary files %s and %s differ\n", file1, file2); 308ae8d569bSderaadt fclose(f1); 309ae8d569bSderaadt fclose(f2); 310ae8d569bSderaadt done(); 311ae8d569bSderaadt } 312ae8d569bSderaadt prepare(0, f1); 313ae8d569bSderaadt prepare(1, f2); 314ae8d569bSderaadt fclose(f1); 315ae8d569bSderaadt fclose(f2); 316ae8d569bSderaadt prune(); 317ae8d569bSderaadt sort(sfile[0], slen[0]); 318ae8d569bSderaadt sort(sfile[1], slen[1]); 319ae8d569bSderaadt 320ae8d569bSderaadt member = (int *)file[1]; 321ae8d569bSderaadt equiv(sfile[0], slen[0], sfile[1], slen[1], member); 322*0c9f493eStedu member = ralloc(member, (slen[1] + 2) * sizeof(int)); 323ae8d569bSderaadt 324ae8d569bSderaadt class = (int *)file[0]; 325ae8d569bSderaadt unsort(sfile[0], slen[0], class); 326*0c9f493eStedu class = ralloc(class, (slen[0] + 2) * sizeof(int)); 327ae8d569bSderaadt 32826da422aStedu klist = talloc((slen[0] + 2) * sizeof(int)); 32926da422aStedu clist = talloc(sizeof(cand)); 330ae8d569bSderaadt i = stone(class, slen[0], member, klist); 33126da422aStedu free(member); 33226da422aStedu free(class); 333ae8d569bSderaadt 33426da422aStedu J = talloc((len[0] + 2) * sizeof(int)); 335ae8d569bSderaadt unravel(klist[i]); 33626da422aStedu free(clist); 33726da422aStedu free(klist); 338ae8d569bSderaadt 33926da422aStedu ixold = talloc((len[0] + 2) * sizeof(long)); 34026da422aStedu ixnew = talloc((len[1] + 2) * sizeof(long)); 341ae8d569bSderaadt check(); 342ae8d569bSderaadt output(); 343ae8d569bSderaadt status = anychange; 344ae8d569bSderaadt same: 345ae8d569bSderaadt if (opt == D_CONTEXT && anychange == 0) 346ae8d569bSderaadt printf("No differences encountered\n"); 347ae8d569bSderaadt done(); 348ae8d569bSderaadt } 349ae8d569bSderaadt 350ae8d569bSderaadt char *tempfile = _PATH_TMP; 351ae8d569bSderaadt 352ae8d569bSderaadt char * 35326da422aStedu copytemp(void) 354ae8d569bSderaadt { 355ae8d569bSderaadt char buf[BUFSIZ]; 35626da422aStedu int i, f; 357ae8d569bSderaadt 35826da422aStedu signal(SIGHUP, catchsig); 35926da422aStedu signal(SIGINT, catchsig); 36026da422aStedu signal(SIGPIPE, catchsig); 36126da422aStedu signal(SIGTERM, catchsig); 36226da422aStedu f = mkstemp(tempfile); 363ae8d569bSderaadt if (f < 0) { 364ae8d569bSderaadt fprintf(stderr, "diff: "); 365ae8d569bSderaadt perror(tempfile); 366ae8d569bSderaadt done(); 367ae8d569bSderaadt } 368ae8d569bSderaadt while ((i = read(0, buf, BUFSIZ)) > 0) 369ae8d569bSderaadt if (write(f, buf, i) != i) { 370ae8d569bSderaadt fprintf(stderr, "diff: "); 371ae8d569bSderaadt perror(tempfile); 372ae8d569bSderaadt done(); 373ae8d569bSderaadt } 374ae8d569bSderaadt close(f); 375ae8d569bSderaadt return (tempfile); 376ae8d569bSderaadt } 377ae8d569bSderaadt 378ae8d569bSderaadt char * 37926da422aStedu splice(char *dir, char *file) 380ae8d569bSderaadt { 381ae8d569bSderaadt char *tail; 382ae8d569bSderaadt char buf[BUFSIZ]; 383ae8d569bSderaadt 384ae8d569bSderaadt if (!strcmp(file, "-")) { 385ae8d569bSderaadt fprintf(stderr, "diff: can't specify - with other arg directory\n"); 386ae8d569bSderaadt done(); 387ae8d569bSderaadt } 388ae8d569bSderaadt tail = rindex(file, '/'); 389ae8d569bSderaadt if (tail == 0) 390ae8d569bSderaadt tail = file; 391ae8d569bSderaadt else 392ae8d569bSderaadt tail++; 39326da422aStedu snprintf(buf, sizeof buf, "%s/%s", dir, tail); 39426da422aStedu return (strdup(buf)); 395ae8d569bSderaadt } 396ae8d569bSderaadt 39726da422aStedu static void 39826da422aStedu prepare(int i, FILE *fd) 399ae8d569bSderaadt { 40026da422aStedu struct line *p; 40126da422aStedu int j, h; 402ae8d569bSderaadt 40326da422aStedu fseek(fd, 0, 0); 40426da422aStedu p = talloc(3 * sizeof(line)); 40526da422aStedu for (j = 0; (h = readhash(fd));) { 406*0c9f493eStedu p = ralloc(p, (++j + 3) * sizeof(line)); 407ae8d569bSderaadt p[j].value = h; 408ae8d569bSderaadt } 409ae8d569bSderaadt len[i] = j; 410ae8d569bSderaadt file[i] = p; 411ae8d569bSderaadt } 412ae8d569bSderaadt 41326da422aStedu static void 41426da422aStedu prune(void) 415ae8d569bSderaadt { 41626da422aStedu int i, j; 417ae8d569bSderaadt for (pref = 0; pref < len[0] && pref < len[1] && 418ae8d569bSderaadt file[0][pref + 1].value == file[1][pref + 1].value; 419ae8d569bSderaadt pref++); 420ae8d569bSderaadt for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 421ae8d569bSderaadt file[0][len[0] - suff].value == file[1][len[1] - suff].value; 422ae8d569bSderaadt suff++); 423ae8d569bSderaadt for (j = 0; j < 2; j++) { 424ae8d569bSderaadt sfile[j] = file[j] + pref; 425ae8d569bSderaadt slen[j] = len[j] - pref - suff; 426ae8d569bSderaadt for (i = 0; i <= slen[j]; i++) 427ae8d569bSderaadt sfile[j][i].serial = i; 428ae8d569bSderaadt } 429ae8d569bSderaadt } 430ae8d569bSderaadt 43126da422aStedu static void 43226da422aStedu equiv(struct line *a, int n, struct line *b, int m, int *c) 433ae8d569bSderaadt { 43426da422aStedu int i, j; 435ae8d569bSderaadt i = j = 1; 436ae8d569bSderaadt while (i <= n && j <= m) { 437ae8d569bSderaadt if (a[i].value < b[j].value) 438ae8d569bSderaadt a[i++].value = 0; 439ae8d569bSderaadt else if (a[i].value == b[j].value) 440ae8d569bSderaadt a[i++].value = j; 441ae8d569bSderaadt else 442ae8d569bSderaadt j++; 443ae8d569bSderaadt } 444ae8d569bSderaadt while (i <= n) 445ae8d569bSderaadt a[i++].value = 0; 446ae8d569bSderaadt b[m + 1].value = 0; 447ae8d569bSderaadt j = 0; 448ae8d569bSderaadt while (++j <= m) { 449ae8d569bSderaadt c[j] = -b[j].serial; 450ae8d569bSderaadt while (b[j + 1].value == b[j].value) { 451ae8d569bSderaadt j++; 452ae8d569bSderaadt c[j] = b[j].serial; 453ae8d569bSderaadt } 454ae8d569bSderaadt } 455ae8d569bSderaadt c[j] = -1; 456ae8d569bSderaadt } 457ae8d569bSderaadt 45826da422aStedu static int 45926da422aStedu stone(int *a, int n, int *b, int *c) 460ae8d569bSderaadt { 46126da422aStedu int i, k, y; 462ae8d569bSderaadt int j, l; 463ae8d569bSderaadt int oldc, tc; 464ae8d569bSderaadt int oldl; 465ae8d569bSderaadt k = 0; 466ae8d569bSderaadt c[0] = newcand(0, 0, 0); 467ae8d569bSderaadt for (i = 1; i <= n; i++) { 468ae8d569bSderaadt j = a[i]; 469ae8d569bSderaadt if (j == 0) 470ae8d569bSderaadt continue; 471ae8d569bSderaadt y = -b[j]; 472ae8d569bSderaadt oldl = 0; 473ae8d569bSderaadt oldc = c[0]; 474ae8d569bSderaadt do { 475ae8d569bSderaadt if (y <= clist[oldc].y) 476ae8d569bSderaadt continue; 477ae8d569bSderaadt l = search(c, k, y); 478ae8d569bSderaadt if (l != oldl + 1) 479ae8d569bSderaadt oldc = c[l - 1]; 480ae8d569bSderaadt if (l <= k) { 481ae8d569bSderaadt if (clist[c[l]].y <= y) 482ae8d569bSderaadt continue; 483ae8d569bSderaadt tc = c[l]; 484ae8d569bSderaadt c[l] = newcand(i, y, oldc); 485ae8d569bSderaadt oldc = tc; 486ae8d569bSderaadt oldl = l; 487ae8d569bSderaadt } else { 488ae8d569bSderaadt c[l] = newcand(i, y, oldc); 489ae8d569bSderaadt k++; 490ae8d569bSderaadt break; 491ae8d569bSderaadt } 492ae8d569bSderaadt } while ((y = b[++j]) > 0); 493ae8d569bSderaadt } 494ae8d569bSderaadt return (k); 495ae8d569bSderaadt } 496ae8d569bSderaadt 49726da422aStedu static int 49826da422aStedu newcand(int x, int y, int pred) 499ae8d569bSderaadt { 50026da422aStedu struct cand *q; 50126da422aStedu 502*0c9f493eStedu clist = ralloc(clist, ++clen * sizeof(cand)); 503ae8d569bSderaadt q = clist + clen - 1; 504ae8d569bSderaadt q->x = x; 505ae8d569bSderaadt q->y = y; 506ae8d569bSderaadt q->pred = pred; 507ae8d569bSderaadt return (clen - 1); 508ae8d569bSderaadt } 509ae8d569bSderaadt 51026da422aStedu static int 51126da422aStedu search(int *c, int k, int y) 512ae8d569bSderaadt { 51326da422aStedu int i, j, l; 514ae8d569bSderaadt int t; 515ae8d569bSderaadt if (clist[c[k]].y < y) /* quick look for typical case */ 516ae8d569bSderaadt return (k + 1); 517ae8d569bSderaadt i = 0; 518ae8d569bSderaadt j = k + 1; 519ae8d569bSderaadt while (1) { 520ae8d569bSderaadt l = i + j; 521ae8d569bSderaadt if ((l >>= 1) <= i) 522ae8d569bSderaadt break; 523ae8d569bSderaadt t = clist[c[l]].y; 524ae8d569bSderaadt if (t > y) 525ae8d569bSderaadt j = l; 526ae8d569bSderaadt else if (t < y) 527ae8d569bSderaadt i = l; 528ae8d569bSderaadt else 529ae8d569bSderaadt return (l); 530ae8d569bSderaadt } 531ae8d569bSderaadt return (l + 1); 532ae8d569bSderaadt } 533ae8d569bSderaadt 53426da422aStedu static void 53526da422aStedu unravel(int p) 536ae8d569bSderaadt { 53726da422aStedu int i; 53826da422aStedu struct cand *q; 539ae8d569bSderaadt for (i = 0; i <= len[0]; i++) 540ae8d569bSderaadt J[i] = i <= pref ? i : 541ae8d569bSderaadt i > len[0] - suff ? i + len[1] - len[0] : 542ae8d569bSderaadt 0; 543ae8d569bSderaadt for (q = clist + p; q->y != 0; q = clist + q->pred) 544ae8d569bSderaadt J[q->x + pref] = q->y + pref; 545ae8d569bSderaadt } 546ae8d569bSderaadt 54726da422aStedu /* 54826da422aStedu * check does double duty: 1. ferret out any fortuitous correspondences due 54926da422aStedu * to confounding by hashing (which result in "jackpot") 2. collect random 55026da422aStedu * access indexes to the two files 55126da422aStedu */ 552ae8d569bSderaadt 55326da422aStedu static void 55426da422aStedu check(void) 555ae8d569bSderaadt { 55626da422aStedu int i, j; 557ae8d569bSderaadt int jackpot; 558ae8d569bSderaadt long ctold, ctnew; 55926da422aStedu int c, d; 560ae8d569bSderaadt 561ae8d569bSderaadt if ((input[0] = fopen(file1, "r")) == NULL) { 562ae8d569bSderaadt perror(file1); 563ae8d569bSderaadt done(); 564ae8d569bSderaadt } 565ae8d569bSderaadt if ((input[1] = fopen(file2, "r")) == NULL) { 566ae8d569bSderaadt perror(file2); 567ae8d569bSderaadt done(); 568ae8d569bSderaadt } 569ae8d569bSderaadt j = 1; 570ae8d569bSderaadt ixold[0] = ixnew[0] = 0; 571ae8d569bSderaadt jackpot = 0; 572ae8d569bSderaadt ctold = ctnew = 0; 573ae8d569bSderaadt for (i = 1; i <= len[0]; i++) { 574ae8d569bSderaadt if (J[i] == 0) { 575ae8d569bSderaadt ixold[i] = ctold += skipline(0); 576ae8d569bSderaadt continue; 577ae8d569bSderaadt } 578ae8d569bSderaadt while (j < J[i]) { 579ae8d569bSderaadt ixnew[j] = ctnew += skipline(1); 580ae8d569bSderaadt j++; 581ae8d569bSderaadt } 582ae8d569bSderaadt if (bflag || wflag || iflag) { 583ae8d569bSderaadt for (;;) { 584ae8d569bSderaadt c = getc(input[0]); 585ae8d569bSderaadt d = getc(input[1]); 586ae8d569bSderaadt ctold++; 587ae8d569bSderaadt ctnew++; 588ae8d569bSderaadt if (bflag && isspace(c) && isspace(d)) { 589ae8d569bSderaadt do { 590ae8d569bSderaadt if (c == '\n') 591ae8d569bSderaadt break; 592ae8d569bSderaadt ctold++; 593ae8d569bSderaadt } while (isspace(c = getc(input[0]))); 594ae8d569bSderaadt do { 595ae8d569bSderaadt if (d == '\n') 596ae8d569bSderaadt break; 597ae8d569bSderaadt ctnew++; 598ae8d569bSderaadt } while (isspace(d = getc(input[1]))); 599ae8d569bSderaadt } else if (wflag) { 600ae8d569bSderaadt while (isspace(c) && c != '\n') { 601ae8d569bSderaadt c = getc(input[0]); 602ae8d569bSderaadt ctold++; 603ae8d569bSderaadt } 604ae8d569bSderaadt while (isspace(d) && d != '\n') { 605ae8d569bSderaadt d = getc(input[1]); 606ae8d569bSderaadt ctnew++; 607ae8d569bSderaadt } 608ae8d569bSderaadt } 609ae8d569bSderaadt if (chrtran[c] != chrtran[d]) { 610ae8d569bSderaadt jackpot++; 611ae8d569bSderaadt J[i] = 0; 612ae8d569bSderaadt if (c != '\n') 613ae8d569bSderaadt ctold += skipline(0); 614ae8d569bSderaadt if (d != '\n') 615ae8d569bSderaadt ctnew += skipline(1); 616ae8d569bSderaadt break; 617ae8d569bSderaadt } 618ae8d569bSderaadt if (c == '\n') 619ae8d569bSderaadt break; 620ae8d569bSderaadt } 621ae8d569bSderaadt } else { 622ae8d569bSderaadt for (;;) { 623ae8d569bSderaadt ctold++; 624ae8d569bSderaadt ctnew++; 625ae8d569bSderaadt if ((c = getc(input[0])) != (d = getc(input[1]))) { 626ae8d569bSderaadt /* jackpot++; */ 627ae8d569bSderaadt J[i] = 0; 628ae8d569bSderaadt if (c != '\n') 629ae8d569bSderaadt ctold += skipline(0); 630ae8d569bSderaadt if (d != '\n') 631ae8d569bSderaadt ctnew += skipline(1); 632ae8d569bSderaadt break; 633ae8d569bSderaadt } 634ae8d569bSderaadt if (c == '\n') 635ae8d569bSderaadt break; 636ae8d569bSderaadt } 637ae8d569bSderaadt } 638ae8d569bSderaadt ixold[i] = ctold; 639ae8d569bSderaadt ixnew[j] = ctnew; 640ae8d569bSderaadt j++; 641ae8d569bSderaadt } 642ae8d569bSderaadt for (; j <= len[1]; j++) { 643ae8d569bSderaadt ixnew[j] = ctnew += skipline(1); 644ae8d569bSderaadt } 645ae8d569bSderaadt fclose(input[0]); 646ae8d569bSderaadt fclose(input[1]); 647ae8d569bSderaadt /* 648ae8d569bSderaadt if(jackpot) 649ae8d569bSderaadt fprintf(stderr, "jackpot\n"); 650ae8d569bSderaadt */ 651ae8d569bSderaadt } 652ae8d569bSderaadt 65326da422aStedu static void 65426da422aStedu sort(struct line *a, int n) 65526da422aStedu { /* shellsort CACM #201 */ 656ae8d569bSderaadt struct line w; 65726da422aStedu int j, m = 0; /* gcc */ 658ae8d569bSderaadt struct line *ai; 65926da422aStedu struct line *aim; 660ae8d569bSderaadt int k; 661ae8d569bSderaadt 662ae8d569bSderaadt if (n == 0) 663ae8d569bSderaadt return; 664ae8d569bSderaadt for (j = 1; j <= n; j *= 2) 665ae8d569bSderaadt m = 2 * j - 1; 666ae8d569bSderaadt for (m /= 2; m != 0; m /= 2) { 667ae8d569bSderaadt k = n - m; 668ae8d569bSderaadt for (j = 1; j <= k; j++) { 669ae8d569bSderaadt for (ai = &a[j]; ai > a; ai -= m) { 670ae8d569bSderaadt aim = &ai[m]; 671ae8d569bSderaadt if (aim < ai) 672ae8d569bSderaadt break; /* wraparound */ 673ae8d569bSderaadt if (aim->value > ai[0].value || 67426da422aStedu (aim->value == ai[0].value && 67526da422aStedu aim->serial > ai[0].serial)) 676ae8d569bSderaadt break; 677ae8d569bSderaadt w.value = ai[0].value; 678ae8d569bSderaadt ai[0].value = aim->value; 679ae8d569bSderaadt aim->value = w.value; 680ae8d569bSderaadt w.serial = ai[0].serial; 681ae8d569bSderaadt ai[0].serial = aim->serial; 682ae8d569bSderaadt aim->serial = w.serial; 683ae8d569bSderaadt } 684ae8d569bSderaadt } 685ae8d569bSderaadt } 686ae8d569bSderaadt } 687ae8d569bSderaadt 68826da422aStedu static void 68926da422aStedu unsort(struct line *f, int l, int *b) 690ae8d569bSderaadt { 69126da422aStedu int *a; 69226da422aStedu int i; 69326da422aStedu 69426da422aStedu a = talloc((l + 1) * sizeof(int)); 695ae8d569bSderaadt for (i = 1; i <= l; i++) 696ae8d569bSderaadt a[f[i].serial] = f[i].value; 697ae8d569bSderaadt for (i = 1; i <= l; i++) 698ae8d569bSderaadt b[i] = a[i]; 69926da422aStedu free(a); 700ae8d569bSderaadt } 701ae8d569bSderaadt 70226da422aStedu static int 70326da422aStedu skipline(int f) 704ae8d569bSderaadt { 70526da422aStedu int i, c; 706ae8d569bSderaadt 707ae8d569bSderaadt for (i = 1; (c = getc(input[f])) != '\n'; i++) 708ae8d569bSderaadt if (c < 0) 709ae8d569bSderaadt return (i); 710ae8d569bSderaadt return (i); 711ae8d569bSderaadt } 712ae8d569bSderaadt 71326da422aStedu static void 71426da422aStedu output(void) 715ae8d569bSderaadt { 716ae8d569bSderaadt int m; 71726da422aStedu int i0, i1, j1; 718ae8d569bSderaadt int j0; 719ae8d569bSderaadt input[0] = fopen(file1, "r"); 720ae8d569bSderaadt input[1] = fopen(file2, "r"); 721ae8d569bSderaadt m = len[0]; 722ae8d569bSderaadt J[0] = 0; 723ae8d569bSderaadt J[m + 1] = len[1] + 1; 72426da422aStedu if (opt != D_EDIT) { 72526da422aStedu for (i0 = 1; i0 <= m; i0 = i1 + 1) { 72626da422aStedu while (i0 <= m && J[i0] == J[i0 - 1] + 1) 72726da422aStedu i0++; 728ae8d569bSderaadt j0 = J[i0 - 1] + 1; 729ae8d569bSderaadt i1 = i0 - 1; 73026da422aStedu while (i1 < m && J[i1 + 1] == 0) 73126da422aStedu i1++; 732ae8d569bSderaadt j1 = J[i1 + 1] - 1; 733ae8d569bSderaadt J[i1] = j1; 734ae8d569bSderaadt change(i0, i1, j0, j1); 73526da422aStedu } 73626da422aStedu } else { 73726da422aStedu for (i0 = m; i0 >= 1; i0 = i1 - 1) { 73826da422aStedu while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0) 73926da422aStedu i0--; 740ae8d569bSderaadt j0 = J[i0 + 1] - 1; 741ae8d569bSderaadt i1 = i0 + 1; 74226da422aStedu while (i1 > 1 && J[i1 - 1] == 0) 74326da422aStedu i1--; 744ae8d569bSderaadt j1 = J[i1 - 1] + 1; 745ae8d569bSderaadt J[i1] = j1; 746ae8d569bSderaadt change(i1, i0, j1, j0); 747ae8d569bSderaadt } 74826da422aStedu } 749ae8d569bSderaadt if (m == 0) 750ae8d569bSderaadt change(1, 0, 1, len[1]); 751ae8d569bSderaadt if (opt == D_IFDEF) { 752ae8d569bSderaadt for (;;) { 753ae8d569bSderaadt #define c i0 754ae8d569bSderaadt c = getc(input[0]); 755ae8d569bSderaadt if (c < 0) 756ae8d569bSderaadt return; 757ae8d569bSderaadt putchar(c); 758ae8d569bSderaadt } 759ae8d569bSderaadt #undef c 760ae8d569bSderaadt } 761ae8d569bSderaadt if (anychange && opt == D_CONTEXT) 762ae8d569bSderaadt dump_context_vec(); 763ae8d569bSderaadt } 764ae8d569bSderaadt 765ae8d569bSderaadt /* 766ae8d569bSderaadt * The following struct is used to record change information when 767ae8d569bSderaadt * doing a "context" diff. (see routine "change" to understand the 768ae8d569bSderaadt * highly mneumonic field names) 769ae8d569bSderaadt */ 770ae8d569bSderaadt struct context_vec { 771ae8d569bSderaadt int a; /* start line in old file */ 772ae8d569bSderaadt int b; /* end line in old file */ 773ae8d569bSderaadt int c; /* start line in new file */ 774ae8d569bSderaadt int d; /* end line in new file */ 775ae8d569bSderaadt }; 776ae8d569bSderaadt 77726da422aStedu struct context_vec *context_vec_start, *context_vec_end, *context_vec_ptr; 778ae8d569bSderaadt 779ae8d569bSderaadt #define MAX_CONTEXT 128 780ae8d569bSderaadt 78126da422aStedu /* 78226da422aStedu * indicate that there is a difference between lines a and b of the from file 78326da422aStedu * to get to lines c to d of the to file. If a is greater then b then there 78426da422aStedu * are no lines in the from file involved and this means that there were 78526da422aStedu * lines appended (beginning at b). If c is greater than d then there are 78626da422aStedu * lines missing from the to file. 787ae8d569bSderaadt */ 78826da422aStedu static void 78926da422aStedu change(int a, int b, int c, int d) 790ae8d569bSderaadt { 791ae8d569bSderaadt struct stat stbuf; 792ae8d569bSderaadt 793ae8d569bSderaadt if (opt != D_IFDEF && a > b && c > d) 794ae8d569bSderaadt return; 795ae8d569bSderaadt if (anychange == 0) { 796ae8d569bSderaadt anychange = 1; 797ae8d569bSderaadt if (opt == D_CONTEXT) { 798ae8d569bSderaadt printf("*** %s ", file1); 799ae8d569bSderaadt stat(file1, &stbuf); 800ae8d569bSderaadt printf("%s--- %s ", 801ae8d569bSderaadt ctime(&stbuf.st_mtime), file2); 802ae8d569bSderaadt stat(file2, &stbuf); 803ae8d569bSderaadt printf("%s", ctime(&stbuf.st_mtime)); 804ae8d569bSderaadt 80526da422aStedu context_vec_start = talloc(MAX_CONTEXT * 806ae8d569bSderaadt sizeof(struct context_vec)); 807ae8d569bSderaadt context_vec_end = context_vec_start + MAX_CONTEXT; 808ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 809ae8d569bSderaadt } 810ae8d569bSderaadt } 811ae8d569bSderaadt if (opt == D_CONTEXT) { 812ae8d569bSderaadt /* 813ae8d569bSderaadt * if this new change is within 'context' lines of 814ae8d569bSderaadt * the previous change, just add it to the change 815ae8d569bSderaadt * record. If the record is full or if this 816ae8d569bSderaadt * change is more than 'context' lines from the previous 817ae8d569bSderaadt * change, dump the record, reset it & add the new change. 818ae8d569bSderaadt */ 819ae8d569bSderaadt if (context_vec_ptr >= context_vec_end || 820ae8d569bSderaadt (context_vec_ptr >= context_vec_start && 821ae8d569bSderaadt a > (context_vec_ptr->b + 2 * context) && 822ae8d569bSderaadt c > (context_vec_ptr->d + 2 * context))) 823ae8d569bSderaadt dump_context_vec(); 824ae8d569bSderaadt 825ae8d569bSderaadt context_vec_ptr++; 826ae8d569bSderaadt context_vec_ptr->a = a; 827ae8d569bSderaadt context_vec_ptr->b = b; 828ae8d569bSderaadt context_vec_ptr->c = c; 829ae8d569bSderaadt context_vec_ptr->d = d; 830ae8d569bSderaadt return; 831ae8d569bSderaadt } 832ae8d569bSderaadt switch (opt) { 833ae8d569bSderaadt 834ae8d569bSderaadt case D_NORMAL: 835ae8d569bSderaadt case D_EDIT: 836ae8d569bSderaadt range(a, b, ","); 837ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 838ae8d569bSderaadt if (opt == D_NORMAL) 839ae8d569bSderaadt range(c, d, ","); 840ae8d569bSderaadt putchar('\n'); 841ae8d569bSderaadt break; 842ae8d569bSderaadt case D_REVERSE: 843ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 844ae8d569bSderaadt range(a, b, " "); 845ae8d569bSderaadt putchar('\n'); 846ae8d569bSderaadt break; 847ae8d569bSderaadt case D_NREVERSE: 848ae8d569bSderaadt if (a > b) 849ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 850ae8d569bSderaadt else { 851ae8d569bSderaadt printf("d%d %d\n", a, b - a + 1); 852ae8d569bSderaadt if (!(c > d)) 853ae8d569bSderaadt /* add changed lines */ 854ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 855ae8d569bSderaadt } 856ae8d569bSderaadt break; 857ae8d569bSderaadt } 858ae8d569bSderaadt if (opt == D_NORMAL || opt == D_IFDEF) { 859ae8d569bSderaadt fetch(ixold, a, b, input[0], "< ", 1); 860ae8d569bSderaadt if (a <= b && c <= d && opt == D_NORMAL) 861ae8d569bSderaadt prints("---\n"); 862ae8d569bSderaadt } 863ae8d569bSderaadt fetch(ixnew, c, d, input[1], opt == D_NORMAL ? "> " : "", 0); 864ae8d569bSderaadt if ((opt == D_EDIT || opt == D_REVERSE) && c <= d) 865ae8d569bSderaadt prints(".\n"); 866ae8d569bSderaadt if (inifdef) { 867ae8d569bSderaadt fprintf(stdout, "#endif /* %s */\n", endifname); 868ae8d569bSderaadt inifdef = 0; 869ae8d569bSderaadt } 870ae8d569bSderaadt } 871ae8d569bSderaadt 87226da422aStedu static void 87326da422aStedu range(int a, int b, char *separator) 874ae8d569bSderaadt { 875ae8d569bSderaadt printf("%d", a > b ? b : a); 876ae8d569bSderaadt if (a < b) { 877ae8d569bSderaadt printf("%s%d", separator, b); 878ae8d569bSderaadt } 879ae8d569bSderaadt } 880ae8d569bSderaadt 88126da422aStedu static void 88226da422aStedu fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile) 883ae8d569bSderaadt { 88426da422aStedu int i, j; 88526da422aStedu int c; 88626da422aStedu int col; 88726da422aStedu int nc; 888ae8d569bSderaadt int oneflag = (*ifdef1 != '\0') != (*ifdef2 != '\0'); 889ae8d569bSderaadt 890ae8d569bSderaadt /* 891ae8d569bSderaadt * When doing #ifdef's, copy down to current line 892ae8d569bSderaadt * if this is the first file, so that stuff makes it to output. 893ae8d569bSderaadt */ 894ae8d569bSderaadt if (opt == D_IFDEF && oldfile) { 895ae8d569bSderaadt long curpos = ftell(lb); 896ae8d569bSderaadt /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 897ae8d569bSderaadt nc = f[a > b ? b : a - 1] - curpos; 898ae8d569bSderaadt for (i = 0; i < nc; i++) 899ae8d569bSderaadt putchar(getc(lb)); 900ae8d569bSderaadt } 901ae8d569bSderaadt if (a > b) 902ae8d569bSderaadt return; 903ae8d569bSderaadt if (opt == D_IFDEF) { 904ae8d569bSderaadt if (inifdef) 905ae8d569bSderaadt fprintf(stdout, "#else /* %s%s */\n", oneflag && oldfile == 1 ? "!" : "", ifdef2); 906ae8d569bSderaadt else { 907ae8d569bSderaadt if (oneflag) { 908ae8d569bSderaadt /* There was only one ifdef given */ 909ae8d569bSderaadt endifname = ifdef2; 910ae8d569bSderaadt if (oldfile) 911ae8d569bSderaadt fprintf(stdout, "#ifndef %s\n", endifname); 912ae8d569bSderaadt else 913ae8d569bSderaadt fprintf(stdout, "#ifdef %s\n", endifname); 91426da422aStedu } else { 915ae8d569bSderaadt endifname = oldfile ? ifdef1 : ifdef2; 916ae8d569bSderaadt fprintf(stdout, "#ifdef %s\n", endifname); 917ae8d569bSderaadt } 918ae8d569bSderaadt } 919ae8d569bSderaadt inifdef = 1 + oldfile; 920ae8d569bSderaadt } 921ae8d569bSderaadt for (i = a; i <= b; i++) { 922ae8d569bSderaadt fseek(lb, f[i - 1], 0); 923ae8d569bSderaadt nc = f[i] - f[i - 1]; 924ae8d569bSderaadt if (opt != D_IFDEF) 925ae8d569bSderaadt prints(s); 926ae8d569bSderaadt col = 0; 927ae8d569bSderaadt for (j = 0; j < nc; j++) { 928ae8d569bSderaadt c = getc(lb); 929ae8d569bSderaadt if (c == '\t' && tflag) 930ae8d569bSderaadt do 931ae8d569bSderaadt putchar(' '); 932ae8d569bSderaadt while (++col & 7); 933ae8d569bSderaadt else { 934ae8d569bSderaadt putchar(c); 935ae8d569bSderaadt col++; 936ae8d569bSderaadt } 937ae8d569bSderaadt } 938ae8d569bSderaadt } 939ae8d569bSderaadt 940ae8d569bSderaadt if (inifdef && !wantelses) { 941ae8d569bSderaadt fprintf(stdout, "#endif /* %s */\n", endifname); 942ae8d569bSderaadt inifdef = 0; 943ae8d569bSderaadt } 944ae8d569bSderaadt } 945ae8d569bSderaadt 946ae8d569bSderaadt #define POW2 /* define only if HALFLONG is 2**n */ 947ae8d569bSderaadt #define HALFLONG 16 948ae8d569bSderaadt #define low(x) (x&((1L<<HALFLONG)-1)) 949ae8d569bSderaadt #define high(x) (x>>HALFLONG) 950ae8d569bSderaadt 951ae8d569bSderaadt /* 952ae8d569bSderaadt * hashing has the effect of 953ae8d569bSderaadt * arranging line in 7-bit bytes and then 954ae8d569bSderaadt * summing 1-s complement in 16-bit hunks 955ae8d569bSderaadt */ 95626da422aStedu static int 95726da422aStedu readhash(FILE *f) 958ae8d569bSderaadt { 95926da422aStedu long sum; 96026da422aStedu unsigned shift; 96126da422aStedu int t; 96226da422aStedu int space; 963ae8d569bSderaadt 964ae8d569bSderaadt sum = 1; 965ae8d569bSderaadt space = 0; 966ae8d569bSderaadt if (!bflag && !wflag) { 967ae8d569bSderaadt if (iflag) 968ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 969ae8d569bSderaadt if (t == -1) 970ae8d569bSderaadt return (0); 971ae8d569bSderaadt sum += (long)chrtran[t] << (shift 972ae8d569bSderaadt #ifdef POW2 973ae8d569bSderaadt &= HALFLONG - 1); 974ae8d569bSderaadt #else 975ae8d569bSderaadt %= HALFLONG); 976ae8d569bSderaadt #endif 977ae8d569bSderaadt } 978ae8d569bSderaadt else 979ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 980ae8d569bSderaadt if (t == -1) 981ae8d569bSderaadt return (0); 982ae8d569bSderaadt sum += (long)t << (shift 983ae8d569bSderaadt #ifdef POW2 984ae8d569bSderaadt &= HALFLONG - 1); 985ae8d569bSderaadt #else 986ae8d569bSderaadt %= HALFLONG); 987ae8d569bSderaadt #endif 988ae8d569bSderaadt } 989ae8d569bSderaadt } else { 990ae8d569bSderaadt for (shift = 0;;) { 991ae8d569bSderaadt switch (t = getc(f)) { 992ae8d569bSderaadt case -1: 993ae8d569bSderaadt return (0); 994ae8d569bSderaadt case '\t': 995ae8d569bSderaadt case ' ': 996ae8d569bSderaadt space++; 997ae8d569bSderaadt continue; 998ae8d569bSderaadt default: 999ae8d569bSderaadt if (space && !wflag) { 1000ae8d569bSderaadt shift += 7; 1001ae8d569bSderaadt space = 0; 1002ae8d569bSderaadt } 1003ae8d569bSderaadt sum += (long)chrtran[t] << (shift 1004ae8d569bSderaadt #ifdef POW2 1005ae8d569bSderaadt &= HALFLONG - 1); 1006ae8d569bSderaadt #else 1007ae8d569bSderaadt %= HALFLONG); 1008ae8d569bSderaadt #endif 1009ae8d569bSderaadt shift += 7; 1010ae8d569bSderaadt continue; 1011ae8d569bSderaadt case '\n': 1012ae8d569bSderaadt break; 1013ae8d569bSderaadt } 1014ae8d569bSderaadt break; 1015ae8d569bSderaadt } 1016ae8d569bSderaadt } 1017ae8d569bSderaadt sum = low(sum) + high(sum); 1018ae8d569bSderaadt return ((short) low(sum) + (short) high(sum)); 1019ae8d569bSderaadt } 1020ae8d569bSderaadt 102126da422aStedu static int 102226da422aStedu asciifile(FILE *f) 1023ae8d569bSderaadt { 1024ae8d569bSderaadt char buf[BUFSIZ]; 102526da422aStedu int cnt; 102626da422aStedu char *cp; 1027ae8d569bSderaadt 102826da422aStedu fseek(f, 0, 0); 1029ae8d569bSderaadt cnt = fread(buf, 1, BUFSIZ, f); 1030ae8d569bSderaadt cp = buf; 1031ae8d569bSderaadt while (--cnt >= 0) 1032ae8d569bSderaadt if (*cp++ & 0200) 1033ae8d569bSderaadt return (0); 1034ae8d569bSderaadt return (1); 1035ae8d569bSderaadt } 1036ae8d569bSderaadt 1037ae8d569bSderaadt 1038ae8d569bSderaadt /* dump accumulated "context" diff changes */ 103926da422aStedu static void 104026da422aStedu dump_context_vec(void) 1041ae8d569bSderaadt { 104226da422aStedu int a, b, c, d; 104326da422aStedu char ch; 104426da422aStedu struct context_vec *cvp = context_vec_start; 104526da422aStedu int lowa, upb, lowc, upd; 104626da422aStedu int do_output; 1047ae8d569bSderaadt 1048ae8d569bSderaadt if (cvp > context_vec_ptr) 1049ae8d569bSderaadt return; 1050ae8d569bSderaadt 105126da422aStedu b = d = 0; /* gcc */ 1052ae8d569bSderaadt lowa = max(1, cvp->a - context); 1053ae8d569bSderaadt upb = min(len[0], context_vec_ptr->b + context); 1054ae8d569bSderaadt lowc = max(1, cvp->c - context); 1055ae8d569bSderaadt upd = min(len[1], context_vec_ptr->d + context); 1056ae8d569bSderaadt 1057ae8d569bSderaadt printf("***************\n*** "); 1058ae8d569bSderaadt range(lowa, upb, ","); 1059ae8d569bSderaadt printf(" ****\n"); 1060ae8d569bSderaadt 1061ae8d569bSderaadt /* 1062ae8d569bSderaadt * output changes to the "old" file. The first loop suppresses 1063ae8d569bSderaadt * output if there were no changes to the "old" file (we'll see 1064ae8d569bSderaadt * the "old" lines as context in the "new" list). 1065ae8d569bSderaadt */ 1066ae8d569bSderaadt do_output = 0; 1067ae8d569bSderaadt for (; cvp <= context_vec_ptr; cvp++) 1068ae8d569bSderaadt if (cvp->a <= cvp->b) { 1069ae8d569bSderaadt cvp = context_vec_start; 1070ae8d569bSderaadt do_output++; 1071ae8d569bSderaadt break; 1072ae8d569bSderaadt } 1073ae8d569bSderaadt if (do_output) { 1074ae8d569bSderaadt while (cvp <= context_vec_ptr) { 107526da422aStedu a = cvp->a; 107626da422aStedu b = cvp->b; 107726da422aStedu c = cvp->c; 107826da422aStedu d = cvp->d; 1079ae8d569bSderaadt 1080ae8d569bSderaadt if (a <= b && c <= d) 1081ae8d569bSderaadt ch = 'c'; 1082ae8d569bSderaadt else 1083ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1084ae8d569bSderaadt 1085ae8d569bSderaadt if (ch == 'a') 108626da422aStedu fetch(ixold, lowa, b, input[0], " ", 0); 1087ae8d569bSderaadt else { 108826da422aStedu fetch(ixold, lowa, a - 1, input[0], " ", 0); 108926da422aStedu fetch(ixold, a, b, input[0], ch == 'c' ? "! " : "- ", 0); 1090ae8d569bSderaadt } 1091ae8d569bSderaadt lowa = b + 1; 1092ae8d569bSderaadt cvp++; 1093ae8d569bSderaadt } 109426da422aStedu fetch(ixold, b + 1, upb, input[0], " ", 0); 1095ae8d569bSderaadt } 1096ae8d569bSderaadt /* output changes to the "new" file */ 1097ae8d569bSderaadt printf("--- "); 1098ae8d569bSderaadt range(lowc, upd, ","); 1099ae8d569bSderaadt printf(" ----\n"); 1100ae8d569bSderaadt 1101ae8d569bSderaadt do_output = 0; 1102ae8d569bSderaadt for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 1103ae8d569bSderaadt if (cvp->c <= cvp->d) { 1104ae8d569bSderaadt cvp = context_vec_start; 1105ae8d569bSderaadt do_output++; 1106ae8d569bSderaadt break; 1107ae8d569bSderaadt } 1108ae8d569bSderaadt if (do_output) { 1109ae8d569bSderaadt while (cvp <= context_vec_ptr) { 111026da422aStedu a = cvp->a; 111126da422aStedu b = cvp->b; 111226da422aStedu c = cvp->c; 111326da422aStedu d = cvp->d; 1114ae8d569bSderaadt 1115ae8d569bSderaadt if (a <= b && c <= d) 1116ae8d569bSderaadt ch = 'c'; 1117ae8d569bSderaadt else 1118ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1119ae8d569bSderaadt 1120ae8d569bSderaadt if (ch == 'd') 112126da422aStedu fetch(ixnew, lowc, d, input[1], " ", 0); 1122ae8d569bSderaadt else { 112326da422aStedu fetch(ixnew, lowc, c - 1, input[1], " ", 0); 112426da422aStedu fetch(ixnew, c, d, input[1], ch == 'c' ? "! " : "+ ", 0); 1125ae8d569bSderaadt } 1126ae8d569bSderaadt lowc = d + 1; 1127ae8d569bSderaadt cvp++; 1128ae8d569bSderaadt } 112926da422aStedu fetch(ixnew, d + 1, upd, input[1], " ", 0); 1130ae8d569bSderaadt } 1131ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 1132ae8d569bSderaadt } 1133