1*dc6a6879Sjfb /* $OpenBSD: diff.c,v 1.4 2004/07/30 01:49:23 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" 149*dc6a6879Sjfb #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 201*dc6a6879Sjfb struct diff_arg { 202*dc6a6879Sjfb char *rev1; 203*dc6a6879Sjfb char *rev2; 204*dc6a6879Sjfb char *date1; 205*dc6a6879Sjfb char *date2; 206*dc6a6879Sjfb }; 207*dc6a6879Sjfb 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 *); 217*dc6a6879Sjfb int cvs_diff_file (struct cvs_file *, void *); 21808f90673Sjfb static void output(const char *, FILE *, const char *, FILE *); 21908f90673Sjfb static void check(FILE *, FILE *); 22008f90673Sjfb static void range(int, int, char *); 22108f90673Sjfb static void uni_range(int, int); 22208f90673Sjfb static void dump_context_vec(FILE *, FILE *); 22308f90673Sjfb static void dump_unified_vec(FILE *, FILE *); 22408f90673Sjfb static void prepare(int, FILE *, off_t); 22508f90673Sjfb static void prune(void); 22608f90673Sjfb static void equiv(struct line *, int, struct line *, int, int *); 22708f90673Sjfb static void unravel(int); 22808f90673Sjfb static void unsort(struct line *, int, int *); 22908f90673Sjfb static void change(const char *, FILE *, const char *, FILE *, int, int, int, int); 23008f90673Sjfb static void sort(struct line *, int); 23108f90673Sjfb static int ignoreline(char *); 23208f90673Sjfb static int asciifile(FILE *); 23308f90673Sjfb static int fetch(long *, int, int, FILE *, int, int); 23408f90673Sjfb static int newcand(int, int, int); 23508f90673Sjfb static int search(int *, int, int); 23608f90673Sjfb static int skipline(FILE *); 23708f90673Sjfb static int isqrt(int); 23808f90673Sjfb static int stone(int *, int, int *, int *); 23908f90673Sjfb static int readhash(FILE *); 24008f90673Sjfb static int files_differ(FILE *, FILE *); 24108f90673Sjfb static char *preadline(int, size_t, off_t); 24208f90673Sjfb 24308f90673Sjfb 24408f90673Sjfb 24508f90673Sjfb extern int cvs_client; 24608f90673Sjfb 24708f90673Sjfb static int aflag, bflag, dflag, iflag, tflag, Tflag, wflag; 24808f90673Sjfb static int context, status; 24908f90673Sjfb static int format = D_NORMAL; 25008f90673Sjfb static struct stat stb1, stb2; 251f5638424Sjfb static char *ifdefname, *ignore_pats, diffargs[128]; 252f5638424Sjfb static const char *diff_file; 25308f90673Sjfb regex_t ignore_re; 25408f90673Sjfb 25508f90673Sjfb static int *J; /* will be overlaid on class */ 25608f90673Sjfb static int *class; /* will be overlaid on file[0] */ 25708f90673Sjfb static int *klist; /* will be overlaid on file[0] after class */ 25808f90673Sjfb static int *member; /* will be overlaid on file[1] */ 25908f90673Sjfb static int clen; 26008f90673Sjfb static int inifdef; /* whether or not we are in a #ifdef block */ 26108f90673Sjfb static int len[2]; 26208f90673Sjfb static int pref, suff; /* length of prefix and suffix */ 26308f90673Sjfb static int slen[2]; 26408f90673Sjfb static int anychange; 26508f90673Sjfb static long *ixnew; /* will be overlaid on file[1] */ 26608f90673Sjfb static long *ixold; /* will be overlaid on klist */ 26708f90673Sjfb static struct cand *clist; /* merely a free storage pot for candidates */ 26808f90673Sjfb static int clistlen; /* the length of clist */ 26908f90673Sjfb static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 27008f90673Sjfb static u_char *chrtran; /* translation table for case-folding */ 27108f90673Sjfb static struct context_vec *context_vec_start; 27208f90673Sjfb static struct context_vec *context_vec_end; 27308f90673Sjfb static struct context_vec *context_vec_ptr; 27408f90673Sjfb 27508f90673Sjfb #define FUNCTION_CONTEXT_SIZE 41 27608f90673Sjfb static int lastline; 27708f90673Sjfb static int lastmatchline; 27808f90673Sjfb 27908f90673Sjfb 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 /* 34308f90673Sjfb * cvs_diff() 34408f90673Sjfb * 34508f90673Sjfb * Handler for the `cvs diff' command. 34608f90673Sjfb * 34708f90673Sjfb * SYNOPSIS: cvs [args] diff [-clipu] [-D date] [-r rev] 34808f90673Sjfb */ 34908f90673Sjfb 35008f90673Sjfb int 35108f90673Sjfb cvs_diff(int argc, char **argv) 35208f90673Sjfb { 353*dc6a6879Sjfb int ch, recurse, flags; 354*dc6a6879Sjfb struct cvs_file *files; 355*dc6a6879Sjfb struct diff_arg darg; 356*dc6a6879Sjfb struct cvsroot *root; 35708f90673Sjfb 35808f90673Sjfb context = CVS_DIFF_DEFCTX; 359*dc6a6879Sjfb flags = CF_RECURSE|CF_IGNORE|CF_SORT|CF_KNOWN; 36008f90673Sjfb recurse = 1; 36108f90673Sjfb 362*dc6a6879Sjfb memset(&darg, 0, sizeof(darg)); 363*dc6a6879Sjfb strlcpy(diffargs, argv[0], sizeof(diffargs)); 364*dc6a6879Sjfb 36508f90673Sjfb while ((ch = getopt(argc, argv, "cD:lir:u")) != -1) { 36608f90673Sjfb switch (ch) { 36708f90673Sjfb case 'c': 368f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 36908f90673Sjfb format = D_CONTEXT; 37008f90673Sjfb break; 37108f90673Sjfb case 'D': 372*dc6a6879Sjfb if (darg.date1 == NULL && darg.rev1 == NULL) 373*dc6a6879Sjfb darg.date1 = optarg; 374*dc6a6879Sjfb else if (darg.date2 == NULL && darg.rev2 == NULL) 375*dc6a6879Sjfb darg.date2 = optarg; 37608f90673Sjfb else { 37708f90673Sjfb cvs_log(LP_ERR, 37808f90673Sjfb "no more than two revisions/dates can " 37908f90673Sjfb "be specified"); 38008f90673Sjfb } 38108f90673Sjfb break; 38208f90673Sjfb case 'l': 383f5638424Sjfb strlcat(diffargs, " -l", sizeof(diffargs)); 38408f90673Sjfb recurse = 0; 385*dc6a6879Sjfb flags &= ~CF_RECURSE; 38608f90673Sjfb break; 38708f90673Sjfb case 'i': 388f5638424Sjfb strlcat(diffargs, " -i", sizeof(diffargs)); 38908f90673Sjfb iflag = 1; 39008f90673Sjfb break; 39108f90673Sjfb case 'r': 392*dc6a6879Sjfb if ((darg.rev1 == NULL) && (darg.date1 == NULL)) 393*dc6a6879Sjfb darg.rev1 = optarg; 394*dc6a6879Sjfb else if ((darg.rev2 == NULL) && (darg.date2 == NULL)) 395*dc6a6879Sjfb darg.rev2 = optarg; 39608f90673Sjfb else { 39708f90673Sjfb cvs_log(LP_ERR, 39808f90673Sjfb "no more than two revisions/dates can " 39908f90673Sjfb "be specified"); 40008f90673Sjfb return (EX_USAGE); 40108f90673Sjfb } 40208f90673Sjfb break; 40308f90673Sjfb case 'u': 404f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 40508f90673Sjfb format = D_UNIFIED; 40608f90673Sjfb break; 40708f90673Sjfb default: 40808f90673Sjfb return (EX_USAGE); 40908f90673Sjfb } 41008f90673Sjfb } 41108f90673Sjfb 41208f90673Sjfb argc -= optind; 41308f90673Sjfb argv += optind; 41408f90673Sjfb 41508f90673Sjfb if (argc == 0) { 416*dc6a6879Sjfb files = cvs_file_get(".", flags); 417*dc6a6879Sjfb } 418*dc6a6879Sjfb else 419*dc6a6879Sjfb files = cvs_file_getspec(argv, argc, 0); 42008f90673Sjfb 421*dc6a6879Sjfb cvs_file_examine(files, cvs_diff_file, &darg); 42208f90673Sjfb 423*dc6a6879Sjfb root = files->cf_ddat->cd_root; 424*dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) 425*dc6a6879Sjfb cvs_sendreq(root, CVS_REQ_DIFF, NULL); 42608f90673Sjfb 427*dc6a6879Sjfb return (0); 428*dc6a6879Sjfb } 429*dc6a6879Sjfb 430*dc6a6879Sjfb 431*dc6a6879Sjfb /* 432*dc6a6879Sjfb * cvs_diff_sendflags() 433*dc6a6879Sjfb * 434*dc6a6879Sjfb */ 435*dc6a6879Sjfb 436*dc6a6879Sjfb int 437*dc6a6879Sjfb cvs_diff_sendflags(struct cvsroot *root, struct diff_arg *dap) 438*dc6a6879Sjfb { 43908f90673Sjfb /* send the flags */ 44008f90673Sjfb if (format == D_CONTEXT) 441*dc6a6879Sjfb cvs_sendarg(root, "-c", 0); 44208f90673Sjfb else if (format == D_UNIFIED) 443*dc6a6879Sjfb cvs_sendarg(root, "-u", 0); 44408f90673Sjfb 445*dc6a6879Sjfb if (dap->rev1 != NULL) { 446*dc6a6879Sjfb cvs_sendarg(root, "-r", 0); 447*dc6a6879Sjfb cvs_sendarg(root, dap->rev1, 1); 44808f90673Sjfb } 449*dc6a6879Sjfb else if (dap->date1 != NULL) { 450*dc6a6879Sjfb cvs_sendarg(root, "-D", 0); 451*dc6a6879Sjfb cvs_sendarg(root, dap->date1, 1); 45208f90673Sjfb } 453*dc6a6879Sjfb if (dap->rev2 != NULL) { 454*dc6a6879Sjfb cvs_sendarg(root, "-r", 0); 455*dc6a6879Sjfb cvs_sendarg(root, dap->rev2, 1); 45608f90673Sjfb } 457*dc6a6879Sjfb else if (dap->date2 != NULL) { 458*dc6a6879Sjfb cvs_sendarg(root, "-D", 0); 459*dc6a6879Sjfb cvs_sendarg(root, dap->date2, 1); 46008f90673Sjfb } 46108f90673Sjfb 46208f90673Sjfb return (0); 46308f90673Sjfb } 46408f90673Sjfb 46508f90673Sjfb 46608f90673Sjfb /* 46708f90673Sjfb * cvs_diff_file() 46808f90673Sjfb * 46908f90673Sjfb * Diff a single file. 47008f90673Sjfb */ 47108f90673Sjfb 47208f90673Sjfb int 473*dc6a6879Sjfb cvs_diff_file(struct cvs_file *cfp, void *arg) 47408f90673Sjfb { 475*dc6a6879Sjfb char *dir, *repo, rcspath[MAXPATHLEN], buf[64]; 47608f90673Sjfb BUF *b1, *b2; 47708f90673Sjfb RCSNUM *r1, *r2; 47808f90673Sjfb RCSFILE *rf; 479*dc6a6879Sjfb struct diff_arg *dap; 48008f90673Sjfb struct cvs_ent *entp; 481*dc6a6879Sjfb struct cvsroot *root; 482*dc6a6879Sjfb 483*dc6a6879Sjfb dap = (struct diff_arg *)arg; 484*dc6a6879Sjfb 485*dc6a6879Sjfb cvs_log(LP_DEBUG, "%s: diffing %s", __func__, cfp->cf_path); 486*dc6a6879Sjfb 487*dc6a6879Sjfb if (cfp->cf_type == DT_DIR) { 488*dc6a6879Sjfb root = cfp->cf_ddat->cd_root; 489*dc6a6879Sjfb if ((cfp->cf_parent == NULL) || 490*dc6a6879Sjfb (root != cfp->cf_parent->cf_ddat->cd_root)) { 491*dc6a6879Sjfb cvs_connect(root); 492*dc6a6879Sjfb cvs_diff_sendflags(root, dap); 493*dc6a6879Sjfb } 494*dc6a6879Sjfb 495*dc6a6879Sjfb cvs_senddir(root, cfp); 496*dc6a6879Sjfb return (0); 497*dc6a6879Sjfb } 498*dc6a6879Sjfb else /* take the root of parent directory */ 499*dc6a6879Sjfb root = cfp->cf_parent->cf_ddat->cd_root; 50008f90673Sjfb 50108f90673Sjfb rf = NULL; 502*dc6a6879Sjfb diff_file = cfp->cf_path; 503*dc6a6879Sjfb if (cfp->cf_parent != NULL) { 504*dc6a6879Sjfb dir = cfp->cf_parent->cf_path; 505*dc6a6879Sjfb repo = cfp->cf_parent->cf_ddat->cd_repo; 506*dc6a6879Sjfb } 507*dc6a6879Sjfb else { 508*dc6a6879Sjfb dir = "."; 509*dc6a6879Sjfb repo = NULL; 51008f90673Sjfb } 51108f90673Sjfb 512*dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UNKNOWN) { 513*dc6a6879Sjfb if (root->cr_method == CVS_METHOD_LOCAL) 514*dc6a6879Sjfb cvs_log(LP_WARN, "I know nothing about %s", diff_file); 515*dc6a6879Sjfb else 516*dc6a6879Sjfb cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name); 517*dc6a6879Sjfb return (0); 51808f90673Sjfb } 51908f90673Sjfb 520*dc6a6879Sjfb entp = cvs_ent_getent(diff_file); 521*dc6a6879Sjfb if (entp == NULL) 522*dc6a6879Sjfb return (-1); 523*dc6a6879Sjfb 524*dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 525*dc6a6879Sjfb if (cvs_sendentry(root, entp) < 0) { 526*dc6a6879Sjfb cvs_ent_free(entp); 52708f90673Sjfb return (-1); 52808f90673Sjfb } 52908f90673Sjfb } 53008f90673Sjfb 531*dc6a6879Sjfb if (cfp->cf_cvstat == CVS_FST_UPTODATE) { 532*dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) 533*dc6a6879Sjfb cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name); 534*dc6a6879Sjfb cvs_ent_free(entp); 53508f90673Sjfb return (0); 53608f90673Sjfb } 53708f90673Sjfb 53808f90673Sjfb /* at this point, the file is modified */ 539*dc6a6879Sjfb if (root->cr_method != CVS_METHOD_LOCAL) { 540*dc6a6879Sjfb cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name); 541*dc6a6879Sjfb cvs_sendfile(root, diff_file); 54208f90673Sjfb } 54308f90673Sjfb else { 54408f90673Sjfb snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s", 545*dc6a6879Sjfb root->cr_dir, repo, diff_file, RCS_FILE_EXT); 54608f90673Sjfb 54708f90673Sjfb rf = rcs_open(rcspath, RCS_MODE_READ); 548*dc6a6879Sjfb if (rf == NULL) { 549*dc6a6879Sjfb cvs_ent_free(entp); 55008f90673Sjfb return (-1); 551*dc6a6879Sjfb } 55208f90673Sjfb 553*dc6a6879Sjfb cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file, 55408f90673Sjfb RCS_DIFF_DIV, rcspath); 55508f90673Sjfb 556*dc6a6879Sjfb if (dap->rev1 == NULL) 55708f90673Sjfb r1 = entp->ce_rev; 55808f90673Sjfb else { 55908f90673Sjfb r1 = rcsnum_alloc(); 560*dc6a6879Sjfb rcsnum_aton(dap->rev1, NULL, r1); 56108f90673Sjfb } 56208f90673Sjfb 563*dc6a6879Sjfb cvs_printf("retrieving revision %s\n", 56408f90673Sjfb rcsnum_tostr(r1, buf, sizeof(buf))); 56508f90673Sjfb b1 = rcs_getrev(rf, r1); 56608f90673Sjfb 567*dc6a6879Sjfb if (dap->rev2 != NULL) { 568*dc6a6879Sjfb cvs_printf("retrieving revision %s\n", dap->rev2); 56908f90673Sjfb r2 = rcsnum_alloc(); 570*dc6a6879Sjfb rcsnum_aton(dap->rev2, NULL, r2); 57108f90673Sjfb b2 = rcs_getrev(rf, r2); 57208f90673Sjfb } 57308f90673Sjfb else { 574*dc6a6879Sjfb b2 = cvs_buf_load(diff_file, BUF_AUTOEXT); 57508f90673Sjfb } 57608f90673Sjfb 577*dc6a6879Sjfb rcs_close(rf); 578*dc6a6879Sjfb 579f5638424Sjfb printf("%s", diffargs); 580f5638424Sjfb printf(" -r%s", buf); 581*dc6a6879Sjfb if (dap->rev2 != NULL) 582*dc6a6879Sjfb printf(" -r%s", dap->rev2); 583*dc6a6879Sjfb printf(" %s\n", diff_file); 58408f90673Sjfb cvs_buf_write(b1, "/tmp/diff1", 0600); 58508f90673Sjfb cvs_buf_write(b2, "/tmp/diff2", 0600); 58608f90673Sjfb cvs_diffreg("/tmp/diff1", "/tmp/diff2"); 58708f90673Sjfb } 58808f90673Sjfb 589*dc6a6879Sjfb cvs_ent_free(entp); 59008f90673Sjfb return (0); 59108f90673Sjfb } 59208f90673Sjfb 59308f90673Sjfb 59408f90673Sjfb int 59508f90673Sjfb cvs_diffreg(const char *file1, const char *file2) 59608f90673Sjfb { 59708f90673Sjfb FILE *f1, *f2; 59808f90673Sjfb int i, rval; 59908f90673Sjfb 60008f90673Sjfb f1 = f2 = NULL; 60108f90673Sjfb rval = D_SAME; 60208f90673Sjfb anychange = 0; 60308f90673Sjfb lastline = 0; 60408f90673Sjfb lastmatchline = 0; 60508f90673Sjfb context_vec_ptr = context_vec_start - 1; 60608f90673Sjfb chrtran = (iflag ? cup2low : clow2low); 60708f90673Sjfb 60808f90673Sjfb f1 = fopen(file1, "r"); 60908f90673Sjfb if (f1 == NULL) { 61008f90673Sjfb cvs_log(LP_ERRNO, "%s", file1); 61108f90673Sjfb status |= 2; 61208f90673Sjfb goto closem; 61308f90673Sjfb } 61408f90673Sjfb 61508f90673Sjfb f2 = fopen(file2, "r"); 61608f90673Sjfb if (f2 == NULL) { 61708f90673Sjfb cvs_log(LP_ERRNO, "%s", file2); 61808f90673Sjfb status |= 2; 61908f90673Sjfb goto closem; 62008f90673Sjfb } 62108f90673Sjfb 62208f90673Sjfb switch (files_differ(f1, f2)) { 62308f90673Sjfb case 0: 62408f90673Sjfb goto closem; 62508f90673Sjfb case 1: 62608f90673Sjfb break; 62708f90673Sjfb default: 62808f90673Sjfb /* error */ 62908f90673Sjfb status |= 2; 63008f90673Sjfb goto closem; 63108f90673Sjfb } 63208f90673Sjfb 63308f90673Sjfb if (!asciifile(f1) || !asciifile(f2)) { 63408f90673Sjfb rval = D_BINARY; 63508f90673Sjfb status |= 1; 63608f90673Sjfb goto closem; 63708f90673Sjfb } 63808f90673Sjfb prepare(0, f1, stb1.st_size); 63908f90673Sjfb prepare(1, f2, stb2.st_size); 64008f90673Sjfb prune(); 64108f90673Sjfb sort(sfile[0], slen[0]); 64208f90673Sjfb sort(sfile[1], slen[1]); 64308f90673Sjfb 64408f90673Sjfb member = (int *)file[1]; 64508f90673Sjfb equiv(sfile[0], slen[0], sfile[1], slen[1], member); 64608f90673Sjfb member = realloc(member, (slen[1] + 2) * sizeof(int)); 64708f90673Sjfb 64808f90673Sjfb class = (int *)file[0]; 64908f90673Sjfb unsort(sfile[0], slen[0], class); 65008f90673Sjfb class = realloc(class, (slen[0] + 2) * sizeof(int)); 65108f90673Sjfb 65208f90673Sjfb klist = malloc((slen[0] + 2) * sizeof(int)); 65308f90673Sjfb clen = 0; 65408f90673Sjfb clistlen = 100; 65508f90673Sjfb clist = malloc(clistlen * sizeof(cand)); 65608f90673Sjfb i = stone(class, slen[0], member, klist); 65708f90673Sjfb free(member); 65808f90673Sjfb free(class); 65908f90673Sjfb 66008f90673Sjfb J = realloc(J, (len[0] + 2) * sizeof(int)); 66108f90673Sjfb unravel(klist[i]); 66208f90673Sjfb free(clist); 66308f90673Sjfb free(klist); 66408f90673Sjfb 66508f90673Sjfb ixold = realloc(ixold, (len[0] + 2) * sizeof(long)); 66608f90673Sjfb ixnew = realloc(ixnew, (len[1] + 2) * sizeof(long)); 66708f90673Sjfb check(f1, f2); 66808f90673Sjfb output(file1, f1, file2, f2); 66908f90673Sjfb 67008f90673Sjfb closem: 67108f90673Sjfb if (anychange) { 67208f90673Sjfb status |= 1; 67308f90673Sjfb if (rval == D_SAME) 67408f90673Sjfb rval = D_DIFFER; 67508f90673Sjfb } 67608f90673Sjfb if (f1 != NULL) 67708f90673Sjfb fclose(f1); 67808f90673Sjfb if (f2 != NULL) 67908f90673Sjfb fclose(f2); 68008f90673Sjfb return (rval); 68108f90673Sjfb } 68208f90673Sjfb 68308f90673Sjfb /* 68408f90673Sjfb * Check to see if the given files differ. 68508f90673Sjfb * Returns 0 if they are the same, 1 if different, and -1 on error. 68608f90673Sjfb * XXX - could use code from cmp(1) [faster] 68708f90673Sjfb */ 68808f90673Sjfb static int 68908f90673Sjfb files_differ(FILE *f1, FILE *f2) 69008f90673Sjfb { 69108f90673Sjfb char buf1[BUFSIZ], buf2[BUFSIZ]; 69208f90673Sjfb size_t i, j; 69308f90673Sjfb 69408f90673Sjfb if (stb1.st_size != stb2.st_size) 69508f90673Sjfb return (1); 69608f90673Sjfb for (;;) { 69708f90673Sjfb i = fread(buf1, 1, sizeof(buf1), f1); 69808f90673Sjfb j = fread(buf2, 1, sizeof(buf2), f2); 69908f90673Sjfb if (i != j) 70008f90673Sjfb return (1); 70108f90673Sjfb if (i == 0 && j == 0) { 70208f90673Sjfb if (ferror(f1) || ferror(f2)) 70308f90673Sjfb return (1); 70408f90673Sjfb return (0); 70508f90673Sjfb } 70608f90673Sjfb if (memcmp(buf1, buf2, i) != 0) 70708f90673Sjfb return (1); 70808f90673Sjfb } 70908f90673Sjfb } 71008f90673Sjfb 71108f90673Sjfb 71208f90673Sjfb char * 71308f90673Sjfb splice(char *dir, char *file) 71408f90673Sjfb { 71508f90673Sjfb char *tail, *buf; 71608f90673Sjfb 71708f90673Sjfb if ((tail = strrchr(file, '/')) == NULL) 71808f90673Sjfb tail = file; 71908f90673Sjfb else 72008f90673Sjfb tail++; 72108f90673Sjfb asprintf(&buf, "%s/%s", dir, tail); 72208f90673Sjfb return (buf); 72308f90673Sjfb } 72408f90673Sjfb 72508f90673Sjfb static void 72608f90673Sjfb prepare(int i, FILE *fd, off_t filesize) 72708f90673Sjfb { 72808f90673Sjfb struct line *p; 72908f90673Sjfb int j, h; 73008f90673Sjfb size_t sz; 73108f90673Sjfb 73208f90673Sjfb rewind(fd); 73308f90673Sjfb 73408f90673Sjfb sz = (filesize <= SIZE_MAX ? filesize : SIZE_MAX) / 25; 73508f90673Sjfb if (sz < 100) 73608f90673Sjfb sz = 100; 73708f90673Sjfb 73808f90673Sjfb p = malloc((sz + 3) * sizeof(struct line)); 73908f90673Sjfb for (j = 0; (h = readhash(fd));) { 74008f90673Sjfb if (j == (int)sz) { 74108f90673Sjfb sz = sz * 3 / 2; 74208f90673Sjfb p = realloc(p, (sz + 3) * sizeof(struct line)); 74308f90673Sjfb } 74408f90673Sjfb p[++j].value = h; 74508f90673Sjfb } 74608f90673Sjfb len[i] = j; 74708f90673Sjfb file[i] = p; 74808f90673Sjfb } 74908f90673Sjfb 75008f90673Sjfb static void 75108f90673Sjfb prune(void) 75208f90673Sjfb { 75308f90673Sjfb int i, j; 75408f90673Sjfb 75508f90673Sjfb for (pref = 0; pref < len[0] && pref < len[1] && 75608f90673Sjfb file[0][pref + 1].value == file[1][pref + 1].value; 75708f90673Sjfb pref++) 75808f90673Sjfb ; 75908f90673Sjfb for (suff = 0; suff < len[0] - pref && suff < len[1] - pref && 76008f90673Sjfb file[0][len[0] - suff].value == file[1][len[1] - suff].value; 76108f90673Sjfb suff++) 76208f90673Sjfb ; 76308f90673Sjfb for (j = 0; j < 2; j++) { 76408f90673Sjfb sfile[j] = file[j] + pref; 76508f90673Sjfb slen[j] = len[j] - pref - suff; 76608f90673Sjfb for (i = 0; i <= slen[j]; i++) 76708f90673Sjfb sfile[j][i].serial = i; 76808f90673Sjfb } 76908f90673Sjfb } 77008f90673Sjfb 77108f90673Sjfb static void 77208f90673Sjfb equiv(struct line *a, int n, struct line *b, int m, int *c) 77308f90673Sjfb { 77408f90673Sjfb int i, j; 77508f90673Sjfb 77608f90673Sjfb i = j = 1; 77708f90673Sjfb while (i <= n && j <= m) { 77808f90673Sjfb if (a[i].value < b[j].value) 77908f90673Sjfb a[i++].value = 0; 78008f90673Sjfb else if (a[i].value == b[j].value) 78108f90673Sjfb a[i++].value = j; 78208f90673Sjfb else 78308f90673Sjfb j++; 78408f90673Sjfb } 78508f90673Sjfb while (i <= n) 78608f90673Sjfb a[i++].value = 0; 78708f90673Sjfb b[m + 1].value = 0; 78808f90673Sjfb j = 0; 78908f90673Sjfb while (++j <= m) { 79008f90673Sjfb c[j] = -b[j].serial; 79108f90673Sjfb while (b[j + 1].value == b[j].value) { 79208f90673Sjfb j++; 79308f90673Sjfb c[j] = b[j].serial; 79408f90673Sjfb } 79508f90673Sjfb } 79608f90673Sjfb c[j] = -1; 79708f90673Sjfb } 79808f90673Sjfb 79908f90673Sjfb /* Code taken from ping.c */ 80008f90673Sjfb static int 80108f90673Sjfb isqrt(int n) 80208f90673Sjfb { 80308f90673Sjfb int y, x = 1; 80408f90673Sjfb 80508f90673Sjfb if (n == 0) 80608f90673Sjfb return(0); 80708f90673Sjfb 80808f90673Sjfb do { /* newton was a stinker */ 80908f90673Sjfb y = x; 81008f90673Sjfb x = n / x; 81108f90673Sjfb x += y; 81208f90673Sjfb x /= 2; 81308f90673Sjfb } while ((x - y) > 1 || (x - y) < -1); 81408f90673Sjfb 81508f90673Sjfb return (x); 81608f90673Sjfb } 81708f90673Sjfb 81808f90673Sjfb static int 81908f90673Sjfb stone(int *a, int n, int *b, int *c) 82008f90673Sjfb { 82108f90673Sjfb int i, k, y, j, l; 82208f90673Sjfb int oldc, tc, oldl; 82308f90673Sjfb u_int numtries; 82408f90673Sjfb 825*dc6a6879Sjfb const u_int bound = dflag ? UINT_MAX : MAX(256, isqrt(n)); 82608f90673Sjfb 82708f90673Sjfb k = 0; 82808f90673Sjfb c[0] = newcand(0, 0, 0); 82908f90673Sjfb for (i = 1; i <= n; i++) { 83008f90673Sjfb j = a[i]; 83108f90673Sjfb if (j == 0) 83208f90673Sjfb continue; 83308f90673Sjfb y = -b[j]; 83408f90673Sjfb oldl = 0; 83508f90673Sjfb oldc = c[0]; 83608f90673Sjfb numtries = 0; 83708f90673Sjfb do { 83808f90673Sjfb if (y <= clist[oldc].y) 83908f90673Sjfb continue; 84008f90673Sjfb l = search(c, k, y); 84108f90673Sjfb if (l != oldl + 1) 84208f90673Sjfb oldc = c[l - 1]; 84308f90673Sjfb if (l <= k) { 84408f90673Sjfb if (clist[c[l]].y <= y) 84508f90673Sjfb continue; 84608f90673Sjfb tc = c[l]; 84708f90673Sjfb c[l] = newcand(i, y, oldc); 84808f90673Sjfb oldc = tc; 84908f90673Sjfb oldl = l; 85008f90673Sjfb numtries++; 85108f90673Sjfb } else { 85208f90673Sjfb c[l] = newcand(i, y, oldc); 85308f90673Sjfb k++; 85408f90673Sjfb break; 85508f90673Sjfb } 85608f90673Sjfb } while ((y = b[++j]) > 0 && numtries < bound); 85708f90673Sjfb } 85808f90673Sjfb return (k); 85908f90673Sjfb } 86008f90673Sjfb 86108f90673Sjfb static int 86208f90673Sjfb newcand(int x, int y, int pred) 86308f90673Sjfb { 86408f90673Sjfb struct cand *q; 86508f90673Sjfb 86608f90673Sjfb if (clen == clistlen) { 86708f90673Sjfb clistlen = clistlen * 11 / 10; 86808f90673Sjfb clist = realloc(clist, clistlen * sizeof(cand)); 86908f90673Sjfb } 87008f90673Sjfb q = clist + clen; 87108f90673Sjfb q->x = x; 87208f90673Sjfb q->y = y; 87308f90673Sjfb q->pred = pred; 87408f90673Sjfb return (clen++); 87508f90673Sjfb } 87608f90673Sjfb 87708f90673Sjfb static int 87808f90673Sjfb search(int *c, int k, int y) 87908f90673Sjfb { 88008f90673Sjfb int i, j, l, t; 88108f90673Sjfb 88208f90673Sjfb if (clist[c[k]].y < y) /* quick look for typical case */ 88308f90673Sjfb return (k + 1); 88408f90673Sjfb i = 0; 88508f90673Sjfb j = k + 1; 88608f90673Sjfb while (1) { 88708f90673Sjfb l = i + j; 88808f90673Sjfb if ((l >>= 1) <= i) 88908f90673Sjfb break; 89008f90673Sjfb t = clist[c[l]].y; 89108f90673Sjfb if (t > y) 89208f90673Sjfb j = l; 89308f90673Sjfb else if (t < y) 89408f90673Sjfb i = l; 89508f90673Sjfb else 89608f90673Sjfb return (l); 89708f90673Sjfb } 89808f90673Sjfb return (l + 1); 89908f90673Sjfb } 90008f90673Sjfb 90108f90673Sjfb static void 90208f90673Sjfb unravel(int p) 90308f90673Sjfb { 90408f90673Sjfb struct cand *q; 90508f90673Sjfb int i; 90608f90673Sjfb 90708f90673Sjfb for (i = 0; i <= len[0]; i++) 90808f90673Sjfb J[i] = i <= pref ? i : 90908f90673Sjfb i > len[0] - suff ? i + len[1] - len[0] : 0; 91008f90673Sjfb for (q = clist + p; q->y != 0; q = clist + q->pred) 91108f90673Sjfb J[q->x + pref] = q->y + pref; 91208f90673Sjfb } 91308f90673Sjfb 91408f90673Sjfb /* 91508f90673Sjfb * Check does double duty: 91608f90673Sjfb * 1. ferret out any fortuitous correspondences due 91708f90673Sjfb * to confounding by hashing (which result in "jackpot") 91808f90673Sjfb * 2. collect random access indexes to the two files 91908f90673Sjfb */ 92008f90673Sjfb static void 92108f90673Sjfb check(FILE *f1, FILE *f2) 92208f90673Sjfb { 92308f90673Sjfb int i, j, jackpot, c, d; 92408f90673Sjfb long ctold, ctnew; 92508f90673Sjfb 92608f90673Sjfb rewind(f1); 92708f90673Sjfb rewind(f2); 92808f90673Sjfb j = 1; 92908f90673Sjfb ixold[0] = ixnew[0] = 0; 93008f90673Sjfb jackpot = 0; 93108f90673Sjfb ctold = ctnew = 0; 93208f90673Sjfb for (i = 1; i <= len[0]; i++) { 93308f90673Sjfb if (J[i] == 0) { 93408f90673Sjfb ixold[i] = ctold += skipline(f1); 93508f90673Sjfb continue; 93608f90673Sjfb } 93708f90673Sjfb while (j < J[i]) { 93808f90673Sjfb ixnew[j] = ctnew += skipline(f2); 93908f90673Sjfb j++; 94008f90673Sjfb } 94108f90673Sjfb if (bflag || wflag || iflag) { 94208f90673Sjfb for (;;) { 94308f90673Sjfb c = getc(f1); 94408f90673Sjfb d = getc(f2); 94508f90673Sjfb /* 94608f90673Sjfb * GNU diff ignores a missing newline 94708f90673Sjfb * in one file if bflag || wflag. 94808f90673Sjfb */ 94908f90673Sjfb if ((bflag || wflag) && 95008f90673Sjfb ((c == EOF && d == '\n') || 95108f90673Sjfb (c == '\n' && d == EOF))) { 95208f90673Sjfb break; 95308f90673Sjfb } 95408f90673Sjfb ctold++; 95508f90673Sjfb ctnew++; 95608f90673Sjfb if (bflag && isspace(c) && isspace(d)) { 95708f90673Sjfb do { 95808f90673Sjfb if (c == '\n') 95908f90673Sjfb break; 96008f90673Sjfb ctold++; 96108f90673Sjfb } while (isspace(c = getc(f1))); 96208f90673Sjfb do { 96308f90673Sjfb if (d == '\n') 96408f90673Sjfb break; 96508f90673Sjfb ctnew++; 96608f90673Sjfb } while (isspace(d = getc(f2))); 96708f90673Sjfb } else if (wflag) { 96808f90673Sjfb while (isspace(c) && c != '\n') { 96908f90673Sjfb c = getc(f1); 97008f90673Sjfb ctold++; 97108f90673Sjfb } 97208f90673Sjfb while (isspace(d) && d != '\n') { 97308f90673Sjfb d = getc(f2); 97408f90673Sjfb ctnew++; 97508f90673Sjfb } 97608f90673Sjfb } 97708f90673Sjfb if (chrtran[c] != chrtran[d]) { 97808f90673Sjfb jackpot++; 97908f90673Sjfb J[i] = 0; 98008f90673Sjfb if (c != '\n' && c != EOF) 98108f90673Sjfb ctold += skipline(f1); 98208f90673Sjfb if (d != '\n' && c != EOF) 98308f90673Sjfb ctnew += skipline(f2); 98408f90673Sjfb break; 98508f90673Sjfb } 98608f90673Sjfb if (c == '\n' || c == EOF) 98708f90673Sjfb break; 98808f90673Sjfb } 98908f90673Sjfb } else { 99008f90673Sjfb for (;;) { 99108f90673Sjfb ctold++; 99208f90673Sjfb ctnew++; 99308f90673Sjfb if ((c = getc(f1)) != (d = getc(f2))) { 99408f90673Sjfb /* jackpot++; */ 99508f90673Sjfb J[i] = 0; 99608f90673Sjfb if (c != '\n' && c != EOF) 99708f90673Sjfb ctold += skipline(f1); 99808f90673Sjfb if (d != '\n' && c != EOF) 99908f90673Sjfb ctnew += skipline(f2); 100008f90673Sjfb break; 100108f90673Sjfb } 100208f90673Sjfb if (c == '\n' || c == EOF) 100308f90673Sjfb break; 100408f90673Sjfb } 100508f90673Sjfb } 100608f90673Sjfb ixold[i] = ctold; 100708f90673Sjfb ixnew[j] = ctnew; 100808f90673Sjfb j++; 100908f90673Sjfb } 101008f90673Sjfb for (; j <= len[1]; j++) 101108f90673Sjfb ixnew[j] = ctnew += skipline(f2); 101208f90673Sjfb /* 101308f90673Sjfb * if (jackpot) 101408f90673Sjfb * fprintf(stderr, "jackpot\n"); 101508f90673Sjfb */ 101608f90673Sjfb } 101708f90673Sjfb 101808f90673Sjfb /* shellsort CACM #201 */ 101908f90673Sjfb static void 102008f90673Sjfb sort(struct line *a, int n) 102108f90673Sjfb { 102208f90673Sjfb struct line *ai, *aim, w; 102308f90673Sjfb int j, m = 0, k; 102408f90673Sjfb 102508f90673Sjfb if (n == 0) 102608f90673Sjfb return; 102708f90673Sjfb for (j = 1; j <= n; j *= 2) 102808f90673Sjfb m = 2 * j - 1; 102908f90673Sjfb for (m /= 2; m != 0; m /= 2) { 103008f90673Sjfb k = n - m; 103108f90673Sjfb for (j = 1; j <= k; j++) { 103208f90673Sjfb for (ai = &a[j]; ai > a; ai -= m) { 103308f90673Sjfb aim = &ai[m]; 103408f90673Sjfb if (aim < ai) 103508f90673Sjfb break; /* wraparound */ 103608f90673Sjfb if (aim->value > ai[0].value || 103708f90673Sjfb (aim->value == ai[0].value && 103808f90673Sjfb aim->serial > ai[0].serial)) 103908f90673Sjfb break; 104008f90673Sjfb w.value = ai[0].value; 104108f90673Sjfb ai[0].value = aim->value; 104208f90673Sjfb aim->value = w.value; 104308f90673Sjfb w.serial = ai[0].serial; 104408f90673Sjfb ai[0].serial = aim->serial; 104508f90673Sjfb aim->serial = w.serial; 104608f90673Sjfb } 104708f90673Sjfb } 104808f90673Sjfb } 104908f90673Sjfb } 105008f90673Sjfb 105108f90673Sjfb static void 105208f90673Sjfb unsort(struct line *f, int l, int *b) 105308f90673Sjfb { 105408f90673Sjfb int *a, i; 105508f90673Sjfb 105608f90673Sjfb a = malloc((l + 1) * sizeof(int)); 105708f90673Sjfb for (i = 1; i <= l; i++) 105808f90673Sjfb a[f[i].serial] = f[i].value; 105908f90673Sjfb for (i = 1; i <= l; i++) 106008f90673Sjfb b[i] = a[i]; 106108f90673Sjfb free(a); 106208f90673Sjfb } 106308f90673Sjfb 106408f90673Sjfb static int 106508f90673Sjfb skipline(FILE *f) 106608f90673Sjfb { 106708f90673Sjfb int i, c; 106808f90673Sjfb 106908f90673Sjfb for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 107008f90673Sjfb continue; 107108f90673Sjfb return (i); 107208f90673Sjfb } 107308f90673Sjfb 107408f90673Sjfb static void 107508f90673Sjfb output(const char *file1, FILE *f1, const char *file2, FILE *f2) 107608f90673Sjfb { 107708f90673Sjfb int m, i0, i1, j0, j1; 107808f90673Sjfb 107908f90673Sjfb rewind(f1); 108008f90673Sjfb rewind(f2); 108108f90673Sjfb m = len[0]; 108208f90673Sjfb J[0] = 0; 108308f90673Sjfb J[m + 1] = len[1] + 1; 108408f90673Sjfb for (i0 = 1; i0 <= m; i0 = i1 + 1) { 108508f90673Sjfb while (i0 <= m && J[i0] == J[i0 - 1] + 1) 108608f90673Sjfb i0++; 108708f90673Sjfb j0 = J[i0 - 1] + 1; 108808f90673Sjfb i1 = i0 - 1; 108908f90673Sjfb while (i1 < m && J[i1 + 1] == 0) 109008f90673Sjfb i1++; 109108f90673Sjfb j1 = J[i1 + 1] - 1; 109208f90673Sjfb J[i1] = j1; 109308f90673Sjfb change(file1, f1, file2, f2, i0, i1, j0, j1); 109408f90673Sjfb } 109508f90673Sjfb if (m == 0) 109608f90673Sjfb change(file1, f1, file2, f2, 1, 0, 1, len[1]); 109708f90673Sjfb if (format == D_IFDEF) { 109808f90673Sjfb for (;;) { 109908f90673Sjfb #define c i0 110008f90673Sjfb if ((c = getc(f1)) == EOF) 110108f90673Sjfb return; 110208f90673Sjfb putchar(c); 110308f90673Sjfb } 110408f90673Sjfb #undef c 110508f90673Sjfb } 110608f90673Sjfb if (anychange != 0) { 110708f90673Sjfb if (format == D_CONTEXT) 110808f90673Sjfb dump_context_vec(f1, f2); 110908f90673Sjfb else if (format == D_UNIFIED) 111008f90673Sjfb dump_unified_vec(f1, f2); 111108f90673Sjfb } 111208f90673Sjfb } 111308f90673Sjfb 111408f90673Sjfb static __inline void 111508f90673Sjfb range(int a, int b, char *separator) 111608f90673Sjfb { 111708f90673Sjfb printf("%d", a > b ? b : a); 111808f90673Sjfb if (a < b) 111908f90673Sjfb printf("%s%d", separator, b); 112008f90673Sjfb } 112108f90673Sjfb 112208f90673Sjfb static __inline void 112308f90673Sjfb uni_range(int a, int b) 112408f90673Sjfb { 112508f90673Sjfb if (a < b) 112608f90673Sjfb printf("%d,%d", a, b - a + 1); 112708f90673Sjfb else if (a == b) 112808f90673Sjfb printf("%d", b); 112908f90673Sjfb else 113008f90673Sjfb printf("%d,0", b); 113108f90673Sjfb } 113208f90673Sjfb 113308f90673Sjfb static char * 113408f90673Sjfb preadline(int fd, size_t len, off_t off) 113508f90673Sjfb { 113608f90673Sjfb char *line; 113708f90673Sjfb ssize_t nr; 113808f90673Sjfb 113908f90673Sjfb line = malloc(len + 1); 114008f90673Sjfb if (line == NULL) { 114108f90673Sjfb cvs_log(LP_ERRNO, "failed to allocate line"); 114208f90673Sjfb return (NULL); 114308f90673Sjfb } 114408f90673Sjfb if ((nr = pread(fd, line, len, off)) < 0) { 114508f90673Sjfb cvs_log(LP_ERRNO, "preadline failed"); 114608f90673Sjfb return (NULL); 114708f90673Sjfb } 114808f90673Sjfb line[nr] = '\0'; 114908f90673Sjfb return (line); 115008f90673Sjfb } 115108f90673Sjfb 115208f90673Sjfb static int 115308f90673Sjfb ignoreline(char *line) 115408f90673Sjfb { 115508f90673Sjfb int ret; 115608f90673Sjfb 115708f90673Sjfb ret = regexec(&ignore_re, line, 0, NULL, 0); 115808f90673Sjfb free(line); 115908f90673Sjfb return (ret == 0); /* if it matched, it should be ignored. */ 116008f90673Sjfb } 116108f90673Sjfb 116208f90673Sjfb /* 116308f90673Sjfb * Indicate that there is a difference between lines a and b of the from file 116408f90673Sjfb * to get to lines c to d of the to file. If a is greater then b then there 116508f90673Sjfb * are no lines in the from file involved and this means that there were 116608f90673Sjfb * lines appended (beginning at b). If c is greater than d then there are 116708f90673Sjfb * lines missing from the to file. 116808f90673Sjfb */ 116908f90673Sjfb static void 117008f90673Sjfb change(const char *file1, FILE *f1, const char *file2, FILE *f2, 117108f90673Sjfb int a, int b, int c, int d) 117208f90673Sjfb { 117308f90673Sjfb static size_t max_context = 64; 117408f90673Sjfb int i; 117508f90673Sjfb 117608f90673Sjfb if (format != D_IFDEF && a > b && c > d) 117708f90673Sjfb return; 117808f90673Sjfb if (ignore_pats != NULL) { 117908f90673Sjfb char *line; 118008f90673Sjfb /* 118108f90673Sjfb * All lines in the change, insert, or delete must 118208f90673Sjfb * match an ignore pattern for the change to be 118308f90673Sjfb * ignored. 118408f90673Sjfb */ 118508f90673Sjfb if (a <= b) { /* Changes and deletes. */ 118608f90673Sjfb for (i = a; i <= b; i++) { 118708f90673Sjfb line = preadline(fileno(f1), 118808f90673Sjfb ixold[i] - ixold[i - 1], ixold[i - 1]); 118908f90673Sjfb if (!ignoreline(line)) 119008f90673Sjfb goto proceed; 119108f90673Sjfb } 119208f90673Sjfb } 119308f90673Sjfb if (a > b || c <= d) { /* Changes and inserts. */ 119408f90673Sjfb for (i = c; i <= d; i++) { 119508f90673Sjfb line = preadline(fileno(f2), 119608f90673Sjfb ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 119708f90673Sjfb if (!ignoreline(line)) 119808f90673Sjfb goto proceed; 119908f90673Sjfb } 120008f90673Sjfb } 120108f90673Sjfb return; 120208f90673Sjfb } 120308f90673Sjfb proceed: 120408f90673Sjfb if (format == D_CONTEXT || format == D_UNIFIED) { 120508f90673Sjfb /* 120608f90673Sjfb * Allocate change records as needed. 120708f90673Sjfb */ 120808f90673Sjfb if (context_vec_ptr == context_vec_end - 1) { 120908f90673Sjfb ptrdiff_t offset = context_vec_ptr - context_vec_start; 121008f90673Sjfb max_context <<= 1; 121108f90673Sjfb context_vec_start = realloc(context_vec_start, 121208f90673Sjfb max_context * sizeof(struct context_vec)); 121308f90673Sjfb context_vec_end = context_vec_start + max_context; 121408f90673Sjfb context_vec_ptr = context_vec_start + offset; 121508f90673Sjfb } 121608f90673Sjfb if (anychange == 0) { 121708f90673Sjfb /* 121808f90673Sjfb * Print the context/unidiff header first time through. 121908f90673Sjfb */ 122008f90673Sjfb printf("%s %s %s", 122108f90673Sjfb format == D_CONTEXT ? "***" : "---", diff_file, 122208f90673Sjfb ctime(&stb1.st_mtime)); 122308f90673Sjfb printf("%s %s %s", 122408f90673Sjfb format == D_CONTEXT ? "---" : "+++", diff_file, 122508f90673Sjfb ctime(&stb2.st_mtime)); 122608f90673Sjfb anychange = 1; 122708f90673Sjfb } else if (a > context_vec_ptr->b + (2 * context) + 1 && 122808f90673Sjfb c > context_vec_ptr->d + (2 * context) + 1) { 122908f90673Sjfb /* 123008f90673Sjfb * If this change is more than 'context' lines from the 123108f90673Sjfb * previous change, dump the record and reset it. 123208f90673Sjfb */ 123308f90673Sjfb if (format == D_CONTEXT) 123408f90673Sjfb dump_context_vec(f1, f2); 123508f90673Sjfb else 123608f90673Sjfb dump_unified_vec(f1, f2); 123708f90673Sjfb } 123808f90673Sjfb context_vec_ptr++; 123908f90673Sjfb context_vec_ptr->a = a; 124008f90673Sjfb context_vec_ptr->b = b; 124108f90673Sjfb context_vec_ptr->c = c; 124208f90673Sjfb context_vec_ptr->d = d; 124308f90673Sjfb return; 124408f90673Sjfb } 124508f90673Sjfb if (anychange == 0) 124608f90673Sjfb anychange = 1; 124708f90673Sjfb switch (format) { 124808f90673Sjfb case D_BRIEF: 124908f90673Sjfb return; 125008f90673Sjfb case D_NORMAL: 125108f90673Sjfb range(a, b, ","); 125208f90673Sjfb putchar(a > b ? 'a' : c > d ? 'd' : 'c'); 125308f90673Sjfb if (format == D_NORMAL) 125408f90673Sjfb range(c, d, ","); 125508f90673Sjfb putchar('\n'); 125608f90673Sjfb break; 125708f90673Sjfb } 125808f90673Sjfb if (format == D_NORMAL || format == D_IFDEF) { 125908f90673Sjfb fetch(ixold, a, b, f1, '<', 1); 126008f90673Sjfb if (a <= b && c <= d && format == D_NORMAL) 126108f90673Sjfb puts("---"); 126208f90673Sjfb } 126308f90673Sjfb i = fetch(ixnew, c, d, f2, format == D_NORMAL ? '>' : '\0', 0); 126408f90673Sjfb if (inifdef) { 126508f90673Sjfb printf("#endif /* %s */\n", ifdefname); 126608f90673Sjfb inifdef = 0; 126708f90673Sjfb } 126808f90673Sjfb } 126908f90673Sjfb 127008f90673Sjfb static int 127108f90673Sjfb fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile) 127208f90673Sjfb { 127308f90673Sjfb int i, j, c, lastc, col, nc; 127408f90673Sjfb 127508f90673Sjfb /* 127608f90673Sjfb * When doing #ifdef's, copy down to current line 127708f90673Sjfb * if this is the first file, so that stuff makes it to output. 127808f90673Sjfb */ 127908f90673Sjfb if (format == D_IFDEF && oldfile) { 128008f90673Sjfb long curpos = ftell(lb); 128108f90673Sjfb /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 128208f90673Sjfb nc = f[a > b ? b : a - 1] - curpos; 128308f90673Sjfb for (i = 0; i < nc; i++) 128408f90673Sjfb putchar(getc(lb)); 128508f90673Sjfb } 128608f90673Sjfb if (a > b) 128708f90673Sjfb return (0); 128808f90673Sjfb if (format == D_IFDEF) { 128908f90673Sjfb if (inifdef) { 129008f90673Sjfb printf("#else /* %s%s */\n", 129108f90673Sjfb oldfile == 1 ? "!" : "", ifdefname); 129208f90673Sjfb } else { 129308f90673Sjfb if (oldfile) 129408f90673Sjfb printf("#ifndef %s\n", ifdefname); 129508f90673Sjfb else 129608f90673Sjfb printf("#ifdef %s\n", ifdefname); 129708f90673Sjfb } 129808f90673Sjfb inifdef = 1 + oldfile; 129908f90673Sjfb } 130008f90673Sjfb for (i = a; i <= b; i++) { 130108f90673Sjfb fseek(lb, f[i - 1], SEEK_SET); 130208f90673Sjfb nc = f[i] - f[i - 1]; 130308f90673Sjfb if (format != D_IFDEF && ch != '\0') { 130408f90673Sjfb putchar(ch); 130508f90673Sjfb if (Tflag && (format == D_NORMAL || format == D_CONTEXT 130608f90673Sjfb || format == D_UNIFIED)) 130708f90673Sjfb putchar('\t'); 130808f90673Sjfb else if (format != D_UNIFIED) 130908f90673Sjfb putchar(' '); 131008f90673Sjfb } 131108f90673Sjfb col = 0; 131208f90673Sjfb for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) { 131308f90673Sjfb if ((c = getc(lb)) == EOF) { 131408f90673Sjfb puts("\n\\ No newline at end of file"); 131508f90673Sjfb return (0); 131608f90673Sjfb } 131708f90673Sjfb if (c == '\t' && tflag) { 131808f90673Sjfb do { 131908f90673Sjfb putchar(' '); 132008f90673Sjfb } while (++col & 7); 132108f90673Sjfb } else { 132208f90673Sjfb putchar(c); 132308f90673Sjfb col++; 132408f90673Sjfb } 132508f90673Sjfb } 132608f90673Sjfb } 132708f90673Sjfb return (0); 132808f90673Sjfb } 132908f90673Sjfb 133008f90673Sjfb /* 133108f90673Sjfb * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 133208f90673Sjfb */ 133308f90673Sjfb static int 133408f90673Sjfb readhash(FILE *f) 133508f90673Sjfb { 133608f90673Sjfb int i, t, space; 133708f90673Sjfb int sum; 133808f90673Sjfb 133908f90673Sjfb sum = 1; 134008f90673Sjfb space = 0; 134108f90673Sjfb if (!bflag && !wflag) { 134208f90673Sjfb if (iflag) 134308f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 134408f90673Sjfb if (t == EOF) { 134508f90673Sjfb if (i == 0) 134608f90673Sjfb return (0); 134708f90673Sjfb break; 134808f90673Sjfb } 134908f90673Sjfb sum = sum * 127 + chrtran[t]; 135008f90673Sjfb } 135108f90673Sjfb else 135208f90673Sjfb for (i = 0; (t = getc(f)) != '\n'; i++) { 135308f90673Sjfb if (t == EOF) { 135408f90673Sjfb if (i == 0) 135508f90673Sjfb return (0); 135608f90673Sjfb break; 135708f90673Sjfb } 135808f90673Sjfb sum = sum * 127 + t; 135908f90673Sjfb } 136008f90673Sjfb } else { 136108f90673Sjfb for (i = 0;;) { 136208f90673Sjfb switch (t = getc(f)) { 136308f90673Sjfb case '\t': 136408f90673Sjfb case ' ': 136508f90673Sjfb space++; 136608f90673Sjfb continue; 136708f90673Sjfb default: 136808f90673Sjfb if (space && !wflag) { 136908f90673Sjfb i++; 137008f90673Sjfb space = 0; 137108f90673Sjfb } 137208f90673Sjfb sum = sum * 127 + chrtran[t]; 137308f90673Sjfb i++; 137408f90673Sjfb continue; 137508f90673Sjfb case EOF: 137608f90673Sjfb if (i == 0) 137708f90673Sjfb return (0); 137808f90673Sjfb /* FALLTHROUGH */ 137908f90673Sjfb case '\n': 138008f90673Sjfb break; 138108f90673Sjfb } 138208f90673Sjfb break; 138308f90673Sjfb } 138408f90673Sjfb } 138508f90673Sjfb /* 138608f90673Sjfb * There is a remote possibility that we end up with a zero sum. 138708f90673Sjfb * Zero is used as an EOF marker, so return 1 instead. 138808f90673Sjfb */ 138908f90673Sjfb return (sum == 0 ? 1 : sum); 139008f90673Sjfb } 139108f90673Sjfb 139208f90673Sjfb static int 139308f90673Sjfb asciifile(FILE *f) 139408f90673Sjfb { 139508f90673Sjfb char buf[BUFSIZ]; 139608f90673Sjfb int i, cnt; 139708f90673Sjfb 139808f90673Sjfb if (aflag || f == NULL) 139908f90673Sjfb return (1); 140008f90673Sjfb 140108f90673Sjfb rewind(f); 140208f90673Sjfb cnt = fread(buf, 1, sizeof(buf), f); 140308f90673Sjfb for (i = 0; i < cnt; i++) 140408f90673Sjfb if (!isprint(buf[i]) && !isspace(buf[i])) 140508f90673Sjfb return (0); 140608f90673Sjfb return (1); 140708f90673Sjfb } 140808f90673Sjfb 140908f90673Sjfb 141008f90673Sjfb /* dump accumulated "context" diff changes */ 141108f90673Sjfb static void 141208f90673Sjfb dump_context_vec(FILE *f1, FILE *f2) 141308f90673Sjfb { 141408f90673Sjfb struct context_vec *cvp = context_vec_start; 141508f90673Sjfb int lowa, upb, lowc, upd, do_output; 141608f90673Sjfb int a, b, c, d; 1417*dc6a6879Sjfb char ch; 141808f90673Sjfb 141908f90673Sjfb if (context_vec_start > context_vec_ptr) 142008f90673Sjfb return; 142108f90673Sjfb 142208f90673Sjfb b = d = 0; /* gcc */ 1423*dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1424*dc6a6879Sjfb upb = MIN(len[0], context_vec_ptr->b + context); 1425*dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1426*dc6a6879Sjfb upd = MIN(len[1], context_vec_ptr->d + context); 142708f90673Sjfb 142808f90673Sjfb printf("***************"); 142908f90673Sjfb printf("\n*** "); 143008f90673Sjfb range(lowa, upb, ","); 143108f90673Sjfb printf(" ****\n"); 143208f90673Sjfb 143308f90673Sjfb /* 143408f90673Sjfb * Output changes to the "old" file. The first loop suppresses 143508f90673Sjfb * output if there were no changes to the "old" file (we'll see 143608f90673Sjfb * the "old" lines as context in the "new" list). 143708f90673Sjfb */ 143808f90673Sjfb do_output = 0; 143908f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) 144008f90673Sjfb if (cvp->a <= cvp->b) { 144108f90673Sjfb cvp = context_vec_start; 144208f90673Sjfb do_output++; 144308f90673Sjfb break; 144408f90673Sjfb } 144508f90673Sjfb if (do_output) { 144608f90673Sjfb while (cvp <= context_vec_ptr) { 144708f90673Sjfb a = cvp->a; 144808f90673Sjfb b = cvp->b; 144908f90673Sjfb c = cvp->c; 145008f90673Sjfb d = cvp->d; 145108f90673Sjfb 145208f90673Sjfb if (a <= b && c <= d) 145308f90673Sjfb ch = 'c'; 145408f90673Sjfb else 145508f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 145608f90673Sjfb 145708f90673Sjfb if (ch == 'a') 145808f90673Sjfb fetch(ixold, lowa, b, f1, ' ', 0); 145908f90673Sjfb else { 146008f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 146108f90673Sjfb fetch(ixold, a, b, f1, 146208f90673Sjfb ch == 'c' ? '!' : '-', 0); 146308f90673Sjfb } 146408f90673Sjfb lowa = b + 1; 146508f90673Sjfb cvp++; 146608f90673Sjfb } 146708f90673Sjfb fetch(ixold, b + 1, upb, f1, ' ', 0); 146808f90673Sjfb } 146908f90673Sjfb /* output changes to the "new" file */ 147008f90673Sjfb printf("--- "); 147108f90673Sjfb range(lowc, upd, ","); 147208f90673Sjfb printf(" ----\n"); 147308f90673Sjfb 147408f90673Sjfb do_output = 0; 147508f90673Sjfb for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 147608f90673Sjfb if (cvp->c <= cvp->d) { 147708f90673Sjfb cvp = context_vec_start; 147808f90673Sjfb do_output++; 147908f90673Sjfb break; 148008f90673Sjfb } 148108f90673Sjfb if (do_output) { 148208f90673Sjfb while (cvp <= context_vec_ptr) { 148308f90673Sjfb a = cvp->a; 148408f90673Sjfb b = cvp->b; 148508f90673Sjfb c = cvp->c; 148608f90673Sjfb d = cvp->d; 148708f90673Sjfb 148808f90673Sjfb if (a <= b && c <= d) 148908f90673Sjfb ch = 'c'; 149008f90673Sjfb else 149108f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 149208f90673Sjfb 149308f90673Sjfb if (ch == 'd') 149408f90673Sjfb fetch(ixnew, lowc, d, f2, ' ', 0); 149508f90673Sjfb else { 149608f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 149708f90673Sjfb fetch(ixnew, c, d, f2, 149808f90673Sjfb ch == 'c' ? '!' : '+', 0); 149908f90673Sjfb } 150008f90673Sjfb lowc = d + 1; 150108f90673Sjfb cvp++; 150208f90673Sjfb } 150308f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 150408f90673Sjfb } 150508f90673Sjfb context_vec_ptr = context_vec_start - 1; 150608f90673Sjfb } 150708f90673Sjfb 150808f90673Sjfb /* dump accumulated "unified" diff changes */ 150908f90673Sjfb static void 151008f90673Sjfb dump_unified_vec(FILE *f1, FILE *f2) 151108f90673Sjfb { 151208f90673Sjfb struct context_vec *cvp = context_vec_start; 151308f90673Sjfb int lowa, upb, lowc, upd; 151408f90673Sjfb int a, b, c, d; 1515*dc6a6879Sjfb char ch; 151608f90673Sjfb 151708f90673Sjfb if (context_vec_start > context_vec_ptr) 151808f90673Sjfb return; 151908f90673Sjfb 152008f90673Sjfb b = d = 0; /* gcc */ 1521*dc6a6879Sjfb lowa = MAX(1, cvp->a - context); 1522*dc6a6879Sjfb upb = MIN(len[0], context_vec_ptr->b + context); 1523*dc6a6879Sjfb lowc = MAX(1, cvp->c - context); 1524*dc6a6879Sjfb upd = MIN(len[1], context_vec_ptr->d + context); 152508f90673Sjfb 152608f90673Sjfb fputs("@@ -", stdout); 152708f90673Sjfb uni_range(lowa, upb); 152808f90673Sjfb fputs(" +", stdout); 152908f90673Sjfb uni_range(lowc, upd); 153008f90673Sjfb fputs(" @@", stdout); 153108f90673Sjfb putchar('\n'); 153208f90673Sjfb 153308f90673Sjfb /* 153408f90673Sjfb * Output changes in "unified" diff format--the old and new lines 153508f90673Sjfb * are printed together. 153608f90673Sjfb */ 153708f90673Sjfb for (; cvp <= context_vec_ptr; cvp++) { 153808f90673Sjfb a = cvp->a; 153908f90673Sjfb b = cvp->b; 154008f90673Sjfb c = cvp->c; 154108f90673Sjfb d = cvp->d; 154208f90673Sjfb 154308f90673Sjfb /* 154408f90673Sjfb * c: both new and old changes 154508f90673Sjfb * d: only changes in the old file 154608f90673Sjfb * a: only changes in the new file 154708f90673Sjfb */ 154808f90673Sjfb if (a <= b && c <= d) 154908f90673Sjfb ch = 'c'; 155008f90673Sjfb else 155108f90673Sjfb ch = (a <= b) ? 'd' : 'a'; 155208f90673Sjfb 155308f90673Sjfb switch (ch) { 155408f90673Sjfb case 'c': 155508f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 155608f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 155708f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 155808f90673Sjfb break; 155908f90673Sjfb case 'd': 156008f90673Sjfb fetch(ixold, lowa, a - 1, f1, ' ', 0); 156108f90673Sjfb fetch(ixold, a, b, f1, '-', 0); 156208f90673Sjfb break; 156308f90673Sjfb case 'a': 156408f90673Sjfb fetch(ixnew, lowc, c - 1, f2, ' ', 0); 156508f90673Sjfb fetch(ixnew, c, d, f2, '+', 0); 156608f90673Sjfb break; 156708f90673Sjfb } 156808f90673Sjfb lowa = b + 1; 156908f90673Sjfb lowc = d + 1; 157008f90673Sjfb } 157108f90673Sjfb fetch(ixnew, d + 1, upd, f2, ' ', 0); 157208f90673Sjfb 157308f90673Sjfb context_vec_ptr = context_vec_start - 1; 157408f90673Sjfb } 1575