1*80566be2Sray /* $OpenBSD: diff_internals.c,v 1.9 2007/05/29 00:19:10 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 */ 663ad3fb45Sjoris /* 673ad3fb45Sjoris * Uses an algorithm due to Harold Stone, which finds 683ad3fb45Sjoris * a pair of longest identical subsequences in the two 693ad3fb45Sjoris * files. 703ad3fb45Sjoris * 713ad3fb45Sjoris * The major goal is to generate the match vector J. 723ad3fb45Sjoris * J[i] is the index of the line in file1 corresponding 733ad3fb45Sjoris * to line i file0. J[i] = 0 if there is no 743ad3fb45Sjoris * such line in file1. 753ad3fb45Sjoris * 763ad3fb45Sjoris * Lines are hashed so as to work in core. All potential 773ad3fb45Sjoris * matches are located by sorting the lines of each file 783ad3fb45Sjoris * on the hash (called ``value''). In particular, this 793ad3fb45Sjoris * collects the equivalence classes in file1 together. 803ad3fb45Sjoris * Subroutine equiv replaces the value of each line in 813ad3fb45Sjoris * file0 by the index of the first element of its 823ad3fb45Sjoris * matching equivalence in (the reordered) file1. 833ad3fb45Sjoris * To save space equiv squeezes file1 into a single 843ad3fb45Sjoris * array member in which the equivalence classes 853ad3fb45Sjoris * are simply concatenated, except that their first 863ad3fb45Sjoris * members are flagged by changing sign. 873ad3fb45Sjoris * 883ad3fb45Sjoris * Next the indices that point into member are unsorted into 893ad3fb45Sjoris * array class according to the original order of file0. 903ad3fb45Sjoris * 913ad3fb45Sjoris * The cleverness lies in routine stone. This marches 923ad3fb45Sjoris * through the lines of file0, developing a vector klist 933ad3fb45Sjoris * of "k-candidates". At step i a k-candidate is a matched 943ad3fb45Sjoris * pair of lines x,y (x in file0 y in file1) such that 953ad3fb45Sjoris * there is a common subsequence of length k 963ad3fb45Sjoris * between the first i lines of file0 and the first y 973ad3fb45Sjoris * lines of file1, but there is no such subsequence for 983ad3fb45Sjoris * any smaller y. x is the earliest possible mate to y 993ad3fb45Sjoris * that occurs in such a subsequence. 1003ad3fb45Sjoris * 1013ad3fb45Sjoris * Whenever any of the members of the equivalence class of 1023ad3fb45Sjoris * lines in file1 matable to a line in file0 has serial number 1033ad3fb45Sjoris * less than the y of some k-candidate, that k-candidate 1043ad3fb45Sjoris * with the smallest such y is replaced. The new 1053ad3fb45Sjoris * k-candidate is chained (via pred) to the current 1063ad3fb45Sjoris * k-1 candidate so that the actual subsequence can 1073ad3fb45Sjoris * be recovered. When a member has serial number greater 1083ad3fb45Sjoris * that the y of all k-candidates, the klist is extended. 1093ad3fb45Sjoris * At the end, the longest subsequence is pulled out 1103ad3fb45Sjoris * and placed in the array J by unravel 1113ad3fb45Sjoris * 1123ad3fb45Sjoris * With J in hand, the matches there recorded are 1133ad3fb45Sjoris * check'ed against reality to assure that no spurious 1143ad3fb45Sjoris * matches have crept in due to hashing. If they have, 1153ad3fb45Sjoris * they are broken, and "jackpot" is recorded--a harmless 1163ad3fb45Sjoris * matter except that a true match for a spuriously 1173ad3fb45Sjoris * mated line may now be unnecessarily reported as a change. 1183ad3fb45Sjoris * 1193ad3fb45Sjoris * Much of the complexity of the program comes simply 1203ad3fb45Sjoris * from trying to minimize core utilization and 1213ad3fb45Sjoris * maximize the range of doable problems by dynamically 1223ad3fb45Sjoris * allocating what is needed and reusing what is not. 1233ad3fb45Sjoris * The core requirements for problems larger than somewhat 1243ad3fb45Sjoris * are (in words) 2*length(file0) + length(file1) + 1253ad3fb45Sjoris * 3*(number of k-candidates installed), typically about 1263ad3fb45Sjoris * 6n words for files of length n. 1273ad3fb45Sjoris */ 1283ad3fb45Sjoris 1291f8531bdSotto #include <sys/stat.h> 1303ad3fb45Sjoris 1311f8531bdSotto #include <ctype.h> 1321f8531bdSotto #include <errno.h> 1331f8531bdSotto #include <regex.h> 1341f8531bdSotto #include <stddef.h> 1351f8531bdSotto #include <string.h> 1361f8531bdSotto #include <unistd.h> 1371f8531bdSotto 1383ad3fb45Sjoris #include "cvs.h" 1393ad3fb45Sjoris #include "diff.h" 1403ad3fb45Sjoris 1413ad3fb45Sjoris struct cand { 1423ad3fb45Sjoris int x; 1433ad3fb45Sjoris int y; 1443ad3fb45Sjoris int pred; 1453ad3fb45Sjoris } cand; 1463ad3fb45Sjoris 1473ad3fb45Sjoris struct line { 1483ad3fb45Sjoris int serial; 1493ad3fb45Sjoris int value; 1503ad3fb45Sjoris } *file[2]; 1513ad3fb45Sjoris 1523ad3fb45Sjoris /* 1533ad3fb45Sjoris * The following struct is used to record change information when 1543ad3fb45Sjoris * doing a "context" or "unified" diff. (see routine "change" to 1553ad3fb45Sjoris * understand the highly mnemonic field names) 1563ad3fb45Sjoris */ 1573ad3fb45Sjoris struct context_vec { 1583ad3fb45Sjoris int a; /* start line in old file */ 1593ad3fb45Sjoris int b; /* end line in old file */ 1603ad3fb45Sjoris int c; /* start line in new file */ 1613ad3fb45Sjoris int d; /* end line in new file */ 1623ad3fb45Sjoris }; 1633ad3fb45Sjoris 1643ad3fb45Sjoris struct diff_arg { 1653ad3fb45Sjoris char *rev1; 1663ad3fb45Sjoris char *rev2; 1673ad3fb45Sjoris char *date1; 1683ad3fb45Sjoris char *date2; 1693ad3fb45Sjoris }; 1703ad3fb45Sjoris 1713ad3fb45Sjoris static void output(FILE *, FILE *); 1723ad3fb45Sjoris static void check(FILE *, FILE *); 1733ad3fb45Sjoris static void range(int, int, char *); 1743ad3fb45Sjoris static void uni_range(int, int); 1753ad3fb45Sjoris static void dump_context_vec(FILE *, FILE *); 1763ad3fb45Sjoris static void dump_unified_vec(FILE *, FILE *); 1773ad3fb45Sjoris static int prepare(int, FILE *, off_t); 1783ad3fb45Sjoris static void prune(void); 1793ad3fb45Sjoris static void equiv(struct line *, int, struct line *, int, int *); 1803ad3fb45Sjoris static void unravel(int); 1813ad3fb45Sjoris static void unsort(struct line *, int, int *); 1823ad3fb45Sjoris static void change(FILE *, FILE *, int, int, int, int); 1833ad3fb45Sjoris static void sort(struct line *, int); 1843ad3fb45Sjoris static int ignoreline(char *); 1853ad3fb45Sjoris static int asciifile(FILE *); 1863ad3fb45Sjoris static void fetch(long *, int, int, FILE *, int, int); 1873ad3fb45Sjoris static int newcand(int, int, int); 1883ad3fb45Sjoris static int search(int *, int, int); 1893ad3fb45Sjoris static int skipline(FILE *); 1903ad3fb45Sjoris static int isqrt(int); 1913ad3fb45Sjoris static int stone(int *, int, int *, int *); 1923ad3fb45Sjoris static int readhash(FILE *); 1933ad3fb45Sjoris static int files_differ(FILE *, FILE *); 1943ad3fb45Sjoris static char *match_function(const long *, int, FILE *); 1953ad3fb45Sjoris static char *preadline(int, size_t, off_t); 1963ad3fb45Sjoris 197261cb0daSjoris static int aflag, bflag, dflag, iflag, tflag, Tflag, wflag; 1983ad3fb45Sjoris static int context = 3; 1993ad3fb45Sjoris int diff_format = D_NORMAL; 200261cb0daSjoris int diff_pflag = 0; 2013ad3fb45Sjoris char *diff_file = NULL; 2023ad3fb45Sjoris RCSNUM *diff_rev1 = NULL; 2033ad3fb45Sjoris RCSNUM *diff_rev2 = NULL; 2043ad3fb45Sjoris char diffargs[128]; 2053ad3fb45Sjoris static struct stat stb1, stb2; 2063ad3fb45Sjoris static char *ifdefname, *ignore_pats; 2073ad3fb45Sjoris regex_t ignore_re; 2083ad3fb45Sjoris 2093ad3fb45Sjoris static int *J; /* will be overlaid on class */ 2103ad3fb45Sjoris static int *class; /* will be overlaid on file[0] */ 2113ad3fb45Sjoris static int *klist; /* will be overlaid on file[0] after class */ 2123ad3fb45Sjoris static int *member; /* will be overlaid on file[1] */ 2133ad3fb45Sjoris static int clen; 2143ad3fb45Sjoris static int inifdef; /* whether or not we are in a #ifdef block */ 2153ad3fb45Sjoris static int diff_len[2]; 2163ad3fb45Sjoris static int pref, suff; /* length of prefix and suffix */ 2173ad3fb45Sjoris static int slen[2]; 2183ad3fb45Sjoris static int anychange; 2193ad3fb45Sjoris static long *ixnew; /* will be overlaid on file[1] */ 2203ad3fb45Sjoris static long *ixold; /* will be overlaid on klist */ 2213ad3fb45Sjoris static struct cand *clist; /* merely a free storage pot for candidates */ 2223ad3fb45Sjoris static int clistlen; /* the length of clist */ 2233ad3fb45Sjoris static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 2243ad3fb45Sjoris static u_char *chrtran; /* translation table for case-folding */ 2253ad3fb45Sjoris static struct context_vec *context_vec_start; 2263ad3fb45Sjoris static struct context_vec *context_vec_end; 2273ad3fb45Sjoris static struct context_vec *context_vec_ptr; 2283ad3fb45Sjoris 229e22e6974Sxsa #define FUNCTION_CONTEXT_SIZE 55 2303ad3fb45Sjoris static char lastbuf[FUNCTION_CONTEXT_SIZE]; 2313ad3fb45Sjoris static int lastline; 2323ad3fb45Sjoris static int lastmatchline; 2333ad3fb45Sjoris BUF *diffbuf = NULL; 2343ad3fb45Sjoris 2353ad3fb45Sjoris /* 2363ad3fb45Sjoris * chrtran points to one of 2 translation tables: cup2low if folding upper to 2373ad3fb45Sjoris * lower case clow2low if not folding case 2383ad3fb45Sjoris */ 2393ad3fb45Sjoris u_char clow2low[256] = { 2403ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2413ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2423ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2433ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2443ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2453ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 2463ad3fb45Sjoris 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 2473ad3fb45Sjoris 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 2483ad3fb45Sjoris 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 2493ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2503ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2513ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2523ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2533ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2543ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2553ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2563ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2573ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2583ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2593ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2603ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2613ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2623ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2633ad3fb45Sjoris 0xfd, 0xfe, 0xff 2643ad3fb45Sjoris }; 2653ad3fb45Sjoris 2663ad3fb45Sjoris u_char cup2low[256] = { 2673ad3fb45Sjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2683ad3fb45Sjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2693ad3fb45Sjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2703ad3fb45Sjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2713ad3fb45Sjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2723ad3fb45Sjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 2733ad3fb45Sjoris 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 2743ad3fb45Sjoris 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 2753ad3fb45Sjoris 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 2763ad3fb45Sjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2773ad3fb45Sjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2783ad3fb45Sjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2793ad3fb45Sjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2803ad3fb45Sjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2813ad3fb45Sjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2823ad3fb45Sjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2833ad3fb45Sjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2843ad3fb45Sjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2853ad3fb45Sjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2863ad3fb45Sjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2873ad3fb45Sjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2883ad3fb45Sjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2893ad3fb45Sjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2903ad3fb45Sjoris 0xfd, 0xfe, 0xff 2913ad3fb45Sjoris }; 2923ad3fb45Sjoris 2933ad3fb45Sjoris int 2943ad3fb45Sjoris cvs_diffreg(const char *file1, const char *file2, BUF *out) 2953ad3fb45Sjoris { 2963ad3fb45Sjoris FILE *f1, *f2; 2973ad3fb45Sjoris int i, rval; 2983ad3fb45Sjoris 2993ad3fb45Sjoris f1 = f2 = NULL; 3003ad3fb45Sjoris rval = D_SAME; 3013ad3fb45Sjoris anychange = 0; 3023ad3fb45Sjoris lastline = 0; 3033ad3fb45Sjoris lastmatchline = 0; 3043ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 3053ad3fb45Sjoris chrtran = (iflag ? cup2low : clow2low); 3063ad3fb45Sjoris if (out != NULL) 3073ad3fb45Sjoris diffbuf = out; 3083ad3fb45Sjoris 3093ad3fb45Sjoris f1 = fopen(file1, "r"); 3103ad3fb45Sjoris if (f1 == NULL) { 3113ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 3123ad3fb45Sjoris goto closem; 3133ad3fb45Sjoris } 3143ad3fb45Sjoris 3153ad3fb45Sjoris f2 = fopen(file2, "r"); 3163ad3fb45Sjoris if (f2 == NULL) { 3173ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 3183ad3fb45Sjoris goto closem; 3193ad3fb45Sjoris } 3203ad3fb45Sjoris 3213ad3fb45Sjoris if (stat(file1, &stb1) < 0) { 3223ad3fb45Sjoris cvs_log(LP_ERR, "%s", file1); 3233ad3fb45Sjoris goto closem; 3243ad3fb45Sjoris } 3253ad3fb45Sjoris if (stat(file2, &stb2) < 0) { 3263ad3fb45Sjoris cvs_log(LP_ERR, "%s", file2); 3273ad3fb45Sjoris goto closem; 3283ad3fb45Sjoris } 3293ad3fb45Sjoris switch (files_differ(f1, f2)) { 3303ad3fb45Sjoris case 0: 3313ad3fb45Sjoris goto closem; 3323ad3fb45Sjoris case 1: 3333ad3fb45Sjoris break; 3343ad3fb45Sjoris default: 3353ad3fb45Sjoris /* error */ 3363ad3fb45Sjoris goto closem; 3373ad3fb45Sjoris } 3383ad3fb45Sjoris 3393ad3fb45Sjoris if (!asciifile(f1) || !asciifile(f2)) { 3403ad3fb45Sjoris rval = D_BINARY; 3413ad3fb45Sjoris goto closem; 3423ad3fb45Sjoris } 3433ad3fb45Sjoris if (prepare(0, f1, stb1.st_size) < 0 || 3443ad3fb45Sjoris prepare(1, f2, stb2.st_size) < 0) { 3453ad3fb45Sjoris goto closem; 3463ad3fb45Sjoris } 3473ad3fb45Sjoris prune(); 3483ad3fb45Sjoris sort(sfile[0], slen[0]); 3493ad3fb45Sjoris sort(sfile[1], slen[1]); 3503ad3fb45Sjoris 3513ad3fb45Sjoris member = (int *)file[1]; 3523ad3fb45Sjoris equiv(sfile[0], slen[0], sfile[1], slen[1], member); 353*80566be2Sray member = xrealloc(member, slen[1] + 2, sizeof(*member)); 3543ad3fb45Sjoris 3553ad3fb45Sjoris class = (int *)file[0]; 3563ad3fb45Sjoris unsort(sfile[0], slen[0], class); 357*80566be2Sray class = xrealloc(class, slen[0] + 2, sizeof(*class)); 3583ad3fb45Sjoris 3593ad3fb45Sjoris klist = xcalloc(slen[0] + 2, sizeof(*klist)); 3603ad3fb45Sjoris clen = 0; 3613ad3fb45Sjoris clistlen = 100; 3623ad3fb45Sjoris clist = xcalloc(clistlen, sizeof(*clist)); 3633ad3fb45Sjoris 3643ad3fb45Sjoris if ((i = stone(class, slen[0], member, klist)) < 0) 3653ad3fb45Sjoris goto closem; 3663ad3fb45Sjoris 3673ad3fb45Sjoris xfree(member); 3683ad3fb45Sjoris xfree(class); 3693ad3fb45Sjoris 370*80566be2Sray J = xrealloc(J, diff_len[0] + 2, sizeof(*J)); 3713ad3fb45Sjoris unravel(klist[i]); 3723ad3fb45Sjoris xfree(clist); 3733ad3fb45Sjoris xfree(klist); 3743ad3fb45Sjoris 375*80566be2Sray ixold = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold)); 3763ad3fb45Sjoris 377*80566be2Sray ixnew = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew)); 3783ad3fb45Sjoris check(f1, f2); 3793ad3fb45Sjoris output(f1, f2); 3803ad3fb45Sjoris 3813ad3fb45Sjoris closem: 3823ad3fb45Sjoris if (anychange == 1) { 3833ad3fb45Sjoris if (rval == D_SAME) 3843ad3fb45Sjoris rval = D_DIFFER; 3853ad3fb45Sjoris } 3863ad3fb45Sjoris if (f1 != NULL) 3873ad3fb45Sjoris fclose(f1); 3883ad3fb45Sjoris if (f2 != NULL) 3893ad3fb45Sjoris fclose(f2); 3903ad3fb45Sjoris 3913ad3fb45Sjoris return (rval); 3923ad3fb45Sjoris } 3933ad3fb45Sjoris 3943ad3fb45Sjoris /* 3953ad3fb45Sjoris * Check to see if the given files differ. 3963ad3fb45Sjoris * Returns 0 if they are the same, 1 if different, and -1 on error. 3973ad3fb45Sjoris * XXX - could use code from cmp(1) [faster] 3983ad3fb45Sjoris */ 3993ad3fb45Sjoris static int 4003ad3fb45Sjoris files_differ(FILE *f1, FILE *f2) 4013ad3fb45Sjoris { 4023ad3fb45Sjoris char buf1[BUFSIZ], buf2[BUFSIZ]; 4033ad3fb45Sjoris size_t i, j; 4043ad3fb45Sjoris 4053ad3fb45Sjoris if (stb1.st_size != stb2.st_size) 4063ad3fb45Sjoris return (1); 4073ad3fb45Sjoris for (;;) { 4083ad3fb45Sjoris i = fread(buf1, (size_t)1, sizeof(buf1), f1); 4093ad3fb45Sjoris j = fread(buf2, (size_t)1, sizeof(buf2), f2); 4103ad3fb45Sjoris if (i != j) 4113ad3fb45Sjoris return (1); 4123ad3fb45Sjoris if (i == 0 && j == 0) { 4133ad3fb45Sjoris if (ferror(f1) || ferror(f2)) 4143ad3fb45Sjoris return (1); 4153ad3fb45Sjoris return (0); 4163ad3fb45Sjoris } 4173ad3fb45Sjoris if (memcmp(buf1, buf2, i) != 0) 4183ad3fb45Sjoris return (1); 4193ad3fb45Sjoris } 4203ad3fb45Sjoris } 4213ad3fb45Sjoris 4223ad3fb45Sjoris static int 4233ad3fb45Sjoris prepare(int i, FILE *fd, off_t filesize) 4243ad3fb45Sjoris { 4253ad3fb45Sjoris struct line *p; 4263ad3fb45Sjoris int j, h; 4273ad3fb45Sjoris size_t sz; 4283ad3fb45Sjoris 4293ad3fb45Sjoris rewind(fd); 4303ad3fb45Sjoris 4313ad3fb45Sjoris sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 4323ad3fb45Sjoris if (sz < 100) 4333ad3fb45Sjoris sz = 100; 4343ad3fb45Sjoris 4353ad3fb45Sjoris p = xcalloc(sz + 3, sizeof(*p)); 4363ad3fb45Sjoris for (j = 0; (h = readhash(fd));) { 4373ad3fb45Sjoris if (j == (int)sz) { 4383ad3fb45Sjoris sz = sz * 3 / 2; 439*80566be2Sray p = xrealloc(p, sz + 3, sizeof(*p)); 4403ad3fb45Sjoris } 4413ad3fb45Sjoris p[++j].value = h; 4423ad3fb45Sjoris } 4433ad3fb45Sjoris diff_len[i] = j; 4443ad3fb45Sjoris file[i] = p; 4453ad3fb45Sjoris 4463ad3fb45Sjoris return (0); 4473ad3fb45Sjoris } 4483ad3fb45Sjoris 4493ad3fb45Sjoris static void 4503ad3fb45Sjoris prune(void) 4513ad3fb45Sjoris { 4523ad3fb45Sjoris int i, j; 4533ad3fb45Sjoris 4543ad3fb45Sjoris for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 4553ad3fb45Sjoris file[0][pref + 1].value == file[1][pref + 1].value; 4563ad3fb45Sjoris pref++) 4573ad3fb45Sjoris ; 4583ad3fb45Sjoris for (suff = 0; 4593ad3fb45Sjoris (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 4603ad3fb45Sjoris (file[0][diff_len[0] - suff].value == 4613ad3fb45Sjoris file[1][diff_len[1] - suff].value); 4623ad3fb45Sjoris suff++) 4633ad3fb45Sjoris ; 4643ad3fb45Sjoris for (j = 0; j < 2; j++) { 4653ad3fb45Sjoris sfile[j] = file[j] + pref; 4663ad3fb45Sjoris slen[j] = diff_len[j] - pref - suff; 4673ad3fb45Sjoris for (i = 0; i <= slen[j]; i++) 4683ad3fb45Sjoris sfile[j][i].serial = i; 4693ad3fb45Sjoris } 4703ad3fb45Sjoris } 4713ad3fb45Sjoris 4723ad3fb45Sjoris static void 4733ad3fb45Sjoris equiv(struct line *a, int n, struct line *b, int m, int *c) 4743ad3fb45Sjoris { 4753ad3fb45Sjoris int i, j; 4763ad3fb45Sjoris 4773ad3fb45Sjoris i = j = 1; 4783ad3fb45Sjoris while (i <= n && j <= m) { 4793ad3fb45Sjoris if (a[i].value < b[j].value) 4803ad3fb45Sjoris a[i++].value = 0; 4813ad3fb45Sjoris else if (a[i].value == b[j].value) 4823ad3fb45Sjoris a[i++].value = j; 4833ad3fb45Sjoris else 4843ad3fb45Sjoris j++; 4853ad3fb45Sjoris } 4863ad3fb45Sjoris while (i <= n) 4873ad3fb45Sjoris a[i++].value = 0; 4883ad3fb45Sjoris b[m + 1].value = 0; 4893ad3fb45Sjoris j = 0; 4903ad3fb45Sjoris while (++j <= m) { 4913ad3fb45Sjoris c[j] = -b[j].serial; 4923ad3fb45Sjoris while (b[j + 1].value == b[j].value) { 4933ad3fb45Sjoris j++; 4943ad3fb45Sjoris c[j] = b[j].serial; 4953ad3fb45Sjoris } 4963ad3fb45Sjoris } 4973ad3fb45Sjoris c[j] = -1; 4983ad3fb45Sjoris } 4993ad3fb45Sjoris 5003ad3fb45Sjoris /* Code taken from ping.c */ 5013ad3fb45Sjoris static int 5023ad3fb45Sjoris isqrt(int n) 5033ad3fb45Sjoris { 5043ad3fb45Sjoris int y, x = 1; 5053ad3fb45Sjoris 5063ad3fb45Sjoris if (n == 0) 5073ad3fb45Sjoris return (0); 5083ad3fb45Sjoris 5093ad3fb45Sjoris do { /* newton was a stinker */ 5103ad3fb45Sjoris y = x; 5113ad3fb45Sjoris x = n / x; 5123ad3fb45Sjoris x += y; 5133ad3fb45Sjoris x /= 2; 5143ad3fb45Sjoris } while (x - y > 1 || x - y < -1); 5153ad3fb45Sjoris 5163ad3fb45Sjoris return (x); 5173ad3fb45Sjoris } 5183ad3fb45Sjoris 5193ad3fb45Sjoris static int 5203ad3fb45Sjoris stone(int *a, int n, int *b, int *c) 5213ad3fb45Sjoris { 5223ad3fb45Sjoris int ret; 5233ad3fb45Sjoris int i, k, y, j, l; 5243ad3fb45Sjoris int oldc, tc, oldl; 5253ad3fb45Sjoris u_int numtries; 5263ad3fb45Sjoris 5273ad3fb45Sjoris /* XXX move the isqrt() out of the macro to avoid multiple calls */ 5283ad3fb45Sjoris const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 5293ad3fb45Sjoris 5303ad3fb45Sjoris k = 0; 5313ad3fb45Sjoris if ((ret = newcand(0, 0, 0)) < 0) 5323ad3fb45Sjoris return (-1); 5333ad3fb45Sjoris c[0] = ret; 5343ad3fb45Sjoris for (i = 1; i <= n; i++) { 5353ad3fb45Sjoris j = a[i]; 5363ad3fb45Sjoris if (j == 0) 5373ad3fb45Sjoris continue; 5383ad3fb45Sjoris y = -b[j]; 5393ad3fb45Sjoris oldl = 0; 5403ad3fb45Sjoris oldc = c[0]; 5413ad3fb45Sjoris numtries = 0; 5423ad3fb45Sjoris do { 5433ad3fb45Sjoris if (y <= clist[oldc].y) 5443ad3fb45Sjoris continue; 5453ad3fb45Sjoris l = search(c, k, y); 5463ad3fb45Sjoris if (l != oldl + 1) 5473ad3fb45Sjoris oldc = c[l - 1]; 5483ad3fb45Sjoris if (l <= k) { 5493ad3fb45Sjoris if (clist[c[l]].y <= y) 5503ad3fb45Sjoris continue; 5513ad3fb45Sjoris tc = c[l]; 5523ad3fb45Sjoris if ((ret = newcand(i, y, oldc)) < 0) 5533ad3fb45Sjoris return (-1); 5543ad3fb45Sjoris c[l] = ret; 5553ad3fb45Sjoris oldc = tc; 5563ad3fb45Sjoris oldl = l; 5573ad3fb45Sjoris numtries++; 5583ad3fb45Sjoris } else { 5593ad3fb45Sjoris if ((ret = newcand(i, y, oldc)) < 0) 5603ad3fb45Sjoris return (-1); 5613ad3fb45Sjoris c[l] = ret; 5623ad3fb45Sjoris k++; 5633ad3fb45Sjoris break; 5643ad3fb45Sjoris } 5653ad3fb45Sjoris } while ((y = b[++j]) > 0 && numtries < bound); 5663ad3fb45Sjoris } 5673ad3fb45Sjoris return (k); 5683ad3fb45Sjoris } 5693ad3fb45Sjoris 5703ad3fb45Sjoris static int 5713ad3fb45Sjoris newcand(int x, int y, int pred) 5723ad3fb45Sjoris { 573*80566be2Sray struct cand *q; 5743ad3fb45Sjoris int newclistlen; 5753ad3fb45Sjoris 5763ad3fb45Sjoris if (clen == clistlen) { 5773ad3fb45Sjoris newclistlen = clistlen * 11 / 10; 578*80566be2Sray clist = xrealloc(clist, newclistlen, sizeof(*clist)); 5793ad3fb45Sjoris clistlen = newclistlen; 5803ad3fb45Sjoris } 5813ad3fb45Sjoris q = clist + clen; 5823ad3fb45Sjoris q->x = x; 5833ad3fb45Sjoris q->y = y; 5843ad3fb45Sjoris q->pred = pred; 5853ad3fb45Sjoris return (clen++); 5863ad3fb45Sjoris } 5873ad3fb45Sjoris 5883ad3fb45Sjoris static int 5893ad3fb45Sjoris search(int *c, int k, int y) 5903ad3fb45Sjoris { 5913ad3fb45Sjoris int i, j, l, t; 5923ad3fb45Sjoris 5933ad3fb45Sjoris if (clist[c[k]].y < y) /* quick look for typical case */ 5943ad3fb45Sjoris return (k + 1); 5953ad3fb45Sjoris i = 0; 5963ad3fb45Sjoris j = k + 1; 5973ad3fb45Sjoris for (;;) { 5983ad3fb45Sjoris l = (i + j) / 2; 5993ad3fb45Sjoris if (l <= i) 6003ad3fb45Sjoris break; 6013ad3fb45Sjoris t = clist[c[l]].y; 6023ad3fb45Sjoris if (t > y) 6033ad3fb45Sjoris j = l; 6043ad3fb45Sjoris else if (t < y) 6053ad3fb45Sjoris i = l; 6063ad3fb45Sjoris else 6073ad3fb45Sjoris return (l); 6083ad3fb45Sjoris } 6093ad3fb45Sjoris return (l + 1); 6103ad3fb45Sjoris } 6113ad3fb45Sjoris 6123ad3fb45Sjoris static void 6133ad3fb45Sjoris unravel(int p) 6143ad3fb45Sjoris { 6153ad3fb45Sjoris struct cand *q; 6163ad3fb45Sjoris int i; 6173ad3fb45Sjoris 6183ad3fb45Sjoris for (i = 0; i <= diff_len[0]; i++) 6193ad3fb45Sjoris J[i] = i <= pref ? i : 6203ad3fb45Sjoris i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 6213ad3fb45Sjoris for (q = clist + p; q->y != 0; q = clist + q->pred) 6223ad3fb45Sjoris J[q->x + pref] = q->y + pref; 6233ad3fb45Sjoris } 6243ad3fb45Sjoris 6253ad3fb45Sjoris /* 6263ad3fb45Sjoris * Check does double duty: 6273ad3fb45Sjoris * 1. ferret out any fortuitous correspondences due 6283ad3fb45Sjoris * to confounding by hashing (which result in "jackpot") 6293ad3fb45Sjoris * 2. collect random access indexes to the two files 6303ad3fb45Sjoris */ 6313ad3fb45Sjoris static void 6323ad3fb45Sjoris check(FILE *f1, FILE *f2) 6333ad3fb45Sjoris { 6343ad3fb45Sjoris int i, j, jackpot, c, d; 6353ad3fb45Sjoris long ctold, ctnew; 6363ad3fb45Sjoris 6373ad3fb45Sjoris rewind(f1); 6383ad3fb45Sjoris rewind(f2); 6393ad3fb45Sjoris j = 1; 6403ad3fb45Sjoris ixold[0] = ixnew[0] = 0; 6413ad3fb45Sjoris jackpot = 0; 6423ad3fb45Sjoris ctold = ctnew = 0; 6433ad3fb45Sjoris for (i = 1; i <= diff_len[0]; i++) { 6443ad3fb45Sjoris if (J[i] == 0) { 6453ad3fb45Sjoris ixold[i] = ctold += skipline(f1); 6463ad3fb45Sjoris continue; 6473ad3fb45Sjoris } 6483ad3fb45Sjoris while (j < J[i]) { 6493ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 6503ad3fb45Sjoris j++; 6513ad3fb45Sjoris } 6523ad3fb45Sjoris if (bflag == 1 || wflag == 1 || iflag == 1) { 6533ad3fb45Sjoris for (;;) { 6543ad3fb45Sjoris c = getc(f1); 6553ad3fb45Sjoris d = getc(f2); 6563ad3fb45Sjoris /* 6573ad3fb45Sjoris * GNU diff ignores a missing newline 6583ad3fb45Sjoris * in one file if bflag || wflag. 6593ad3fb45Sjoris */ 6603ad3fb45Sjoris if ((bflag == 1 || wflag == 1) && 6613ad3fb45Sjoris ((c == EOF && d == '\n') || 6623ad3fb45Sjoris (c == '\n' && d == EOF))) { 6633ad3fb45Sjoris break; 6643ad3fb45Sjoris } 6653ad3fb45Sjoris ctold++; 6663ad3fb45Sjoris ctnew++; 6673ad3fb45Sjoris if (bflag == 1 && isspace(c) && isspace(d)) { 6683ad3fb45Sjoris do { 6693ad3fb45Sjoris if (c == '\n') 6703ad3fb45Sjoris break; 6713ad3fb45Sjoris ctold++; 6723ad3fb45Sjoris } while (isspace(c = getc(f1))); 6733ad3fb45Sjoris do { 6743ad3fb45Sjoris if (d == '\n') 6753ad3fb45Sjoris break; 6763ad3fb45Sjoris ctnew++; 6773ad3fb45Sjoris } while (isspace(d = getc(f2))); 6783ad3fb45Sjoris } else if (wflag == 1) { 6793ad3fb45Sjoris while (isspace(c) && c != '\n') { 6803ad3fb45Sjoris c = getc(f1); 6813ad3fb45Sjoris ctold++; 6823ad3fb45Sjoris } 6833ad3fb45Sjoris while (isspace(d) && d != '\n') { 6843ad3fb45Sjoris d = getc(f2); 6853ad3fb45Sjoris ctnew++; 6863ad3fb45Sjoris } 6873ad3fb45Sjoris } 6883ad3fb45Sjoris if (chrtran[c] != chrtran[d]) { 6893ad3fb45Sjoris jackpot++; 6903ad3fb45Sjoris J[i] = 0; 6913ad3fb45Sjoris if (c != '\n' && c != EOF) 6923ad3fb45Sjoris ctold += skipline(f1); 6933ad3fb45Sjoris if (d != '\n' && c != EOF) 6943ad3fb45Sjoris ctnew += skipline(f2); 6953ad3fb45Sjoris break; 6963ad3fb45Sjoris } 6973ad3fb45Sjoris if (c == '\n' || c == EOF) 6983ad3fb45Sjoris break; 6993ad3fb45Sjoris } 7003ad3fb45Sjoris } else { 7013ad3fb45Sjoris for (;;) { 7023ad3fb45Sjoris ctold++; 7033ad3fb45Sjoris ctnew++; 7043ad3fb45Sjoris if ((c = getc(f1)) != (d = getc(f2))) { 7053ad3fb45Sjoris /* jackpot++; */ 7063ad3fb45Sjoris J[i] = 0; 7073ad3fb45Sjoris if (c != '\n' && c != EOF) 7083ad3fb45Sjoris ctold += skipline(f1); 7093ad3fb45Sjoris if (d != '\n' && c != EOF) 7103ad3fb45Sjoris ctnew += skipline(f2); 7113ad3fb45Sjoris break; 7123ad3fb45Sjoris } 7133ad3fb45Sjoris if (c == '\n' || c == EOF) 7143ad3fb45Sjoris break; 7153ad3fb45Sjoris } 7163ad3fb45Sjoris } 7173ad3fb45Sjoris ixold[i] = ctold; 7183ad3fb45Sjoris ixnew[j] = ctnew; 7193ad3fb45Sjoris j++; 7203ad3fb45Sjoris } 7213ad3fb45Sjoris for (; j <= diff_len[1]; j++) 7223ad3fb45Sjoris ixnew[j] = ctnew += skipline(f2); 7233ad3fb45Sjoris /* 7243ad3fb45Sjoris * if (jackpot != 0) 7253ad3fb45Sjoris * cvs_printf("jackpot\n"); 7263ad3fb45Sjoris */ 7273ad3fb45Sjoris } 7283ad3fb45Sjoris 7293ad3fb45Sjoris /* shellsort CACM #201 */ 7303ad3fb45Sjoris static void 7313ad3fb45Sjoris sort(struct line *a, int n) 7323ad3fb45Sjoris { 7333ad3fb45Sjoris struct line *ai, *aim, w; 7343ad3fb45Sjoris int j, m = 0, k; 7353ad3fb45Sjoris 7363ad3fb45Sjoris if (n == 0) 7373ad3fb45Sjoris return; 7383ad3fb45Sjoris for (j = 1; j <= n; j *= 2) 7393ad3fb45Sjoris m = 2 * j - 1; 7403ad3fb45Sjoris for (m /= 2; m != 0; m /= 2) { 7413ad3fb45Sjoris k = n - m; 7423ad3fb45Sjoris for (j = 1; j <= k; j++) { 7433ad3fb45Sjoris for (ai = &a[j]; ai > a; ai -= m) { 7443ad3fb45Sjoris aim = &ai[m]; 7453ad3fb45Sjoris if (aim < ai) 7463ad3fb45Sjoris break; /* wraparound */ 7473ad3fb45Sjoris if (aim->value > ai[0].value || 7483ad3fb45Sjoris (aim->value == ai[0].value && 7493ad3fb45Sjoris aim->serial > ai[0].serial)) 7503ad3fb45Sjoris break; 7513ad3fb45Sjoris w.value = ai[0].value; 7523ad3fb45Sjoris ai[0].value = aim->value; 7533ad3fb45Sjoris aim->value = w.value; 7543ad3fb45Sjoris w.serial = ai[0].serial; 7553ad3fb45Sjoris ai[0].serial = aim->serial; 7563ad3fb45Sjoris aim->serial = w.serial; 7573ad3fb45Sjoris } 7583ad3fb45Sjoris } 7593ad3fb45Sjoris } 7603ad3fb45Sjoris } 7613ad3fb45Sjoris 7623ad3fb45Sjoris static void 7633ad3fb45Sjoris unsort(struct line *f, int l, int *b) 7643ad3fb45Sjoris { 7653ad3fb45Sjoris int *a, i; 7663ad3fb45Sjoris 7673ad3fb45Sjoris a = xcalloc(l + 1, sizeof(*a)); 7683ad3fb45Sjoris for (i = 1; i <= l; i++) 7693ad3fb45Sjoris a[f[i].serial] = f[i].value; 7703ad3fb45Sjoris for (i = 1; i <= l; i++) 7713ad3fb45Sjoris b[i] = a[i]; 7723ad3fb45Sjoris xfree(a); 7733ad3fb45Sjoris } 7743ad3fb45Sjoris 7753ad3fb45Sjoris static int 7763ad3fb45Sjoris skipline(FILE *f) 7773ad3fb45Sjoris { 7783ad3fb45Sjoris int i, c; 7793ad3fb45Sjoris 7803ad3fb45Sjoris for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 7813ad3fb45Sjoris continue; 7823ad3fb45Sjoris return (i); 7833ad3fb45Sjoris } 7843ad3fb45Sjoris 7853ad3fb45Sjoris static void 7863ad3fb45Sjoris output(FILE *f1, FILE *f2) 7873ad3fb45Sjoris { 7883ad3fb45Sjoris int m, i0, i1, j0, j1; 7893ad3fb45Sjoris 7903ad3fb45Sjoris rewind(f1); 7913ad3fb45Sjoris rewind(f2); 7923ad3fb45Sjoris m = diff_len[0]; 7933ad3fb45Sjoris J[0] = 0; 7943ad3fb45Sjoris J[m + 1] = diff_len[1] + 1; 7953ad3fb45Sjoris for (i0 = 1; i0 <= m; i0 = i1 + 1) { 7963ad3fb45Sjoris while (i0 <= m && J[i0] == J[i0 - 1] + 1) 7973ad3fb45Sjoris i0++; 7983ad3fb45Sjoris j0 = J[i0 - 1] + 1; 7993ad3fb45Sjoris i1 = i0 - 1; 8003ad3fb45Sjoris while (i1 < m && J[i1 + 1] == 0) 8013ad3fb45Sjoris i1++; 8023ad3fb45Sjoris j1 = J[i1 + 1] - 1; 8033ad3fb45Sjoris J[i1] = j1; 8043ad3fb45Sjoris change(f1, f2, i0, i1, j0, j1); 8053ad3fb45Sjoris } 8063ad3fb45Sjoris if (m == 0) 8073ad3fb45Sjoris change(f1, f2, 1, 0, 1, diff_len[1]); 8083ad3fb45Sjoris if (diff_format == D_IFDEF) { 8093ad3fb45Sjoris for (;;) { 8103ad3fb45Sjoris #define c i0 8113ad3fb45Sjoris if ((c = getc(f1)) == EOF) 8123ad3fb45Sjoris return; 8133ad3fb45Sjoris diff_output("%c", c); 8143ad3fb45Sjoris } 8153ad3fb45Sjoris #undef c 8163ad3fb45Sjoris } 8173ad3fb45Sjoris if (anychange != 0) { 8183ad3fb45Sjoris if (diff_format == D_CONTEXT) 8193ad3fb45Sjoris dump_context_vec(f1, f2); 8203ad3fb45Sjoris else if (diff_format == D_UNIFIED) 8213ad3fb45Sjoris dump_unified_vec(f1, f2); 8223ad3fb45Sjoris } 8233ad3fb45Sjoris } 8243ad3fb45Sjoris 8253ad3fb45Sjoris static __inline void 8263ad3fb45Sjoris range(int a, int b, char *separator) 8273ad3fb45Sjoris { 8283ad3fb45Sjoris diff_output("%d", a > b ? b : a); 8293ad3fb45Sjoris if (a < b) 8303ad3fb45Sjoris diff_output("%s%d", separator, b); 8313ad3fb45Sjoris } 8323ad3fb45Sjoris 8333ad3fb45Sjoris static __inline void 8343ad3fb45Sjoris uni_range(int a, int b) 8353ad3fb45Sjoris { 8363ad3fb45Sjoris if (a < b) 8373ad3fb45Sjoris diff_output("%d,%d", a, b - a + 1); 8383ad3fb45Sjoris else if (a == b) 8393ad3fb45Sjoris diff_output("%d", b); 8403ad3fb45Sjoris else 8413ad3fb45Sjoris diff_output("%d,0", b); 8423ad3fb45Sjoris } 8433ad3fb45Sjoris 8443ad3fb45Sjoris static char * 8453ad3fb45Sjoris preadline(int fd, size_t rlen, off_t off) 8463ad3fb45Sjoris { 8473ad3fb45Sjoris char *line; 8483ad3fb45Sjoris ssize_t nr; 8493ad3fb45Sjoris 8503ad3fb45Sjoris line = xmalloc(rlen + 1); 8513ad3fb45Sjoris if ((nr = pread(fd, line, rlen, off)) < 0) { 8523ad3fb45Sjoris cvs_log(LP_ERR, "preadline failed"); 8533ad3fb45Sjoris return (NULL); 8543ad3fb45Sjoris } 8553ad3fb45Sjoris line[nr] = '\0'; 8563ad3fb45Sjoris return (line); 8573ad3fb45Sjoris } 8583ad3fb45Sjoris 8593ad3fb45Sjoris static int 8603ad3fb45Sjoris ignoreline(char *line) 8613ad3fb45Sjoris { 8623ad3fb45Sjoris int ret; 8633ad3fb45Sjoris 8643ad3fb45Sjoris ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); 8653ad3fb45Sjoris xfree(line); 8663ad3fb45Sjoris return (ret == 0); /* if it matched, it should be ignored. */ 8673ad3fb45Sjoris } 8683ad3fb45Sjoris 8693ad3fb45Sjoris /* 8703ad3fb45Sjoris * Indicate that there is a difference between lines a and b of the from file 8713ad3fb45Sjoris * to get to lines c to d of the to file. If a is greater then b then there 8723ad3fb45Sjoris * are no lines in the from file involved and this means that there were 8733ad3fb45Sjoris * lines appended (beginning at b). If c is greater than d then there are 8743ad3fb45Sjoris * lines missing from the to file. 8753ad3fb45Sjoris */ 8763ad3fb45Sjoris static void 8773ad3fb45Sjoris change(FILE *f1, FILE *f2, int a, int b, int c, int d) 8783ad3fb45Sjoris { 8793ad3fb45Sjoris int i; 8803ad3fb45Sjoris static size_t max_context = 64; 8813ad3fb45Sjoris char buf[64]; 8823ad3fb45Sjoris struct tm *t; 8833ad3fb45Sjoris 8843ad3fb45Sjoris if (diff_format != D_IFDEF && a > b && c > d) 8853ad3fb45Sjoris return; 8863ad3fb45Sjoris if (ignore_pats != NULL) { 8873ad3fb45Sjoris char *line; 8883ad3fb45Sjoris /* 8893ad3fb45Sjoris * All lines in the change, insert, or delete must 8903ad3fb45Sjoris * match an ignore pattern for the change to be 8913ad3fb45Sjoris * ignored. 8923ad3fb45Sjoris */ 8933ad3fb45Sjoris if (a <= b) { /* Changes and deletes. */ 8943ad3fb45Sjoris for (i = a; i <= b; i++) { 8953ad3fb45Sjoris line = preadline(fileno(f1), 8963ad3fb45Sjoris ixold[i] - ixold[i - 1], ixold[i - 1]); 8973ad3fb45Sjoris if (!ignoreline(line)) 8983ad3fb45Sjoris goto proceed; 8993ad3fb45Sjoris } 9003ad3fb45Sjoris } 9013ad3fb45Sjoris if (a > b || c <= d) { /* Changes and inserts. */ 9023ad3fb45Sjoris for (i = c; i <= d; i++) { 9033ad3fb45Sjoris line = preadline(fileno(f2), 9043ad3fb45Sjoris ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 9053ad3fb45Sjoris if (!ignoreline(line)) 9063ad3fb45Sjoris goto proceed; 9073ad3fb45Sjoris } 9083ad3fb45Sjoris } 9093ad3fb45Sjoris return; 9103ad3fb45Sjoris } 9113ad3fb45Sjoris proceed: 9123ad3fb45Sjoris if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 9133ad3fb45Sjoris /* 9143ad3fb45Sjoris * Allocate change records as needed. 9153ad3fb45Sjoris */ 9163ad3fb45Sjoris if (context_vec_ptr == context_vec_end - 1) { 9173ad3fb45Sjoris ptrdiff_t offset = context_vec_ptr - context_vec_start; 9183ad3fb45Sjoris max_context <<= 1; 919*80566be2Sray context_vec_start = xrealloc(context_vec_start, 920*80566be2Sray max_context, sizeof(*context_vec_start)); 9213ad3fb45Sjoris context_vec_end = context_vec_start + max_context; 9223ad3fb45Sjoris context_vec_ptr = context_vec_start + offset; 9233ad3fb45Sjoris } 9243ad3fb45Sjoris if (anychange == 0) { 9253ad3fb45Sjoris /* 9263ad3fb45Sjoris * Print the context/unidiff header first time through. 9273ad3fb45Sjoris */ 9283ad3fb45Sjoris t = localtime(&stb1.st_mtime); 9293ad3fb45Sjoris (void)strftime(buf, sizeof(buf), 9303ad3fb45Sjoris "%d %b %G %H:%M:%S", t); 9313ad3fb45Sjoris 9323ad3fb45Sjoris diff_output("%s %s %s", 9333ad3fb45Sjoris diff_format == D_CONTEXT ? "***" : "---", diff_file, 9343ad3fb45Sjoris buf); 9353ad3fb45Sjoris 9363ad3fb45Sjoris if (diff_rev1 != NULL) { 9373ad3fb45Sjoris rcsnum_tostr(diff_rev1, buf, sizeof(buf)); 9383ad3fb45Sjoris diff_output("\t%s", buf); 9393ad3fb45Sjoris } 9403ad3fb45Sjoris 9419fac60a5Sjoris diff_output("\n"); 9423ad3fb45Sjoris 9433ad3fb45Sjoris t = localtime(&stb2.st_mtime); 9443ad3fb45Sjoris (void)strftime(buf, sizeof(buf), 9453ad3fb45Sjoris "%d %b %G %H:%M:%S", t); 9463ad3fb45Sjoris 9473ad3fb45Sjoris diff_output("%s %s %s", 9483ad3fb45Sjoris diff_format == D_CONTEXT ? "---" : "+++", diff_file, 9493ad3fb45Sjoris buf); 9503ad3fb45Sjoris 9513ad3fb45Sjoris if (diff_rev2 != NULL) { 9523ad3fb45Sjoris rcsnum_tostr(diff_rev2, buf, sizeof(buf)); 9533ad3fb45Sjoris diff_output("\t%s", buf); 9543ad3fb45Sjoris } 9553ad3fb45Sjoris 9569fac60a5Sjoris diff_output("\n"); 9573ad3fb45Sjoris anychange = 1; 9583ad3fb45Sjoris } else if (a > context_vec_ptr->b + (2 * context) + 1 && 9593ad3fb45Sjoris c > context_vec_ptr->d + (2 * context) + 1) { 9603ad3fb45Sjoris /* 9613ad3fb45Sjoris * If this change is more than 'context' lines from the 9623ad3fb45Sjoris * previous change, dump the record and reset it. 9633ad3fb45Sjoris */ 9643ad3fb45Sjoris if (diff_format == D_CONTEXT) 9653ad3fb45Sjoris dump_context_vec(f1, f2); 9663ad3fb45Sjoris else 9673ad3fb45Sjoris dump_unified_vec(f1, f2); 9683ad3fb45Sjoris } 9693ad3fb45Sjoris context_vec_ptr++; 9703ad3fb45Sjoris context_vec_ptr->a = a; 9713ad3fb45Sjoris context_vec_ptr->b = b; 9723ad3fb45Sjoris context_vec_ptr->c = c; 9733ad3fb45Sjoris context_vec_ptr->d = d; 9743ad3fb45Sjoris return; 9753ad3fb45Sjoris } 9763ad3fb45Sjoris if (anychange == 0) 9773ad3fb45Sjoris anychange = 1; 9783ad3fb45Sjoris switch (diff_format) { 9793ad3fb45Sjoris case D_BRIEF: 9803ad3fb45Sjoris return; 9813ad3fb45Sjoris case D_NORMAL: 9823ad3fb45Sjoris range(a, b, ","); 9833ad3fb45Sjoris diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 9843ad3fb45Sjoris if (diff_format == D_NORMAL) 9853ad3fb45Sjoris range(c, d, ","); 9863ad3fb45Sjoris diff_output("\n"); 9873ad3fb45Sjoris break; 9883ad3fb45Sjoris case D_RCSDIFF: 9893ad3fb45Sjoris if (a > b) 9903ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 9913ad3fb45Sjoris else { 9923ad3fb45Sjoris diff_output("d%d %d\n", a, b - a + 1); 9933ad3fb45Sjoris 9943ad3fb45Sjoris if (!(c > d)) /* add changed lines */ 9953ad3fb45Sjoris diff_output("a%d %d\n", b, d - c + 1); 9963ad3fb45Sjoris } 9973ad3fb45Sjoris break; 9983ad3fb45Sjoris } 9993ad3fb45Sjoris if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 10003ad3fb45Sjoris fetch(ixold, a, b, f1, '<', 1); 10013ad3fb45Sjoris if (a <= b && c <= d && diff_format == D_NORMAL) 10023ad3fb45Sjoris diff_output("---\n"); 10033ad3fb45Sjoris } 10043ad3fb45Sjoris fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); 10053ad3fb45Sjoris if (inifdef) { 10063ad3fb45Sjoris diff_output("#endif /* %s */\n", ifdefname); 10073ad3fb45Sjoris inifdef = 0; 10083ad3fb45Sjoris } 10093ad3fb45Sjoris } 10103ad3fb45Sjoris 10113ad3fb45Sjoris static void 10123ad3fb45Sjoris fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 10133ad3fb45Sjoris { 10143ad3fb45Sjoris long j, nc; 10153ad3fb45Sjoris int i, c, col; 10163ad3fb45Sjoris 10173ad3fb45Sjoris /* 10183ad3fb45Sjoris * When doing #ifdef's, copy down to current line 10193ad3fb45Sjoris * if this is the first file, so that stuff makes it to output. 10203ad3fb45Sjoris */ 10213ad3fb45Sjoris if (diff_format == D_IFDEF && oldfile) { 10223ad3fb45Sjoris long curpos = ftell(lb); 10233ad3fb45Sjoris /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 10243ad3fb45Sjoris nc = f[a > b ? b : a - 1] - curpos; 10253ad3fb45Sjoris for (i = 0; i < nc; i++) 10263ad3fb45Sjoris diff_output("%c", getc(lb)); 10273ad3fb45Sjoris } 10283ad3fb45Sjoris if (a > b) 10293ad3fb45Sjoris return; 10303ad3fb45Sjoris if (diff_format == D_IFDEF) { 10313ad3fb45Sjoris if (inifdef) { 10323ad3fb45Sjoris diff_output("#else /* %s%s */\n", 10333ad3fb45Sjoris oldfile == 1 ? "!" : "", ifdefname); 10343ad3fb45Sjoris } else { 10353ad3fb45Sjoris if (oldfile) 10363ad3fb45Sjoris diff_output("#ifndef %s\n", ifdefname); 10373ad3fb45Sjoris else 10383ad3fb45Sjoris diff_output("#ifdef %s\n", ifdefname); 10393ad3fb45Sjoris } 10403ad3fb45Sjoris inifdef = 1 + oldfile; 10413ad3fb45Sjoris } 10423ad3fb45Sjoris for (i = a; i <= b; i++) { 10433ad3fb45Sjoris fseek(lb, f[i - 1], SEEK_SET); 10443ad3fb45Sjoris nc = f[i] - f[i - 1]; 10453ad3fb45Sjoris if (diff_format != D_IFDEF && ch != '\0') { 10463ad3fb45Sjoris diff_output("%c", ch); 10473ad3fb45Sjoris if (Tflag == 1 && (diff_format == D_NORMAL || 10483ad3fb45Sjoris diff_format == D_CONTEXT || 10493ad3fb45Sjoris diff_format == D_UNIFIED)) 10503ad3fb45Sjoris diff_output("\t"); 10513ad3fb45Sjoris else if (diff_format != D_UNIFIED) 10523ad3fb45Sjoris diff_output(" "); 10533ad3fb45Sjoris } 10543ad3fb45Sjoris col = 0; 10553ad3fb45Sjoris for (j = 0; j < nc; j++) { 10563ad3fb45Sjoris if ((c = getc(lb)) == EOF) { 10573ad3fb45Sjoris if (diff_format == D_RCSDIFF) 10583ad3fb45Sjoris cvs_log(LP_ERR, 10593ad3fb45Sjoris "No newline at end of file"); 10603ad3fb45Sjoris else 10613ad3fb45Sjoris diff_output("\n\\ No newline at end of " 10623ad3fb45Sjoris "file"); 10633ad3fb45Sjoris return; 10643ad3fb45Sjoris } 10653ad3fb45Sjoris if (c == '\t' && tflag == 1) { 10663ad3fb45Sjoris do { 10673ad3fb45Sjoris diff_output(" "); 10683ad3fb45Sjoris } while (++col & 7); 10693ad3fb45Sjoris } else { 10703ad3fb45Sjoris diff_output("%c", c); 10713ad3fb45Sjoris col++; 10723ad3fb45Sjoris } 10733ad3fb45Sjoris } 10743ad3fb45Sjoris } 10753ad3fb45Sjoris } 10763ad3fb45Sjoris 10773ad3fb45Sjoris /* 10783ad3fb45Sjoris * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 10793ad3fb45Sjoris */ 10803ad3fb45Sjoris static int 10813ad3fb45Sjoris readhash(FILE *f) 10823ad3fb45Sjoris { 10833ad3fb45Sjoris int i, t, space; 10843ad3fb45Sjoris int sum; 10853ad3fb45Sjoris 10863ad3fb45Sjoris sum = 1; 10873ad3fb45Sjoris space = 0; 10883ad3fb45Sjoris if (bflag != 1 && wflag != 1) { 10893ad3fb45Sjoris if (iflag == 1) 10903ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 10913ad3fb45Sjoris if (t == EOF) { 10923ad3fb45Sjoris if (i == 0) 10933ad3fb45Sjoris return (0); 10943ad3fb45Sjoris break; 10953ad3fb45Sjoris } 10963ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 10973ad3fb45Sjoris } 10983ad3fb45Sjoris else 10993ad3fb45Sjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 11003ad3fb45Sjoris if (t == EOF) { 11013ad3fb45Sjoris if (i == 0) 11023ad3fb45Sjoris return (0); 11033ad3fb45Sjoris break; 11043ad3fb45Sjoris } 11053ad3fb45Sjoris sum = sum * 127 + t; 11063ad3fb45Sjoris } 11073ad3fb45Sjoris } else { 11083ad3fb45Sjoris for (i = 0;;) { 11093ad3fb45Sjoris switch (t = getc(f)) { 11103ad3fb45Sjoris case '\t': 11113ad3fb45Sjoris case ' ': 11123ad3fb45Sjoris space++; 11133ad3fb45Sjoris continue; 11143ad3fb45Sjoris default: 11153ad3fb45Sjoris if (space != 0 && wflag != 1) { 11163ad3fb45Sjoris i++; 11173ad3fb45Sjoris space = 0; 11183ad3fb45Sjoris } 11193ad3fb45Sjoris sum = sum * 127 + chrtran[t]; 11203ad3fb45Sjoris i++; 11213ad3fb45Sjoris continue; 11223ad3fb45Sjoris case EOF: 11233ad3fb45Sjoris if (i == 0) 11243ad3fb45Sjoris return (0); 11253ad3fb45Sjoris /* FALLTHROUGH */ 11263ad3fb45Sjoris case '\n': 11273ad3fb45Sjoris break; 11283ad3fb45Sjoris } 11293ad3fb45Sjoris break; 11303ad3fb45Sjoris } 11313ad3fb45Sjoris } 11323ad3fb45Sjoris /* 11333ad3fb45Sjoris * There is a remote possibility that we end up with a zero sum. 11343ad3fb45Sjoris * Zero is used as an EOF marker, so return 1 instead. 11353ad3fb45Sjoris */ 11363ad3fb45Sjoris return (sum == 0 ? 1 : sum); 11373ad3fb45Sjoris } 11383ad3fb45Sjoris 11393ad3fb45Sjoris static int 11403ad3fb45Sjoris asciifile(FILE *f) 11413ad3fb45Sjoris { 11423ad3fb45Sjoris char buf[BUFSIZ]; 11433ad3fb45Sjoris size_t i, cnt; 11443ad3fb45Sjoris 11453ad3fb45Sjoris if (aflag == 1 || f == NULL) 11463ad3fb45Sjoris return (1); 11473ad3fb45Sjoris 11483ad3fb45Sjoris rewind(f); 11493ad3fb45Sjoris cnt = fread(buf, (size_t)1, sizeof(buf), f); 11503ad3fb45Sjoris for (i = 0; i < cnt; i++) 11513ad3fb45Sjoris if (!isprint(buf[i]) && !isspace(buf[i])) 11523ad3fb45Sjoris return (0); 11533ad3fb45Sjoris return (1); 11543ad3fb45Sjoris } 11553ad3fb45Sjoris 1156e22e6974Sxsa #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) 1157e22e6974Sxsa 11583ad3fb45Sjoris static char* 11593ad3fb45Sjoris match_function(const long *f, int pos, FILE *fp) 11603ad3fb45Sjoris { 11613ad3fb45Sjoris unsigned char buf[FUNCTION_CONTEXT_SIZE]; 11623ad3fb45Sjoris size_t nc; 11633ad3fb45Sjoris int last = lastline; 11643ad3fb45Sjoris char *p; 1165e22e6974Sxsa char *state = NULL; 11663ad3fb45Sjoris 11673ad3fb45Sjoris lastline = pos; 11683ad3fb45Sjoris while (pos > last) { 11693ad3fb45Sjoris fseek(fp, f[pos - 1], SEEK_SET); 11703ad3fb45Sjoris nc = f[pos] - f[pos - 1]; 11713ad3fb45Sjoris if (nc >= sizeof(buf)) 11723ad3fb45Sjoris nc = sizeof(buf) - 1; 11733ad3fb45Sjoris nc = fread(buf, (size_t)1, nc, fp); 11743ad3fb45Sjoris if (nc > 0) { 11753ad3fb45Sjoris buf[nc] = '\0'; 11763ad3fb45Sjoris p = strchr((const char *)buf, '\n'); 11773ad3fb45Sjoris if (p != NULL) 11783ad3fb45Sjoris *p = '\0'; 11793ad3fb45Sjoris if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 1180e22e6974Sxsa if (begins_with(buf, "private:")) { 1181e22e6974Sxsa if (!state) 1182e22e6974Sxsa state = " (private)"; 1183e22e6974Sxsa } else if (begins_with(buf, "protected:")) { 1184e22e6974Sxsa if (!state) 1185e22e6974Sxsa state = " (protected)"; 1186e22e6974Sxsa } else if (begins_with(buf, "public:")) { 1187e22e6974Sxsa if (!state) 1188e22e6974Sxsa state = " (public)"; 1189e22e6974Sxsa } else { 11903ad3fb45Sjoris strlcpy(lastbuf, (const char *)buf, 11913ad3fb45Sjoris sizeof lastbuf); 1192e22e6974Sxsa if (state) 1193e22e6974Sxsa strlcat(lastbuf, state, 1194e22e6974Sxsa sizeof lastbuf); 11953ad3fb45Sjoris lastmatchline = pos; 11963ad3fb45Sjoris return lastbuf; 11973ad3fb45Sjoris } 11983ad3fb45Sjoris } 1199e22e6974Sxsa } 12003ad3fb45Sjoris pos--; 12013ad3fb45Sjoris } 12023ad3fb45Sjoris return (lastmatchline > 0) ? lastbuf : NULL; 12033ad3fb45Sjoris } 12043ad3fb45Sjoris 12053ad3fb45Sjoris 12063ad3fb45Sjoris /* dump accumulated "context" diff changes */ 12073ad3fb45Sjoris static void 12083ad3fb45Sjoris dump_context_vec(FILE *f1, FILE *f2) 12093ad3fb45Sjoris { 12103ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 12113ad3fb45Sjoris int lowa, upb, lowc, upd, do_output; 12123ad3fb45Sjoris int a, b, c, d; 12133ad3fb45Sjoris char ch, *f; 12143ad3fb45Sjoris 12153ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 12163ad3fb45Sjoris return; 12173ad3fb45Sjoris 12183ad3fb45Sjoris b = d = 0; /* gcc */ 12193ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 12203ad3fb45Sjoris upb = MIN(diff_len[0], context_vec_ptr->b + context); 12213ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 12223ad3fb45Sjoris upd = MIN(diff_len[1], context_vec_ptr->d + context); 12233ad3fb45Sjoris 12243ad3fb45Sjoris diff_output("***************"); 1225261cb0daSjoris if (diff_pflag == 1) { 12263ad3fb45Sjoris f = match_function(ixold, lowa - 1, f1); 12273ad3fb45Sjoris if (f != NULL) { 12283ad3fb45Sjoris diff_output(" "); 12293ad3fb45Sjoris diff_output("%s", f); 12303ad3fb45Sjoris } 12313ad3fb45Sjoris } 12323ad3fb45Sjoris diff_output("\n*** "); 12333ad3fb45Sjoris range(lowa, upb, ","); 12343ad3fb45Sjoris diff_output(" ****\n"); 12353ad3fb45Sjoris 12363ad3fb45Sjoris /* 12373ad3fb45Sjoris * Output changes to the "old" file. The first loop suppresses 12383ad3fb45Sjoris * output if there were no changes to the "old" file (we'll see 12393ad3fb45Sjoris * the "old" lines as context in the "new" list). 12403ad3fb45Sjoris */ 12413ad3fb45Sjoris do_output = 0; 12423ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) 12433ad3fb45Sjoris if (cvp->a <= cvp->b) { 12443ad3fb45Sjoris cvp = context_vec_start; 12453ad3fb45Sjoris do_output++; 12463ad3fb45Sjoris break; 12473ad3fb45Sjoris } 12483ad3fb45Sjoris if (do_output != 0) { 12493ad3fb45Sjoris while (cvp <= context_vec_ptr) { 12503ad3fb45Sjoris a = cvp->a; 12513ad3fb45Sjoris b = cvp->b; 12523ad3fb45Sjoris c = cvp->c; 12533ad3fb45Sjoris d = cvp->d; 12543ad3fb45Sjoris 12553ad3fb45Sjoris if (a <= b && c <= d) 12563ad3fb45Sjoris ch = 'c'; 12573ad3fb45Sjoris else 12583ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 12593ad3fb45Sjoris 12603ad3fb45Sjoris if (ch == 'a') 12613ad3fb45Sjoris fetch(ixold, lowa, b, f1, ' ', 0); 12623ad3fb45Sjoris else { 12633ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 12643ad3fb45Sjoris fetch(ixold, a, b, f1, 12653ad3fb45Sjoris ch == 'c' ? '!' : '-', 0); 12663ad3fb45Sjoris } 12673ad3fb45Sjoris lowa = b + 1; 12683ad3fb45Sjoris cvp++; 12693ad3fb45Sjoris } 12703ad3fb45Sjoris fetch(ixold, b + 1, upb, f1, ' ', 0); 12713ad3fb45Sjoris } 12723ad3fb45Sjoris /* output changes to the "new" file */ 12733ad3fb45Sjoris diff_output("--- "); 12743ad3fb45Sjoris range(lowc, upd, ","); 12753ad3fb45Sjoris diff_output(" ----\n"); 12763ad3fb45Sjoris 12773ad3fb45Sjoris do_output = 0; 12783ad3fb45Sjoris for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 12793ad3fb45Sjoris if (cvp->c <= cvp->d) { 12803ad3fb45Sjoris cvp = context_vec_start; 12813ad3fb45Sjoris do_output++; 12823ad3fb45Sjoris break; 12833ad3fb45Sjoris } 12843ad3fb45Sjoris if (do_output != 0) { 12853ad3fb45Sjoris while (cvp <= context_vec_ptr) { 12863ad3fb45Sjoris a = cvp->a; 12873ad3fb45Sjoris b = cvp->b; 12883ad3fb45Sjoris c = cvp->c; 12893ad3fb45Sjoris d = cvp->d; 12903ad3fb45Sjoris 12913ad3fb45Sjoris if (a <= b && c <= d) 12923ad3fb45Sjoris ch = 'c'; 12933ad3fb45Sjoris else 12943ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 12953ad3fb45Sjoris 12963ad3fb45Sjoris if (ch == 'd') 12973ad3fb45Sjoris fetch(ixnew, lowc, d, f2, ' ', 0); 12983ad3fb45Sjoris else { 12993ad3fb45Sjoris fetch(ixnew, lowc, c - 1, f2, ' ', 0); 13003ad3fb45Sjoris fetch(ixnew, c, d, f2, 13013ad3fb45Sjoris ch == 'c' ? '!' : '+', 0); 13023ad3fb45Sjoris } 13033ad3fb45Sjoris lowc = d + 1; 13043ad3fb45Sjoris cvp++; 13053ad3fb45Sjoris } 13063ad3fb45Sjoris fetch(ixnew, d + 1, upd, f2, ' ', 0); 13073ad3fb45Sjoris } 13083ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 13093ad3fb45Sjoris } 13103ad3fb45Sjoris 13113ad3fb45Sjoris /* dump accumulated "unified" diff changes */ 13123ad3fb45Sjoris static void 13133ad3fb45Sjoris dump_unified_vec(FILE *f1, FILE *f2) 13143ad3fb45Sjoris { 13153ad3fb45Sjoris struct context_vec *cvp = context_vec_start; 13163ad3fb45Sjoris int lowa, upb, lowc, upd; 13173ad3fb45Sjoris int a, b, c, d; 13183ad3fb45Sjoris char ch, *f; 13193ad3fb45Sjoris 13203ad3fb45Sjoris if (context_vec_start > context_vec_ptr) 13213ad3fb45Sjoris return; 13223ad3fb45Sjoris 13233ad3fb45Sjoris b = d = 0; /* gcc */ 13243ad3fb45Sjoris lowa = MAX(1, cvp->a - context); 13253ad3fb45Sjoris upb = MIN(diff_len[0], context_vec_ptr->b + context); 13263ad3fb45Sjoris lowc = MAX(1, cvp->c - context); 13273ad3fb45Sjoris upd = MIN(diff_len[1], context_vec_ptr->d + context); 13283ad3fb45Sjoris 13293ad3fb45Sjoris diff_output("@@ -"); 13303ad3fb45Sjoris uni_range(lowa, upb); 13313ad3fb45Sjoris diff_output(" +"); 13323ad3fb45Sjoris uni_range(lowc, upd); 13333ad3fb45Sjoris diff_output(" @@"); 1334261cb0daSjoris if (diff_pflag == 1) { 13353ad3fb45Sjoris f = match_function(ixold, lowa - 1, f1); 13363ad3fb45Sjoris if (f != NULL) { 13373ad3fb45Sjoris diff_output(" "); 13383ad3fb45Sjoris diff_output("%s", f); 13393ad3fb45Sjoris } 13403ad3fb45Sjoris } 13413ad3fb45Sjoris diff_output("\n"); 13423ad3fb45Sjoris 13433ad3fb45Sjoris /* 13443ad3fb45Sjoris * Output changes in "unified" diff format--the old and new lines 13453ad3fb45Sjoris * are printed together. 13463ad3fb45Sjoris */ 13473ad3fb45Sjoris for (; cvp <= context_vec_ptr; cvp++) { 13483ad3fb45Sjoris a = cvp->a; 13493ad3fb45Sjoris b = cvp->b; 13503ad3fb45Sjoris c = cvp->c; 13513ad3fb45Sjoris d = cvp->d; 13523ad3fb45Sjoris 13533ad3fb45Sjoris /* 13543ad3fb45Sjoris * c: both new and old changes 13553ad3fb45Sjoris * d: only changes in the old file 13563ad3fb45Sjoris * a: only changes in the new file 13573ad3fb45Sjoris */ 13583ad3fb45Sjoris if (a <= b && c <= d) 13593ad3fb45Sjoris ch = 'c'; 13603ad3fb45Sjoris else 13613ad3fb45Sjoris ch = (a <= b) ? 'd' : 'a'; 13623ad3fb45Sjoris 13633ad3fb45Sjoris switch (ch) { 13643ad3fb45Sjoris case 'c': 13653ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 13663ad3fb45Sjoris fetch(ixold, a, b, f1, '-', 0); 13673ad3fb45Sjoris fetch(ixnew, c, d, f2, '+', 0); 13683ad3fb45Sjoris break; 13693ad3fb45Sjoris case 'd': 13703ad3fb45Sjoris fetch(ixold, lowa, a - 1, f1, ' ', 0); 13713ad3fb45Sjoris fetch(ixold, a, b, f1, '-', 0); 13723ad3fb45Sjoris break; 13733ad3fb45Sjoris case 'a': 13743ad3fb45Sjoris fetch(ixnew, lowc, c - 1, f2, ' ', 0); 13753ad3fb45Sjoris fetch(ixnew, c, d, f2, '+', 0); 13763ad3fb45Sjoris break; 13773ad3fb45Sjoris } 13783ad3fb45Sjoris lowa = b + 1; 13793ad3fb45Sjoris lowc = d + 1; 13803ad3fb45Sjoris } 13813ad3fb45Sjoris fetch(ixnew, d + 1, upd, f2, ' ', 0); 13823ad3fb45Sjoris 13833ad3fb45Sjoris context_vec_ptr = context_vec_start - 1; 13843ad3fb45Sjoris } 13853ad3fb45Sjoris 13863ad3fb45Sjoris void 13873ad3fb45Sjoris diff_output(const char *fmt, ...) 13883ad3fb45Sjoris { 13893ad3fb45Sjoris va_list vap; 13903ad3fb45Sjoris int i; 13913ad3fb45Sjoris char *str; 13923ad3fb45Sjoris 13933ad3fb45Sjoris va_start(vap, fmt); 13943ad3fb45Sjoris i = vasprintf(&str, fmt, vap); 13953ad3fb45Sjoris va_end(vap); 13963ad3fb45Sjoris if (i == -1) 13973ad3fb45Sjoris fatal("diff_output: %s", strerror(errno)); 13983ad3fb45Sjoris if (diffbuf != NULL) 13993ad3fb45Sjoris cvs_buf_append(diffbuf, str, strlen(str)); 14003ad3fb45Sjoris else 14013ad3fb45Sjoris cvs_printf("%s", str); 14023ad3fb45Sjoris xfree(str); 14033ad3fb45Sjoris } 1404