1*78de3304Sniallo /* $OpenBSD: diff.c,v 1.68 2005/12/01 20:36:30 niallo 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; 220*78de3304Sniallo 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 36016cfc147Sjoris dap = (struct diff_arg *)malloc(sizeof(*dap)); 36116cfc147Sjoris if (dap == NULL) 36231274bbfSjoris return (CVS_EX_DATA); 36316cfc147Sjoris dap->date1 = dap->date2 = dap->rev1 = dap->rev2 = NULL; 364dc6a6879Sjfb strlcpy(diffargs, argv[0], sizeof(diffargs)); 365dc6a6879Sjfb 366e4276007Sjfb while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { 36708f90673Sjfb switch (ch) { 36808f90673Sjfb case 'c': 369f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 370f9b67873Sniallo diff_format = D_CONTEXT; 37108f90673Sjfb break; 37208f90673Sjfb case 'D': 37316cfc147Sjoris if (dap->date1 == NULL && dap->rev1 == NULL) { 37416cfc147Sjoris dap->date1 = optarg; 37516cfc147Sjoris } else if (dap->date2 == NULL && dap->rev2 == NULL) { 37616cfc147Sjoris dap->date2 = optarg; 37716cfc147Sjoris } else { 37808f90673Sjfb cvs_log(LP_ERR, 37908f90673Sjfb "no more than two revisions/dates can " 38008f90673Sjfb "be specified"); 38108f90673Sjfb } 38208f90673Sjfb break; 38308f90673Sjfb case 'l': 384f5638424Sjfb strlcat(diffargs, " -l", sizeof(diffargs)); 38508f90673Sjfb recurse = 0; 386e4276007Sjfb cvs_cmd_diff.file_flags &= ~CF_RECURSE; 38708f90673Sjfb break; 38808f90673Sjfb case 'i': 389f5638424Sjfb strlcat(diffargs, " -i", sizeof(diffargs)); 39008f90673Sjfb iflag = 1; 39108f90673Sjfb break; 392c710bc5aSjfb case 'N': 393c710bc5aSjfb strlcat(diffargs, " -N", sizeof(diffargs)); 394c710bc5aSjfb Nflag = 1; 395c710bc5aSjfb break; 396394180a4Sjfb case 'n': 397394180a4Sjfb strlcat(diffargs, " -n", sizeof(diffargs)); 398f9b67873Sniallo diff_format = D_RCSDIFF; 399394180a4Sjfb break; 4005e78344dSjfb case 'p': 4015e78344dSjfb strlcat(diffargs, " -p", sizeof(diffargs)); 4025e78344dSjfb pflag = 1; 4035e78344dSjfb break; 40408f90673Sjfb case 'r': 40516cfc147Sjoris if ((dap->rev1 == NULL) && (dap->date1 == NULL)) { 40616cfc147Sjoris dap->rev1 = optarg; 40716cfc147Sjoris } else if ((dap->rev2 == NULL) && 40816cfc147Sjoris (dap->date2 == NULL)) { 40916cfc147Sjoris dap->rev2 = optarg; 41016cfc147Sjoris } else { 41108f90673Sjfb cvs_log(LP_ERR, 41208f90673Sjfb "no more than two revisions/dates can " 41308f90673Sjfb "be specified"); 41431274bbfSjoris return (CVS_EX_USAGE); 41508f90673Sjfb } 41608f90673Sjfb break; 417f203c484Sjoris case 'R': 418e4276007Sjfb cvs_cmd_diff.file_flags |= CF_RECURSE; 419f203c484Sjoris break; 42008f90673Sjfb case 'u': 421f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 422f9b67873Sniallo diff_format = D_UNIFIED; 42308f90673Sjfb break; 42408f90673Sjfb default: 42531274bbfSjoris return (CVS_EX_USAGE); 42608f90673Sjfb } 42708f90673Sjfb } 42808f90673Sjfb 42916cfc147Sjoris *arg = optind; 430dc6a6879Sjfb return (0); 431dc6a6879Sjfb } 432dc6a6879Sjfb 43316cfc147Sjoris int 43416cfc147Sjoris cvs_diff_cleanup(void) 43516cfc147Sjoris { 436e4276007Sjfb if (dap != NULL) { 43716cfc147Sjoris free(dap); 438e4276007Sjfb dap = NULL; 439e4276007Sjfb } 44016cfc147Sjoris return (0); 44116cfc147Sjoris } 442dc6a6879Sjfb 443dc6a6879Sjfb /* 444e4276007Sjfb * cvs_diff_pre_exec() 445dc6a6879Sjfb * 446dc6a6879Sjfb */ 447dc6a6879Sjfb int 448e4276007Sjfb cvs_diff_pre_exec(struct cvsroot *root) 449dc6a6879Sjfb { 450e4276007Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 45108f90673Sjfb /* send the flags */ 45248dc77e6Sxsa if ((Nflag == 1) && (cvs_sendarg(root, "-N", 0) < 0)) 45331274bbfSjoris return (CVS_EX_PROTO); 45448dc77e6Sxsa if ((pflag ==1) && (cvs_sendarg(root, "-p", 0) < 0)) 45531274bbfSjoris return (CVS_EX_PROTO); 4565e78344dSjfb 457f9b67873Sniallo if (diff_format == D_CONTEXT) { 458610801e8Sxsa if (cvs_sendarg(root, "-c", 0) < 0) 459610801e8Sxsa return (CVS_EX_PROTO); 460f9b67873Sniallo } else if (diff_format == D_UNIFIED) { 461610801e8Sxsa if (cvs_sendarg(root, "-u", 0) < 0) 462610801e8Sxsa return (CVS_EX_PROTO); 463610801e8Sxsa } 46408f90673Sjfb 465dc6a6879Sjfb if (dap->rev1 != NULL) { 466610801e8Sxsa if ((cvs_sendarg(root, "-r", 0) < 0) || 467610801e8Sxsa (cvs_sendarg(root, dap->rev1, 0) < 0)) 468610801e8Sxsa return (CVS_EX_PROTO); 4693917c9bfSderaadt } else if (dap->date1 != NULL) { 470610801e8Sxsa if ((cvs_sendarg(root, "-D", 0) < 0) || 471610801e8Sxsa (cvs_sendarg(root, dap->date1, 0) < 0)) 472610801e8Sxsa return (CVS_EX_PROTO); 47308f90673Sjfb } 474dc6a6879Sjfb if (dap->rev2 != NULL) { 475610801e8Sxsa if ((cvs_sendarg(root, "-r", 0) < 0) || 476610801e8Sxsa (cvs_sendarg(root, dap->rev2, 0) < 0)) 477610801e8Sxsa return (CVS_EX_PROTO); 4783917c9bfSderaadt } else if (dap->date2 != NULL) { 479610801e8Sxsa if ((cvs_sendarg(root, "-D", 0) < 0) || 480610801e8Sxsa (cvs_sendarg(root, dap->date2, 0) < 0)) 481610801e8Sxsa return (CVS_EX_PROTO); 48208f90673Sjfb } 483e4276007Sjfb } 48408f90673Sjfb 48508f90673Sjfb return (0); 48608f90673Sjfb } 48708f90673Sjfb 48808f90673Sjfb 48908f90673Sjfb /* 49008f90673Sjfb * cvs_diff_file() 49108f90673Sjfb * 49208f90673Sjfb * Diff a single file. 49308f90673Sjfb */ 494e4276007Sjfb static int 495e4276007Sjfb cvs_diff_remote(struct cvs_file *cfp, void *arg) 49608f90673Sjfb { 497e4276007Sjfb char *dir, *repo; 498e4276007Sjfb char fpath[MAXPATHLEN], dfpath[MAXPATHLEN]; 499dc6a6879Sjfb struct cvsroot *root; 500dc6a6879Sjfb 501dc6a6879Sjfb if (cfp->cf_type == DT_DIR) { 502895e6cf6Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 503bb029937Sjfb root = cfp->cf_parent->cf_root; 504b904ba2eSjoris cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 5053917c9bfSderaadt } else { 506bb029937Sjfb root = cfp->cf_root; 50716cfc147Sjoris #if 0 508dc6a6879Sjfb if ((cfp->cf_parent == NULL) || 509bb029937Sjfb (root != cfp->cf_parent->cf_root)) { 510dc6a6879Sjfb cvs_connect(root); 511e4276007Sjfb cvs_diff_pre_exec(root); 512dc6a6879Sjfb } 51316cfc147Sjoris #endif 514dc6a6879Sjfb 515dc6a6879Sjfb cvs_senddir(root, cfp); 516895e6cf6Sjfb } 517895e6cf6Sjfb 518dc6a6879Sjfb return (0); 519dc6a6879Sjfb } 52008f90673Sjfb 5212d5b8b1dSjfb if (cfp->cf_cvstat == CVS_FST_LOST) { 522b904ba2eSjoris cvs_log(LP_WARN, "cannot find file %s", cfp->cf_name); 5232d5b8b1dSjfb return (0); 5242d5b8b1dSjfb } 5252d5b8b1dSjfb 526c710bc5aSjfb diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath)); 527895e6cf6Sjfb 528dc6a6879Sjfb if (cfp->cf_parent != NULL) { 529c710bc5aSjfb dir = cvs_file_getpath(cfp->cf_parent, dfpath, sizeof(dfpath)); 530bb029937Sjfb root = cfp->cf_parent->cf_root; 531bb029937Sjfb repo = cfp->cf_parent->cf_repo; 5323917c9bfSderaadt } else { 533dc6a6879Sjfb dir = "."; 534895e6cf6Sjfb root = NULL; 535dc6a6879Sjfb repo = NULL; 53608f90673Sjfb } 53708f90673Sjfb 538dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 539e4276007Sjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 540dc6a6879Sjfb return (0); 54108f90673Sjfb } 54208f90673Sjfb 543e4276007Sjfb if (cvs_sendentry(root, cfp) < 0) 54431274bbfSjoris return (CVS_EX_PROTO); 54508f90673Sjfb 546dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UPTODATE) { 547e4276007Sjfb cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); 54808f90673Sjfb return (0); 54908f90673Sjfb } 55008f90673Sjfb 55108f90673Sjfb /* at this point, the file is modified */ 552e4276007Sjfb if ((cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name) < 0) || 553e4276007Sjfb (cvs_sendfile(root, diff_file) < 0)) 554e4276007Sjfb return (CVS_EX_PROTO); 555e4276007Sjfb 556e4276007Sjfb return (0); 557e4276007Sjfb } 558e4276007Sjfb 559e4276007Sjfb static int 560e4276007Sjfb cvs_diff_local(CVSFILE *cf, void *arg) 561e4276007Sjfb { 562e4276007Sjfb int len; 563e4276007Sjfb char *repo, buf[64]; 564e4276007Sjfb char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; 565e4276007Sjfb char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN]; 566e4276007Sjfb BUF *b1, *b2; 567e4276007Sjfb RCSNUM *r1, *r2; 568e4276007Sjfb RCSFILE *rf; 569e4276007Sjfb struct cvsroot *root; 570e4276007Sjfb 571e4276007Sjfb rf = NULL; 572e4276007Sjfb root = CVS_DIR_ROOT(cf); 573e4276007Sjfb repo = CVS_DIR_REPO(cf); 574e4276007Sjfb diff_file = cvs_file_getpath(cf, fpath, sizeof(fpath)); 575e4276007Sjfb 576e4276007Sjfb if (cf->cf_type == DT_DIR) { 577b87c59bdSxsa if (verbosity > 1) 578246675edSxsa cvs_log(LP_NOTICE, "Diffing %s", fpath); 579e4276007Sjfb return (0); 580e4276007Sjfb } 581e4276007Sjfb 582e4276007Sjfb if (cf->cf_cvstat == CVS_FST_LOST) { 583e4276007Sjfb cvs_log(LP_WARN, "cannot find file %s", cf->cf_name); 584e4276007Sjfb return (0); 585e4276007Sjfb } 586e4276007Sjfb 587e4276007Sjfb if (cf->cf_cvstat == CVS_FST_UNKNOWN) { 588e4276007Sjfb cvs_log(LP_WARN, "I know nothing about %s", diff_file); 589e4276007Sjfb return (0); 5905c0cd766Sniallo } else if (cf->cf_cvstat == CVS_FST_UPTODATE) 591e4276007Sjfb return (0); 592e4276007Sjfb 593e4276007Sjfb /* at this point, the file is modified */ 594e4276007Sjfb len = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 595dc6a6879Sjfb root->cr_dir, repo, diff_file, RCS_FILE_EXT); 596e4276007Sjfb if (len == -1 || len >= (int)sizeof(rcspath)) { 59727b85f85Sxsa errno = ENAMETOOLONG; 59827b85f85Sxsa cvs_log(LP_ERRNO, "%s", rcspath); 59901b3d77aSjoris return (CVS_EX_DATA); 60027b85f85Sxsa } 60108f90673Sjfb 6021b6534b8Sjfb rf = rcs_open(rcspath, RCS_READ); 603dc6a6879Sjfb if (rf == NULL) { 60431274bbfSjoris return (CVS_EX_DATA); 605dc6a6879Sjfb } 60608f90673Sjfb 607dc6a6879Sjfb cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, 60808f90673Sjfb RCS_DIFF_DIV, rcspath); 60908f90673Sjfb 610dc6a6879Sjfb if (dap->rev1 == NULL) 611e4276007Sjfb r1 = cf->cf_lrev; 61208f90673Sjfb else { 61325b74b48Sjfb if ((r1 = rcsnum_parse(dap->rev1)) == NULL) { 61464672f74Sjoris rcs_close(rf); 61531274bbfSjoris return (CVS_EX_DATA); 6167f535ec4Sjfb } 61708f90673Sjfb } 61808f90673Sjfb 619dc6a6879Sjfb cvs_printf("retrieving revision %s\n", 62008f90673Sjfb rcsnum_tostr(r1, buf, sizeof(buf))); 62108f90673Sjfb b1 = rcs_getrev(rf, r1); 62208f90673Sjfb 62395ae1173Sjoris if (b1 == NULL) { 624289b97f4Sxsa cvs_log(LP_ERR, "failed to retrieve revision %s\n", 62595ae1173Sjoris rcsnum_tostr(r1, buf, sizeof(buf))); 62695ae1173Sjoris if (r1 != cf->cf_lrev) 62795ae1173Sjoris rcsnum_free(r1); 62864672f74Sjoris rcs_close(rf); 62995ae1173Sjoris return (CVS_EX_DATA); 63095ae1173Sjoris } 63195ae1173Sjoris 632e4276007Sjfb if (r1 != cf->cf_lrev) 6337f535ec4Sjfb rcsnum_free(r1); 6347f535ec4Sjfb 635dc6a6879Sjfb if (dap->rev2 != NULL) { 636dc6a6879Sjfb cvs_printf("retrieving revision %s\n", dap->rev2); 63725b74b48Sjfb if ((r2 = rcsnum_parse(dap->rev2)) == NULL) { 63864672f74Sjoris rcs_close(rf); 63931274bbfSjoris return (CVS_EX_DATA); 6407f535ec4Sjfb } 64108f90673Sjfb b2 = rcs_getrev(rf, r2); 6427f535ec4Sjfb rcsnum_free(r2); 6433917c9bfSderaadt } else { 644dc6a6879Sjfb b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); 64508f90673Sjfb } 64608f90673Sjfb 647dc6a6879Sjfb rcs_close(rf); 648dc6a6879Sjfb 64995ae1173Sjoris if (b2 == NULL) { 650289b97f4Sxsa cvs_log(LP_ERR, "failed to retrieve revision %s\n", 65195ae1173Sjoris dap->rev2); 65295ae1173Sjoris cvs_buf_free(b1); 65395ae1173Sjoris return (CVS_EX_DATA); 65495ae1173Sjoris } 65595ae1173Sjoris 6565ac8b1e7Sjoris cvs_printf("%s", diffargs); 6575ac8b1e7Sjoris cvs_printf(" -r%s", buf); 658dc6a6879Sjfb if (dap->rev2 != NULL) 6595ac8b1e7Sjoris cvs_printf(" -r%s", dap->rev2); 6605ac8b1e7Sjoris cvs_printf(" %s\n", diff_file); 6611dee9299Sxsa strlcpy(path_tmp1, cvs_tmpdir, sizeof(path_tmp1)); 6621dee9299Sxsa strlcat(path_tmp1, "/diff1.XXXXXXXXXX", sizeof(path_tmp1)); 6637f535ec4Sjfb if (cvs_buf_write_stmp(b1, path_tmp1, 0600) == -1) { 6647f535ec4Sjfb cvs_buf_free(b1); 6657f535ec4Sjfb cvs_buf_free(b2); 66631274bbfSjoris return (CVS_EX_DATA); 6677f535ec4Sjfb } 6687f535ec4Sjfb cvs_buf_free(b1); 6697f535ec4Sjfb 6701dee9299Sxsa strlcpy(path_tmp2, cvs_tmpdir, sizeof(path_tmp2)); 6711dee9299Sxsa strlcat(path_tmp2, "/diff2.XXXXXXXXXX", sizeof(path_tmp2)); 672946f6157Sdjm if (cvs_buf_write_stmp(b2, path_tmp2, 0600) == -1) { 6737f535ec4Sjfb cvs_buf_free(b2); 674946f6157Sdjm (void)unlink(path_tmp1); 67531274bbfSjoris return (CVS_EX_DATA); 676946f6157Sdjm } 6777f535ec4Sjfb cvs_buf_free(b2); 6787f535ec4Sjfb 679f9b67873Sniallo cvs_diffreg(path_tmp1, path_tmp2, NULL); 680946f6157Sdjm (void)unlink(path_tmp1); 681946f6157Sdjm (void)unlink(path_tmp2); 68208f90673Sjfb 68308f90673Sjfb return (0); 68408f90673Sjfb } 685af5bb824Sniallo #endif 68608f90673Sjfb 68708f90673Sjfb 68808f90673Sjfb int 689f9b67873Sniallo cvs_diffreg(const char *file1, const char *file2, BUF *out) 69008f90673Sjfb { 69108f90673Sjfb FILE *f1, *f2; 69208f90673Sjfb int i, rval; 6937f535ec4Sjfb void *tmp; 69408f90673Sjfb 69508f90673Sjfb f1 = f2 = NULL; 69608f90673Sjfb rval = D_SAME; 69708f90673Sjfb anychange = 0; 69808f90673Sjfb lastline = 0; 69908f90673Sjfb lastmatchline = 0; 70008f90673Sjfb context_vec_ptr = context_vec_start - 1; 70108f90673Sjfb chrtran = (iflag ? cup2low : clow2low); 702f9b67873Sniallo if (out != NULL) 703f9b67873Sniallo diffbuf = out; 70408f90673Sjfb 70508f90673Sjfb f1 = fopen(file1, "r"); 70608f90673Sjfb if (f1 == NULL) { 70708f90673Sjfb cvs_log(LP_ERRNO, "%s", file1); 70808f90673Sjfb goto closem; 70908f90673Sjfb } 71008f90673Sjfb 71108f90673Sjfb f2 = fopen(file2, "r"); 71208f90673Sjfb if (f2 == NULL) { 71308f90673Sjfb cvs_log(LP_ERRNO, "%s", file2); 71408f90673Sjfb goto closem; 71508f90673Sjfb } 71608f90673Sjfb 71708f90673Sjfb switch (files_differ(f1, f2)) { 71808f90673Sjfb case 0: 71908f90673Sjfb goto closem; 72008f90673Sjfb case 1: 72108f90673Sjfb break; 72208f90673Sjfb default: 72308f90673Sjfb /* error */ 72408f90673Sjfb goto closem; 72508f90673Sjfb } 72608f90673Sjfb 72708f90673Sjfb if (!asciifile(f1) || !asciifile(f2)) { 72808f90673Sjfb rval = D_BINARY; 72908f90673Sjfb goto closem; 73008f90673Sjfb } 7317f535ec4Sjfb if ((prepare(0, f1, stb1.st_size) < 0) || 7327f535ec4Sjfb (prepare(1, f2, stb2.st_size) < 0)) { 7337f535ec4Sjfb goto closem; 7347f535ec4Sjfb } 73508f90673Sjfb prune(); 73608f90673Sjfb sort(sfile[0], slen[0]); 73708f90673Sjfb sort(sfile[1], slen[1]); 73808f90673Sjfb 73908f90673Sjfb member = (int *)file[1]; 74008f90673Sjfb equiv(sfile[0], slen[0], sfile[1], slen[1], member); 74118501190Sniallo if ((tmp = realloc(member, (slen[1] + 2) * sizeof(int))) == NULL) { 74218501190Sniallo free(member); 74318501190Sniallo member = NULL; 74418501190Sniallo cvs_log(LP_ERRNO, "failed to resize member"); 7457f535ec4Sjfb goto closem; 74618501190Sniallo } 7477f535ec4Sjfb member = (int *)tmp; 74808f90673Sjfb 74908f90673Sjfb class = (int *)file[0]; 75008f90673Sjfb unsort(sfile[0], slen[0], class); 75118501190Sniallo if ((tmp = realloc(class, (slen[0] + 2) * sizeof(int))) == NULL) { 75218501190Sniallo free(class); 75318501190Sniallo class = NULL; 75418501190Sniallo cvs_log(LP_ERRNO, "failed to resize class"); 7557f535ec4Sjfb goto closem; 75618501190Sniallo } 7577f535ec4Sjfb class = (int *)tmp; 75808f90673Sjfb 7597f535ec4Sjfb if ((klist = malloc((slen[0] + 2) * sizeof(int))) == NULL) { 7607f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate klist"); 7617f535ec4Sjfb goto closem; 7627f535ec4Sjfb } 76308f90673Sjfb clen = 0; 76408f90673Sjfb clistlen = 100; 7657f535ec4Sjfb if ((clist = malloc(clistlen * sizeof(cand))) == NULL) { 7667f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate clist"); 7677f535ec4Sjfb goto closem; 7687f535ec4Sjfb } 769ece76a70Sjoris 770ece76a70Sjoris if ((i = stone(class, slen[0], member, klist)) < 0) 771ece76a70Sjoris goto closem; 772ece76a70Sjoris 77308f90673Sjfb free(member); 77408f90673Sjfb free(class); 77508f90673Sjfb 77618501190Sniallo if ((tmp = realloc(J, (diff_len[0] + 2) * sizeof(int))) == NULL) { 77718501190Sniallo free(J); 77818501190Sniallo J = NULL; 77918501190Sniallo cvs_log(LP_ERRNO, "failed to resize J"); 78018501190Sniallo goto closem; 78118501190Sniallo } 78218501190Sniallo J = (int *)tmp; 78308f90673Sjfb unravel(klist[i]); 78408f90673Sjfb free(clist); 78508f90673Sjfb free(klist); 78608f90673Sjfb 78718501190Sniallo if ((tmp = realloc(ixold, (diff_len[0] + 2) * sizeof(long))) == NULL) { 78818501190Sniallo free(ixold); 78918501190Sniallo ixold = NULL; 79018501190Sniallo cvs_log(LP_ERRNO, "failed to resize ixold"); 79118501190Sniallo goto closem; 79218501190Sniallo } 79318501190Sniallo ixold = (long *)tmp; 79418501190Sniallo if ((tmp = realloc(ixnew, (diff_len[1] + 2) * sizeof(long))) == NULL) { 79518501190Sniallo free(ixnew); 79618501190Sniallo ixnew = NULL; 79718501190Sniallo cvs_log(LP_ERRNO, "failed to resize ixnew"); 79818501190Sniallo goto closem; 79918501190Sniallo } 80018501190Sniallo ixnew = (long *)tmp; 80108f90673Sjfb check(f1, f2); 80208f90673Sjfb output(file1, f1, file2, f2); 80308f90673Sjfb 80408f90673Sjfb closem: 80537af5b8bSxsa if (anychange == 1) { 80608f90673Sjfb if (rval == D_SAME) 80708f90673Sjfb rval = D_DIFFER; 80808f90673Sjfb } 80908f90673Sjfb if (f1 != NULL) 81008f90673Sjfb fclose(f1); 81108f90673Sjfb if (f2 != NULL) 81208f90673Sjfb fclose(f2); 8137f535ec4Sjfb 81408f90673Sjfb return (rval); 81508f90673Sjfb } 81608f90673Sjfb 81708f90673Sjfb /* 81808f90673Sjfb * Check to see if the given files differ. 81908f90673Sjfb * Returns 0 if they are the same, 1 if different, and -1 on error. 82008f90673Sjfb * XXX - could use code from cmp(1) [faster] 82108f90673Sjfb */ 82208f90673Sjfb static int 82308f90673Sjfb files_differ(FILE *f1, FILE *f2) 82408f90673Sjfb { 82508f90673Sjfb char buf1[BUFSIZ], buf2[BUFSIZ]; 82608f90673Sjfb size_t i, j; 82708f90673Sjfb 82808f90673Sjfb if (stb1.st_size != stb2.st_size) 82908f90673Sjfb return (1); 83008f90673Sjfb for (;;) { 831f1901a5aSxsa i = fread(buf1, (size_t)1, sizeof(buf1), f1); 832f1901a5aSxsa j = fread(buf2, (size_t)1, sizeof(buf2), f2); 83308f90673Sjfb if (i != j) 83408f90673Sjfb return (1); 83537af5b8bSxsa if ((i == 0) && (j == 0)) { 83608f90673Sjfb if (ferror(f1) || ferror(f2)) 83708f90673Sjfb return (1); 83808f90673Sjfb return (0); 83908f90673Sjfb } 84008f90673Sjfb if (memcmp(buf1, buf2, i) != 0) 84108f90673Sjfb return (1); 84208f90673Sjfb } 84308f90673Sjfb } 84408f90673Sjfb 8457f535ec4Sjfb static int 84608f90673Sjfb prepare(int i, FILE *fd, off_t filesize) 84708f90673Sjfb { 8487f535ec4Sjfb void *tmp; 84908f90673Sjfb struct line *p; 85008f90673Sjfb int j, h; 85108f90673Sjfb size_t sz; 85208f90673Sjfb 85308f90673Sjfb rewind(fd); 85408f90673Sjfb 855c48da046Sxsa sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 85608f90673Sjfb if (sz < 100) 85708f90673Sjfb sz = 100; 85808f90673Sjfb 8597f535ec4Sjfb p = (struct line *)malloc((sz + 3) * sizeof(struct line)); 8607f535ec4Sjfb if (p == NULL) { 8617f535ec4Sjfb cvs_log(LP_ERRNO, "failed to prepare line array"); 8627f535ec4Sjfb return (-1); 8637f535ec4Sjfb } 86408f90673Sjfb for (j = 0; (h = readhash(fd));) { 86508f90673Sjfb if (j == (int)sz) { 86608f90673Sjfb sz = sz * 3 / 2; 8677f535ec4Sjfb tmp = realloc(p, (sz + 3) * sizeof(struct line)); 8687f535ec4Sjfb if (tmp == NULL) { 8697f535ec4Sjfb cvs_log(LP_ERRNO, "failed to grow line array"); 8707f535ec4Sjfb free(p); 8717f535ec4Sjfb return (-1); 8727f535ec4Sjfb } 8737f535ec4Sjfb p = (struct line *)tmp; 87408f90673Sjfb } 87508f90673Sjfb p[++j].value = h; 87608f90673Sjfb } 877e4276007Sjfb diff_len[i] = j; 87808f90673Sjfb file[i] = p; 8797f535ec4Sjfb 8807f535ec4Sjfb return (0); 88108f90673Sjfb } 88208f90673Sjfb 88308f90673Sjfb static void 88408f90673Sjfb prune(void) 88508f90673Sjfb { 88608f90673Sjfb int i, j; 88708f90673Sjfb 888e4276007Sjfb for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 88908f90673Sjfb file[0][pref + 1].value == file[1][pref + 1].value; 89008f90673Sjfb pref++) 89108f90673Sjfb ; 892e4276007Sjfb for (suff = 0; 893e4276007Sjfb (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 894e4276007Sjfb (file[0][diff_len[0] - suff].value == 895e4276007Sjfb file[1][diff_len[1] - suff].value); 89608f90673Sjfb suff++) 89708f90673Sjfb ; 89808f90673Sjfb for (j = 0; j < 2; j++) { 89908f90673Sjfb sfile[j] = file[j] + pref; 900e4276007Sjfb slen[j] = diff_len[j] - pref - suff; 90108f90673Sjfb for (i = 0; i <= slen[j]; i++) 90208f90673Sjfb sfile[j][i].serial = i; 90308f90673Sjfb } 90408f90673Sjfb } 90508f90673Sjfb 90608f90673Sjfb static void 90708f90673Sjfb equiv(struct line *a, int n, struct line *b, int m, int *c) 90808f90673Sjfb { 90908f90673Sjfb int i, j; 91008f90673Sjfb 91108f90673Sjfb i = j = 1; 91208f90673Sjfb while (i <= n && j <= m) { 91308f90673Sjfb if (a[i].value < b[j].value) 91408f90673Sjfb a[i++].value = 0; 91508f90673Sjfb else if (a[i].value == b[j].value) 91608f90673Sjfb a[i++].value = j; 91708f90673Sjfb else 91808f90673Sjfb j++; 91908f90673Sjfb } 92008f90673Sjfb while (i <= n) 92108f90673Sjfb a[i++].value = 0; 92208f90673Sjfb b[m + 1].value = 0; 92308f90673Sjfb j = 0; 92408f90673Sjfb while (++j <= m) { 92508f90673Sjfb c[j] = -b[j].serial; 92608f90673Sjfb while (b[j + 1].value == b[j].value) { 92708f90673Sjfb j++; 92808f90673Sjfb c[j] = b[j].serial; 92908f90673Sjfb } 93008f90673Sjfb } 93108f90673Sjfb c[j] = -1; 93208f90673Sjfb } 93308f90673Sjfb 93408f90673Sjfb /* Code taken from ping.c */ 93508f90673Sjfb static int 93608f90673Sjfb isqrt(int n) 93708f90673Sjfb { 93808f90673Sjfb int y, x = 1; 93908f90673Sjfb 94008f90673Sjfb if (n == 0) 94108f90673Sjfb return (0); 94208f90673Sjfb 94308f90673Sjfb do { /* newton was a stinker */ 94408f90673Sjfb y = x; 94508f90673Sjfb x = n / x; 94608f90673Sjfb x += y; 94708f90673Sjfb x /= 2; 94808f90673Sjfb } while ((x - y) > 1 || (x - y) < -1); 94908f90673Sjfb 95008f90673Sjfb return (x); 95108f90673Sjfb } 95208f90673Sjfb 95308f90673Sjfb static int 95408f90673Sjfb stone(int *a, int n, int *b, int *c) 95508f90673Sjfb { 956ece76a70Sjoris int ret; 95708f90673Sjfb int i, k, y, j, l; 95808f90673Sjfb int oldc, tc, oldl; 95908f90673Sjfb u_int numtries; 96008f90673Sjfb 961cc649edbSjfb /* XXX move the isqrt() out of the macro to avoid multiple calls */ 962cc649edbSjfb const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 96308f90673Sjfb 96408f90673Sjfb k = 0; 965ece76a70Sjoris if ((ret = newcand(0, 0, 0)) < 0) 966ece76a70Sjoris return (-1); 967ece76a70Sjoris c[0] = ret; 96808f90673Sjfb for (i = 1; i <= n; i++) { 96908f90673Sjfb j = a[i]; 97008f90673Sjfb if (j == 0) 97108f90673Sjfb continue; 97208f90673Sjfb y = -b[j]; 97308f90673Sjfb oldl = 0; 97408f90673Sjfb oldc = c[0]; 97508f90673Sjfb numtries = 0; 97608f90673Sjfb do { 97708f90673Sjfb if (y <= clist[oldc].y) 97808f90673Sjfb continue; 97908f90673Sjfb l = search(c, k, y); 98008f90673Sjfb if (l != oldl + 1) 98108f90673Sjfb oldc = c[l - 1]; 98208f90673Sjfb if (l <= k) { 98308f90673Sjfb if (clist[c[l]].y <= y) 98408f90673Sjfb continue; 98508f90673Sjfb tc = c[l]; 986ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 987ece76a70Sjoris return (-1); 988ece76a70Sjoris c[l] = ret; 98908f90673Sjfb oldc = tc; 99008f90673Sjfb oldl = l; 99108f90673Sjfb numtries++; 99208f90673Sjfb } else { 993ece76a70Sjoris if ((ret = newcand(i, y, oldc)) < 0) 994ece76a70Sjoris return (-1); 995ece76a70Sjoris c[l] = ret; 99608f90673Sjfb k++; 99708f90673Sjfb break; 99808f90673Sjfb } 99908f90673Sjfb } while ((y = b[++j]) > 0 && numtries < bound); 100008f90673Sjfb } 100108f90673Sjfb return (k); 100208f90673Sjfb } 100308f90673Sjfb 100408f90673Sjfb static int 100508f90673Sjfb newcand(int x, int y, int pred) 100608f90673Sjfb { 100718501190Sniallo struct cand *q, *tmp; 100818501190Sniallo int newclistlen; 100908f90673Sjfb 101008f90673Sjfb if (clen == clistlen) { 101118501190Sniallo newclistlen = clistlen * 11 / 10; 101218501190Sniallo tmp = realloc(clist, newclistlen * sizeof(cand)); 101318501190Sniallo if (tmp == NULL) { 10147f535ec4Sjfb cvs_log(LP_ERRNO, "failed to resize clist"); 10157f535ec4Sjfb return (-1); 10167f535ec4Sjfb } 101718501190Sniallo clist = tmp; 101818501190Sniallo clistlen = newclistlen; 101908f90673Sjfb } 102008f90673Sjfb q = clist + clen; 102108f90673Sjfb q->x = x; 102208f90673Sjfb q->y = y; 102308f90673Sjfb q->pred = pred; 102408f90673Sjfb return (clen++); 102508f90673Sjfb } 102608f90673Sjfb 102708f90673Sjfb static int 102808f90673Sjfb search(int *c, int k, int y) 102908f90673Sjfb { 103008f90673Sjfb int i, j, l, t; 103108f90673Sjfb 103208f90673Sjfb if (clist[c[k]].y < y) /* quick look for typical case */ 103308f90673Sjfb return (k + 1); 103408f90673Sjfb i = 0; 103508f90673Sjfb j = k + 1; 103608f90673Sjfb while (1) { 103708f90673Sjfb l = i + j; 103808f90673Sjfb if ((l >>= 1) <= i) 103908f90673Sjfb break; 104008f90673Sjfb t = clist[c[l]].y; 104108f90673Sjfb if (t > y) 104208f90673Sjfb j = l; 104308f90673Sjfb else if (t < y) 104408f90673Sjfb i = l; 104508f90673Sjfb else 104608f90673Sjfb return (l); 104708f90673Sjfb } 104808f90673Sjfb return (l + 1); 104908f90673Sjfb } 105008f90673Sjfb 105108f90673Sjfb static void 105208f90673Sjfb unravel(int p) 105308f90673Sjfb { 105408f90673Sjfb struct cand *q; 105508f90673Sjfb int i; 105608f90673Sjfb 1057e4276007Sjfb for (i = 0; i <= diff_len[0]; i++) 105808f90673Sjfb J[i] = i <= pref ? i : 1059e4276007Sjfb i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 106008f90673Sjfb for (q = clist + p; q->y != 0; q = clist + q->pred) 106108f90673Sjfb J[q->x + pref] = q->y + pref; 106208f90673Sjfb } 106308f90673Sjfb 106408f90673Sjfb /* 106508f90673Sjfb * Check does double duty: 106608f90673Sjfb * 1. ferret out any fortuitous correspondences due 106708f90673Sjfb * to confounding by hashing (which result in "jackpot") 106808f90673Sjfb * 2. collect random access indexes to the two files 106908f90673Sjfb */ 107008f90673Sjfb static void 107108f90673Sjfb check(FILE *f1, FILE *f2) 107208f90673Sjfb { 107308f90673Sjfb int i, j, jackpot, c, d; 107408f90673Sjfb long ctold, ctnew; 107508f90673Sjfb 107608f90673Sjfb rewind(f1); 107708f90673Sjfb rewind(f2); 107808f90673Sjfb j = 1; 107908f90673Sjfb ixold[0] = ixnew[0] = 0; 108008f90673Sjfb jackpot = 0; 108108f90673Sjfb ctold = ctnew = 0; 1082e4276007Sjfb for (i = 1; i <= diff_len[0]; i++) { 108308f90673Sjfb if (J[i] == 0) { 108408f90673Sjfb ixold[i] = ctold += skipline(f1); 108508f90673Sjfb continue; 108608f90673Sjfb } 108708f90673Sjfb while (j < J[i]) { 108808f90673Sjfb ixnew[j] = ctnew += skipline(f2); 108908f90673Sjfb j++; 109008f90673Sjfb } 109148dc77e6Sxsa if ((bflag == 1)|| (wflag == 1) || (iflag == 1)) { 109208f90673Sjfb for (;;) { 109308f90673Sjfb c = getc(f1); 109408f90673Sjfb d = getc(f2); 109508f90673Sjfb /* 109608f90673Sjfb * GNU diff ignores a missing newline 109708f90673Sjfb * in one file if bflag || wflag. 109808f90673Sjfb */ 109948dc77e6Sxsa if (((bflag == 1) || (wflag == 1)) && 110008f90673Sjfb ((c == EOF && d == '\n') || 110108f90673Sjfb (c == '\n' && d == EOF))) { 110208f90673Sjfb break; 110308f90673Sjfb } 110408f90673Sjfb ctold++; 110508f90673Sjfb ctnew++; 110648dc77e6Sxsa if ((bflag == 1) && isspace(c) && isspace(d)) { 110708f90673Sjfb do { 110808f90673Sjfb if (c == '\n') 110908f90673Sjfb break; 111008f90673Sjfb ctold++; 111108f90673Sjfb } while (isspace(c = getc(f1))); 111208f90673Sjfb do { 111308f90673Sjfb if (d == '\n') 111408f90673Sjfb break; 111508f90673Sjfb ctnew++; 111608f90673Sjfb } while (isspace(d = getc(f2))); 111748dc77e6Sxsa } else if (wflag == 1) { 111808f90673Sjfb while (isspace(c) && c != '\n') { 111908f90673Sjfb c = getc(f1); 112008f90673Sjfb ctold++; 112108f90673Sjfb } 112208f90673Sjfb while (isspace(d) && d != '\n') { 112308f90673Sjfb d = getc(f2); 112408f90673Sjfb ctnew++; 112508f90673Sjfb } 112608f90673Sjfb } 112708f90673Sjfb if (chrtran[c] != chrtran[d]) { 112808f90673Sjfb jackpot++; 112908f90673Sjfb J[i] = 0; 113037af5b8bSxsa if ((c != '\n') && (c != EOF)) 113108f90673Sjfb ctold += skipline(f1); 113237af5b8bSxsa if ((d != '\n') && (c != EOF)) 113308f90673Sjfb ctnew += skipline(f2); 113408f90673Sjfb break; 113508f90673Sjfb } 113637af5b8bSxsa if ((c == '\n') || (c == EOF)) 113708f90673Sjfb break; 113808f90673Sjfb } 113908f90673Sjfb } else { 114008f90673Sjfb for (;;) { 114108f90673Sjfb ctold++; 114208f90673Sjfb ctnew++; 114308f90673Sjfb if ((c = getc(f1)) != (d = getc(f2))) { 114408f90673Sjfb /* jackpot++; */ 114508f90673Sjfb J[i] = 0; 114637af5b8bSxsa if ((c != '\n') && (c != EOF)) 114708f90673Sjfb ctold += skipline(f1); 114837af5b8bSxsa if ((d != '\n') && (c != EOF)) 114908f90673Sjfb ctnew += skipline(f2); 115008f90673Sjfb break; 115108f90673Sjfb } 115237af5b8bSxsa if ((c == '\n') || (c == EOF)) 115308f90673Sjfb break; 115408f90673Sjfb } 115508f90673Sjfb } 115608f90673Sjfb ixold[i] = ctold; 115708f90673Sjfb ixnew[j] = ctnew; 115808f90673Sjfb j++; 115908f90673Sjfb } 1160e4276007Sjfb for (; j <= diff_len[1]; j++) 116108f90673Sjfb ixnew[j] = ctnew += skipline(f2); 116208f90673Sjfb /* 116337af5b8bSxsa * if (jackpot != 0) 11645ac8b1e7Sjoris * cvs_printf("jackpot\n"); 116508f90673Sjfb */ 116608f90673Sjfb } 116708f90673Sjfb 116808f90673Sjfb /* shellsort CACM #201 */ 116908f90673Sjfb static void 117008f90673Sjfb sort(struct line *a, int n) 117108f90673Sjfb { 117208f90673Sjfb struct line *ai, *aim, w; 117308f90673Sjfb int j, m = 0, k; 117408f90673Sjfb 117508f90673Sjfb if (n == 0) 117608f90673Sjfb return; 117708f90673Sjfb for (j = 1; j <= n; j *= 2) 117808f90673Sjfb m = 2 * j - 1; 117908f90673Sjfb for (m /= 2; m != 0; m /= 2) { 118008f90673Sjfb k = n - m; 118108f90673Sjfb for (j = 1; j <= k; j++) { 118208f90673Sjfb for (ai = &a[j]; ai > a; ai -= m) { 118308f90673Sjfb aim = &ai[m]; 118408f90673Sjfb if (aim < ai) 118508f90673Sjfb break; /* wraparound */ 118608f90673Sjfb if (aim->value > ai[0].value || 118708f90673Sjfb (aim->value == ai[0].value && 118808f90673Sjfb aim->serial > ai[0].serial)) 118908f90673Sjfb break; 119008f90673Sjfb w.value = ai[0].value; 119108f90673Sjfb ai[0].value = aim->value; 119208f90673Sjfb aim->value = w.value; 119308f90673Sjfb w.serial = ai[0].serial; 119408f90673Sjfb ai[0].serial = aim->serial; 119508f90673Sjfb aim->serial = w.serial; 119608f90673Sjfb } 119708f90673Sjfb } 119808f90673Sjfb } 119908f90673Sjfb } 120008f90673Sjfb 120108f90673Sjfb static void 120208f90673Sjfb unsort(struct line *f, int l, int *b) 120308f90673Sjfb { 120408f90673Sjfb int *a, i; 120508f90673Sjfb 12067f535ec4Sjfb if ((a = (int *)malloc((l + 1) * sizeof(int))) == NULL) { 12077f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate sort array"); 12087f535ec4Sjfb return; 12097f535ec4Sjfb } 121008f90673Sjfb for (i = 1; i <= l; i++) 121108f90673Sjfb a[f[i].serial] = f[i].value; 121208f90673Sjfb for (i = 1; i <= l; i++) 121308f90673Sjfb b[i] = a[i]; 121408f90673Sjfb free(a); 121508f90673Sjfb } 121608f90673Sjfb 121708f90673Sjfb static int 121808f90673Sjfb skipline(FILE *f) 121908f90673Sjfb { 122008f90673Sjfb int i, c; 122108f90673Sjfb 122208f90673Sjfb for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 122308f90673Sjfb continue; 122408f90673Sjfb return (i); 122508f90673Sjfb } 122608f90673Sjfb 122708f90673Sjfb static void 122808f90673Sjfb output(const char *file1, FILE *f1, const char *file2, FILE *f2) 122908f90673Sjfb { 123008f90673Sjfb int m, i0, i1, j0, j1; 123108f90673Sjfb 123208f90673Sjfb rewind(f1); 123308f90673Sjfb rewind(f2); 1234e4276007Sjfb m = diff_len[0]; 123508f90673Sjfb J[0] = 0; 1236e4276007Sjfb J[m + 1] = diff_len[1] + 1; 123708f90673Sjfb for (i0 = 1; i0 <= m; i0 = i1 + 1) { 123808f90673Sjfb while (i0 <= m && J[i0] == J[i0 - 1] + 1) 123908f90673Sjfb i0++; 124008f90673Sjfb j0 = J[i0 - 1] + 1; 124108f90673Sjfb i1 = i0 - 1; 124208f90673Sjfb while (i1 < m && J[i1 + 1] == 0) 124308f90673Sjfb i1++; 124408f90673Sjfb j1 = J[i1 + 1] - 1; 124508f90673Sjfb J[i1] = j1; 124608f90673Sjfb change(file1, f1, file2, f2, i0, i1, j0, j1); 124708f90673Sjfb } 124808f90673Sjfb if (m == 0) 1249e4276007Sjfb change(file1, f1, file2, f2, 1, 0, 1, diff_len[1]); 1250f9b67873Sniallo if (diff_format == D_IFDEF) { 125108f90673Sjfb for (;;) { 125208f90673Sjfb #define c i0 125308f90673Sjfb if ((c = getc(f1)) == EOF) 125408f90673Sjfb return; 1255f9b67873Sniallo diff_output("%c", c); 125608f90673Sjfb } 125708f90673Sjfb #undef c 125808f90673Sjfb } 125908f90673Sjfb if (anychange != 0) { 1260f9b67873Sniallo if (diff_format == D_CONTEXT) 126108f90673Sjfb dump_context_vec(f1, f2); 1262f9b67873Sniallo else if (diff_format == D_UNIFIED) 126308f90673Sjfb dump_unified_vec(f1, f2); 126408f90673Sjfb } 126508f90673Sjfb } 126608f90673Sjfb 126708f90673Sjfb static __inline void 126808f90673Sjfb range(int a, int b, char *separator) 126908f90673Sjfb { 1270f9b67873Sniallo diff_output("%d", a > b ? b : a); 127108f90673Sjfb if (a < b) 1272f9b67873Sniallo diff_output("%s%d", separator, b); 127308f90673Sjfb } 127408f90673Sjfb 127508f90673Sjfb static __inline void 127608f90673Sjfb uni_range(int a, int b) 127708f90673Sjfb { 127808f90673Sjfb if (a < b) 1279f9b67873Sniallo diff_output("%d,%d", a, b - a + 1); 128008f90673Sjfb else if (a == b) 1281f9b67873Sniallo diff_output("%d", b); 128208f90673Sjfb else 1283f9b67873Sniallo diff_output("%d,0", b); 128408f90673Sjfb } 128508f90673Sjfb 128608f90673Sjfb static char * 12872a0de57dSjfb preadline(int fd, size_t rlen, off_t off) 128808f90673Sjfb { 128908f90673Sjfb char *line; 129008f90673Sjfb ssize_t nr; 129108f90673Sjfb 12922a0de57dSjfb line = malloc(rlen + 1); 129308f90673Sjfb if (line == NULL) { 129408f90673Sjfb cvs_log(LP_ERRNO, "failed to allocate line"); 129508f90673Sjfb return (NULL); 129608f90673Sjfb } 12972a0de57dSjfb if ((nr = pread(fd, line, rlen, off)) < 0) { 129808f90673Sjfb cvs_log(LP_ERRNO, "preadline failed"); 129908f90673Sjfb return (NULL); 130008f90673Sjfb } 130108f90673Sjfb line[nr] = '\0'; 130208f90673Sjfb return (line); 130308f90673Sjfb } 130408f90673Sjfb 130508f90673Sjfb static int 130608f90673Sjfb ignoreline(char *line) 130708f90673Sjfb { 130808f90673Sjfb int ret; 130908f90673Sjfb 1310f1901a5aSxsa ret = regexec(&ignore_re, line, (size_t)0, NULL, 0); 131108f90673Sjfb free(line); 131208f90673Sjfb return (ret == 0); /* if it matched, it should be ignored. */ 131308f90673Sjfb } 131408f90673Sjfb 131508f90673Sjfb /* 131608f90673Sjfb * Indicate that there is a difference between lines a and b of the from file 131708f90673Sjfb * to get to lines c to d of the to file. If a is greater then b then there 131808f90673Sjfb * are no lines in the from file involved and this means that there were 131908f90673Sjfb * lines appended (beginning at b). If c is greater than d then there are 132008f90673Sjfb * lines missing from the to file. 132108f90673Sjfb */ 132208f90673Sjfb static void 132308f90673Sjfb change(const char *file1, FILE *f1, const char *file2, FILE *f2, 132408f90673Sjfb int a, int b, int c, int d) 132508f90673Sjfb { 132608f90673Sjfb static size_t max_context = 64; 132708f90673Sjfb int i; 132808f90673Sjfb 1329f9b67873Sniallo if (diff_format != D_IFDEF && a > b && c > d) 133008f90673Sjfb return; 133108f90673Sjfb if (ignore_pats != NULL) { 133208f90673Sjfb char *line; 133308f90673Sjfb /* 133408f90673Sjfb * All lines in the change, insert, or delete must 133508f90673Sjfb * match an ignore pattern for the change to be 133608f90673Sjfb * ignored. 133708f90673Sjfb */ 133808f90673Sjfb if (a <= b) { /* Changes and deletes. */ 133908f90673Sjfb for (i = a; i <= b; i++) { 134008f90673Sjfb line = preadline(fileno(f1), 134108f90673Sjfb ixold[i] - ixold[i - 1], ixold[i - 1]); 134208f90673Sjfb if (!ignoreline(line)) 134308f90673Sjfb goto proceed; 134408f90673Sjfb } 134508f90673Sjfb } 134637af5b8bSxsa if ((a > b) || (c <= d)) { /* Changes and inserts. */ 134708f90673Sjfb for (i = c; i <= d; i++) { 134808f90673Sjfb line = preadline(fileno(f2), 134908f90673Sjfb ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 135008f90673Sjfb if (!ignoreline(line)) 135108f90673Sjfb goto proceed; 135208f90673Sjfb } 135308f90673Sjfb } 135408f90673Sjfb return; 135508f90673Sjfb } 135608f90673Sjfb proceed: 1357f9b67873Sniallo if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 135808f90673Sjfb /* 135908f90673Sjfb * Allocate change records as needed. 136008f90673Sjfb */ 136108f90673Sjfb if (context_vec_ptr == context_vec_end - 1) { 136218501190Sniallo struct context_vec *tmp; 136308f90673Sjfb ptrdiff_t offset = context_vec_ptr - context_vec_start; 136408f90673Sjfb max_context <<= 1; 13654c06e5f6Sreyk if ((tmp = realloc(context_vec_start, max_context * 13664c06e5f6Sreyk sizeof(struct context_vec))) == NULL) { 136718501190Sniallo free(context_vec_start); 136818501190Sniallo context_vec_start = NULL; 136918501190Sniallo cvs_log(LP_ERRNO, 137018501190Sniallo "failed to resize context_vec_start"); 137118501190Sniallo return; 137218501190Sniallo } 137318501190Sniallo context_vec_start = tmp; 137408f90673Sjfb context_vec_end = context_vec_start + max_context; 137508f90673Sjfb context_vec_ptr = context_vec_start + offset; 137608f90673Sjfb } 137708f90673Sjfb if (anychange == 0) { 137808f90673Sjfb /* 137908f90673Sjfb * Print the context/unidiff header first time through. 138008f90673Sjfb */ 1381f9b67873Sniallo diff_output("%s %s %s", 1382f9b67873Sniallo diff_format == D_CONTEXT ? "***" : "---", diff_file, 138308f90673Sjfb ctime(&stb1.st_mtime)); 1384f9b67873Sniallo diff_output("%s %s %s", 1385f9b67873Sniallo diff_format == D_CONTEXT ? "---" : "+++", diff_file, 138608f90673Sjfb ctime(&stb2.st_mtime)); 138708f90673Sjfb anychange = 1; 138808f90673Sjfb } else if (a > context_vec_ptr->b + (2 * context) + 1 && 138908f90673Sjfb c > context_vec_ptr->d + (2 * context) + 1) { 139008f90673Sjfb /* 139108f90673Sjfb * If this change is more than 'context' lines from the 139208f90673Sjfb * previous change, dump the record and reset it. 139308f90673Sjfb */ 1394f9b67873Sniallo if (diff_format == D_CONTEXT) 139508f90673Sjfb dump_context_vec(f1, f2); 139608f90673Sjfb else 139708f90673Sjfb dump_unified_vec(f1, f2); 139808f90673Sjfb } 139908f90673Sjfb context_vec_ptr++; 140008f90673Sjfb context_vec_ptr->a = a; 140108f90673Sjfb context_vec_ptr->b = b; 140208f90673Sjfb context_vec_ptr->c = c; 140308f90673Sjfb context_vec_ptr->d = d; 140408f90673Sjfb return; 140508f90673Sjfb } 140608f90673Sjfb if (anychange == 0) 140708f90673Sjfb anychange = 1; 1408f9b67873Sniallo switch (diff_format) { 140908f90673Sjfb case D_BRIEF: 141008f90673Sjfb return; 141108f90673Sjfb case D_NORMAL: 141208f90673Sjfb range(a, b, ","); 1413f9b67873Sniallo diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 1414f9b67873Sniallo if (diff_format == D_NORMAL) 141508f90673Sjfb range(c, d, ","); 1416f9b67873Sniallo diff_output("\n"); 141708f90673Sjfb break; 1418394180a4Sjfb case D_RCSDIFF: 1419394180a4Sjfb if (a > b) 1420f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1421394180a4Sjfb else { 1422f9b67873Sniallo diff_output("d%d %d\n", a, b - a + 1); 1423394180a4Sjfb 1424394180a4Sjfb if (!(c > d)) /* add changed lines */ 1425f9b67873Sniallo diff_output("a%d %d\n", b, d - c + 1); 1426394180a4Sjfb } 1427394180a4Sjfb break; 142808f90673Sjfb } 1429f9b67873Sniallo if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 143008f90673Sjfb fetch(ixold, a, b, f1, '<', 1); 1431f9b67873Sniallo if (a <= b && c <= d && diff_format == D_NORMAL) 1432206543eeSjoris diff_output("---\n"); 143308f90673Sjfb } 1434f9b67873Sniallo i = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0); 143508f90673Sjfb if (inifdef) { 1436f9b67873Sniallo diff_output("#endif /* %s */\n", ifdefname); 143708f90673Sjfb inifdef = 0; 143808f90673Sjfb } 143908f90673Sjfb } 144008f90673Sjfb 144108f90673Sjfb static int 144208f90673Sjfb fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 144308f90673Sjfb { 144408f90673Sjfb int i, j, c, lastc, col, nc; 144508f90673Sjfb 144608f90673Sjfb /* 144708f90673Sjfb * When doing #ifdef's, copy down to current line 144808f90673Sjfb * if this is the first file, so that stuff makes it to output. 144908f90673Sjfb */ 1450f9b67873Sniallo if (diff_format == D_IFDEF && oldfile) { 145108f90673Sjfb long curpos = ftell(lb); 145208f90673Sjfb /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 145308f90673Sjfb nc = f[a > b ? b : a - 1] - curpos; 145408f90673Sjfb for (i = 0; i < nc; i++) 1455f9b67873Sniallo diff_output("%c", getc(lb)); 145608f90673Sjfb } 145708f90673Sjfb if (a > b) 145808f90673Sjfb return (0); 1459f9b67873Sniallo if (diff_format == D_IFDEF) { 146008f90673Sjfb if (inifdef) { 1461f9b67873Sniallo diff_output("#else /* %s%s */\n", 146208f90673Sjfb oldfile == 1 ? "!" : "", ifdefname); 146308f90673Sjfb } else { 146408f90673Sjfb if (oldfile) 1465f9b67873Sniallo diff_output("#ifndef %s\n", ifdefname); 146608f90673Sjfb else 1467f9b67873Sniallo diff_output("#ifdef %s\n", ifdefname); 146808f90673Sjfb } 146908f90673Sjfb inifdef = 1 + oldfile; 147008f90673Sjfb } 147108f90673Sjfb for (i = a; i <= b; i++) { 147208f90673Sjfb fseek(lb, f[i - 1], SEEK_SET); 147308f90673Sjfb nc = f[i] - f[i - 1]; 1474f9b67873Sniallo if (diff_format != D_IFDEF && ch != '\0') { 1475f9b67873Sniallo diff_output("%c", ch); 147648dc77e6Sxsa if ((Tflag == 1 ) && (diff_format == D_NORMAL || 14779c5161e4Sjoris diff_format == D_CONTEXT || 14789c5161e4Sjoris diff_format == D_UNIFIED)) 1479f9b67873Sniallo diff_output("\t"); 1480f9b67873Sniallo else if (diff_format != D_UNIFIED) 1481f9b67873Sniallo diff_output(" "); 148208f90673Sjfb } 148308f90673Sjfb col = 0; 148408f90673Sjfb for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { 148508f90673Sjfb if ((c = getc(lb)) == EOF) { 1486f9b67873Sniallo if (diff_format == D_RCSDIFF) 1487394180a4Sjfb warnx("No newline at end of file"); 1488394180a4Sjfb else 14899c5161e4Sjoris diff_output("\n\\ No newline at end of " 14909c5161e4Sjoris "file"); 149108f90673Sjfb return (0); 149208f90673Sjfb } 149348dc77e6Sxsa if ((c == '\t') && (tflag == 1)) { 149408f90673Sjfb do { 1495f9b67873Sniallo diff_output(" "); 149608f90673Sjfb } while (++col & 7); 149708f90673Sjfb } else { 1498f9b67873Sniallo diff_output("%c", c); 149908f90673Sjfb col++; 150008f90673Sjfb } 150108f90673Sjfb } 150208f90673Sjfb } 150308f90673Sjfb return (0); 150408f90673Sjfb } 150508f90673Sjfb 150608f90673Sjfb /* 150708f90673Sjfb * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 150808f90673Sjfb */ 150908f90673Sjfb static int 151008f90673Sjfb readhash(FILE *f) 151108f90673Sjfb { 151208f90673Sjfb int i, t, space; 151308f90673Sjfb int sum; 151408f90673Sjfb 151508f90673Sjfb sum = 1; 151608f90673Sjfb space = 0; 151748dc77e6Sxsa if ((bflag != 1) && (wflag != 1)) { 151848dc77e6Sxsa if (iflag == 1) 151908f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 152008f90673Sjfb if (t == EOF) { 152108f90673Sjfb if (i == 0) 152208f90673Sjfb return (0); 152308f90673Sjfb break; 152408f90673Sjfb } 152508f90673Sjfb sum = sum * 127 + chrtran[t]; 152608f90673Sjfb } 152708f90673Sjfb else 152808f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 152908f90673Sjfb if (t == EOF) { 153008f90673Sjfb if (i == 0) 153108f90673Sjfb return (0); 153208f90673Sjfb break; 153308f90673Sjfb } 153408f90673Sjfb sum = sum * 127 + t; 153508f90673Sjfb } 153608f90673Sjfb } else { 153708f90673Sjfb for (i = 0;;) { 153808f90673Sjfb switch (t = getc(f)) { 153908f90673Sjfb case '\t': 154008f90673Sjfb case ' ': 154108f90673Sjfb space++; 154208f90673Sjfb continue; 154308f90673Sjfb default: 154448dc77e6Sxsa if ((space != 0) && (wflag != 1)) { 154508f90673Sjfb i++; 154608f90673Sjfb space = 0; 154708f90673Sjfb } 154808f90673Sjfb sum = sum * 127 + chrtran[t]; 154908f90673Sjfb i++; 155008f90673Sjfb continue; 155108f90673Sjfb case EOF: 155208f90673Sjfb if (i == 0) 155308f90673Sjfb return (0); 155408f90673Sjfb /* FALLTHROUGH */ 155508f90673Sjfb case '\n': 155608f90673Sjfb break; 155708f90673Sjfb } 155808f90673Sjfb break; 155908f90673Sjfb } 156008f90673Sjfb } 156108f90673Sjfb /* 156208f90673Sjfb * There is a remote possibility that we end up with a zero sum. 156308f90673Sjfb * Zero is used as an EOF marker, so return 1 instead. 156408f90673Sjfb */ 156508f90673Sjfb return (sum == 0 ? 1 : sum); 156608f90673Sjfb } 156708f90673Sjfb 156808f90673Sjfb static int 156908f90673Sjfb asciifile(FILE *f) 157008f90673Sjfb { 157108f90673Sjfb char buf[BUFSIZ]; 157208f90673Sjfb int i, cnt; 157308f90673Sjfb 157448dc77e6Sxsa if ((aflag == 1) || (f == NULL)) 157508f90673Sjfb return (1); 157608f90673Sjfb 157708f90673Sjfb rewind(f); 1578f1901a5aSxsa cnt = fread(buf, (size_t)1, sizeof(buf), f); 157908f90673Sjfb for (i = 0; i < cnt; i++) 158008f90673Sjfb if (!isprint(buf[i]) && !isspace(buf[i])) 158108f90673Sjfb return (0); 158208f90673Sjfb return (1); 158308f90673Sjfb } 158408f90673Sjfb 15855e78344dSjfb static char* 15865e78344dSjfb match_function(const long *f, int pos, FILE *fp) 15875e78344dSjfb { 15885e78344dSjfb unsigned char buf[FUNCTION_CONTEXT_SIZE]; 15895e78344dSjfb size_t nc; 15905e78344dSjfb int last = lastline; 15915e78344dSjfb char *p; 15925e78344dSjfb 15935e78344dSjfb lastline = pos; 15945e78344dSjfb while (pos > last) { 15955e78344dSjfb fseek(fp, f[pos - 1], SEEK_SET); 15965e78344dSjfb nc = f[pos] - f[pos - 1]; 15975e78344dSjfb if (nc >= sizeof(buf)) 15985e78344dSjfb nc = sizeof(buf) - 1; 1599f1901a5aSxsa nc = fread(buf, (size_t)1, nc, fp); 16005e78344dSjfb if (nc > 0) { 16015e78344dSjfb buf[nc] = '\0'; 1602634926d6Sniallo p = strchr((const char *)buf, '\n'); 16035e78344dSjfb if (p != NULL) 16045e78344dSjfb *p = '\0'; 16055e78344dSjfb if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 16064c06e5f6Sreyk strlcpy(lastbuf, (const char *)buf, 16074c06e5f6Sreyk sizeof lastbuf); 16085e78344dSjfb lastmatchline = pos; 16095e78344dSjfb return lastbuf; 16105e78344dSjfb } 16115e78344dSjfb } 16125e78344dSjfb pos--; 16135e78344dSjfb } 16145e78344dSjfb return (lastmatchline > 0) ? lastbuf : NULL; 16155e78344dSjfb } 16165e78344dSjfb 161708f90673Sjfb 161808f90673Sjfb /* dump accumulated "context" diff changes */ 161908f90673Sjfb static void 162008f90673Sjfb dump_context_vec(FILE *f1, FILE *f2) 162108f90673Sjfb { 162208f90673Sjfb struct context_vec *cvp = context_vec_start; 162308f90673Sjfb int lowa, upb, lowc, upd, do_output; 162408f90673Sjfb int a, b, c, d; 16255e78344dSjfb char ch, *f; 162608f90673Sjfb 162708f90673Sjfb if (context_vec_start > context_vec_ptr) 162808f90673Sjfb return; 162908f90673Sjfb 163008f90673Sjfb b = d = 0; /* gcc */ 1631dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1632e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1633dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1634e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 163508f90673Sjfb 1636f9b67873Sniallo diff_output("***************"); 163748dc77e6Sxsa if (pflag == 1) { 16385e78344dSjfb f = match_function(ixold, lowa - 1, f1); 16395e78344dSjfb if (f != NULL) { 1640f9b67873Sniallo diff_output(" "); 1641f9b67873Sniallo diff_output("%s", f); 16425e78344dSjfb } 16435e78344dSjfb } 1644f9b67873Sniallo diff_output("\n*** "); 164508f90673Sjfb range(lowa, upb, ","); 1646f9b67873Sniallo diff_output(" ****\n"); 164708f90673Sjfb 164808f90673Sjfb /* 164908f90673Sjfb * Output changes to the "old" file. The first loop suppresses 165008f90673Sjfb * output if there were no changes to the "old" file (we'll see 165108f90673Sjfb * the "old" lines as context in the "new" list). 165208f90673Sjfb */ 165308f90673Sjfb do_output = 0; 165408f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) 165508f90673Sjfb if (cvp->a <= cvp->b) { 165608f90673Sjfb cvp = context_vec_start; 165708f90673Sjfb do_output++; 165808f90673Sjfb break; 165908f90673Sjfb } 166037af5b8bSxsa if (do_output != 0) { 166108f90673Sjfb while (cvp <= context_vec_ptr) { 166208f90673Sjfb a = cvp->a; 166308f90673Sjfb b = cvp->b; 166408f90673Sjfb c = cvp->c; 166508f90673Sjfb d = cvp->d; 166608f90673Sjfb 166708f90673Sjfb if (a <= b && c <= d) 166808f90673Sjfb ch = 'c'; 166908f90673Sjfb else 167008f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 167108f90673Sjfb 167208f90673Sjfb if (ch == 'a') 167308f90673Sjfb fetch(ixold, lowa, b, f1, ' ', 0); 167408f90673Sjfb else { 167508f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 167608f90673Sjfb fetch(ixold, a, b, f1, 167708f90673Sjfb ch == 'c' ? '!' : '-', 0); 167808f90673Sjfb } 167908f90673Sjfb lowa = b + 1; 168008f90673Sjfb cvp++; 168108f90673Sjfb } 168208f90673Sjfb fetch(ixold, b + 1, upb, f1, ' ', 0); 168308f90673Sjfb } 168408f90673Sjfb /* output changes to the "new" file */ 1685f9b67873Sniallo diff_output("--- "); 168608f90673Sjfb range(lowc, upd, ","); 1687f9b67873Sniallo diff_output(" ----\n"); 168808f90673Sjfb 168908f90673Sjfb do_output = 0; 169008f90673Sjfb for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 169108f90673Sjfb if (cvp->c <= cvp->d) { 169208f90673Sjfb cvp = context_vec_start; 169308f90673Sjfb do_output++; 169408f90673Sjfb break; 169508f90673Sjfb } 169637af5b8bSxsa if (do_output != 0) { 169708f90673Sjfb while (cvp <= context_vec_ptr) { 169808f90673Sjfb a = cvp->a; 169908f90673Sjfb b = cvp->b; 170008f90673Sjfb c = cvp->c; 170108f90673Sjfb d = cvp->d; 170208f90673Sjfb 170308f90673Sjfb if (a <= b && c <= d) 170408f90673Sjfb ch = 'c'; 170508f90673Sjfb else 170608f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 170708f90673Sjfb 170808f90673Sjfb if (ch == 'd') 170908f90673Sjfb fetch(ixnew, lowc, d, f2, ' ', 0); 171008f90673Sjfb else { 171108f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 171208f90673Sjfb fetch(ixnew, c, d, f2, 171308f90673Sjfb ch == 'c' ? '!' : '+', 0); 171408f90673Sjfb } 171508f90673Sjfb lowc = d + 1; 171608f90673Sjfb cvp++; 171708f90673Sjfb } 171808f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 171908f90673Sjfb } 172008f90673Sjfb context_vec_ptr = context_vec_start - 1; 172108f90673Sjfb } 172208f90673Sjfb 172308f90673Sjfb /* dump accumulated "unified" diff changes */ 172408f90673Sjfb static void 172508f90673Sjfb dump_unified_vec(FILE *f1, FILE *f2) 172608f90673Sjfb { 172708f90673Sjfb struct context_vec *cvp = context_vec_start; 172808f90673Sjfb int lowa, upb, lowc, upd; 172908f90673Sjfb int a, b, c, d; 17305e78344dSjfb char ch, *f; 173108f90673Sjfb 173208f90673Sjfb if (context_vec_start > context_vec_ptr) 173308f90673Sjfb return; 173408f90673Sjfb 173508f90673Sjfb b = d = 0; /* gcc */ 1736dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1737e4276007Sjfb upb = MIN(diff_len[0], context_vec_ptr->b + context); 1738dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1739e4276007Sjfb upd = MIN(diff_len[1], context_vec_ptr->d + context); 174008f90673Sjfb 1741f9b67873Sniallo diff_output("@@ -"); 174208f90673Sjfb uni_range(lowa, upb); 1743f9b67873Sniallo diff_output(" +"); 174408f90673Sjfb uni_range(lowc, upd); 1745f9b67873Sniallo diff_output(" @@"); 174648dc77e6Sxsa if (pflag == 1) { 17475e78344dSjfb f = match_function(ixold, lowa - 1, f1); 17485e78344dSjfb if (f != NULL) { 1749f9b67873Sniallo diff_output(" "); 1750f9b67873Sniallo diff_output("%s", f); 17515e78344dSjfb } 17525e78344dSjfb } 1753f9b67873Sniallo diff_output("\n"); 175408f90673Sjfb 175508f90673Sjfb /* 175608f90673Sjfb * Output changes in "unified" diff format--the old and new lines 175708f90673Sjfb * are printed together. 175808f90673Sjfb */ 175908f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) { 176008f90673Sjfb a = cvp->a; 176108f90673Sjfb b = cvp->b; 176208f90673Sjfb c = cvp->c; 176308f90673Sjfb d = cvp->d; 176408f90673Sjfb 176508f90673Sjfb /* 176608f90673Sjfb * c: both new and old changes 176708f90673Sjfb * d: only changes in the old file 176808f90673Sjfb * a: only changes in the new file 176908f90673Sjfb */ 177008f90673Sjfb if (a <= b && c <= d) 177108f90673Sjfb ch = 'c'; 177208f90673Sjfb else 177308f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 177408f90673Sjfb 177508f90673Sjfb switch (ch) { 177608f90673Sjfb case 'c': 177708f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 177808f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 177908f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 178008f90673Sjfb break; 178108f90673Sjfb case 'd': 178208f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 178308f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 178408f90673Sjfb break; 178508f90673Sjfb case 'a': 178608f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 178708f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 178808f90673Sjfb break; 178908f90673Sjfb } 179008f90673Sjfb lowa = b + 1; 179108f90673Sjfb lowc = d + 1; 179208f90673Sjfb } 179308f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 179408f90673Sjfb 179508f90673Sjfb context_vec_ptr = context_vec_start - 1; 179608f90673Sjfb } 1797f9b67873Sniallo 179801af718aSjoris void 1799f9b67873Sniallo diff_output(const char *fmt, ...) 1800f9b67873Sniallo { 1801f9b67873Sniallo va_list vap; 1802f9b67873Sniallo char *str; 1803f9b67873Sniallo 1804f9b67873Sniallo va_start(vap, fmt); 1805f9b67873Sniallo vasprintf(&str, fmt, vap); 1806f9b67873Sniallo if (diffbuf != NULL) 1807f9b67873Sniallo cvs_buf_append(diffbuf, str, strlen(str)); 1808f9b67873Sniallo else 1809f9b67873Sniallo cvs_printf("%s", str); 1810f9b67873Sniallo free(str); 1811f9b67873Sniallo va_end(vap); 1812f9b67873Sniallo } 1813