1*90f56ad8Smillert /* $OpenBSD: diffreg.c,v 1.22 2003/06/26 22:04:45 millert 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 122ae8d569bSderaadt struct cand { 123ae8d569bSderaadt int x; 124ae8d569bSderaadt int y; 125ae8d569bSderaadt int pred; 126ae8d569bSderaadt } cand; 12726da422aStedu 128ae8d569bSderaadt struct line { 129ae8d569bSderaadt int serial; 130ae8d569bSderaadt int value; 13192af4c2dStedu } *file[2]; 13226da422aStedu 133ae8d569bSderaadt int len[2]; 1340c9f493eStedu struct line *sfile[2]; /* shortened by pruning common prefix and suffix */ 135ae8d569bSderaadt int slen[2]; 136ae8d569bSderaadt int pref, suff; /* length of prefix and suffix */ 137ae8d569bSderaadt int *class; /* will be overlaid on file[0] */ 138ae8d569bSderaadt int *member; /* will be overlaid on file[1] */ 139ae8d569bSderaadt int *klist; /* will be overlaid on file[0] after class */ 140ae8d569bSderaadt struct cand *clist; /* merely a free storage pot for candidates */ 141ae8d569bSderaadt int clen = 0; 142ae8d569bSderaadt int *J; /* will be overlaid on class */ 143ae8d569bSderaadt long *ixold; /* will be overlaid on klist */ 144ae8d569bSderaadt long *ixnew; /* will be overlaid on file[1] */ 1458a15d8deSderaadt u_char *chrtran; /* translation table for case-folding */ 146ae8d569bSderaadt 14726da422aStedu static void fetch(long *, int, int, FILE *, char *, int); 14826da422aStedu static void output(void); 14926da422aStedu static void check(void); 15026da422aStedu static void range(int, int, char *); 15126da422aStedu static void dump_context_vec(void); 1529de32c1bSmillert static void dump_unified_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 */ 1718a15d8deSderaadt u_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 1988a15d8deSderaadt u_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 { 228ae8d569bSderaadt char buf1[BUFSIZ], buf2[BUFSIZ]; 22948b8c3e3Sderaadt FILE *f1, *f2; 23048b8c3e3Sderaadt int i, j; 231ae8d569bSderaadt 232ae8d569bSderaadt if (hflag) { 233ae8d569bSderaadt diffargv[0] = "diffh"; 234ae8d569bSderaadt execv(diffh, diffargv); 23566e5764eSmillert error("%s", diffh); 236ae8d569bSderaadt } 237ae8d569bSderaadt chrtran = (iflag ? cup2low : clow2low); 23866e5764eSmillert if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) 23966e5764eSmillert errorx("can't specify - -"); 24048b947b7Smillert if (S_ISDIR(stb1.st_mode)) { 241ae8d569bSderaadt file1 = splice(file1, file2); 24266e5764eSmillert if (stat(file1, &stb1) < 0) 24366e5764eSmillert error("%s", file1); 24448b947b7Smillert } else if (!S_ISREG(stb1.st_mode) || strcmp(file1, "-") == 0) { 24548b947b7Smillert file1 = copytemp(file1, 1); 24666e5764eSmillert if (stat(file1, &stb1) < 0) 24766e5764eSmillert error("%s", file1); 24848b947b7Smillert } 24948b947b7Smillert if (S_ISDIR(stb2.st_mode)) { 250ae8d569bSderaadt file2 = splice(file2, file1); 25166e5764eSmillert if (stat(file2, &stb2) < 0) 25266e5764eSmillert error("%s", file2); 25348b947b7Smillert } else if (!S_ISREG(stb2.st_mode) || strcmp(file2, "-") == 0) { 25448b947b7Smillert file2 = copytemp(file2, 2); 25566e5764eSmillert if (stat(file2, &stb2) < 0) 25666e5764eSmillert error("%s", file2); 257ae8d569bSderaadt } 25866e5764eSmillert if ((f1 = fopen(file1, "r")) == NULL) 25966e5764eSmillert error("%s", file1); 26066e5764eSmillert if ((f2 = fopen(file2, "r")) == NULL) 26166e5764eSmillert error("%s", file2); 26248b947b7Smillert if (S_ISREG(stb1.st_mode) && S_ISREG(stb2.st_mode) && 26348b947b7Smillert stb1.st_size != stb2.st_size) 264ae8d569bSderaadt goto notsame; 265ae8d569bSderaadt for (;;) { 266ae8d569bSderaadt i = fread(buf1, 1, BUFSIZ, f1); 267ae8d569bSderaadt j = fread(buf2, 1, BUFSIZ, f2); 268ae8d569bSderaadt if (i < 0 || j < 0 || i != j) 269ae8d569bSderaadt goto notsame; 270ae8d569bSderaadt if (i == 0 && j == 0) { 271ae8d569bSderaadt fclose(f1); 272ae8d569bSderaadt fclose(f2); 273ae8d569bSderaadt status = 0; /* files don't differ */ 274ae8d569bSderaadt goto same; 275ae8d569bSderaadt } 276ae8d569bSderaadt for (j = 0; j < i; j++) 277ae8d569bSderaadt if (buf1[j] != buf2[j]) 278ae8d569bSderaadt goto notsame; 279ae8d569bSderaadt } 280ae8d569bSderaadt notsame: 281ae8d569bSderaadt /* 282ae8d569bSderaadt * Files certainly differ at this point; set status accordingly 283ae8d569bSderaadt */ 284ae8d569bSderaadt status = 1; 285ae8d569bSderaadt if (!asciifile(f1) || !asciifile(f2)) { 286ae8d569bSderaadt printf("Binary files %s and %s differ\n", file1, file2); 28766e5764eSmillert exit(status); 288ae8d569bSderaadt } 289ae8d569bSderaadt prepare(0, f1); 290ae8d569bSderaadt prepare(1, f2); 291ae8d569bSderaadt fclose(f1); 292ae8d569bSderaadt fclose(f2); 293ae8d569bSderaadt prune(); 294ae8d569bSderaadt sort(sfile[0], slen[0]); 295ae8d569bSderaadt sort(sfile[1], slen[1]); 296ae8d569bSderaadt 297ae8d569bSderaadt member = (int *)file[1]; 298ae8d569bSderaadt equiv(sfile[0], slen[0], sfile[1], slen[1], member); 29949dffe13Smillert member = erealloc(member, (slen[1] + 2) * sizeof(int)); 300ae8d569bSderaadt 301ae8d569bSderaadt class = (int *)file[0]; 302ae8d569bSderaadt unsort(sfile[0], slen[0], class); 30349dffe13Smillert class = erealloc(class, (slen[0] + 2) * sizeof(int)); 304ae8d569bSderaadt 30549dffe13Smillert klist = emalloc((slen[0] + 2) * sizeof(int)); 30649dffe13Smillert clist = emalloc(sizeof(cand)); 307ae8d569bSderaadt i = stone(class, slen[0], member, klist); 30826da422aStedu free(member); 30926da422aStedu free(class); 310ae8d569bSderaadt 31149dffe13Smillert J = emalloc((len[0] + 2) * sizeof(int)); 312ae8d569bSderaadt unravel(klist[i]); 31326da422aStedu free(clist); 31426da422aStedu free(klist); 315ae8d569bSderaadt 31649dffe13Smillert ixold = emalloc((len[0] + 2) * sizeof(long)); 31749dffe13Smillert ixnew = emalloc((len[1] + 2) * sizeof(long)); 318ae8d569bSderaadt check(); 319ae8d569bSderaadt output(); 320ae8d569bSderaadt status = anychange; 321ae8d569bSderaadt same: 3229de32c1bSmillert if (anychange == 0 && (opt == D_CONTEXT || opt == D_UNIFIED)) 323ae8d569bSderaadt printf("No differences encountered\n"); 324ae8d569bSderaadt } 325ae8d569bSderaadt 32648b947b7Smillert char *tempfiles[2]; 327ae8d569bSderaadt 328ae8d569bSderaadt char * 32948b947b7Smillert copytemp(const char *file, int n) 330ae8d569bSderaadt { 33148b947b7Smillert char buf[BUFSIZ], *tempdir, *tempfile; 33248b947b7Smillert int i, ifd, ofd; 33348b947b7Smillert 33448b947b7Smillert if (n != 1 && n != 2) 33548b947b7Smillert return (NULL); 33648b947b7Smillert 33748b947b7Smillert if (strcmp(file, "-") == 0) 33848b947b7Smillert ifd = STDIN_FILENO; 33966e5764eSmillert else if ((ifd = open(file, O_RDONLY, 0644)) < 0) 34066e5764eSmillert error("%s", file); 34148b947b7Smillert 34248b947b7Smillert if ((tempdir = getenv("TMPDIR")) == NULL) 34348b947b7Smillert tempdir = _PATH_TMP; 34466e5764eSmillert if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1) 34566e5764eSmillert error(NULL); 34648b947b7Smillert tempfiles[n - 1] = tempfile; 347ae8d569bSderaadt 3487d9f164dStedu signal(SIGHUP, done); 3497d9f164dStedu signal(SIGINT, done); 3507d9f164dStedu signal(SIGPIPE, done); 3517d9f164dStedu signal(SIGTERM, done); 35248b947b7Smillert ofd = mkstemp(tempfile); 35366e5764eSmillert if (ofd < 0) 35466e5764eSmillert error("%s", tempfile); 35566e5764eSmillert while ((i = read(ifd, buf, BUFSIZ)) > 0) { 35666e5764eSmillert if (write(ofd, buf, i) != i) 35766e5764eSmillert error("%s", tempfile); 358ae8d569bSderaadt } 35948b947b7Smillert close(ifd); 36048b947b7Smillert close(ofd); 361ae8d569bSderaadt return (tempfile); 362ae8d569bSderaadt } 363ae8d569bSderaadt 364ae8d569bSderaadt char * 36526da422aStedu splice(char *dir, char *file) 366ae8d569bSderaadt { 36749dffe13Smillert char *tail, *buf; 36849dffe13Smillert size_t len; 369ae8d569bSderaadt 37066e5764eSmillert if (!strcmp(file, "-")) 37166e5764eSmillert errorx("can't specify - with other arg directory"); 372d226b3cdSderaadt tail = strrchr(file, '/'); 37349dffe13Smillert if (tail == NULL) 374ae8d569bSderaadt tail = file; 375ae8d569bSderaadt else 376ae8d569bSderaadt tail++; 3777f136ccbSvincent len = strlen(dir) + 1 + strlen(tail) + 1; 37849dffe13Smillert buf = emalloc(len); 37949dffe13Smillert snprintf(buf, len, "%s/%s", dir, tail); 38049dffe13Smillert return (buf); 381ae8d569bSderaadt } 382ae8d569bSderaadt 38326da422aStedu static void 38426da422aStedu prepare(int i, FILE *fd) 385ae8d569bSderaadt { 38626da422aStedu struct line *p; 38726da422aStedu int j, h; 388ae8d569bSderaadt 3898ae1ab09Sderaadt fseek(fd, 0L, SEEK_SET); 39049dffe13Smillert p = emalloc(3 * sizeof(struct line)); 39126da422aStedu for (j = 0; (h = readhash(fd));) { 39249dffe13Smillert p = erealloc(p, (++j + 3) * sizeof(struct line)); 393ae8d569bSderaadt p[j].value = h; 394ae8d569bSderaadt } 395ae8d569bSderaadt len[i] = j; 396ae8d569bSderaadt file[i] = p; 397ae8d569bSderaadt } 398ae8d569bSderaadt 39926da422aStedu static void 40026da422aStedu prune(void) 401ae8d569bSderaadt { 40226da422aStedu int i, j; 40348b8c3e3Sderaadt 404ae8d569bSderaadt for (pref = 0; pref < len[0] && pref < len[1] && 405ae8d569bSderaadt file[0][pref + 1].value == file[1][pref + 1].value; 4067d2b2b91Sderaadt pref++) 4077d2b2b91Sderaadt ; 408ae8d569bSderaadt for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 409ae8d569bSderaadt file[0][len[0] - suff].value == file[1][len[1] - suff].value; 4107d2b2b91Sderaadt suff++) 4117d2b2b91Sderaadt ; 412ae8d569bSderaadt for (j = 0; j < 2; j++) { 413ae8d569bSderaadt sfile[j] = file[j] + pref; 414ae8d569bSderaadt slen[j] = len[j] - pref - suff; 415ae8d569bSderaadt for (i = 0; i <= slen[j]; i++) 416ae8d569bSderaadt sfile[j][i].serial = i; 417ae8d569bSderaadt } 418ae8d569bSderaadt } 419ae8d569bSderaadt 42026da422aStedu static void 42126da422aStedu equiv(struct line *a, int n, struct line *b, int m, int *c) 422ae8d569bSderaadt { 42326da422aStedu int i, j; 42448b8c3e3Sderaadt 425ae8d569bSderaadt i = j = 1; 426ae8d569bSderaadt while (i <= n && j <= m) { 427ae8d569bSderaadt if (a[i].value < b[j].value) 428ae8d569bSderaadt a[i++].value = 0; 429ae8d569bSderaadt else if (a[i].value == b[j].value) 430ae8d569bSderaadt a[i++].value = j; 431ae8d569bSderaadt else 432ae8d569bSderaadt j++; 433ae8d569bSderaadt } 434ae8d569bSderaadt while (i <= n) 435ae8d569bSderaadt a[i++].value = 0; 436ae8d569bSderaadt b[m + 1].value = 0; 437ae8d569bSderaadt j = 0; 438ae8d569bSderaadt while (++j <= m) { 439ae8d569bSderaadt c[j] = -b[j].serial; 440ae8d569bSderaadt while (b[j + 1].value == b[j].value) { 441ae8d569bSderaadt j++; 442ae8d569bSderaadt c[j] = b[j].serial; 443ae8d569bSderaadt } 444ae8d569bSderaadt } 445ae8d569bSderaadt c[j] = -1; 446ae8d569bSderaadt } 447ae8d569bSderaadt 44826da422aStedu static int 44926da422aStedu stone(int *a, int n, int *b, int *c) 450ae8d569bSderaadt { 45148b8c3e3Sderaadt int i, k, y, j, l; 45248b8c3e3Sderaadt int oldc, tc, oldl; 45348b8c3e3Sderaadt 454ae8d569bSderaadt k = 0; 455ae8d569bSderaadt c[0] = newcand(0, 0, 0); 456ae8d569bSderaadt for (i = 1; i <= n; i++) { 457ae8d569bSderaadt j = a[i]; 458ae8d569bSderaadt if (j == 0) 459ae8d569bSderaadt continue; 460ae8d569bSderaadt y = -b[j]; 461ae8d569bSderaadt oldl = 0; 462ae8d569bSderaadt oldc = c[0]; 463ae8d569bSderaadt do { 464ae8d569bSderaadt if (y <= clist[oldc].y) 465ae8d569bSderaadt continue; 466ae8d569bSderaadt l = search(c, k, y); 467ae8d569bSderaadt if (l != oldl + 1) 468ae8d569bSderaadt oldc = c[l - 1]; 469ae8d569bSderaadt if (l <= k) { 470ae8d569bSderaadt if (clist[c[l]].y <= y) 471ae8d569bSderaadt continue; 472ae8d569bSderaadt tc = c[l]; 473ae8d569bSderaadt c[l] = newcand(i, y, oldc); 474ae8d569bSderaadt oldc = tc; 475ae8d569bSderaadt oldl = l; 476ae8d569bSderaadt } else { 477ae8d569bSderaadt c[l] = newcand(i, y, oldc); 478ae8d569bSderaadt k++; 479ae8d569bSderaadt break; 480ae8d569bSderaadt } 481ae8d569bSderaadt } while ((y = b[++j]) > 0); 482ae8d569bSderaadt } 483ae8d569bSderaadt return (k); 484ae8d569bSderaadt } 485ae8d569bSderaadt 48626da422aStedu static int 48726da422aStedu newcand(int x, int y, int pred) 488ae8d569bSderaadt { 48926da422aStedu struct cand *q; 49026da422aStedu 49149dffe13Smillert clist = erealloc(clist, ++clen * sizeof(cand)); 492ae8d569bSderaadt q = clist + clen - 1; 493ae8d569bSderaadt q->x = x; 494ae8d569bSderaadt q->y = y; 495ae8d569bSderaadt q->pred = pred; 496ae8d569bSderaadt return (clen - 1); 497ae8d569bSderaadt } 498ae8d569bSderaadt 49926da422aStedu static int 50026da422aStedu search(int *c, int k, int y) 501ae8d569bSderaadt { 50248b8c3e3Sderaadt int i, j, l, t; 50348b8c3e3Sderaadt 504ae8d569bSderaadt if (clist[c[k]].y < y) /* quick look for typical case */ 505ae8d569bSderaadt return (k + 1); 506ae8d569bSderaadt i = 0; 507ae8d569bSderaadt j = k + 1; 508ae8d569bSderaadt while (1) { 509ae8d569bSderaadt l = i + j; 510ae8d569bSderaadt if ((l >>= 1) <= i) 511ae8d569bSderaadt break; 512ae8d569bSderaadt t = clist[c[l]].y; 513ae8d569bSderaadt if (t > y) 514ae8d569bSderaadt j = l; 515ae8d569bSderaadt else if (t < y) 516ae8d569bSderaadt i = l; 517ae8d569bSderaadt else 518ae8d569bSderaadt return (l); 519ae8d569bSderaadt } 520ae8d569bSderaadt return (l + 1); 521ae8d569bSderaadt } 522ae8d569bSderaadt 52326da422aStedu static void 52426da422aStedu unravel(int p) 525ae8d569bSderaadt { 52626da422aStedu struct cand *q; 52748b8c3e3Sderaadt int i; 52848b8c3e3Sderaadt 529ae8d569bSderaadt for (i = 0; i <= len[0]; i++) 530ae8d569bSderaadt J[i] = i <= pref ? i : 5317d2b2b91Sderaadt i > len[0] - suff ? i + len[1] - len[0] : 0; 532ae8d569bSderaadt for (q = clist + p; q->y != 0; q = clist + q->pred) 533ae8d569bSderaadt J[q->x + pref] = q->y + pref; 534ae8d569bSderaadt } 535ae8d569bSderaadt 53626da422aStedu /* 53749dffe13Smillert * Check does double duty: 53849dffe13Smillert * 1. ferret out any fortuitous correspondences due 53949dffe13Smillert * to confounding by hashing (which result in "jackpot") 54049dffe13Smillert * 2. collect random access indexes to the two files 54126da422aStedu */ 54226da422aStedu static void 54326da422aStedu check(void) 544ae8d569bSderaadt { 54548b8c3e3Sderaadt int i, j, jackpot, c, d; 546ae8d569bSderaadt long ctold, ctnew; 547ae8d569bSderaadt 54866e5764eSmillert if ((input[0] = fopen(file1, "r")) == NULL) 54966e5764eSmillert error("%s", file1); 55066e5764eSmillert if ((input[1] = fopen(file2, "r")) == NULL) 55166e5764eSmillert error("%s", file2); 552ae8d569bSderaadt j = 1; 553ae8d569bSderaadt ixold[0] = ixnew[0] = 0; 554ae8d569bSderaadt jackpot = 0; 555ae8d569bSderaadt ctold = ctnew = 0; 556ae8d569bSderaadt for (i = 1; i <= len[0]; i++) { 557ae8d569bSderaadt if (J[i] == 0) { 558ae8d569bSderaadt ixold[i] = ctold += skipline(0); 559ae8d569bSderaadt continue; 560ae8d569bSderaadt } 561ae8d569bSderaadt while (j < J[i]) { 562ae8d569bSderaadt ixnew[j] = ctnew += skipline(1); 563ae8d569bSderaadt j++; 564ae8d569bSderaadt } 565ae8d569bSderaadt if (bflag || wflag || iflag) { 566ae8d569bSderaadt for (;;) { 567ae8d569bSderaadt c = getc(input[0]); 568ae8d569bSderaadt d = getc(input[1]); 569ae8d569bSderaadt ctold++; 570ae8d569bSderaadt ctnew++; 571ae8d569bSderaadt if (bflag && isspace(c) && isspace(d)) { 572ae8d569bSderaadt do { 573ae8d569bSderaadt if (c == '\n') 574ae8d569bSderaadt break; 575ae8d569bSderaadt ctold++; 576ae8d569bSderaadt } while (isspace(c = getc(input[0]))); 577ae8d569bSderaadt do { 578ae8d569bSderaadt if (d == '\n') 579ae8d569bSderaadt break; 580ae8d569bSderaadt ctnew++; 581ae8d569bSderaadt } while (isspace(d = getc(input[1]))); 582ae8d569bSderaadt } else if (wflag) { 583ae8d569bSderaadt while (isspace(c) && c != '\n') { 584ae8d569bSderaadt c = getc(input[0]); 585ae8d569bSderaadt ctold++; 586ae8d569bSderaadt } 587ae8d569bSderaadt while (isspace(d) && d != '\n') { 588ae8d569bSderaadt d = getc(input[1]); 589ae8d569bSderaadt ctnew++; 590ae8d569bSderaadt } 591ae8d569bSderaadt } 592ae8d569bSderaadt if (chrtran[c] != chrtran[d]) { 593ae8d569bSderaadt jackpot++; 594ae8d569bSderaadt J[i] = 0; 595ae8d569bSderaadt if (c != '\n') 596ae8d569bSderaadt ctold += skipline(0); 597ae8d569bSderaadt if (d != '\n') 598ae8d569bSderaadt ctnew += skipline(1); 599ae8d569bSderaadt break; 600ae8d569bSderaadt } 601ae8d569bSderaadt if (c == '\n') 602ae8d569bSderaadt break; 603ae8d569bSderaadt } 604ae8d569bSderaadt } else { 605ae8d569bSderaadt for (;;) { 606ae8d569bSderaadt ctold++; 607ae8d569bSderaadt ctnew++; 608ae8d569bSderaadt if ((c = getc(input[0])) != (d = getc(input[1]))) { 609ae8d569bSderaadt /* jackpot++; */ 610ae8d569bSderaadt J[i] = 0; 611ae8d569bSderaadt if (c != '\n') 612ae8d569bSderaadt ctold += skipline(0); 613ae8d569bSderaadt if (d != '\n') 614ae8d569bSderaadt ctnew += skipline(1); 615ae8d569bSderaadt break; 616ae8d569bSderaadt } 617ae8d569bSderaadt if (c == '\n') 618ae8d569bSderaadt break; 619ae8d569bSderaadt } 620ae8d569bSderaadt } 621ae8d569bSderaadt ixold[i] = ctold; 622ae8d569bSderaadt ixnew[j] = ctnew; 623ae8d569bSderaadt j++; 624ae8d569bSderaadt } 625ae8d569bSderaadt for (; j <= len[1]; j++) { 626ae8d569bSderaadt ixnew[j] = ctnew += skipline(1); 627ae8d569bSderaadt } 628ae8d569bSderaadt fclose(input[0]); 629ae8d569bSderaadt fclose(input[1]); 630ae8d569bSderaadt /* 63148b8c3e3Sderaadt * if (jackpot) 63248b8c3e3Sderaadt * fprintf(stderr, "jackpot\n"); 633ae8d569bSderaadt */ 634ae8d569bSderaadt } 635ae8d569bSderaadt 63648b8c3e3Sderaadt /* shellsort CACM #201 */ 63726da422aStedu static void 63826da422aStedu sort(struct line *a, int n) 63948b8c3e3Sderaadt { 64048b8c3e3Sderaadt struct line *ai, *aim, w; 64148b8c3e3Sderaadt int j, m = 0, k; 642ae8d569bSderaadt 643ae8d569bSderaadt if (n == 0) 644ae8d569bSderaadt return; 645ae8d569bSderaadt for (j = 1; j <= n; j *= 2) 646ae8d569bSderaadt m = 2 * j - 1; 647ae8d569bSderaadt for (m /= 2; m != 0; m /= 2) { 648ae8d569bSderaadt k = n - m; 649ae8d569bSderaadt for (j = 1; j <= k; j++) { 650ae8d569bSderaadt for (ai = &a[j]; ai > a; ai -= m) { 651ae8d569bSderaadt aim = &ai[m]; 652ae8d569bSderaadt if (aim < ai) 653ae8d569bSderaadt break; /* wraparound */ 654ae8d569bSderaadt if (aim->value > ai[0].value || 65526da422aStedu (aim->value == ai[0].value && 65626da422aStedu aim->serial > ai[0].serial)) 657ae8d569bSderaadt break; 658ae8d569bSderaadt w.value = ai[0].value; 659ae8d569bSderaadt ai[0].value = aim->value; 660ae8d569bSderaadt aim->value = w.value; 661ae8d569bSderaadt w.serial = ai[0].serial; 662ae8d569bSderaadt ai[0].serial = aim->serial; 663ae8d569bSderaadt aim->serial = w.serial; 664ae8d569bSderaadt } 665ae8d569bSderaadt } 666ae8d569bSderaadt } 667ae8d569bSderaadt } 668ae8d569bSderaadt 66926da422aStedu static void 67026da422aStedu unsort(struct line *f, int l, int *b) 671ae8d569bSderaadt { 67248b8c3e3Sderaadt int *a, i; 67326da422aStedu 67449dffe13Smillert a = emalloc((l + 1) * sizeof(int)); 675ae8d569bSderaadt for (i = 1; i <= l; i++) 676ae8d569bSderaadt a[f[i].serial] = f[i].value; 677ae8d569bSderaadt for (i = 1; i <= l; i++) 678ae8d569bSderaadt b[i] = a[i]; 67926da422aStedu free(a); 680ae8d569bSderaadt } 681ae8d569bSderaadt 68226da422aStedu static int 68326da422aStedu skipline(int f) 684ae8d569bSderaadt { 68526da422aStedu int i, c; 686ae8d569bSderaadt 687ae8d569bSderaadt for (i = 1; (c = getc(input[f])) != '\n'; i++) 688ae8d569bSderaadt if (c < 0) 689ae8d569bSderaadt return (i); 690ae8d569bSderaadt return (i); 691ae8d569bSderaadt } 692ae8d569bSderaadt 69326da422aStedu static void 69426da422aStedu output(void) 695ae8d569bSderaadt { 69648b8c3e3Sderaadt int m, i0, i1, j0, j1; 69748b8c3e3Sderaadt 698ae8d569bSderaadt input[0] = fopen(file1, "r"); 699ae8d569bSderaadt input[1] = fopen(file2, "r"); 700ae8d569bSderaadt m = len[0]; 701ae8d569bSderaadt J[0] = 0; 702ae8d569bSderaadt J[m + 1] = len[1] + 1; 70326da422aStedu if (opt != D_EDIT) { 70426da422aStedu for (i0 = 1; i0 <= m; i0 = i1 + 1) { 70526da422aStedu while (i0 <= m && J[i0] == J[i0 - 1] + 1) 70626da422aStedu i0++; 707ae8d569bSderaadt j0 = J[i0 - 1] + 1; 708ae8d569bSderaadt i1 = i0 - 1; 70926da422aStedu while (i1 < m && J[i1 + 1] == 0) 71026da422aStedu i1++; 711ae8d569bSderaadt j1 = J[i1 + 1] - 1; 712ae8d569bSderaadt J[i1] = j1; 713ae8d569bSderaadt change(i0, i1, j0, j1); 71426da422aStedu } 71526da422aStedu } else { 71626da422aStedu for (i0 = m; i0 >= 1; i0 = i1 - 1) { 71726da422aStedu while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0) 71826da422aStedu i0--; 719ae8d569bSderaadt j0 = J[i0 + 1] - 1; 720ae8d569bSderaadt i1 = i0 + 1; 72126da422aStedu while (i1 > 1 && J[i1 - 1] == 0) 72226da422aStedu i1--; 723ae8d569bSderaadt j1 = J[i1 - 1] + 1; 724ae8d569bSderaadt J[i1] = j1; 725ae8d569bSderaadt change(i1, i0, j1, j0); 726ae8d569bSderaadt } 72726da422aStedu } 728ae8d569bSderaadt if (m == 0) 729ae8d569bSderaadt change(1, 0, 1, len[1]); 730ae8d569bSderaadt if (opt == D_IFDEF) { 731ae8d569bSderaadt for (;;) { 732ae8d569bSderaadt #define c i0 733ae8d569bSderaadt c = getc(input[0]); 734ae8d569bSderaadt if (c < 0) 735ae8d569bSderaadt return; 736ae8d569bSderaadt putchar(c); 737ae8d569bSderaadt } 738ae8d569bSderaadt #undef c 739ae8d569bSderaadt } 7409de32c1bSmillert if (anychange != 0) { 7419de32c1bSmillert if (opt == D_CONTEXT) 742ae8d569bSderaadt dump_context_vec(); 7439de32c1bSmillert else if (opt == D_UNIFIED) 7449de32c1bSmillert dump_unified_vec(); 7459de32c1bSmillert } 746ae8d569bSderaadt } 747ae8d569bSderaadt 748ae8d569bSderaadt /* 749ae8d569bSderaadt * The following struct is used to record change information when 750ae8d569bSderaadt * doing a "context" diff. (see routine "change" to understand the 751ae8d569bSderaadt * highly mneumonic field names) 752ae8d569bSderaadt */ 753ae8d569bSderaadt struct context_vec { 754ae8d569bSderaadt int a; /* start line in old file */ 755ae8d569bSderaadt int b; /* end line in old file */ 756ae8d569bSderaadt int c; /* start line in new file */ 757ae8d569bSderaadt int d; /* end line in new file */ 758ae8d569bSderaadt }; 759ae8d569bSderaadt 76026da422aStedu struct context_vec *context_vec_start, *context_vec_end, *context_vec_ptr; 761ae8d569bSderaadt 762ae8d569bSderaadt #define MAX_CONTEXT 128 763ae8d569bSderaadt 76426da422aStedu /* 76526da422aStedu * indicate that there is a difference between lines a and b of the from file 76626da422aStedu * to get to lines c to d of the to file. If a is greater then b then there 76726da422aStedu * are no lines in the from file involved and this means that there were 76826da422aStedu * lines appended (beginning at b). If c is greater than d then there are 76926da422aStedu * lines missing from the to file. 770ae8d569bSderaadt */ 77126da422aStedu static void 77226da422aStedu change(int a, int b, int c, int d) 773ae8d569bSderaadt { 774ae8d569bSderaadt struct stat stbuf; 775ae8d569bSderaadt 776ae8d569bSderaadt if (opt != D_IFDEF && a > b && c > d) 777ae8d569bSderaadt return; 778ae8d569bSderaadt if (anychange == 0) { 779ae8d569bSderaadt anychange = 1; 7809de32c1bSmillert if (opt == D_CONTEXT || opt == D_UNIFIED) { 781ae8d569bSderaadt stat(file1, &stbuf); 7829de32c1bSmillert printf("%s %s %s", opt == D_CONTEXT ? "***" : "---", 7839de32c1bSmillert file1, ctime(&stbuf.st_mtime)); 784ae8d569bSderaadt stat(file2, &stbuf); 7859de32c1bSmillert printf("%s %s %s", opt == D_CONTEXT ? "---" : "+++", 7869de32c1bSmillert file2, ctime(&stbuf.st_mtime)); 78749dffe13Smillert context_vec_start = emalloc(MAX_CONTEXT * 788ae8d569bSderaadt sizeof(struct context_vec)); 789ae8d569bSderaadt context_vec_end = context_vec_start + MAX_CONTEXT; 790ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 791ae8d569bSderaadt } 792ae8d569bSderaadt } 7939de32c1bSmillert if (opt == D_CONTEXT || opt == D_UNIFIED) { 794ae8d569bSderaadt /* 795*90f56ad8Smillert * If this new change is within 'context' lines of 796ae8d569bSderaadt * the previous change, just add it to the change 797ae8d569bSderaadt * record. If the record is full or if this 798ae8d569bSderaadt * change is more than 'context' lines from the previous 799ae8d569bSderaadt * change, dump the record, reset it & add the new change. 800ae8d569bSderaadt */ 801ae8d569bSderaadt if (context_vec_ptr >= context_vec_end || 802ae8d569bSderaadt (context_vec_ptr >= context_vec_start && 803ae8d569bSderaadt a > (context_vec_ptr->b + 2 * context) && 8049de32c1bSmillert c > (context_vec_ptr->d + 2 * context))) { 8059de32c1bSmillert if (opt == D_CONTEXT) 806ae8d569bSderaadt dump_context_vec(); 8079de32c1bSmillert else 8089de32c1bSmillert dump_unified_vec(); 8099de32c1bSmillert } 810ae8d569bSderaadt context_vec_ptr++; 811ae8d569bSderaadt context_vec_ptr->a = a; 812ae8d569bSderaadt context_vec_ptr->b = b; 813ae8d569bSderaadt context_vec_ptr->c = c; 814ae8d569bSderaadt context_vec_ptr->d = d; 815ae8d569bSderaadt return; 816ae8d569bSderaadt } 817ae8d569bSderaadt switch (opt) { 818ae8d569bSderaadt 819ae8d569bSderaadt case D_NORMAL: 820ae8d569bSderaadt case D_EDIT: 821ae8d569bSderaadt range(a, b, ","); 822ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 823ae8d569bSderaadt if (opt == D_NORMAL) 824ae8d569bSderaadt range(c, d, ","); 825ae8d569bSderaadt putchar('\n'); 826ae8d569bSderaadt break; 827ae8d569bSderaadt case D_REVERSE: 828ae8d569bSderaadt putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 829ae8d569bSderaadt range(a, b, " "); 830ae8d569bSderaadt putchar('\n'); 831ae8d569bSderaadt break; 832ae8d569bSderaadt case D_NREVERSE: 833ae8d569bSderaadt if (a > b) 834ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 835ae8d569bSderaadt else { 836ae8d569bSderaadt printf("d%d %d\n", a, b - a + 1); 837ae8d569bSderaadt if (!(c > d)) 838ae8d569bSderaadt /* add changed lines */ 839ae8d569bSderaadt printf("a%d %d\n", b, d - c + 1); 840ae8d569bSderaadt } 841ae8d569bSderaadt break; 842ae8d569bSderaadt } 843ae8d569bSderaadt if (opt == D_NORMAL || opt == D_IFDEF) { 844ae8d569bSderaadt fetch(ixold, a, b, input[0], "< ", 1); 845ae8d569bSderaadt if (a <= b && c <= d && opt == D_NORMAL) 846ae8d569bSderaadt prints("---\n"); 847ae8d569bSderaadt } 848ae8d569bSderaadt fetch(ixnew, c, d, input[1], opt == D_NORMAL ? "> " : "", 0); 849ae8d569bSderaadt if ((opt == D_EDIT || opt == D_REVERSE) && c <= d) 850ae8d569bSderaadt prints(".\n"); 851ae8d569bSderaadt if (inifdef) { 852*90f56ad8Smillert fprintf(stdout, "#endif /* %s */\n", ifdefname); 853ae8d569bSderaadt inifdef = 0; 854ae8d569bSderaadt } 855ae8d569bSderaadt } 856ae8d569bSderaadt 85726da422aStedu static void 85826da422aStedu range(int a, int b, char *separator) 859ae8d569bSderaadt { 860ae8d569bSderaadt printf("%d", a > b ? b : a); 86148b8c3e3Sderaadt if (a < b) 862ae8d569bSderaadt printf("%s%d", separator, b); 863ae8d569bSderaadt } 864ae8d569bSderaadt 86526da422aStedu static void 86626da422aStedu fetch(long *f, int a, int b, FILE *lb, char *s, int oldfile) 867ae8d569bSderaadt { 86848b8c3e3Sderaadt int i, j, c, col, nc; 869ae8d569bSderaadt 870ae8d569bSderaadt /* 871ae8d569bSderaadt * When doing #ifdef's, copy down to current line 872ae8d569bSderaadt * if this is the first file, so that stuff makes it to output. 873ae8d569bSderaadt */ 874ae8d569bSderaadt if (opt == D_IFDEF && oldfile) { 875ae8d569bSderaadt long curpos = ftell(lb); 876ae8d569bSderaadt /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 877ae8d569bSderaadt nc = f[a > b ? b : a - 1] - curpos; 878ae8d569bSderaadt for (i = 0; i < nc; i++) 879ae8d569bSderaadt putchar(getc(lb)); 880ae8d569bSderaadt } 881ae8d569bSderaadt if (a > b) 882ae8d569bSderaadt return; 883ae8d569bSderaadt if (opt == D_IFDEF) { 884*90f56ad8Smillert if (inifdef) { 88548b8c3e3Sderaadt fprintf(stdout, "#else /* %s%s */\n", 886*90f56ad8Smillert oldfile == 1 ? "!" : "", ifdefname); 88726da422aStedu } else { 888*90f56ad8Smillert if (oldfile) 889*90f56ad8Smillert fprintf(stdout, "#ifndef %s\n", ifdefname); 890*90f56ad8Smillert else 891*90f56ad8Smillert fprintf(stdout, "#ifdef %s\n", ifdefname); 892ae8d569bSderaadt } 893ae8d569bSderaadt inifdef = 1 + oldfile; 894ae8d569bSderaadt } 895ae8d569bSderaadt for (i = a; i <= b; i++) { 89691cf91eeSderaadt fseek(lb, f[i - 1], SEEK_SET); 897ae8d569bSderaadt nc = f[i] - f[i - 1]; 898ae8d569bSderaadt if (opt != D_IFDEF) 899ae8d569bSderaadt prints(s); 900ae8d569bSderaadt col = 0; 901ae8d569bSderaadt for (j = 0; j < nc; j++) { 902ae8d569bSderaadt c = getc(lb); 903ae8d569bSderaadt if (c == '\t' && tflag) 904ae8d569bSderaadt do 905ae8d569bSderaadt putchar(' '); 9067d9f164dStedu while (++col & 7); 907ae8d569bSderaadt else { 908ae8d569bSderaadt putchar(c); 909ae8d569bSderaadt col++; 910ae8d569bSderaadt } 911ae8d569bSderaadt } 912ae8d569bSderaadt } 913ae8d569bSderaadt } 914ae8d569bSderaadt 915ae8d569bSderaadt #define POW2 /* define only if HALFLONG is 2**n */ 916ae8d569bSderaadt #define HALFLONG 16 917ae8d569bSderaadt #define low(x) (x&((1L<<HALFLONG)-1)) 918ae8d569bSderaadt #define high(x) (x>>HALFLONG) 919ae8d569bSderaadt 920ae8d569bSderaadt /* 921ae8d569bSderaadt * hashing has the effect of 922ae8d569bSderaadt * arranging line in 7-bit bytes and then 923ae8d569bSderaadt * summing 1-s complement in 16-bit hunks 924ae8d569bSderaadt */ 92526da422aStedu static int 92626da422aStedu readhash(FILE *f) 927ae8d569bSderaadt { 92848b8c3e3Sderaadt unsigned int shift; 92948b8c3e3Sderaadt int t, space; 93026da422aStedu long sum; 931ae8d569bSderaadt 932ae8d569bSderaadt sum = 1; 933ae8d569bSderaadt space = 0; 934ae8d569bSderaadt if (!bflag && !wflag) { 935ae8d569bSderaadt if (iflag) 936ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 937ae8d569bSderaadt if (t == -1) 938ae8d569bSderaadt return (0); 939ae8d569bSderaadt sum += (long)chrtran[t] << (shift 940ae8d569bSderaadt #ifdef POW2 941ae8d569bSderaadt &= HALFLONG - 1); 942ae8d569bSderaadt #else 943ae8d569bSderaadt %= HALFLONG); 944ae8d569bSderaadt #endif 945ae8d569bSderaadt } 946ae8d569bSderaadt else 947ae8d569bSderaadt for (shift = 0; (t = getc(f)) != '\n'; shift += 7) { 948ae8d569bSderaadt if (t == -1) 949ae8d569bSderaadt return (0); 950ae8d569bSderaadt sum += (long)t << (shift 951ae8d569bSderaadt #ifdef POW2 952ae8d569bSderaadt &= HALFLONG - 1); 953ae8d569bSderaadt #else 954ae8d569bSderaadt %= HALFLONG); 955ae8d569bSderaadt #endif 956ae8d569bSderaadt } 957ae8d569bSderaadt } else { 958ae8d569bSderaadt for (shift = 0;;) { 959ae8d569bSderaadt switch (t = getc(f)) { 960ae8d569bSderaadt case -1: 961ae8d569bSderaadt return (0); 962ae8d569bSderaadt case '\t': 963ae8d569bSderaadt case ' ': 964ae8d569bSderaadt space++; 965ae8d569bSderaadt continue; 966ae8d569bSderaadt default: 967ae8d569bSderaadt if (space && !wflag) { 968ae8d569bSderaadt shift += 7; 969ae8d569bSderaadt space = 0; 970ae8d569bSderaadt } 971ae8d569bSderaadt sum += (long)chrtran[t] << (shift 972ae8d569bSderaadt #ifdef POW2 973ae8d569bSderaadt &= HALFLONG - 1); 974ae8d569bSderaadt #else 975ae8d569bSderaadt %= HALFLONG); 976ae8d569bSderaadt #endif 977ae8d569bSderaadt shift += 7; 978ae8d569bSderaadt continue; 979ae8d569bSderaadt case '\n': 980ae8d569bSderaadt break; 981ae8d569bSderaadt } 982ae8d569bSderaadt break; 983ae8d569bSderaadt } 984ae8d569bSderaadt } 985ae8d569bSderaadt sum = low(sum) + high(sum); 986ae8d569bSderaadt return ((short) low(sum) + (short) high(sum)); 987ae8d569bSderaadt } 988ae8d569bSderaadt 98926da422aStedu static int 99026da422aStedu asciifile(FILE *f) 991ae8d569bSderaadt { 99248b8c3e3Sderaadt char buf[BUFSIZ], *cp; 99326da422aStedu int cnt; 994ae8d569bSderaadt 9958ae1ab09Sderaadt fseek(f, 0L, SEEK_SET); 996ae8d569bSderaadt cnt = fread(buf, 1, BUFSIZ, f); 997ae8d569bSderaadt cp = buf; 998ae8d569bSderaadt while (--cnt >= 0) 999ae8d569bSderaadt if (*cp++ & 0200) 1000ae8d569bSderaadt return (0); 1001ae8d569bSderaadt return (1); 1002ae8d569bSderaadt } 1003ae8d569bSderaadt 1004ae8d569bSderaadt /* dump accumulated "context" diff changes */ 100526da422aStedu static void 100626da422aStedu dump_context_vec(void) 1007ae8d569bSderaadt { 100848b8c3e3Sderaadt struct context_vec *cvp = context_vec_start; 100948b8c3e3Sderaadt int lowa, upb, lowc, upd, do_output; 101026da422aStedu int a, b, c, d; 101126da422aStedu char ch; 1012ae8d569bSderaadt 1013*90f56ad8Smillert if (context_vec_start > context_vec_ptr) 1014ae8d569bSderaadt return; 1015ae8d569bSderaadt 101626da422aStedu b = d = 0; /* gcc */ 1017ae8d569bSderaadt lowa = max(1, cvp->a - context); 1018ae8d569bSderaadt upb = min(len[0], context_vec_ptr->b + context); 1019ae8d569bSderaadt lowc = max(1, cvp->c - context); 1020ae8d569bSderaadt upd = min(len[1], context_vec_ptr->d + context); 1021ae8d569bSderaadt 1022ae8d569bSderaadt printf("***************\n*** "); 1023ae8d569bSderaadt range(lowa, upb, ","); 1024ae8d569bSderaadt printf(" ****\n"); 1025ae8d569bSderaadt 1026ae8d569bSderaadt /* 1027ae8d569bSderaadt * output changes to the "old" file. The first loop suppresses 1028ae8d569bSderaadt * output if there were no changes to the "old" file (we'll see 1029ae8d569bSderaadt * the "old" lines as context in the "new" list). 1030ae8d569bSderaadt */ 1031ae8d569bSderaadt do_output = 0; 1032ae8d569bSderaadt for (; cvp <= context_vec_ptr; cvp++) 1033ae8d569bSderaadt if (cvp->a <= cvp->b) { 1034ae8d569bSderaadt cvp = context_vec_start; 1035ae8d569bSderaadt do_output++; 1036ae8d569bSderaadt break; 1037ae8d569bSderaadt } 1038ae8d569bSderaadt if (do_output) { 1039ae8d569bSderaadt while (cvp <= context_vec_ptr) { 104026da422aStedu a = cvp->a; 104126da422aStedu b = cvp->b; 104226da422aStedu c = cvp->c; 104326da422aStedu d = cvp->d; 1044ae8d569bSderaadt 1045ae8d569bSderaadt if (a <= b && c <= d) 1046ae8d569bSderaadt ch = 'c'; 1047ae8d569bSderaadt else 1048ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1049ae8d569bSderaadt 1050ae8d569bSderaadt if (ch == 'a') 105126da422aStedu fetch(ixold, lowa, b, input[0], " ", 0); 1052ae8d569bSderaadt else { 105326da422aStedu fetch(ixold, lowa, a - 1, input[0], " ", 0); 105448b8c3e3Sderaadt fetch(ixold, a, b, input[0], 105548b8c3e3Sderaadt ch == 'c' ? "! " : "- ", 0); 1056ae8d569bSderaadt } 1057ae8d569bSderaadt lowa = b + 1; 1058ae8d569bSderaadt cvp++; 1059ae8d569bSderaadt } 106026da422aStedu fetch(ixold, b + 1, upb, input[0], " ", 0); 1061ae8d569bSderaadt } 1062ae8d569bSderaadt /* output changes to the "new" file */ 1063ae8d569bSderaadt printf("--- "); 1064ae8d569bSderaadt range(lowc, upd, ","); 1065ae8d569bSderaadt printf(" ----\n"); 1066ae8d569bSderaadt 1067ae8d569bSderaadt do_output = 0; 1068ae8d569bSderaadt for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 1069ae8d569bSderaadt if (cvp->c <= cvp->d) { 1070ae8d569bSderaadt cvp = context_vec_start; 1071ae8d569bSderaadt do_output++; 1072ae8d569bSderaadt break; 1073ae8d569bSderaadt } 1074ae8d569bSderaadt if (do_output) { 1075ae8d569bSderaadt while (cvp <= context_vec_ptr) { 107626da422aStedu a = cvp->a; 107726da422aStedu b = cvp->b; 107826da422aStedu c = cvp->c; 107926da422aStedu d = cvp->d; 1080ae8d569bSderaadt 1081ae8d569bSderaadt if (a <= b && c <= d) 1082ae8d569bSderaadt ch = 'c'; 1083ae8d569bSderaadt else 1084ae8d569bSderaadt ch = (a <= b) ? 'd' : 'a'; 1085ae8d569bSderaadt 1086ae8d569bSderaadt if (ch == 'd') 108726da422aStedu fetch(ixnew, lowc, d, input[1], " ", 0); 1088ae8d569bSderaadt else { 108926da422aStedu fetch(ixnew, lowc, c - 1, input[1], " ", 0); 109048b8c3e3Sderaadt fetch(ixnew, c, d, input[1], 109148b8c3e3Sderaadt ch == 'c' ? "! " : "+ ", 0); 1092ae8d569bSderaadt } 1093ae8d569bSderaadt lowc = d + 1; 1094ae8d569bSderaadt cvp++; 1095ae8d569bSderaadt } 109626da422aStedu fetch(ixnew, d + 1, upd, input[1], " ", 0); 1097ae8d569bSderaadt } 1098ae8d569bSderaadt context_vec_ptr = context_vec_start - 1; 1099ae8d569bSderaadt } 11009de32c1bSmillert 11019de32c1bSmillert /* dump accumulated "unified" diff changes */ 11029de32c1bSmillert static void 11039de32c1bSmillert dump_unified_vec(void) 11049de32c1bSmillert { 11059de32c1bSmillert struct context_vec *cvp = context_vec_start; 11069de32c1bSmillert int lowa, upb, lowc, upd; 11079de32c1bSmillert int a, b, c, d; 11089de32c1bSmillert char ch; 11099de32c1bSmillert 1110*90f56ad8Smillert if (context_vec_start > context_vec_ptr) 11119de32c1bSmillert return; 11129de32c1bSmillert 11139de32c1bSmillert b = d = 0; /* gcc */ 11149de32c1bSmillert lowa = max(1, cvp->a - context); 11159de32c1bSmillert upb = min(len[0], context_vec_ptr->b + context); 11169de32c1bSmillert lowc = max(1, cvp->c - context); 11179de32c1bSmillert upd = min(len[1], context_vec_ptr->d + context); 11189de32c1bSmillert 11199de32c1bSmillert printf("@@ -%d,%d +%d,%d @@\n", lowa, upb - lowa + 1, 11209de32c1bSmillert lowc, upd - lowc + 1); 11219de32c1bSmillert 11229de32c1bSmillert /* 11239de32c1bSmillert * Output changes in "unified" diff format--the old and new lines 11249de32c1bSmillert * are printed together. 11259de32c1bSmillert */ 11269de32c1bSmillert for (; cvp <= context_vec_ptr; cvp++) { 11279de32c1bSmillert a = cvp->a; 11289de32c1bSmillert b = cvp->b; 11299de32c1bSmillert c = cvp->c; 11309de32c1bSmillert d = cvp->d; 11319de32c1bSmillert 11329de32c1bSmillert /* 11339de32c1bSmillert * c: both new and old changes 11349de32c1bSmillert * d: only changes in the old file 11359de32c1bSmillert * a: only changes in the new file 11369de32c1bSmillert */ 11379de32c1bSmillert if (a <= b && c <= d) 11389de32c1bSmillert ch = 'c'; 11399de32c1bSmillert else 11409de32c1bSmillert ch = (a <= b) ? 'd' : 'a'; 11419de32c1bSmillert 11429de32c1bSmillert switch (ch) { 11439de32c1bSmillert case 'c': 11449de32c1bSmillert fetch(ixold, lowa, a - 1, input[0], " ", 0); 11459de32c1bSmillert fetch(ixold, a, b, input[0], "-", 0); 11469de32c1bSmillert fetch(ixnew, c, d, input[1], "+", 0); 11479de32c1bSmillert break; 11489de32c1bSmillert case 'd': 11499de32c1bSmillert fetch(ixold, lowa, a - 1, input[0], " ", 0); 11509de32c1bSmillert fetch(ixold, a, b, input[0], "-", 0); 11519de32c1bSmillert break; 11529de32c1bSmillert case 'a': 11539de32c1bSmillert fetch(ixnew, lowc, c - 1, input[1], " ", 0); 11549de32c1bSmillert fetch(ixnew, c, d, input[1], "+", 0); 11559de32c1bSmillert break; 11569de32c1bSmillert } 11579de32c1bSmillert lowa = b + 1; 11589de32c1bSmillert lowc = d + 1; 11599de32c1bSmillert } 11609de32c1bSmillert fetch(ixnew, d + 1, upd, input[1], " ", 0); 11619de32c1bSmillert 11629de32c1bSmillert context_vec_ptr = context_vec_start - 1; 11639de32c1bSmillert } 1164