1*ec6ed1abSjoris /* $OpenBSD: diff.c,v 1.86 2006/04/01 20:11:25 joris Exp $ */ 208f90673Sjfb /* 308f90673Sjfb * Copyright (C) Caldera International Inc. 2001-2002. 408f90673Sjfb * All rights reserved. 508f90673Sjfb * 608f90673Sjfb * Redistribution and use in source and binary forms, with or without 708f90673Sjfb * modification, are permitted provided that the following conditions 808f90673Sjfb * are met: 908f90673Sjfb * 1. Redistributions of source code and documentation must retain the above 1008f90673Sjfb * copyright notice, this list of conditions and the following disclaimer. 1108f90673Sjfb * 2. Redistributions in binary form must reproduce the above copyright 1208f90673Sjfb * notice, this list of conditions and the following disclaimer in the 1308f90673Sjfb * documentation and/or other materials provided with the distribution. 1408f90673Sjfb * 3. All advertising materials mentioning features or use of this software 1508f90673Sjfb * must display the following acknowledgement: 1608f90673Sjfb * This product includes software developed or owned by Caldera 1708f90673Sjfb * International, Inc. 1808f90673Sjfb * 4. Neither the name of Caldera International, Inc. nor the names of other 1908f90673Sjfb * contributors may be used to endorse or promote products derived from 2008f90673Sjfb * this software without specific prior written permission. 2108f90673Sjfb * 2208f90673Sjfb * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 2308f90673Sjfb * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 2408f90673Sjfb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2508f90673Sjfb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2608f90673Sjfb * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 2708f90673Sjfb * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2808f90673Sjfb * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2908f90673Sjfb * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3008f90673Sjfb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3108f90673Sjfb * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 3208f90673Sjfb * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3308f90673Sjfb * POSSIBILITY OF SUCH DAMAGE. 3408f90673Sjfb */ 3508f90673Sjfb /*- 3608f90673Sjfb * Copyright (c) 1991, 1993 3708f90673Sjfb * The Regents of the University of California. All rights reserved. 3808f90673Sjfb * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved. 3908f90673Sjfb * 4008f90673Sjfb * Redistribution and use in source and binary forms, with or without 4108f90673Sjfb * modification, are permitted provided that the following conditions 4208f90673Sjfb * are met: 4308f90673Sjfb * 1. Redistributions of source code must retain the above copyright 4408f90673Sjfb * notice, this list of conditions and the following disclaimer. 4508f90673Sjfb * 2. Redistributions in binary form must reproduce the above copyright 4608f90673Sjfb * notice, this list of conditions and the following disclaimer in the 4708f90673Sjfb * documentation and/or other materials provided with the distribution. 4808f90673Sjfb * 3. Neither the name of the University nor the names of its contributors 4908f90673Sjfb * may be used to endorse or promote products derived from this software 5008f90673Sjfb * without specific prior written permission. 5108f90673Sjfb * 5208f90673Sjfb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5308f90673Sjfb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5408f90673Sjfb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5508f90673Sjfb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5608f90673Sjfb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5708f90673Sjfb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5808f90673Sjfb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5908f90673Sjfb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6008f90673Sjfb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6108f90673Sjfb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6208f90673Sjfb * SUCH DAMAGE. 6308f90673Sjfb * 6408f90673Sjfb * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 6508f90673Sjfb */ 6608f90673Sjfb /* 6708f90673Sjfb * Uses an algorithm due to Harold Stone, which finds 6808f90673Sjfb * a pair of longest identical subsequences in the two 6908f90673Sjfb * files. 7008f90673Sjfb * 7108f90673Sjfb * The major goal is to generate the match vector J. 7208f90673Sjfb * J[i] is the index of the line in file1 corresponding 7308f90673Sjfb * to line i file0. J[i] = 0 if there is no 7408f90673Sjfb * such line in file1. 7508f90673Sjfb * 7608f90673Sjfb * Lines are hashed so as to work in core. All potential 7708f90673Sjfb * matches are located by sorting the lines of each file 7808f90673Sjfb * on the hash (called ``value''). In particular, this 7908f90673Sjfb * collects the equivalence classes in file1 together. 8008f90673Sjfb * Subroutine equiv replaces the value of each line in 8108f90673Sjfb * file0 by the index of the first element of its 8208f90673Sjfb * matching equivalence in (the reordered) file1. 8308f90673Sjfb * To save space equiv squeezes file1 into a single 8408f90673Sjfb * array member in which the equivalence classes 8508f90673Sjfb * are simply concatenated, except that their first 8608f90673Sjfb * members are flagged by changing sign. 8708f90673Sjfb * 8808f90673Sjfb * Next the indices that point into member are unsorted into 8908f90673Sjfb * array class according to the original order of file0. 9008f90673Sjfb * 9108f90673Sjfb * The cleverness lies in routine stone. This marches 9208f90673Sjfb * through the lines of file0, developing a vector klist 9308f90673Sjfb * of "k-candidates". At step i a k-candidate is a matched 9408f90673Sjfb * pair of lines x,y (x in file0 y in file1) such that 9508f90673Sjfb * there is a common subsequence of length k 9608f90673Sjfb * between the first i lines of file0 and the first y 9708f90673Sjfb * lines of file1, but there is no such subsequence for 9808f90673Sjfb * any smaller y. x is the earliest possible mate to y 9908f90673Sjfb * that occurs in such a subsequence. 10008f90673Sjfb * 10108f90673Sjfb * Whenever any of the members of the equivalence class of 10208f90673Sjfb * lines in file1 matable to a line in file0 has serial number 10308f90673Sjfb * less than the y of some k-candidate, that k-candidate 10408f90673Sjfb * with the smallest such y is replaced. The new 10508f90673Sjfb * k-candidate is chained (via pred) to the current 10608f90673Sjfb * k-1 candidate so that the actual subsequence can 10708f90673Sjfb * be recovered. When a member has serial number greater 10808f90673Sjfb * that the y of all k-candidates, the klist is extended. 10908f90673Sjfb * At the end, the longest subsequence is pulled out 11008f90673Sjfb * and placed in the array J by unravel 11108f90673Sjfb * 11208f90673Sjfb * With J in hand, the matches there recorded are 11308f90673Sjfb * check'ed against reality to assure that no spurious 11408f90673Sjfb * matches have crept in due to hashing. If they have, 11508f90673Sjfb * they are broken, and "jackpot" is recorded--a harmless 11608f90673Sjfb * matter except that a true match for a spuriously 11708f90673Sjfb * mated line may now be unnecessarily reported as a change. 11808f90673Sjfb * 11908f90673Sjfb * Much of the complexity of the program comes simply 12008f90673Sjfb * from trying to minimize core utilization and 12108f90673Sjfb * maximize the range of doable problems by dynamically 12208f90673Sjfb * allocating what is needed and reusing what is not. 12308f90673Sjfb * The core requirements for problems larger than somewhat 12408f90673Sjfb * are (in words) 2*length(file0) + length(file1) + 12508f90673Sjfb * 3*(number of k-candidates installed), typically about 12608f90673Sjfb * 6n words for files of length n. 12708f90673Sjfb */ 12808f90673Sjfb 129ac41f80cSxsa #include "includes.h" 13008f90673Sjfb 1319225b0caSxsa #include "buf.h" 13208f90673Sjfb #include "cvs.h" 133af5bb824Sniallo #include "diff.h" 13408f90673Sjfb #include "log.h" 135dc6a6879Sjfb #include "proto.h" 13608f90673Sjfb 137*ec6ed1abSjoris #include "xmalloc.h" 138*ec6ed1abSjoris 13908f90673Sjfb struct cand { 14008f90673Sjfb int x; 14108f90673Sjfb int y; 14208f90673Sjfb int pred; 14308f90673Sjfb } cand; 14408f90673Sjfb 14508f90673Sjfb struct line { 14608f90673Sjfb int serial; 14708f90673Sjfb int value; 14808f90673Sjfb } *file[2]; 14908f90673Sjfb 15008f90673Sjfb /* 15108f90673Sjfb * The following struct is used to record change in formation when 15208f90673Sjfb * doing a "context" or "unified" diff. (see routine "change" to 15308f90673Sjfb * understand the highly mnemonic field names) 15408f90673Sjfb */ 15508f90673Sjfb struct context_vec { 15608f90673Sjfb int a; /* start line in old file */ 15708f90673Sjfb int b; /* end line in old file */ 15808f90673Sjfb int c; /* start line in new file */ 15908f90673Sjfb int d; /* end line in new file */ 16008f90673Sjfb }; 16108f90673Sjfb 162dc6a6879Sjfb struct diff_arg { 163dc6a6879Sjfb char *rev1; 164dc6a6879Sjfb char *rev2; 165dc6a6879Sjfb char *date1; 166dc6a6879Sjfb char *date2; 167dc6a6879Sjfb }; 168dc6a6879Sjfb 169af5bb824Sniallo #if !defined(RCSPROG) 170e4276007Sjfb static int cvs_diff_init(struct cvs_cmd *, int, char **, int *); 171e4276007Sjfb static int cvs_diff_remote(CVSFILE *, void *); 172e4276007Sjfb static int cvs_diff_local(CVSFILE *, void *); 173e4276007Sjfb static int cvs_diff_pre_exec(struct cvsroot *); 174e4276007Sjfb static int cvs_diff_cleanup(void); 175af5bb824Sniallo #endif 17616cfc147Sjoris 177b2dc910bSray static void output(FILE *, FILE *); 17808f90673Sjfb static void check(FILE *, FILE *); 17908f90673Sjfb static void range(int, int, char *); 18008f90673Sjfb static void uni_range(int, int); 18108f90673Sjfb static void dump_context_vec(FILE *, FILE *); 18208f90673Sjfb static void dump_unified_vec(FILE *, FILE *); 1837f535ec4Sjfb static int prepare(int, FILE *, off_t); 18408f90673Sjfb static void prune(void); 18508f90673Sjfb static void equiv(struct line *, int, struct line *, int, int *); 18608f90673Sjfb static void unravel(int); 18708f90673Sjfb static void unsort(struct line *, int, int *); 188b2dc910bSray static void change(FILE *, FILE *, int, int, int, int); 18908f90673Sjfb static void sort(struct line *, int); 19008f90673Sjfb static int ignoreline(char *); 19108f90673Sjfb static int asciifile(FILE *); 192a44f42a4Sxsa static void fetch(long *, int, int, FILE *, int, int); 19308f90673Sjfb static int newcand(int, int, int); 19408f90673Sjfb static int search(int *, int, int); 19508f90673Sjfb static int skipline(FILE *); 19608f90673Sjfb static int isqrt(int); 19708f90673Sjfb static int stone(int *, int, int *, int *); 19808f90673Sjfb static int readhash(FILE *); 19908f90673Sjfb static int files_differ(FILE *, FILE *); 2005e78344dSjfb static char *match_function(const long *, int, FILE *); 20108f90673Sjfb static char *preadline(int, size_t, off_t); 20208f90673Sjfb 20308f90673Sjfb 204af5bb824Sniallo #if !defined(RCSPROG) 205af5bb824Sniallo static int Nflag; 206af5bb824Sniallo #endif 207af5bb824Sniallo static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; 20878de3304Sniallo static int context = 3; 209f9b67873Sniallo int diff_format = D_NORMAL; 2101ff4dac1Sjoris char *diff_file = NULL; 211c60b216dSxsa char diffargs[128]; 21208f90673Sjfb static struct stat stb1, stb2; 213af5bb824Sniallo static char *ifdefname, *ignore_pats; 21408f90673Sjfb regex_t ignore_re; 21508f90673Sjfb 21608f90673Sjfb static int *J; /* will be overlaid on class */ 21708f90673Sjfb static int *class; /* will be overlaid on file[0] */ 21808f90673Sjfb static int *klist; /* will be overlaid on file[0] after class */ 21908f90673Sjfb static int *member; /* will be overlaid on file[1] */ 22008f90673Sjfb static int clen; 22108f90673Sjfb static int inifdef; /* whether or not we are in a #ifdef block */ 222e4276007Sjfb static int diff_len[2]; 22308f90673Sjfb static int pref, suff; /* length of prefix and suffix */ 22408f90673Sjfb static int slen[2]; 22508f90673Sjfb static int anychange; 22608f90673Sjfb static long *ixnew; /* will be overlaid on file[1] */ 22708f90673Sjfb static long *ixold; /* will be overlaid on klist */ 22808f90673Sjfb static struct cand *clist; /* merely a free storage pot for candidates */ 22908f90673Sjfb static int clistlen; /* the length of clist */ 23008f90673Sjfb static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 23108f90673Sjfb static u_char *chrtran; /* translation table for case-folding */ 23208f90673Sjfb static struct context_vec *context_vec_start; 23308f90673Sjfb static struct context_vec *context_vec_end; 23408f90673Sjfb static struct context_vec *context_vec_ptr; 23508f90673Sjfb 23608f90673Sjfb #define FUNCTION_CONTEXT_SIZE 41 2375e78344dSjfb static char lastbuf[FUNCTION_CONTEXT_SIZE]; 23808f90673Sjfb static int lastline; 23908f90673Sjfb static int lastmatchline; 24001af718aSjoris BUF *diffbuf = NULL; 241f9b67873Sniallo 24208f90673Sjfb /* 24308f90673Sjfb * chrtran points to one of 2 translation tables: cup2low if folding upper to 24408f90673Sjfb * lower case clow2low if not folding case 24508f90673Sjfb */ 24608f90673Sjfb u_char clow2low[256] = { 24708f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 24808f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 24908f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 25008f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 25108f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 25208f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 25308f90673Sjfb 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 25408f90673Sjfb 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 25508f90673Sjfb 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 25608f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 25708f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 25808f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 25908f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 26008f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 26108f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 26208f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 26308f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 26408f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 26508f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 26608f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 26708f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 26808f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 26908f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 27008f90673Sjfb 0xfd, 0xfe, 0xff 27108f90673Sjfb }; 27208f90673Sjfb 27308f90673Sjfb u_char cup2low[256] = { 27408f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 27508f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 27608f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 27708f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 27808f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 27908f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 28008f90673Sjfb 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 28108f90673Sjfb 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 28208f90673Sjfb 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 28308f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 28408f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 28508f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 28608f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 28708f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 28808f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 28908f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 29008f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 29108f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 29208f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 29308f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 29408f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 29508f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 29608f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 29708f90673Sjfb 0xfd, 0xfe, 0xff 29808f90673Sjfb }; 29908f90673Sjfb 300af5bb824Sniallo #if !defined(RCSPROG) 301e4276007Sjfb struct cvs_cmd cvs_cmd_diff = { 302e4276007Sjfb CVS_OP_DIFF, CVS_REQ_DIFF, "diff", 303e4276007Sjfb { "di", "dif" }, 304e4276007Sjfb "Show differences between revisions", 305c9150269Sxsa "[-cilNnpu] [[-D date] [-r rev] [-D date2 | -r rev2]] " 306c9150269Sxsa "[-k mode] [file ...]", 307c9150269Sxsa "cD:iklNnpr:Ru", 30816cfc147Sjoris NULL, 30916cfc147Sjoris CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, 310e4276007Sjfb cvs_diff_init, 311e4276007Sjfb cvs_diff_pre_exec, 312e4276007Sjfb cvs_diff_remote, 313e4276007Sjfb cvs_diff_local, 314e4276007Sjfb NULL, 315e4276007Sjfb cvs_diff_cleanup, 316e4276007Sjfb CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR 317e4276007Sjfb }; 318e4276007Sjfb 319e4276007Sjfb 320e4276007Sjfb struct cvs_cmd cvs_cmd_rdiff = { 321e4276007Sjfb CVS_OP_RDIFF, CVS_REQ_DIFF, "rdiff", 322c9150269Sxsa { "pa", "patch" }, 323e4276007Sjfb "Create 'patch' format diffs between releases", 324c9150269Sxsa "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev " 325c9150269Sxsa "[-D date2 | -rev2] module ...", 326c9150269Sxsa "cD:flRr:stuV:", 327e4276007Sjfb NULL, 328e4276007Sjfb CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, 329e4276007Sjfb cvs_diff_init, 330e4276007Sjfb cvs_diff_pre_exec, 331e4276007Sjfb cvs_diff_remote, 332e4276007Sjfb cvs_diff_local, 333e4276007Sjfb NULL, 334e4276007Sjfb cvs_diff_cleanup, 33544381dcbSjoris CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR 33616cfc147Sjoris }; 337af5bb824Sniallo #endif 33808f90673Sjfb 339af5bb824Sniallo #if !defined(RCSPROG) 34016cfc147Sjoris static struct diff_arg *dap = NULL; 34116cfc147Sjoris 342e4276007Sjfb static int 343e4276007Sjfb cvs_diff_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) 34408f90673Sjfb { 34516cfc147Sjoris int ch; 34608f90673Sjfb 3470450b43bSjoris dap = (struct diff_arg *)xmalloc(sizeof(*dap)); 34816cfc147Sjoris dap->date1 = dap->date2 = dap->rev1 = dap->rev2 = NULL; 349dc6a6879Sjfb strlcpy(diffargs, argv[0], sizeof(diffargs)); 350dc6a6879Sjfb 351e4276007Sjfb while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { 35208f90673Sjfb switch (ch) { 35308f90673Sjfb case 'c': 354f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 355f9b67873Sniallo diff_format = D_CONTEXT; 35608f90673Sjfb break; 35708f90673Sjfb case 'D': 35816cfc147Sjoris if (dap->date1 == NULL && dap->rev1 == NULL) { 35916cfc147Sjoris dap->date1 = optarg; 36016cfc147Sjoris } else if (dap->date2 == NULL && dap->rev2 == NULL) { 36116cfc147Sjoris dap->date2 = optarg; 36216cfc147Sjoris } else { 36308f90673Sjfb cvs_log(LP_ERR, 36408f90673Sjfb "no more than two revisions/dates can " 36508f90673Sjfb "be specified"); 36608f90673Sjfb } 36708f90673Sjfb break; 36808f90673Sjfb case 'l': 369f5638424Sjfb strlcat(diffargs, " -l", sizeof(diffargs)); 370e4276007Sjfb cvs_cmd_diff.file_flags &= ~CF_RECURSE; 37108f90673Sjfb break; 37208f90673Sjfb case 'i': 373f5638424Sjfb strlcat(diffargs, " -i", sizeof(diffargs)); 37408f90673Sjfb iflag = 1; 37508f90673Sjfb break; 376c710bc5aSjfb case 'N': 377c710bc5aSjfb strlcat(diffargs, " -N", sizeof(diffargs)); 378c710bc5aSjfb Nflag = 1; 379c710bc5aSjfb break; 380394180a4Sjfb case 'n': 381394180a4Sjfb strlcat(diffargs, " -n", sizeof(diffargs)); 382f9b67873Sniallo diff_format = D_RCSDIFF; 383394180a4Sjfb break; 3845e78344dSjfb case 'p': 3855e78344dSjfb strlcat(diffargs, " -p", sizeof(diffargs)); 3865e78344dSjfb pflag = 1; 3875e78344dSjfb break; 38808f90673Sjfb case 'r': 38916cfc147Sjoris if ((dap->rev1 == NULL) && (dap->date1 == NULL)) { 39016cfc147Sjoris dap->rev1 = optarg; 39116cfc147Sjoris } else if ((dap->rev2 == NULL) && 39216cfc147Sjoris (dap->date2 == NULL)) { 39316cfc147Sjoris dap->rev2 = optarg; 39416cfc147Sjoris } else { 39508f90673Sjfb cvs_log(LP_ERR, 39608f90673Sjfb "no more than two revisions/dates can " 39708f90673Sjfb "be specified"); 39831274bbfSjoris return (CVS_EX_USAGE); 39908f90673Sjfb } 40008f90673Sjfb break; 401f203c484Sjoris case 'R': 402e4276007Sjfb cvs_cmd_diff.file_flags |= CF_RECURSE; 403f203c484Sjoris break; 40408f90673Sjfb case 'u': 405f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 406f9b67873Sniallo diff_format = D_UNIFIED; 40708f90673Sjfb break; 40808f90673Sjfb default: 40931274bbfSjoris return (CVS_EX_USAGE); 41008f90673Sjfb } 41108f90673Sjfb } 41208f90673Sjfb 41316cfc147Sjoris *arg = optind; 414dc6a6879Sjfb return (0); 415dc6a6879Sjfb } 416dc6a6879Sjfb 41716cfc147Sjoris int 41816cfc147Sjoris cvs_diff_cleanup(void) 41916cfc147Sjoris { 420e4276007Sjfb if (dap != NULL) { 4210450b43bSjoris xfree(dap); 422e4276007Sjfb dap = NULL; 423e4276007Sjfb } 42416cfc147Sjoris return (0); 42516cfc147Sjoris } 426dc6a6879Sjfb 427dc6a6879Sjfb /* 428e4276007Sjfb * cvs_diff_pre_exec() 429dc6a6879Sjfb * 430dc6a6879Sjfb */ 431dc6a6879Sjfb int 432e4276007Sjfb cvs_diff_pre_exec(struct cvsroot *root) 433dc6a6879Sjfb { 434e4276007Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 43508f90673Sjfb /* send the flags */ 4367e393898Sjoris if (Nflag == 1) 4377e393898Sjoris cvs_sendarg(root, "-N", 0); 4387e393898Sjoris if (pflag == 1) 4397e393898Sjoris cvs_sendarg(root, "-p", 0); 4405e78344dSjfb 4417e393898Sjoris if (diff_format == D_CONTEXT) 4427e393898Sjoris cvs_sendarg(root, "-c", 0); 4437e393898Sjoris else if (diff_format == D_UNIFIED) 4447e393898Sjoris cvs_sendarg(root, "-u", 0); 44508f90673Sjfb 446dc6a6879Sjfb if (dap->rev1 != NULL) { 4477e393898Sjoris cvs_sendarg(root, "-r", 0); 4487e393898Sjoris cvs_sendarg(root, dap->rev1, 0); 4493917c9bfSderaadt } else if (dap->date1 != NULL) { 4507e393898Sjoris cvs_sendarg(root, "-D", 0); 4517e393898Sjoris cvs_sendarg(root, dap->date1, 0); 45208f90673Sjfb } 453dc6a6879Sjfb if (dap->rev2 != NULL) { 4547e393898Sjoris cvs_sendarg(root, "-r", 0); 4557e393898Sjoris cvs_sendarg(root, dap->rev2, 0); 4563917c9bfSderaadt } else if (dap->date2 != NULL) { 4577e393898Sjoris cvs_sendarg(root, "-D", 0); 4587e393898Sjoris cvs_sendarg(root, dap->date2, 0); 45908f90673Sjfb } 460e4276007Sjfb } 46108f90673Sjfb 46208f90673Sjfb return (0); 46308f90673Sjfb } 46408f90673Sjfb 46508f90673Sjfb 46608f90673Sjfb /* 46708f90673Sjfb * cvs_diff_file() 46808f90673Sjfb * 46908f90673Sjfb * Diff a single file. 47008f90673Sjfb */ 471e4276007Sjfb static int 472e4276007Sjfb cvs_diff_remote(struct cvs_file *cfp, void *arg) 47308f90673Sjfb { 474d990145dSray char fpath[MAXPATHLEN]; 475dc6a6879Sjfb struct cvsroot *root; 476dc6a6879Sjfb 477dc6a6879Sjfb if (cfp->cf_type == DT_DIR) { 478895e6cf6Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 479bb029937Sjfb root = cfp->cf_parent->cf_root; 480b904ba2eSjoris cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 4813917c9bfSderaadt } else { 482bb029937Sjfb root = cfp->cf_root; 48316cfc147Sjoris #if 0 484dc6a6879Sjfb if ((cfp->cf_parent == NULL) || 485bb029937Sjfb (root != cfp->cf_parent->cf_root)) { 486dc6a6879Sjfb cvs_connect(root); 487e4276007Sjfb cvs_diff_pre_exec(root); 488dc6a6879Sjfb } 48916cfc147Sjoris #endif 490dc6a6879Sjfb 491dc6a6879Sjfb cvs_senddir(root, cfp); 492895e6cf6Sjfb } 493895e6cf6Sjfb 494dc6a6879Sjfb return (0); 495dc6a6879Sjfb } 49608f90673Sjfb 4972d5b8b1dSjfb if (cfp->cf_cvstat == CVS_FST_LOST) { 498b904ba2eSjoris cvs_log(LP_WARN, "cannot find file %s", cfp->cf_name); 4992d5b8b1dSjfb return (0); 5002d5b8b1dSjfb } 5012d5b8b1dSjfb 502c710bc5aSjfb diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath)); 503895e6cf6Sjfb 504d990145dSray if (cfp->cf_parent != NULL) 505bb029937Sjfb root = cfp->cf_parent->cf_root; 506d990145dSray else 507895e6cf6Sjfb root = NULL; 50808f90673Sjfb 509dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 510e4276007Sjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 511dc6a6879Sjfb return (0); 51208f90673Sjfb } 51308f90673Sjfb 5147e393898Sjoris cvs_sendentry(root, cfp); 51508f90673Sjfb 516dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UPTODATE) { 517e4276007Sjfb cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); 51808f90673Sjfb return (0); 51908f90673Sjfb } 52008f90673Sjfb 52108f90673Sjfb /* at this point, the file is modified */ 5227e393898Sjoris cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name); 5237e393898Sjoris cvs_sendfile(root, diff_file); 524e4276007Sjfb 525e4276007Sjfb return (0); 526e4276007Sjfb } 527e4276007Sjfb 528e4276007Sjfb static int 529e4276007Sjfb cvs_diff_local(CVSFILE *cf, void *arg) 530e4276007Sjfb { 531d990145dSray char buf[64]; 532e4276007Sjfb char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; 533e4276007Sjfb char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN]; 534e4276007Sjfb BUF *b1, *b2; 535e4276007Sjfb RCSNUM *r1, *r2; 536e4276007Sjfb RCSFILE *rf; 537bf951d2dSniallo struct timeval tv[2], tv2[2]; 538bf951d2dSniallo 539bf951d2dSniallo memset(&tv, 0, sizeof(tv)); 540bf951d2dSniallo memset(&tv2, 0, sizeof(tv2)); 541e4276007Sjfb 542e4276007Sjfb rf = NULL; 543e4276007Sjfb diff_file = cvs_file_getpath(cf, fpath, sizeof(fpath)); 544e4276007Sjfb 545e4276007Sjfb if (cf->cf_type == DT_DIR) { 546b87c59bdSxsa if (verbosity > 1) 547246675edSxsa cvs_log(LP_NOTICE, "Diffing %s", fpath); 548e4276007Sjfb return (0); 549e4276007Sjfb } 550e4276007Sjfb 551e4276007Sjfb if (cf->cf_cvstat == CVS_FST_LOST) { 552e4276007Sjfb cvs_log(LP_WARN, "cannot find file %s", cf->cf_name); 553e4276007Sjfb return (0); 554e4276007Sjfb } 555e4276007Sjfb 556e4276007Sjfb if (cf->cf_cvstat == CVS_FST_UNKNOWN) { 557e4276007Sjfb cvs_log(LP_WARN, "I know nothing about %s", diff_file); 558e4276007Sjfb return (0); 5595c0cd766Sniallo } else if (cf->cf_cvstat == CVS_FST_UPTODATE) 560e4276007Sjfb return (0); 561e4276007Sjfb 562e4276007Sjfb /* at this point, the file is modified */ 563cb9f80caSxsa cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)); 56408f90673Sjfb 5653956f8daSxsa if ((rf = rcs_open(rcspath, RCS_READ)) == NULL) 5663956f8daSxsa fatal("cvs_diff_local: rcs_open `%s': %s", rcspath, 56766c1e2eaSxsa rcs_errstr(rcs_errno)); 56808f90673Sjfb 569dc6a6879Sjfb cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, 57008f90673Sjfb RCS_DIFF_DIV, rcspath); 57108f90673Sjfb 572dc6a6879Sjfb if (dap->rev1 == NULL) 573e4276007Sjfb r1 = cf->cf_lrev; 57408f90673Sjfb else { 5753956f8daSxsa if ((r1 = rcsnum_parse(dap->rev1)) == NULL) 5763956f8daSxsa fatal("cvs_diff_local: rcsnum_parse failed"); 57708f90673Sjfb } 57808f90673Sjfb 579dc6a6879Sjfb cvs_printf("retrieving revision %s\n", 58008f90673Sjfb rcsnum_tostr(r1, buf, sizeof(buf))); 58108f90673Sjfb b1 = rcs_getrev(rf, r1); 58208f90673Sjfb 58395ae1173Sjoris if (b1 == NULL) { 5840e9dc9e3Sniallo cvs_log(LP_ERR, "failed to retrieve revision %s", 58595ae1173Sjoris rcsnum_tostr(r1, buf, sizeof(buf))); 58695ae1173Sjoris if (r1 != cf->cf_lrev) 58795ae1173Sjoris rcsnum_free(r1); 58864672f74Sjoris rcs_close(rf); 58995ae1173Sjoris return (CVS_EX_DATA); 59095ae1173Sjoris } 591bf951d2dSniallo tv[0].tv_sec = (long)rcs_rev_getdate(rf, r1); 592bf951d2dSniallo tv[1].tv_sec = tv[0].tv_sec; 59395ae1173Sjoris 594e4276007Sjfb if (r1 != cf->cf_lrev) 5957f535ec4Sjfb rcsnum_free(r1); 5967f535ec4Sjfb 597dc6a6879Sjfb if (dap->rev2 != NULL) { 598dc6a6879Sjfb cvs_printf("retrieving revision %s\n", dap->rev2); 59925b74b48Sjfb if ((r2 = rcsnum_parse(dap->rev2)) == NULL) { 60064672f74Sjoris rcs_close(rf); 60131274bbfSjoris return (CVS_EX_DATA); 6027f535ec4Sjfb } 60308f90673Sjfb b2 = rcs_getrev(rf, r2); 604f3e6c8ebSniallo tv2[0].tv_sec = (long)rcs_rev_getdate(rf, r2); 605f3e6c8ebSniallo tv2[1].tv_sec = tv2[0].tv_sec; 6067f535ec4Sjfb rcsnum_free(r2); 6073917c9bfSderaadt } else { 608f3e6c8ebSniallo struct stat st; 609f3e6c8ebSniallo if (stat(diff_file, &st) < 0) { 6100e9dc9e3Sniallo cvs_log(LP_ERR, "failed to retrieve revision %s", 611f3e6c8ebSniallo dap->rev2); 612f3e6c8ebSniallo cvs_buf_free(b1); 613f3e6c8ebSniallo return (CVS_EX_DATA); 614f3e6c8ebSniallo } 615dc6a6879Sjfb b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); 616f3e6c8ebSniallo tv2[0].tv_sec = st.st_mtime; 617f3e6c8ebSniallo tv2[1].tv_sec = st.st_mtime; 61808f90673Sjfb } 61908f90673Sjfb 620dc6a6879Sjfb rcs_close(rf); 621dc6a6879Sjfb 62295ae1173Sjoris if (b2 == NULL) { 6230e9dc9e3Sniallo cvs_log(LP_ERR, "failed to retrieve revision %s", 62495ae1173Sjoris dap->rev2); 62595ae1173Sjoris cvs_buf_free(b1); 62695ae1173Sjoris return (CVS_EX_DATA); 62795ae1173Sjoris } 62895ae1173Sjoris 6295ac8b1e7Sjoris cvs_printf("%s", diffargs); 6305ac8b1e7Sjoris cvs_printf(" -r%s", buf); 631dc6a6879Sjfb if (dap->rev2 != NULL) 6325ac8b1e7Sjoris cvs_printf(" -r%s", dap->rev2); 6335ac8b1e7Sjoris cvs_printf(" %s\n", diff_file); 6341dee9299Sxsa strlcpy(path_tmp1, cvs_tmpdir, sizeof(path_tmp1)); 6351dee9299Sxsa strlcat(path_tmp1, "/diff1.XXXXXXXXXX", sizeof(path_tmp1)); 636fbe562adSxsa cvs_buf_write_stmp(b1, path_tmp1, 0600); 6377f535ec4Sjfb cvs_buf_free(b1); 638bf951d2dSniallo if (utimes(path_tmp1, (const struct timeval *)&tv) < 0) 639bf951d2dSniallo cvs_log(LP_ERRNO, "error setting utimes"); 6407f535ec4Sjfb 6411dee9299Sxsa strlcpy(path_tmp2, cvs_tmpdir, sizeof(path_tmp2)); 6421dee9299Sxsa strlcat(path_tmp2, "/diff2.XXXXXXXXXX", sizeof(path_tmp2)); 6438dbc5e14Sxsa cvs_buf_write_stmp(b2, path_tmp2, 0600); 6447f535ec4Sjfb cvs_buf_free(b2); 645bf951d2dSniallo if (utimes(path_tmp2, (const struct timeval *)&tv2) < 0) 646bf951d2dSniallo cvs_log(LP_ERRNO, "error setting utimes"); 6477f535ec4Sjfb 648f9b67873Sniallo cvs_diffreg(path_tmp1, path_tmp2, NULL); 649946f6157Sdjm (void)unlink(path_tmp1); 650946f6157Sdjm (void)unlink(path_tmp2); 65108f90673Sjfb 65208f90673Sjfb return (0); 65308f90673Sjfb } 654af5bb824Sniallo #endif 65508f90673Sjfb 65608f90673Sjfb 65708f90673Sjfb int 658f9b67873Sniallo cvs_diffreg(const char *file1, const char *file2, BUF *out) 65908f90673Sjfb { 66008f90673Sjfb FILE *f1, *f2; 66108f90673Sjfb int i, rval; 6627f535ec4Sjfb void *tmp; 66308f90673Sjfb 66408f90673Sjfb f1 = f2 = NULL; 66508f90673Sjfb rval = D_SAME; 66608f90673Sjfb anychange = 0; 66708f90673Sjfb lastline = 0; 66808f90673Sjfb lastmatchline = 0; 66908f90673Sjfb context_vec_ptr = context_vec_start - 1; 67008f90673Sjfb chrtran = (iflag ? cup2low : clow2low); 671f9b67873Sniallo if (out != NULL) 672f9b67873Sniallo diffbuf = out; 67308f90673Sjfb 67408f90673Sjfb f1 = fopen(file1, "r"); 67508f90673Sjfb if (f1 == NULL) { 67608f90673Sjfb cvs_log(LP_ERRNO, "%s", file1); 67708f90673Sjfb goto closem; 67808f90673Sjfb } 67908f90673Sjfb 68008f90673Sjfb f2 = fopen(file2, "r"); 68108f90673Sjfb if (f2 == NULL) { 68208f90673Sjfb cvs_log(LP_ERRNO, "%s", file2); 68308f90673Sjfb goto closem; 68408f90673Sjfb } 68508f90673Sjfb 686bf951d2dSniallo if (stat(file1, &stb1) < 0) { 687bf951d2dSniallo cvs_log(LP_ERRNO, "%s", file1); 688bf951d2dSniallo goto closem; 689bf951d2dSniallo } 690bf951d2dSniallo if (stat(file2, &stb2) < 0) { 691bf951d2dSniallo cvs_log(LP_ERRNO, "%s", file2); 692bf951d2dSniallo goto closem; 693bf951d2dSniallo } 69408f90673Sjfb switch (files_differ(f1, f2)) { 69508f90673Sjfb case 0: 69608f90673Sjfb goto closem; 69708f90673Sjfb case 1: 69808f90673Sjfb break; 69908f90673Sjfb default: 70008f90673Sjfb /* error */ 70108f90673Sjfb goto closem; 70208f90673Sjfb } 70308f90673Sjfb 70408f90673Sjfb if (!asciifile(f1) || !asciifile(f2)) { 70508f90673Sjfb rval = D_BINARY; 70608f90673Sjfb goto closem; 70708f90673Sjfb } 7087f535ec4Sjfb if ((prepare(0, f1, stb1.st_size) < 0) || 7097f535ec4Sjfb (prepare(1, f2, stb2.st_size) < 0)) { 7107f535ec4Sjfb goto closem; 7117f535ec4Sjfb } 71208f90673Sjfb prune(); 71308f90673Sjfb sort(sfile[0], slen[0]); 71408f90673Sjfb sort(sfile[1], slen[1]); 71508f90673Sjfb 71608f90673Sjfb member = (int *)file[1]; 71708f90673Sjfb equiv(sfile[0], slen[0], sfile[1], slen[1], member); 7182e0e138cSray tmp = xrealloc(member, slen[1] + 2, sizeof(int)); 7197f535ec4Sjfb member = (int *)tmp; 72008f90673Sjfb 72108f90673Sjfb class = (int *)file[0]; 72208f90673Sjfb unsort(sfile[0], slen[0], class); 7232e0e138cSray tmp = xrealloc(class, slen[0] + 2, sizeof(int)); 7247f535ec4Sjfb class = (int *)tmp; 72508f90673Sjfb 726b39d2e28Sray klist = xcalloc(slen[0] + 2, sizeof(int)); 72708f90673Sjfb clen = 0; 72808f90673Sjfb clistlen = 100; 729b39d2e28Sray clist = xcalloc(clistlen, sizeof(cand)); 730ece76a70Sjoris 731ece76a70Sjoris if ((i = stone(class, slen[0], member, klist)) < 0) 732ece76a70Sjoris goto closem; 733ece76a70Sjoris 7340450b43bSjoris xfree(member); 7350450b43bSjoris xfree(class); 73608f90673Sjfb 7372e0e138cSray tmp = xrealloc(J, diff_len[0] + 2, sizeof(int)); 73818501190Sniallo J = (int *)tmp; 73908f90673Sjfb unravel(klist[i]); 7400450b43bSjoris xfree(clist); 7410450b43bSjoris xfree(klist); 74208f90673Sjfb 7432e0e138cSray tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(long)); 74418501190Sniallo ixold = (long *)tmp; 7450450b43bSjoris 7462e0e138cSray tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(long)); 74718501190Sniallo ixnew = (long *)tmp; 74808f90673Sjfb check(f1, f2); 749b2dc910bSray output(f1, f2); 75008f90673Sjfb 75108f90673Sjfb closem: 75237af5b8bSxsa if (anychange == 1) { 75308f90673Sjfb if (rval == D_SAME) 75408f90673Sjfb rval = D_DIFFER; 75508f90673Sjfb } 75608f90673Sjfb if (f1 != NULL) 75708f90673Sjfb fclose(f1); 75808f90673Sjfb if (f2 != NULL) 75908f90673Sjfb fclose(f2); 7607f535ec4Sjfb 76108f90673Sjfb return (rval); 76208f90673Sjfb } 76308f90673Sjfb 76408f90673Sjfb /* 76508f90673Sjfb * Check to see if the given files differ. 76608f90673Sjfb * Returns 0 if they are the same, 1 if different, and -1 on error. 76708f90673Sjfb * XXX - could use code from cmp(1) [faster] 76808f90673Sjfb */ 76908f90673Sjfb static int 77008f90673Sjfb files_differ(FILE *f1, FILE *f2) 77108f90673Sjfb { 77208f90673Sjfb char buf1[BUFSIZ], buf2[BUFSIZ]; 77308f90673Sjfb size_t i, j; 77408f90673Sjfb 77508f90673Sjfb if (stb1.st_size != stb2.st_size) 77608f90673Sjfb return (1); 77708f90673Sjfb for (;;) { 778f1901a5aSxsa i = fread(buf1, (size_t)1, sizeof(buf1), f1); 779f1901a5aSxsa j = fread(buf2, (size_t)1, sizeof(buf2), f2); 78008f90673Sjfb if (i != j) 78108f90673Sjfb return (1); 78237af5b8bSxsa if ((i == 0) && (j == 0)) { 78308f90673Sjfb if (ferror(f1) || ferror(f2)) 78408f90673Sjfb return (1); 78508f90673Sjfb return (0); 78608f90673Sjfb } 78708f90673Sjfb if (memcmp(buf1, buf2, i) != 0) 78808f90673Sjfb return (1); 78908f90673Sjfb } 79008f90673Sjfb } 79108f90673Sjfb 7927f535ec4Sjfb static int 79308f90673Sjfb prepare(int i, FILE *fd, off_t filesize) 79408f90673Sjfb { 7957f535ec4Sjfb void *tmp; 79608f90673Sjfb struct line *p; 79708f90673Sjfb int j, h; 79808f90673Sjfb size_t sz; 79908f90673Sjfb 80008f90673Sjfb rewind(fd); 80108f90673Sjfb 802c48da046Sxsa sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 80308f90673Sjfb if (sz < 100) 80408f90673Sjfb sz = 100; 80508f90673Sjfb 806b39d2e28Sray p = (struct line *)xcalloc(sz + 3, sizeof(struct line)); 80708f90673Sjfb for (j = 0; (h = readhash(fd));) { 80808f90673Sjfb if (j == (int)sz) { 80908f90673Sjfb sz = sz * 3 / 2; 8102e0e138cSray tmp = xrealloc(p, sz + 3, sizeof(struct line)); 8117f535ec4Sjfb p = (struct line *)tmp; 81208f90673Sjfb } 81308f90673Sjfb p[++j].value = h; 81408f90673Sjfb } 815e4276007Sjfb diff_len[i] = j; 81608f90673Sjfb file[i] = p; 8177f535ec4Sjfb 8187f535ec4Sjfb return (0); 81908f90673Sjfb } 82008f90673Sjfb 82108f90673Sjfb static void 82208f90673Sjfb prune(void) 82308f90673Sjfb { 82408f90673Sjfb int i, j; 82508f90673Sjfb 826e4276007Sjfb for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 82708f90673Sjfb file[0][pref + 1].value == file[1][pref + 1].value; 82808f90673Sjfb pref++) 82908f90673Sjfb ; 830e4276007Sjfb for (suff = 0; 831e4276007Sjfb (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 832e4276007Sjfb (file[0][diff_len[0] - suff].value == 833e4276007Sjfb file[1][diff_len[1] - suff].value); 83408f90673Sjfb suff++) 83508f90673Sjfb ; 83608f90673Sjfb for (j = 0; j < 2; j++) { 83708f90673Sjfb sfile[j] = file[j] + pref; 838e4276007Sjfb slen[j] = diff_len[j] - pref - suff; 83908f90673Sjfb for (i = 0; i <= slen[j]; i++) 84008f90673Sjfb sfile[j][i].serial = i; 84108f90673Sjfb } 84208f90673Sjfb } 84308f90673Sjfb 84408f90673Sjfb static void 84508f90673Sjfb equiv(struct line *a, int n, struct line *b, int m, int *c) 84608f90673Sjfb { 84708f90673Sjfb int i, j; 84808f90673Sjfb 84908f90673Sjfb i = j = 1; 85008f90673Sjfb while (i <= n && j <= m) { 85108f90673Sjfb if (a[i].value < b[j].value) 85208f90673Sjfb a[i++].value = 0; 85308f90673Sjfb else if (a[i].value == b[j].value) 85408f90673Sjfb a[i++].value = j; 85508f90673Sjfb else 85608f90673Sjfb j++; 85708f90673Sjfb } 85808f90673Sjfb while (i <= n) 85908f90673Sjfb a[i++].value = 0; 86008f90673Sjfb b[m + 1].value = 0; 86108f90673Sjfb j = 0; 86208f90673Sjfb while (++j <= m) { 86308f90673Sjfb c[j] = -b[j].serial; 86408f90673Sjfb while (b[j + 1].value == b[j].value) { 86508f90673Sjfb j++; 86608f90673Sjfb c[j] = b[j].serial; 86708f90673Sjfb } 86808f90673Sjfb } 86908f90673Sjfb c[j] = -1; 87008f90673Sjfb } 87108f90673Sjfb 87208f90673Sjfb /* Code taken from ping.c */ 87308f90673Sjfb static int 87408f90673Sjfb isqrt(int n) 87508f90673Sjfb { 87608f90673Sjfb int y, x = 1; 87708f90673Sjfb 87808f90673Sjfb if (n == 0) 87908f90673Sjfb return (0); 88008f90673Sjfb 88108f90673Sjfb do { /* newton was a stinker */ 88208f90673Sjfb y = x; 88308f90673Sjfb x = n / x; 88408f90673Sjfb x += y; 88508f90673Sjfb x /= 2; 88608f90673Sjfb } while ((x - y) > 1 || (x - y) < -1); 88708f90673Sjfb 88808f90673Sjfb return (x); 88908f90673Sjfb } 89008f90673Sjfb 89108f90673Sjfb static int 89208f90673Sjfb stone(int *a, int n, int *b, int *c) 89308f90673Sjfb { 894ece76a70Sjoris int ret; 89508f90673Sjfb int i, k, y, j, l; 89608f90673Sjfb int oldc, tc, oldl; 89708f90673Sjfb u_int numtries; 89808f90673Sjfb 899cc649edbSjfb /* XXX move the isqrt() out of the macro to avoid multiple calls */ 900cc649edbSjfb const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 90108f90673Sjfb 90208f90673Sjfb k = 0; 903ece76a70Sjoris if ((ret = newcand(0, 0, 0)) < 0) 904ece76a70Sjoris return (-1); 905ece76a70Sjoris c[0] = ret; 90608f90673Sjfb for (i = 1; i <= n; i++) { 90708f90673Sjfb j = a[i]; 90808f90673Sjfb if (j == 0) 90908f90673Sjfb continue; 91008f90673Sjfb y = -b[j]; 91108f90673Sjfb oldl = 0; 91208f90673Sjfb oldc = c[0]; 91308f90673Sjfb numtries = 0; 91408f90673Sjfb do { 91508f90673Sjfb if (y <= clist[oldc].y) 91608f90673Sjfb continue; 91708f90673Sjfb l = search(c, k, y); 91808f90673Sjfb if (l != oldl + 1) 91908f90673Sjfb oldc = c[l - 1]; 92008f90673Sjfb if (l <= k) { 92108f90673Sjfb if (clist[c[l]].y <= y) 92208f90673Sjfb continue; 92308f90673Sjfb tc = c[l]; 924ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 925ece76a70Sjoris return (-1); 926ece76a70Sjoris c[l] = ret; 92708f90673Sjfb oldc = tc; 92808f90673Sjfb oldl = l; 92908f90673Sjfb numtries++; 93008f90673Sjfb } else { 931ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 932ece76a70Sjoris return (-1); 933ece76a70Sjoris c[l] = ret; 93408f90673Sjfb k++; 93508f90673Sjfb break; 93608f90673Sjfb } 93708f90673Sjfb } while ((y = b[++j]) > 0 && numtries < bound); 93808f90673Sjfb } 93908f90673Sjfb return (k); 94008f90673Sjfb } 94108f90673Sjfb 94208f90673Sjfb static int 94308f90673Sjfb newcand(int x, int y, int pred) 94408f90673Sjfb { 94518501190Sniallo struct cand *q, *tmp; 94618501190Sniallo int newclistlen; 94708f90673Sjfb 94808f90673Sjfb if (clen == clistlen) { 94918501190Sniallo newclistlen = clistlen * 11 / 10; 9502e0e138cSray tmp = xrealloc(clist, newclistlen, sizeof(cand)); 95118501190Sniallo clist = tmp; 95218501190Sniallo clistlen = newclistlen; 95308f90673Sjfb } 95408f90673Sjfb q = clist + clen; 95508f90673Sjfb q->x = x; 95608f90673Sjfb q->y = y; 95708f90673Sjfb q->pred = pred; 95808f90673Sjfb return (clen++); 95908f90673Sjfb } 96008f90673Sjfb 96108f90673Sjfb static int 96208f90673Sjfb search(int *c, int k, int y) 96308f90673Sjfb { 96408f90673Sjfb int i, j, l, t; 96508f90673Sjfb 96608f90673Sjfb if (clist[c[k]].y < y) /* quick look for typical case */ 96708f90673Sjfb return (k + 1); 96808f90673Sjfb i = 0; 96908f90673Sjfb j = k + 1; 970b2dc910bSray for (;;) { 971b2dc910bSray l = (i + j) / 2; 972b2dc910bSray if (l <= i) 97308f90673Sjfb break; 97408f90673Sjfb t = clist[c[l]].y; 97508f90673Sjfb if (t > y) 97608f90673Sjfb j = l; 97708f90673Sjfb else if (t < y) 97808f90673Sjfb i = l; 97908f90673Sjfb else 98008f90673Sjfb return (l); 98108f90673Sjfb } 98208f90673Sjfb return (l + 1); 98308f90673Sjfb } 98408f90673Sjfb 98508f90673Sjfb static void 98608f90673Sjfb unravel(int p) 98708f90673Sjfb { 98808f90673Sjfb struct cand *q; 98908f90673Sjfb int i; 99008f90673Sjfb 991e4276007Sjfb for (i = 0; i <= diff_len[0]; i++) 99208f90673Sjfb J[i] = i <= pref ? i : 993e4276007Sjfb i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 99408f90673Sjfb for (q = clist + p; q->y != 0; q = clist + q->pred) 99508f90673Sjfb J[q->x + pref] = q->y + pref; 99608f90673Sjfb } 99708f90673Sjfb 99808f90673Sjfb /* 99908f90673Sjfb * Check does double duty: 100008f90673Sjfb * 1. ferret out any fortuitous correspondences due 100108f90673Sjfb * to confounding by hashing (which result in "jackpot") 100208f90673Sjfb * 2. collect random access indexes to the two files 100308f90673Sjfb */ 100408f90673Sjfb static void 100508f90673Sjfb check(FILE *f1, FILE *f2) 100608f90673Sjfb { 100708f90673Sjfb int i, j, jackpot, c, d; 100808f90673Sjfb long ctold, ctnew; 100908f90673Sjfb 101008f90673Sjfb rewind(f1); 101108f90673Sjfb rewind(f2); 101208f90673Sjfb j = 1; 101308f90673Sjfb ixold[0] = ixnew[0] = 0; 101408f90673Sjfb jackpot = 0; 101508f90673Sjfb ctold = ctnew = 0; 1016e4276007Sjfb for (i = 1; i <= diff_len[0]; i++) { 101708f90673Sjfb if (J[i] == 0) { 101808f90673Sjfb ixold[i] = ctold += skipline(f1); 101908f90673Sjfb continue; 102008f90673Sjfb } 102108f90673Sjfb while (j < J[i]) { 102208f90673Sjfb ixnew[j] = ctnew += skipline(f2); 102308f90673Sjfb j++; 102408f90673Sjfb } 102548dc77e6Sxsa if ((bflag == 1)|| (wflag == 1) || (iflag == 1)) { 102608f90673Sjfb for (;;) { 102708f90673Sjfb c = getc(f1); 102808f90673Sjfb d = getc(f2); 102908f90673Sjfb /* 103008f90673Sjfb * GNU diff ignores a missing newline 103108f90673Sjfb * in one file if bflag || wflag. 103208f90673Sjfb */ 103348dc77e6Sxsa if (((bflag == 1) || (wflag == 1)) && 103408f90673Sjfb ((c == EOF && d == '\n') || 103508f90673Sjfb (c == '\n' && d == EOF))) { 103608f90673Sjfb break; 103708f90673Sjfb } 103808f90673Sjfb ctold++; 103908f90673Sjfb ctnew++; 104048dc77e6Sxsa if ((bflag == 1) && isspace(c) && isspace(d)) { 104108f90673Sjfb do { 104208f90673Sjfb if (c == '\n') 104308f90673Sjfb break; 104408f90673Sjfb ctold++; 104508f90673Sjfb } while (isspace(c = getc(f1))); 104608f90673Sjfb do { 104708f90673Sjfb if (d == '\n') 104808f90673Sjfb break; 104908f90673Sjfb ctnew++; 105008f90673Sjfb } while (isspace(d = getc(f2))); 105148dc77e6Sxsa } else if (wflag == 1) { 105208f90673Sjfb while (isspace(c) && c != '\n') { 105308f90673Sjfb c = getc(f1); 105408f90673Sjfb ctold++; 105508f90673Sjfb } 105608f90673Sjfb while (isspace(d) && d != '\n') { 105708f90673Sjfb d = getc(f2); 105808f90673Sjfb ctnew++; 105908f90673Sjfb } 106008f90673Sjfb } 106108f90673Sjfb if (chrtran[c] != chrtran[d]) { 106208f90673Sjfb jackpot++; 106308f90673Sjfb J[i] = 0; 106437af5b8bSxsa if ((c != '\n') && (c != EOF)) 106508f90673Sjfb ctold += skipline(f1); 106637af5b8bSxsa if ((d != '\n') && (c != EOF)) 106708f90673Sjfb ctnew += skipline(f2); 106808f90673Sjfb break; 106908f90673Sjfb } 107037af5b8bSxsa if ((c == '\n') || (c == EOF)) 107108f90673Sjfb break; 107208f90673Sjfb } 107308f90673Sjfb } else { 107408f90673Sjfb for (;;) { 107508f90673Sjfb ctold++; 107608f90673Sjfb ctnew++; 107708f90673Sjfb if ((c = getc(f1)) != (d = getc(f2))) { 107808f90673Sjfb /* jackpot++; */ 107908f90673Sjfb J[i] = 0; 108037af5b8bSxsa if ((c != '\n') && (c != EOF)) 108108f90673Sjfb ctold += skipline(f1); 108237af5b8bSxsa if ((d != '\n') && (c != EOF)) 108308f90673Sjfb ctnew += skipline(f2); 108408f90673Sjfb break; 108508f90673Sjfb } 108637af5b8bSxsa if ((c == '\n') || (c == EOF)) 108708f90673Sjfb break; 108808f90673Sjfb } 108908f90673Sjfb } 109008f90673Sjfb ixold[i] = ctold; 109108f90673Sjfb ixnew[j] = ctnew; 109208f90673Sjfb j++; 109308f90673Sjfb } 1094e4276007Sjfb for (; j <= diff_len[1]; j++) 109508f90673Sjfb ixnew[j] = ctnew += skipline(f2); 109608f90673Sjfb /* 109737af5b8bSxsa * if (jackpot != 0) 10985ac8b1e7Sjoris * cvs_printf("jackpot\n"); 109908f90673Sjfb */ 110008f90673Sjfb } 110108f90673Sjfb 110208f90673Sjfb /* shellsort CACM #201 */ 110308f90673Sjfb static void 110408f90673Sjfb sort(struct line *a, int n) 110508f90673Sjfb { 110608f90673Sjfb struct line *ai, *aim, w; 110708f90673Sjfb int j, m = 0, k; 110808f90673Sjfb 110908f90673Sjfb if (n == 0) 111008f90673Sjfb return; 111108f90673Sjfb for (j = 1; j <= n; j *= 2) 111208f90673Sjfb m = 2 * j - 1; 111308f90673Sjfb for (m /= 2; m != 0; m /= 2) { 111408f90673Sjfb k = n - m; 111508f90673Sjfb for (j = 1; j <= k; j++) { 111608f90673Sjfb for (ai = &a[j]; ai > a; ai -= m) { 111708f90673Sjfb aim = &ai[m]; 111808f90673Sjfb if (aim < ai) 111908f90673Sjfb break; /* wraparound */ 112008f90673Sjfb if (aim->value > ai[0].value || 112108f90673Sjfb (aim->value == ai[0].value && 112208f90673Sjfb aim->serial > ai[0].serial)) 112308f90673Sjfb break; 112408f90673Sjfb w.value = ai[0].value; 112508f90673Sjfb ai[0].value = aim->value; 112608f90673Sjfb aim->value = w.value; 112708f90673Sjfb w.serial = ai[0].serial; 112808f90673Sjfb ai[0].serial = aim->serial; 112908f90673Sjfb aim->serial = w.serial; 113008f90673Sjfb } 113108f90673Sjfb } 113208f90673Sjfb } 113308f90673Sjfb } 113408f90673Sjfb 113508f90673Sjfb static void 113608f90673Sjfb unsort(struct line *f, int l, int *b) 113708f90673Sjfb { 113808f90673Sjfb int *a, i; 113908f90673Sjfb 1140b39d2e28Sray a = (int *)xcalloc(l + 1, sizeof(int)); 114108f90673Sjfb for (i = 1; i <= l; i++) 114208f90673Sjfb a[f[i].serial] = f[i].value; 114308f90673Sjfb for (i = 1; i <= l; i++) 114408f90673Sjfb b[i] = a[i]; 11450450b43bSjoris xfree(a); 114608f90673Sjfb } 114708f90673Sjfb 114808f90673Sjfb static int 114908f90673Sjfb skipline(FILE *f) 115008f90673Sjfb { 115108f90673Sjfb int i, c; 115208f90673Sjfb 115308f90673Sjfb for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 115408f90673Sjfb continue; 115508f90673Sjfb return (i); 115608f90673Sjfb } 115708f90673Sjfb 115808f90673Sjfb static void 1159b2dc910bSray output(FILE *f1, FILE *f2) 116008f90673Sjfb { 116108f90673Sjfb int m, i0, i1, j0, j1; 116208f90673Sjfb 116308f90673Sjfb rewind(f1); 116408f90673Sjfb rewind(f2); 1165e4276007Sjfb m = diff_len[0]; 116608f90673Sjfb J[0] = 0; 1167e4276007Sjfb J[m + 1] = diff_len[1] + 1; 116808f90673Sjfb for (i0 = 1; i0 <= m; i0 = i1 + 1) { 116908f90673Sjfb while (i0 <= m && J[i0] == J[i0 - 1] + 1) 117008f90673Sjfb i0++; 117108f90673Sjfb j0 = J[i0 - 1] + 1; 117208f90673Sjfb i1 = i0 - 1; 117308f90673Sjfb while (i1 < m && J[i1 + 1] == 0) 117408f90673Sjfb i1++; 117508f90673Sjfb j1 = J[i1 + 1] - 1; 117608f90673Sjfb J[i1] = j1; 1177b2dc910bSray change(f1, f2, i0, i1, j0, j1); 117808f90673Sjfb } 117908f90673Sjfb if (m == 0) 1180b2dc910bSray change(f1, f2, 1, 0, 1, diff_len[1]); 1181f9b67873Sniallo if (diff_format == D_IFDEF) { 118208f90673Sjfb for (;;) { 118308f90673Sjfb #define c i0 118408f90673Sjfb if ((c = getc(f1)) == EOF) 118508f90673Sjfb return; 1186f9b67873Sniallo diff_output("%c", c); 118708f90673Sjfb } 118808f90673Sjfb #undef c 118908f90673Sjfb } 119008f90673Sjfb if (anychange != 0) { 1191f9b67873Sniallo if (diff_format == D_CONTEXT) 119208f90673Sjfb dump_context_vec(f1, f2); 1193f9b67873Sniallo else if (diff_format == D_UNIFIED) 119408f90673Sjfb dump_unified_vec(f1, f2); 119508f90673Sjfb } 119608f90673Sjfb } 119708f90673Sjfb 119808f90673Sjfb static __inline void 119908f90673Sjfb range(int a, int b, char *separator) 120008f90673Sjfb { 1201f9b67873Sniallo diff_output("%d", a > b ? b : a); 120208f90673Sjfb if (a < b) 1203f9b67873Sniallo diff_output("%s%d", separator, b); 120408f90673Sjfb } 120508f90673Sjfb 120608f90673Sjfb static __inline void 120708f90673Sjfb uni_range(int a, int b) 120808f90673Sjfb { 120908f90673Sjfb if (a < b) 1210f9b67873Sniallo diff_output("%d,%d", a, b - a + 1); 121108f90673Sjfb else if (a == b) 1212f9b67873Sniallo diff_output("%d", b); 121308f90673Sjfb else 1214f9b67873Sniallo diff_output("%d,0", b); 121508f90673Sjfb } 121608f90673Sjfb 121708f90673Sjfb static char * 12182a0de57dSjfb preadline(int fd, size_t rlen, off_t off) 121908f90673Sjfb { 122008f90673Sjfb char *line; 122108f90673Sjfb ssize_t nr; 122208f90673Sjfb 12230450b43bSjoris line = xmalloc(rlen + 1); 12242a0de57dSjfb if ((nr = pread(fd, line, rlen, off)) < 0) { 122508f90673Sjfb cvs_log(LP_ERRNO, "preadline failed"); 122608f90673Sjfb return (NULL); 122708f90673Sjfb } 122808f90673Sjfb line[nr] = '\0'; 122908f90673Sjfb return (line); 123008f90673Sjfb } 123108f90673Sjfb 123208f90673Sjfb static int 123308f90673Sjfb ignoreline(char *line) 123408f90673Sjfb { 123508f90673Sjfb int ret; 123608f90673Sjfb 1237f1901a5aSxsa ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); 12380450b43bSjoris xfree(line); 123908f90673Sjfb return (ret == 0); /* if it matched, it should be ignored. */ 124008f90673Sjfb } 124108f90673Sjfb 124208f90673Sjfb /* 124308f90673Sjfb * Indicate that there is a difference between lines a and b of the from file 124408f90673Sjfb * to get to lines c to d of the to file. If a is greater then b then there 124508f90673Sjfb * are no lines in the from file involved and this means that there were 124608f90673Sjfb * lines appended (beginning at b). If c is greater than d then there are 124708f90673Sjfb * lines missing from the to file. 124808f90673Sjfb */ 124908f90673Sjfb static void 1250b2dc910bSray change(FILE *f1, FILE *f2, int a, int b, int c, int d) 125108f90673Sjfb { 125208f90673Sjfb static size_t max_context = 64; 125308f90673Sjfb int i; 125408f90673Sjfb 1255f9b67873Sniallo if (diff_format != D_IFDEF && a > b && c > d) 125608f90673Sjfb return; 125708f90673Sjfb if (ignore_pats != NULL) { 125808f90673Sjfb char *line; 125908f90673Sjfb /* 126008f90673Sjfb * All lines in the change, insert, or delete must 126108f90673Sjfb * match an ignore pattern for the change to be 126208f90673Sjfb * ignored. 126308f90673Sjfb */ 126408f90673Sjfb if (a <= b) { /* Changes and deletes. */ 126508f90673Sjfb for (i = a; i <= b; i++) { 126608f90673Sjfb line = preadline(fileno(f1), 126708f90673Sjfb ixold[i] - ixold[i - 1], ixold[i - 1]); 126808f90673Sjfb if (!ignoreline(line)) 126908f90673Sjfb goto proceed; 127008f90673Sjfb } 127108f90673Sjfb } 127237af5b8bSxsa if ((a > b) || (c <= d)) { /* Changes and inserts. */ 127308f90673Sjfb for (i = c; i <= d; i++) { 127408f90673Sjfb line = preadline(fileno(f2), 127508f90673Sjfb ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 127608f90673Sjfb if (!ignoreline(line)) 127708f90673Sjfb goto proceed; 127808f90673Sjfb } 127908f90673Sjfb } 128008f90673Sjfb return; 128108f90673Sjfb } 128208f90673Sjfb proceed: 1283f9b67873Sniallo if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 128408f90673Sjfb /* 128508f90673Sjfb * Allocate change records as needed. 128608f90673Sjfb */ 128708f90673Sjfb if (context_vec_ptr == context_vec_end - 1) { 128818501190Sniallo struct context_vec *tmp; 128908f90673Sjfb ptrdiff_t offset = context_vec_ptr - context_vec_start; 129008f90673Sjfb max_context <<= 1; 12912e0e138cSray tmp = xrealloc(context_vec_start, max_context, 12920450b43bSjoris sizeof(struct context_vec)); 129318501190Sniallo context_vec_start = tmp; 129408f90673Sjfb context_vec_end = context_vec_start + max_context; 129508f90673Sjfb context_vec_ptr = context_vec_start + offset; 129608f90673Sjfb } 129708f90673Sjfb if (anychange == 0) { 129808f90673Sjfb /* 129908f90673Sjfb * Print the context/unidiff header first time through. 130008f90673Sjfb */ 1301f9b67873Sniallo diff_output("%s %s %s", 1302f9b67873Sniallo diff_format == D_CONTEXT ? "***" : "---", diff_file, 130308f90673Sjfb ctime(&stb1.st_mtime)); 1304f9b67873Sniallo diff_output("%s %s %s", 1305f9b67873Sniallo diff_format == D_CONTEXT ? "---" : "+++", diff_file, 130608f90673Sjfb ctime(&stb2.st_mtime)); 130708f90673Sjfb anychange = 1; 130808f90673Sjfb } else if (a > context_vec_ptr->b + (2 * context) + 1 && 130908f90673Sjfb c > context_vec_ptr->d + (2 * context) + 1) { 131008f90673Sjfb /* 131108f90673Sjfb * If this change is more than 'context' lines from the 131208f90673Sjfb * previous change, dump the record and reset it. 131308f90673Sjfb */ 1314f9b67873Sniallo if (diff_format == D_CONTEXT) 131508f90673Sjfb dump_context_vec(f1, f2); 131608f90673Sjfb else 131708f90673Sjfb dump_unified_vec(f1, f2); 131808f90673Sjfb } 131908f90673Sjfb context_vec_ptr++; 132008f90673Sjfb context_vec_ptr->a = a; 132108f90673Sjfb context_vec_ptr->b = b; 132208f90673Sjfb context_vec_ptr->c = c; 132308f90673Sjfb context_vec_ptr->d = d; 132408f90673Sjfb return; 132508f90673Sjfb } 132608f90673Sjfb if (anychange == 0) 132708f90673Sjfb anychange = 1; 1328f9b67873Sniallo switch (diff_format) { 132908f90673Sjfb case D_BRIEF: 133008f90673Sjfb return; 133108f90673Sjfb case D_NORMAL: 133208f90673Sjfb range(a, b, ","); 1333f9b67873Sniallo diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 1334f9b67873Sniallo if (diff_format == D_NORMAL) 133508f90673Sjfb range(c, d, ","); 1336f9b67873Sniallo diff_output("\n"); 133708f90673Sjfb break; 1338394180a4Sjfb case D_RCSDIFF: 1339394180a4Sjfb if (a > b) 1340f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1341394180a4Sjfb else { 1342f9b67873Sniallo diff_output("d%d %d\n", a, b - a + 1); 1343394180a4Sjfb 1344394180a4Sjfb if (!(c > d)) /* add changed lines */ 1345f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1346394180a4Sjfb } 1347394180a4Sjfb break; 134808f90673Sjfb } 1349f9b67873Sniallo if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 135008f90673Sjfb fetch(ixold, a, b, f1, '<', 1); 1351f9b67873Sniallo if (a <= b && c <= d && diff_format == D_NORMAL) 1352206543eeSjoris diff_output("---\n"); 135308f90673Sjfb } 1354a44f42a4Sxsa fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); 135508f90673Sjfb if (inifdef) { 1356f9b67873Sniallo diff_output("#endif /* %s */\n", ifdefname); 135708f90673Sjfb inifdef = 0; 135808f90673Sjfb } 135908f90673Sjfb } 136008f90673Sjfb 1361a44f42a4Sxsa static void 136208f90673Sjfb fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 136308f90673Sjfb { 1364d990145dSray long j, nc; 1365d990145dSray int i, c, col; 136608f90673Sjfb 136708f90673Sjfb /* 136808f90673Sjfb * When doing #ifdef's, copy down to current line 136908f90673Sjfb * if this is the first file, so that stuff makes it to output. 137008f90673Sjfb */ 1371f9b67873Sniallo if (diff_format == D_IFDEF && oldfile) { 137208f90673Sjfb long curpos = ftell(lb); 137308f90673Sjfb /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 137408f90673Sjfb nc = f[a > b ? b : a - 1] - curpos; 137508f90673Sjfb for (i = 0; i < nc; i++) 1376f9b67873Sniallo diff_output("%c", getc(lb)); 137708f90673Sjfb } 137808f90673Sjfb if (a > b) 1379a44f42a4Sxsa return; 1380f9b67873Sniallo if (diff_format == D_IFDEF) { 138108f90673Sjfb if (inifdef) { 1382f9b67873Sniallo diff_output("#else /* %s%s */\n", 138308f90673Sjfb oldfile == 1 ? "!" : "", ifdefname); 138408f90673Sjfb } else { 138508f90673Sjfb if (oldfile) 1386f9b67873Sniallo diff_output("#ifndef %s\n", ifdefname); 138708f90673Sjfb else 1388f9b67873Sniallo diff_output("#ifdef %s\n", ifdefname); 138908f90673Sjfb } 139008f90673Sjfb inifdef = 1 + oldfile; 139108f90673Sjfb } 139208f90673Sjfb for (i = a; i <= b; i++) { 139308f90673Sjfb fseek(lb, f[i - 1], SEEK_SET); 139408f90673Sjfb nc = f[i] - f[i - 1]; 1395f9b67873Sniallo if (diff_format != D_IFDEF && ch != '\0') { 1396f9b67873Sniallo diff_output("%c", ch); 139748dc77e6Sxsa if ((Tflag == 1 ) && (diff_format == D_NORMAL || 13989c5161e4Sjoris diff_format == D_CONTEXT || 13999c5161e4Sjoris diff_format == D_UNIFIED)) 1400f9b67873Sniallo diff_output("\t"); 1401f9b67873Sniallo else if (diff_format != D_UNIFIED) 1402f9b67873Sniallo diff_output(" "); 140308f90673Sjfb } 140408f90673Sjfb col = 0; 1405d990145dSray for (j = 0; j < nc; j++) { 140608f90673Sjfb if ((c = getc(lb)) == EOF) { 1407f9b67873Sniallo if (diff_format == D_RCSDIFF) 1408b9a6f00eSxsa cvs_log(LP_WARN, 1409b9a6f00eSxsa "No newline at end of file"); 1410394180a4Sjfb else 14119c5161e4Sjoris diff_output("\n\\ No newline at end of " 14129c5161e4Sjoris "file"); 1413a44f42a4Sxsa return; 141408f90673Sjfb } 141548dc77e6Sxsa if ((c == '\t') && (tflag == 1)) { 141608f90673Sjfb do { 1417f9b67873Sniallo diff_output(" "); 141808f90673Sjfb } while (++col & 7); 141908f90673Sjfb } else { 1420f9b67873Sniallo diff_output("%c", c); 142108f90673Sjfb col++; 142208f90673Sjfb } 142308f90673Sjfb } 142408f90673Sjfb } 142508f90673Sjfb } 142608f90673Sjfb 142708f90673Sjfb /* 142808f90673Sjfb * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 142908f90673Sjfb */ 143008f90673Sjfb static int 143108f90673Sjfb readhash(FILE *f) 143208f90673Sjfb { 143308f90673Sjfb int i, t, space; 143408f90673Sjfb int sum; 143508f90673Sjfb 143608f90673Sjfb sum = 1; 143708f90673Sjfb space = 0; 143848dc77e6Sxsa if ((bflag != 1) && (wflag != 1)) { 143948dc77e6Sxsa if (iflag == 1) 144008f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 144108f90673Sjfb if (t == EOF) { 144208f90673Sjfb if (i == 0) 144308f90673Sjfb return (0); 144408f90673Sjfb break; 144508f90673Sjfb } 144608f90673Sjfb sum = sum * 127 + chrtran[t]; 144708f90673Sjfb } 144808f90673Sjfb else 144908f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 145008f90673Sjfb if (t == EOF) { 145108f90673Sjfb if (i == 0) 145208f90673Sjfb return (0); 145308f90673Sjfb break; 145408f90673Sjfb } 145508f90673Sjfb sum = sum * 127 + t; 145608f90673Sjfb } 145708f90673Sjfb } else { 145808f90673Sjfb for (i = 0;;) { 145908f90673Sjfb switch (t = getc(f)) { 146008f90673Sjfb case '\t': 146108f90673Sjfb case ' ': 146208f90673Sjfb space++; 146308f90673Sjfb continue; 146408f90673Sjfb default: 146548dc77e6Sxsa if ((space != 0) && (wflag != 1)) { 146608f90673Sjfb i++; 146708f90673Sjfb space = 0; 146808f90673Sjfb } 146908f90673Sjfb sum = sum * 127 + chrtran[t]; 147008f90673Sjfb i++; 147108f90673Sjfb continue; 147208f90673Sjfb case EOF: 147308f90673Sjfb if (i == 0) 147408f90673Sjfb return (0); 147508f90673Sjfb /* FALLTHROUGH */ 147608f90673Sjfb case '\n': 147708f90673Sjfb break; 147808f90673Sjfb } 147908f90673Sjfb break; 148008f90673Sjfb } 148108f90673Sjfb } 148208f90673Sjfb /* 148308f90673Sjfb * There is a remote possibility that we end up with a zero sum. 148408f90673Sjfb * Zero is used as an EOF marker, so return 1 instead. 148508f90673Sjfb */ 148608f90673Sjfb return (sum == 0 ? 1 : sum); 148708f90673Sjfb } 148808f90673Sjfb 148908f90673Sjfb static int 149008f90673Sjfb asciifile(FILE *f) 149108f90673Sjfb { 149208f90673Sjfb char buf[BUFSIZ]; 1493d990145dSray size_t i, cnt; 149408f90673Sjfb 149548dc77e6Sxsa if ((aflag == 1) || (f == NULL)) 149608f90673Sjfb return (1); 149708f90673Sjfb 149808f90673Sjfb rewind(f); 1499f1901a5aSxsa cnt = fread(buf, (size_t)1, sizeof(buf), f); 150008f90673Sjfb for (i = 0; i < cnt; i++) 150108f90673Sjfb if (!isprint(buf[i]) && !isspace(buf[i])) 150208f90673Sjfb return (0); 150308f90673Sjfb return (1); 150408f90673Sjfb } 150508f90673Sjfb 15065e78344dSjfb static char* 15075e78344dSjfb match_function(const long *f, int pos, FILE *fp) 15085e78344dSjfb { 15095e78344dSjfb unsigned char buf[FUNCTION_CONTEXT_SIZE]; 15105e78344dSjfb size_t nc; 15115e78344dSjfb int last = lastline; 15125e78344dSjfb char *p; 15135e78344dSjfb 15145e78344dSjfb lastline = pos; 15155e78344dSjfb while (pos > last) { 15165e78344dSjfb fseek(fp, f[pos - 1], SEEK_SET); 15175e78344dSjfb nc = f[pos] - f[pos - 1]; 15185e78344dSjfb if (nc >= sizeof(buf)) 15195e78344dSjfb nc = sizeof(buf) - 1; 1520f1901a5aSxsa nc = fread(buf, (size_t)1, nc, fp); 15215e78344dSjfb if (nc > 0) { 15225e78344dSjfb buf[nc] = '\0'; 1523634926d6Sniallo p = strchr((const char *)buf, '\n'); 15245e78344dSjfb if (p != NULL) 15255e78344dSjfb *p = '\0'; 15265e78344dSjfb if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 15274c06e5f6Sreyk strlcpy(lastbuf, (const char *)buf, 15284c06e5f6Sreyk sizeof lastbuf); 15295e78344dSjfb lastmatchline = pos; 15305e78344dSjfb return lastbuf; 15315e78344dSjfb } 15325e78344dSjfb } 15335e78344dSjfb pos--; 15345e78344dSjfb } 15355e78344dSjfb return (lastmatchline > 0) ? lastbuf : NULL; 15365e78344dSjfb } 15375e78344dSjfb 153808f90673Sjfb 153908f90673Sjfb /* dump accumulated "context" diff changes */ 154008f90673Sjfb static void 154108f90673Sjfb dump_context_vec(FILE *f1, FILE *f2) 154208f90673Sjfb { 154308f90673Sjfb struct context_vec *cvp = context_vec_start; 154408f90673Sjfb int lowa, upb, lowc, upd, do_output; 154508f90673Sjfb int a, b, c, d; 15465e78344dSjfb char ch, *f; 154708f90673Sjfb 154808f90673Sjfb if (context_vec_start > context_vec_ptr) 154908f90673Sjfb return; 155008f90673Sjfb 155108f90673Sjfb b = d = 0; /* gcc */ 1552dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1553e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1554dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1555e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 155608f90673Sjfb 1557f9b67873Sniallo diff_output("***************"); 155848dc77e6Sxsa if (pflag == 1) { 15595e78344dSjfb f = match_function(ixold, lowa - 1, f1); 15605e78344dSjfb if (f != NULL) { 1561f9b67873Sniallo diff_output(" "); 1562f9b67873Sniallo diff_output("%s", f); 15635e78344dSjfb } 15645e78344dSjfb } 1565f9b67873Sniallo diff_output("\n*** "); 156608f90673Sjfb range(lowa, upb, ","); 1567f9b67873Sniallo diff_output(" ****\n"); 156808f90673Sjfb 156908f90673Sjfb /* 157008f90673Sjfb * Output changes to the "old" file. The first loop suppresses 157108f90673Sjfb * output if there were no changes to the "old" file (we'll see 157208f90673Sjfb * the "old" lines as context in the "new" list). 157308f90673Sjfb */ 157408f90673Sjfb do_output = 0; 157508f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) 157608f90673Sjfb if (cvp->a <= cvp->b) { 157708f90673Sjfb cvp = context_vec_start; 157808f90673Sjfb do_output++; 157908f90673Sjfb break; 158008f90673Sjfb } 158137af5b8bSxsa if (do_output != 0) { 158208f90673Sjfb while (cvp <= context_vec_ptr) { 158308f90673Sjfb a = cvp->a; 158408f90673Sjfb b = cvp->b; 158508f90673Sjfb c = cvp->c; 158608f90673Sjfb d = cvp->d; 158708f90673Sjfb 158808f90673Sjfb if (a <= b && c <= d) 158908f90673Sjfb ch = 'c'; 159008f90673Sjfb else 159108f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 159208f90673Sjfb 159308f90673Sjfb if (ch == 'a') 159408f90673Sjfb fetch(ixold, lowa, b, f1, ' ', 0); 159508f90673Sjfb else { 159608f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 159708f90673Sjfb fetch(ixold, a, b, f1, 159808f90673Sjfb ch == 'c' ? '!' : '-', 0); 159908f90673Sjfb } 160008f90673Sjfb lowa = b + 1; 160108f90673Sjfb cvp++; 160208f90673Sjfb } 160308f90673Sjfb fetch(ixold, b + 1, upb, f1, ' ', 0); 160408f90673Sjfb } 160508f90673Sjfb /* output changes to the "new" file */ 1606f9b67873Sniallo diff_output("--- "); 160708f90673Sjfb range(lowc, upd, ","); 1608f9b67873Sniallo diff_output(" ----\n"); 160908f90673Sjfb 161008f90673Sjfb do_output = 0; 161108f90673Sjfb for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 161208f90673Sjfb if (cvp->c <= cvp->d) { 161308f90673Sjfb cvp = context_vec_start; 161408f90673Sjfb do_output++; 161508f90673Sjfb break; 161608f90673Sjfb } 161737af5b8bSxsa if (do_output != 0) { 161808f90673Sjfb while (cvp <= context_vec_ptr) { 161908f90673Sjfb a = cvp->a; 162008f90673Sjfb b = cvp->b; 162108f90673Sjfb c = cvp->c; 162208f90673Sjfb d = cvp->d; 162308f90673Sjfb 162408f90673Sjfb if (a <= b && c <= d) 162508f90673Sjfb ch = 'c'; 162608f90673Sjfb else 162708f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 162808f90673Sjfb 162908f90673Sjfb if (ch == 'd') 163008f90673Sjfb fetch(ixnew, lowc, d, f2, ' ', 0); 163108f90673Sjfb else { 163208f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 163308f90673Sjfb fetch(ixnew, c, d, f2, 163408f90673Sjfb ch == 'c' ? '!' : '+', 0); 163508f90673Sjfb } 163608f90673Sjfb lowc = d + 1; 163708f90673Sjfb cvp++; 163808f90673Sjfb } 163908f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 164008f90673Sjfb } 164108f90673Sjfb context_vec_ptr = context_vec_start - 1; 164208f90673Sjfb } 164308f90673Sjfb 164408f90673Sjfb /* dump accumulated "unified" diff changes */ 164508f90673Sjfb static void 164608f90673Sjfb dump_unified_vec(FILE *f1, FILE *f2) 164708f90673Sjfb { 164808f90673Sjfb struct context_vec *cvp = context_vec_start; 164908f90673Sjfb int lowa, upb, lowc, upd; 165008f90673Sjfb int a, b, c, d; 16515e78344dSjfb char ch, *f; 165208f90673Sjfb 165308f90673Sjfb if (context_vec_start > context_vec_ptr) 165408f90673Sjfb return; 165508f90673Sjfb 165608f90673Sjfb b = d = 0; /* gcc */ 1657dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1658e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1659dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1660e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 166108f90673Sjfb 1662f9b67873Sniallo diff_output("@@ -"); 166308f90673Sjfb uni_range(lowa, upb); 1664f9b67873Sniallo diff_output(" +"); 166508f90673Sjfb uni_range(lowc, upd); 1666f9b67873Sniallo diff_output(" @@"); 166748dc77e6Sxsa if (pflag == 1) { 16685e78344dSjfb f = match_function(ixold, lowa - 1, f1); 16695e78344dSjfb if (f != NULL) { 1670f9b67873Sniallo diff_output(" "); 1671f9b67873Sniallo diff_output("%s", f); 16725e78344dSjfb } 16735e78344dSjfb } 1674f9b67873Sniallo diff_output("\n"); 167508f90673Sjfb 167608f90673Sjfb /* 167708f90673Sjfb * Output changes in "unified" diff format--the old and new lines 167808f90673Sjfb * are printed together. 167908f90673Sjfb */ 168008f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) { 168108f90673Sjfb a = cvp->a; 168208f90673Sjfb b = cvp->b; 168308f90673Sjfb c = cvp->c; 168408f90673Sjfb d = cvp->d; 168508f90673Sjfb 168608f90673Sjfb /* 168708f90673Sjfb * c: both new and old changes 168808f90673Sjfb * d: only changes in the old file 168908f90673Sjfb * a: only changes in the new file 169008f90673Sjfb */ 169108f90673Sjfb if (a <= b && c <= d) 169208f90673Sjfb ch = 'c'; 169308f90673Sjfb else 169408f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 169508f90673Sjfb 169608f90673Sjfb switch (ch) { 169708f90673Sjfb case 'c': 169808f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 169908f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 170008f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 170108f90673Sjfb break; 170208f90673Sjfb case 'd': 170308f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 170408f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 170508f90673Sjfb break; 170608f90673Sjfb case 'a': 170708f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 170808f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 170908f90673Sjfb break; 171008f90673Sjfb } 171108f90673Sjfb lowa = b + 1; 171208f90673Sjfb lowc = d + 1; 171308f90673Sjfb } 171408f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 171508f90673Sjfb 171608f90673Sjfb context_vec_ptr = context_vec_start - 1; 171708f90673Sjfb } 1718f9b67873Sniallo 171901af718aSjoris void 1720f9b67873Sniallo diff_output(const char *fmt, ...) 1721f9b67873Sniallo { 1722f9b67873Sniallo va_list vap; 1723f9b67873Sniallo char *str; 1724f9b67873Sniallo 1725f9b67873Sniallo va_start(vap, fmt); 1726f9b67873Sniallo vasprintf(&str, fmt, vap); 1727f9b67873Sniallo if (diffbuf != NULL) 1728f9b67873Sniallo cvs_buf_append(diffbuf, str, strlen(str)); 1729f9b67873Sniallo else 1730f9b67873Sniallo cvs_printf("%s", str); 17310450b43bSjoris xfree(str); 1732f9b67873Sniallo va_end(vap); 1733f9b67873Sniallo } 1734