1*d5d01609Sray /* $OpenBSD: diff_internals.c,v 1.31 2010/07/16 17:53:20 ray Exp $ */ 23ad3fb45Sjoris /* 33ad3fb45Sjoris * Copyright (C) Caldera International Inc. 2001-2002. 43ad3fb45Sjoris * All rights reserved. 53ad3fb45Sjoris * 63ad3fb45Sjoris * Redistribution and use in source and binary forms, with or without 73ad3fb45Sjoris * modification, are permitted provided that the following conditions 83ad3fb45Sjoris * are met: 93ad3fb45Sjoris * 1. Redistributions of source code and documentation must retain the above 103ad3fb45Sjoris * copyright notice, this list of conditions and the following disclaimer. 113ad3fb45Sjoris * 2. Redistributions in binary form must reproduce the above copyright 123ad3fb45Sjoris * notice, this list of conditions and the following disclaimer in the 133ad3fb45Sjoris * documentation and/or other materials provided with the distribution. 143ad3fb45Sjoris * 3. All advertising materials mentioning features or use of this software 153ad3fb45Sjoris * must display the following acknowledgement: 163ad3fb45Sjoris * This product includes software developed or owned by Caldera 173ad3fb45Sjoris * International, Inc. 183ad3fb45Sjoris * 4. Neither the name of Caldera International, Inc. nor the names of other 193ad3fb45Sjoris * contributors may be used to endorse or promote products derived from 203ad3fb45Sjoris * this software without specific prior written permission. 213ad3fb45Sjoris * 223ad3fb45Sjoris * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 233ad3fb45Sjoris * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 243ad3fb45Sjoris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 253ad3fb45Sjoris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 263ad3fb45Sjoris * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 273ad3fb45Sjoris * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 283ad3fb45Sjoris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 293ad3fb45Sjoris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 303ad3fb45Sjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 313ad3fb45Sjoris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 323ad3fb45Sjoris * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 333ad3fb45Sjoris * POSSIBILITY OF SUCH DAMAGE. 343ad3fb45Sjoris */ 353ad3fb45Sjoris /*- 363ad3fb45Sjoris * Copyright (c) 1991, 1993 373ad3fb45Sjoris * The Regents of the University of California. All rights reserved. 383ad3fb45Sjoris * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved. 393ad3fb45Sjoris * 403ad3fb45Sjoris * Redistribution and use in source and binary forms, with or without 413ad3fb45Sjoris * modification, are permitted provided that the following conditions 423ad3fb45Sjoris * are met: 433ad3fb45Sjoris * 1. Redistributions of source code must retain the above copyright 443ad3fb45Sjoris * notice, this list of conditions and the following disclaimer. 453ad3fb45Sjoris * 2. Redistributions in binary form must reproduce the above copyright 463ad3fb45Sjoris * notice, this list of conditions and the following disclaimer in the 473ad3fb45Sjoris * documentation and/or other materials provided with the distribution. 483ad3fb45Sjoris * 3. Neither the name of the University nor the names of its contributors 493ad3fb45Sjoris * may be used to endorse or promote products derived from this software 503ad3fb45Sjoris * without specific prior written permission. 513ad3fb45Sjoris * 523ad3fb45Sjoris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 533ad3fb45Sjoris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 543ad3fb45Sjoris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 553ad3fb45Sjoris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 563ad3fb45Sjoris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 573ad3fb45Sjoris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 583ad3fb45Sjoris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 593ad3fb45Sjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 603ad3fb45Sjoris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 613ad3fb45Sjoris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 623ad3fb45Sjoris * SUCH DAMAGE. 633ad3fb45Sjoris * 643ad3fb45Sjoris * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 653ad3fb45Sjoris */ 66eea21b3cSray 67eea21b3cSray #include <sys/param.h> 68eea21b3cSray #include <sys/stat.h> 69eea21b3cSray 70eea21b3cSray #include <ctype.h> 71eea21b3cSray #include <errno.h> 72eea21b3cSray #include <regex.h> 73eea21b3cSray #include <stddef.h> 74101e9cbeStobias #include <stdio.h> 75eea21b3cSray #include <string.h> 766534056aStobias #include <time.h> 77eea21b3cSray #include <unistd.h> 78eea21b3cSray 79eea21b3cSray #include "cvs.h" 80eea21b3cSray #include "diff.h" 81eea21b3cSray 82eea21b3cSray /* 83eea21b3cSray * diff - compare two files. 84eea21b3cSray */ 85eea21b3cSray 863ad3fb45Sjoris /* 873ad3fb45Sjoris * Uses an algorithm due to Harold Stone, which finds 883ad3fb45Sjoris * a pair of longest identical subsequences in the two 893ad3fb45Sjoris * files. 903ad3fb45Sjoris * 913ad3fb45Sjoris * The major goal is to generate the match vector J. 923ad3fb45Sjoris * J[i] is the index of the line in file1 corresponding 933ad3fb45Sjoris * to line i file0. J[i] = 0 if there is no 943ad3fb45Sjoris * such line in file1. 953ad3fb45Sjoris * 963ad3fb45Sjoris * Lines are hashed so as to work in core. All potential 973ad3fb45Sjoris * matches are located by sorting the lines of each file 983ad3fb45Sjoris * on the hash (called ``value''). In particular, this 993ad3fb45Sjoris * collects the equivalence classes in file1 together. 1003ad3fb45Sjoris * Subroutine equiv replaces the value of each line in 1013ad3fb45Sjoris * file0 by the index of the first element of its 1023ad3fb45Sjoris * matching equivalence in (the reordered) file1. 1033ad3fb45Sjoris * To save space equiv squeezes file1 into a single 1043ad3fb45Sjoris * array member in which the equivalence classes 1053ad3fb45Sjoris * are simply concatenated, except that their first 1063ad3fb45Sjoris * members are flagged by changing sign. 1073ad3fb45Sjoris * 1083ad3fb45Sjoris * Next the indices that point into member are unsorted into 1093ad3fb45Sjoris * array class according to the original order of file0. 1103ad3fb45Sjoris * 1113ad3fb45Sjoris * The cleverness lies in routine stone. This marches 1123ad3fb45Sjoris * through the lines of file0, developing a vector klist 1133ad3fb45Sjoris * of "k-candidates". At step i a k-candidate is a matched 1143ad3fb45Sjoris * pair of lines x,y (x in file0 y in file1) such that 1153ad3fb45Sjoris * there is a common subsequence of length k 1163ad3fb45Sjoris * between the first i lines of file0 and the first y 1173ad3fb45Sjoris * lines of file1, but there is no such subsequence for 1183ad3fb45Sjoris * any smaller y. x is the earliest possible mate to y 1193ad3fb45Sjoris * that occurs in such a subsequence. 1203ad3fb45Sjoris * 1213ad3fb45Sjoris * Whenever any of the members of the equivalence class of 1223ad3fb45Sjoris * lines in file1 matable to a line in file0 has serial number 1233ad3fb45Sjoris * less than the y of some k-candidate, that k-candidate 1243ad3fb45Sjoris * with the smallest such y is replaced. The new 1253ad3fb45Sjoris * k-candidate is chained (via pred) to the current 1263ad3fb45Sjoris * k-1 candidate so that the actual subsequence can 1273ad3fb45Sjoris * be recovered. When a member has serial number greater 1283ad3fb45Sjoris * that the y of all k-candidates, the klist is extended. 1293ad3fb45Sjoris * At the end, the longest subsequence is pulled out 1303ad3fb45Sjoris * and placed in the array J by unravel 1313ad3fb45Sjoris * 1323ad3fb45Sjoris * With J in hand, the matches there recorded are 1333ad3fb45Sjoris * check'ed against reality to assure that no spurious 1343ad3fb45Sjoris * matches have crept in due to hashing. If they have, 1353ad3fb45Sjoris * they are broken, and "jackpot" is recorded--a harmless 1363ad3fb45Sjoris * matter except that a true match for a spuriously 1373ad3fb45Sjoris * mated line may now be unnecessarily reported as a change. 1383ad3fb45Sjoris * 1393ad3fb45Sjoris * Much of the complexity of the program comes simply 1403ad3fb45Sjoris * from trying to minimize core utilization and 1413ad3fb45Sjoris * maximize the range of doable problems by dynamically 1423ad3fb45Sjoris * allocating what is needed and reusing what is not. 1433ad3fb45Sjoris * The core requirements for problems larger than somewhat 1443ad3fb45Sjoris * are (in words) 2*length(file0) + length(file1) + 1453ad3fb45Sjoris * 3*(number of k-candidates installed), typically about 1463ad3fb45Sjoris * 6n words for files of length n. 1473ad3fb45Sjoris */ 1483ad3fb45Sjoris 1493ad3fb45Sjoris struct cand { 1503ad3fb45Sjoris int x; 1513ad3fb45Sjoris int y; 1523ad3fb45Sjoris int pred; 153ccf8fb4cSray }; 1543ad3fb45Sjoris 1553ad3fb45Sjoris struct line { 1563ad3fb45Sjoris int serial; 1573ad3fb45Sjoris int value; 1583ad3fb45Sjoris } *file[2]; 1593ad3fb45Sjoris 1603ad3fb45Sjoris /* 1613ad3fb45Sjoris * The following struct is used to record change information when 1623ad3fb45Sjoris * doing a "context" or "unified" diff. (see routine "change" to 1633ad3fb45Sjoris * understand the highly mnemonic field names) 1643ad3fb45Sjoris */ 1653ad3fb45Sjoris struct context_vec { 1663ad3fb45Sjoris int a; /* start line in old file */ 1673ad3fb45Sjoris int b; /* end line in old file */ 1683ad3fb45Sjoris int c; /* start line in new file */ 1693ad3fb45Sjoris int d; /* end line in new file */ 1703ad3fb45Sjoris }; 1713ad3fb45Sjoris 172219c50abSray static void output(FILE *, FILE *, int); 173219c50abSray static void check(FILE *, FILE *, int); 1743ad3fb45Sjoris static void range(int, int, char *); 1753ad3fb45Sjoris static void uni_range(int, int); 176219c50abSray static void dump_context_vec(FILE *, FILE *, int); 177219c50abSray static void dump_unified_vec(FILE *, FILE *, int); 178219c50abSray static void prepare(int, FILE *, off_t, int); 1793ad3fb45Sjoris static void prune(void); 1803ad3fb45Sjoris static void equiv(struct line *, int, struct line *, int, int *); 1813ad3fb45Sjoris static void unravel(int); 1823ad3fb45Sjoris static void unsort(struct line *, int, int *); 183fd660bf2Stobias static void diff_head(void); 184fd660bf2Stobias static void rdiff_head(void); 185219c50abSray static void change(FILE *, FILE *, int, int, int, int, int); 1863ad3fb45Sjoris static void sort(struct line *, int); 1873ad3fb45Sjoris static int ignoreline(char *); 1883ad3fb45Sjoris static int asciifile(FILE *); 189219c50abSray static void fetch(long *, int, int, FILE *, int, int, int); 1903ad3fb45Sjoris static int newcand(int, int, int); 1913ad3fb45Sjoris static int search(int *, int, int); 1923ad3fb45Sjoris static int skipline(FILE *); 1933ad3fb45Sjoris static int isqrt(int); 194219c50abSray static int stone(int *, int, int *, int *, int); 195219c50abSray static int readhash(FILE *, int); 1963ad3fb45Sjoris static int files_differ(FILE *, FILE *); 1973ad3fb45Sjoris static char *match_function(const long *, int, FILE *); 1983ad3fb45Sjoris static char *preadline(int, size_t, off_t); 1993ad3fb45Sjoris 200219c50abSray static int Tflag; 2013ad3fb45Sjoris static int context = 3; 2023ad3fb45Sjoris int diff_format = D_NORMAL; 203be756b91Stobias const char *diff_file1 = NULL; 204be756b91Stobias const char *diff_file2 = NULL; 2053ad3fb45Sjoris RCSNUM *diff_rev1 = NULL; 2063ad3fb45Sjoris RCSNUM *diff_rev2 = NULL; 2073ad3fb45Sjoris char diffargs[128]; 2083ad3fb45Sjoris static struct stat stb1, stb2; 2093ad3fb45Sjoris static char *ifdefname, *ignore_pats; 2103ad3fb45Sjoris regex_t ignore_re; 2113ad3fb45Sjoris 2123ad3fb45Sjoris static int *J; /* will be overlaid on class */ 2133ad3fb45Sjoris static int *class; /* will be overlaid on file[0] */ 2143ad3fb45Sjoris static int *klist; /* will be overlaid on file[0] after class */ 2153ad3fb45Sjoris static int *member; /* will be overlaid on file[1] */ 2163ad3fb45Sjoris static int clen; 2173ad3fb45Sjoris static int inifdef; /* whether or not we are in a #ifdef block */ 218eea21b3cSray static int len[2]; 2193ad3fb45Sjoris static int pref, suff; /* length of prefix and suffix */ 2203ad3fb45Sjoris static int slen[2]; 2213ad3fb45Sjoris static int anychange; 2223ad3fb45Sjoris static long *ixnew; /* will be overlaid on file[1] */ 2233ad3fb45Sjoris static long *ixold; /* will be overlaid on klist */ 2243ad3fb45Sjoris static struct cand *clist; /* merely a free storage pot for candidates */ 2253ad3fb45Sjoris static int clistlen; /* the length of clist */ 2263ad3fb45Sjoris static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 2273ad3fb45Sjoris static u_char *chrtran; /* translation table for case-folding */ 2283ad3fb45Sjoris static struct context_vec *context_vec_start; 2293ad3fb45Sjoris static struct context_vec *context_vec_end; 2303ad3fb45Sjoris static struct context_vec *context_vec_ptr; 2313ad3fb45Sjoris 232e22e6974Sxsa #define FUNCTION_CONTEXT_SIZE 55 2333ad3fb45Sjoris static char lastbuf[FUNCTION_CONTEXT_SIZE]; 2343ad3fb45Sjoris static int lastline; 2353ad3fb45Sjoris static int lastmatchline; 2363ad3fb45Sjoris BUF *diffbuf = NULL; 2373ad3fb45Sjoris 238eea21b3cSray 2393ad3fb45Sjoris /* 2403ad3fb45Sjoris * chrtran points to one of 2 translation tables: cup2low if folding upper to 2413ad3fb45Sjoris * lower case clow2low if not folding case 2423ad3fb45Sjoris */ 2433ad3fb45Sjoris u_char clow2low[256] = { 2443ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2453ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2463ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2473ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2483ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2493ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 2503ad3fb45Sjoris 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 2513ad3fb45Sjoris 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 2523ad3fb45Sjoris 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 2533ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2543ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2553ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2563ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2573ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2583ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2593ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2603ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2613ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2623ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2633ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2643ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2653ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2663ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2673ad3fb45Sjoris 0xfd, 0xfe, 0xff 2683ad3fb45Sjoris }; 2693ad3fb45Sjoris 2703ad3fb45Sjoris u_char cup2low[256] = { 2713ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2723ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2733ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2743ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2753ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2763ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 2773ad3fb45Sjoris 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 2783ad3fb45Sjoris 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 2793ad3fb45Sjoris 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 2803ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2813ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2823ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2833ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2843ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2853ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2863ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2873ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2883ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2893ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2903ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2913ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2923ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2933ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2943ad3fb45Sjoris 0xfd, 0xfe, 0xff 2953ad3fb45Sjoris }; 2963ad3fb45Sjoris 2973ad3fb45Sjoris int 29857003866Sray diffreg(const char *file1, const char *file2, int _fd1, int _fd2, 299219c50abSray BUF *out, int flags) 3003ad3fb45Sjoris { 3013ad3fb45Sjoris FILE *f1, *f2; 3022e0d696aSjoris int i, rval, fd1, fd2; 3033ad3fb45Sjoris 304be756b91Stobias diff_file1 = file1; 305be756b91Stobias diff_file2 = file2; 3063ad3fb45Sjoris f1 = f2 = NULL; 3073ad3fb45Sjoris rval = D_SAME; 3083ad3fb45Sjoris anychange = 0; 3093ad3fb45Sjoris lastline = 0; 3103ad3fb45Sjoris lastmatchline = 0; 3113ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 312219c50abSray if (flags & D_IGNORECASE) 313219c50abSray chrtran = cup2low; 314219c50abSray else 315219c50abSray chrtran = clow2low; 3163ad3fb45Sjoris if (out != NULL) 3173ad3fb45Sjoris diffbuf = out; 3183ad3fb45Sjoris 3192e0d696aSjoris fd1 = dup(_fd1); 3202e0d696aSjoris if (fd1 == -1) 32157003866Sray fatal("diffreg: dup: %s", strerror(errno)); 3222e0d696aSjoris 3232e0d696aSjoris fd2 = dup(_fd2); 3242e0d696aSjoris if (fd2 == -1) 32557003866Sray fatal("diffreg: dup: %s", strerror(errno)); 3262e0d696aSjoris 327651312a5Sjoris if (lseek(fd1, 0, SEEK_SET) < 0) 32857003866Sray fatal("diffreg: lseek: %s", strerror(errno)); 3292e0d696aSjoris 3302e0d696aSjoris f1 = fdopen(fd1, "r"); 3313ad3fb45Sjoris if (f1 == NULL) { 3323ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 3333ad3fb45Sjoris goto closem; 3343ad3fb45Sjoris } 3353ad3fb45Sjoris 336651312a5Sjoris if (lseek(fd2, 0, SEEK_SET) < 0) 33757003866Sray fatal("diffreg: lseek: %s", strerror(errno)); 3382e0d696aSjoris 3392e0d696aSjoris f2 = fdopen(fd2, "r"); 3403ad3fb45Sjoris if (f2 == NULL) { 3413ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 3423ad3fb45Sjoris goto closem; 3433ad3fb45Sjoris } 3443ad3fb45Sjoris 3452e0d696aSjoris if (fstat(fd1, &stb1) < 0) { 3463ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 3473ad3fb45Sjoris goto closem; 3483ad3fb45Sjoris } 3492e0d696aSjoris 3502e0d696aSjoris if (fstat(fd2, &stb2) < 0) { 3513ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 3523ad3fb45Sjoris goto closem; 3533ad3fb45Sjoris } 354eea21b3cSray 3553ad3fb45Sjoris switch (files_differ(f1, f2)) { 3563ad3fb45Sjoris case 0: 3573ad3fb45Sjoris goto closem; 3583ad3fb45Sjoris case 1: 3593ad3fb45Sjoris break; 3603ad3fb45Sjoris default: 3613ad3fb45Sjoris /* error */ 3623ad3fb45Sjoris goto closem; 3633ad3fb45Sjoris } 3643ad3fb45Sjoris 365219c50abSray if ((flags & D_FORCEASCII) == 0 && 366219c50abSray (!asciifile(f1) || !asciifile(f2))) { 3673ad3fb45Sjoris rval = D_BINARY; 3683ad3fb45Sjoris goto closem; 3693ad3fb45Sjoris } 370eea21b3cSray 371219c50abSray prepare(0, f1, stb1.st_size, flags); 372219c50abSray prepare(1, f2, stb2.st_size, flags); 373eea21b3cSray 3743ad3fb45Sjoris prune(); 3753ad3fb45Sjoris sort(sfile[0], slen[0]); 3763ad3fb45Sjoris sort(sfile[1], slen[1]); 3773ad3fb45Sjoris 3783ad3fb45Sjoris member = (int *)file[1]; 3793ad3fb45Sjoris equiv(sfile[0], slen[0], sfile[1], slen[1], member); 38080566be2Sray member = xrealloc(member, slen[1] + 2, sizeof(*member)); 3813ad3fb45Sjoris 3823ad3fb45Sjoris class = (int *)file[0]; 3833ad3fb45Sjoris unsort(sfile[0], slen[0], class); 38480566be2Sray class = xrealloc(class, slen[0] + 2, sizeof(*class)); 3853ad3fb45Sjoris 3863ad3fb45Sjoris klist = xcalloc(slen[0] + 2, sizeof(*klist)); 3873ad3fb45Sjoris clen = 0; 3883ad3fb45Sjoris clistlen = 100; 3893ad3fb45Sjoris clist = xcalloc(clistlen, sizeof(*clist)); 390219c50abSray i = stone(class, slen[0], member, klist, flags); 3913ad3fb45Sjoris xfree(member); 3923ad3fb45Sjoris xfree(class); 3933ad3fb45Sjoris 394eea21b3cSray J = xrealloc(J, len[0] + 2, sizeof(*J)); 3953ad3fb45Sjoris unravel(klist[i]); 3963ad3fb45Sjoris xfree(clist); 3973ad3fb45Sjoris xfree(klist); 3983ad3fb45Sjoris 399eea21b3cSray ixold = xrealloc(ixold, len[0] + 2, sizeof(*ixold)); 400eea21b3cSray ixnew = xrealloc(ixnew, len[1] + 2, sizeof(*ixnew)); 401219c50abSray check(f1, f2, flags); 402219c50abSray output(f1, f2, flags); 4033ad3fb45Sjoris 4043ad3fb45Sjoris closem: 405eea21b3cSray if (anychange) { 4063ad3fb45Sjoris if (rval == D_SAME) 4073ad3fb45Sjoris rval = D_DIFFER; 4083ad3fb45Sjoris } 4093ad3fb45Sjoris if (f1 != NULL) 4103ad3fb45Sjoris fclose(f1); 4113ad3fb45Sjoris if (f2 != NULL) 4123ad3fb45Sjoris fclose(f2); 4133ad3fb45Sjoris 4143ad3fb45Sjoris return (rval); 4153ad3fb45Sjoris } 4163ad3fb45Sjoris 4173ad3fb45Sjoris /* 4183ad3fb45Sjoris * Check to see if the given files differ. 4193ad3fb45Sjoris * Returns 0 if they are the same, 1 if different, and -1 on error. 4203ad3fb45Sjoris * XXX - could use code from cmp(1) [faster] 4213ad3fb45Sjoris */ 4223ad3fb45Sjoris static int 4233ad3fb45Sjoris files_differ(FILE *f1, FILE *f2) 4243ad3fb45Sjoris { 4253ad3fb45Sjoris char buf1[BUFSIZ], buf2[BUFSIZ]; 4263ad3fb45Sjoris size_t i, j; 4273ad3fb45Sjoris 4283ad3fb45Sjoris if (stb1.st_size != stb2.st_size) 4293ad3fb45Sjoris return (1); 4303ad3fb45Sjoris for (;;) { 431a304c0f4Sray i = fread(buf1, 1, sizeof(buf1), f1); 432a304c0f4Sray j = fread(buf2, 1, sizeof(buf2), f2); 43309523d6fSray if ((!i && ferror(f1)) || (!j && ferror(f2))) 43409523d6fSray return (-1); 4353ad3fb45Sjoris if (i != j) 4363ad3fb45Sjoris return (1); 43709523d6fSray if (i == 0) 4383ad3fb45Sjoris return (0); 4393ad3fb45Sjoris if (memcmp(buf1, buf2, i) != 0) 4403ad3fb45Sjoris return (1); 4413ad3fb45Sjoris } 4423ad3fb45Sjoris } 4433ad3fb45Sjoris 444eea21b3cSray static void 445219c50abSray prepare(int i, FILE *fd, off_t filesize, int flags) 4463ad3fb45Sjoris { 4473ad3fb45Sjoris struct line *p; 4483ad3fb45Sjoris int j, h; 4493ad3fb45Sjoris size_t sz; 4503ad3fb45Sjoris 4513ad3fb45Sjoris rewind(fd); 4523ad3fb45Sjoris 453a304c0f4Sray sz = (filesize <= SIZE_MAX ? filesize : SIZE_MAX) / 25; 4543ad3fb45Sjoris if (sz < 100) 4553ad3fb45Sjoris sz = 100; 4563ad3fb45Sjoris 4573ad3fb45Sjoris p = xcalloc(sz + 3, sizeof(*p)); 458219c50abSray for (j = 0; (h = readhash(fd, flags));) { 459eea21b3cSray if (j == sz) { 4603ad3fb45Sjoris sz = sz * 3 / 2; 46180566be2Sray p = xrealloc(p, sz + 3, sizeof(*p)); 4623ad3fb45Sjoris } 4633ad3fb45Sjoris p[++j].value = h; 4643ad3fb45Sjoris } 465eea21b3cSray len[i] = j; 4663ad3fb45Sjoris file[i] = p; 4673ad3fb45Sjoris } 4683ad3fb45Sjoris 4693ad3fb45Sjoris static void 4703ad3fb45Sjoris prune(void) 4713ad3fb45Sjoris { 4723ad3fb45Sjoris int i, j; 4733ad3fb45Sjoris 474eea21b3cSray for (pref = 0; pref < len[0] && pref < len[1] && 4753ad3fb45Sjoris file[0][pref + 1].value == file[1][pref + 1].value; 4763ad3fb45Sjoris pref++) 4773ad3fb45Sjoris ; 478eea21b3cSray for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 479eea21b3cSray file[0][len[0] - suff].value == file[1][len[1] - suff].value; 4803ad3fb45Sjoris suff++) 4813ad3fb45Sjoris ; 4823ad3fb45Sjoris for (j = 0; j < 2; j++) { 4833ad3fb45Sjoris sfile[j] = file[j] + pref; 484eea21b3cSray slen[j] = len[j] - pref - suff; 4853ad3fb45Sjoris for (i = 0; i <= slen[j]; i++) 4863ad3fb45Sjoris sfile[j][i].serial = i; 4873ad3fb45Sjoris } 4883ad3fb45Sjoris } 4893ad3fb45Sjoris 4903ad3fb45Sjoris static void 4913ad3fb45Sjoris equiv(struct line *a, int n, struct line *b, int m, int *c) 4923ad3fb45Sjoris { 4933ad3fb45Sjoris int i, j; 4943ad3fb45Sjoris 4953ad3fb45Sjoris i = j = 1; 4963ad3fb45Sjoris while (i <= n && j <= m) { 4973ad3fb45Sjoris if (a[i].value < b[j].value) 4983ad3fb45Sjoris a[i++].value = 0; 4993ad3fb45Sjoris else if (a[i].value == b[j].value) 5003ad3fb45Sjoris a[i++].value = j; 5013ad3fb45Sjoris else 5023ad3fb45Sjoris j++; 5033ad3fb45Sjoris } 5043ad3fb45Sjoris while (i <= n) 5053ad3fb45Sjoris a[i++].value = 0; 5063ad3fb45Sjoris b[m + 1].value = 0; 5073ad3fb45Sjoris j = 0; 5083ad3fb45Sjoris while (++j <= m) { 5093ad3fb45Sjoris c[j] = -b[j].serial; 5103ad3fb45Sjoris while (b[j + 1].value == b[j].value) { 5113ad3fb45Sjoris j++; 5123ad3fb45Sjoris c[j] = b[j].serial; 5133ad3fb45Sjoris } 5143ad3fb45Sjoris } 5153ad3fb45Sjoris c[j] = -1; 5163ad3fb45Sjoris } 5173ad3fb45Sjoris 5183ad3fb45Sjoris /* Code taken from ping.c */ 5193ad3fb45Sjoris static int 5203ad3fb45Sjoris isqrt(int n) 5213ad3fb45Sjoris { 5223ad3fb45Sjoris int y, x = 1; 5233ad3fb45Sjoris 5243ad3fb45Sjoris if (n == 0) 5253ad3fb45Sjoris return (0); 5263ad3fb45Sjoris 5273ad3fb45Sjoris do { /* newton was a stinker */ 5283ad3fb45Sjoris y = x; 5293ad3fb45Sjoris x = n / x; 5303ad3fb45Sjoris x += y; 5313ad3fb45Sjoris x /= 2; 532eea21b3cSray } while ((x - y) > 1 || (x - y) < -1); 5333ad3fb45Sjoris 5343ad3fb45Sjoris return (x); 5353ad3fb45Sjoris } 5363ad3fb45Sjoris 5373ad3fb45Sjoris static int 538219c50abSray stone(int *a, int n, int *b, int *c, int flags) 5393ad3fb45Sjoris { 5403ad3fb45Sjoris int i, k, y, j, l; 5413ad3fb45Sjoris int oldc, tc, oldl; 5423ad3fb45Sjoris u_int numtries; 5433ad3fb45Sjoris 5443ad3fb45Sjoris /* XXX move the isqrt() out of the macro to avoid multiple calls */ 545219c50abSray const u_int bound = (flags & D_MINIMAL) ? UINT_MAX : 54657003866Sray MAX(256, isqrt(n)); 5473ad3fb45Sjoris 5483ad3fb45Sjoris k = 0; 549eea21b3cSray c[0] = newcand(0, 0, 0); 5503ad3fb45Sjoris for (i = 1; i <= n; i++) { 5513ad3fb45Sjoris j = a[i]; 5523ad3fb45Sjoris if (j == 0) 5533ad3fb45Sjoris continue; 5543ad3fb45Sjoris y = -b[j]; 5553ad3fb45Sjoris oldl = 0; 5563ad3fb45Sjoris oldc = c[0]; 5573ad3fb45Sjoris numtries = 0; 5583ad3fb45Sjoris do { 5593ad3fb45Sjoris if (y <= clist[oldc].y) 5603ad3fb45Sjoris continue; 5613ad3fb45Sjoris l = search(c, k, y); 5623ad3fb45Sjoris if (l != oldl + 1) 5633ad3fb45Sjoris oldc = c[l - 1]; 5643ad3fb45Sjoris if (l <= k) { 5653ad3fb45Sjoris if (clist[c[l]].y <= y) 5663ad3fb45Sjoris continue; 5673ad3fb45Sjoris tc = c[l]; 568eea21b3cSray c[l] = newcand(i, y, oldc); 5693ad3fb45Sjoris oldc = tc; 5703ad3fb45Sjoris oldl = l; 5713ad3fb45Sjoris numtries++; 5723ad3fb45Sjoris } else { 573eea21b3cSray c[l] = newcand(i, y, oldc); 5743ad3fb45Sjoris k++; 5753ad3fb45Sjoris break; 5763ad3fb45Sjoris } 5773ad3fb45Sjoris } while ((y = b[++j]) > 0 && numtries < bound); 5783ad3fb45Sjoris } 5793ad3fb45Sjoris return (k); 5803ad3fb45Sjoris } 5813ad3fb45Sjoris 5823ad3fb45Sjoris static int 5833ad3fb45Sjoris newcand(int x, int y, int pred) 5843ad3fb45Sjoris { 58580566be2Sray struct cand *q; 5863ad3fb45Sjoris 5873ad3fb45Sjoris if (clen == clistlen) { 588f74aa433Sray clistlen = clistlen * 11 / 10; 589f74aa433Sray clist = xrealloc(clist, clistlen, sizeof(*clist)); 5903ad3fb45Sjoris } 5913ad3fb45Sjoris q = clist + clen; 5923ad3fb45Sjoris q->x = x; 5933ad3fb45Sjoris q->y = y; 5943ad3fb45Sjoris q->pred = pred; 5953ad3fb45Sjoris return (clen++); 5963ad3fb45Sjoris } 5973ad3fb45Sjoris 5983ad3fb45Sjoris static int 5993ad3fb45Sjoris search(int *c, int k, int y) 6003ad3fb45Sjoris { 6013ad3fb45Sjoris int i, j, l, t; 6023ad3fb45Sjoris 6033ad3fb45Sjoris if (clist[c[k]].y < y) /* quick look for typical case */ 6043ad3fb45Sjoris return (k + 1); 6053ad3fb45Sjoris i = 0; 6063ad3fb45Sjoris j = k + 1; 6073ad3fb45Sjoris for (;;) { 6083ad3fb45Sjoris l = (i + j) / 2; 6093ad3fb45Sjoris if (l <= i) 6103ad3fb45Sjoris break; 6113ad3fb45Sjoris t = clist[c[l]].y; 6123ad3fb45Sjoris if (t > y) 6133ad3fb45Sjoris j = l; 6143ad3fb45Sjoris else if (t < y) 6153ad3fb45Sjoris i = l; 6163ad3fb45Sjoris else 6173ad3fb45Sjoris return (l); 6183ad3fb45Sjoris } 6193ad3fb45Sjoris return (l + 1); 6203ad3fb45Sjoris } 6213ad3fb45Sjoris 6223ad3fb45Sjoris static void 6233ad3fb45Sjoris unravel(int p) 6243ad3fb45Sjoris { 6253ad3fb45Sjoris struct cand *q; 6263ad3fb45Sjoris int i; 6273ad3fb45Sjoris 628eea21b3cSray for (i = 0; i <= len[0]; i++) 6293ad3fb45Sjoris J[i] = i <= pref ? i : 630eea21b3cSray i > len[0] - suff ? i + len[1] - len[0] : 0; 6313ad3fb45Sjoris for (q = clist + p; q->y != 0; q = clist + q->pred) 6323ad3fb45Sjoris J[q->x + pref] = q->y + pref; 6333ad3fb45Sjoris } 6343ad3fb45Sjoris 6353ad3fb45Sjoris /* 6363ad3fb45Sjoris * Check does double duty: 6373ad3fb45Sjoris * 1. ferret out any fortuitous correspondences due 6383ad3fb45Sjoris * to confounding by hashing (which result in "jackpot") 6393ad3fb45Sjoris * 2. collect random access indexes to the two files 6403ad3fb45Sjoris */ 6413ad3fb45Sjoris static void 642219c50abSray check(FILE *f1, FILE *f2, int flags) 6433ad3fb45Sjoris { 6443ad3fb45Sjoris int i, j, jackpot, c, d; 6453ad3fb45Sjoris long ctold, ctnew; 6463ad3fb45Sjoris 6473ad3fb45Sjoris rewind(f1); 6483ad3fb45Sjoris rewind(f2); 6493ad3fb45Sjoris j = 1; 6503ad3fb45Sjoris ixold[0] = ixnew[0] = 0; 6513ad3fb45Sjoris jackpot = 0; 6523ad3fb45Sjoris ctold = ctnew = 0; 653eea21b3cSray for (i = 1; i <= len[0]; i++) { 6543ad3fb45Sjoris if (J[i] == 0) { 6553ad3fb45Sjoris ixold[i] = ctold += skipline(f1); 6563ad3fb45Sjoris continue; 6573ad3fb45Sjoris } 6583ad3fb45Sjoris while (j < J[i]) { 6593ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 6603ad3fb45Sjoris j++; 6613ad3fb45Sjoris } 662219c50abSray if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE)) { 6633ad3fb45Sjoris for (;;) { 6643ad3fb45Sjoris c = getc(f1); 6653ad3fb45Sjoris d = getc(f2); 6663ad3fb45Sjoris /* 6673ad3fb45Sjoris * GNU diff ignores a missing newline 668eea21b3cSray * in one file for -b or -w. 6693ad3fb45Sjoris */ 670219c50abSray if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) && 6713ad3fb45Sjoris ((c == EOF && d == '\n') || 6723ad3fb45Sjoris (c == '\n' && d == EOF))) { 6733ad3fb45Sjoris break; 6743ad3fb45Sjoris } 6753ad3fb45Sjoris ctold++; 6763ad3fb45Sjoris ctnew++; 677219c50abSray if ((flags & D_FOLDBLANKS) && isspace(c) && 678219c50abSray isspace(d)) { 6793ad3fb45Sjoris do { 6803ad3fb45Sjoris if (c == '\n') 6813ad3fb45Sjoris break; 6823ad3fb45Sjoris ctold++; 6833ad3fb45Sjoris } while (isspace(c = getc(f1))); 6843ad3fb45Sjoris do { 6853ad3fb45Sjoris if (d == '\n') 6863ad3fb45Sjoris break; 6873ad3fb45Sjoris ctnew++; 6883ad3fb45Sjoris } while (isspace(d = getc(f2))); 689219c50abSray } else if ((flags & D_IGNOREBLANKS)) { 6903ad3fb45Sjoris while (isspace(c) && c != '\n') { 6913ad3fb45Sjoris c = getc(f1); 6923ad3fb45Sjoris ctold++; 6933ad3fb45Sjoris } 6943ad3fb45Sjoris while (isspace(d) && d != '\n') { 6953ad3fb45Sjoris d = getc(f2); 6963ad3fb45Sjoris ctnew++; 6973ad3fb45Sjoris } 6983ad3fb45Sjoris } 6993ad3fb45Sjoris if (chrtran[c] != chrtran[d]) { 7003ad3fb45Sjoris jackpot++; 7013ad3fb45Sjoris J[i] = 0; 7023ad3fb45Sjoris if (c != '\n' && c != EOF) 7033ad3fb45Sjoris ctold += skipline(f1); 7043ad3fb45Sjoris if (d != '\n' && c != EOF) 7053ad3fb45Sjoris ctnew += skipline(f2); 7063ad3fb45Sjoris break; 7073ad3fb45Sjoris } 7083ad3fb45Sjoris if (c == '\n' || c == EOF) 7093ad3fb45Sjoris break; 7103ad3fb45Sjoris } 7113ad3fb45Sjoris } else { 7123ad3fb45Sjoris for (;;) { 7133ad3fb45Sjoris ctold++; 7143ad3fb45Sjoris ctnew++; 7153ad3fb45Sjoris if ((c = getc(f1)) != (d = getc(f2))) { 7163ad3fb45Sjoris /* jackpot++; */ 7173ad3fb45Sjoris J[i] = 0; 7183ad3fb45Sjoris if (c != '\n' && c != EOF) 7193ad3fb45Sjoris ctold += skipline(f1); 7203ad3fb45Sjoris if (d != '\n' && c != EOF) 7213ad3fb45Sjoris ctnew += skipline(f2); 7223ad3fb45Sjoris break; 7233ad3fb45Sjoris } 7243ad3fb45Sjoris if (c == '\n' || c == EOF) 7253ad3fb45Sjoris break; 7263ad3fb45Sjoris } 7273ad3fb45Sjoris } 7283ad3fb45Sjoris ixold[i] = ctold; 7293ad3fb45Sjoris ixnew[j] = ctnew; 7303ad3fb45Sjoris j++; 7313ad3fb45Sjoris } 732eea21b3cSray for (; j <= len[1]; j++) 7333ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 7343ad3fb45Sjoris /* 735eea21b3cSray * if (jackpot) 736eea21b3cSray * fprintf(stderr, "jackpot\n"); 7373ad3fb45Sjoris */ 7383ad3fb45Sjoris } 7393ad3fb45Sjoris 7403ad3fb45Sjoris /* shellsort CACM #201 */ 7413ad3fb45Sjoris static void 7423ad3fb45Sjoris sort(struct line *a, int n) 7433ad3fb45Sjoris { 7443ad3fb45Sjoris struct line *ai, *aim, w; 7453ad3fb45Sjoris int j, m = 0, k; 7463ad3fb45Sjoris 7473ad3fb45Sjoris if (n == 0) 7483ad3fb45Sjoris return; 7493ad3fb45Sjoris for (j = 1; j <= n; j *= 2) 7503ad3fb45Sjoris m = 2 * j - 1; 7513ad3fb45Sjoris for (m /= 2; m != 0; m /= 2) { 7523ad3fb45Sjoris k = n - m; 7533ad3fb45Sjoris for (j = 1; j <= k; j++) { 7543ad3fb45Sjoris for (ai = &a[j]; ai > a; ai -= m) { 7553ad3fb45Sjoris aim = &ai[m]; 7563ad3fb45Sjoris if (aim < ai) 7573ad3fb45Sjoris break; /* wraparound */ 7583ad3fb45Sjoris if (aim->value > ai[0].value || 7593ad3fb45Sjoris (aim->value == ai[0].value && 7603ad3fb45Sjoris aim->serial > ai[0].serial)) 7613ad3fb45Sjoris break; 7623ad3fb45Sjoris w.value = ai[0].value; 7633ad3fb45Sjoris ai[0].value = aim->value; 7643ad3fb45Sjoris aim->value = w.value; 7653ad3fb45Sjoris w.serial = ai[0].serial; 7663ad3fb45Sjoris ai[0].serial = aim->serial; 7673ad3fb45Sjoris aim->serial = w.serial; 7683ad3fb45Sjoris } 7693ad3fb45Sjoris } 7703ad3fb45Sjoris } 7713ad3fb45Sjoris } 7723ad3fb45Sjoris 7733ad3fb45Sjoris static void 7743ad3fb45Sjoris unsort(struct line *f, int l, int *b) 7753ad3fb45Sjoris { 7763ad3fb45Sjoris int *a, i; 7773ad3fb45Sjoris 7783ad3fb45Sjoris a = xcalloc(l + 1, sizeof(*a)); 7793ad3fb45Sjoris for (i = 1; i <= l; i++) 7803ad3fb45Sjoris a[f[i].serial] = f[i].value; 7813ad3fb45Sjoris for (i = 1; i <= l; i++) 7823ad3fb45Sjoris b[i] = a[i]; 7833ad3fb45Sjoris xfree(a); 7843ad3fb45Sjoris } 7853ad3fb45Sjoris 7863ad3fb45Sjoris static int 7873ad3fb45Sjoris skipline(FILE *f) 7883ad3fb45Sjoris { 7893ad3fb45Sjoris int i, c; 7903ad3fb45Sjoris 7913ad3fb45Sjoris for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 7923ad3fb45Sjoris continue; 7933ad3fb45Sjoris return (i); 7943ad3fb45Sjoris } 7953ad3fb45Sjoris 7963ad3fb45Sjoris static void 797219c50abSray output(FILE *f1, FILE *f2, int flags) 7983ad3fb45Sjoris { 7993ad3fb45Sjoris int m, i0, i1, j0, j1; 8003ad3fb45Sjoris 8013ad3fb45Sjoris rewind(f1); 8023ad3fb45Sjoris rewind(f2); 803eea21b3cSray m = len[0]; 8043ad3fb45Sjoris J[0] = 0; 805eea21b3cSray J[m + 1] = len[1] + 1; 8063ad3fb45Sjoris for (i0 = 1; i0 <= m; i0 = i1 + 1) { 8073ad3fb45Sjoris while (i0 <= m && J[i0] == J[i0 - 1] + 1) 8083ad3fb45Sjoris i0++; 8093ad3fb45Sjoris j0 = J[i0 - 1] + 1; 8103ad3fb45Sjoris i1 = i0 - 1; 8113ad3fb45Sjoris while (i1 < m && J[i1 + 1] == 0) 8123ad3fb45Sjoris i1++; 8133ad3fb45Sjoris j1 = J[i1 + 1] - 1; 8143ad3fb45Sjoris J[i1] = j1; 815219c50abSray change(f1, f2, i0, i1, j0, j1, flags); 8163ad3fb45Sjoris } 8173ad3fb45Sjoris if (m == 0) 818219c50abSray change(f1, f2, 1, 0, 1, len[1], flags); 8193ad3fb45Sjoris if (diff_format == D_IFDEF) { 8203ad3fb45Sjoris for (;;) { 8213ad3fb45Sjoris #define c i0 8223ad3fb45Sjoris if ((c = getc(f1)) == EOF) 8233ad3fb45Sjoris return; 8243ad3fb45Sjoris diff_output("%c", c); 8253ad3fb45Sjoris } 8263ad3fb45Sjoris #undef c 8273ad3fb45Sjoris } 8283ad3fb45Sjoris if (anychange != 0) { 8293ad3fb45Sjoris if (diff_format == D_CONTEXT) 830219c50abSray dump_context_vec(f1, f2, flags); 8313ad3fb45Sjoris else if (diff_format == D_UNIFIED) 832219c50abSray dump_unified_vec(f1, f2, flags); 8333ad3fb45Sjoris } 8343ad3fb45Sjoris } 8353ad3fb45Sjoris 836a304c0f4Sray static void 8373ad3fb45Sjoris range(int a, int b, char *separator) 8383ad3fb45Sjoris { 8393ad3fb45Sjoris diff_output("%d", a > b ? b : a); 8403ad3fb45Sjoris if (a < b) 8413ad3fb45Sjoris diff_output("%s%d", separator, b); 8423ad3fb45Sjoris } 8433ad3fb45Sjoris 844a304c0f4Sray static void 8453ad3fb45Sjoris uni_range(int a, int b) 8463ad3fb45Sjoris { 8473ad3fb45Sjoris if (a < b) 8483ad3fb45Sjoris diff_output("%d,%d", a, b - a + 1); 8493ad3fb45Sjoris else if (a == b) 8503ad3fb45Sjoris diff_output("%d", b); 8513ad3fb45Sjoris else 8523ad3fb45Sjoris diff_output("%d,0", b); 8533ad3fb45Sjoris } 8543ad3fb45Sjoris 8553ad3fb45Sjoris static char * 8563ad3fb45Sjoris preadline(int fd, size_t rlen, off_t off) 8573ad3fb45Sjoris { 8583ad3fb45Sjoris char *line; 8593ad3fb45Sjoris ssize_t nr; 8603ad3fb45Sjoris 8613ad3fb45Sjoris line = xmalloc(rlen + 1); 8627a6efebcSray if ((nr = pread(fd, line, rlen, off)) < 0) 8637a6efebcSray fatal("preadline: %s", strerror(errno)); 8643ad3fb45Sjoris line[nr] = '\0'; 8653ad3fb45Sjoris return (line); 8663ad3fb45Sjoris } 8673ad3fb45Sjoris 8683ad3fb45Sjoris static int 8693ad3fb45Sjoris ignoreline(char *line) 8703ad3fb45Sjoris { 8713ad3fb45Sjoris int ret; 8723ad3fb45Sjoris 873a304c0f4Sray ret = regexec(&ignore_re, line, 0, NULL, 0); 8743ad3fb45Sjoris xfree(line); 8753ad3fb45Sjoris return (ret == 0); /* if it matched, it should be ignored. */ 8763ad3fb45Sjoris } 8773ad3fb45Sjoris 878fd660bf2Stobias static void 879fd660bf2Stobias diff_head(void) 880fd660bf2Stobias { 881fd660bf2Stobias char buf[64]; 8826534056aStobias struct tm t; 883fd660bf2Stobias time_t curr_time; 884fd660bf2Stobias 885fd660bf2Stobias if (diff_rev1 != NULL) { 8866534056aStobias gmtime_r(&stb1.st_mtime, &t); 887fd660bf2Stobias } else { 888fd660bf2Stobias time(&curr_time); 8896534056aStobias localtime_r(&curr_time, &t); 890fd660bf2Stobias } 891fd660bf2Stobias 8926534056aStobias (void)strftime(buf, sizeof(buf), "%b %G %H:%M:%S -0000", &t); 893d00c0f9eStobias diff_output("%s %s %d %s", diff_format == D_CONTEXT ? 8946534056aStobias "***" : "---", diff_file1, t.tm_mday, buf); 895fd660bf2Stobias 896fd660bf2Stobias if (diff_rev1 != NULL) { 897fd660bf2Stobias rcsnum_tostr(diff_rev1, buf, sizeof(buf)); 898fd660bf2Stobias diff_output("\t%s", buf); 899fd660bf2Stobias } 900fd660bf2Stobias 901fd660bf2Stobias diff_output("\n"); 902fd660bf2Stobias 9036534056aStobias gmtime_r(&stb2.st_mtime, &t); 904fd660bf2Stobias 9056534056aStobias (void)strftime(buf, sizeof(buf), "%b %G %H:%M:%S -0000", &t); 906d00c0f9eStobias diff_output("%s %s %d %s", diff_format == D_CONTEXT ? 9076534056aStobias "---" : "+++", diff_file2, t.tm_mday, buf); 908fd660bf2Stobias 909fd660bf2Stobias if (diff_rev2 != NULL) { 910fd660bf2Stobias rcsnum_tostr(diff_rev2, buf, sizeof(buf)); 911fd660bf2Stobias diff_output("\t%s", buf); 912fd660bf2Stobias } 913fd660bf2Stobias 914fd660bf2Stobias diff_output("\n"); 915fd660bf2Stobias } 916fd660bf2Stobias 917fd660bf2Stobias static void 918fd660bf2Stobias rdiff_head(void) 919fd660bf2Stobias { 920fd660bf2Stobias char buf[64]; 9216534056aStobias struct tm t; 922fd660bf2Stobias time_t curr_time; 923fd660bf2Stobias 924fd660bf2Stobias diff_output("%s ", diff_format == D_CONTEXT ? "***" : "---"); 925fd660bf2Stobias 926fd660bf2Stobias if (diff_rev1 == NULL) { 927fd660bf2Stobias diff_output("%s", CVS_PATH_DEVNULL); 9286534056aStobias gmtime_r(&stb1.st_atime, &t); 929fd660bf2Stobias } else { 930fd660bf2Stobias rcsnum_tostr(diff_rev1, buf, sizeof(buf)); 931be756b91Stobias diff_output("%s:%s", diff_file1, buf); 93245ea4f19Stobias localtime_r(&stb1.st_mtime, &t); 933fd660bf2Stobias } 934fd660bf2Stobias 9356534056aStobias (void)strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %G", &t); 936fd660bf2Stobias diff_output("\t%s\n", buf); 937fd660bf2Stobias 938fd660bf2Stobias if (diff_rev2 != NULL) { 9396534056aStobias localtime_r(&stb2.st_mtime, &t); 940fd660bf2Stobias } else { 941fd660bf2Stobias time(&curr_time); 9426534056aStobias localtime_r(&curr_time, &t); 943fd660bf2Stobias } 944fd660bf2Stobias 9456534056aStobias (void)strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %G", &t); 946fd660bf2Stobias 947fd660bf2Stobias diff_output("%s %s %s\n", diff_format == D_CONTEXT ? "---" : "+++", 948be756b91Stobias diff_file2, buf); 949fd660bf2Stobias } 950fd660bf2Stobias 9513ad3fb45Sjoris /* 9523ad3fb45Sjoris * Indicate that there is a difference between lines a and b of the from file 9533ad3fb45Sjoris * to get to lines c to d of the to file. If a is greater then b then there 9543ad3fb45Sjoris * are no lines in the from file involved and this means that there were 9553ad3fb45Sjoris * lines appended (beginning at b). If c is greater than d then there are 9563ad3fb45Sjoris * lines missing from the to file. 9573ad3fb45Sjoris */ 9583ad3fb45Sjoris static void 959219c50abSray change(FILE *f1, FILE *f2, int a, int b, int c, int d, int flags) 9603ad3fb45Sjoris { 9613ad3fb45Sjoris static size_t max_context = 64; 962eea21b3cSray int i; 9633ad3fb45Sjoris 9643ad3fb45Sjoris if (diff_format != D_IFDEF && a > b && c > d) 9653ad3fb45Sjoris return; 9663ad3fb45Sjoris if (ignore_pats != NULL) { 9673ad3fb45Sjoris char *line; 9683ad3fb45Sjoris /* 9693ad3fb45Sjoris * All lines in the change, insert, or delete must 9703ad3fb45Sjoris * match an ignore pattern for the change to be 9713ad3fb45Sjoris * ignored. 9723ad3fb45Sjoris */ 9733ad3fb45Sjoris if (a <= b) { /* Changes and deletes. */ 9743ad3fb45Sjoris for (i = a; i <= b; i++) { 9753ad3fb45Sjoris line = preadline(fileno(f1), 9763ad3fb45Sjoris ixold[i] - ixold[i - 1], ixold[i - 1]); 9773ad3fb45Sjoris if (!ignoreline(line)) 9783ad3fb45Sjoris goto proceed; 9793ad3fb45Sjoris } 9803ad3fb45Sjoris } 9813ad3fb45Sjoris if (a > b || c <= d) { /* Changes and inserts. */ 9823ad3fb45Sjoris for (i = c; i <= d; i++) { 9833ad3fb45Sjoris line = preadline(fileno(f2), 9843ad3fb45Sjoris ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 9853ad3fb45Sjoris if (!ignoreline(line)) 9863ad3fb45Sjoris goto proceed; 9873ad3fb45Sjoris } 9883ad3fb45Sjoris } 9893ad3fb45Sjoris return; 9903ad3fb45Sjoris } 9913ad3fb45Sjoris proceed: 9923ad3fb45Sjoris if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 9933ad3fb45Sjoris /* 9943ad3fb45Sjoris * Allocate change records as needed. 9953ad3fb45Sjoris */ 9963ad3fb45Sjoris if (context_vec_ptr == context_vec_end - 1) { 9973ad3fb45Sjoris ptrdiff_t offset = context_vec_ptr - context_vec_start; 9983ad3fb45Sjoris max_context <<= 1; 99980566be2Sray context_vec_start = xrealloc(context_vec_start, 100080566be2Sray max_context, sizeof(*context_vec_start)); 10013ad3fb45Sjoris context_vec_end = context_vec_start + max_context; 10023ad3fb45Sjoris context_vec_ptr = context_vec_start + offset; 10033ad3fb45Sjoris } 10043ad3fb45Sjoris if (anychange == 0) { 10053ad3fb45Sjoris /* 10063ad3fb45Sjoris * Print the context/unidiff header first time through. 10073ad3fb45Sjoris */ 1008fd660bf2Stobias if (cvs_cmdop == CVS_OP_RDIFF) 1009fd660bf2Stobias rdiff_head(); 1010fd660bf2Stobias else 1011fd660bf2Stobias diff_head(); 10123ad3fb45Sjoris 10133ad3fb45Sjoris anychange = 1; 10143ad3fb45Sjoris } else if (a > context_vec_ptr->b + (2 * context) + 1 && 10153ad3fb45Sjoris c > context_vec_ptr->d + (2 * context) + 1) { 10163ad3fb45Sjoris /* 10173ad3fb45Sjoris * If this change is more than 'context' lines from the 10183ad3fb45Sjoris * previous change, dump the record and reset it. 10193ad3fb45Sjoris */ 10203ad3fb45Sjoris if (diff_format == D_CONTEXT) 1021219c50abSray dump_context_vec(f1, f2, flags); 10223ad3fb45Sjoris else 1023219c50abSray dump_unified_vec(f1, f2, flags); 10243ad3fb45Sjoris } 10253ad3fb45Sjoris context_vec_ptr++; 10263ad3fb45Sjoris context_vec_ptr->a = a; 10273ad3fb45Sjoris context_vec_ptr->b = b; 10283ad3fb45Sjoris context_vec_ptr->c = c; 10293ad3fb45Sjoris context_vec_ptr->d = d; 10303ad3fb45Sjoris return; 10313ad3fb45Sjoris } 10323ad3fb45Sjoris if (anychange == 0) 10333ad3fb45Sjoris anychange = 1; 10343ad3fb45Sjoris switch (diff_format) { 10353ad3fb45Sjoris case D_BRIEF: 10363ad3fb45Sjoris return; 10373ad3fb45Sjoris case D_NORMAL: 10383ad3fb45Sjoris range(a, b, ","); 10393ad3fb45Sjoris diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 10403ad3fb45Sjoris if (diff_format == D_NORMAL) 10413ad3fb45Sjoris range(c, d, ","); 10423ad3fb45Sjoris diff_output("\n"); 10433ad3fb45Sjoris break; 10443ad3fb45Sjoris case D_RCSDIFF: 10453ad3fb45Sjoris if (a > b) 10463ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 10473ad3fb45Sjoris else { 10483ad3fb45Sjoris diff_output("d%d %d\n", a, b - a + 1); 10493ad3fb45Sjoris 10503ad3fb45Sjoris if (!(c > d)) /* add changed lines */ 10513ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 10523ad3fb45Sjoris } 10533ad3fb45Sjoris break; 10543ad3fb45Sjoris } 10553ad3fb45Sjoris if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 1056219c50abSray fetch(ixold, a, b, f1, '<', 1, flags); 10573ad3fb45Sjoris if (a <= b && c <= d && diff_format == D_NORMAL) 10583ad3fb45Sjoris diff_output("---\n"); 10593ad3fb45Sjoris } 1060219c50abSray fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, flags); 10613ad3fb45Sjoris if (inifdef) { 10623ad3fb45Sjoris diff_output("#endif /* %s */\n", ifdefname); 10633ad3fb45Sjoris inifdef = 0; 10643ad3fb45Sjoris } 10653ad3fb45Sjoris } 10663ad3fb45Sjoris 10673ad3fb45Sjoris static void 1068219c50abSray fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) 10693ad3fb45Sjoris { 10703ad3fb45Sjoris long j, nc; 10713ad3fb45Sjoris int i, c, col; 10723ad3fb45Sjoris 10733ad3fb45Sjoris /* 10743ad3fb45Sjoris * When doing #ifdef's, copy down to current line 10753ad3fb45Sjoris * if this is the first file, so that stuff makes it to output. 10763ad3fb45Sjoris */ 10773ad3fb45Sjoris if (diff_format == D_IFDEF && oldfile) { 10783ad3fb45Sjoris long curpos = ftell(lb); 10793ad3fb45Sjoris /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 10803ad3fb45Sjoris nc = f[a > b ? b : a - 1] - curpos; 10813ad3fb45Sjoris for (i = 0; i < nc; i++) 10823ad3fb45Sjoris diff_output("%c", getc(lb)); 10833ad3fb45Sjoris } 10843ad3fb45Sjoris if (a > b) 10853ad3fb45Sjoris return; 10863ad3fb45Sjoris if (diff_format == D_IFDEF) { 10873ad3fb45Sjoris if (inifdef) { 10883ad3fb45Sjoris diff_output("#else /* %s%s */\n", 10893ad3fb45Sjoris oldfile == 1 ? "!" : "", ifdefname); 10903ad3fb45Sjoris } else { 10913ad3fb45Sjoris if (oldfile) 10923ad3fb45Sjoris diff_output("#ifndef %s\n", ifdefname); 10933ad3fb45Sjoris else 10943ad3fb45Sjoris diff_output("#ifdef %s\n", ifdefname); 10953ad3fb45Sjoris } 10963ad3fb45Sjoris inifdef = 1 + oldfile; 10973ad3fb45Sjoris } 10983ad3fb45Sjoris for (i = a; i <= b; i++) { 10993ad3fb45Sjoris fseek(lb, f[i - 1], SEEK_SET); 11003ad3fb45Sjoris nc = f[i] - f[i - 1]; 11013ad3fb45Sjoris if (diff_format != D_IFDEF && ch != '\0') { 11023ad3fb45Sjoris diff_output("%c", ch); 11033ad3fb45Sjoris if (Tflag == 1 && (diff_format == D_NORMAL || 11043ad3fb45Sjoris diff_format == D_CONTEXT || 11053ad3fb45Sjoris diff_format == D_UNIFIED)) 11063ad3fb45Sjoris diff_output("\t"); 11073ad3fb45Sjoris else if (diff_format != D_UNIFIED) 11083ad3fb45Sjoris diff_output(" "); 11093ad3fb45Sjoris } 11103ad3fb45Sjoris col = 0; 11113ad3fb45Sjoris for (j = 0; j < nc; j++) { 11123ad3fb45Sjoris if ((c = getc(lb)) == EOF) { 11133ad3fb45Sjoris if (diff_format == D_RCSDIFF) 11143ad3fb45Sjoris cvs_log(LP_ERR, 11153ad3fb45Sjoris "No newline at end of file"); 11163ad3fb45Sjoris else 11173ad3fb45Sjoris diff_output("\n\\ No newline at end of " 111825d5ee6bSjoris "file\n"); 11193ad3fb45Sjoris return; 11203ad3fb45Sjoris } 1121219c50abSray if (c == '\t' && (flags & D_EXPANDTABS)) { 11223ad3fb45Sjoris do { 11233ad3fb45Sjoris diff_output(" "); 11243ad3fb45Sjoris } while (++col & 7); 11253ad3fb45Sjoris } else { 11263ad3fb45Sjoris diff_output("%c", c); 11273ad3fb45Sjoris col++; 11283ad3fb45Sjoris } 11293ad3fb45Sjoris } 11303ad3fb45Sjoris } 11313ad3fb45Sjoris } 11323ad3fb45Sjoris 11333ad3fb45Sjoris /* 11343ad3fb45Sjoris * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 11353ad3fb45Sjoris */ 11363ad3fb45Sjoris static int 1137219c50abSray readhash(FILE *f, int flags) 11383ad3fb45Sjoris { 11393ad3fb45Sjoris int i, t, space; 11403ad3fb45Sjoris int sum; 11413ad3fb45Sjoris 11423ad3fb45Sjoris sum = 1; 11433ad3fb45Sjoris space = 0; 1144219c50abSray if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) { 1145219c50abSray if (flags & D_IGNORECASE) 11463ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 11473ad3fb45Sjoris if (t == EOF) { 11483ad3fb45Sjoris if (i == 0) 11493ad3fb45Sjoris return (0); 11503ad3fb45Sjoris break; 11513ad3fb45Sjoris } 11523ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 11533ad3fb45Sjoris } 11543ad3fb45Sjoris else 11553ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 11563ad3fb45Sjoris if (t == EOF) { 11573ad3fb45Sjoris if (i == 0) 11583ad3fb45Sjoris return (0); 11593ad3fb45Sjoris break; 11603ad3fb45Sjoris } 11613ad3fb45Sjoris sum = sum * 127 + t; 11623ad3fb45Sjoris } 11633ad3fb45Sjoris } else { 11643ad3fb45Sjoris for (i = 0;;) { 11653ad3fb45Sjoris switch (t = getc(f)) { 11663ad3fb45Sjoris case '\t': 1167eea21b3cSray case '\r': 1168eea21b3cSray case '\v': 1169eea21b3cSray case '\f': 11703ad3fb45Sjoris case ' ': 11713ad3fb45Sjoris space++; 11723ad3fb45Sjoris continue; 11733ad3fb45Sjoris default: 1174219c50abSray if (space && (flags & D_IGNOREBLANKS) == 0) { 11753ad3fb45Sjoris i++; 11763ad3fb45Sjoris space = 0; 11773ad3fb45Sjoris } 11783ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 11793ad3fb45Sjoris i++; 11803ad3fb45Sjoris continue; 11813ad3fb45Sjoris case EOF: 11823ad3fb45Sjoris if (i == 0) 11833ad3fb45Sjoris return (0); 11843ad3fb45Sjoris /* FALLTHROUGH */ 11853ad3fb45Sjoris case '\n': 11863ad3fb45Sjoris break; 11873ad3fb45Sjoris } 11883ad3fb45Sjoris break; 11893ad3fb45Sjoris } 11903ad3fb45Sjoris } 11913ad3fb45Sjoris /* 11923ad3fb45Sjoris * There is a remote possibility that we end up with a zero sum. 11933ad3fb45Sjoris * Zero is used as an EOF marker, so return 1 instead. 11943ad3fb45Sjoris */ 11953ad3fb45Sjoris return (sum == 0 ? 1 : sum); 11963ad3fb45Sjoris } 11973ad3fb45Sjoris 11983ad3fb45Sjoris static int 11993ad3fb45Sjoris asciifile(FILE *f) 12003ad3fb45Sjoris { 1201eea21b3cSray unsigned char buf[BUFSIZ]; 12023ad3fb45Sjoris size_t i, cnt; 12033ad3fb45Sjoris 1204219c50abSray if (f == NULL) 12053ad3fb45Sjoris return (1); 12063ad3fb45Sjoris 12073ad3fb45Sjoris rewind(f); 1208a304c0f4Sray cnt = fread(buf, 1, sizeof(buf), f); 12093ad3fb45Sjoris for (i = 0; i < cnt; i++) 12103ad3fb45Sjoris if (!isprint(buf[i]) && !isspace(buf[i])) 12113ad3fb45Sjoris return (0); 12123ad3fb45Sjoris return (1); 12133ad3fb45Sjoris } 12143ad3fb45Sjoris 1215e22e6974Sxsa #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) 1216e22e6974Sxsa 12173ad3fb45Sjoris static char * 12183ad3fb45Sjoris match_function(const long *f, int pos, FILE *fp) 12193ad3fb45Sjoris { 12203ad3fb45Sjoris unsigned char buf[FUNCTION_CONTEXT_SIZE]; 12213ad3fb45Sjoris size_t nc; 12223ad3fb45Sjoris int last = lastline; 1223e22e6974Sxsa char *state = NULL; 12243ad3fb45Sjoris 12253ad3fb45Sjoris lastline = pos; 12263ad3fb45Sjoris while (pos > last) { 12273ad3fb45Sjoris fseek(fp, f[pos - 1], SEEK_SET); 12283ad3fb45Sjoris nc = f[pos] - f[pos - 1]; 12293ad3fb45Sjoris if (nc >= sizeof(buf)) 12303ad3fb45Sjoris nc = sizeof(buf) - 1; 1231a304c0f4Sray nc = fread(buf, 1, nc, fp); 12323ad3fb45Sjoris if (nc > 0) { 12333ad3fb45Sjoris buf[nc] = '\0'; 123457003866Sray buf[strcspn(buf, "\n")] = '\0'; 12353ad3fb45Sjoris if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 1236e22e6974Sxsa if (begins_with(buf, "private:")) { 1237e22e6974Sxsa if (!state) 1238e22e6974Sxsa state = " (private)"; 1239e22e6974Sxsa } else if (begins_with(buf, "protected:")) { 1240e22e6974Sxsa if (!state) 1241e22e6974Sxsa state = " (protected)"; 1242e22e6974Sxsa } else if (begins_with(buf, "public:")) { 1243e22e6974Sxsa if (!state) 1244e22e6974Sxsa state = " (public)"; 1245e22e6974Sxsa } else { 124657003866Sray strlcpy(lastbuf, buf, sizeof lastbuf); 1247e22e6974Sxsa if (state) 1248e22e6974Sxsa strlcat(lastbuf, state, 1249e22e6974Sxsa sizeof lastbuf); 12503ad3fb45Sjoris lastmatchline = pos; 12513ad3fb45Sjoris return lastbuf; 12523ad3fb45Sjoris } 12533ad3fb45Sjoris } 1254e22e6974Sxsa } 12553ad3fb45Sjoris pos--; 12563ad3fb45Sjoris } 1257eea21b3cSray return lastmatchline > 0 ? lastbuf : NULL; 12583ad3fb45Sjoris } 12593ad3fb45Sjoris 12603ad3fb45Sjoris /* dump accumulated "context" diff changes */ 12613ad3fb45Sjoris static void 1262219c50abSray dump_context_vec(FILE *f1, FILE *f2, int flags) 12633ad3fb45Sjoris { 12643ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 12653ad3fb45Sjoris int lowa, upb, lowc, upd, do_output; 12663ad3fb45Sjoris int a, b, c, d; 12673ad3fb45Sjoris char ch, *f; 12683ad3fb45Sjoris 12693ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 12703ad3fb45Sjoris return; 12713ad3fb45Sjoris 12723ad3fb45Sjoris b = d = 0; /* gcc */ 12733ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 1274eea21b3cSray upb = MIN(len[0], context_vec_ptr->b + context); 12753ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 1276eea21b3cSray upd = MIN(len[1], context_vec_ptr->d + context); 12773ad3fb45Sjoris 12783ad3fb45Sjoris diff_output("***************"); 1279219c50abSray if ((flags & D_PROTOTYPE)) { 12803ad3fb45Sjoris f = match_function(ixold, lowa-1, f1); 1281*d5d01609Sray if (f != NULL) 12823ad3fb45Sjoris diff_output(" %s", f); 12833ad3fb45Sjoris } 12843ad3fb45Sjoris diff_output("\n*** "); 12853ad3fb45Sjoris range(lowa, upb, ","); 12863ad3fb45Sjoris diff_output(" ****\n"); 12873ad3fb45Sjoris 12883ad3fb45Sjoris /* 12893ad3fb45Sjoris * Output changes to the "old" file. The first loop suppresses 12903ad3fb45Sjoris * output if there were no changes to the "old" file (we'll see 12913ad3fb45Sjoris * the "old" lines as context in the "new" list). 12923ad3fb45Sjoris */ 12933ad3fb45Sjoris do_output = 0; 12943ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) 12953ad3fb45Sjoris if (cvp->a <= cvp->b) { 12963ad3fb45Sjoris cvp = context_vec_start; 12973ad3fb45Sjoris do_output++; 12983ad3fb45Sjoris break; 12993ad3fb45Sjoris } 1300eea21b3cSray if (do_output) { 13013ad3fb45Sjoris while (cvp <= context_vec_ptr) { 13023ad3fb45Sjoris a = cvp->a; 13033ad3fb45Sjoris b = cvp->b; 13043ad3fb45Sjoris c = cvp->c; 13053ad3fb45Sjoris d = cvp->d; 13063ad3fb45Sjoris 13073ad3fb45Sjoris if (a <= b && c <= d) 13083ad3fb45Sjoris ch = 'c'; 13093ad3fb45Sjoris else 13103ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 13113ad3fb45Sjoris 13123ad3fb45Sjoris if (ch == 'a') 1313219c50abSray fetch(ixold, lowa, b, f1, ' ', 0, flags); 13143ad3fb45Sjoris else { 1315219c50abSray fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 13163ad3fb45Sjoris fetch(ixold, a, b, f1, 1317219c50abSray ch == 'c' ? '!' : '-', 0, flags); 13183ad3fb45Sjoris } 13193ad3fb45Sjoris lowa = b + 1; 13203ad3fb45Sjoris cvp++; 13213ad3fb45Sjoris } 1322219c50abSray fetch(ixold, b + 1, upb, f1, ' ', 0, flags); 13233ad3fb45Sjoris } 13243ad3fb45Sjoris /* output changes to the "new" file */ 13253ad3fb45Sjoris diff_output("--- "); 13263ad3fb45Sjoris range(lowc, upd, ","); 13273ad3fb45Sjoris diff_output(" ----\n"); 13283ad3fb45Sjoris 13293ad3fb45Sjoris do_output = 0; 13303ad3fb45Sjoris for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 13313ad3fb45Sjoris if (cvp->c <= cvp->d) { 13323ad3fb45Sjoris cvp = context_vec_start; 13333ad3fb45Sjoris do_output++; 13343ad3fb45Sjoris break; 13353ad3fb45Sjoris } 1336eea21b3cSray if (do_output) { 13373ad3fb45Sjoris while (cvp <= context_vec_ptr) { 13383ad3fb45Sjoris a = cvp->a; 13393ad3fb45Sjoris b = cvp->b; 13403ad3fb45Sjoris c = cvp->c; 13413ad3fb45Sjoris d = cvp->d; 13423ad3fb45Sjoris 13433ad3fb45Sjoris if (a <= b && c <= d) 13443ad3fb45Sjoris ch = 'c'; 13453ad3fb45Sjoris else 13463ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 13473ad3fb45Sjoris 13483ad3fb45Sjoris if (ch == 'd') 1349219c50abSray fetch(ixnew, lowc, d, f2, ' ', 0, flags); 13503ad3fb45Sjoris else { 1351219c50abSray fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); 13523ad3fb45Sjoris fetch(ixnew, c, d, f2, 1353219c50abSray ch == 'c' ? '!' : '+', 0, flags); 13543ad3fb45Sjoris } 13553ad3fb45Sjoris lowc = d + 1; 13563ad3fb45Sjoris cvp++; 13573ad3fb45Sjoris } 1358219c50abSray fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); 13593ad3fb45Sjoris } 13603ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 13613ad3fb45Sjoris } 13623ad3fb45Sjoris 13633ad3fb45Sjoris /* dump accumulated "unified" diff changes */ 13643ad3fb45Sjoris static void 1365219c50abSray dump_unified_vec(FILE *f1, FILE *f2, int flags) 13663ad3fb45Sjoris { 13673ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 13683ad3fb45Sjoris int lowa, upb, lowc, upd; 13693ad3fb45Sjoris int a, b, c, d; 13703ad3fb45Sjoris char ch, *f; 13713ad3fb45Sjoris 13723ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 13733ad3fb45Sjoris return; 13743ad3fb45Sjoris 13753ad3fb45Sjoris b = d = 0; /* gcc */ 13763ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 1377eea21b3cSray upb = MIN(len[0], context_vec_ptr->b + context); 13783ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 1379eea21b3cSray upd = MIN(len[1], context_vec_ptr->d + context); 13803ad3fb45Sjoris 13813ad3fb45Sjoris diff_output("@@ -"); 13823ad3fb45Sjoris uni_range(lowa, upb); 13833ad3fb45Sjoris diff_output(" +"); 13843ad3fb45Sjoris uni_range(lowc, upd); 13853ad3fb45Sjoris diff_output(" @@"); 1386219c50abSray if ((flags & D_PROTOTYPE)) { 13873ad3fb45Sjoris f = match_function(ixold, lowa-1, f1); 1388*d5d01609Sray if (f != NULL) 13893ad3fb45Sjoris diff_output(" %s", f); 13903ad3fb45Sjoris } 13913ad3fb45Sjoris diff_output("\n"); 13923ad3fb45Sjoris 13933ad3fb45Sjoris /* 13943ad3fb45Sjoris * Output changes in "unified" diff format--the old and new lines 13953ad3fb45Sjoris * are printed together. 13963ad3fb45Sjoris */ 13973ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) { 13983ad3fb45Sjoris a = cvp->a; 13993ad3fb45Sjoris b = cvp->b; 14003ad3fb45Sjoris c = cvp->c; 14013ad3fb45Sjoris d = cvp->d; 14023ad3fb45Sjoris 14033ad3fb45Sjoris /* 14043ad3fb45Sjoris * c: both new and old changes 14053ad3fb45Sjoris * d: only changes in the old file 14063ad3fb45Sjoris * a: only changes in the new file 14073ad3fb45Sjoris */ 14083ad3fb45Sjoris if (a <= b && c <= d) 14093ad3fb45Sjoris ch = 'c'; 14103ad3fb45Sjoris else 14113ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 14123ad3fb45Sjoris 14133ad3fb45Sjoris switch (ch) { 14143ad3fb45Sjoris case 'c': 1415219c50abSray fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 1416219c50abSray fetch(ixold, a, b, f1, '-', 0, flags); 1417219c50abSray fetch(ixnew, c, d, f2, '+', 0, flags); 14183ad3fb45Sjoris break; 14193ad3fb45Sjoris case 'd': 1420219c50abSray fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 1421219c50abSray fetch(ixold, a, b, f1, '-', 0, flags); 14223ad3fb45Sjoris break; 14233ad3fb45Sjoris case 'a': 1424219c50abSray fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); 1425219c50abSray fetch(ixnew, c, d, f2, '+', 0, flags); 14263ad3fb45Sjoris break; 14273ad3fb45Sjoris } 14283ad3fb45Sjoris lowa = b + 1; 14293ad3fb45Sjoris lowc = d + 1; 14303ad3fb45Sjoris } 1431219c50abSray fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); 14323ad3fb45Sjoris 14333ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 14343ad3fb45Sjoris } 14353ad3fb45Sjoris 14363ad3fb45Sjoris void 14373ad3fb45Sjoris diff_output(const char *fmt, ...) 14383ad3fb45Sjoris { 14393ad3fb45Sjoris va_list vap; 14403ad3fb45Sjoris int i; 14413ad3fb45Sjoris char *str; 14423ad3fb45Sjoris 14433ad3fb45Sjoris va_start(vap, fmt); 14443ad3fb45Sjoris i = vasprintf(&str, fmt, vap); 14453ad3fb45Sjoris va_end(vap); 14463ad3fb45Sjoris if (i == -1) 14479a0ecc80Stobias fatal("diff_output: could not allocate memory"); 14483ad3fb45Sjoris if (diffbuf != NULL) 14490a2f95d0Stobias cvs_buf_puts(diffbuf, str); 14503ad3fb45Sjoris else 14513ad3fb45Sjoris cvs_printf("%s", str); 14523ad3fb45Sjoris xfree(str); 14533ad3fb45Sjoris } 1454