1*25b74b48Sjfb /* $OpenBSD: diff.c,v 1.21 2005/02/25 20:32:48 jfb 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/param.h> 13008f90673Sjfb #include <sys/stat.h> 13108f90673Sjfb #include <sys/wait.h> 13208f90673Sjfb 13308f90673Sjfb #include <errno.h> 13408f90673Sjfb #include <ctype.h> 13508f90673Sjfb #include <stdio.h> 13608f90673Sjfb #include <fcntl.h> 13708f90673Sjfb #include <paths.h> 13808f90673Sjfb #include <regex.h> 13908f90673Sjfb #include <dirent.h> 14008f90673Sjfb #include <stdlib.h> 14108f90673Sjfb #include <stddef.h> 14208f90673Sjfb #include <unistd.h> 14308f90673Sjfb #include <string.h> 14408f90673Sjfb #include <sysexits.h> 14508f90673Sjfb 14608f90673Sjfb #include "cvs.h" 14708f90673Sjfb #include "log.h" 14808f90673Sjfb #include "buf.h" 149dc6a6879Sjfb #include "proto.h" 15008f90673Sjfb 15108f90673Sjfb 15208f90673Sjfb #define CVS_DIFF_DEFCTX 3 /* default context length */ 15308f90673Sjfb 15408f90673Sjfb 15508f90673Sjfb /* 15608f90673Sjfb * Output format options 15708f90673Sjfb */ 15808f90673Sjfb #define D_NORMAL 0 /* Normal output */ 15908f90673Sjfb #define D_CONTEXT 1 /* Diff with context */ 16008f90673Sjfb #define D_UNIFIED 2 /* Unified context diff */ 16108f90673Sjfb #define D_IFDEF 3 /* Diff with merged #ifdef's */ 16208f90673Sjfb #define D_BRIEF 4 /* Say if the files differ */ 16308f90673Sjfb 16408f90673Sjfb /* 16508f90673Sjfb * Status values for print_status() and diffreg() return values 16608f90673Sjfb */ 16708f90673Sjfb #define D_SAME 0 /* Files are the same */ 16808f90673Sjfb #define D_DIFFER 1 /* Files are different */ 16908f90673Sjfb #define D_BINARY 2 /* Binary files are different */ 17008f90673Sjfb #define D_COMMON 3 /* Subdirectory common to both dirs */ 17108f90673Sjfb #define D_ONLY 4 /* Only exists in one directory */ 17208f90673Sjfb #define D_MISMATCH1 5 /* path1 was a dir, path2 a file */ 17308f90673Sjfb #define D_MISMATCH2 6 /* path1 was a file, path2 a dir */ 17408f90673Sjfb #define D_ERROR 7 /* An error occurred */ 17508f90673Sjfb #define D_SKIPPED1 8 /* path1 was a special file */ 17608f90673Sjfb #define D_SKIPPED2 9 /* path2 was a special file */ 17708f90673Sjfb 17808f90673Sjfb struct cand { 17908f90673Sjfb int x; 18008f90673Sjfb int y; 18108f90673Sjfb int pred; 18208f90673Sjfb } cand; 18308f90673Sjfb 18408f90673Sjfb struct line { 18508f90673Sjfb int serial; 18608f90673Sjfb int value; 18708f90673Sjfb } *file[2]; 18808f90673Sjfb 18908f90673Sjfb /* 19008f90673Sjfb * The following struct is used to record change information when 19108f90673Sjfb * doing a "context" or "unified" diff. (see routine "change" to 19208f90673Sjfb * understand the highly mnemonic field names) 19308f90673Sjfb */ 19408f90673Sjfb struct context_vec { 19508f90673Sjfb int a; /* start line in old file */ 19608f90673Sjfb int b; /* end line in old file */ 19708f90673Sjfb int c; /* start line in new file */ 19808f90673Sjfb int d; /* end line in new file */ 19908f90673Sjfb }; 20008f90673Sjfb 201dc6a6879Sjfb struct diff_arg { 202dc6a6879Sjfb char *rev1; 203dc6a6879Sjfb char *rev2; 204dc6a6879Sjfb char *date1; 205dc6a6879Sjfb char *date2; 206dc6a6879Sjfb }; 207dc6a6879Sjfb 20808f90673Sjfb 20908f90673Sjfb struct excludes { 21008f90673Sjfb char *pattern; 21108f90673Sjfb struct excludes *next; 21208f90673Sjfb }; 21308f90673Sjfb 21408f90673Sjfb 21508f90673Sjfb char *splice(char *, char *); 21608f90673Sjfb int cvs_diffreg(const char *, const char *); 217dc6a6879Sjfb int cvs_diff_file(struct cvs_file *, void *); 218cc811931Sjfb int cvs_diff_sendflags(struct cvsroot *, struct diff_arg *); 21908f90673Sjfb static void output(const char *, FILE *, const char *, FILE *); 22008f90673Sjfb static void check(FILE *, FILE *); 22108f90673Sjfb static void range(int, int, char *); 22208f90673Sjfb static void uni_range(int, int); 22308f90673Sjfb static void dump_context_vec(FILE *, FILE *); 22408f90673Sjfb static void dump_unified_vec(FILE *, FILE *); 2257f535ec4Sjfb static int prepare(int, FILE *, off_t); 22608f90673Sjfb static void prune(void); 22708f90673Sjfb static void equiv(struct line *, int, struct line *, int, int *); 22808f90673Sjfb static void unravel(int); 22908f90673Sjfb static void unsort(struct line *, int, int *); 23008f90673Sjfb static void change(const char *, FILE *, const char *, FILE *, int, int, int, int); 23108f90673Sjfb static void sort(struct line *, int); 23208f90673Sjfb static int ignoreline(char *); 23308f90673Sjfb static int asciifile(FILE *); 23408f90673Sjfb static int fetch(long *, int, int, FILE *, int, int); 23508f90673Sjfb static int newcand(int, int, int); 23608f90673Sjfb static int search(int *, int, int); 23708f90673Sjfb static int skipline(FILE *); 23808f90673Sjfb static int isqrt(int); 23908f90673Sjfb static int stone(int *, int, int *, int *); 24008f90673Sjfb static int readhash(FILE *); 24108f90673Sjfb static int files_differ(FILE *, FILE *); 2425e78344dSjfb static char *match_function(const long *, int, FILE *); 24308f90673Sjfb static char *preadline(int, size_t, off_t); 24408f90673Sjfb 24508f90673Sjfb 24608f90673Sjfb extern int cvs_client; 24708f90673Sjfb 2485e78344dSjfb static int aflag, bflag, dflag, iflag, Nflag, pflag, tflag, Tflag, wflag; 24908f90673Sjfb static int context, status; 25008f90673Sjfb static int format = D_NORMAL; 25108f90673Sjfb static struct stat stb1, stb2; 252f5638424Sjfb static char *ifdefname, *ignore_pats, diffargs[128]; 253f5638424Sjfb static const char *diff_file; 25408f90673Sjfb regex_t ignore_re; 25508f90673Sjfb 25608f90673Sjfb static int *J; /* will be overlaid on class */ 25708f90673Sjfb static int *class; /* will be overlaid on file[0] */ 25808f90673Sjfb static int *klist; /* will be overlaid on file[0] after class */ 25908f90673Sjfb static int *member; /* will be overlaid on file[1] */ 26008f90673Sjfb static int clen; 26108f90673Sjfb static int inifdef; /* whether or not we are in a #ifdef block */ 26208f90673Sjfb static int len[2]; 26308f90673Sjfb static int pref, suff; /* length of prefix and suffix */ 26408f90673Sjfb static int slen[2]; 26508f90673Sjfb static int anychange; 26608f90673Sjfb static long *ixnew; /* will be overlaid on file[1] */ 26708f90673Sjfb static long *ixold; /* will be overlaid on klist */ 26808f90673Sjfb static struct cand *clist; /* merely a free storage pot for candidates */ 26908f90673Sjfb static int clistlen; /* the length of clist */ 27008f90673Sjfb static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 27108f90673Sjfb static u_char *chrtran; /* translation table for case-folding */ 27208f90673Sjfb static struct context_vec *context_vec_start; 27308f90673Sjfb static struct context_vec *context_vec_end; 27408f90673Sjfb static struct context_vec *context_vec_ptr; 27508f90673Sjfb 27608f90673Sjfb #define FUNCTION_CONTEXT_SIZE 41 2775e78344dSjfb static char lastbuf[FUNCTION_CONTEXT_SIZE]; 27808f90673Sjfb static int lastline; 27908f90673Sjfb static int lastmatchline; 28008f90673Sjfb 28108f90673Sjfb 28208f90673Sjfb /* 28308f90673Sjfb * chrtran points to one of 2 translation tables: cup2low if folding upper to 28408f90673Sjfb * lower case clow2low if not folding case 28508f90673Sjfb */ 28608f90673Sjfb u_char clow2low[256] = { 28708f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 28808f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 28908f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 29008f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 29108f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 29208f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 29308f90673Sjfb 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 29408f90673Sjfb 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 29508f90673Sjfb 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 29608f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 29708f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 29808f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 29908f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 30008f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 30108f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 30208f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 30308f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 30408f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 30508f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 30608f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 30708f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 30808f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 30908f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 31008f90673Sjfb 0xfd, 0xfe, 0xff 31108f90673Sjfb }; 31208f90673Sjfb 31308f90673Sjfb u_char cup2low[256] = { 31408f90673Sjfb 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 31508f90673Sjfb 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 31608f90673Sjfb 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 31708f90673Sjfb 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 31808f90673Sjfb 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 31908f90673Sjfb 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 32008f90673Sjfb 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 32108f90673Sjfb 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 32208f90673Sjfb 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 32308f90673Sjfb 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 32408f90673Sjfb 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 32508f90673Sjfb 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 32608f90673Sjfb 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 32708f90673Sjfb 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 32808f90673Sjfb 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 32908f90673Sjfb 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 33008f90673Sjfb 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 33108f90673Sjfb 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 33208f90673Sjfb 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 33308f90673Sjfb 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 33408f90673Sjfb 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 33508f90673Sjfb 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 33608f90673Sjfb 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 33708f90673Sjfb 0xfd, 0xfe, 0xff 33808f90673Sjfb }; 33908f90673Sjfb 34008f90673Sjfb 34108f90673Sjfb /* 34208f90673Sjfb * cvs_diff() 34308f90673Sjfb * 34408f90673Sjfb * Handler for the `cvs diff' command. 34508f90673Sjfb * 34608f90673Sjfb * SYNOPSIS: cvs [args] diff [-clipu] [-D date] [-r rev] 34708f90673Sjfb */ 34808f90673Sjfb int 34908f90673Sjfb cvs_diff(int argc, char **argv) 35008f90673Sjfb { 351dc6a6879Sjfb int ch, recurse, flags; 352dc6a6879Sjfb struct diff_arg darg; 353dc6a6879Sjfb struct cvsroot *root; 35408f90673Sjfb 35508f90673Sjfb context = CVS_DIFF_DEFCTX; 356dc6a6879Sjfb flags = CF_RECURSE|CF_IGNORE|CF_SORT|CF_KNOWN; 35708f90673Sjfb recurse = 1; 35808f90673Sjfb 359dc6a6879Sjfb memset(&darg, 0, sizeof(darg)); 360dc6a6879Sjfb strlcpy(diffargs, argv[0], sizeof(diffargs)); 361dc6a6879Sjfb 3625e78344dSjfb while ((ch = getopt(argc, argv, "cD:liNpr:u")) != -1) { 36308f90673Sjfb switch (ch) { 36408f90673Sjfb case 'c': 365f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 36608f90673Sjfb format = D_CONTEXT; 36708f90673Sjfb break; 36808f90673Sjfb case 'D': 369dc6a6879Sjfb if (darg.date1 == NULL && darg.rev1 == NULL) 370dc6a6879Sjfb darg.date1 = optarg; 371dc6a6879Sjfb else if (darg.date2 == NULL && darg.rev2 == NULL) 372dc6a6879Sjfb darg.date2 = optarg; 37308f90673Sjfb else { 37408f90673Sjfb cvs_log(LP_ERR, 37508f90673Sjfb "no more than two revisions/dates can " 37608f90673Sjfb "be specified"); 37708f90673Sjfb } 37808f90673Sjfb break; 37908f90673Sjfb case 'l': 380f5638424Sjfb strlcat(diffargs, " -l", sizeof(diffargs)); 38108f90673Sjfb recurse = 0; 382dc6a6879Sjfb flags &= ~CF_RECURSE; 38308f90673Sjfb break; 38408f90673Sjfb case 'i': 385f5638424Sjfb strlcat(diffargs, " -i", sizeof(diffargs)); 38608f90673Sjfb iflag = 1; 38708f90673Sjfb break; 388c710bc5aSjfb case 'N': 389c710bc5aSjfb strlcat(diffargs, " -N", sizeof(diffargs)); 390c710bc5aSjfb Nflag = 1; 391c710bc5aSjfb break; 3925e78344dSjfb case 'p': 3935e78344dSjfb strlcat(diffargs, " -p", sizeof(diffargs)); 3945e78344dSjfb pflag = 1; 3955e78344dSjfb break; 39608f90673Sjfb case 'r': 397dc6a6879Sjfb if ((darg.rev1 == NULL) && (darg.date1 == NULL)) 398dc6a6879Sjfb darg.rev1 = optarg; 399dc6a6879Sjfb else if ((darg.rev2 == NULL) && (darg.date2 == NULL)) 400dc6a6879Sjfb darg.rev2 = optarg; 40108f90673Sjfb else { 40208f90673Sjfb cvs_log(LP_ERR, 40308f90673Sjfb "no more than two revisions/dates can " 40408f90673Sjfb "be specified"); 40508f90673Sjfb return (EX_USAGE); 40608f90673Sjfb } 40708f90673Sjfb break; 40808f90673Sjfb case 'u': 409f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 41008f90673Sjfb format = D_UNIFIED; 41108f90673Sjfb break; 41208f90673Sjfb default: 41308f90673Sjfb return (EX_USAGE); 41408f90673Sjfb } 41508f90673Sjfb } 41608f90673Sjfb 41708f90673Sjfb argc -= optind; 41808f90673Sjfb argv += optind; 41908f90673Sjfb 42008f90673Sjfb if (argc == 0) { 421b33893e8Sjfb cvs_files = cvs_file_get(".", flags); 4223917c9bfSderaadt } else 423b33893e8Sjfb cvs_files = cvs_file_getspec(argv, argc, 0); 424895e6cf6Sjfb if (cvs_files == NULL) 425895e6cf6Sjfb return (EX_DATAERR); 42608f90673Sjfb 427b33893e8Sjfb cvs_file_examine(cvs_files, cvs_diff_file, &darg); 42808f90673Sjfb 429b33893e8Sjfb root = cvs_files->cf_ddat->cd_root; 430dd2c5b0dSjfb if (root->cr_method != CVS_METHOD_LOCAL) { 431b33893e8Sjfb cvs_senddir(root, cvs_files); 432dc6a6879Sjfb cvs_sendreq(root, CVS_REQ_DIFF, NULL); 433dd2c5b0dSjfb } 43408f90673Sjfb 435dc6a6879Sjfb return (0); 436dc6a6879Sjfb } 437dc6a6879Sjfb 438dc6a6879Sjfb 439dc6a6879Sjfb /* 440dc6a6879Sjfb * cvs_diff_sendflags() 441dc6a6879Sjfb * 442dc6a6879Sjfb */ 443dc6a6879Sjfb int 444dc6a6879Sjfb cvs_diff_sendflags(struct cvsroot *root, struct diff_arg *dap) 445dc6a6879Sjfb { 44608f90673Sjfb /* send the flags */ 4475e78344dSjfb if (Nflag && (cvs_sendarg(root, "-N", 0) < 0)) 4485e78344dSjfb return (-1); 4495e78344dSjfb if (pflag && (cvs_sendarg(root, "-p", 0) < 0)) 4505e78344dSjfb return (-1); 4515e78344dSjfb 45208f90673Sjfb if (format == D_CONTEXT) 453dc6a6879Sjfb cvs_sendarg(root, "-c", 0); 45408f90673Sjfb else if (format == D_UNIFIED) 455dc6a6879Sjfb cvs_sendarg(root, "-u", 0); 45608f90673Sjfb 457dc6a6879Sjfb if (dap->rev1 != NULL) { 458dc6a6879Sjfb cvs_sendarg(root, "-r", 0); 45943579e5bSjfb cvs_sendarg(root, dap->rev1, 0); 4603917c9bfSderaadt } else if (dap->date1 != NULL) { 461dc6a6879Sjfb cvs_sendarg(root, "-D", 0); 46243579e5bSjfb cvs_sendarg(root, dap->date1, 0); 46308f90673Sjfb } 464dc6a6879Sjfb if (dap->rev2 != NULL) { 465dc6a6879Sjfb cvs_sendarg(root, "-r", 0); 46643579e5bSjfb cvs_sendarg(root, dap->rev2, 0); 4673917c9bfSderaadt } else if (dap->date2 != NULL) { 468dc6a6879Sjfb cvs_sendarg(root, "-D", 0); 46943579e5bSjfb cvs_sendarg(root, dap->date2, 0); 47008f90673Sjfb } 47108f90673Sjfb 47208f90673Sjfb return (0); 47308f90673Sjfb } 47408f90673Sjfb 47508f90673Sjfb 47608f90673Sjfb /* 47708f90673Sjfb * cvs_diff_file() 47808f90673Sjfb * 47908f90673Sjfb * Diff a single file. 48008f90673Sjfb */ 48108f90673Sjfb int 482dc6a6879Sjfb cvs_diff_file(struct cvs_file *cfp, void *arg) 48308f90673Sjfb { 484c710bc5aSjfb char *dir, *repo, buf[64]; 485c710bc5aSjfb char fpath[MAXPATHLEN], dfpath[MAXPATHLEN], rcspath[MAXPATHLEN]; 486946f6157Sdjm char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN]; 48708f90673Sjfb BUF *b1, *b2; 48808f90673Sjfb RCSNUM *r1, *r2; 48908f90673Sjfb RCSFILE *rf; 490dc6a6879Sjfb struct diff_arg *dap; 49108f90673Sjfb struct cvs_ent *entp; 492dc6a6879Sjfb struct cvsroot *root; 493dc6a6879Sjfb 494dc6a6879Sjfb dap = (struct diff_arg *)arg; 495dc6a6879Sjfb 496dc6a6879Sjfb if (cfp->cf_type == DT_DIR) { 497895e6cf6Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 498895e6cf6Sjfb root = cfp->cf_parent->cf_ddat->cd_root; 499c710bc5aSjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, 500c710bc5aSjfb CVS_FILE_NAME(cfp)); 5013917c9bfSderaadt } else { 502dc6a6879Sjfb root = cfp->cf_ddat->cd_root; 503dc6a6879Sjfb if ((cfp->cf_parent == NULL) || 504dc6a6879Sjfb (root != cfp->cf_parent->cf_ddat->cd_root)) { 505dc6a6879Sjfb cvs_connect(root); 506dc6a6879Sjfb cvs_diff_sendflags(root, dap); 507dc6a6879Sjfb } 508dc6a6879Sjfb 509dc6a6879Sjfb cvs_senddir(root, cfp); 510895e6cf6Sjfb } 511895e6cf6Sjfb 512dc6a6879Sjfb return (0); 513dc6a6879Sjfb } 51408f90673Sjfb 5152d5b8b1dSjfb if (cfp->cf_cvstat == CVS_FST_LOST) { 5162d5b8b1dSjfb cvs_log(LP_WARN, "cannot find file %s", CVS_FILE_NAME(cfp)); 5172d5b8b1dSjfb return (0); 5182d5b8b1dSjfb } 5192d5b8b1dSjfb 52008f90673Sjfb rf = NULL; 521c710bc5aSjfb diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath)); 522895e6cf6Sjfb 523dc6a6879Sjfb if (cfp->cf_parent != NULL) { 524c710bc5aSjfb dir = cvs_file_getpath(cfp->cf_parent, dfpath, sizeof(dfpath)); 525895e6cf6Sjfb root = cfp->cf_parent->cf_ddat->cd_root; 526dc6a6879Sjfb repo = cfp->cf_parent->cf_ddat->cd_repo; 5273917c9bfSderaadt } else { 528dc6a6879Sjfb dir = "."; 529895e6cf6Sjfb root = NULL; 530dc6a6879Sjfb repo = NULL; 53108f90673Sjfb } 53208f90673Sjfb 533dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 534dc6a6879Sjfb if (root->cr_method == CVS_METHOD_LOCAL) 535dc6a6879Sjfb cvs_log(LP_WARN, "I know nothing about %s", diff_file); 536dc6a6879Sjfb else 537c710bc5aSjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, 538c710bc5aSjfb CVS_FILE_NAME(cfp)); 539dc6a6879Sjfb return (0); 54008f90673Sjfb } 54108f90673Sjfb 542dc6a6879Sjfb entp = cvs_ent_getent(diff_file); 543dc6a6879Sjfb if (entp == NULL) 544dc6a6879Sjfb return (-1); 545dc6a6879Sjfb 546dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 547dc6a6879Sjfb if (cvs_sendentry(root, entp) < 0) { 548dc6a6879Sjfb cvs_ent_free(entp); 54908f90673Sjfb return (-1); 55008f90673Sjfb } 55108f90673Sjfb } 55208f90673Sjfb 553dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UPTODATE) { 554dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) 555c710bc5aSjfb cvs_sendreq(root, CVS_REQ_UNCHANGED, 556c710bc5aSjfb CVS_FILE_NAME(cfp)); 557dc6a6879Sjfb cvs_ent_free(entp); 55808f90673Sjfb return (0); 55908f90673Sjfb } 56008f90673Sjfb 56108f90673Sjfb /* at this point, the file is modified */ 562dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 563c710bc5aSjfb cvs_sendreq(root, CVS_REQ_MODIFIED, CVS_FILE_NAME(cfp)); 564dc6a6879Sjfb cvs_sendfile(root, diff_file); 5653917c9bfSderaadt } else { 56608f90673Sjfb snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 567dc6a6879Sjfb root->cr_dir, repo, diff_file, RCS_FILE_EXT); 56808f90673Sjfb 56908f90673Sjfb rf = rcs_open(rcspath, RCS_MODE_READ); 570dc6a6879Sjfb if (rf == NULL) { 571dc6a6879Sjfb cvs_ent_free(entp); 57208f90673Sjfb return (-1); 573dc6a6879Sjfb } 57408f90673Sjfb 575dc6a6879Sjfb cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, 57608f90673Sjfb RCS_DIFF_DIV, rcspath); 57708f90673Sjfb 578dc6a6879Sjfb if (dap->rev1 == NULL) 57908f90673Sjfb r1 = entp->ce_rev; 58008f90673Sjfb else { 581*25b74b48Sjfb if ((r1 = rcsnum_parse(dap->rev1)) == NULL) { 5827f535ec4Sjfb cvs_ent_free(entp); 5837f535ec4Sjfb return (-1); 5847f535ec4Sjfb } 58508f90673Sjfb } 58608f90673Sjfb 587dc6a6879Sjfb cvs_printf("retrieving revision %s\n", 58808f90673Sjfb rcsnum_tostr(r1, buf, sizeof(buf))); 58908f90673Sjfb b1 = rcs_getrev(rf, r1); 59008f90673Sjfb 5917f535ec4Sjfb if (r1 != entp->ce_rev) 5927f535ec4Sjfb rcsnum_free(r1); 5937f535ec4Sjfb 594dc6a6879Sjfb if (dap->rev2 != NULL) { 595dc6a6879Sjfb cvs_printf("retrieving revision %s\n", dap->rev2); 596*25b74b48Sjfb if ((r2 = rcsnum_parse(dap->rev2)) == NULL) { 5977f535ec4Sjfb cvs_ent_free(entp); 5987f535ec4Sjfb return (-1); 5997f535ec4Sjfb } 60008f90673Sjfb b2 = rcs_getrev(rf, r2); 6017f535ec4Sjfb rcsnum_free(r2); 6023917c9bfSderaadt } else { 603dc6a6879Sjfb b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); 60408f90673Sjfb } 60508f90673Sjfb 606dc6a6879Sjfb rcs_close(rf); 607dc6a6879Sjfb 608f5638424Sjfb printf("%s", diffargs); 609f5638424Sjfb printf(" -r%s", buf); 610dc6a6879Sjfb if (dap->rev2 != NULL) 611dc6a6879Sjfb printf(" -r%s", dap->rev2); 612dc6a6879Sjfb printf(" %s\n", diff_file); 613946f6157Sdjm strlcpy(path_tmp1, "/tmp/diff1.XXXXXXXXXX", sizeof(path_tmp1)); 6147f535ec4Sjfb if (cvs_buf_write_stmp(b1, path_tmp1, 0600) == -1) { 6157f535ec4Sjfb cvs_buf_free(b1); 6167f535ec4Sjfb cvs_buf_free(b2); 617946f6157Sdjm return (-1); 6187f535ec4Sjfb } 6197f535ec4Sjfb cvs_buf_free(b1); 6207f535ec4Sjfb 62169853e40Sjfb strlcpy(path_tmp2, "/tmp/diff2.XXXXXXXXXX", sizeof(path_tmp2)); 622946f6157Sdjm if (cvs_buf_write_stmp(b2, path_tmp2, 0600) == -1) { 6237f535ec4Sjfb cvs_buf_free(b2); 624946f6157Sdjm (void)unlink(path_tmp1); 625946f6157Sdjm return (-1); 626946f6157Sdjm } 6277f535ec4Sjfb cvs_buf_free(b2); 6287f535ec4Sjfb 629946f6157Sdjm cvs_diffreg(path_tmp1, path_tmp2); 630946f6157Sdjm (void)unlink(path_tmp1); 631946f6157Sdjm (void)unlink(path_tmp2); 63208f90673Sjfb } 63308f90673Sjfb 634dc6a6879Sjfb cvs_ent_free(entp); 63508f90673Sjfb return (0); 63608f90673Sjfb } 63708f90673Sjfb 63808f90673Sjfb 63908f90673Sjfb int 64008f90673Sjfb cvs_diffreg(const char *file1, const char *file2) 64108f90673Sjfb { 64208f90673Sjfb FILE *f1, *f2; 64308f90673Sjfb int i, rval; 6447f535ec4Sjfb void *tmp; 64508f90673Sjfb 64608f90673Sjfb f1 = f2 = NULL; 64708f90673Sjfb rval = D_SAME; 64808f90673Sjfb anychange = 0; 64908f90673Sjfb lastline = 0; 65008f90673Sjfb lastmatchline = 0; 65108f90673Sjfb context_vec_ptr = context_vec_start - 1; 65208f90673Sjfb chrtran = (iflag ? cup2low : clow2low); 65308f90673Sjfb 65408f90673Sjfb f1 = fopen(file1, "r"); 65508f90673Sjfb if (f1 == NULL) { 65608f90673Sjfb cvs_log(LP_ERRNO, "%s", file1); 65708f90673Sjfb status |= 2; 65808f90673Sjfb goto closem; 65908f90673Sjfb } 66008f90673Sjfb 66108f90673Sjfb f2 = fopen(file2, "r"); 66208f90673Sjfb if (f2 == NULL) { 66308f90673Sjfb cvs_log(LP_ERRNO, "%s", file2); 66408f90673Sjfb status |= 2; 66508f90673Sjfb goto closem; 66608f90673Sjfb } 66708f90673Sjfb 66808f90673Sjfb switch (files_differ(f1, f2)) { 66908f90673Sjfb case 0: 67008f90673Sjfb goto closem; 67108f90673Sjfb case 1: 67208f90673Sjfb break; 67308f90673Sjfb default: 67408f90673Sjfb /* error */ 67508f90673Sjfb status |= 2; 67608f90673Sjfb goto closem; 67708f90673Sjfb } 67808f90673Sjfb 67908f90673Sjfb if (!asciifile(f1) || !asciifile(f2)) { 68008f90673Sjfb rval = D_BINARY; 68108f90673Sjfb status |= 1; 68208f90673Sjfb goto closem; 68308f90673Sjfb } 6847f535ec4Sjfb if ((prepare(0, f1, stb1.st_size) < 0) || 6857f535ec4Sjfb (prepare(1, f2, stb2.st_size) < 0)) { 6867f535ec4Sjfb status |= 2; 6877f535ec4Sjfb goto closem; 6887f535ec4Sjfb } 68908f90673Sjfb prune(); 69008f90673Sjfb sort(sfile[0], slen[0]); 69108f90673Sjfb sort(sfile[1], slen[1]); 69208f90673Sjfb 69308f90673Sjfb member = (int *)file[1]; 69408f90673Sjfb equiv(sfile[0], slen[0], sfile[1], slen[1], member); 6957f535ec4Sjfb if ((tmp = realloc(member, (slen[1] + 2) * sizeof(int))) == NULL) { 6967f535ec4Sjfb status |= 2; 6977f535ec4Sjfb goto closem; 6987f535ec4Sjfb } 6997f535ec4Sjfb member = (int *)tmp; 70008f90673Sjfb 70108f90673Sjfb class = (int *)file[0]; 70208f90673Sjfb unsort(sfile[0], slen[0], class); 7037f535ec4Sjfb if ((tmp = realloc(class, (slen[0] + 2) * sizeof(int))) == NULL) { 7047f535ec4Sjfb status |= 2; 7057f535ec4Sjfb goto closem; 7067f535ec4Sjfb } 7077f535ec4Sjfb class = (int *)tmp; 70808f90673Sjfb 7097f535ec4Sjfb if ((klist = malloc((slen[0] + 2) * sizeof(int))) == NULL) { 7107f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate klist"); 7117f535ec4Sjfb status |= 2; 7127f535ec4Sjfb goto closem; 7137f535ec4Sjfb } 71408f90673Sjfb clen = 0; 71508f90673Sjfb clistlen = 100; 7167f535ec4Sjfb if ((clist = malloc(clistlen * sizeof(cand))) == NULL) { 7177f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate clist"); 7187f535ec4Sjfb status |= 2; 7197f535ec4Sjfb goto closem; 7207f535ec4Sjfb } 72108f90673Sjfb i = stone(class, slen[0], member, klist); 72208f90673Sjfb free(member); 72308f90673Sjfb free(class); 72408f90673Sjfb 72508f90673Sjfb J = realloc(J, (len[0] + 2) * sizeof(int)); 72608f90673Sjfb unravel(klist[i]); 72708f90673Sjfb free(clist); 72808f90673Sjfb free(klist); 72908f90673Sjfb 73008f90673Sjfb ixold = realloc(ixold, (len[0] + 2) * sizeof(long)); 73108f90673Sjfb ixnew = realloc(ixnew, (len[1] + 2) * sizeof(long)); 73208f90673Sjfb check(f1, f2); 73308f90673Sjfb output(file1, f1, file2, f2); 73408f90673Sjfb 73508f90673Sjfb closem: 73608f90673Sjfb if (anychange) { 73708f90673Sjfb status |= 1; 73808f90673Sjfb if (rval == D_SAME) 73908f90673Sjfb rval = D_DIFFER; 74008f90673Sjfb } 74108f90673Sjfb if (f1 != NULL) 74208f90673Sjfb fclose(f1); 74308f90673Sjfb if (f2 != NULL) 74408f90673Sjfb fclose(f2); 7457f535ec4Sjfb 74608f90673Sjfb return (rval); 74708f90673Sjfb } 74808f90673Sjfb 74908f90673Sjfb /* 75008f90673Sjfb * Check to see if the given files differ. 75108f90673Sjfb * Returns 0 if they are the same, 1 if different, and -1 on error. 75208f90673Sjfb * XXX - could use code from cmp(1) [faster] 75308f90673Sjfb */ 75408f90673Sjfb static int 75508f90673Sjfb files_differ(FILE *f1, FILE *f2) 75608f90673Sjfb { 75708f90673Sjfb char buf1[BUFSIZ], buf2[BUFSIZ]; 75808f90673Sjfb size_t i, j; 75908f90673Sjfb 76008f90673Sjfb if (stb1.st_size != stb2.st_size) 76108f90673Sjfb return (1); 76208f90673Sjfb for (;;) { 76308f90673Sjfb i = fread(buf1, 1, sizeof(buf1), f1); 76408f90673Sjfb j = fread(buf2, 1, sizeof(buf2), f2); 76508f90673Sjfb if (i != j) 76608f90673Sjfb return (1); 76708f90673Sjfb if (i == 0 && j == 0) { 76808f90673Sjfb if (ferror(f1) || ferror(f2)) 76908f90673Sjfb return (1); 77008f90673Sjfb return (0); 77108f90673Sjfb } 77208f90673Sjfb if (memcmp(buf1, buf2, i) != 0) 77308f90673Sjfb return (1); 77408f90673Sjfb } 77508f90673Sjfb } 77608f90673Sjfb 77708f90673Sjfb 77808f90673Sjfb char * 7792a0de57dSjfb splice(char *dir, char *filename) 78008f90673Sjfb { 78108f90673Sjfb char *tail, *buf; 78208f90673Sjfb 7832a0de57dSjfb if ((tail = strrchr(filename, '/')) == NULL) 7842a0de57dSjfb tail = filename; 78508f90673Sjfb else 78608f90673Sjfb tail++; 78708f90673Sjfb asprintf(&buf, "%s/%s", dir, tail); 78808f90673Sjfb return (buf); 78908f90673Sjfb } 79008f90673Sjfb 7917f535ec4Sjfb static int 79208f90673Sjfb prepare(int i, FILE *fd, off_t filesize) 79308f90673Sjfb { 7947f535ec4Sjfb void *tmp; 79508f90673Sjfb struct line *p; 79608f90673Sjfb int j, h; 79708f90673Sjfb size_t sz; 79808f90673Sjfb 79908f90673Sjfb rewind(fd); 80008f90673Sjfb 801c48da046Sxsa sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 80208f90673Sjfb if (sz < 100) 80308f90673Sjfb sz = 100; 80408f90673Sjfb 8057f535ec4Sjfb p = (struct line *)malloc((sz + 3) * sizeof(struct line)); 8067f535ec4Sjfb if (p == NULL) { 8077f535ec4Sjfb cvs_log(LP_ERRNO, "failed to prepare line array"); 8087f535ec4Sjfb return (-1); 8097f535ec4Sjfb } 81008f90673Sjfb for (j = 0; (h = readhash(fd));) { 81108f90673Sjfb if (j == (int)sz) { 81208f90673Sjfb sz = sz * 3 / 2; 8137f535ec4Sjfb tmp = realloc(p, (sz + 3) * sizeof(struct line)); 8147f535ec4Sjfb if (tmp == NULL) { 8157f535ec4Sjfb cvs_log(LP_ERRNO, "failed to grow line array"); 8167f535ec4Sjfb free(p); 8177f535ec4Sjfb return (-1); 8187f535ec4Sjfb } 8197f535ec4Sjfb p = (struct line *)tmp; 82008f90673Sjfb } 82108f90673Sjfb p[++j].value = h; 82208f90673Sjfb } 82308f90673Sjfb len[i] = j; 82408f90673Sjfb file[i] = p; 8257f535ec4Sjfb 8267f535ec4Sjfb return (0); 82708f90673Sjfb } 82808f90673Sjfb 82908f90673Sjfb static void 83008f90673Sjfb prune(void) 83108f90673Sjfb { 83208f90673Sjfb int i, j; 83308f90673Sjfb 83408f90673Sjfb for (pref = 0; pref < len[0] && pref < len[1] && 83508f90673Sjfb file[0][pref + 1].value == file[1][pref + 1].value; 83608f90673Sjfb pref++) 83708f90673Sjfb ; 83808f90673Sjfb for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 83908f90673Sjfb file[0][len[0] - suff].value == file[1][len[1] - suff].value; 84008f90673Sjfb suff++) 84108f90673Sjfb ; 84208f90673Sjfb for (j = 0; j < 2; j++) { 84308f90673Sjfb sfile[j] = file[j] + pref; 84408f90673Sjfb slen[j] = len[j] - pref - suff; 84508f90673Sjfb for (i = 0; i <= slen[j]; i++) 84608f90673Sjfb sfile[j][i].serial = i; 84708f90673Sjfb } 84808f90673Sjfb } 84908f90673Sjfb 85008f90673Sjfb static void 85108f90673Sjfb equiv(struct line *a, int n, struct line *b, int m, int *c) 85208f90673Sjfb { 85308f90673Sjfb int i, j; 85408f90673Sjfb 85508f90673Sjfb i = j = 1; 85608f90673Sjfb while (i <= n && j <= m) { 85708f90673Sjfb if (a[i].value < b[j].value) 85808f90673Sjfb a[i++].value = 0; 85908f90673Sjfb else if (a[i].value == b[j].value) 86008f90673Sjfb a[i++].value = j; 86108f90673Sjfb else 86208f90673Sjfb j++; 86308f90673Sjfb } 86408f90673Sjfb while (i <= n) 86508f90673Sjfb a[i++].value = 0; 86608f90673Sjfb b[m + 1].value = 0; 86708f90673Sjfb j = 0; 86808f90673Sjfb while (++j <= m) { 86908f90673Sjfb c[j] = -b[j].serial; 87008f90673Sjfb while (b[j + 1].value == b[j].value) { 87108f90673Sjfb j++; 87208f90673Sjfb c[j] = b[j].serial; 87308f90673Sjfb } 87408f90673Sjfb } 87508f90673Sjfb c[j] = -1; 87608f90673Sjfb } 87708f90673Sjfb 87808f90673Sjfb /* Code taken from ping.c */ 87908f90673Sjfb static int 88008f90673Sjfb isqrt(int n) 88108f90673Sjfb { 88208f90673Sjfb int y, x = 1; 88308f90673Sjfb 88408f90673Sjfb if (n == 0) 88508f90673Sjfb return (0); 88608f90673Sjfb 88708f90673Sjfb do { /* newton was a stinker */ 88808f90673Sjfb y = x; 88908f90673Sjfb x = n / x; 89008f90673Sjfb x += y; 89108f90673Sjfb x /= 2; 89208f90673Sjfb } while ((x - y) > 1 || (x - y) < -1); 89308f90673Sjfb 89408f90673Sjfb return (x); 89508f90673Sjfb } 89608f90673Sjfb 89708f90673Sjfb static int 89808f90673Sjfb stone(int *a, int n, int *b, int *c) 89908f90673Sjfb { 90008f90673Sjfb int i, k, y, j, l; 90108f90673Sjfb int oldc, tc, oldl; 90208f90673Sjfb u_int numtries; 90308f90673Sjfb 904cc649edbSjfb /* XXX move the isqrt() out of the macro to avoid multiple calls */ 905cc649edbSjfb const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n)); 90608f90673Sjfb 90708f90673Sjfb k = 0; 90808f90673Sjfb c[0] = newcand(0, 0, 0); 90908f90673Sjfb for (i = 1; i <= n; i++) { 91008f90673Sjfb j = a[i]; 91108f90673Sjfb if (j == 0) 91208f90673Sjfb continue; 91308f90673Sjfb y = -b[j]; 91408f90673Sjfb oldl = 0; 91508f90673Sjfb oldc = c[0]; 91608f90673Sjfb numtries = 0; 91708f90673Sjfb do { 91808f90673Sjfb if (y <= clist[oldc].y) 91908f90673Sjfb continue; 92008f90673Sjfb l = search(c, k, y); 92108f90673Sjfb if (l != oldl + 1) 92208f90673Sjfb oldc = c[l - 1]; 92308f90673Sjfb if (l <= k) { 92408f90673Sjfb if (clist[c[l]].y <= y) 92508f90673Sjfb continue; 92608f90673Sjfb tc = c[l]; 92708f90673Sjfb c[l] = newcand(i, y, oldc); 92808f90673Sjfb oldc = tc; 92908f90673Sjfb oldl = l; 93008f90673Sjfb numtries++; 93108f90673Sjfb } else { 93208f90673Sjfb c[l] = newcand(i, y, oldc); 93308f90673Sjfb k++; 93408f90673Sjfb break; 93508f90673Sjfb } 93608f90673Sjfb } while ((y = b[++j]) > 0 && numtries < bound); 93708f90673Sjfb } 93808f90673Sjfb return (k); 93908f90673Sjfb } 94008f90673Sjfb 94108f90673Sjfb static int 94208f90673Sjfb newcand(int x, int y, int pred) 94308f90673Sjfb { 94408f90673Sjfb struct cand *q; 94508f90673Sjfb 94608f90673Sjfb if (clen == clistlen) { 94708f90673Sjfb clistlen = clistlen * 11 / 10; 94808f90673Sjfb clist = realloc(clist, clistlen * sizeof(cand)); 9497f535ec4Sjfb if (clist == NULL) { 9507f535ec4Sjfb cvs_log(LP_ERRNO, "failed to resize clist"); 9517f535ec4Sjfb return (-1); 9527f535ec4Sjfb } 95308f90673Sjfb } 95408f90673Sjfb q = clist + clen; 95508f90673Sjfb q->x = x; 95608f90673Sjfb q->y = y; 95708f90673Sjfb q->pred = pred; 95808f90673Sjfb return (clen++); 95908f90673Sjfb } 96008f90673Sjfb 96108f90673Sjfb static int 96208f90673Sjfb search(int *c, int k, int y) 96308f90673Sjfb { 96408f90673Sjfb int i, j, l, t; 96508f90673Sjfb 96608f90673Sjfb if (clist[c[k]].y < y) /* quick look for typical case */ 96708f90673Sjfb return (k + 1); 96808f90673Sjfb i = 0; 96908f90673Sjfb j = k + 1; 97008f90673Sjfb while (1) { 97108f90673Sjfb l = i + j; 97208f90673Sjfb if ((l >>= 1) <= i) 97308f90673Sjfb break; 97408f90673Sjfb t = clist[c[l]].y; 97508f90673Sjfb if (t > y) 97608f90673Sjfb j = l; 97708f90673Sjfb else if (t < y) 97808f90673Sjfb i = l; 97908f90673Sjfb else 98008f90673Sjfb return (l); 98108f90673Sjfb } 98208f90673Sjfb return (l + 1); 98308f90673Sjfb } 98408f90673Sjfb 98508f90673Sjfb static void 98608f90673Sjfb unravel(int p) 98708f90673Sjfb { 98808f90673Sjfb struct cand *q; 98908f90673Sjfb int i; 99008f90673Sjfb 99108f90673Sjfb for (i = 0; i <= len[0]; i++) 99208f90673Sjfb J[i] = i <= pref ? i : 99308f90673Sjfb i > len[0] - suff ? i + len[1] - len[0] : 0; 99408f90673Sjfb for (q = clist + p; q->y != 0; q = clist + q->pred) 99508f90673Sjfb J[q->x + pref] = q->y + pref; 99608f90673Sjfb } 99708f90673Sjfb 99808f90673Sjfb /* 99908f90673Sjfb * Check does double duty: 100008f90673Sjfb * 1. ferret out any fortuitous correspondences due 100108f90673Sjfb * to confounding by hashing (which result in "jackpot") 100208f90673Sjfb * 2. collect random access indexes to the two files 100308f90673Sjfb */ 100408f90673Sjfb static void 100508f90673Sjfb check(FILE *f1, FILE *f2) 100608f90673Sjfb { 100708f90673Sjfb int i, j, jackpot, c, d; 100808f90673Sjfb long ctold, ctnew; 100908f90673Sjfb 101008f90673Sjfb rewind(f1); 101108f90673Sjfb rewind(f2); 101208f90673Sjfb j = 1; 101308f90673Sjfb ixold[0] = ixnew[0] = 0; 101408f90673Sjfb jackpot = 0; 101508f90673Sjfb ctold = ctnew = 0; 101608f90673Sjfb for (i = 1; i <= len[0]; i++) { 101708f90673Sjfb if (J[i] == 0) { 101808f90673Sjfb ixold[i] = ctold += skipline(f1); 101908f90673Sjfb continue; 102008f90673Sjfb } 102108f90673Sjfb while (j < J[i]) { 102208f90673Sjfb ixnew[j] = ctnew += skipline(f2); 102308f90673Sjfb j++; 102408f90673Sjfb } 102508f90673Sjfb if (bflag || wflag || iflag) { 102608f90673Sjfb for (;;) { 102708f90673Sjfb c = getc(f1); 102808f90673Sjfb d = getc(f2); 102908f90673Sjfb /* 103008f90673Sjfb * GNU diff ignores a missing newline 103108f90673Sjfb * in one file if bflag || wflag. 103208f90673Sjfb */ 103308f90673Sjfb if ((bflag || wflag) && 103408f90673Sjfb ((c == EOF && d == '\n') || 103508f90673Sjfb (c == '\n' && d == EOF))) { 103608f90673Sjfb break; 103708f90673Sjfb } 103808f90673Sjfb ctold++; 103908f90673Sjfb ctnew++; 104008f90673Sjfb if (bflag && isspace(c) && isspace(d)) { 104108f90673Sjfb do { 104208f90673Sjfb if (c == '\n') 104308f90673Sjfb break; 104408f90673Sjfb ctold++; 104508f90673Sjfb } while (isspace(c = getc(f1))); 104608f90673Sjfb do { 104708f90673Sjfb if (d == '\n') 104808f90673Sjfb break; 104908f90673Sjfb ctnew++; 105008f90673Sjfb } while (isspace(d = getc(f2))); 105108f90673Sjfb } else if (wflag) { 105208f90673Sjfb while (isspace(c) && c != '\n') { 105308f90673Sjfb c = getc(f1); 105408f90673Sjfb ctold++; 105508f90673Sjfb } 105608f90673Sjfb while (isspace(d) && d != '\n') { 105708f90673Sjfb d = getc(f2); 105808f90673Sjfb ctnew++; 105908f90673Sjfb } 106008f90673Sjfb } 106108f90673Sjfb if (chrtran[c] != chrtran[d]) { 106208f90673Sjfb jackpot++; 106308f90673Sjfb J[i] = 0; 106408f90673Sjfb if (c != '\n' && c != EOF) 106508f90673Sjfb ctold += skipline(f1); 106608f90673Sjfb if (d != '\n' && c != EOF) 106708f90673Sjfb ctnew += skipline(f2); 106808f90673Sjfb break; 106908f90673Sjfb } 107008f90673Sjfb if (c == '\n' || c == EOF) 107108f90673Sjfb break; 107208f90673Sjfb } 107308f90673Sjfb } else { 107408f90673Sjfb for (;;) { 107508f90673Sjfb ctold++; 107608f90673Sjfb ctnew++; 107708f90673Sjfb if ((c = getc(f1)) != (d = getc(f2))) { 107808f90673Sjfb /* jackpot++; */ 107908f90673Sjfb J[i] = 0; 108008f90673Sjfb if (c != '\n' && c != EOF) 108108f90673Sjfb ctold += skipline(f1); 108208f90673Sjfb if (d != '\n' && c != EOF) 108308f90673Sjfb ctnew += skipline(f2); 108408f90673Sjfb break; 108508f90673Sjfb } 108608f90673Sjfb if (c == '\n' || c == EOF) 108708f90673Sjfb break; 108808f90673Sjfb } 108908f90673Sjfb } 109008f90673Sjfb ixold[i] = ctold; 109108f90673Sjfb ixnew[j] = ctnew; 109208f90673Sjfb j++; 109308f90673Sjfb } 109408f90673Sjfb for (; j <= len[1]; j++) 109508f90673Sjfb ixnew[j] = ctnew += skipline(f2); 109608f90673Sjfb /* 109708f90673Sjfb * if (jackpot) 109808f90673Sjfb * fprintf(stderr, "jackpot\n"); 109908f90673Sjfb */ 110008f90673Sjfb } 110108f90673Sjfb 110208f90673Sjfb /* shellsort CACM #201 */ 110308f90673Sjfb static void 110408f90673Sjfb sort(struct line *a, int n) 110508f90673Sjfb { 110608f90673Sjfb struct line *ai, *aim, w; 110708f90673Sjfb int j, m = 0, k; 110808f90673Sjfb 110908f90673Sjfb if (n == 0) 111008f90673Sjfb return; 111108f90673Sjfb for (j = 1; j <= n; j *= 2) 111208f90673Sjfb m = 2 * j - 1; 111308f90673Sjfb for (m /= 2; m != 0; m /= 2) { 111408f90673Sjfb k = n - m; 111508f90673Sjfb for (j = 1; j <= k; j++) { 111608f90673Sjfb for (ai = &a[j]; ai > a; ai -= m) { 111708f90673Sjfb aim = &ai[m]; 111808f90673Sjfb if (aim < ai) 111908f90673Sjfb break; /* wraparound */ 112008f90673Sjfb if (aim->value > ai[0].value || 112108f90673Sjfb (aim->value == ai[0].value && 112208f90673Sjfb aim->serial > ai[0].serial)) 112308f90673Sjfb break; 112408f90673Sjfb w.value = ai[0].value; 112508f90673Sjfb ai[0].value = aim->value; 112608f90673Sjfb aim->value = w.value; 112708f90673Sjfb w.serial = ai[0].serial; 112808f90673Sjfb ai[0].serial = aim->serial; 112908f90673Sjfb aim->serial = w.serial; 113008f90673Sjfb } 113108f90673Sjfb } 113208f90673Sjfb } 113308f90673Sjfb } 113408f90673Sjfb 113508f90673Sjfb static void 113608f90673Sjfb unsort(struct line *f, int l, int *b) 113708f90673Sjfb { 113808f90673Sjfb int *a, i; 113908f90673Sjfb 11407f535ec4Sjfb if ((a = (int *)malloc((l + 1) * sizeof(int))) == NULL) { 11417f535ec4Sjfb cvs_log(LP_ERRNO, "failed to allocate sort array"); 11427f535ec4Sjfb return; 11437f535ec4Sjfb } 114408f90673Sjfb for (i = 1; i <= l; i++) 114508f90673Sjfb a[f[i].serial] = f[i].value; 114608f90673Sjfb for (i = 1; i <= l; i++) 114708f90673Sjfb b[i] = a[i]; 114808f90673Sjfb free(a); 114908f90673Sjfb } 115008f90673Sjfb 115108f90673Sjfb static int 115208f90673Sjfb skipline(FILE *f) 115308f90673Sjfb { 115408f90673Sjfb int i, c; 115508f90673Sjfb 115608f90673Sjfb for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 115708f90673Sjfb continue; 115808f90673Sjfb return (i); 115908f90673Sjfb } 116008f90673Sjfb 116108f90673Sjfb static void 116208f90673Sjfb output(const char *file1, FILE *f1, const char *file2, FILE *f2) 116308f90673Sjfb { 116408f90673Sjfb int m, i0, i1, j0, j1; 116508f90673Sjfb 116608f90673Sjfb rewind(f1); 116708f90673Sjfb rewind(f2); 116808f90673Sjfb m = len[0]; 116908f90673Sjfb J[0] = 0; 117008f90673Sjfb J[m + 1] = len[1] + 1; 117108f90673Sjfb for (i0 = 1; i0 <= m; i0 = i1 + 1) { 117208f90673Sjfb while (i0 <= m && J[i0] == J[i0 - 1] + 1) 117308f90673Sjfb i0++; 117408f90673Sjfb j0 = J[i0 - 1] + 1; 117508f90673Sjfb i1 = i0 - 1; 117608f90673Sjfb while (i1 < m && J[i1 + 1] == 0) 117708f90673Sjfb i1++; 117808f90673Sjfb j1 = J[i1 + 1] - 1; 117908f90673Sjfb J[i1] = j1; 118008f90673Sjfb change(file1, f1, file2, f2, i0, i1, j0, j1); 118108f90673Sjfb } 118208f90673Sjfb if (m == 0) 118308f90673Sjfb change(file1, f1, file2, f2, 1, 0, 1, len[1]); 118408f90673Sjfb if (format == D_IFDEF) { 118508f90673Sjfb for (;;) { 118608f90673Sjfb #define c i0 118708f90673Sjfb if ((c = getc(f1)) == EOF) 118808f90673Sjfb return; 118908f90673Sjfb putchar(c); 119008f90673Sjfb } 119108f90673Sjfb #undef c 119208f90673Sjfb } 119308f90673Sjfb if (anychange != 0) { 119408f90673Sjfb if (format == D_CONTEXT) 119508f90673Sjfb dump_context_vec(f1, f2); 119608f90673Sjfb else if (format == D_UNIFIED) 119708f90673Sjfb dump_unified_vec(f1, f2); 119808f90673Sjfb } 119908f90673Sjfb } 120008f90673Sjfb 120108f90673Sjfb static __inline void 120208f90673Sjfb range(int a, int b, char *separator) 120308f90673Sjfb { 120408f90673Sjfb printf("%d", a > b ? b : a); 120508f90673Sjfb if (a < b) 120608f90673Sjfb printf("%s%d", separator, b); 120708f90673Sjfb } 120808f90673Sjfb 120908f90673Sjfb static __inline void 121008f90673Sjfb uni_range(int a, int b) 121108f90673Sjfb { 121208f90673Sjfb if (a < b) 121308f90673Sjfb printf("%d,%d", a, b - a + 1); 121408f90673Sjfb else if (a == b) 121508f90673Sjfb printf("%d", b); 121608f90673Sjfb else 121708f90673Sjfb printf("%d,0", b); 121808f90673Sjfb } 121908f90673Sjfb 122008f90673Sjfb static char * 12212a0de57dSjfb preadline(int fd, size_t rlen, off_t off) 122208f90673Sjfb { 122308f90673Sjfb char *line; 122408f90673Sjfb ssize_t nr; 122508f90673Sjfb 12262a0de57dSjfb line = malloc(rlen + 1); 122708f90673Sjfb if (line == NULL) { 122808f90673Sjfb cvs_log(LP_ERRNO, "failed to allocate line"); 122908f90673Sjfb return (NULL); 123008f90673Sjfb } 12312a0de57dSjfb if ((nr = pread(fd, line, rlen, off)) < 0) { 123208f90673Sjfb cvs_log(LP_ERRNO, "preadline failed"); 123308f90673Sjfb return (NULL); 123408f90673Sjfb } 123508f90673Sjfb line[nr] = '\0'; 123608f90673Sjfb return (line); 123708f90673Sjfb } 123808f90673Sjfb 123908f90673Sjfb static int 124008f90673Sjfb ignoreline(char *line) 124108f90673Sjfb { 124208f90673Sjfb int ret; 124308f90673Sjfb 124408f90673Sjfb ret = regexec(&ignore_re, line, 0, NULL, 0); 124508f90673Sjfb free(line); 124608f90673Sjfb return (ret == 0); /* if it matched, it should be ignored. */ 124708f90673Sjfb } 124808f90673Sjfb 124908f90673Sjfb /* 125008f90673Sjfb * Indicate that there is a difference between lines a and b of the from file 125108f90673Sjfb * to get to lines c to d of the to file. If a is greater then b then there 125208f90673Sjfb * are no lines in the from file involved and this means that there were 125308f90673Sjfb * lines appended (beginning at b). If c is greater than d then there are 125408f90673Sjfb * lines missing from the to file. 125508f90673Sjfb */ 125608f90673Sjfb static void 125708f90673Sjfb change(const char *file1, FILE *f1, const char *file2, FILE *f2, 125808f90673Sjfb int a, int b, int c, int d) 125908f90673Sjfb { 126008f90673Sjfb static size_t max_context = 64; 126108f90673Sjfb int i; 126208f90673Sjfb 126308f90673Sjfb if (format != D_IFDEF && a > b && c > d) 126408f90673Sjfb return; 126508f90673Sjfb if (ignore_pats != NULL) { 126608f90673Sjfb char *line; 126708f90673Sjfb /* 126808f90673Sjfb * All lines in the change, insert, or delete must 126908f90673Sjfb * match an ignore pattern for the change to be 127008f90673Sjfb * ignored. 127108f90673Sjfb */ 127208f90673Sjfb if (a <= b) { /* Changes and deletes. */ 127308f90673Sjfb for (i = a; i <= b; i++) { 127408f90673Sjfb line = preadline(fileno(f1), 127508f90673Sjfb ixold[i] - ixold[i - 1], ixold[i - 1]); 127608f90673Sjfb if (!ignoreline(line)) 127708f90673Sjfb goto proceed; 127808f90673Sjfb } 127908f90673Sjfb } 128008f90673Sjfb if (a > b || c <= d) { /* Changes and inserts. */ 128108f90673Sjfb for (i = c; i <= d; i++) { 128208f90673Sjfb line = preadline(fileno(f2), 128308f90673Sjfb ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 128408f90673Sjfb if (!ignoreline(line)) 128508f90673Sjfb goto proceed; 128608f90673Sjfb } 128708f90673Sjfb } 128808f90673Sjfb return; 128908f90673Sjfb } 129008f90673Sjfb proceed: 129108f90673Sjfb if (format == D_CONTEXT || format == D_UNIFIED) { 129208f90673Sjfb /* 129308f90673Sjfb * Allocate change records as needed. 129408f90673Sjfb */ 129508f90673Sjfb if (context_vec_ptr == context_vec_end - 1) { 129608f90673Sjfb ptrdiff_t offset = context_vec_ptr - context_vec_start; 129708f90673Sjfb max_context <<= 1; 129808f90673Sjfb context_vec_start = realloc(context_vec_start, 129908f90673Sjfb max_context * sizeof(struct context_vec)); 130008f90673Sjfb context_vec_end = context_vec_start + max_context; 130108f90673Sjfb context_vec_ptr = context_vec_start + offset; 130208f90673Sjfb } 130308f90673Sjfb if (anychange == 0) { 130408f90673Sjfb /* 130508f90673Sjfb * Print the context/unidiff header first time through. 130608f90673Sjfb */ 130708f90673Sjfb printf("%s %s %s", 130808f90673Sjfb format == D_CONTEXT ? "***" : "---", diff_file, 130908f90673Sjfb ctime(&stb1.st_mtime)); 131008f90673Sjfb printf("%s %s %s", 131108f90673Sjfb format == D_CONTEXT ? "---" : "+++", diff_file, 131208f90673Sjfb ctime(&stb2.st_mtime)); 131308f90673Sjfb anychange = 1; 131408f90673Sjfb } else if (a > context_vec_ptr->b + (2 * context) + 1 && 131508f90673Sjfb c > context_vec_ptr->d + (2 * context) + 1) { 131608f90673Sjfb /* 131708f90673Sjfb * If this change is more than 'context' lines from the 131808f90673Sjfb * previous change, dump the record and reset it. 131908f90673Sjfb */ 132008f90673Sjfb if (format == D_CONTEXT) 132108f90673Sjfb dump_context_vec(f1, f2); 132208f90673Sjfb else 132308f90673Sjfb dump_unified_vec(f1, f2); 132408f90673Sjfb } 132508f90673Sjfb context_vec_ptr++; 132608f90673Sjfb context_vec_ptr->a = a; 132708f90673Sjfb context_vec_ptr->b = b; 132808f90673Sjfb context_vec_ptr->c = c; 132908f90673Sjfb context_vec_ptr->d = d; 133008f90673Sjfb return; 133108f90673Sjfb } 133208f90673Sjfb if (anychange == 0) 133308f90673Sjfb anychange = 1; 133408f90673Sjfb switch (format) { 133508f90673Sjfb case D_BRIEF: 133608f90673Sjfb return; 133708f90673Sjfb case D_NORMAL: 133808f90673Sjfb range(a, b, ","); 133908f90673Sjfb putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 134008f90673Sjfb if (format == D_NORMAL) 134108f90673Sjfb range(c, d, ","); 134208f90673Sjfb putchar('\n'); 134308f90673Sjfb break; 134408f90673Sjfb } 134508f90673Sjfb if (format == D_NORMAL || format == D_IFDEF) { 134608f90673Sjfb fetch(ixold, a, b, f1, '<', 1); 134708f90673Sjfb if (a <= b && c <= d && format == D_NORMAL) 134808f90673Sjfb puts("---"); 134908f90673Sjfb } 135008f90673Sjfb i = fetch(ixnew, c, d, f2, format == D_NORMAL ? '>' : '\0', 0); 135108f90673Sjfb if (inifdef) { 135208f90673Sjfb printf("#endif /* %s */\n", ifdefname); 135308f90673Sjfb inifdef = 0; 135408f90673Sjfb } 135508f90673Sjfb } 135608f90673Sjfb 135708f90673Sjfb static int 135808f90673Sjfb fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 135908f90673Sjfb { 136008f90673Sjfb int i, j, c, lastc, col, nc; 136108f90673Sjfb 136208f90673Sjfb /* 136308f90673Sjfb * When doing #ifdef's, copy down to current line 136408f90673Sjfb * if this is the first file, so that stuff makes it to output. 136508f90673Sjfb */ 136608f90673Sjfb if (format == D_IFDEF && oldfile) { 136708f90673Sjfb long curpos = ftell(lb); 136808f90673Sjfb /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 136908f90673Sjfb nc = f[a > b ? b : a - 1] - curpos; 137008f90673Sjfb for (i = 0; i < nc; i++) 137108f90673Sjfb putchar(getc(lb)); 137208f90673Sjfb } 137308f90673Sjfb if (a > b) 137408f90673Sjfb return (0); 137508f90673Sjfb if (format == D_IFDEF) { 137608f90673Sjfb if (inifdef) { 137708f90673Sjfb printf("#else /* %s%s */\n", 137808f90673Sjfb oldfile == 1 ? "!" : "", ifdefname); 137908f90673Sjfb } else { 138008f90673Sjfb if (oldfile) 138108f90673Sjfb printf("#ifndef %s\n", ifdefname); 138208f90673Sjfb else 138308f90673Sjfb printf("#ifdef %s\n", ifdefname); 138408f90673Sjfb } 138508f90673Sjfb inifdef = 1 + oldfile; 138608f90673Sjfb } 138708f90673Sjfb for (i = a; i <= b; i++) { 138808f90673Sjfb fseek(lb, f[i - 1], SEEK_SET); 138908f90673Sjfb nc = f[i] - f[i - 1]; 139008f90673Sjfb if (format != D_IFDEF && ch != '\0') { 139108f90673Sjfb putchar(ch); 139208f90673Sjfb if (Tflag && (format == D_NORMAL || format == D_CONTEXT 139308f90673Sjfb || format == D_UNIFIED)) 139408f90673Sjfb putchar('\t'); 139508f90673Sjfb else if (format != D_UNIFIED) 139608f90673Sjfb putchar(' '); 139708f90673Sjfb } 139808f90673Sjfb col = 0; 139908f90673Sjfb for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { 140008f90673Sjfb if ((c = getc(lb)) == EOF) { 140108f90673Sjfb puts("\n\\ No newline at end of file"); 140208f90673Sjfb return (0); 140308f90673Sjfb } 140408f90673Sjfb if (c == '\t' && tflag) { 140508f90673Sjfb do { 140608f90673Sjfb putchar(' '); 140708f90673Sjfb } while (++col & 7); 140808f90673Sjfb } else { 140908f90673Sjfb putchar(c); 141008f90673Sjfb col++; 141108f90673Sjfb } 141208f90673Sjfb } 141308f90673Sjfb } 141408f90673Sjfb return (0); 141508f90673Sjfb } 141608f90673Sjfb 141708f90673Sjfb /* 141808f90673Sjfb * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 141908f90673Sjfb */ 142008f90673Sjfb static int 142108f90673Sjfb readhash(FILE *f) 142208f90673Sjfb { 142308f90673Sjfb int i, t, space; 142408f90673Sjfb int sum; 142508f90673Sjfb 142608f90673Sjfb sum = 1; 142708f90673Sjfb space = 0; 142808f90673Sjfb if (!bflag && !wflag) { 142908f90673Sjfb if (iflag) 143008f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 143108f90673Sjfb if (t == EOF) { 143208f90673Sjfb if (i == 0) 143308f90673Sjfb return (0); 143408f90673Sjfb break; 143508f90673Sjfb } 143608f90673Sjfb sum = sum * 127 + chrtran[t]; 143708f90673Sjfb } 143808f90673Sjfb else 143908f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 144008f90673Sjfb if (t == EOF) { 144108f90673Sjfb if (i == 0) 144208f90673Sjfb return (0); 144308f90673Sjfb break; 144408f90673Sjfb } 144508f90673Sjfb sum = sum * 127 + t; 144608f90673Sjfb } 144708f90673Sjfb } else { 144808f90673Sjfb for (i = 0;;) { 144908f90673Sjfb switch (t = getc(f)) { 145008f90673Sjfb case '\t': 145108f90673Sjfb case ' ': 145208f90673Sjfb space++; 145308f90673Sjfb continue; 145408f90673Sjfb default: 145508f90673Sjfb if (space && !wflag) { 145608f90673Sjfb i++; 145708f90673Sjfb space = 0; 145808f90673Sjfb } 145908f90673Sjfb sum = sum * 127 + chrtran[t]; 146008f90673Sjfb i++; 146108f90673Sjfb continue; 146208f90673Sjfb case EOF: 146308f90673Sjfb if (i == 0) 146408f90673Sjfb return (0); 146508f90673Sjfb /* FALLTHROUGH */ 146608f90673Sjfb case '\n': 146708f90673Sjfb break; 146808f90673Sjfb } 146908f90673Sjfb break; 147008f90673Sjfb } 147108f90673Sjfb } 147208f90673Sjfb /* 147308f90673Sjfb * There is a remote possibility that we end up with a zero sum. 147408f90673Sjfb * Zero is used as an EOF marker, so return 1 instead. 147508f90673Sjfb */ 147608f90673Sjfb return (sum == 0 ? 1 : sum); 147708f90673Sjfb } 147808f90673Sjfb 147908f90673Sjfb static int 148008f90673Sjfb asciifile(FILE *f) 148108f90673Sjfb { 148208f90673Sjfb char buf[BUFSIZ]; 148308f90673Sjfb int i, cnt; 148408f90673Sjfb 148508f90673Sjfb if (aflag || f == NULL) 148608f90673Sjfb return (1); 148708f90673Sjfb 148808f90673Sjfb rewind(f); 148908f90673Sjfb cnt = fread(buf, 1, sizeof(buf), f); 149008f90673Sjfb for (i = 0; i < cnt; i++) 149108f90673Sjfb if (!isprint(buf[i]) && !isspace(buf[i])) 149208f90673Sjfb return (0); 149308f90673Sjfb return (1); 149408f90673Sjfb } 149508f90673Sjfb 14965e78344dSjfb static char* 14975e78344dSjfb match_function(const long *f, int pos, FILE *fp) 14985e78344dSjfb { 14995e78344dSjfb unsigned char buf[FUNCTION_CONTEXT_SIZE]; 15005e78344dSjfb size_t nc; 15015e78344dSjfb int last = lastline; 15025e78344dSjfb char *p; 15035e78344dSjfb 15045e78344dSjfb lastline = pos; 15055e78344dSjfb while (pos > last) { 15065e78344dSjfb fseek(fp, f[pos - 1], SEEK_SET); 15075e78344dSjfb nc = f[pos] - f[pos - 1]; 15085e78344dSjfb if (nc >= sizeof(buf)) 15095e78344dSjfb nc = sizeof(buf) - 1; 15105e78344dSjfb nc = fread(buf, 1, nc, fp); 15115e78344dSjfb if (nc > 0) { 15125e78344dSjfb buf[nc] = '\0'; 15135e78344dSjfb p = strchr(buf, '\n'); 15145e78344dSjfb if (p != NULL) 15155e78344dSjfb *p = '\0'; 15165e78344dSjfb if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 15175e78344dSjfb strlcpy(lastbuf, buf, sizeof lastbuf); 15185e78344dSjfb lastmatchline = pos; 15195e78344dSjfb return lastbuf; 15205e78344dSjfb } 15215e78344dSjfb } 15225e78344dSjfb pos--; 15235e78344dSjfb } 15245e78344dSjfb return (lastmatchline > 0) ? lastbuf : NULL; 15255e78344dSjfb } 15265e78344dSjfb 152708f90673Sjfb 152808f90673Sjfb /* dump accumulated "context" diff changes */ 152908f90673Sjfb static void 153008f90673Sjfb dump_context_vec(FILE *f1, FILE *f2) 153108f90673Sjfb { 153208f90673Sjfb struct context_vec *cvp = context_vec_start; 153308f90673Sjfb int lowa, upb, lowc, upd, do_output; 153408f90673Sjfb int a, b, c, d; 15355e78344dSjfb char ch, *f; 153608f90673Sjfb 153708f90673Sjfb if (context_vec_start > context_vec_ptr) 153808f90673Sjfb return; 153908f90673Sjfb 154008f90673Sjfb b = d = 0; /* gcc */ 1541dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1542dc6a6879Sjfb upb = MIN(len[0], context_vec_ptr->b + context); 1543dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1544dc6a6879Sjfb upd = MIN(len[1], context_vec_ptr->d + context); 154508f90673Sjfb 154608f90673Sjfb printf("***************"); 15475e78344dSjfb if (pflag) { 15485e78344dSjfb f = match_function(ixold, lowa - 1, f1); 15495e78344dSjfb if (f != NULL) { 15505e78344dSjfb putchar(' '); 15515e78344dSjfb fputs(f, stdout); 15525e78344dSjfb } 15535e78344dSjfb } 155408f90673Sjfb printf("\n*** "); 155508f90673Sjfb range(lowa, upb, ","); 155608f90673Sjfb printf(" ****\n"); 155708f90673Sjfb 155808f90673Sjfb /* 155908f90673Sjfb * Output changes to the "old" file. The first loop suppresses 156008f90673Sjfb * output if there were no changes to the "old" file (we'll see 156108f90673Sjfb * the "old" lines as context in the "new" list). 156208f90673Sjfb */ 156308f90673Sjfb do_output = 0; 156408f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) 156508f90673Sjfb if (cvp->a <= cvp->b) { 156608f90673Sjfb cvp = context_vec_start; 156708f90673Sjfb do_output++; 156808f90673Sjfb break; 156908f90673Sjfb } 157008f90673Sjfb if (do_output) { 157108f90673Sjfb while (cvp <= context_vec_ptr) { 157208f90673Sjfb a = cvp->a; 157308f90673Sjfb b = cvp->b; 157408f90673Sjfb c = cvp->c; 157508f90673Sjfb d = cvp->d; 157608f90673Sjfb 157708f90673Sjfb if (a <= b && c <= d) 157808f90673Sjfb ch = 'c'; 157908f90673Sjfb else 158008f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 158108f90673Sjfb 158208f90673Sjfb if (ch == 'a') 158308f90673Sjfb fetch(ixold, lowa, b, f1, ' ', 0); 158408f90673Sjfb else { 158508f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 158608f90673Sjfb fetch(ixold, a, b, f1, 158708f90673Sjfb ch == 'c' ? '!' : '-', 0); 158808f90673Sjfb } 158908f90673Sjfb lowa = b + 1; 159008f90673Sjfb cvp++; 159108f90673Sjfb } 159208f90673Sjfb fetch(ixold, b + 1, upb, f1, ' ', 0); 159308f90673Sjfb } 159408f90673Sjfb /* output changes to the "new" file */ 159508f90673Sjfb printf("--- "); 159608f90673Sjfb range(lowc, upd, ","); 159708f90673Sjfb printf(" ----\n"); 159808f90673Sjfb 159908f90673Sjfb do_output = 0; 160008f90673Sjfb for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 160108f90673Sjfb if (cvp->c <= cvp->d) { 160208f90673Sjfb cvp = context_vec_start; 160308f90673Sjfb do_output++; 160408f90673Sjfb break; 160508f90673Sjfb } 160608f90673Sjfb if (do_output) { 160708f90673Sjfb while (cvp <= context_vec_ptr) { 160808f90673Sjfb a = cvp->a; 160908f90673Sjfb b = cvp->b; 161008f90673Sjfb c = cvp->c; 161108f90673Sjfb d = cvp->d; 161208f90673Sjfb 161308f90673Sjfb if (a <= b && c <= d) 161408f90673Sjfb ch = 'c'; 161508f90673Sjfb else 161608f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 161708f90673Sjfb 161808f90673Sjfb if (ch == 'd') 161908f90673Sjfb fetch(ixnew, lowc, d, f2, ' ', 0); 162008f90673Sjfb else { 162108f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 162208f90673Sjfb fetch(ixnew, c, d, f2, 162308f90673Sjfb ch == 'c' ? '!' : '+', 0); 162408f90673Sjfb } 162508f90673Sjfb lowc = d + 1; 162608f90673Sjfb cvp++; 162708f90673Sjfb } 162808f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 162908f90673Sjfb } 163008f90673Sjfb context_vec_ptr = context_vec_start - 1; 163108f90673Sjfb } 163208f90673Sjfb 163308f90673Sjfb /* dump accumulated "unified" diff changes */ 163408f90673Sjfb static void 163508f90673Sjfb dump_unified_vec(FILE *f1, FILE *f2) 163608f90673Sjfb { 163708f90673Sjfb struct context_vec *cvp = context_vec_start; 163808f90673Sjfb int lowa, upb, lowc, upd; 163908f90673Sjfb int a, b, c, d; 16405e78344dSjfb char ch, *f; 164108f90673Sjfb 164208f90673Sjfb if (context_vec_start > context_vec_ptr) 164308f90673Sjfb return; 164408f90673Sjfb 164508f90673Sjfb b = d = 0; /* gcc */ 1646dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1647dc6a6879Sjfb upb = MIN(len[0], context_vec_ptr->b + context); 1648dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1649dc6a6879Sjfb upd = MIN(len[1], context_vec_ptr->d + context); 165008f90673Sjfb 165108f90673Sjfb fputs("@@ -", stdout); 165208f90673Sjfb uni_range(lowa, upb); 165308f90673Sjfb fputs(" +", stdout); 165408f90673Sjfb uni_range(lowc, upd); 165508f90673Sjfb fputs(" @@", stdout); 16565e78344dSjfb if (pflag) { 16575e78344dSjfb f = match_function(ixold, lowa - 1, f1); 16585e78344dSjfb if (f != NULL) { 16595e78344dSjfb putchar(' '); 16605e78344dSjfb fputs(f, stdout); 16615e78344dSjfb } 16625e78344dSjfb } 166308f90673Sjfb putchar('\n'); 166408f90673Sjfb 166508f90673Sjfb /* 166608f90673Sjfb * Output changes in "unified" diff format--the old and new lines 166708f90673Sjfb * are printed together. 166808f90673Sjfb */ 166908f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) { 167008f90673Sjfb a = cvp->a; 167108f90673Sjfb b = cvp->b; 167208f90673Sjfb c = cvp->c; 167308f90673Sjfb d = cvp->d; 167408f90673Sjfb 167508f90673Sjfb /* 167608f90673Sjfb * c: both new and old changes 167708f90673Sjfb * d: only changes in the old file 167808f90673Sjfb * a: only changes in the new file 167908f90673Sjfb */ 168008f90673Sjfb if (a <= b && c <= d) 168108f90673Sjfb ch = 'c'; 168208f90673Sjfb else 168308f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 168408f90673Sjfb 168508f90673Sjfb switch (ch) { 168608f90673Sjfb case 'c': 168708f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 168808f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 168908f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 169008f90673Sjfb break; 169108f90673Sjfb case 'd': 169208f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 169308f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 169408f90673Sjfb break; 169508f90673Sjfb case 'a': 169608f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 169708f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 169808f90673Sjfb break; 169908f90673Sjfb } 170008f90673Sjfb lowa = b + 1; 170108f90673Sjfb lowc = d + 1; 170208f90673Sjfb } 170308f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 170408f90673Sjfb 170508f90673Sjfb context_vec_ptr = context_vec_start - 1; 170608f90673Sjfb } 1707