1*3ad3fb45Sjoris /* $OpenBSD: diff_internals.c,v 1.1 2006/05/27 03:30:30 joris Exp $ */ 2*3ad3fb45Sjoris /* 3*3ad3fb45Sjoris * Copyright (C) Caldera International Inc. 2001-2002. 4*3ad3fb45Sjoris * All rights reserved. 5*3ad3fb45Sjoris * 6*3ad3fb45Sjoris * Redistribution and use in source and binary forms, with or without 7*3ad3fb45Sjoris * modification, are permitted provided that the following conditions 8*3ad3fb45Sjoris * are met: 9*3ad3fb45Sjoris * 1. Redistributions of source code and documentation must retain the above 10*3ad3fb45Sjoris * copyright notice, this list of conditions and the following disclaimer. 11*3ad3fb45Sjoris * 2. Redistributions in binary form must reproduce the above copyright 12*3ad3fb45Sjoris * notice, this list of conditions and the following disclaimer in the 13*3ad3fb45Sjoris * documentation and/or other materials provided with the distribution. 14*3ad3fb45Sjoris * 3. All advertising materials mentioning features or use of this software 15*3ad3fb45Sjoris * must display the following acknowledgement: 16*3ad3fb45Sjoris * This product includes software developed or owned by Caldera 17*3ad3fb45Sjoris * International, Inc. 18*3ad3fb45Sjoris * 4. Neither the name of Caldera International, Inc. nor the names of other 19*3ad3fb45Sjoris * contributors may be used to endorse or promote products derived from 20*3ad3fb45Sjoris * this software without specific prior written permission. 21*3ad3fb45Sjoris * 22*3ad3fb45Sjoris * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 23*3ad3fb45Sjoris * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 24*3ad3fb45Sjoris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25*3ad3fb45Sjoris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26*3ad3fb45Sjoris * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 27*3ad3fb45Sjoris * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28*3ad3fb45Sjoris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29*3ad3fb45Sjoris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30*3ad3fb45Sjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31*3ad3fb45Sjoris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32*3ad3fb45Sjoris * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*3ad3fb45Sjoris * POSSIBILITY OF SUCH DAMAGE. 34*3ad3fb45Sjoris */ 35*3ad3fb45Sjoris /*- 36*3ad3fb45Sjoris * Copyright (c) 1991, 1993 37*3ad3fb45Sjoris * The Regents of the University of California. All rights reserved. 38*3ad3fb45Sjoris * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved. 39*3ad3fb45Sjoris * 40*3ad3fb45Sjoris * Redistribution and use in source and binary forms, with or without 41*3ad3fb45Sjoris * modification, are permitted provided that the following conditions 42*3ad3fb45Sjoris * are met: 43*3ad3fb45Sjoris * 1. Redistributions of source code must retain the above copyright 44*3ad3fb45Sjoris * notice, this list of conditions and the following disclaimer. 45*3ad3fb45Sjoris * 2. Redistributions in binary form must reproduce the above copyright 46*3ad3fb45Sjoris * notice, this list of conditions and the following disclaimer in the 47*3ad3fb45Sjoris * documentation and/or other materials provided with the distribution. 48*3ad3fb45Sjoris * 3. Neither the name of the University nor the names of its contributors 49*3ad3fb45Sjoris * may be used to endorse or promote products derived from this software 50*3ad3fb45Sjoris * without specific prior written permission. 51*3ad3fb45Sjoris * 52*3ad3fb45Sjoris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53*3ad3fb45Sjoris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54*3ad3fb45Sjoris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55*3ad3fb45Sjoris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56*3ad3fb45Sjoris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57*3ad3fb45Sjoris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58*3ad3fb45Sjoris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59*3ad3fb45Sjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60*3ad3fb45Sjoris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61*3ad3fb45Sjoris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62*3ad3fb45Sjoris * SUCH DAMAGE. 63*3ad3fb45Sjoris * 64*3ad3fb45Sjoris * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 65*3ad3fb45Sjoris */ 66*3ad3fb45Sjoris /* 67*3ad3fb45Sjoris * Uses an algorithm due to Harold Stone, which finds 68*3ad3fb45Sjoris * a pair of longest identical subsequences in the two 69*3ad3fb45Sjoris * files. 70*3ad3fb45Sjoris * 71*3ad3fb45Sjoris * The major goal is to generate the match vector J. 72*3ad3fb45Sjoris * J[i] is the index of the line in file1 corresponding 73*3ad3fb45Sjoris * to line i file0. J[i] = 0 if there is no 74*3ad3fb45Sjoris * such line in file1. 75*3ad3fb45Sjoris * 76*3ad3fb45Sjoris * Lines are hashed so as to work in core. All potential 77*3ad3fb45Sjoris * matches are located by sorting the lines of each file 78*3ad3fb45Sjoris * on the hash (called ``value''). In particular, this 79*3ad3fb45Sjoris * collects the equivalence classes in file1 together. 80*3ad3fb45Sjoris * Subroutine equiv replaces the value of each line in 81*3ad3fb45Sjoris * file0 by the index of the first element of its 82*3ad3fb45Sjoris * matching equivalence in (the reordered) file1. 83*3ad3fb45Sjoris * To save space equiv squeezes file1 into a single 84*3ad3fb45Sjoris * array member in which the equivalence classes 85*3ad3fb45Sjoris * are simply concatenated, except that their first 86*3ad3fb45Sjoris * members are flagged by changing sign. 87*3ad3fb45Sjoris * 88*3ad3fb45Sjoris * Next the indices that point into member are unsorted into 89*3ad3fb45Sjoris * array class according to the original order of file0. 90*3ad3fb45Sjoris * 91*3ad3fb45Sjoris * The cleverness lies in routine stone. This marches 92*3ad3fb45Sjoris * through the lines of file0, developing a vector klist 93*3ad3fb45Sjoris * of "k-candidates". At step i a k-candidate is a matched 94*3ad3fb45Sjoris * pair of lines x,y (x in file0 y in file1) such that 95*3ad3fb45Sjoris * there is a common subsequence of length k 96*3ad3fb45Sjoris * between the first i lines of file0 and the first y 97*3ad3fb45Sjoris * lines of file1, but there is no such subsequence for 98*3ad3fb45Sjoris * any smaller y. x is the earliest possible mate to y 99*3ad3fb45Sjoris * that occurs in such a subsequence. 100*3ad3fb45Sjoris * 101*3ad3fb45Sjoris * Whenever any of the members of the equivalence class of 102*3ad3fb45Sjoris * lines in file1 matable to a line in file0 has serial number 103*3ad3fb45Sjoris * less than the y of some k-candidate, that k-candidate 104*3ad3fb45Sjoris * with the smallest such y is replaced. The new 105*3ad3fb45Sjoris * k-candidate is chained (via pred) to the current 106*3ad3fb45Sjoris * k-1 candidate so that the actual subsequence can 107*3ad3fb45Sjoris * be recovered. When a member has serial number greater 108*3ad3fb45Sjoris * that the y of all k-candidates, the klist is extended. 109*3ad3fb45Sjoris * At the end, the longest subsequence is pulled out 110*3ad3fb45Sjoris * and placed in the array J by unravel 111*3ad3fb45Sjoris * 112*3ad3fb45Sjoris * With J in hand, the matches there recorded are 113*3ad3fb45Sjoris * check'ed against reality to assure that no spurious 114*3ad3fb45Sjoris * matches have crept in due to hashing. If they have, 115*3ad3fb45Sjoris * they are broken, and "jackpot" is recorded--a harmless 116*3ad3fb45Sjoris * matter except that a true match for a spuriously 117*3ad3fb45Sjoris * mated line may now be unnecessarily reported as a change. 118*3ad3fb45Sjoris * 119*3ad3fb45Sjoris * Much of the complexity of the program comes simply 120*3ad3fb45Sjoris * from trying to minimize core utilization and 121*3ad3fb45Sjoris * maximize the range of doable problems by dynamically 122*3ad3fb45Sjoris * allocating what is needed and reusing what is not. 123*3ad3fb45Sjoris * The core requirements for problems larger than somewhat 124*3ad3fb45Sjoris * are (in words) 2*length(file0) + length(file1) + 125*3ad3fb45Sjoris * 3*(number of k-candidates installed), typically about 126*3ad3fb45Sjoris * 6n words for files of length n. 127*3ad3fb45Sjoris */ 128*3ad3fb45Sjoris 129*3ad3fb45Sjoris #include "includes.h" 130*3ad3fb45Sjoris 131*3ad3fb45Sjoris #include "buf.h" 132*3ad3fb45Sjoris #include "cvs.h" 133*3ad3fb45Sjoris #include "diff.h" 134*3ad3fb45Sjoris #include "log.h" 135*3ad3fb45Sjoris 136*3ad3fb45Sjoris #include "xmalloc.h" 137*3ad3fb45Sjoris 138*3ad3fb45Sjoris struct cand { 139*3ad3fb45Sjoris int x; 140*3ad3fb45Sjoris int y; 141*3ad3fb45Sjoris int pred; 142*3ad3fb45Sjoris } cand; 143*3ad3fb45Sjoris 144*3ad3fb45Sjoris struct line { 145*3ad3fb45Sjoris int serial; 146*3ad3fb45Sjoris int value; 147*3ad3fb45Sjoris } *file[2]; 148*3ad3fb45Sjoris 149*3ad3fb45Sjoris /* 150*3ad3fb45Sjoris * The following struct is used to record change in formation when 151*3ad3fb45Sjoris * doing a "context" or "unified" diff. (see routine "change" to 152*3ad3fb45Sjoris * understand the highly mnemonic field names) 153*3ad3fb45Sjoris */ 154*3ad3fb45Sjoris struct context_vec { 155*3ad3fb45Sjoris int a; /* start line in old file */ 156*3ad3fb45Sjoris int b; /* end line in old file */ 157*3ad3fb45Sjoris int c; /* start line in new file */ 158*3ad3fb45Sjoris int d; /* end line in new file */ 159*3ad3fb45Sjoris }; 160*3ad3fb45Sjoris 161*3ad3fb45Sjoris struct diff_arg { 162*3ad3fb45Sjoris char *rev1; 163*3ad3fb45Sjoris char *rev2; 164*3ad3fb45Sjoris char *date1; 165*3ad3fb45Sjoris char *date2; 166*3ad3fb45Sjoris }; 167*3ad3fb45Sjoris 168*3ad3fb45Sjoris static void output(FILE *, FILE *); 169*3ad3fb45Sjoris static void check(FILE *, FILE *); 170*3ad3fb45Sjoris static void range(int, int, char *); 171*3ad3fb45Sjoris static void uni_range(int, int); 172*3ad3fb45Sjoris static void dump_context_vec(FILE *, FILE *); 173*3ad3fb45Sjoris static void dump_unified_vec(FILE *, FILE *); 174*3ad3fb45Sjoris static int prepare(int, FILE *, off_t); 175*3ad3fb45Sjoris static void prune(void); 176*3ad3fb45Sjoris static void equiv(struct line *, int, struct line *, int, int *); 177*3ad3fb45Sjoris static void unravel(int); 178*3ad3fb45Sjoris static void unsort(struct line *, int, int *); 179*3ad3fb45Sjoris static void change(FILE *, FILE *, int, int, int, int); 180*3ad3fb45Sjoris static void sort(struct line *, int); 181*3ad3fb45Sjoris static int ignoreline(char *); 182*3ad3fb45Sjoris static int asciifile(FILE *); 183*3ad3fb45Sjoris static void fetch(long *, int, int, FILE *, int, int); 184*3ad3fb45Sjoris static int newcand(int, int, int); 185*3ad3fb45Sjoris static int search(int *, int, int); 186*3ad3fb45Sjoris static int skipline(FILE *); 187*3ad3fb45Sjoris static int isqrt(int); 188*3ad3fb45Sjoris static int stone(int *, int, int *, int *); 189*3ad3fb45Sjoris static int readhash(FILE *); 190*3ad3fb45Sjoris static int files_differ(FILE *, FILE *); 191*3ad3fb45Sjoris static char *match_function(const long *, int, FILE *); 192*3ad3fb45Sjoris static char *preadline(int, size_t, off_t); 193*3ad3fb45Sjoris 194*3ad3fb45Sjoris static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; 195*3ad3fb45Sjoris static int context = 3; 196*3ad3fb45Sjoris int diff_format = D_NORMAL; 197*3ad3fb45Sjoris char *diff_file = NULL; 198*3ad3fb45Sjoris RCSNUM *diff_rev1 = NULL; 199*3ad3fb45Sjoris RCSNUM *diff_rev2 = NULL; 200*3ad3fb45Sjoris char diffargs[128]; 201*3ad3fb45Sjoris static struct stat stb1, stb2; 202*3ad3fb45Sjoris static char *ifdefname, *ignore_pats; 203*3ad3fb45Sjoris regex_t ignore_re; 204*3ad3fb45Sjoris 205*3ad3fb45Sjoris static int *J; /* will be overlaid on class */ 206*3ad3fb45Sjoris static int *class; /* will be overlaid on file[0] */ 207*3ad3fb45Sjoris static int *klist; /* will be overlaid on file[0] after class */ 208*3ad3fb45Sjoris static int *member; /* will be overlaid on file[1] */ 209*3ad3fb45Sjoris static int clen; 210*3ad3fb45Sjoris static int inifdef; /* whether or not we are in a #ifdef block */ 211*3ad3fb45Sjoris static int diff_len[2]; 212*3ad3fb45Sjoris static int pref, suff; /* length of prefix and suffix */ 213*3ad3fb45Sjoris static int slen[2]; 214*3ad3fb45Sjoris static int anychange; 215*3ad3fb45Sjoris static long *ixnew; /* will be overlaid on file[1] */ 216*3ad3fb45Sjoris static long *ixold; /* will be overlaid on klist */ 217*3ad3fb45Sjoris static struct cand *clist; /* merely a free storage pot for candidates */ 218*3ad3fb45Sjoris static int clistlen; /* the length of clist */ 219*3ad3fb45Sjoris static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 220*3ad3fb45Sjoris static u_char *chrtran; /* translation table for case-folding */ 221*3ad3fb45Sjoris static struct context_vec *context_vec_start; 222*3ad3fb45Sjoris static struct context_vec *context_vec_end; 223*3ad3fb45Sjoris static struct context_vec *context_vec_ptr; 224*3ad3fb45Sjoris 225*3ad3fb45Sjoris #define FUNCTION_CONTEXT_SIZE 41 226*3ad3fb45Sjoris static char lastbuf[FUNCTION_CONTEXT_SIZE]; 227*3ad3fb45Sjoris static int lastline; 228*3ad3fb45Sjoris static int lastmatchline; 229*3ad3fb45Sjoris BUF *diffbuf = NULL; 230*3ad3fb45Sjoris 231*3ad3fb45Sjoris /* 232*3ad3fb45Sjoris * chrtran points to one of 2 translation tables: cup2low if folding upper to 233*3ad3fb45Sjoris * lower case clow2low if not folding case 234*3ad3fb45Sjoris */ 235*3ad3fb45Sjoris u_char clow2low[256] = { 236*3ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 237*3ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 238*3ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 239*3ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 240*3ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 241*3ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 242*3ad3fb45Sjoris 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 243*3ad3fb45Sjoris 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 244*3ad3fb45Sjoris 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 245*3ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 246*3ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 247*3ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 248*3ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 249*3ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 250*3ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 251*3ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 252*3ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 253*3ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 254*3ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 255*3ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 256*3ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 257*3ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 258*3ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 259*3ad3fb45Sjoris 0xfd, 0xfe, 0xff 260*3ad3fb45Sjoris }; 261*3ad3fb45Sjoris 262*3ad3fb45Sjoris u_char cup2low[256] = { 263*3ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 264*3ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 265*3ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 266*3ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 267*3ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 268*3ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 269*3ad3fb45Sjoris 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 270*3ad3fb45Sjoris 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 271*3ad3fb45Sjoris 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 272*3ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 273*3ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 274*3ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 275*3ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 276*3ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 277*3ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 278*3ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 279*3ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 280*3ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 281*3ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 282*3ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 283*3ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 284*3ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 285*3ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 286*3ad3fb45Sjoris 0xfd, 0xfe, 0xff 287*3ad3fb45Sjoris }; 288*3ad3fb45Sjoris 289*3ad3fb45Sjoris int 290*3ad3fb45Sjoris cvs_diffreg(const char *file1, const char *file2, BUF *out) 291*3ad3fb45Sjoris { 292*3ad3fb45Sjoris FILE *f1, *f2; 293*3ad3fb45Sjoris int i, rval; 294*3ad3fb45Sjoris void *tmp; 295*3ad3fb45Sjoris 296*3ad3fb45Sjoris f1 = f2 = NULL; 297*3ad3fb45Sjoris rval = D_SAME; 298*3ad3fb45Sjoris anychange = 0; 299*3ad3fb45Sjoris lastline = 0; 300*3ad3fb45Sjoris lastmatchline = 0; 301*3ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 302*3ad3fb45Sjoris chrtran = (iflag ? cup2low : clow2low); 303*3ad3fb45Sjoris if (out != NULL) 304*3ad3fb45Sjoris diffbuf = out; 305*3ad3fb45Sjoris 306*3ad3fb45Sjoris f1 = fopen(file1, "r"); 307*3ad3fb45Sjoris if (f1 == NULL) { 308*3ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 309*3ad3fb45Sjoris goto closem; 310*3ad3fb45Sjoris } 311*3ad3fb45Sjoris 312*3ad3fb45Sjoris f2 = fopen(file2, "r"); 313*3ad3fb45Sjoris if (f2 == NULL) { 314*3ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 315*3ad3fb45Sjoris goto closem; 316*3ad3fb45Sjoris } 317*3ad3fb45Sjoris 318*3ad3fb45Sjoris if (stat(file1, &stb1) < 0) { 319*3ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 320*3ad3fb45Sjoris goto closem; 321*3ad3fb45Sjoris } 322*3ad3fb45Sjoris if (stat(file2, &stb2) < 0) { 323*3ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 324*3ad3fb45Sjoris goto closem; 325*3ad3fb45Sjoris } 326*3ad3fb45Sjoris switch (files_differ(f1, f2)) { 327*3ad3fb45Sjoris case 0: 328*3ad3fb45Sjoris goto closem; 329*3ad3fb45Sjoris case 1: 330*3ad3fb45Sjoris break; 331*3ad3fb45Sjoris default: 332*3ad3fb45Sjoris /* error */ 333*3ad3fb45Sjoris goto closem; 334*3ad3fb45Sjoris } 335*3ad3fb45Sjoris 336*3ad3fb45Sjoris if (!asciifile(f1) || !asciifile(f2)) { 337*3ad3fb45Sjoris rval = D_BINARY; 338*3ad3fb45Sjoris goto closem; 339*3ad3fb45Sjoris } 340*3ad3fb45Sjoris if (prepare(0, f1, stb1.st_size) < 0 || 341*3ad3fb45Sjoris prepare(1, f2, stb2.st_size) < 0) { 342*3ad3fb45Sjoris goto closem; 343*3ad3fb45Sjoris } 344*3ad3fb45Sjoris prune(); 345*3ad3fb45Sjoris sort(sfile[0], slen[0]); 346*3ad3fb45Sjoris sort(sfile[1], slen[1]); 347*3ad3fb45Sjoris 348*3ad3fb45Sjoris member = (int *)file[1]; 349*3ad3fb45Sjoris equiv(sfile[0], slen[0], sfile[1], slen[1], member); 350*3ad3fb45Sjoris tmp = xrealloc(member, slen[1] + 2, sizeof(*member)); 351*3ad3fb45Sjoris member = tmp; 352*3ad3fb45Sjoris 353*3ad3fb45Sjoris class = (int *)file[0]; 354*3ad3fb45Sjoris unsort(sfile[0], slen[0], class); 355*3ad3fb45Sjoris tmp = xrealloc(class, slen[0] + 2, sizeof(*class)); 356*3ad3fb45Sjoris class = tmp; 357*3ad3fb45Sjoris 358*3ad3fb45Sjoris klist = xcalloc(slen[0] + 2, sizeof(*klist)); 359*3ad3fb45Sjoris clen = 0; 360*3ad3fb45Sjoris clistlen = 100; 361*3ad3fb45Sjoris clist = xcalloc(clistlen, sizeof(*clist)); 362*3ad3fb45Sjoris 363*3ad3fb45Sjoris if ((i = stone(class, slen[0], member, klist)) < 0) 364*3ad3fb45Sjoris goto closem; 365*3ad3fb45Sjoris 366*3ad3fb45Sjoris xfree(member); 367*3ad3fb45Sjoris xfree(class); 368*3ad3fb45Sjoris 369*3ad3fb45Sjoris tmp = xrealloc(J, diff_len[0] + 2, sizeof(*J)); 370*3ad3fb45Sjoris J = tmp; 371*3ad3fb45Sjoris unravel(klist[i]); 372*3ad3fb45Sjoris xfree(clist); 373*3ad3fb45Sjoris xfree(klist); 374*3ad3fb45Sjoris 375*3ad3fb45Sjoris tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold)); 376*3ad3fb45Sjoris ixold = tmp; 377*3ad3fb45Sjoris 378*3ad3fb45Sjoris tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew)); 379*3ad3fb45Sjoris ixnew = tmp; 380*3ad3fb45Sjoris check(f1, f2); 381*3ad3fb45Sjoris output(f1, f2); 382*3ad3fb45Sjoris 383*3ad3fb45Sjoris closem: 384*3ad3fb45Sjoris if (anychange == 1) { 385*3ad3fb45Sjoris if (rval == D_SAME) 386*3ad3fb45Sjoris rval = D_DIFFER; 387*3ad3fb45Sjoris } 388*3ad3fb45Sjoris if (f1 != NULL) 389*3ad3fb45Sjoris fclose(f1); 390*3ad3fb45Sjoris if (f2 != NULL) 391*3ad3fb45Sjoris fclose(f2); 392*3ad3fb45Sjoris 393*3ad3fb45Sjoris return (rval); 394*3ad3fb45Sjoris } 395*3ad3fb45Sjoris 396*3ad3fb45Sjoris /* 397*3ad3fb45Sjoris * Check to see if the given files differ. 398*3ad3fb45Sjoris * Returns 0 if they are the same, 1 if different, and -1 on error. 399*3ad3fb45Sjoris * XXX - could use code from cmp(1) [faster] 400*3ad3fb45Sjoris */ 401*3ad3fb45Sjoris static int 402*3ad3fb45Sjoris files_differ(FILE *f1, FILE *f2) 403*3ad3fb45Sjoris { 404*3ad3fb45Sjoris char buf1[BUFSIZ], buf2[BUFSIZ]; 405*3ad3fb45Sjoris size_t i, j; 406*3ad3fb45Sjoris 407*3ad3fb45Sjoris if (stb1.st_size != stb2.st_size) 408*3ad3fb45Sjoris return (1); 409*3ad3fb45Sjoris for (;;) { 410*3ad3fb45Sjoris i = fread(buf1, (size_t)1, sizeof(buf1), f1); 411*3ad3fb45Sjoris j = fread(buf2, (size_t)1, sizeof(buf2), f2); 412*3ad3fb45Sjoris if (i != j) 413*3ad3fb45Sjoris return (1); 414*3ad3fb45Sjoris if (i == 0 && j == 0) { 415*3ad3fb45Sjoris if (ferror(f1) || ferror(f2)) 416*3ad3fb45Sjoris return (1); 417*3ad3fb45Sjoris return (0); 418*3ad3fb45Sjoris } 419*3ad3fb45Sjoris if (memcmp(buf1, buf2, i) != 0) 420*3ad3fb45Sjoris return (1); 421*3ad3fb45Sjoris } 422*3ad3fb45Sjoris } 423*3ad3fb45Sjoris 424*3ad3fb45Sjoris static int 425*3ad3fb45Sjoris prepare(int i, FILE *fd, off_t filesize) 426*3ad3fb45Sjoris { 427*3ad3fb45Sjoris void *tmp; 428*3ad3fb45Sjoris struct line *p; 429*3ad3fb45Sjoris int j, h; 430*3ad3fb45Sjoris size_t sz; 431*3ad3fb45Sjoris 432*3ad3fb45Sjoris rewind(fd); 433*3ad3fb45Sjoris 434*3ad3fb45Sjoris sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 435*3ad3fb45Sjoris if (sz < 100) 436*3ad3fb45Sjoris sz = 100; 437*3ad3fb45Sjoris 438*3ad3fb45Sjoris p = xcalloc(sz + 3, sizeof(*p)); 439*3ad3fb45Sjoris for (j = 0; (h = readhash(fd));) { 440*3ad3fb45Sjoris if (j == (int)sz) { 441*3ad3fb45Sjoris sz = sz * 3 / 2; 442*3ad3fb45Sjoris tmp = xrealloc(p, sz + 3, sizeof(*p)); 443*3ad3fb45Sjoris p = tmp; 444*3ad3fb45Sjoris } 445*3ad3fb45Sjoris p[++j].value = h; 446*3ad3fb45Sjoris } 447*3ad3fb45Sjoris diff_len[i] = j; 448*3ad3fb45Sjoris file[i] = p; 449*3ad3fb45Sjoris 450*3ad3fb45Sjoris return (0); 451*3ad3fb45Sjoris } 452*3ad3fb45Sjoris 453*3ad3fb45Sjoris static void 454*3ad3fb45Sjoris prune(void) 455*3ad3fb45Sjoris { 456*3ad3fb45Sjoris int i, j; 457*3ad3fb45Sjoris 458*3ad3fb45Sjoris for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 459*3ad3fb45Sjoris file[0][pref + 1].value == file[1][pref + 1].value; 460*3ad3fb45Sjoris pref++) 461*3ad3fb45Sjoris ; 462*3ad3fb45Sjoris for (suff = 0; 463*3ad3fb45Sjoris (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 464*3ad3fb45Sjoris (file[0][diff_len[0] - suff].value == 465*3ad3fb45Sjoris file[1][diff_len[1] - suff].value); 466*3ad3fb45Sjoris suff++) 467*3ad3fb45Sjoris ; 468*3ad3fb45Sjoris for (j = 0; j < 2; j++) { 469*3ad3fb45Sjoris sfile[j] = file[j] + pref; 470*3ad3fb45Sjoris slen[j] = diff_len[j] - pref - suff; 471*3ad3fb45Sjoris for (i = 0; i <= slen[j]; i++) 472*3ad3fb45Sjoris sfile[j][i].serial = i; 473*3ad3fb45Sjoris } 474*3ad3fb45Sjoris } 475*3ad3fb45Sjoris 476*3ad3fb45Sjoris static void 477*3ad3fb45Sjoris equiv(struct line *a, int n, struct line *b, int m, int *c) 478*3ad3fb45Sjoris { 479*3ad3fb45Sjoris int i, j; 480*3ad3fb45Sjoris 481*3ad3fb45Sjoris i = j = 1; 482*3ad3fb45Sjoris while (i <= n && j <= m) { 483*3ad3fb45Sjoris if (a[i].value < b[j].value) 484*3ad3fb45Sjoris a[i++].value = 0; 485*3ad3fb45Sjoris else if (a[i].value == b[j].value) 486*3ad3fb45Sjoris a[i++].value = j; 487*3ad3fb45Sjoris else 488*3ad3fb45Sjoris j++; 489*3ad3fb45Sjoris } 490*3ad3fb45Sjoris while (i <= n) 491*3ad3fb45Sjoris a[i++].value = 0; 492*3ad3fb45Sjoris b[m + 1].value = 0; 493*3ad3fb45Sjoris j = 0; 494*3ad3fb45Sjoris while (++j <= m) { 495*3ad3fb45Sjoris c[j] = -b[j].serial; 496*3ad3fb45Sjoris while (b[j + 1].value == b[j].value) { 497*3ad3fb45Sjoris j++; 498*3ad3fb45Sjoris c[j] = b[j].serial; 499*3ad3fb45Sjoris } 500*3ad3fb45Sjoris } 501*3ad3fb45Sjoris c[j] = -1; 502*3ad3fb45Sjoris } 503*3ad3fb45Sjoris 504*3ad3fb45Sjoris /* Code taken from ping.c */ 505*3ad3fb45Sjoris static int 506*3ad3fb45Sjoris isqrt(int n) 507*3ad3fb45Sjoris { 508*3ad3fb45Sjoris int y, x = 1; 509*3ad3fb45Sjoris 510*3ad3fb45Sjoris if (n == 0) 511*3ad3fb45Sjoris return (0); 512*3ad3fb45Sjoris 513*3ad3fb45Sjoris do { /* newton was a stinker */ 514*3ad3fb45Sjoris y = x; 515*3ad3fb45Sjoris x = n / x; 516*3ad3fb45Sjoris x += y; 517*3ad3fb45Sjoris x /= 2; 518*3ad3fb45Sjoris } while (x - y > 1 || x - y < -1); 519*3ad3fb45Sjoris 520*3ad3fb45Sjoris return (x); 521*3ad3fb45Sjoris } 522*3ad3fb45Sjoris 523*3ad3fb45Sjoris static int 524*3ad3fb45Sjoris stone(int *a, int n, int *b, int *c) 525*3ad3fb45Sjoris { 526*3ad3fb45Sjoris int ret; 527*3ad3fb45Sjoris int i, k, y, j, l; 528*3ad3fb45Sjoris int oldc, tc, oldl; 529*3ad3fb45Sjoris u_int numtries; 530*3ad3fb45Sjoris 531*3ad3fb45Sjoris /* XXX move the isqrt() out of the macro to avoid multiple calls */ 532*3ad3fb45Sjoris const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 533*3ad3fb45Sjoris 534*3ad3fb45Sjoris k = 0; 535*3ad3fb45Sjoris if ((ret = newcand(0, 0, 0)) < 0) 536*3ad3fb45Sjoris return (-1); 537*3ad3fb45Sjoris c[0] = ret; 538*3ad3fb45Sjoris for (i = 1; i <= n; i++) { 539*3ad3fb45Sjoris j = a[i]; 540*3ad3fb45Sjoris if (j == 0) 541*3ad3fb45Sjoris continue; 542*3ad3fb45Sjoris y = -b[j]; 543*3ad3fb45Sjoris oldl = 0; 544*3ad3fb45Sjoris oldc = c[0]; 545*3ad3fb45Sjoris numtries = 0; 546*3ad3fb45Sjoris do { 547*3ad3fb45Sjoris if (y <= clist[oldc].y) 548*3ad3fb45Sjoris continue; 549*3ad3fb45Sjoris l = search(c, k, y); 550*3ad3fb45Sjoris if (l != oldl + 1) 551*3ad3fb45Sjoris oldc = c[l - 1]; 552*3ad3fb45Sjoris if (l <= k) { 553*3ad3fb45Sjoris if (clist[c[l]].y <= y) 554*3ad3fb45Sjoris continue; 555*3ad3fb45Sjoris tc = c[l]; 556*3ad3fb45Sjoris if ((ret = newcand(i, y, oldc)) < 0) 557*3ad3fb45Sjoris return (-1); 558*3ad3fb45Sjoris c[l] = ret; 559*3ad3fb45Sjoris oldc = tc; 560*3ad3fb45Sjoris oldl = l; 561*3ad3fb45Sjoris numtries++; 562*3ad3fb45Sjoris } else { 563*3ad3fb45Sjoris if ((ret = newcand(i, y, oldc)) < 0) 564*3ad3fb45Sjoris return (-1); 565*3ad3fb45Sjoris c[l] = ret; 566*3ad3fb45Sjoris k++; 567*3ad3fb45Sjoris break; 568*3ad3fb45Sjoris } 569*3ad3fb45Sjoris } while ((y = b[++j]) > 0 && numtries < bound); 570*3ad3fb45Sjoris } 571*3ad3fb45Sjoris return (k); 572*3ad3fb45Sjoris } 573*3ad3fb45Sjoris 574*3ad3fb45Sjoris static int 575*3ad3fb45Sjoris newcand(int x, int y, int pred) 576*3ad3fb45Sjoris { 577*3ad3fb45Sjoris struct cand *q, *tmp; 578*3ad3fb45Sjoris int newclistlen; 579*3ad3fb45Sjoris 580*3ad3fb45Sjoris if (clen == clistlen) { 581*3ad3fb45Sjoris newclistlen = clistlen * 11 / 10; 582*3ad3fb45Sjoris tmp = xrealloc(clist, newclistlen, sizeof(*clist)); 583*3ad3fb45Sjoris clist = tmp; 584*3ad3fb45Sjoris clistlen = newclistlen; 585*3ad3fb45Sjoris } 586*3ad3fb45Sjoris q = clist + clen; 587*3ad3fb45Sjoris q->x = x; 588*3ad3fb45Sjoris q->y = y; 589*3ad3fb45Sjoris q->pred = pred; 590*3ad3fb45Sjoris return (clen++); 591*3ad3fb45Sjoris } 592*3ad3fb45Sjoris 593*3ad3fb45Sjoris static int 594*3ad3fb45Sjoris search(int *c, int k, int y) 595*3ad3fb45Sjoris { 596*3ad3fb45Sjoris int i, j, l, t; 597*3ad3fb45Sjoris 598*3ad3fb45Sjoris if (clist[c[k]].y < y) /* quick look for typical case */ 599*3ad3fb45Sjoris return (k + 1); 600*3ad3fb45Sjoris i = 0; 601*3ad3fb45Sjoris j = k + 1; 602*3ad3fb45Sjoris for (;;) { 603*3ad3fb45Sjoris l = (i + j) / 2; 604*3ad3fb45Sjoris if (l <= i) 605*3ad3fb45Sjoris break; 606*3ad3fb45Sjoris t = clist[c[l]].y; 607*3ad3fb45Sjoris if (t > y) 608*3ad3fb45Sjoris j = l; 609*3ad3fb45Sjoris else if (t < y) 610*3ad3fb45Sjoris i = l; 611*3ad3fb45Sjoris else 612*3ad3fb45Sjoris return (l); 613*3ad3fb45Sjoris } 614*3ad3fb45Sjoris return (l + 1); 615*3ad3fb45Sjoris } 616*3ad3fb45Sjoris 617*3ad3fb45Sjoris static void 618*3ad3fb45Sjoris unravel(int p) 619*3ad3fb45Sjoris { 620*3ad3fb45Sjoris struct cand *q; 621*3ad3fb45Sjoris int i; 622*3ad3fb45Sjoris 623*3ad3fb45Sjoris for (i = 0; i <= diff_len[0]; i++) 624*3ad3fb45Sjoris J[i] = i <= pref ? i : 625*3ad3fb45Sjoris i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 626*3ad3fb45Sjoris for (q = clist + p; q->y != 0; q = clist + q->pred) 627*3ad3fb45Sjoris J[q->x + pref] = q->y + pref; 628*3ad3fb45Sjoris } 629*3ad3fb45Sjoris 630*3ad3fb45Sjoris /* 631*3ad3fb45Sjoris * Check does double duty: 632*3ad3fb45Sjoris * 1. ferret out any fortuitous correspondences due 633*3ad3fb45Sjoris * to confounding by hashing (which result in "jackpot") 634*3ad3fb45Sjoris * 2. collect random access indexes to the two files 635*3ad3fb45Sjoris */ 636*3ad3fb45Sjoris static void 637*3ad3fb45Sjoris check(FILE *f1, FILE *f2) 638*3ad3fb45Sjoris { 639*3ad3fb45Sjoris int i, j, jackpot, c, d; 640*3ad3fb45Sjoris long ctold, ctnew; 641*3ad3fb45Sjoris 642*3ad3fb45Sjoris rewind(f1); 643*3ad3fb45Sjoris rewind(f2); 644*3ad3fb45Sjoris j = 1; 645*3ad3fb45Sjoris ixold[0] = ixnew[0] = 0; 646*3ad3fb45Sjoris jackpot = 0; 647*3ad3fb45Sjoris ctold = ctnew = 0; 648*3ad3fb45Sjoris for (i = 1; i <= diff_len[0]; i++) { 649*3ad3fb45Sjoris if (J[i] == 0) { 650*3ad3fb45Sjoris ixold[i] = ctold += skipline(f1); 651*3ad3fb45Sjoris continue; 652*3ad3fb45Sjoris } 653*3ad3fb45Sjoris while (j < J[i]) { 654*3ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 655*3ad3fb45Sjoris j++; 656*3ad3fb45Sjoris } 657*3ad3fb45Sjoris if (bflag == 1 || wflag == 1 || iflag == 1) { 658*3ad3fb45Sjoris for (;;) { 659*3ad3fb45Sjoris c = getc(f1); 660*3ad3fb45Sjoris d = getc(f2); 661*3ad3fb45Sjoris /* 662*3ad3fb45Sjoris * GNU diff ignores a missing newline 663*3ad3fb45Sjoris * in one file if bflag || wflag. 664*3ad3fb45Sjoris */ 665*3ad3fb45Sjoris if ((bflag == 1 || wflag == 1) && 666*3ad3fb45Sjoris ((c == EOF && d == '\n') || 667*3ad3fb45Sjoris (c == '\n' && d == EOF))) { 668*3ad3fb45Sjoris break; 669*3ad3fb45Sjoris } 670*3ad3fb45Sjoris ctold++; 671*3ad3fb45Sjoris ctnew++; 672*3ad3fb45Sjoris if (bflag == 1 && isspace(c) && isspace(d)) { 673*3ad3fb45Sjoris do { 674*3ad3fb45Sjoris if (c == '\n') 675*3ad3fb45Sjoris break; 676*3ad3fb45Sjoris ctold++; 677*3ad3fb45Sjoris } while (isspace(c = getc(f1))); 678*3ad3fb45Sjoris do { 679*3ad3fb45Sjoris if (d == '\n') 680*3ad3fb45Sjoris break; 681*3ad3fb45Sjoris ctnew++; 682*3ad3fb45Sjoris } while (isspace(d = getc(f2))); 683*3ad3fb45Sjoris } else if (wflag == 1) { 684*3ad3fb45Sjoris while (isspace(c) && c != '\n') { 685*3ad3fb45Sjoris c = getc(f1); 686*3ad3fb45Sjoris ctold++; 687*3ad3fb45Sjoris } 688*3ad3fb45Sjoris while (isspace(d) && d != '\n') { 689*3ad3fb45Sjoris d = getc(f2); 690*3ad3fb45Sjoris ctnew++; 691*3ad3fb45Sjoris } 692*3ad3fb45Sjoris } 693*3ad3fb45Sjoris if (chrtran[c] != chrtran[d]) { 694*3ad3fb45Sjoris jackpot++; 695*3ad3fb45Sjoris J[i] = 0; 696*3ad3fb45Sjoris if (c != '\n' && c != EOF) 697*3ad3fb45Sjoris ctold += skipline(f1); 698*3ad3fb45Sjoris if (d != '\n' && c != EOF) 699*3ad3fb45Sjoris ctnew += skipline(f2); 700*3ad3fb45Sjoris break; 701*3ad3fb45Sjoris } 702*3ad3fb45Sjoris if (c == '\n' || c == EOF) 703*3ad3fb45Sjoris break; 704*3ad3fb45Sjoris } 705*3ad3fb45Sjoris } else { 706*3ad3fb45Sjoris for (;;) { 707*3ad3fb45Sjoris ctold++; 708*3ad3fb45Sjoris ctnew++; 709*3ad3fb45Sjoris if ((c = getc(f1)) != (d = getc(f2))) { 710*3ad3fb45Sjoris /* jackpot++; */ 711*3ad3fb45Sjoris J[i] = 0; 712*3ad3fb45Sjoris if (c != '\n' && c != EOF) 713*3ad3fb45Sjoris ctold += skipline(f1); 714*3ad3fb45Sjoris if (d != '\n' && c != EOF) 715*3ad3fb45Sjoris ctnew += skipline(f2); 716*3ad3fb45Sjoris break; 717*3ad3fb45Sjoris } 718*3ad3fb45Sjoris if (c == '\n' || c == EOF) 719*3ad3fb45Sjoris break; 720*3ad3fb45Sjoris } 721*3ad3fb45Sjoris } 722*3ad3fb45Sjoris ixold[i] = ctold; 723*3ad3fb45Sjoris ixnew[j] = ctnew; 724*3ad3fb45Sjoris j++; 725*3ad3fb45Sjoris } 726*3ad3fb45Sjoris for (; j <= diff_len[1]; j++) 727*3ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 728*3ad3fb45Sjoris /* 729*3ad3fb45Sjoris * if (jackpot != 0) 730*3ad3fb45Sjoris * cvs_printf("jackpot\n"); 731*3ad3fb45Sjoris */ 732*3ad3fb45Sjoris } 733*3ad3fb45Sjoris 734*3ad3fb45Sjoris /* shellsort CACM #201 */ 735*3ad3fb45Sjoris static void 736*3ad3fb45Sjoris sort(struct line *a, int n) 737*3ad3fb45Sjoris { 738*3ad3fb45Sjoris struct line *ai, *aim, w; 739*3ad3fb45Sjoris int j, m = 0, k; 740*3ad3fb45Sjoris 741*3ad3fb45Sjoris if (n == 0) 742*3ad3fb45Sjoris return; 743*3ad3fb45Sjoris for (j = 1; j <= n; j *= 2) 744*3ad3fb45Sjoris m = 2 * j - 1; 745*3ad3fb45Sjoris for (m /= 2; m != 0; m /= 2) { 746*3ad3fb45Sjoris k = n - m; 747*3ad3fb45Sjoris for (j = 1; j <= k; j++) { 748*3ad3fb45Sjoris for (ai = &a[j]; ai > a; ai -= m) { 749*3ad3fb45Sjoris aim = &ai[m]; 750*3ad3fb45Sjoris if (aim < ai) 751*3ad3fb45Sjoris break; /* wraparound */ 752*3ad3fb45Sjoris if (aim->value > ai[0].value || 753*3ad3fb45Sjoris (aim->value == ai[0].value && 754*3ad3fb45Sjoris aim->serial > ai[0].serial)) 755*3ad3fb45Sjoris break; 756*3ad3fb45Sjoris w.value = ai[0].value; 757*3ad3fb45Sjoris ai[0].value = aim->value; 758*3ad3fb45Sjoris aim->value = w.value; 759*3ad3fb45Sjoris w.serial = ai[0].serial; 760*3ad3fb45Sjoris ai[0].serial = aim->serial; 761*3ad3fb45Sjoris aim->serial = w.serial; 762*3ad3fb45Sjoris } 763*3ad3fb45Sjoris } 764*3ad3fb45Sjoris } 765*3ad3fb45Sjoris } 766*3ad3fb45Sjoris 767*3ad3fb45Sjoris static void 768*3ad3fb45Sjoris unsort(struct line *f, int l, int *b) 769*3ad3fb45Sjoris { 770*3ad3fb45Sjoris int *a, i; 771*3ad3fb45Sjoris 772*3ad3fb45Sjoris a = xcalloc(l + 1, sizeof(*a)); 773*3ad3fb45Sjoris for (i = 1; i <= l; i++) 774*3ad3fb45Sjoris a[f[i].serial] = f[i].value; 775*3ad3fb45Sjoris for (i = 1; i <= l; i++) 776*3ad3fb45Sjoris b[i] = a[i]; 777*3ad3fb45Sjoris xfree(a); 778*3ad3fb45Sjoris } 779*3ad3fb45Sjoris 780*3ad3fb45Sjoris static int 781*3ad3fb45Sjoris skipline(FILE *f) 782*3ad3fb45Sjoris { 783*3ad3fb45Sjoris int i, c; 784*3ad3fb45Sjoris 785*3ad3fb45Sjoris for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 786*3ad3fb45Sjoris continue; 787*3ad3fb45Sjoris return (i); 788*3ad3fb45Sjoris } 789*3ad3fb45Sjoris 790*3ad3fb45Sjoris static void 791*3ad3fb45Sjoris output(FILE *f1, FILE *f2) 792*3ad3fb45Sjoris { 793*3ad3fb45Sjoris int m, i0, i1, j0, j1; 794*3ad3fb45Sjoris 795*3ad3fb45Sjoris rewind(f1); 796*3ad3fb45Sjoris rewind(f2); 797*3ad3fb45Sjoris m = diff_len[0]; 798*3ad3fb45Sjoris J[0] = 0; 799*3ad3fb45Sjoris J[m + 1] = diff_len[1] + 1; 800*3ad3fb45Sjoris for (i0 = 1; i0 <= m; i0 = i1 + 1) { 801*3ad3fb45Sjoris while (i0 <= m && J[i0] == J[i0 - 1] + 1) 802*3ad3fb45Sjoris i0++; 803*3ad3fb45Sjoris j0 = J[i0 - 1] + 1; 804*3ad3fb45Sjoris i1 = i0 - 1; 805*3ad3fb45Sjoris while (i1 < m && J[i1 + 1] == 0) 806*3ad3fb45Sjoris i1++; 807*3ad3fb45Sjoris j1 = J[i1 + 1] - 1; 808*3ad3fb45Sjoris J[i1] = j1; 809*3ad3fb45Sjoris change(f1, f2, i0, i1, j0, j1); 810*3ad3fb45Sjoris } 811*3ad3fb45Sjoris if (m == 0) 812*3ad3fb45Sjoris change(f1, f2, 1, 0, 1, diff_len[1]); 813*3ad3fb45Sjoris if (diff_format == D_IFDEF) { 814*3ad3fb45Sjoris for (;;) { 815*3ad3fb45Sjoris #define c i0 816*3ad3fb45Sjoris if ((c = getc(f1)) == EOF) 817*3ad3fb45Sjoris return; 818*3ad3fb45Sjoris diff_output("%c", c); 819*3ad3fb45Sjoris } 820*3ad3fb45Sjoris #undef c 821*3ad3fb45Sjoris } 822*3ad3fb45Sjoris if (anychange != 0) { 823*3ad3fb45Sjoris if (diff_format == D_CONTEXT) 824*3ad3fb45Sjoris dump_context_vec(f1, f2); 825*3ad3fb45Sjoris else if (diff_format == D_UNIFIED) 826*3ad3fb45Sjoris dump_unified_vec(f1, f2); 827*3ad3fb45Sjoris } 828*3ad3fb45Sjoris } 829*3ad3fb45Sjoris 830*3ad3fb45Sjoris static __inline void 831*3ad3fb45Sjoris range(int a, int b, char *separator) 832*3ad3fb45Sjoris { 833*3ad3fb45Sjoris diff_output("%d", a > b ? b : a); 834*3ad3fb45Sjoris if (a < b) 835*3ad3fb45Sjoris diff_output("%s%d", separator, b); 836*3ad3fb45Sjoris } 837*3ad3fb45Sjoris 838*3ad3fb45Sjoris static __inline void 839*3ad3fb45Sjoris uni_range(int a, int b) 840*3ad3fb45Sjoris { 841*3ad3fb45Sjoris if (a < b) 842*3ad3fb45Sjoris diff_output("%d,%d", a, b - a + 1); 843*3ad3fb45Sjoris else if (a == b) 844*3ad3fb45Sjoris diff_output("%d", b); 845*3ad3fb45Sjoris else 846*3ad3fb45Sjoris diff_output("%d,0", b); 847*3ad3fb45Sjoris } 848*3ad3fb45Sjoris 849*3ad3fb45Sjoris static char * 850*3ad3fb45Sjoris preadline(int fd, size_t rlen, off_t off) 851*3ad3fb45Sjoris { 852*3ad3fb45Sjoris char *line; 853*3ad3fb45Sjoris ssize_t nr; 854*3ad3fb45Sjoris 855*3ad3fb45Sjoris line = xmalloc(rlen + 1); 856*3ad3fb45Sjoris if ((nr = pread(fd, line, rlen, off)) < 0) { 857*3ad3fb45Sjoris cvs_log(LP_ERR, "preadline failed"); 858*3ad3fb45Sjoris return (NULL); 859*3ad3fb45Sjoris } 860*3ad3fb45Sjoris line[nr] = '\0'; 861*3ad3fb45Sjoris return (line); 862*3ad3fb45Sjoris } 863*3ad3fb45Sjoris 864*3ad3fb45Sjoris static int 865*3ad3fb45Sjoris ignoreline(char *line) 866*3ad3fb45Sjoris { 867*3ad3fb45Sjoris int ret; 868*3ad3fb45Sjoris 869*3ad3fb45Sjoris ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); 870*3ad3fb45Sjoris xfree(line); 871*3ad3fb45Sjoris return (ret == 0); /* if it matched, it should be ignored. */ 872*3ad3fb45Sjoris } 873*3ad3fb45Sjoris 874*3ad3fb45Sjoris /* 875*3ad3fb45Sjoris * Indicate that there is a difference between lines a and b of the from file 876*3ad3fb45Sjoris * to get to lines c to d of the to file. If a is greater then b then there 877*3ad3fb45Sjoris * are no lines in the from file involved and this means that there were 878*3ad3fb45Sjoris * lines appended (beginning at b). If c is greater than d then there are 879*3ad3fb45Sjoris * lines missing from the to file. 880*3ad3fb45Sjoris */ 881*3ad3fb45Sjoris static void 882*3ad3fb45Sjoris change(FILE *f1, FILE *f2, int a, int b, int c, int d) 883*3ad3fb45Sjoris { 884*3ad3fb45Sjoris int i; 885*3ad3fb45Sjoris static size_t max_context = 64; 886*3ad3fb45Sjoris char buf[64]; 887*3ad3fb45Sjoris struct tm *t; 888*3ad3fb45Sjoris 889*3ad3fb45Sjoris if (diff_format != D_IFDEF && a > b && c > d) 890*3ad3fb45Sjoris return; 891*3ad3fb45Sjoris if (ignore_pats != NULL) { 892*3ad3fb45Sjoris char *line; 893*3ad3fb45Sjoris /* 894*3ad3fb45Sjoris * All lines in the change, insert, or delete must 895*3ad3fb45Sjoris * match an ignore pattern for the change to be 896*3ad3fb45Sjoris * ignored. 897*3ad3fb45Sjoris */ 898*3ad3fb45Sjoris if (a <= b) { /* Changes and deletes. */ 899*3ad3fb45Sjoris for (i = a; i <= b; i++) { 900*3ad3fb45Sjoris line = preadline(fileno(f1), 901*3ad3fb45Sjoris ixold[i] - ixold[i - 1], ixold[i - 1]); 902*3ad3fb45Sjoris if (!ignoreline(line)) 903*3ad3fb45Sjoris goto proceed; 904*3ad3fb45Sjoris } 905*3ad3fb45Sjoris } 906*3ad3fb45Sjoris if (a > b || c <= d) { /* Changes and inserts. */ 907*3ad3fb45Sjoris for (i = c; i <= d; i++) { 908*3ad3fb45Sjoris line = preadline(fileno(f2), 909*3ad3fb45Sjoris ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 910*3ad3fb45Sjoris if (!ignoreline(line)) 911*3ad3fb45Sjoris goto proceed; 912*3ad3fb45Sjoris } 913*3ad3fb45Sjoris } 914*3ad3fb45Sjoris return; 915*3ad3fb45Sjoris } 916*3ad3fb45Sjoris proceed: 917*3ad3fb45Sjoris if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 918*3ad3fb45Sjoris /* 919*3ad3fb45Sjoris * Allocate change records as needed. 920*3ad3fb45Sjoris */ 921*3ad3fb45Sjoris if (context_vec_ptr == context_vec_end - 1) { 922*3ad3fb45Sjoris struct context_vec *tmp; 923*3ad3fb45Sjoris ptrdiff_t offset = context_vec_ptr - context_vec_start; 924*3ad3fb45Sjoris max_context <<= 1; 925*3ad3fb45Sjoris tmp = xrealloc(context_vec_start, max_context, 926*3ad3fb45Sjoris sizeof(*context_vec_start)); 927*3ad3fb45Sjoris context_vec_start = tmp; 928*3ad3fb45Sjoris context_vec_end = context_vec_start + max_context; 929*3ad3fb45Sjoris context_vec_ptr = context_vec_start + offset; 930*3ad3fb45Sjoris } 931*3ad3fb45Sjoris if (anychange == 0) { 932*3ad3fb45Sjoris /* 933*3ad3fb45Sjoris * Print the context/unidiff header first time through. 934*3ad3fb45Sjoris */ 935*3ad3fb45Sjoris t = localtime(&stb1.st_mtime); 936*3ad3fb45Sjoris (void)strftime(buf, sizeof(buf), 937*3ad3fb45Sjoris "%d %b %G %H:%M:%S", t); 938*3ad3fb45Sjoris 939*3ad3fb45Sjoris diff_output("%s %s %s", 940*3ad3fb45Sjoris diff_format == D_CONTEXT ? "***" : "---", diff_file, 941*3ad3fb45Sjoris buf); 942*3ad3fb45Sjoris 943*3ad3fb45Sjoris if (diff_rev1 != NULL) { 944*3ad3fb45Sjoris rcsnum_tostr(diff_rev1, buf, sizeof(buf)); 945*3ad3fb45Sjoris diff_output("\t%s", buf); 946*3ad3fb45Sjoris } 947*3ad3fb45Sjoris 948*3ad3fb45Sjoris printf("\n"); 949*3ad3fb45Sjoris 950*3ad3fb45Sjoris t = localtime(&stb2.st_mtime); 951*3ad3fb45Sjoris (void)strftime(buf, sizeof(buf), 952*3ad3fb45Sjoris "%d %b %G %H:%M:%S", t); 953*3ad3fb45Sjoris 954*3ad3fb45Sjoris diff_output("%s %s %s", 955*3ad3fb45Sjoris diff_format == D_CONTEXT ? "---" : "+++", diff_file, 956*3ad3fb45Sjoris buf); 957*3ad3fb45Sjoris 958*3ad3fb45Sjoris if (diff_rev2 != NULL) { 959*3ad3fb45Sjoris rcsnum_tostr(diff_rev2, buf, sizeof(buf)); 960*3ad3fb45Sjoris diff_output("\t%s", buf); 961*3ad3fb45Sjoris } 962*3ad3fb45Sjoris 963*3ad3fb45Sjoris printf("\n"); 964*3ad3fb45Sjoris anychange = 1; 965*3ad3fb45Sjoris } else if (a > context_vec_ptr->b + (2 * context) + 1 && 966*3ad3fb45Sjoris c > context_vec_ptr->d + (2 * context) + 1) { 967*3ad3fb45Sjoris /* 968*3ad3fb45Sjoris * If this change is more than 'context' lines from the 969*3ad3fb45Sjoris * previous change, dump the record and reset it. 970*3ad3fb45Sjoris */ 971*3ad3fb45Sjoris if (diff_format == D_CONTEXT) 972*3ad3fb45Sjoris dump_context_vec(f1, f2); 973*3ad3fb45Sjoris else 974*3ad3fb45Sjoris dump_unified_vec(f1, f2); 975*3ad3fb45Sjoris } 976*3ad3fb45Sjoris context_vec_ptr++; 977*3ad3fb45Sjoris context_vec_ptr->a = a; 978*3ad3fb45Sjoris context_vec_ptr->b = b; 979*3ad3fb45Sjoris context_vec_ptr->c = c; 980*3ad3fb45Sjoris context_vec_ptr->d = d; 981*3ad3fb45Sjoris return; 982*3ad3fb45Sjoris } 983*3ad3fb45Sjoris if (anychange == 0) 984*3ad3fb45Sjoris anychange = 1; 985*3ad3fb45Sjoris switch (diff_format) { 986*3ad3fb45Sjoris case D_BRIEF: 987*3ad3fb45Sjoris return; 988*3ad3fb45Sjoris case D_NORMAL: 989*3ad3fb45Sjoris range(a, b, ","); 990*3ad3fb45Sjoris diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 991*3ad3fb45Sjoris if (diff_format == D_NORMAL) 992*3ad3fb45Sjoris range(c, d, ","); 993*3ad3fb45Sjoris diff_output("\n"); 994*3ad3fb45Sjoris break; 995*3ad3fb45Sjoris case D_RCSDIFF: 996*3ad3fb45Sjoris if (a > b) 997*3ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 998*3ad3fb45Sjoris else { 999*3ad3fb45Sjoris diff_output("d%d %d\n", a, b - a + 1); 1000*3ad3fb45Sjoris 1001*3ad3fb45Sjoris if (!(c > d)) /* add changed lines */ 1002*3ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 1003*3ad3fb45Sjoris } 1004*3ad3fb45Sjoris break; 1005*3ad3fb45Sjoris } 1006*3ad3fb45Sjoris if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 1007*3ad3fb45Sjoris fetch(ixold, a, b, f1, '<', 1); 1008*3ad3fb45Sjoris if (a <= b && c <= d && diff_format == D_NORMAL) 1009*3ad3fb45Sjoris diff_output("---\n"); 1010*3ad3fb45Sjoris } 1011*3ad3fb45Sjoris fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); 1012*3ad3fb45Sjoris if (inifdef) { 1013*3ad3fb45Sjoris diff_output("#endif /* %s */\n", ifdefname); 1014*3ad3fb45Sjoris inifdef = 0; 1015*3ad3fb45Sjoris } 1016*3ad3fb45Sjoris } 1017*3ad3fb45Sjoris 1018*3ad3fb45Sjoris static void 1019*3ad3fb45Sjoris fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 1020*3ad3fb45Sjoris { 1021*3ad3fb45Sjoris long j, nc; 1022*3ad3fb45Sjoris int i, c, col; 1023*3ad3fb45Sjoris 1024*3ad3fb45Sjoris /* 1025*3ad3fb45Sjoris * When doing #ifdef's, copy down to current line 1026*3ad3fb45Sjoris * if this is the first file, so that stuff makes it to output. 1027*3ad3fb45Sjoris */ 1028*3ad3fb45Sjoris if (diff_format == D_IFDEF && oldfile) { 1029*3ad3fb45Sjoris long curpos = ftell(lb); 1030*3ad3fb45Sjoris /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 1031*3ad3fb45Sjoris nc = f[a > b ? b : a - 1] - curpos; 1032*3ad3fb45Sjoris for (i = 0; i < nc; i++) 1033*3ad3fb45Sjoris diff_output("%c", getc(lb)); 1034*3ad3fb45Sjoris } 1035*3ad3fb45Sjoris if (a > b) 1036*3ad3fb45Sjoris return; 1037*3ad3fb45Sjoris if (diff_format == D_IFDEF) { 1038*3ad3fb45Sjoris if (inifdef) { 1039*3ad3fb45Sjoris diff_output("#else /* %s%s */\n", 1040*3ad3fb45Sjoris oldfile == 1 ? "!" : "", ifdefname); 1041*3ad3fb45Sjoris } else { 1042*3ad3fb45Sjoris if (oldfile) 1043*3ad3fb45Sjoris diff_output("#ifndef %s\n", ifdefname); 1044*3ad3fb45Sjoris else 1045*3ad3fb45Sjoris diff_output("#ifdef %s\n", ifdefname); 1046*3ad3fb45Sjoris } 1047*3ad3fb45Sjoris inifdef = 1 + oldfile; 1048*3ad3fb45Sjoris } 1049*3ad3fb45Sjoris for (i = a; i <= b; i++) { 1050*3ad3fb45Sjoris fseek(lb, f[i - 1], SEEK_SET); 1051*3ad3fb45Sjoris nc = f[i] - f[i - 1]; 1052*3ad3fb45Sjoris if (diff_format != D_IFDEF && ch != '\0') { 1053*3ad3fb45Sjoris diff_output("%c", ch); 1054*3ad3fb45Sjoris if (Tflag == 1 && (diff_format == D_NORMAL || 1055*3ad3fb45Sjoris diff_format == D_CONTEXT || 1056*3ad3fb45Sjoris diff_format == D_UNIFIED)) 1057*3ad3fb45Sjoris diff_output("\t"); 1058*3ad3fb45Sjoris else if (diff_format != D_UNIFIED) 1059*3ad3fb45Sjoris diff_output(" "); 1060*3ad3fb45Sjoris } 1061*3ad3fb45Sjoris col = 0; 1062*3ad3fb45Sjoris for (j = 0; j < nc; j++) { 1063*3ad3fb45Sjoris if ((c = getc(lb)) == EOF) { 1064*3ad3fb45Sjoris if (diff_format == D_RCSDIFF) 1065*3ad3fb45Sjoris cvs_log(LP_ERR, 1066*3ad3fb45Sjoris "No newline at end of file"); 1067*3ad3fb45Sjoris else 1068*3ad3fb45Sjoris diff_output("\n\\ No newline at end of " 1069*3ad3fb45Sjoris "file"); 1070*3ad3fb45Sjoris return; 1071*3ad3fb45Sjoris } 1072*3ad3fb45Sjoris if (c == '\t' && tflag == 1) { 1073*3ad3fb45Sjoris do { 1074*3ad3fb45Sjoris diff_output(" "); 1075*3ad3fb45Sjoris } while (++col & 7); 1076*3ad3fb45Sjoris } else { 1077*3ad3fb45Sjoris diff_output("%c", c); 1078*3ad3fb45Sjoris col++; 1079*3ad3fb45Sjoris } 1080*3ad3fb45Sjoris } 1081*3ad3fb45Sjoris } 1082*3ad3fb45Sjoris } 1083*3ad3fb45Sjoris 1084*3ad3fb45Sjoris /* 1085*3ad3fb45Sjoris * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 1086*3ad3fb45Sjoris */ 1087*3ad3fb45Sjoris static int 1088*3ad3fb45Sjoris readhash(FILE *f) 1089*3ad3fb45Sjoris { 1090*3ad3fb45Sjoris int i, t, space; 1091*3ad3fb45Sjoris int sum; 1092*3ad3fb45Sjoris 1093*3ad3fb45Sjoris sum = 1; 1094*3ad3fb45Sjoris space = 0; 1095*3ad3fb45Sjoris if (bflag != 1 && wflag != 1) { 1096*3ad3fb45Sjoris if (iflag == 1) 1097*3ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 1098*3ad3fb45Sjoris if (t == EOF) { 1099*3ad3fb45Sjoris if (i == 0) 1100*3ad3fb45Sjoris return (0); 1101*3ad3fb45Sjoris break; 1102*3ad3fb45Sjoris } 1103*3ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 1104*3ad3fb45Sjoris } 1105*3ad3fb45Sjoris else 1106*3ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 1107*3ad3fb45Sjoris if (t == EOF) { 1108*3ad3fb45Sjoris if (i == 0) 1109*3ad3fb45Sjoris return (0); 1110*3ad3fb45Sjoris break; 1111*3ad3fb45Sjoris } 1112*3ad3fb45Sjoris sum = sum * 127 + t; 1113*3ad3fb45Sjoris } 1114*3ad3fb45Sjoris } else { 1115*3ad3fb45Sjoris for (i = 0;;) { 1116*3ad3fb45Sjoris switch (t = getc(f)) { 1117*3ad3fb45Sjoris case '\t': 1118*3ad3fb45Sjoris case ' ': 1119*3ad3fb45Sjoris space++; 1120*3ad3fb45Sjoris continue; 1121*3ad3fb45Sjoris default: 1122*3ad3fb45Sjoris if (space != 0 && wflag != 1) { 1123*3ad3fb45Sjoris i++; 1124*3ad3fb45Sjoris space = 0; 1125*3ad3fb45Sjoris } 1126*3ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 1127*3ad3fb45Sjoris i++; 1128*3ad3fb45Sjoris continue; 1129*3ad3fb45Sjoris case EOF: 1130*3ad3fb45Sjoris if (i == 0) 1131*3ad3fb45Sjoris return (0); 1132*3ad3fb45Sjoris /* FALLTHROUGH */ 1133*3ad3fb45Sjoris case '\n': 1134*3ad3fb45Sjoris break; 1135*3ad3fb45Sjoris } 1136*3ad3fb45Sjoris break; 1137*3ad3fb45Sjoris } 1138*3ad3fb45Sjoris } 1139*3ad3fb45Sjoris /* 1140*3ad3fb45Sjoris * There is a remote possibility that we end up with a zero sum. 1141*3ad3fb45Sjoris * Zero is used as an EOF marker, so return 1 instead. 1142*3ad3fb45Sjoris */ 1143*3ad3fb45Sjoris return (sum == 0 ? 1 : sum); 1144*3ad3fb45Sjoris } 1145*3ad3fb45Sjoris 1146*3ad3fb45Sjoris static int 1147*3ad3fb45Sjoris asciifile(FILE *f) 1148*3ad3fb45Sjoris { 1149*3ad3fb45Sjoris char buf[BUFSIZ]; 1150*3ad3fb45Sjoris size_t i, cnt; 1151*3ad3fb45Sjoris 1152*3ad3fb45Sjoris if (aflag == 1 || f == NULL) 1153*3ad3fb45Sjoris return (1); 1154*3ad3fb45Sjoris 1155*3ad3fb45Sjoris rewind(f); 1156*3ad3fb45Sjoris cnt = fread(buf, (size_t)1, sizeof(buf), f); 1157*3ad3fb45Sjoris for (i = 0; i < cnt; i++) 1158*3ad3fb45Sjoris if (!isprint(buf[i]) && !isspace(buf[i])) 1159*3ad3fb45Sjoris return (0); 1160*3ad3fb45Sjoris return (1); 1161*3ad3fb45Sjoris } 1162*3ad3fb45Sjoris 1163*3ad3fb45Sjoris static char* 1164*3ad3fb45Sjoris match_function(const long *f, int pos, FILE *fp) 1165*3ad3fb45Sjoris { 1166*3ad3fb45Sjoris unsigned char buf[FUNCTION_CONTEXT_SIZE]; 1167*3ad3fb45Sjoris size_t nc; 1168*3ad3fb45Sjoris int last = lastline; 1169*3ad3fb45Sjoris char *p; 1170*3ad3fb45Sjoris 1171*3ad3fb45Sjoris lastline = pos; 1172*3ad3fb45Sjoris while (pos > last) { 1173*3ad3fb45Sjoris fseek(fp, f[pos - 1], SEEK_SET); 1174*3ad3fb45Sjoris nc = f[pos] - f[pos - 1]; 1175*3ad3fb45Sjoris if (nc >= sizeof(buf)) 1176*3ad3fb45Sjoris nc = sizeof(buf) - 1; 1177*3ad3fb45Sjoris nc = fread(buf, (size_t)1, nc, fp); 1178*3ad3fb45Sjoris if (nc > 0) { 1179*3ad3fb45Sjoris buf[nc] = '\0'; 1180*3ad3fb45Sjoris p = strchr((const char *)buf, '\n'); 1181*3ad3fb45Sjoris if (p != NULL) 1182*3ad3fb45Sjoris *p = '\0'; 1183*3ad3fb45Sjoris if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 1184*3ad3fb45Sjoris strlcpy(lastbuf, (const char *)buf, 1185*3ad3fb45Sjoris sizeof lastbuf); 1186*3ad3fb45Sjoris lastmatchline = pos; 1187*3ad3fb45Sjoris return lastbuf; 1188*3ad3fb45Sjoris } 1189*3ad3fb45Sjoris } 1190*3ad3fb45Sjoris pos--; 1191*3ad3fb45Sjoris } 1192*3ad3fb45Sjoris return (lastmatchline > 0) ? lastbuf : NULL; 1193*3ad3fb45Sjoris } 1194*3ad3fb45Sjoris 1195*3ad3fb45Sjoris 1196*3ad3fb45Sjoris /* dump accumulated "context" diff changes */ 1197*3ad3fb45Sjoris static void 1198*3ad3fb45Sjoris dump_context_vec(FILE *f1, FILE *f2) 1199*3ad3fb45Sjoris { 1200*3ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 1201*3ad3fb45Sjoris int lowa, upb, lowc, upd, do_output; 1202*3ad3fb45Sjoris int a, b, c, d; 1203*3ad3fb45Sjoris char ch, *f; 1204*3ad3fb45Sjoris 1205*3ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 1206*3ad3fb45Sjoris return; 1207*3ad3fb45Sjoris 1208*3ad3fb45Sjoris b = d = 0; /* gcc */ 1209*3ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 1210*3ad3fb45Sjoris upb = MIN(diff_len[0], context_vec_ptr->b + context); 1211*3ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 1212*3ad3fb45Sjoris upd = MIN(diff_len[1], context_vec_ptr->d + context); 1213*3ad3fb45Sjoris 1214*3ad3fb45Sjoris diff_output("***************"); 1215*3ad3fb45Sjoris if (pflag == 1) { 1216*3ad3fb45Sjoris f = match_function(ixold, lowa - 1, f1); 1217*3ad3fb45Sjoris if (f != NULL) { 1218*3ad3fb45Sjoris diff_output(" "); 1219*3ad3fb45Sjoris diff_output("%s", f); 1220*3ad3fb45Sjoris } 1221*3ad3fb45Sjoris } 1222*3ad3fb45Sjoris diff_output("\n*** "); 1223*3ad3fb45Sjoris range(lowa, upb, ","); 1224*3ad3fb45Sjoris diff_output(" ****\n"); 1225*3ad3fb45Sjoris 1226*3ad3fb45Sjoris /* 1227*3ad3fb45Sjoris * Output changes to the "old" file. The first loop suppresses 1228*3ad3fb45Sjoris * output if there were no changes to the "old" file (we'll see 1229*3ad3fb45Sjoris * the "old" lines as context in the "new" list). 1230*3ad3fb45Sjoris */ 1231*3ad3fb45Sjoris do_output = 0; 1232*3ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) 1233*3ad3fb45Sjoris if (cvp->a <= cvp->b) { 1234*3ad3fb45Sjoris cvp = context_vec_start; 1235*3ad3fb45Sjoris do_output++; 1236*3ad3fb45Sjoris break; 1237*3ad3fb45Sjoris } 1238*3ad3fb45Sjoris if (do_output != 0) { 1239*3ad3fb45Sjoris while (cvp <= context_vec_ptr) { 1240*3ad3fb45Sjoris a = cvp->a; 1241*3ad3fb45Sjoris b = cvp->b; 1242*3ad3fb45Sjoris c = cvp->c; 1243*3ad3fb45Sjoris d = cvp->d; 1244*3ad3fb45Sjoris 1245*3ad3fb45Sjoris if (a <= b && c <= d) 1246*3ad3fb45Sjoris ch = 'c'; 1247*3ad3fb45Sjoris else 1248*3ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 1249*3ad3fb45Sjoris 1250*3ad3fb45Sjoris if (ch == 'a') 1251*3ad3fb45Sjoris fetch(ixold, lowa, b, f1, ' ', 0); 1252*3ad3fb45Sjoris else { 1253*3ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 1254*3ad3fb45Sjoris fetch(ixold, a, b, f1, 1255*3ad3fb45Sjoris ch == 'c' ? '!' : '-', 0); 1256*3ad3fb45Sjoris } 1257*3ad3fb45Sjoris lowa = b + 1; 1258*3ad3fb45Sjoris cvp++; 1259*3ad3fb45Sjoris } 1260*3ad3fb45Sjoris fetch(ixold, b + 1, upb, f1, ' ', 0); 1261*3ad3fb45Sjoris } 1262*3ad3fb45Sjoris /* output changes to the "new" file */ 1263*3ad3fb45Sjoris diff_output("--- "); 1264*3ad3fb45Sjoris range(lowc, upd, ","); 1265*3ad3fb45Sjoris diff_output(" ----\n"); 1266*3ad3fb45Sjoris 1267*3ad3fb45Sjoris do_output = 0; 1268*3ad3fb45Sjoris for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 1269*3ad3fb45Sjoris if (cvp->c <= cvp->d) { 1270*3ad3fb45Sjoris cvp = context_vec_start; 1271*3ad3fb45Sjoris do_output++; 1272*3ad3fb45Sjoris break; 1273*3ad3fb45Sjoris } 1274*3ad3fb45Sjoris if (do_output != 0) { 1275*3ad3fb45Sjoris while (cvp <= context_vec_ptr) { 1276*3ad3fb45Sjoris a = cvp->a; 1277*3ad3fb45Sjoris b = cvp->b; 1278*3ad3fb45Sjoris c = cvp->c; 1279*3ad3fb45Sjoris d = cvp->d; 1280*3ad3fb45Sjoris 1281*3ad3fb45Sjoris if (a <= b && c <= d) 1282*3ad3fb45Sjoris ch = 'c'; 1283*3ad3fb45Sjoris else 1284*3ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 1285*3ad3fb45Sjoris 1286*3ad3fb45Sjoris if (ch == 'd') 1287*3ad3fb45Sjoris fetch(ixnew, lowc, d, f2, ' ', 0); 1288*3ad3fb45Sjoris else { 1289*3ad3fb45Sjoris fetch(ixnew, lowc, c - 1, f2, ' ', 0); 1290*3ad3fb45Sjoris fetch(ixnew, c, d, f2, 1291*3ad3fb45Sjoris ch == 'c' ? '!' : '+', 0); 1292*3ad3fb45Sjoris } 1293*3ad3fb45Sjoris lowc = d + 1; 1294*3ad3fb45Sjoris cvp++; 1295*3ad3fb45Sjoris } 1296*3ad3fb45Sjoris fetch(ixnew, d + 1, upd, f2, ' ', 0); 1297*3ad3fb45Sjoris } 1298*3ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 1299*3ad3fb45Sjoris } 1300*3ad3fb45Sjoris 1301*3ad3fb45Sjoris /* dump accumulated "unified" diff changes */ 1302*3ad3fb45Sjoris static void 1303*3ad3fb45Sjoris dump_unified_vec(FILE *f1, FILE *f2) 1304*3ad3fb45Sjoris { 1305*3ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 1306*3ad3fb45Sjoris int lowa, upb, lowc, upd; 1307*3ad3fb45Sjoris int a, b, c, d; 1308*3ad3fb45Sjoris char ch, *f; 1309*3ad3fb45Sjoris 1310*3ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 1311*3ad3fb45Sjoris return; 1312*3ad3fb45Sjoris 1313*3ad3fb45Sjoris b = d = 0; /* gcc */ 1314*3ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 1315*3ad3fb45Sjoris upb = MIN(diff_len[0], context_vec_ptr->b + context); 1316*3ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 1317*3ad3fb45Sjoris upd = MIN(diff_len[1], context_vec_ptr->d + context); 1318*3ad3fb45Sjoris 1319*3ad3fb45Sjoris diff_output("@@ -"); 1320*3ad3fb45Sjoris uni_range(lowa, upb); 1321*3ad3fb45Sjoris diff_output(" +"); 1322*3ad3fb45Sjoris uni_range(lowc, upd); 1323*3ad3fb45Sjoris diff_output(" @@"); 1324*3ad3fb45Sjoris if (pflag == 1) { 1325*3ad3fb45Sjoris f = match_function(ixold, lowa - 1, f1); 1326*3ad3fb45Sjoris if (f != NULL) { 1327*3ad3fb45Sjoris diff_output(" "); 1328*3ad3fb45Sjoris diff_output("%s", f); 1329*3ad3fb45Sjoris } 1330*3ad3fb45Sjoris } 1331*3ad3fb45Sjoris diff_output("\n"); 1332*3ad3fb45Sjoris 1333*3ad3fb45Sjoris /* 1334*3ad3fb45Sjoris * Output changes in "unified" diff format--the old and new lines 1335*3ad3fb45Sjoris * are printed together. 1336*3ad3fb45Sjoris */ 1337*3ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) { 1338*3ad3fb45Sjoris a = cvp->a; 1339*3ad3fb45Sjoris b = cvp->b; 1340*3ad3fb45Sjoris c = cvp->c; 1341*3ad3fb45Sjoris d = cvp->d; 1342*3ad3fb45Sjoris 1343*3ad3fb45Sjoris /* 1344*3ad3fb45Sjoris * c: both new and old changes 1345*3ad3fb45Sjoris * d: only changes in the old file 1346*3ad3fb45Sjoris * a: only changes in the new file 1347*3ad3fb45Sjoris */ 1348*3ad3fb45Sjoris if (a <= b && c <= d) 1349*3ad3fb45Sjoris ch = 'c'; 1350*3ad3fb45Sjoris else 1351*3ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 1352*3ad3fb45Sjoris 1353*3ad3fb45Sjoris switch (ch) { 1354*3ad3fb45Sjoris case 'c': 1355*3ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 1356*3ad3fb45Sjoris fetch(ixold, a, b, f1, '-', 0); 1357*3ad3fb45Sjoris fetch(ixnew, c, d, f2, '+', 0); 1358*3ad3fb45Sjoris break; 1359*3ad3fb45Sjoris case 'd': 1360*3ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 1361*3ad3fb45Sjoris fetch(ixold, a, b, f1, '-', 0); 1362*3ad3fb45Sjoris break; 1363*3ad3fb45Sjoris case 'a': 1364*3ad3fb45Sjoris fetch(ixnew, lowc, c - 1, f2, ' ', 0); 1365*3ad3fb45Sjoris fetch(ixnew, c, d, f2, '+', 0); 1366*3ad3fb45Sjoris break; 1367*3ad3fb45Sjoris } 1368*3ad3fb45Sjoris lowa = b + 1; 1369*3ad3fb45Sjoris lowc = d + 1; 1370*3ad3fb45Sjoris } 1371*3ad3fb45Sjoris fetch(ixnew, d + 1, upd, f2, ' ', 0); 1372*3ad3fb45Sjoris 1373*3ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 1374*3ad3fb45Sjoris } 1375*3ad3fb45Sjoris 1376*3ad3fb45Sjoris void 1377*3ad3fb45Sjoris diff_output(const char *fmt, ...) 1378*3ad3fb45Sjoris { 1379*3ad3fb45Sjoris va_list vap; 1380*3ad3fb45Sjoris int i; 1381*3ad3fb45Sjoris char *str; 1382*3ad3fb45Sjoris 1383*3ad3fb45Sjoris va_start(vap, fmt); 1384*3ad3fb45Sjoris i = vasprintf(&str, fmt, vap); 1385*3ad3fb45Sjoris va_end(vap); 1386*3ad3fb45Sjoris if (i == -1) 1387*3ad3fb45Sjoris fatal("diff_output: %s", strerror(errno)); 1388*3ad3fb45Sjoris if (diffbuf != NULL) 1389*3ad3fb45Sjoris cvs_buf_append(diffbuf, str, strlen(str)); 1390*3ad3fb45Sjoris else 1391*3ad3fb45Sjoris cvs_printf("%s", str); 1392*3ad3fb45Sjoris xfree(str); 1393*3ad3fb45Sjoris } 1394