1*8dbc5e14Sxsa /* $OpenBSD: diff.c,v 1.73 2005/12/21 09:09:02 xsa 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 12908f90673Sjfb #include <sys/stat.h> 13008f90673Sjfb 1319225b0caSxsa #include <ctype.h> 1329225b0caSxsa #include <dirent.h> 133394180a4Sjfb #include <err.h> 13408f90673Sjfb #include <errno.h> 13508f90673Sjfb #include <fcntl.h> 13608f90673Sjfb #include <paths.h> 13708f90673Sjfb #include <regex.h> 13808f90673Sjfb #include <stddef.h> 1399225b0caSxsa #include <stdio.h> 1409225b0caSxsa #include <stdlib.h> 14108f90673Sjfb #include <string.h> 1429225b0caSxsa #include <unistd.h> 14308f90673Sjfb 1449225b0caSxsa #include "buf.h" 14508f90673Sjfb #include "cvs.h" 146af5bb824Sniallo #include "diff.h" 14708f90673Sjfb #include "log.h" 148dc6a6879Sjfb #include "proto.h" 14908f90673Sjfb 15008f90673Sjfb struct cand { 15108f90673Sjfb int x; 15208f90673Sjfb int y; 15308f90673Sjfb int pred; 15408f90673Sjfb } cand; 15508f90673Sjfb 15608f90673Sjfb struct line { 15708f90673Sjfb int serial; 15808f90673Sjfb int value; 15908f90673Sjfb } *file[2]; 16008f90673Sjfb 16108f90673Sjfb /* 16208f90673Sjfb * The following struct is used to record change in formation when 16308f90673Sjfb * doing a "context" or "unified" diff. (see routine "change" to 16408f90673Sjfb * understand the highly mnemonic field names) 16508f90673Sjfb */ 16608f90673Sjfb struct context_vec { 16708f90673Sjfb int a; /* start line in old file */ 16808f90673Sjfb int b; /* end line in old file */ 16908f90673Sjfb int c; /* start line in new file */ 17008f90673Sjfb int d; /* end line in new file */ 17108f90673Sjfb }; 17208f90673Sjfb 173dc6a6879Sjfb struct diff_arg { 174dc6a6879Sjfb char *rev1; 175dc6a6879Sjfb char *rev2; 176dc6a6879Sjfb char *date1; 177dc6a6879Sjfb char *date2; 178dc6a6879Sjfb }; 179dc6a6879Sjfb 180af5bb824Sniallo #if !defined(RCSPROG) 181e4276007Sjfb static int cvs_diff_init(struct cvs_cmd *, int, char **, int *); 182e4276007Sjfb static int cvs_diff_remote(CVSFILE *, void *); 183e4276007Sjfb static int cvs_diff_local(CVSFILE *, void *); 184e4276007Sjfb static int cvs_diff_pre_exec(struct cvsroot *); 185e4276007Sjfb static int cvs_diff_cleanup(void); 186af5bb824Sniallo #endif 18716cfc147Sjoris 18808f90673Sjfb static void output(const char *, FILE *, const char *, FILE *); 18908f90673Sjfb static void check(FILE *, FILE *); 19008f90673Sjfb static void range(int, int, char *); 19108f90673Sjfb static void uni_range(int, int); 19208f90673Sjfb static void dump_context_vec(FILE *, FILE *); 19308f90673Sjfb static void dump_unified_vec(FILE *, FILE *); 1947f535ec4Sjfb static int prepare(int, FILE *, off_t); 19508f90673Sjfb static void prune(void); 19608f90673Sjfb static void equiv(struct line *, int, struct line *, int, int *); 19708f90673Sjfb static void unravel(int); 19808f90673Sjfb static void unsort(struct line *, int, int *); 199ff1f7a8eSxsa static void change(const char *, FILE *, const char *, FILE *, int, 200ff1f7a8eSxsa int, int, int); 20108f90673Sjfb static void sort(struct line *, int); 20208f90673Sjfb static int ignoreline(char *); 20308f90673Sjfb static int asciifile(FILE *); 20408f90673Sjfb static int fetch(long *, int, int, FILE *, int, int); 20508f90673Sjfb static int newcand(int, int, int); 20608f90673Sjfb static int search(int *, int, int); 20708f90673Sjfb static int skipline(FILE *); 20808f90673Sjfb static int isqrt(int); 20908f90673Sjfb static int stone(int *, int, int *, int *); 21008f90673Sjfb static int readhash(FILE *); 21108f90673Sjfb static int files_differ(FILE *, FILE *); 2125e78344dSjfb static char *match_function(const long *, int, FILE *); 21308f90673Sjfb static char *preadline(int, size_t, off_t); 21408f90673Sjfb 21508f90673Sjfb 216af5bb824Sniallo #if !defined(RCSPROG) 217af5bb824Sniallo static int Nflag; 218af5bb824Sniallo #endif 219af5bb824Sniallo static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag; 22078de3304Sniallo static int context = 3; 221f9b67873Sniallo int diff_format = D_NORMAL; 2221ff4dac1Sjoris char *diff_file = NULL; 223c60b216dSxsa char diffargs[128]; 22408f90673Sjfb static struct stat stb1, stb2; 225af5bb824Sniallo static char *ifdefname, *ignore_pats; 22608f90673Sjfb regex_t ignore_re; 22708f90673Sjfb 22808f90673Sjfb static int *J; /* will be overlaid on class */ 22908f90673Sjfb static int *class; /* will be overlaid on file[0] */ 23008f90673Sjfb static int *klist; /* will be overlaid on file[0] after class */ 23108f90673Sjfb static int *member; /* will be overlaid on file[1] */ 23208f90673Sjfb static int clen; 23308f90673Sjfb static int inifdef; /* whether or not we are in a #ifdef block */ 234e4276007Sjfb static int diff_len[2]; 23508f90673Sjfb static int pref, suff; /* length of prefix and suffix */ 23608f90673Sjfb static int slen[2]; 23708f90673Sjfb static int anychange; 23808f90673Sjfb static long *ixnew; /* will be overlaid on file[1] */ 23908f90673Sjfb static long *ixold; /* will be overlaid on klist */ 24008f90673Sjfb static struct cand *clist; /* merely a free storage pot for candidates */ 24108f90673Sjfb static int clistlen; /* the length of clist */ 24208f90673Sjfb static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 24308f90673Sjfb static u_char *chrtran; /* translation table for case-folding */ 24408f90673Sjfb static struct context_vec *context_vec_start; 24508f90673Sjfb static struct context_vec *context_vec_end; 24608f90673Sjfb static struct context_vec *context_vec_ptr; 24708f90673Sjfb 24808f90673Sjfb #define FUNCTION_CONTEXT_SIZE 41 2495e78344dSjfb static char lastbuf[FUNCTION_CONTEXT_SIZE]; 25008f90673Sjfb static int lastline; 25108f90673Sjfb static int lastmatchline; 25201af718aSjoris BUF *diffbuf = NULL; 253f9b67873Sniallo 25408f90673Sjfb /* 25508f90673Sjfb * chrtran points to one of 2 translation tables: cup2low if folding upper to 25608f90673Sjfb * lower case clow2low if not folding case 25708f90673Sjfb */ 25808f90673Sjfb u_char clow2low[256] = { 25908f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 26008f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 26108f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 26208f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 26308f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 26408f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 26508f90673Sjfb 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 26608f90673Sjfb 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 26708f90673Sjfb 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 26808f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 26908f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 27008f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 27108f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 27208f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 27308f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 27408f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 27508f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 27608f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 27708f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 27808f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 27908f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 28008f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 28108f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 28208f90673Sjfb 0xfd, 0xfe, 0xff 28308f90673Sjfb }; 28408f90673Sjfb 28508f90673Sjfb u_char cup2low[256] = { 28608f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 28708f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 28808f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 28908f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 29008f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 29108f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 29208f90673Sjfb 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 29308f90673Sjfb 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 29408f90673Sjfb 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 29508f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 29608f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 29708f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 29808f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 29908f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 30008f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 30108f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 30208f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 30308f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 30408f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 30508f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 30608f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 30708f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 30808f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 30908f90673Sjfb 0xfd, 0xfe, 0xff 31008f90673Sjfb }; 31108f90673Sjfb 312af5bb824Sniallo #if !defined(RCSPROG) 313e4276007Sjfb struct cvs_cmd cvs_cmd_diff = { 314e4276007Sjfb CVS_OP_DIFF, CVS_REQ_DIFF, "diff", 315e4276007Sjfb { "di", "dif" }, 316e4276007Sjfb "Show differences between revisions", 317c9150269Sxsa "[-cilNnpu] [[-D date] [-r rev] [-D date2 | -r rev2]] " 318c9150269Sxsa "[-k mode] [file ...]", 319c9150269Sxsa "cD:iklNnpr:Ru", 32016cfc147Sjoris NULL, 32116cfc147Sjoris CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, 322e4276007Sjfb cvs_diff_init, 323e4276007Sjfb cvs_diff_pre_exec, 324e4276007Sjfb cvs_diff_remote, 325e4276007Sjfb cvs_diff_local, 326e4276007Sjfb NULL, 327e4276007Sjfb cvs_diff_cleanup, 328e4276007Sjfb CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR 329e4276007Sjfb }; 330e4276007Sjfb 331e4276007Sjfb 332e4276007Sjfb struct cvs_cmd cvs_cmd_rdiff = { 333e4276007Sjfb CVS_OP_RDIFF, CVS_REQ_DIFF, "rdiff", 334c9150269Sxsa { "pa", "patch" }, 335e4276007Sjfb "Create 'patch' format diffs between releases", 336c9150269Sxsa "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev " 337c9150269Sxsa "[-D date2 | -rev2] module ...", 338c9150269Sxsa "cD:flRr:stuV:", 339e4276007Sjfb NULL, 340e4276007Sjfb CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN, 341e4276007Sjfb cvs_diff_init, 342e4276007Sjfb cvs_diff_pre_exec, 343e4276007Sjfb cvs_diff_remote, 344e4276007Sjfb cvs_diff_local, 345e4276007Sjfb NULL, 346e4276007Sjfb cvs_diff_cleanup, 34744381dcbSjoris CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR 34816cfc147Sjoris }; 349af5bb824Sniallo #endif 35008f90673Sjfb 351af5bb824Sniallo #if !defined(RCSPROG) 35216cfc147Sjoris static struct diff_arg *dap = NULL; 35316cfc147Sjoris static int recurse; 35416cfc147Sjoris 355e4276007Sjfb static int 356e4276007Sjfb cvs_diff_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) 35708f90673Sjfb { 35816cfc147Sjoris int ch; 35908f90673Sjfb 3600450b43bSjoris dap = (struct diff_arg *)xmalloc(sizeof(*dap)); 36116cfc147Sjoris dap->date1 = dap->date2 = dap->rev1 = dap->rev2 = NULL; 362dc6a6879Sjfb strlcpy(diffargs, argv[0], sizeof(diffargs)); 363dc6a6879Sjfb 364e4276007Sjfb while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { 36508f90673Sjfb switch (ch) { 36608f90673Sjfb case 'c': 367f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 368f9b67873Sniallo diff_format = D_CONTEXT; 36908f90673Sjfb break; 37008f90673Sjfb case 'D': 37116cfc147Sjoris if (dap->date1 == NULL && dap->rev1 == NULL) { 37216cfc147Sjoris dap->date1 = optarg; 37316cfc147Sjoris } else if (dap->date2 == NULL && dap->rev2 == NULL) { 37416cfc147Sjoris dap->date2 = optarg; 37516cfc147Sjoris } else { 37608f90673Sjfb cvs_log(LP_ERR, 37708f90673Sjfb "no more than two revisions/dates can " 37808f90673Sjfb "be specified"); 37908f90673Sjfb } 38008f90673Sjfb break; 38108f90673Sjfb case 'l': 382f5638424Sjfb strlcat(diffargs, " -l", sizeof(diffargs)); 38308f90673Sjfb recurse = 0; 384e4276007Sjfb cvs_cmd_diff.file_flags &= ~CF_RECURSE; 38508f90673Sjfb break; 38608f90673Sjfb case 'i': 387f5638424Sjfb strlcat(diffargs, " -i", sizeof(diffargs)); 38808f90673Sjfb iflag = 1; 38908f90673Sjfb break; 390c710bc5aSjfb case 'N': 391c710bc5aSjfb strlcat(diffargs, " -N", sizeof(diffargs)); 392c710bc5aSjfb Nflag = 1; 393c710bc5aSjfb break; 394394180a4Sjfb case 'n': 395394180a4Sjfb strlcat(diffargs, " -n", sizeof(diffargs)); 396f9b67873Sniallo diff_format = D_RCSDIFF; 397394180a4Sjfb break; 3985e78344dSjfb case 'p': 3995e78344dSjfb strlcat(diffargs, " -p", sizeof(diffargs)); 4005e78344dSjfb pflag = 1; 4015e78344dSjfb break; 40208f90673Sjfb case 'r': 40316cfc147Sjoris if ((dap->rev1 == NULL) && (dap->date1 == NULL)) { 40416cfc147Sjoris dap->rev1 = optarg; 40516cfc147Sjoris } else if ((dap->rev2 == NULL) && 40616cfc147Sjoris (dap->date2 == NULL)) { 40716cfc147Sjoris dap->rev2 = optarg; 40816cfc147Sjoris } else { 40908f90673Sjfb cvs_log(LP_ERR, 41008f90673Sjfb "no more than two revisions/dates can " 41108f90673Sjfb "be specified"); 41231274bbfSjoris return (CVS_EX_USAGE); 41308f90673Sjfb } 41408f90673Sjfb break; 415f203c484Sjoris case 'R': 416e4276007Sjfb cvs_cmd_diff.file_flags |= CF_RECURSE; 417f203c484Sjoris break; 41808f90673Sjfb case 'u': 419f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 420f9b67873Sniallo diff_format = D_UNIFIED; 42108f90673Sjfb break; 42208f90673Sjfb default: 42331274bbfSjoris return (CVS_EX_USAGE); 42408f90673Sjfb } 42508f90673Sjfb } 42608f90673Sjfb 42716cfc147Sjoris *arg = optind; 428dc6a6879Sjfb return (0); 429dc6a6879Sjfb } 430dc6a6879Sjfb 43116cfc147Sjoris int 43216cfc147Sjoris cvs_diff_cleanup(void) 43316cfc147Sjoris { 434e4276007Sjfb if (dap != NULL) { 4350450b43bSjoris xfree(dap); 436e4276007Sjfb dap = NULL; 437e4276007Sjfb } 43816cfc147Sjoris return (0); 43916cfc147Sjoris } 440dc6a6879Sjfb 441dc6a6879Sjfb /* 442e4276007Sjfb * cvs_diff_pre_exec() 443dc6a6879Sjfb * 444dc6a6879Sjfb */ 445dc6a6879Sjfb int 446e4276007Sjfb cvs_diff_pre_exec(struct cvsroot *root) 447dc6a6879Sjfb { 448e4276007Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 44908f90673Sjfb /* send the flags */ 45048dc77e6Sxsa if ((Nflag == 1) && (cvs_sendarg(root, "-N", 0) < 0)) 45131274bbfSjoris return (CVS_EX_PROTO); 45248dc77e6Sxsa if ((pflag ==1) && (cvs_sendarg(root, "-p", 0) < 0)) 45331274bbfSjoris return (CVS_EX_PROTO); 4545e78344dSjfb 455f9b67873Sniallo if (diff_format == D_CONTEXT) { 456610801e8Sxsa if (cvs_sendarg(root, "-c", 0) < 0) 457610801e8Sxsa return (CVS_EX_PROTO); 458f9b67873Sniallo } else if (diff_format == D_UNIFIED) { 459610801e8Sxsa if (cvs_sendarg(root, "-u", 0) < 0) 460610801e8Sxsa return (CVS_EX_PROTO); 461610801e8Sxsa } 46208f90673Sjfb 463dc6a6879Sjfb if (dap->rev1 != NULL) { 464610801e8Sxsa if ((cvs_sendarg(root, "-r", 0) < 0) || 465610801e8Sxsa (cvs_sendarg(root, dap->rev1, 0) < 0)) 466610801e8Sxsa return (CVS_EX_PROTO); 4673917c9bfSderaadt } else if (dap->date1 != NULL) { 468610801e8Sxsa if ((cvs_sendarg(root, "-D", 0) < 0) || 469610801e8Sxsa (cvs_sendarg(root, dap->date1, 0) < 0)) 470610801e8Sxsa return (CVS_EX_PROTO); 47108f90673Sjfb } 472dc6a6879Sjfb if (dap->rev2 != NULL) { 473610801e8Sxsa if ((cvs_sendarg(root, "-r", 0) < 0) || 474610801e8Sxsa (cvs_sendarg(root, dap->rev2, 0) < 0)) 475610801e8Sxsa return (CVS_EX_PROTO); 4763917c9bfSderaadt } else if (dap->date2 != NULL) { 477610801e8Sxsa if ((cvs_sendarg(root, "-D", 0) < 0) || 478610801e8Sxsa (cvs_sendarg(root, dap->date2, 0) < 0)) 479610801e8Sxsa return (CVS_EX_PROTO); 48008f90673Sjfb } 481e4276007Sjfb } 48208f90673Sjfb 48308f90673Sjfb return (0); 48408f90673Sjfb } 48508f90673Sjfb 48608f90673Sjfb 48708f90673Sjfb /* 48808f90673Sjfb * cvs_diff_file() 48908f90673Sjfb * 49008f90673Sjfb * Diff a single file. 49108f90673Sjfb */ 492e4276007Sjfb static int 493e4276007Sjfb cvs_diff_remote(struct cvs_file *cfp, void *arg) 49408f90673Sjfb { 495e4276007Sjfb char *dir, *repo; 496e4276007Sjfb char fpath[MAXPATHLEN], dfpath[MAXPATHLEN]; 497dc6a6879Sjfb struct cvsroot *root; 498dc6a6879Sjfb 499dc6a6879Sjfb if (cfp->cf_type == DT_DIR) { 500895e6cf6Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 501bb029937Sjfb root = cfp->cf_parent->cf_root; 502b904ba2eSjoris cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 5033917c9bfSderaadt } else { 504bb029937Sjfb root = cfp->cf_root; 50516cfc147Sjoris #if 0 506dc6a6879Sjfb if ((cfp->cf_parent == NULL) || 507bb029937Sjfb (root != cfp->cf_parent->cf_root)) { 508dc6a6879Sjfb cvs_connect(root); 509e4276007Sjfb cvs_diff_pre_exec(root); 510dc6a6879Sjfb } 51116cfc147Sjoris #endif 512dc6a6879Sjfb 513dc6a6879Sjfb cvs_senddir(root, cfp); 514895e6cf6Sjfb } 515895e6cf6Sjfb 516dc6a6879Sjfb return (0); 517dc6a6879Sjfb } 51808f90673Sjfb 5192d5b8b1dSjfb if (cfp->cf_cvstat == CVS_FST_LOST) { 520b904ba2eSjoris cvs_log(LP_WARN, "cannot find file %s", cfp->cf_name); 5212d5b8b1dSjfb return (0); 5222d5b8b1dSjfb } 5232d5b8b1dSjfb 524c710bc5aSjfb diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath)); 525895e6cf6Sjfb 526dc6a6879Sjfb if (cfp->cf_parent != NULL) { 527c710bc5aSjfb dir = cvs_file_getpath(cfp->cf_parent, dfpath, sizeof(dfpath)); 528bb029937Sjfb root = cfp->cf_parent->cf_root; 529bb029937Sjfb repo = cfp->cf_parent->cf_repo; 5303917c9bfSderaadt } else { 531dc6a6879Sjfb dir = "."; 532895e6cf6Sjfb root = NULL; 533dc6a6879Sjfb repo = NULL; 53408f90673Sjfb } 53508f90673Sjfb 536dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 537e4276007Sjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 538dc6a6879Sjfb return (0); 53908f90673Sjfb } 54008f90673Sjfb 541e4276007Sjfb if (cvs_sendentry(root, cfp) < 0) 54231274bbfSjoris return (CVS_EX_PROTO); 54308f90673Sjfb 544dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UPTODATE) { 545e4276007Sjfb cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); 54608f90673Sjfb return (0); 54708f90673Sjfb } 54808f90673Sjfb 54908f90673Sjfb /* at this point, the file is modified */ 550e4276007Sjfb if ((cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name) < 0) || 551e4276007Sjfb (cvs_sendfile(root, diff_file) < 0)) 552e4276007Sjfb return (CVS_EX_PROTO); 553e4276007Sjfb 554e4276007Sjfb return (0); 555e4276007Sjfb } 556e4276007Sjfb 557e4276007Sjfb static int 558e4276007Sjfb cvs_diff_local(CVSFILE *cf, void *arg) 559e4276007Sjfb { 560e4276007Sjfb int len; 561e4276007Sjfb char *repo, buf[64]; 562e4276007Sjfb char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; 563e4276007Sjfb char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN]; 564e4276007Sjfb BUF *b1, *b2; 565e4276007Sjfb RCSNUM *r1, *r2; 566e4276007Sjfb RCSFILE *rf; 567e4276007Sjfb struct cvsroot *root; 568bf951d2dSniallo struct timeval tv[2], tv2[2]; 569bf951d2dSniallo 570bf951d2dSniallo memset(&tv, 0, sizeof(tv)); 571bf951d2dSniallo memset(&tv2, 0, sizeof(tv2)); 572e4276007Sjfb 573e4276007Sjfb rf = NULL; 574e4276007Sjfb root = CVS_DIR_ROOT(cf); 575e4276007Sjfb repo = CVS_DIR_REPO(cf); 576e4276007Sjfb diff_file = cvs_file_getpath(cf, fpath, sizeof(fpath)); 577e4276007Sjfb 578e4276007Sjfb if (cf->cf_type == DT_DIR) { 579b87c59bdSxsa if (verbosity > 1) 580246675edSxsa cvs_log(LP_NOTICE, "Diffing %s", fpath); 581e4276007Sjfb return (0); 582e4276007Sjfb } 583e4276007Sjfb 584e4276007Sjfb if (cf->cf_cvstat == CVS_FST_LOST) { 585e4276007Sjfb cvs_log(LP_WARN, "cannot find file %s", cf->cf_name); 586e4276007Sjfb return (0); 587e4276007Sjfb } 588e4276007Sjfb 589e4276007Sjfb if (cf->cf_cvstat == CVS_FST_UNKNOWN) { 590e4276007Sjfb cvs_log(LP_WARN, "I know nothing about %s", diff_file); 591e4276007Sjfb return (0); 5925c0cd766Sniallo } else if (cf->cf_cvstat == CVS_FST_UPTODATE) 593e4276007Sjfb return (0); 594e4276007Sjfb 595e4276007Sjfb /* at this point, the file is modified */ 596e4276007Sjfb len = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 597dc6a6879Sjfb root->cr_dir, repo, diff_file, RCS_FILE_EXT); 598e4276007Sjfb if (len == -1 || len >= (int)sizeof(rcspath)) { 59927b85f85Sxsa errno = ENAMETOOLONG; 60027b85f85Sxsa cvs_log(LP_ERRNO, "%s", rcspath); 60101b3d77aSjoris return (CVS_EX_DATA); 60227b85f85Sxsa } 60308f90673Sjfb 6041b6534b8Sjfb rf = rcs_open(rcspath, RCS_READ); 605dc6a6879Sjfb if (rf == NULL) { 60631274bbfSjoris return (CVS_EX_DATA); 607dc6a6879Sjfb } 60808f90673Sjfb 609dc6a6879Sjfb cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, 61008f90673Sjfb RCS_DIFF_DIV, rcspath); 61108f90673Sjfb 612dc6a6879Sjfb if (dap->rev1 == NULL) 613e4276007Sjfb r1 = cf->cf_lrev; 61408f90673Sjfb else { 61525b74b48Sjfb if ((r1 = rcsnum_parse(dap->rev1)) == NULL) { 61664672f74Sjoris rcs_close(rf); 61731274bbfSjoris return (CVS_EX_DATA); 6187f535ec4Sjfb } 61908f90673Sjfb } 62008f90673Sjfb 621dc6a6879Sjfb cvs_printf("retrieving revision %s\n", 62208f90673Sjfb rcsnum_tostr(r1, buf, sizeof(buf))); 62308f90673Sjfb b1 = rcs_getrev(rf, r1); 62408f90673Sjfb 62595ae1173Sjoris if (b1 == NULL) { 626289b97f4Sxsa cvs_log(LP_ERR, "failed to retrieve revision %s\n", 62795ae1173Sjoris rcsnum_tostr(r1, buf, sizeof(buf))); 62895ae1173Sjoris if (r1 != cf->cf_lrev) 62995ae1173Sjoris rcsnum_free(r1); 63064672f74Sjoris rcs_close(rf); 63195ae1173Sjoris return (CVS_EX_DATA); 63295ae1173Sjoris } 633bf951d2dSniallo tv[0].tv_sec = (long)rcs_rev_getdate(rf, r1); 634bf951d2dSniallo tv[1].tv_sec = tv[0].tv_sec; 63595ae1173Sjoris 636e4276007Sjfb if (r1 != cf->cf_lrev) 6377f535ec4Sjfb rcsnum_free(r1); 6387f535ec4Sjfb 639dc6a6879Sjfb if (dap->rev2 != NULL) { 640dc6a6879Sjfb cvs_printf("retrieving revision %s\n", dap->rev2); 64125b74b48Sjfb if ((r2 = rcsnum_parse(dap->rev2)) == NULL) { 64264672f74Sjoris rcs_close(rf); 64331274bbfSjoris return (CVS_EX_DATA); 6447f535ec4Sjfb } 64508f90673Sjfb b2 = rcs_getrev(rf, r2); 646f3e6c8ebSniallo tv2[0].tv_sec = (long)rcs_rev_getdate(rf, r2); 647f3e6c8ebSniallo tv2[1].tv_sec = tv2[0].tv_sec; 6487f535ec4Sjfb rcsnum_free(r2); 6493917c9bfSderaadt } else { 650f3e6c8ebSniallo struct stat st; 651f3e6c8ebSniallo if (stat(diff_file, &st) < 0) { 652f3e6c8ebSniallo cvs_log(LP_ERR, "failed to retrieve revision %s\n", 653f3e6c8ebSniallo dap->rev2); 654f3e6c8ebSniallo cvs_buf_free(b1); 655f3e6c8ebSniallo return (CVS_EX_DATA); 656f3e6c8ebSniallo } 657dc6a6879Sjfb b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); 658f3e6c8ebSniallo tv2[0].tv_sec = st.st_mtime; 659f3e6c8ebSniallo tv2[1].tv_sec = st.st_mtime; 66008f90673Sjfb } 66108f90673Sjfb 662dc6a6879Sjfb rcs_close(rf); 663dc6a6879Sjfb 66495ae1173Sjoris if (b2 == NULL) { 665289b97f4Sxsa cvs_log(LP_ERR, "failed to retrieve revision %s\n", 66695ae1173Sjoris dap->rev2); 66795ae1173Sjoris cvs_buf_free(b1); 66895ae1173Sjoris return (CVS_EX_DATA); 66995ae1173Sjoris } 67095ae1173Sjoris 6715ac8b1e7Sjoris cvs_printf("%s", diffargs); 6725ac8b1e7Sjoris cvs_printf(" -r%s", buf); 673dc6a6879Sjfb if (dap->rev2 != NULL) 6745ac8b1e7Sjoris cvs_printf(" -r%s", dap->rev2); 6755ac8b1e7Sjoris cvs_printf(" %s\n", diff_file); 6761dee9299Sxsa strlcpy(path_tmp1, cvs_tmpdir, sizeof(path_tmp1)); 6771dee9299Sxsa strlcat(path_tmp1, "/diff1.XXXXXXXXXX", sizeof(path_tmp1)); 678fbe562adSxsa cvs_buf_write_stmp(b1, path_tmp1, 0600); 6797f535ec4Sjfb cvs_buf_free(b1); 680bf951d2dSniallo if (utimes(path_tmp1, (const struct timeval *)&tv) < 0) 681bf951d2dSniallo cvs_log(LP_ERRNO, "error setting utimes"); 6827f535ec4Sjfb 6831dee9299Sxsa strlcpy(path_tmp2, cvs_tmpdir, sizeof(path_tmp2)); 6841dee9299Sxsa strlcat(path_tmp2, "/diff2.XXXXXXXXXX", sizeof(path_tmp2)); 685*8dbc5e14Sxsa cvs_buf_write_stmp(b2, path_tmp2, 0600); 6867f535ec4Sjfb cvs_buf_free(b2); 687bf951d2dSniallo if (utimes(path_tmp2, (const struct timeval *)&tv2) < 0) 688bf951d2dSniallo cvs_log(LP_ERRNO, "error setting utimes"); 6897f535ec4Sjfb 690f9b67873Sniallo cvs_diffreg(path_tmp1, path_tmp2, NULL); 691946f6157Sdjm (void)unlink(path_tmp1); 692946f6157Sdjm (void)unlink(path_tmp2); 69308f90673Sjfb 69408f90673Sjfb return (0); 69508f90673Sjfb } 696af5bb824Sniallo #endif 69708f90673Sjfb 69808f90673Sjfb 69908f90673Sjfb int 700f9b67873Sniallo cvs_diffreg(const char *file1, const char *file2, BUF *out) 70108f90673Sjfb { 70208f90673Sjfb FILE *f1, *f2; 70308f90673Sjfb int i, rval; 7047f535ec4Sjfb void *tmp; 70508f90673Sjfb 70608f90673Sjfb f1 = f2 = NULL; 70708f90673Sjfb rval = D_SAME; 70808f90673Sjfb anychange = 0; 70908f90673Sjfb lastline = 0; 71008f90673Sjfb lastmatchline = 0; 71108f90673Sjfb context_vec_ptr = context_vec_start - 1; 71208f90673Sjfb chrtran = (iflag ? cup2low : clow2low); 713f9b67873Sniallo if (out != NULL) 714f9b67873Sniallo diffbuf = out; 71508f90673Sjfb 71608f90673Sjfb f1 = fopen(file1, "r"); 71708f90673Sjfb if (f1 == NULL) { 71808f90673Sjfb cvs_log(LP_ERRNO, "%s", file1); 71908f90673Sjfb goto closem; 72008f90673Sjfb } 72108f90673Sjfb 72208f90673Sjfb f2 = fopen(file2, "r"); 72308f90673Sjfb if (f2 == NULL) { 72408f90673Sjfb cvs_log(LP_ERRNO, "%s", file2); 72508f90673Sjfb goto closem; 72608f90673Sjfb } 72708f90673Sjfb 728bf951d2dSniallo if (stat(file1, &stb1) < 0) { 729bf951d2dSniallo cvs_log(LP_ERRNO, "%s", file1); 730bf951d2dSniallo goto closem; 731bf951d2dSniallo } 732bf951d2dSniallo if (stat(file2, &stb2) < 0) { 733bf951d2dSniallo cvs_log(LP_ERRNO, "%s", file2); 734bf951d2dSniallo goto closem; 735bf951d2dSniallo } 73608f90673Sjfb switch (files_differ(f1, f2)) { 73708f90673Sjfb case 0: 73808f90673Sjfb goto closem; 73908f90673Sjfb case 1: 74008f90673Sjfb break; 74108f90673Sjfb default: 74208f90673Sjfb /* error */ 74308f90673Sjfb goto closem; 74408f90673Sjfb } 74508f90673Sjfb 74608f90673Sjfb if (!asciifile(f1) || !asciifile(f2)) { 74708f90673Sjfb rval = D_BINARY; 74808f90673Sjfb goto closem; 74908f90673Sjfb } 7507f535ec4Sjfb if ((prepare(0, f1, stb1.st_size) < 0) || 7517f535ec4Sjfb (prepare(1, f2, stb2.st_size) < 0)) { 7527f535ec4Sjfb goto closem; 7537f535ec4Sjfb } 75408f90673Sjfb prune(); 75508f90673Sjfb sort(sfile[0], slen[0]); 75608f90673Sjfb sort(sfile[1], slen[1]); 75708f90673Sjfb 75808f90673Sjfb member = (int *)file[1]; 75908f90673Sjfb equiv(sfile[0], slen[0], sfile[1], slen[1], member); 7600450b43bSjoris tmp = xrealloc(member, (slen[1] + 2) * sizeof(int)); 7617f535ec4Sjfb member = (int *)tmp; 76208f90673Sjfb 76308f90673Sjfb class = (int *)file[0]; 76408f90673Sjfb unsort(sfile[0], slen[0], class); 7650450b43bSjoris tmp = xrealloc(class, (slen[0] + 2) * sizeof(int)); 7667f535ec4Sjfb class = (int *)tmp; 76708f90673Sjfb 7680450b43bSjoris klist = xmalloc((slen[0] + 2) * sizeof(int)); 76908f90673Sjfb clen = 0; 77008f90673Sjfb clistlen = 100; 7710450b43bSjoris clist = xmalloc(clistlen * sizeof(cand)); 772ece76a70Sjoris 773ece76a70Sjoris if ((i = stone(class, slen[0], member, klist)) < 0) 774ece76a70Sjoris goto closem; 775ece76a70Sjoris 7760450b43bSjoris xfree(member); 7770450b43bSjoris xfree(class); 77808f90673Sjfb 7790450b43bSjoris tmp = xrealloc(J, (diff_len[0] + 2) * sizeof(int)); 78018501190Sniallo J = (int *)tmp; 78108f90673Sjfb unravel(klist[i]); 7820450b43bSjoris xfree(clist); 7830450b43bSjoris xfree(klist); 78408f90673Sjfb 7850450b43bSjoris tmp = xrealloc(ixold, (diff_len[0] + 2) * sizeof(long)); 78618501190Sniallo ixold = (long *)tmp; 7870450b43bSjoris 7880450b43bSjoris tmp = xrealloc(ixnew, (diff_len[1] + 2) * sizeof(long)); 78918501190Sniallo ixnew = (long *)tmp; 79008f90673Sjfb check(f1, f2); 79108f90673Sjfb output(file1, f1, file2, f2); 79208f90673Sjfb 79308f90673Sjfb closem: 79437af5b8bSxsa if (anychange == 1) { 79508f90673Sjfb if (rval == D_SAME) 79608f90673Sjfb rval = D_DIFFER; 79708f90673Sjfb } 79808f90673Sjfb if (f1 != NULL) 79908f90673Sjfb fclose(f1); 80008f90673Sjfb if (f2 != NULL) 80108f90673Sjfb fclose(f2); 8027f535ec4Sjfb 80308f90673Sjfb return (rval); 80408f90673Sjfb } 80508f90673Sjfb 80608f90673Sjfb /* 80708f90673Sjfb * Check to see if the given files differ. 80808f90673Sjfb * Returns 0 if they are the same, 1 if different, and -1 on error. 80908f90673Sjfb * XXX - could use code from cmp(1) [faster] 81008f90673Sjfb */ 81108f90673Sjfb static int 81208f90673Sjfb files_differ(FILE *f1, FILE *f2) 81308f90673Sjfb { 81408f90673Sjfb char buf1[BUFSIZ], buf2[BUFSIZ]; 81508f90673Sjfb size_t i, j; 81608f90673Sjfb 81708f90673Sjfb if (stb1.st_size != stb2.st_size) 81808f90673Sjfb return (1); 81908f90673Sjfb for (;;) { 820f1901a5aSxsa i = fread(buf1, (size_t)1, sizeof(buf1), f1); 821f1901a5aSxsa j = fread(buf2, (size_t)1, sizeof(buf2), f2); 82208f90673Sjfb if (i != j) 82308f90673Sjfb return (1); 82437af5b8bSxsa if ((i == 0) && (j == 0)) { 82508f90673Sjfb if (ferror(f1) || ferror(f2)) 82608f90673Sjfb return (1); 82708f90673Sjfb return (0); 82808f90673Sjfb } 82908f90673Sjfb if (memcmp(buf1, buf2, i) != 0) 83008f90673Sjfb return (1); 83108f90673Sjfb } 83208f90673Sjfb } 83308f90673Sjfb 8347f535ec4Sjfb static int 83508f90673Sjfb prepare(int i, FILE *fd, off_t filesize) 83608f90673Sjfb { 8377f535ec4Sjfb void *tmp; 83808f90673Sjfb struct line *p; 83908f90673Sjfb int j, h; 84008f90673Sjfb size_t sz; 84108f90673Sjfb 84208f90673Sjfb rewind(fd); 84308f90673Sjfb 844c48da046Sxsa sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 84508f90673Sjfb if (sz < 100) 84608f90673Sjfb sz = 100; 84708f90673Sjfb 8480450b43bSjoris p = (struct line *)xmalloc((sz + 3) * sizeof(struct line)); 84908f90673Sjfb for (j = 0; (h = readhash(fd));) { 85008f90673Sjfb if (j == (int)sz) { 85108f90673Sjfb sz = sz * 3 / 2; 8520450b43bSjoris tmp = xrealloc(p, (sz + 3) * sizeof(struct line)); 8537f535ec4Sjfb p = (struct line *)tmp; 85408f90673Sjfb } 85508f90673Sjfb p[++j].value = h; 85608f90673Sjfb } 857e4276007Sjfb diff_len[i] = j; 85808f90673Sjfb file[i] = p; 8597f535ec4Sjfb 8607f535ec4Sjfb return (0); 86108f90673Sjfb } 86208f90673Sjfb 86308f90673Sjfb static void 86408f90673Sjfb prune(void) 86508f90673Sjfb { 86608f90673Sjfb int i, j; 86708f90673Sjfb 868e4276007Sjfb for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 86908f90673Sjfb file[0][pref + 1].value == file[1][pref + 1].value; 87008f90673Sjfb pref++) 87108f90673Sjfb ; 872e4276007Sjfb for (suff = 0; 873e4276007Sjfb (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 874e4276007Sjfb (file[0][diff_len[0] - suff].value == 875e4276007Sjfb file[1][diff_len[1] - suff].value); 87608f90673Sjfb suff++) 87708f90673Sjfb ; 87808f90673Sjfb for (j = 0; j < 2; j++) { 87908f90673Sjfb sfile[j] = file[j] + pref; 880e4276007Sjfb slen[j] = diff_len[j] - pref - suff; 88108f90673Sjfb for (i = 0; i <= slen[j]; i++) 88208f90673Sjfb sfile[j][i].serial = i; 88308f90673Sjfb } 88408f90673Sjfb } 88508f90673Sjfb 88608f90673Sjfb static void 88708f90673Sjfb equiv(struct line *a, int n, struct line *b, int m, int *c) 88808f90673Sjfb { 88908f90673Sjfb int i, j; 89008f90673Sjfb 89108f90673Sjfb i = j = 1; 89208f90673Sjfb while (i <= n && j <= m) { 89308f90673Sjfb if (a[i].value < b[j].value) 89408f90673Sjfb a[i++].value = 0; 89508f90673Sjfb else if (a[i].value == b[j].value) 89608f90673Sjfb a[i++].value = j; 89708f90673Sjfb else 89808f90673Sjfb j++; 89908f90673Sjfb } 90008f90673Sjfb while (i <= n) 90108f90673Sjfb a[i++].value = 0; 90208f90673Sjfb b[m + 1].value = 0; 90308f90673Sjfb j = 0; 90408f90673Sjfb while (++j <= m) { 90508f90673Sjfb c[j] = -b[j].serial; 90608f90673Sjfb while (b[j + 1].value == b[j].value) { 90708f90673Sjfb j++; 90808f90673Sjfb c[j] = b[j].serial; 90908f90673Sjfb } 91008f90673Sjfb } 91108f90673Sjfb c[j] = -1; 91208f90673Sjfb } 91308f90673Sjfb 91408f90673Sjfb /* Code taken from ping.c */ 91508f90673Sjfb static int 91608f90673Sjfb isqrt(int n) 91708f90673Sjfb { 91808f90673Sjfb int y, x = 1; 91908f90673Sjfb 92008f90673Sjfb if (n == 0) 92108f90673Sjfb return (0); 92208f90673Sjfb 92308f90673Sjfb do { /* newton was a stinker */ 92408f90673Sjfb y = x; 92508f90673Sjfb x = n / x; 92608f90673Sjfb x += y; 92708f90673Sjfb x /= 2; 92808f90673Sjfb } while ((x - y) > 1 || (x - y) < -1); 92908f90673Sjfb 93008f90673Sjfb return (x); 93108f90673Sjfb } 93208f90673Sjfb 93308f90673Sjfb static int 93408f90673Sjfb stone(int *a, int n, int *b, int *c) 93508f90673Sjfb { 936ece76a70Sjoris int ret; 93708f90673Sjfb int i, k, y, j, l; 93808f90673Sjfb int oldc, tc, oldl; 93908f90673Sjfb u_int numtries; 94008f90673Sjfb 941cc649edbSjfb /* XXX move the isqrt() out of the macro to avoid multiple calls */ 942cc649edbSjfb const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 94308f90673Sjfb 94408f90673Sjfb k = 0; 945ece76a70Sjoris if ((ret = newcand(0, 0, 0)) < 0) 946ece76a70Sjoris return (-1); 947ece76a70Sjoris c[0] = ret; 94808f90673Sjfb for (i = 1; i <= n; i++) { 94908f90673Sjfb j = a[i]; 95008f90673Sjfb if (j == 0) 95108f90673Sjfb continue; 95208f90673Sjfb y = -b[j]; 95308f90673Sjfb oldl = 0; 95408f90673Sjfb oldc = c[0]; 95508f90673Sjfb numtries = 0; 95608f90673Sjfb do { 95708f90673Sjfb if (y <= clist[oldc].y) 95808f90673Sjfb continue; 95908f90673Sjfb l = search(c, k, y); 96008f90673Sjfb if (l != oldl + 1) 96108f90673Sjfb oldc = c[l - 1]; 96208f90673Sjfb if (l <= k) { 96308f90673Sjfb if (clist[c[l]].y <= y) 96408f90673Sjfb continue; 96508f90673Sjfb tc = c[l]; 966ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 967ece76a70Sjoris return (-1); 968ece76a70Sjoris c[l] = ret; 96908f90673Sjfb oldc = tc; 97008f90673Sjfb oldl = l; 97108f90673Sjfb numtries++; 97208f90673Sjfb } else { 973ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 974ece76a70Sjoris return (-1); 975ece76a70Sjoris c[l] = ret; 97608f90673Sjfb k++; 97708f90673Sjfb break; 97808f90673Sjfb } 97908f90673Sjfb } while ((y = b[++j]) > 0 && numtries < bound); 98008f90673Sjfb } 98108f90673Sjfb return (k); 98208f90673Sjfb } 98308f90673Sjfb 98408f90673Sjfb static int 98508f90673Sjfb newcand(int x, int y, int pred) 98608f90673Sjfb { 98718501190Sniallo struct cand *q, *tmp; 98818501190Sniallo int newclistlen; 98908f90673Sjfb 99008f90673Sjfb if (clen == clistlen) { 99118501190Sniallo newclistlen = clistlen * 11 / 10; 9920450b43bSjoris tmp = xrealloc(clist, newclistlen * sizeof(cand)); 99318501190Sniallo clist = tmp; 99418501190Sniallo clistlen = newclistlen; 99508f90673Sjfb } 99608f90673Sjfb q = clist + clen; 99708f90673Sjfb q->x = x; 99808f90673Sjfb q->y = y; 99908f90673Sjfb q->pred = pred; 100008f90673Sjfb return (clen++); 100108f90673Sjfb } 100208f90673Sjfb 100308f90673Sjfb static int 100408f90673Sjfb search(int *c, int k, int y) 100508f90673Sjfb { 100608f90673Sjfb int i, j, l, t; 100708f90673Sjfb 100808f90673Sjfb if (clist[c[k]].y < y) /* quick look for typical case */ 100908f90673Sjfb return (k + 1); 101008f90673Sjfb i = 0; 101108f90673Sjfb j = k + 1; 101208f90673Sjfb while (1) { 101308f90673Sjfb l = i + j; 101408f90673Sjfb if ((l >>= 1) <= i) 101508f90673Sjfb break; 101608f90673Sjfb t = clist[c[l]].y; 101708f90673Sjfb if (t > y) 101808f90673Sjfb j = l; 101908f90673Sjfb else if (t < y) 102008f90673Sjfb i = l; 102108f90673Sjfb else 102208f90673Sjfb return (l); 102308f90673Sjfb } 102408f90673Sjfb return (l + 1); 102508f90673Sjfb } 102608f90673Sjfb 102708f90673Sjfb static void 102808f90673Sjfb unravel(int p) 102908f90673Sjfb { 103008f90673Sjfb struct cand *q; 103108f90673Sjfb int i; 103208f90673Sjfb 1033e4276007Sjfb for (i = 0; i <= diff_len[0]; i++) 103408f90673Sjfb J[i] = i <= pref ? i : 1035e4276007Sjfb i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 103608f90673Sjfb for (q = clist + p; q->y != 0; q = clist + q->pred) 103708f90673Sjfb J[q->x + pref] = q->y + pref; 103808f90673Sjfb } 103908f90673Sjfb 104008f90673Sjfb /* 104108f90673Sjfb * Check does double duty: 104208f90673Sjfb * 1. ferret out any fortuitous correspondences due 104308f90673Sjfb * to confounding by hashing (which result in "jackpot") 104408f90673Sjfb * 2. collect random access indexes to the two files 104508f90673Sjfb */ 104608f90673Sjfb static void 104708f90673Sjfb check(FILE *f1, FILE *f2) 104808f90673Sjfb { 104908f90673Sjfb int i, j, jackpot, c, d; 105008f90673Sjfb long ctold, ctnew; 105108f90673Sjfb 105208f90673Sjfb rewind(f1); 105308f90673Sjfb rewind(f2); 105408f90673Sjfb j = 1; 105508f90673Sjfb ixold[0] = ixnew[0] = 0; 105608f90673Sjfb jackpot = 0; 105708f90673Sjfb ctold = ctnew = 0; 1058e4276007Sjfb for (i = 1; i <= diff_len[0]; i++) { 105908f90673Sjfb if (J[i] == 0) { 106008f90673Sjfb ixold[i] = ctold += skipline(f1); 106108f90673Sjfb continue; 106208f90673Sjfb } 106308f90673Sjfb while (j < J[i]) { 106408f90673Sjfb ixnew[j] = ctnew += skipline(f2); 106508f90673Sjfb j++; 106608f90673Sjfb } 106748dc77e6Sxsa if ((bflag == 1)|| (wflag == 1) || (iflag == 1)) { 106808f90673Sjfb for (;;) { 106908f90673Sjfb c = getc(f1); 107008f90673Sjfb d = getc(f2); 107108f90673Sjfb /* 107208f90673Sjfb * GNU diff ignores a missing newline 107308f90673Sjfb * in one file if bflag || wflag. 107408f90673Sjfb */ 107548dc77e6Sxsa if (((bflag == 1) || (wflag == 1)) && 107608f90673Sjfb ((c == EOF && d == '\n') || 107708f90673Sjfb (c == '\n' && d == EOF))) { 107808f90673Sjfb break; 107908f90673Sjfb } 108008f90673Sjfb ctold++; 108108f90673Sjfb ctnew++; 108248dc77e6Sxsa if ((bflag == 1) && isspace(c) && isspace(d)) { 108308f90673Sjfb do { 108408f90673Sjfb if (c == '\n') 108508f90673Sjfb break; 108608f90673Sjfb ctold++; 108708f90673Sjfb } while (isspace(c = getc(f1))); 108808f90673Sjfb do { 108908f90673Sjfb if (d == '\n') 109008f90673Sjfb break; 109108f90673Sjfb ctnew++; 109208f90673Sjfb } while (isspace(d = getc(f2))); 109348dc77e6Sxsa } else if (wflag == 1) { 109408f90673Sjfb while (isspace(c) && c != '\n') { 109508f90673Sjfb c = getc(f1); 109608f90673Sjfb ctold++; 109708f90673Sjfb } 109808f90673Sjfb while (isspace(d) && d != '\n') { 109908f90673Sjfb d = getc(f2); 110008f90673Sjfb ctnew++; 110108f90673Sjfb } 110208f90673Sjfb } 110308f90673Sjfb if (chrtran[c] != chrtran[d]) { 110408f90673Sjfb jackpot++; 110508f90673Sjfb J[i] = 0; 110637af5b8bSxsa if ((c != '\n') && (c != EOF)) 110708f90673Sjfb ctold += skipline(f1); 110837af5b8bSxsa if ((d != '\n') && (c != EOF)) 110908f90673Sjfb ctnew += skipline(f2); 111008f90673Sjfb break; 111108f90673Sjfb } 111237af5b8bSxsa if ((c == '\n') || (c == EOF)) 111308f90673Sjfb break; 111408f90673Sjfb } 111508f90673Sjfb } else { 111608f90673Sjfb for (;;) { 111708f90673Sjfb ctold++; 111808f90673Sjfb ctnew++; 111908f90673Sjfb if ((c = getc(f1)) != (d = getc(f2))) { 112008f90673Sjfb /* jackpot++; */ 112108f90673Sjfb J[i] = 0; 112237af5b8bSxsa if ((c != '\n') && (c != EOF)) 112308f90673Sjfb ctold += skipline(f1); 112437af5b8bSxsa if ((d != '\n') && (c != EOF)) 112508f90673Sjfb ctnew += skipline(f2); 112608f90673Sjfb break; 112708f90673Sjfb } 112837af5b8bSxsa if ((c == '\n') || (c == EOF)) 112908f90673Sjfb break; 113008f90673Sjfb } 113108f90673Sjfb } 113208f90673Sjfb ixold[i] = ctold; 113308f90673Sjfb ixnew[j] = ctnew; 113408f90673Sjfb j++; 113508f90673Sjfb } 1136e4276007Sjfb for (; j <= diff_len[1]; j++) 113708f90673Sjfb ixnew[j] = ctnew += skipline(f2); 113808f90673Sjfb /* 113937af5b8bSxsa * if (jackpot != 0) 11405ac8b1e7Sjoris * cvs_printf("jackpot\n"); 114108f90673Sjfb */ 114208f90673Sjfb } 114308f90673Sjfb 114408f90673Sjfb /* shellsort CACM #201 */ 114508f90673Sjfb static void 114608f90673Sjfb sort(struct line *a, int n) 114708f90673Sjfb { 114808f90673Sjfb struct line *ai, *aim, w; 114908f90673Sjfb int j, m = 0, k; 115008f90673Sjfb 115108f90673Sjfb if (n == 0) 115208f90673Sjfb return; 115308f90673Sjfb for (j = 1; j <= n; j *= 2) 115408f90673Sjfb m = 2 * j - 1; 115508f90673Sjfb for (m /= 2; m != 0; m /= 2) { 115608f90673Sjfb k = n - m; 115708f90673Sjfb for (j = 1; j <= k; j++) { 115808f90673Sjfb for (ai = &a[j]; ai > a; ai -= m) { 115908f90673Sjfb aim = &ai[m]; 116008f90673Sjfb if (aim < ai) 116108f90673Sjfb break; /* wraparound */ 116208f90673Sjfb if (aim->value > ai[0].value || 116308f90673Sjfb (aim->value == ai[0].value && 116408f90673Sjfb aim->serial > ai[0].serial)) 116508f90673Sjfb break; 116608f90673Sjfb w.value = ai[0].value; 116708f90673Sjfb ai[0].value = aim->value; 116808f90673Sjfb aim->value = w.value; 116908f90673Sjfb w.serial = ai[0].serial; 117008f90673Sjfb ai[0].serial = aim->serial; 117108f90673Sjfb aim->serial = w.serial; 117208f90673Sjfb } 117308f90673Sjfb } 117408f90673Sjfb } 117508f90673Sjfb } 117608f90673Sjfb 117708f90673Sjfb static void 117808f90673Sjfb unsort(struct line *f, int l, int *b) 117908f90673Sjfb { 118008f90673Sjfb int *a, i; 118108f90673Sjfb 11820450b43bSjoris a = (int *)xmalloc((l + 1) * sizeof(int)); 118308f90673Sjfb for (i = 1; i <= l; i++) 118408f90673Sjfb a[f[i].serial] = f[i].value; 118508f90673Sjfb for (i = 1; i <= l; i++) 118608f90673Sjfb b[i] = a[i]; 11870450b43bSjoris xfree(a); 118808f90673Sjfb } 118908f90673Sjfb 119008f90673Sjfb static int 119108f90673Sjfb skipline(FILE *f) 119208f90673Sjfb { 119308f90673Sjfb int i, c; 119408f90673Sjfb 119508f90673Sjfb for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 119608f90673Sjfb continue; 119708f90673Sjfb return (i); 119808f90673Sjfb } 119908f90673Sjfb 120008f90673Sjfb static void 120108f90673Sjfb output(const char *file1, FILE *f1, const char *file2, FILE *f2) 120208f90673Sjfb { 120308f90673Sjfb int m, i0, i1, j0, j1; 120408f90673Sjfb 120508f90673Sjfb rewind(f1); 120608f90673Sjfb rewind(f2); 1207e4276007Sjfb m = diff_len[0]; 120808f90673Sjfb J[0] = 0; 1209e4276007Sjfb J[m + 1] = diff_len[1] + 1; 121008f90673Sjfb for (i0 = 1; i0 <= m; i0 = i1 + 1) { 121108f90673Sjfb while (i0 <= m && J[i0] == J[i0 - 1] + 1) 121208f90673Sjfb i0++; 121308f90673Sjfb j0 = J[i0 - 1] + 1; 121408f90673Sjfb i1 = i0 - 1; 121508f90673Sjfb while (i1 < m && J[i1 + 1] == 0) 121608f90673Sjfb i1++; 121708f90673Sjfb j1 = J[i1 + 1] - 1; 121808f90673Sjfb J[i1] = j1; 121908f90673Sjfb change(file1, f1, file2, f2, i0, i1, j0, j1); 122008f90673Sjfb } 122108f90673Sjfb if (m == 0) 1222e4276007Sjfb change(file1, f1, file2, f2, 1, 0, 1, diff_len[1]); 1223f9b67873Sniallo if (diff_format == D_IFDEF) { 122408f90673Sjfb for (;;) { 122508f90673Sjfb #define c i0 122608f90673Sjfb if ((c = getc(f1)) == EOF) 122708f90673Sjfb return; 1228f9b67873Sniallo diff_output("%c", c); 122908f90673Sjfb } 123008f90673Sjfb #undef c 123108f90673Sjfb } 123208f90673Sjfb if (anychange != 0) { 1233f9b67873Sniallo if (diff_format == D_CONTEXT) 123408f90673Sjfb dump_context_vec(f1, f2); 1235f9b67873Sniallo else if (diff_format == D_UNIFIED) 123608f90673Sjfb dump_unified_vec(f1, f2); 123708f90673Sjfb } 123808f90673Sjfb } 123908f90673Sjfb 124008f90673Sjfb static __inline void 124108f90673Sjfb range(int a, int b, char *separator) 124208f90673Sjfb { 1243f9b67873Sniallo diff_output("%d", a > b ? b : a); 124408f90673Sjfb if (a < b) 1245f9b67873Sniallo diff_output("%s%d", separator, b); 124608f90673Sjfb } 124708f90673Sjfb 124808f90673Sjfb static __inline void 124908f90673Sjfb uni_range(int a, int b) 125008f90673Sjfb { 125108f90673Sjfb if (a < b) 1252f9b67873Sniallo diff_output("%d,%d", a, b - a + 1); 125308f90673Sjfb else if (a == b) 1254f9b67873Sniallo diff_output("%d", b); 125508f90673Sjfb else 1256f9b67873Sniallo diff_output("%d,0", b); 125708f90673Sjfb } 125808f90673Sjfb 125908f90673Sjfb static char * 12602a0de57dSjfb preadline(int fd, size_t rlen, off_t off) 126108f90673Sjfb { 126208f90673Sjfb char *line; 126308f90673Sjfb ssize_t nr; 126408f90673Sjfb 12650450b43bSjoris line = xmalloc(rlen + 1); 12662a0de57dSjfb if ((nr = pread(fd, line, rlen, off)) < 0) { 126708f90673Sjfb cvs_log(LP_ERRNO, "preadline failed"); 126808f90673Sjfb return (NULL); 126908f90673Sjfb } 127008f90673Sjfb line[nr] = '\0'; 127108f90673Sjfb return (line); 127208f90673Sjfb } 127308f90673Sjfb 127408f90673Sjfb static int 127508f90673Sjfb ignoreline(char *line) 127608f90673Sjfb { 127708f90673Sjfb int ret; 127808f90673Sjfb 1279f1901a5aSxsa ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); 12800450b43bSjoris xfree(line); 128108f90673Sjfb return (ret == 0); /* if it matched, it should be ignored. */ 128208f90673Sjfb } 128308f90673Sjfb 128408f90673Sjfb /* 128508f90673Sjfb * Indicate that there is a difference between lines a and b of the from file 128608f90673Sjfb * to get to lines c to d of the to file. If a is greater then b then there 128708f90673Sjfb * are no lines in the from file involved and this means that there were 128808f90673Sjfb * lines appended (beginning at b). If c is greater than d then there are 128908f90673Sjfb * lines missing from the to file. 129008f90673Sjfb */ 129108f90673Sjfb static void 129208f90673Sjfb change(const char *file1, FILE *f1, const char *file2, FILE *f2, 129308f90673Sjfb int a, int b, int c, int d) 129408f90673Sjfb { 129508f90673Sjfb static size_t max_context = 64; 129608f90673Sjfb int i; 129708f90673Sjfb 1298f9b67873Sniallo if (diff_format != D_IFDEF && a > b && c > d) 129908f90673Sjfb return; 130008f90673Sjfb if (ignore_pats != NULL) { 130108f90673Sjfb char *line; 130208f90673Sjfb /* 130308f90673Sjfb * All lines in the change, insert, or delete must 130408f90673Sjfb * match an ignore pattern for the change to be 130508f90673Sjfb * ignored. 130608f90673Sjfb */ 130708f90673Sjfb if (a <= b) { /* Changes and deletes. */ 130808f90673Sjfb for (i = a; i <= b; i++) { 130908f90673Sjfb line = preadline(fileno(f1), 131008f90673Sjfb ixold[i] - ixold[i - 1], ixold[i - 1]); 131108f90673Sjfb if (!ignoreline(line)) 131208f90673Sjfb goto proceed; 131308f90673Sjfb } 131408f90673Sjfb } 131537af5b8bSxsa if ((a > b) || (c <= d)) { /* Changes and inserts. */ 131608f90673Sjfb for (i = c; i <= d; i++) { 131708f90673Sjfb line = preadline(fileno(f2), 131808f90673Sjfb ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 131908f90673Sjfb if (!ignoreline(line)) 132008f90673Sjfb goto proceed; 132108f90673Sjfb } 132208f90673Sjfb } 132308f90673Sjfb return; 132408f90673Sjfb } 132508f90673Sjfb proceed: 1326f9b67873Sniallo if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 132708f90673Sjfb /* 132808f90673Sjfb * Allocate change records as needed. 132908f90673Sjfb */ 133008f90673Sjfb if (context_vec_ptr == context_vec_end - 1) { 133118501190Sniallo struct context_vec *tmp; 133208f90673Sjfb ptrdiff_t offset = context_vec_ptr - context_vec_start; 133308f90673Sjfb max_context <<= 1; 13340450b43bSjoris tmp = xrealloc(context_vec_start, max_context * 13350450b43bSjoris sizeof(struct context_vec)); 133618501190Sniallo context_vec_start = tmp; 133708f90673Sjfb context_vec_end = context_vec_start + max_context; 133808f90673Sjfb context_vec_ptr = context_vec_start + offset; 133908f90673Sjfb } 134008f90673Sjfb if (anychange == 0) { 134108f90673Sjfb /* 134208f90673Sjfb * Print the context/unidiff header first time through. 134308f90673Sjfb */ 1344f9b67873Sniallo diff_output("%s %s %s", 1345f9b67873Sniallo diff_format == D_CONTEXT ? "***" : "---", diff_file, 134608f90673Sjfb ctime(&stb1.st_mtime)); 1347f9b67873Sniallo diff_output("%s %s %s", 1348f9b67873Sniallo diff_format == D_CONTEXT ? "---" : "+++", diff_file, 134908f90673Sjfb ctime(&stb2.st_mtime)); 135008f90673Sjfb anychange = 1; 135108f90673Sjfb } else if (a > context_vec_ptr->b + (2 * context) + 1 && 135208f90673Sjfb c > context_vec_ptr->d + (2 * context) + 1) { 135308f90673Sjfb /* 135408f90673Sjfb * If this change is more than 'context' lines from the 135508f90673Sjfb * previous change, dump the record and reset it. 135608f90673Sjfb */ 1357f9b67873Sniallo if (diff_format == D_CONTEXT) 135808f90673Sjfb dump_context_vec(f1, f2); 135908f90673Sjfb else 136008f90673Sjfb dump_unified_vec(f1, f2); 136108f90673Sjfb } 136208f90673Sjfb context_vec_ptr++; 136308f90673Sjfb context_vec_ptr->a = a; 136408f90673Sjfb context_vec_ptr->b = b; 136508f90673Sjfb context_vec_ptr->c = c; 136608f90673Sjfb context_vec_ptr->d = d; 136708f90673Sjfb return; 136808f90673Sjfb } 136908f90673Sjfb if (anychange == 0) 137008f90673Sjfb anychange = 1; 1371f9b67873Sniallo switch (diff_format) { 137208f90673Sjfb case D_BRIEF: 137308f90673Sjfb return; 137408f90673Sjfb case D_NORMAL: 137508f90673Sjfb range(a, b, ","); 1376f9b67873Sniallo diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 1377f9b67873Sniallo if (diff_format == D_NORMAL) 137808f90673Sjfb range(c, d, ","); 1379f9b67873Sniallo diff_output("\n"); 138008f90673Sjfb break; 1381394180a4Sjfb case D_RCSDIFF: 1382394180a4Sjfb if (a > b) 1383f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1384394180a4Sjfb else { 1385f9b67873Sniallo diff_output("d%d %d\n", a, b - a + 1); 1386394180a4Sjfb 1387394180a4Sjfb if (!(c > d)) /* add changed lines */ 1388f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1389394180a4Sjfb } 1390394180a4Sjfb break; 139108f90673Sjfb } 1392f9b67873Sniallo if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 139308f90673Sjfb fetch(ixold, a, b, f1, '<', 1); 1394f9b67873Sniallo if (a <= b && c <= d && diff_format == D_NORMAL) 1395206543eeSjoris diff_output("---\n"); 139608f90673Sjfb } 1397f9b67873Sniallo i = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); 139808f90673Sjfb if (inifdef) { 1399f9b67873Sniallo diff_output("#endif /* %s */\n", ifdefname); 140008f90673Sjfb inifdef = 0; 140108f90673Sjfb } 140208f90673Sjfb } 140308f90673Sjfb 140408f90673Sjfb static int 140508f90673Sjfb fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 140608f90673Sjfb { 140708f90673Sjfb int i, j, c, lastc, col, nc; 140808f90673Sjfb 140908f90673Sjfb /* 141008f90673Sjfb * When doing #ifdef's, copy down to current line 141108f90673Sjfb * if this is the first file, so that stuff makes it to output. 141208f90673Sjfb */ 1413f9b67873Sniallo if (diff_format == D_IFDEF && oldfile) { 141408f90673Sjfb long curpos = ftell(lb); 141508f90673Sjfb /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 141608f90673Sjfb nc = f[a > b ? b : a - 1] - curpos; 141708f90673Sjfb for (i = 0; i < nc; i++) 1418f9b67873Sniallo diff_output("%c", getc(lb)); 141908f90673Sjfb } 142008f90673Sjfb if (a > b) 142108f90673Sjfb return (0); 1422f9b67873Sniallo if (diff_format == D_IFDEF) { 142308f90673Sjfb if (inifdef) { 1424f9b67873Sniallo diff_output("#else /* %s%s */\n", 142508f90673Sjfb oldfile == 1 ? "!" : "", ifdefname); 142608f90673Sjfb } else { 142708f90673Sjfb if (oldfile) 1428f9b67873Sniallo diff_output("#ifndef %s\n", ifdefname); 142908f90673Sjfb else 1430f9b67873Sniallo diff_output("#ifdef %s\n", ifdefname); 143108f90673Sjfb } 143208f90673Sjfb inifdef = 1 + oldfile; 143308f90673Sjfb } 143408f90673Sjfb for (i = a; i <= b; i++) { 143508f90673Sjfb fseek(lb, f[i - 1], SEEK_SET); 143608f90673Sjfb nc = f[i] - f[i - 1]; 1437f9b67873Sniallo if (diff_format != D_IFDEF && ch != '\0') { 1438f9b67873Sniallo diff_output("%c", ch); 143948dc77e6Sxsa if ((Tflag == 1 ) && (diff_format == D_NORMAL || 14409c5161e4Sjoris diff_format == D_CONTEXT || 14419c5161e4Sjoris diff_format == D_UNIFIED)) 1442f9b67873Sniallo diff_output("\t"); 1443f9b67873Sniallo else if (diff_format != D_UNIFIED) 1444f9b67873Sniallo diff_output(" "); 144508f90673Sjfb } 144608f90673Sjfb col = 0; 144708f90673Sjfb for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { 144808f90673Sjfb if ((c = getc(lb)) == EOF) { 1449f9b67873Sniallo if (diff_format == D_RCSDIFF) 1450394180a4Sjfb warnx("No newline at end of file"); 1451394180a4Sjfb else 14529c5161e4Sjoris diff_output("\n\\ No newline at end of " 14539c5161e4Sjoris "file"); 145408f90673Sjfb return (0); 145508f90673Sjfb } 145648dc77e6Sxsa if ((c == '\t') && (tflag == 1)) { 145708f90673Sjfb do { 1458f9b67873Sniallo diff_output(" "); 145908f90673Sjfb } while (++col & 7); 146008f90673Sjfb } else { 1461f9b67873Sniallo diff_output("%c", c); 146208f90673Sjfb col++; 146308f90673Sjfb } 146408f90673Sjfb } 146508f90673Sjfb } 146608f90673Sjfb return (0); 146708f90673Sjfb } 146808f90673Sjfb 146908f90673Sjfb /* 147008f90673Sjfb * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 147108f90673Sjfb */ 147208f90673Sjfb static int 147308f90673Sjfb readhash(FILE *f) 147408f90673Sjfb { 147508f90673Sjfb int i, t, space; 147608f90673Sjfb int sum; 147708f90673Sjfb 147808f90673Sjfb sum = 1; 147908f90673Sjfb space = 0; 148048dc77e6Sxsa if ((bflag != 1) && (wflag != 1)) { 148148dc77e6Sxsa if (iflag == 1) 148208f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 148308f90673Sjfb if (t == EOF) { 148408f90673Sjfb if (i == 0) 148508f90673Sjfb return (0); 148608f90673Sjfb break; 148708f90673Sjfb } 148808f90673Sjfb sum = sum * 127 + chrtran[t]; 148908f90673Sjfb } 149008f90673Sjfb else 149108f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 149208f90673Sjfb if (t == EOF) { 149308f90673Sjfb if (i == 0) 149408f90673Sjfb return (0); 149508f90673Sjfb break; 149608f90673Sjfb } 149708f90673Sjfb sum = sum * 127 + t; 149808f90673Sjfb } 149908f90673Sjfb } else { 150008f90673Sjfb for (i = 0;;) { 150108f90673Sjfb switch (t = getc(f)) { 150208f90673Sjfb case '\t': 150308f90673Sjfb case ' ': 150408f90673Sjfb space++; 150508f90673Sjfb continue; 150608f90673Sjfb default: 150748dc77e6Sxsa if ((space != 0) && (wflag != 1)) { 150808f90673Sjfb i++; 150908f90673Sjfb space = 0; 151008f90673Sjfb } 151108f90673Sjfb sum = sum * 127 + chrtran[t]; 151208f90673Sjfb i++; 151308f90673Sjfb continue; 151408f90673Sjfb case EOF: 151508f90673Sjfb if (i == 0) 151608f90673Sjfb return (0); 151708f90673Sjfb /* FALLTHROUGH */ 151808f90673Sjfb case '\n': 151908f90673Sjfb break; 152008f90673Sjfb } 152108f90673Sjfb break; 152208f90673Sjfb } 152308f90673Sjfb } 152408f90673Sjfb /* 152508f90673Sjfb * There is a remote possibility that we end up with a zero sum. 152608f90673Sjfb * Zero is used as an EOF marker, so return 1 instead. 152708f90673Sjfb */ 152808f90673Sjfb return (sum == 0 ? 1 : sum); 152908f90673Sjfb } 153008f90673Sjfb 153108f90673Sjfb static int 153208f90673Sjfb asciifile(FILE *f) 153308f90673Sjfb { 153408f90673Sjfb char buf[BUFSIZ]; 153508f90673Sjfb int i, cnt; 153608f90673Sjfb 153748dc77e6Sxsa if ((aflag == 1) || (f == NULL)) 153808f90673Sjfb return (1); 153908f90673Sjfb 154008f90673Sjfb rewind(f); 1541f1901a5aSxsa cnt = fread(buf, (size_t)1, sizeof(buf), f); 154208f90673Sjfb for (i = 0; i < cnt; i++) 154308f90673Sjfb if (!isprint(buf[i]) && !isspace(buf[i])) 154408f90673Sjfb return (0); 154508f90673Sjfb return (1); 154608f90673Sjfb } 154708f90673Sjfb 15485e78344dSjfb static char* 15495e78344dSjfb match_function(const long *f, int pos, FILE *fp) 15505e78344dSjfb { 15515e78344dSjfb unsigned char buf[FUNCTION_CONTEXT_SIZE]; 15525e78344dSjfb size_t nc; 15535e78344dSjfb int last = lastline; 15545e78344dSjfb char *p; 15555e78344dSjfb 15565e78344dSjfb lastline = pos; 15575e78344dSjfb while (pos > last) { 15585e78344dSjfb fseek(fp, f[pos - 1], SEEK_SET); 15595e78344dSjfb nc = f[pos] - f[pos - 1]; 15605e78344dSjfb if (nc >= sizeof(buf)) 15615e78344dSjfb nc = sizeof(buf) - 1; 1562f1901a5aSxsa nc = fread(buf, (size_t)1, nc, fp); 15635e78344dSjfb if (nc > 0) { 15645e78344dSjfb buf[nc] = '\0'; 1565634926d6Sniallo p = strchr((const char *)buf, '\n'); 15665e78344dSjfb if (p != NULL) 15675e78344dSjfb *p = '\0'; 15685e78344dSjfb if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 15694c06e5f6Sreyk strlcpy(lastbuf, (const char *)buf, 15704c06e5f6Sreyk sizeof lastbuf); 15715e78344dSjfb lastmatchline = pos; 15725e78344dSjfb return lastbuf; 15735e78344dSjfb } 15745e78344dSjfb } 15755e78344dSjfb pos--; 15765e78344dSjfb } 15775e78344dSjfb return (lastmatchline > 0) ? lastbuf : NULL; 15785e78344dSjfb } 15795e78344dSjfb 158008f90673Sjfb 158108f90673Sjfb /* dump accumulated "context" diff changes */ 158208f90673Sjfb static void 158308f90673Sjfb dump_context_vec(FILE *f1, FILE *f2) 158408f90673Sjfb { 158508f90673Sjfb struct context_vec *cvp = context_vec_start; 158608f90673Sjfb int lowa, upb, lowc, upd, do_output; 158708f90673Sjfb int a, b, c, d; 15885e78344dSjfb char ch, *f; 158908f90673Sjfb 159008f90673Sjfb if (context_vec_start > context_vec_ptr) 159108f90673Sjfb return; 159208f90673Sjfb 159308f90673Sjfb b = d = 0; /* gcc */ 1594dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1595e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1596dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1597e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 159808f90673Sjfb 1599f9b67873Sniallo diff_output("***************"); 160048dc77e6Sxsa if (pflag == 1) { 16015e78344dSjfb f = match_function(ixold, lowa - 1, f1); 16025e78344dSjfb if (f != NULL) { 1603f9b67873Sniallo diff_output(" "); 1604f9b67873Sniallo diff_output("%s", f); 16055e78344dSjfb } 16065e78344dSjfb } 1607f9b67873Sniallo diff_output("\n*** "); 160808f90673Sjfb range(lowa, upb, ","); 1609f9b67873Sniallo diff_output(" ****\n"); 161008f90673Sjfb 161108f90673Sjfb /* 161208f90673Sjfb * Output changes to the "old" file. The first loop suppresses 161308f90673Sjfb * output if there were no changes to the "old" file (we'll see 161408f90673Sjfb * the "old" lines as context in the "new" list). 161508f90673Sjfb */ 161608f90673Sjfb do_output = 0; 161708f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) 161808f90673Sjfb if (cvp->a <= cvp->b) { 161908f90673Sjfb cvp = context_vec_start; 162008f90673Sjfb do_output++; 162108f90673Sjfb break; 162208f90673Sjfb } 162337af5b8bSxsa if (do_output != 0) { 162408f90673Sjfb while (cvp <= context_vec_ptr) { 162508f90673Sjfb a = cvp->a; 162608f90673Sjfb b = cvp->b; 162708f90673Sjfb c = cvp->c; 162808f90673Sjfb d = cvp->d; 162908f90673Sjfb 163008f90673Sjfb if (a <= b && c <= d) 163108f90673Sjfb ch = 'c'; 163208f90673Sjfb else 163308f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 163408f90673Sjfb 163508f90673Sjfb if (ch == 'a') 163608f90673Sjfb fetch(ixold, lowa, b, f1, ' ', 0); 163708f90673Sjfb else { 163808f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 163908f90673Sjfb fetch(ixold, a, b, f1, 164008f90673Sjfb ch == 'c' ? '!' : '-', 0); 164108f90673Sjfb } 164208f90673Sjfb lowa = b + 1; 164308f90673Sjfb cvp++; 164408f90673Sjfb } 164508f90673Sjfb fetch(ixold, b + 1, upb, f1, ' ', 0); 164608f90673Sjfb } 164708f90673Sjfb /* output changes to the "new" file */ 1648f9b67873Sniallo diff_output("--- "); 164908f90673Sjfb range(lowc, upd, ","); 1650f9b67873Sniallo diff_output(" ----\n"); 165108f90673Sjfb 165208f90673Sjfb do_output = 0; 165308f90673Sjfb for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 165408f90673Sjfb if (cvp->c <= cvp->d) { 165508f90673Sjfb cvp = context_vec_start; 165608f90673Sjfb do_output++; 165708f90673Sjfb break; 165808f90673Sjfb } 165937af5b8bSxsa if (do_output != 0) { 166008f90673Sjfb while (cvp <= context_vec_ptr) { 166108f90673Sjfb a = cvp->a; 166208f90673Sjfb b = cvp->b; 166308f90673Sjfb c = cvp->c; 166408f90673Sjfb d = cvp->d; 166508f90673Sjfb 166608f90673Sjfb if (a <= b && c <= d) 166708f90673Sjfb ch = 'c'; 166808f90673Sjfb else 166908f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 167008f90673Sjfb 167108f90673Sjfb if (ch == 'd') 167208f90673Sjfb fetch(ixnew, lowc, d, f2, ' ', 0); 167308f90673Sjfb else { 167408f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 167508f90673Sjfb fetch(ixnew, c, d, f2, 167608f90673Sjfb ch == 'c' ? '!' : '+', 0); 167708f90673Sjfb } 167808f90673Sjfb lowc = d + 1; 167908f90673Sjfb cvp++; 168008f90673Sjfb } 168108f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 168208f90673Sjfb } 168308f90673Sjfb context_vec_ptr = context_vec_start - 1; 168408f90673Sjfb } 168508f90673Sjfb 168608f90673Sjfb /* dump accumulated "unified" diff changes */ 168708f90673Sjfb static void 168808f90673Sjfb dump_unified_vec(FILE *f1, FILE *f2) 168908f90673Sjfb { 169008f90673Sjfb struct context_vec *cvp = context_vec_start; 169108f90673Sjfb int lowa, upb, lowc, upd; 169208f90673Sjfb int a, b, c, d; 16935e78344dSjfb char ch, *f; 169408f90673Sjfb 169508f90673Sjfb if (context_vec_start > context_vec_ptr) 169608f90673Sjfb return; 169708f90673Sjfb 169808f90673Sjfb b = d = 0; /* gcc */ 1699dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1700e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1701dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1702e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 170308f90673Sjfb 1704f9b67873Sniallo diff_output("@@ -"); 170508f90673Sjfb uni_range(lowa, upb); 1706f9b67873Sniallo diff_output(" +"); 170708f90673Sjfb uni_range(lowc, upd); 1708f9b67873Sniallo diff_output(" @@"); 170948dc77e6Sxsa if (pflag == 1) { 17105e78344dSjfb f = match_function(ixold, lowa - 1, f1); 17115e78344dSjfb if (f != NULL) { 1712f9b67873Sniallo diff_output(" "); 1713f9b67873Sniallo diff_output("%s", f); 17145e78344dSjfb } 17155e78344dSjfb } 1716f9b67873Sniallo diff_output("\n"); 171708f90673Sjfb 171808f90673Sjfb /* 171908f90673Sjfb * Output changes in "unified" diff format--the old and new lines 172008f90673Sjfb * are printed together. 172108f90673Sjfb */ 172208f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) { 172308f90673Sjfb a = cvp->a; 172408f90673Sjfb b = cvp->b; 172508f90673Sjfb c = cvp->c; 172608f90673Sjfb d = cvp->d; 172708f90673Sjfb 172808f90673Sjfb /* 172908f90673Sjfb * c: both new and old changes 173008f90673Sjfb * d: only changes in the old file 173108f90673Sjfb * a: only changes in the new file 173208f90673Sjfb */ 173308f90673Sjfb if (a <= b && c <= d) 173408f90673Sjfb ch = 'c'; 173508f90673Sjfb else 173608f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 173708f90673Sjfb 173808f90673Sjfb switch (ch) { 173908f90673Sjfb case 'c': 174008f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 174108f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 174208f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 174308f90673Sjfb break; 174408f90673Sjfb case 'd': 174508f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 174608f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 174708f90673Sjfb break; 174808f90673Sjfb case 'a': 174908f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 175008f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 175108f90673Sjfb break; 175208f90673Sjfb } 175308f90673Sjfb lowa = b + 1; 175408f90673Sjfb lowc = d + 1; 175508f90673Sjfb } 175608f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 175708f90673Sjfb 175808f90673Sjfb context_vec_ptr = context_vec_start - 1; 175908f90673Sjfb } 1760f9b67873Sniallo 176101af718aSjoris void 1762f9b67873Sniallo diff_output(const char *fmt, ...) 1763f9b67873Sniallo { 1764f9b67873Sniallo va_list vap; 1765f9b67873Sniallo char *str; 1766f9b67873Sniallo 1767f9b67873Sniallo va_start(vap, fmt); 1768f9b67873Sniallo vasprintf(&str, fmt, vap); 1769f9b67873Sniallo if (diffbuf != NULL) 1770f9b67873Sniallo cvs_buf_append(diffbuf, str, strlen(str)); 1771f9b67873Sniallo else 1772f9b67873Sniallo cvs_printf("%s", str); 17730450b43bSjoris xfree(str); 1774f9b67873Sniallo va_end(vap); 1775f9b67873Sniallo } 1776