1*f74aa433Sray /* $OpenBSD: diff.c,v 1.18 2007/05/29 08:02:59 ray Exp $ */ 22dc36bedSjoris /* 32dc36bedSjoris * Copyright (C) Caldera International Inc. 2001-2002. 42dc36bedSjoris * All rights reserved. 52dc36bedSjoris * 62dc36bedSjoris * Redistribution and use in source and binary forms, with or without 72dc36bedSjoris * modification, are permitted provided that the following conditions 82dc36bedSjoris * are met: 92dc36bedSjoris * 1. Redistributions of source code and documentation must retain the above 102dc36bedSjoris * copyright notice, this list of conditions and the following disclaimer. 112dc36bedSjoris * 2. Redistributions in binary form must reproduce the above copyright 122dc36bedSjoris * notice, this list of conditions and the following disclaimer in the 132dc36bedSjoris * documentation and/or other materials provided with the distribution. 142dc36bedSjoris * 3. All advertising materials mentioning features or use of this software 152dc36bedSjoris * must display the following acknowledgement: 162dc36bedSjoris * This product includes software developed or owned by Caldera 172dc36bedSjoris * International, Inc. 182dc36bedSjoris * 4. Neither the name of Caldera International, Inc. nor the names of other 192dc36bedSjoris * contributors may be used to endorse or promote products derived from 202dc36bedSjoris * this software without specific prior written permission. 212dc36bedSjoris * 222dc36bedSjoris * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 232dc36bedSjoris * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 242dc36bedSjoris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 252dc36bedSjoris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 262dc36bedSjoris * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 272dc36bedSjoris * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 282dc36bedSjoris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 292dc36bedSjoris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 302dc36bedSjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 312dc36bedSjoris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 322dc36bedSjoris * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 332dc36bedSjoris * POSSIBILITY OF SUCH DAMAGE. 342dc36bedSjoris */ 352dc36bedSjoris /*- 362dc36bedSjoris * Copyright (c) 1991, 1993 372dc36bedSjoris * The Regents of the University of California. All rights reserved. 382dc36bedSjoris * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved. 392dc36bedSjoris * 402dc36bedSjoris * Redistribution and use in source and binary forms, with or without 412dc36bedSjoris * modification, are permitted provided that the following conditions 422dc36bedSjoris * are met: 432dc36bedSjoris * 1. Redistributions of source code must retain the above copyright 442dc36bedSjoris * notice, this list of conditions and the following disclaimer. 452dc36bedSjoris * 2. Redistributions in binary form must reproduce the above copyright 462dc36bedSjoris * notice, this list of conditions and the following disclaimer in the 472dc36bedSjoris * documentation and/or other materials provided with the distribution. 482dc36bedSjoris * 3. Neither the name of the University nor the names of its contributors 492dc36bedSjoris * may be used to endorse or promote products derived from this software 502dc36bedSjoris * without specific prior written permission. 512dc36bedSjoris * 522dc36bedSjoris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 532dc36bedSjoris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 542dc36bedSjoris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 552dc36bedSjoris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 562dc36bedSjoris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 572dc36bedSjoris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 582dc36bedSjoris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 592dc36bedSjoris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 602dc36bedSjoris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 612dc36bedSjoris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 622dc36bedSjoris * SUCH DAMAGE. 632dc36bedSjoris * 642dc36bedSjoris * @(#)diffreg.c 8.1 (Berkeley) 6/6/93 652dc36bedSjoris */ 662dc36bedSjoris /* 672dc36bedSjoris * Uses an algorithm due to Harold Stone, which finds 682dc36bedSjoris * a pair of longest identical subsequences in the two 692dc36bedSjoris * files. 702dc36bedSjoris * 712dc36bedSjoris * The major goal is to generate the match vector J. 722dc36bedSjoris * J[i] is the index of the line in file1 corresponding 732dc36bedSjoris * to line i file0. J[i] = 0 if there is no 742dc36bedSjoris * such line in file1. 752dc36bedSjoris * 762dc36bedSjoris * Lines are hashed so as to work in core. All potential 772dc36bedSjoris * matches are located by sorting the lines of each file 782dc36bedSjoris * on the hash (called ``value''). In particular, this 792dc36bedSjoris * collects the equivalence classes in file1 together. 802dc36bedSjoris * Subroutine equiv replaces the value of each line in 812dc36bedSjoris * file0 by the index of the first element of its 822dc36bedSjoris * matching equivalence in (the reordered) file1. 832dc36bedSjoris * To save space equiv squeezes file1 into a single 842dc36bedSjoris * array member in which the equivalence classes 852dc36bedSjoris * are simply concatenated, except that their first 862dc36bedSjoris * members are flagged by changing sign. 872dc36bedSjoris * 882dc36bedSjoris * Next the indices that point into member are unsorted into 892dc36bedSjoris * array class according to the original order of file0. 902dc36bedSjoris * 912dc36bedSjoris * The cleverness lies in routine stone. This marches 922dc36bedSjoris * through the lines of file0, developing a vector klist 932dc36bedSjoris * of "k-candidates". At step i a k-candidate is a matched 942dc36bedSjoris * pair of lines x,y (x in file0 y in file1) such that 952dc36bedSjoris * there is a common subsequence of length k 962dc36bedSjoris * between the first i lines of file0 and the first y 972dc36bedSjoris * lines of file1, but there is no such subsequence for 982dc36bedSjoris * any smaller y. x is the earliest possible mate to y 992dc36bedSjoris * that occurs in such a subsequence. 1002dc36bedSjoris * 1012dc36bedSjoris * Whenever any of the members of the equivalence class of 1022dc36bedSjoris * lines in file1 matable to a line in file0 has serial number 1032dc36bedSjoris * less than the y of some k-candidate, that k-candidate 1042dc36bedSjoris * with the smallest such y is replaced. The new 1052dc36bedSjoris * k-candidate is chained (via pred) to the current 1062dc36bedSjoris * k-1 candidate so that the actual subsequence can 1072dc36bedSjoris * be recovered. When a member has serial number greater 1082dc36bedSjoris * that the y of all k-candidates, the klist is extended. 1092dc36bedSjoris * At the end, the longest subsequence is pulled out 1102dc36bedSjoris * and placed in the array J by unravel 1112dc36bedSjoris * 1122dc36bedSjoris * With J in hand, the matches there recorded are 1132dc36bedSjoris * check'ed against reality to assure that no spurious 1142dc36bedSjoris * matches have crept in due to hashing. If they have, 1152dc36bedSjoris * they are broken, and "jackpot" is recorded--a harmless 1162dc36bedSjoris * matter except that a true match for a spuriously 1172dc36bedSjoris * mated line may now be unnecessarily reported as a change. 1182dc36bedSjoris * 1192dc36bedSjoris * Much of the complexity of the program comes simply 1202dc36bedSjoris * from trying to minimize core utilization and 1212dc36bedSjoris * maximize the range of doable problems by dynamically 1222dc36bedSjoris * allocating what is needed and reusing what is not. 1232dc36bedSjoris * The core requirements for problems larger than somewhat 1242dc36bedSjoris * are (in words) 2*length(file0) + length(file1) + 1252dc36bedSjoris * 3*(number of k-candidates installed), typically about 1262dc36bedSjoris * 6n words for files of length n. 1272dc36bedSjoris */ 1282dc36bedSjoris 1294781e2faSxsa #include <sys/param.h> 1304781e2faSxsa #include <sys/stat.h> 1314781e2faSxsa 1324781e2faSxsa #include <ctype.h> 1334781e2faSxsa #include <err.h> 1344781e2faSxsa #include <limits.h> 1354781e2faSxsa #include <stdarg.h> 1364781e2faSxsa #include <stddef.h> 1374781e2faSxsa #include <stdio.h> 1384781e2faSxsa #include <string.h> 1394781e2faSxsa #include <unistd.h> 1402dc36bedSjoris 1412dc36bedSjoris #include "buf.h" 1422dc36bedSjoris #include "diff.h" 1432dc36bedSjoris #include "xmalloc.h" 1442dc36bedSjoris 1452dc36bedSjoris struct cand { 1462dc36bedSjoris int x; 1472dc36bedSjoris int y; 1482dc36bedSjoris int pred; 1492dc36bedSjoris } cand; 1502dc36bedSjoris 1512dc36bedSjoris struct line { 1522dc36bedSjoris int serial; 1532dc36bedSjoris int value; 1542dc36bedSjoris } *file[2]; 1552dc36bedSjoris 1562dc36bedSjoris /* 1572dc36bedSjoris * The following struct is used to record change information when 1582dc36bedSjoris * doing a "context" or "unified" diff. (see routine "change" to 1592dc36bedSjoris * understand the highly mnemonic field names) 1602dc36bedSjoris */ 1612dc36bedSjoris struct context_vec { 1622dc36bedSjoris int a; /* start line in old file */ 1632dc36bedSjoris int b; /* end line in old file */ 1642dc36bedSjoris int c; /* start line in new file */ 1652dc36bedSjoris int d; /* end line in new file */ 1662dc36bedSjoris }; 1672dc36bedSjoris 1682dc36bedSjoris struct diff_arg { 1692dc36bedSjoris char *rev1; 1702dc36bedSjoris char *rev2; 1712dc36bedSjoris char *date1; 1722dc36bedSjoris char *date2; 1732dc36bedSjoris }; 1742dc36bedSjoris 175f5f501bbSmillert static void output(FILE *, FILE *, int); 176f5f501bbSmillert static void check(FILE *, FILE *, int); 1772dc36bedSjoris static void range(int, int, char *); 1782dc36bedSjoris static void uni_range(int, int); 179f5f501bbSmillert static void dump_context_vec(FILE *, FILE *, int); 180f5f501bbSmillert static void dump_unified_vec(FILE *, FILE *, int); 181f5f501bbSmillert static int prepare(int, FILE *, off_t, int); 1822dc36bedSjoris static void prune(void); 1832dc36bedSjoris static void equiv(struct line *, int, struct line *, int, int *); 1842dc36bedSjoris static void unravel(int); 1852dc36bedSjoris static void unsort(struct line *, int, int *); 186f5f501bbSmillert static void change(FILE *, FILE *, int, int, int, int, int); 1872dc36bedSjoris static void sort(struct line *, int); 1882dc36bedSjoris static int ignoreline(char *); 1892dc36bedSjoris static int asciifile(FILE *); 190f5f501bbSmillert static void fetch(long *, int, int, FILE *, int, int, int); 1912dc36bedSjoris static int newcand(int, int, int); 1922dc36bedSjoris static int search(int *, int, int); 1932dc36bedSjoris static int skipline(FILE *); 1942dc36bedSjoris static int isqrt(int); 195f5f501bbSmillert static int stone(int *, int, int *, int *, int); 196f5f501bbSmillert static int readhash(FILE *, int); 1972dc36bedSjoris static int files_differ(FILE *, FILE *); 1982dc36bedSjoris static char *match_function(const long *, int, FILE *); 1992dc36bedSjoris static char *preadline(int, size_t, off_t); 2002dc36bedSjoris 2012dc36bedSjoris 202f5f501bbSmillert int diff_context = 3; 2032dc36bedSjoris int diff_format = D_NORMAL; 2042dc36bedSjoris char *diff_file = NULL; 2052dc36bedSjoris RCSNUM *diff_rev1 = NULL; 2062dc36bedSjoris RCSNUM *diff_rev2 = NULL; 207f5f501bbSmillert char diffargs[512]; /* XXX */ 2082dc36bedSjoris static struct stat stb1, stb2; 209f5f501bbSmillert static char *ifdefname; 210f5f501bbSmillert regex_t *diff_ignore_re; 2112dc36bedSjoris 2122dc36bedSjoris static int *J; /* will be overlaid on class */ 2132dc36bedSjoris static int *class; /* will be overlaid on file[0] */ 2142dc36bedSjoris static int *klist; /* will be overlaid on file[0] after class */ 2152dc36bedSjoris static int *member; /* will be overlaid on file[1] */ 2162dc36bedSjoris static int clen; 2172dc36bedSjoris static int inifdef; /* whether or not we are in a #ifdef block */ 2182dc36bedSjoris static int diff_len[2]; 2192dc36bedSjoris static int pref, suff; /* length of prefix and suffix */ 2202dc36bedSjoris static int slen[2]; 2212dc36bedSjoris static int anychange; 2222dc36bedSjoris static long *ixnew; /* will be overlaid on file[1] */ 2232dc36bedSjoris static long *ixold; /* will be overlaid on klist */ 2242dc36bedSjoris static struct cand *clist; /* merely a free storage pot for candidates */ 2252dc36bedSjoris static int clistlen; /* the length of clist */ 2262dc36bedSjoris static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */ 2272dc36bedSjoris static u_char *chrtran; /* translation table for case-folding */ 2282dc36bedSjoris static struct context_vec *context_vec_start; 2292dc36bedSjoris static struct context_vec *context_vec_end; 2302dc36bedSjoris static struct context_vec *context_vec_ptr; 2312dc36bedSjoris 232e22e6974Sxsa #define FUNCTION_CONTEXT_SIZE 55 2332dc36bedSjoris static char lastbuf[FUNCTION_CONTEXT_SIZE]; 2342dc36bedSjoris static int lastline; 2352dc36bedSjoris static int lastmatchline; 2362dc36bedSjoris BUF *diffbuf = NULL; 2372dc36bedSjoris 2382dc36bedSjoris /* 2392dc36bedSjoris * chrtran points to one of 2 translation tables: cup2low if folding upper to 2402dc36bedSjoris * lower case clow2low if not folding case 2412dc36bedSjoris */ 2422dc36bedSjoris u_char clow2low[256] = { 2432dc36bedSjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2442dc36bedSjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2452dc36bedSjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2462dc36bedSjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2472dc36bedSjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2482dc36bedSjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 2492dc36bedSjoris 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 2502dc36bedSjoris 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 2512dc36bedSjoris 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 2522dc36bedSjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2532dc36bedSjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2542dc36bedSjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2552dc36bedSjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2562dc36bedSjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2572dc36bedSjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2582dc36bedSjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2592dc36bedSjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2602dc36bedSjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2612dc36bedSjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2622dc36bedSjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2632dc36bedSjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2642dc36bedSjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2652dc36bedSjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2662dc36bedSjoris 0xfd, 0xfe, 0xff 2672dc36bedSjoris }; 2682dc36bedSjoris 2692dc36bedSjoris u_char cup2low[256] = { 2702dc36bedSjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 2712dc36bedSjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 2722dc36bedSjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 2732dc36bedSjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 2742dc36bedSjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 2752dc36bedSjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61, 2762dc36bedSjoris 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 2772dc36bedSjoris 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 2782dc36bedSjoris 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62, 2792dc36bedSjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 2802dc36bedSjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 2812dc36bedSjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 2822dc36bedSjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 2832dc36bedSjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 2842dc36bedSjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 2852dc36bedSjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 2862dc36bedSjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 2872dc36bedSjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 2882dc36bedSjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 2892dc36bedSjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 2902dc36bedSjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 2912dc36bedSjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 2922dc36bedSjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 2932dc36bedSjoris 0xfd, 0xfe, 0xff 2942dc36bedSjoris }; 2952dc36bedSjoris 2962dc36bedSjoris int 297f5f501bbSmillert rcs_diffreg(const char *file1, const char *file2, BUF *out, int flags) 2982dc36bedSjoris { 2992dc36bedSjoris FILE *f1, *f2; 3002dc36bedSjoris int i, rval; 3012dc36bedSjoris 3022dc36bedSjoris f1 = f2 = NULL; 3032dc36bedSjoris rval = D_SAME; 3042dc36bedSjoris anychange = 0; 3052dc36bedSjoris lastline = 0; 3062dc36bedSjoris lastmatchline = 0; 3072dc36bedSjoris context_vec_ptr = context_vec_start - 1; 308f5f501bbSmillert if (flags & D_IGNORECASE) 309f5f501bbSmillert chrtran = cup2low; 310f5f501bbSmillert else 311f5f501bbSmillert chrtran = clow2low; 3122dc36bedSjoris if (out != NULL) 3132dc36bedSjoris diffbuf = out; 3142dc36bedSjoris 3152dc36bedSjoris f1 = fopen(file1, "r"); 3162dc36bedSjoris if (f1 == NULL) { 3172dc36bedSjoris warn("%s", file1); 3182dc36bedSjoris goto closem; 3192dc36bedSjoris } 3202dc36bedSjoris 3212dc36bedSjoris f2 = fopen(file2, "r"); 3222dc36bedSjoris if (f2 == NULL) { 3232dc36bedSjoris warn("%s", file2); 3242dc36bedSjoris goto closem; 3252dc36bedSjoris } 3262dc36bedSjoris 327ccac42f6Sray if (fstat(fileno(f1), &stb1) < 0) { 3282dc36bedSjoris warn("%s", file1); 3292dc36bedSjoris goto closem; 3302dc36bedSjoris } 3312dc36bedSjoris 332ccac42f6Sray if (fstat(fileno(f2), &stb2) < 0) { 3332dc36bedSjoris warn("%s", file2); 3342dc36bedSjoris goto closem; 3352dc36bedSjoris } 3362dc36bedSjoris 337616468a8Sray switch (files_differ(f1, f2)) { 338616468a8Sray case 1: 339616468a8Sray break; 340616468a8Sray case -1: 341616468a8Sray rval = D_ERROR; 342616468a8Sray /* FALLTHROUGH */ 343616468a8Sray case 0: 3442dc36bedSjoris goto closem; 345616468a8Sray default: 346616468a8Sray errx(D_ERROR, "files_differ: invalid case"); 347616468a8Sray } 3482dc36bedSjoris 349f5f501bbSmillert if ((flags & D_FORCEASCII) == 0 && 350f5f501bbSmillert (!asciifile(f1) || !asciifile(f2))) { 3511fb625bfSxsa rval = D_ERROR; 3522dc36bedSjoris goto closem; 3532dc36bedSjoris } 3542dc36bedSjoris 355f5f501bbSmillert if (prepare(0, f1, stb1.st_size, flags) < 0 || 356f5f501bbSmillert prepare(1, f2, stb2.st_size, flags) < 0) { 3572dc36bedSjoris goto closem; 3582dc36bedSjoris } 3592dc36bedSjoris 3602dc36bedSjoris prune(); 3612dc36bedSjoris sort(sfile[0], slen[0]); 3622dc36bedSjoris sort(sfile[1], slen[1]); 3632dc36bedSjoris 3642dc36bedSjoris member = (int *)file[1]; 3652dc36bedSjoris equiv(sfile[0], slen[0], sfile[1], slen[1], member); 36680566be2Sray member = xrealloc(member, slen[1] + 2, sizeof(*member)); 3672dc36bedSjoris 3682dc36bedSjoris class = (int *)file[0]; 3692dc36bedSjoris unsort(sfile[0], slen[0], class); 37080566be2Sray class = xrealloc(class, slen[0] + 2, sizeof(*class)); 3712dc36bedSjoris 3722dc36bedSjoris klist = xcalloc(slen[0] + 2, sizeof(*klist)); 3732dc36bedSjoris clen = 0; 3742dc36bedSjoris clistlen = 100; 3752dc36bedSjoris clist = xcalloc(clistlen, sizeof(*clist)); 3762dc36bedSjoris 377f5f501bbSmillert if ((i = stone(class, slen[0], member, klist, flags)) < 0) 3782dc36bedSjoris goto closem; 3792dc36bedSjoris 3802dc36bedSjoris xfree(member); 3812dc36bedSjoris xfree(class); 3822dc36bedSjoris 38380566be2Sray J = xrealloc(J, diff_len[0] + 2, sizeof(*J)); 3842dc36bedSjoris unravel(klist[i]); 3852dc36bedSjoris xfree(clist); 3862dc36bedSjoris xfree(klist); 3872dc36bedSjoris 38880566be2Sray ixold = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold)); 3892dc36bedSjoris 39080566be2Sray ixnew = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew)); 391f5f501bbSmillert check(f1, f2, flags); 392f5f501bbSmillert output(f1, f2, flags); 3932dc36bedSjoris 3942dc36bedSjoris closem: 3952dc36bedSjoris if (anychange == 1) { 3962dc36bedSjoris if (rval == D_SAME) 3972dc36bedSjoris rval = D_DIFFER; 3982dc36bedSjoris } 3992dc36bedSjoris if (f1 != NULL) 4002dc36bedSjoris fclose(f1); 4012dc36bedSjoris if (f2 != NULL) 4022dc36bedSjoris fclose(f2); 4032dc36bedSjoris 4042dc36bedSjoris return (rval); 4052dc36bedSjoris } 4062dc36bedSjoris 4072dc36bedSjoris /* 4082dc36bedSjoris * Check to see if the given files differ. 4092dc36bedSjoris * Returns 0 if they are the same, 1 if different, and -1 on error. 4102dc36bedSjoris * XXX - could use code from cmp(1) [faster] 4112dc36bedSjoris */ 4122dc36bedSjoris static int 4132dc36bedSjoris files_differ(FILE *f1, FILE *f2) 4142dc36bedSjoris { 4152dc36bedSjoris char buf1[BUFSIZ], buf2[BUFSIZ]; 4162dc36bedSjoris size_t i, j; 4172dc36bedSjoris 4182dc36bedSjoris if (stb1.st_size != stb2.st_size) 4192dc36bedSjoris return (1); 4202dc36bedSjoris for (;;) { 42185ea658bSray i = fread(buf1, 1, sizeof(buf1), f1); 42285ea658bSray j = fread(buf2, 1, sizeof(buf2), f2); 4232dc36bedSjoris if (i != j) 4242dc36bedSjoris return (1); 4252dc36bedSjoris if (i == 0 && j == 0) { 4262dc36bedSjoris if (ferror(f1) || ferror(f2)) 427616468a8Sray return (-1); 4282dc36bedSjoris return (0); 4292dc36bedSjoris } 4302dc36bedSjoris if (memcmp(buf1, buf2, i) != 0) 4312dc36bedSjoris return (1); 4322dc36bedSjoris } 4332dc36bedSjoris } 4342dc36bedSjoris 4352dc36bedSjoris static int 436f5f501bbSmillert prepare(int i, FILE *fd, off_t filesize, int flags) 4372dc36bedSjoris { 4382dc36bedSjoris struct line *p; 4392dc36bedSjoris int j, h; 4402dc36bedSjoris size_t sz; 4412dc36bedSjoris 4422dc36bedSjoris rewind(fd); 4432dc36bedSjoris 4442dc36bedSjoris sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25; 4452dc36bedSjoris if (sz < 100) 4462dc36bedSjoris sz = 100; 4472dc36bedSjoris 4482dc36bedSjoris p = xcalloc(sz + 3, sizeof(*p)); 449f5f501bbSmillert for (j = 0; (h = readhash(fd, flags));) { 4502dc36bedSjoris if (j == (int)sz) { 4512dc36bedSjoris sz = sz * 3 / 2; 45280566be2Sray p = xrealloc(p, sz + 3, sizeof(*p)); 4532dc36bedSjoris } 4542dc36bedSjoris p[++j].value = h; 4552dc36bedSjoris } 4562dc36bedSjoris diff_len[i] = j; 4572dc36bedSjoris file[i] = p; 4582dc36bedSjoris 4592dc36bedSjoris return (0); 4602dc36bedSjoris } 4612dc36bedSjoris 4622dc36bedSjoris static void 4632dc36bedSjoris prune(void) 4642dc36bedSjoris { 4652dc36bedSjoris int i, j; 4662dc36bedSjoris 4672dc36bedSjoris for (pref = 0; pref < diff_len[0] && pref < diff_len[1] && 4682dc36bedSjoris file[0][pref + 1].value == file[1][pref + 1].value; 4692dc36bedSjoris pref++) 4702dc36bedSjoris ; 4712dc36bedSjoris for (suff = 0; 4722dc36bedSjoris (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) && 4732dc36bedSjoris (file[0][diff_len[0] - suff].value == 4742dc36bedSjoris file[1][diff_len[1] - suff].value); 4752dc36bedSjoris suff++) 4762dc36bedSjoris ; 4772dc36bedSjoris for (j = 0; j < 2; j++) { 4782dc36bedSjoris sfile[j] = file[j] + pref; 4792dc36bedSjoris slen[j] = diff_len[j] - pref - suff; 4802dc36bedSjoris for (i = 0; i <= slen[j]; i++) 4812dc36bedSjoris sfile[j][i].serial = i; 4822dc36bedSjoris } 4832dc36bedSjoris } 4842dc36bedSjoris 4852dc36bedSjoris static void 4862dc36bedSjoris equiv(struct line *a, int n, struct line *b, int m, int *c) 4872dc36bedSjoris { 4882dc36bedSjoris int i, j; 4892dc36bedSjoris 4902dc36bedSjoris i = j = 1; 4912dc36bedSjoris while (i <= n && j <= m) { 4922dc36bedSjoris if (a[i].value < b[j].value) 4932dc36bedSjoris a[i++].value = 0; 4942dc36bedSjoris else if (a[i].value == b[j].value) 4952dc36bedSjoris a[i++].value = j; 4962dc36bedSjoris else 4972dc36bedSjoris j++; 4982dc36bedSjoris } 4992dc36bedSjoris while (i <= n) 5002dc36bedSjoris a[i++].value = 0; 5012dc36bedSjoris b[m + 1].value = 0; 5022dc36bedSjoris j = 0; 5032dc36bedSjoris while (++j <= m) { 5042dc36bedSjoris c[j] = -b[j].serial; 5052dc36bedSjoris while (b[j + 1].value == b[j].value) { 5062dc36bedSjoris j++; 5072dc36bedSjoris c[j] = b[j].serial; 5082dc36bedSjoris } 5092dc36bedSjoris } 5102dc36bedSjoris c[j] = -1; 5112dc36bedSjoris } 5122dc36bedSjoris 5132dc36bedSjoris /* Code taken from ping.c */ 5142dc36bedSjoris static int 5152dc36bedSjoris isqrt(int n) 5162dc36bedSjoris { 5172dc36bedSjoris int y, x = 1; 5182dc36bedSjoris 5192dc36bedSjoris if (n == 0) 5202dc36bedSjoris return (0); 5212dc36bedSjoris 5222dc36bedSjoris do { /* newton was a stinker */ 5232dc36bedSjoris y = x; 5242dc36bedSjoris x = n / x; 5252dc36bedSjoris x += y; 5262dc36bedSjoris x /= 2; 5272dc36bedSjoris } while (x - y > 1 || x - y < -1); 5282dc36bedSjoris 5292dc36bedSjoris return (x); 5302dc36bedSjoris } 5312dc36bedSjoris 5322dc36bedSjoris static int 533f5f501bbSmillert stone(int *a, int n, int *b, int *c, int flags) 5342dc36bedSjoris { 5352dc36bedSjoris int ret; 5362dc36bedSjoris int i, k, y, j, l; 5372dc36bedSjoris int oldc, tc, oldl; 5382dc36bedSjoris u_int numtries; 5392dc36bedSjoris 5402dc36bedSjoris /* XXX move the isqrt() out of the macro to avoid multiple calls */ 541c2ac0f30Sxsa const u_int bound = (flags & D_MINIMAL) ? UINT_MAX : 542c2ac0f30Sxsa MAX(256, (u_int)isqrt(n)); 5432dc36bedSjoris 5442dc36bedSjoris k = 0; 5452dc36bedSjoris if ((ret = newcand(0, 0, 0)) < 0) 5462dc36bedSjoris return (-1); 5472dc36bedSjoris c[0] = ret; 5482dc36bedSjoris for (i = 1; i <= n; i++) { 5492dc36bedSjoris j = a[i]; 5502dc36bedSjoris if (j == 0) 5512dc36bedSjoris continue; 5522dc36bedSjoris y = -b[j]; 5532dc36bedSjoris oldl = 0; 5542dc36bedSjoris oldc = c[0]; 5552dc36bedSjoris numtries = 0; 5562dc36bedSjoris do { 5572dc36bedSjoris if (y <= clist[oldc].y) 5582dc36bedSjoris continue; 5592dc36bedSjoris l = search(c, k, y); 5602dc36bedSjoris if (l != oldl + 1) 5612dc36bedSjoris oldc = c[l - 1]; 5622dc36bedSjoris if (l <= k) { 5632dc36bedSjoris if (clist[c[l]].y <= y) 5642dc36bedSjoris continue; 5652dc36bedSjoris tc = c[l]; 5662dc36bedSjoris if ((ret = newcand(i, y, oldc)) < 0) 5672dc36bedSjoris return (-1); 5682dc36bedSjoris c[l] = ret; 5692dc36bedSjoris oldc = tc; 5702dc36bedSjoris oldl = l; 5712dc36bedSjoris numtries++; 5722dc36bedSjoris } else { 5732dc36bedSjoris if ((ret = newcand(i, y, oldc)) < 0) 5742dc36bedSjoris return (-1); 5752dc36bedSjoris c[l] = ret; 5762dc36bedSjoris k++; 5772dc36bedSjoris break; 5782dc36bedSjoris } 5792dc36bedSjoris } while ((y = b[++j]) > 0 && numtries < bound); 5802dc36bedSjoris } 5812dc36bedSjoris return (k); 5822dc36bedSjoris } 5832dc36bedSjoris 5842dc36bedSjoris static int 5852dc36bedSjoris newcand(int x, int y, int pred) 5862dc36bedSjoris { 58780566be2Sray struct cand *q; 5882dc36bedSjoris 5892dc36bedSjoris if (clen == clistlen) { 590*f74aa433Sray clistlen = clistlen * 11 / 10; 591*f74aa433Sray clist = xrealloc(clist, clistlen, sizeof(*clist)); 5922dc36bedSjoris } 5932dc36bedSjoris q = clist + clen; 5942dc36bedSjoris q->x = x; 5952dc36bedSjoris q->y = y; 5962dc36bedSjoris q->pred = pred; 5972dc36bedSjoris return (clen++); 5982dc36bedSjoris } 5992dc36bedSjoris 6002dc36bedSjoris static int 6012dc36bedSjoris search(int *c, int k, int y) 6022dc36bedSjoris { 6032dc36bedSjoris int i, j, l, t; 6042dc36bedSjoris 6052dc36bedSjoris if (clist[c[k]].y < y) /* quick look for typical case */ 6062dc36bedSjoris return (k + 1); 6072dc36bedSjoris i = 0; 6082dc36bedSjoris j = k + 1; 6092dc36bedSjoris for (;;) { 6102dc36bedSjoris l = (i + j) / 2; 6112dc36bedSjoris if (l <= i) 6122dc36bedSjoris break; 6132dc36bedSjoris t = clist[c[l]].y; 6142dc36bedSjoris if (t > y) 6152dc36bedSjoris j = l; 6162dc36bedSjoris else if (t < y) 6172dc36bedSjoris i = l; 6182dc36bedSjoris else 6192dc36bedSjoris return (l); 6202dc36bedSjoris } 6212dc36bedSjoris return (l + 1); 6222dc36bedSjoris } 6232dc36bedSjoris 6242dc36bedSjoris static void 6252dc36bedSjoris unravel(int p) 6262dc36bedSjoris { 6272dc36bedSjoris struct cand *q; 6282dc36bedSjoris int i; 6292dc36bedSjoris 6302dc36bedSjoris for (i = 0; i <= diff_len[0]; i++) 6312dc36bedSjoris J[i] = i <= pref ? i : 6322dc36bedSjoris i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0; 6332dc36bedSjoris for (q = clist + p; q->y != 0; q = clist + q->pred) 6342dc36bedSjoris J[q->x + pref] = q->y + pref; 6352dc36bedSjoris } 6362dc36bedSjoris 6372dc36bedSjoris /* 6382dc36bedSjoris * Check does double duty: 6392dc36bedSjoris * 1. ferret out any fortuitous correspondences due 6402dc36bedSjoris * to confounding by hashing (which result in "jackpot") 6412dc36bedSjoris * 2. collect random access indexes to the two files 6422dc36bedSjoris */ 6432dc36bedSjoris static void 644f5f501bbSmillert check(FILE *f1, FILE *f2, int flags) 6452dc36bedSjoris { 6462dc36bedSjoris int i, j, jackpot, c, d; 6472dc36bedSjoris long ctold, ctnew; 6482dc36bedSjoris 6492dc36bedSjoris rewind(f1); 6502dc36bedSjoris rewind(f2); 6512dc36bedSjoris j = 1; 6522dc36bedSjoris ixold[0] = ixnew[0] = 0; 6532dc36bedSjoris jackpot = 0; 6542dc36bedSjoris ctold = ctnew = 0; 6552dc36bedSjoris for (i = 1; i <= diff_len[0]; i++) { 6562dc36bedSjoris if (J[i] == 0) { 6572dc36bedSjoris ixold[i] = ctold += skipline(f1); 6582dc36bedSjoris continue; 6592dc36bedSjoris } 6602dc36bedSjoris while (j < J[i]) { 6612dc36bedSjoris ixnew[j] = ctnew += skipline(f2); 6622dc36bedSjoris j++; 6632dc36bedSjoris } 664f5f501bbSmillert if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE)) { 6652dc36bedSjoris for (;;) { 6662dc36bedSjoris c = getc(f1); 6672dc36bedSjoris d = getc(f2); 6682dc36bedSjoris /* 6692dc36bedSjoris * GNU diff ignores a missing newline 670f5f501bbSmillert * in one file for -b or -w. 6712dc36bedSjoris */ 672f5f501bbSmillert if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) && 6732dc36bedSjoris ((c == EOF && d == '\n') || 6742dc36bedSjoris (c == '\n' && d == EOF))) { 6752dc36bedSjoris break; 6762dc36bedSjoris } 6772dc36bedSjoris ctold++; 6782dc36bedSjoris ctnew++; 679f5f501bbSmillert if ((flags & D_FOLDBLANKS) && isspace(c) && 680f5f501bbSmillert isspace(d)) { 6812dc36bedSjoris do { 6822dc36bedSjoris if (c == '\n') 6832dc36bedSjoris break; 6842dc36bedSjoris ctold++; 6852dc36bedSjoris } while (isspace(c = getc(f1))); 6862dc36bedSjoris do { 6872dc36bedSjoris if (d == '\n') 6882dc36bedSjoris break; 6892dc36bedSjoris ctnew++; 6902dc36bedSjoris } while (isspace(d = getc(f2))); 691f5f501bbSmillert } else if ((flags & D_IGNOREBLANKS)) { 6922dc36bedSjoris while (isspace(c) && c != '\n') { 6932dc36bedSjoris c = getc(f1); 6942dc36bedSjoris ctold++; 6952dc36bedSjoris } 6962dc36bedSjoris while (isspace(d) && d != '\n') { 6972dc36bedSjoris d = getc(f2); 6982dc36bedSjoris ctnew++; 6992dc36bedSjoris } 7002dc36bedSjoris } 7012dc36bedSjoris if (chrtran[c] != chrtran[d]) { 7022dc36bedSjoris jackpot++; 7032dc36bedSjoris J[i] = 0; 7042dc36bedSjoris if (c != '\n' && c != EOF) 7052dc36bedSjoris ctold += skipline(f1); 7062dc36bedSjoris if (d != '\n' && c != EOF) 7072dc36bedSjoris ctnew += skipline(f2); 7082dc36bedSjoris break; 7092dc36bedSjoris } 7102dc36bedSjoris if (c == '\n' || c == EOF) 7112dc36bedSjoris break; 7122dc36bedSjoris } 7132dc36bedSjoris } else { 7142dc36bedSjoris for (;;) { 7152dc36bedSjoris ctold++; 7162dc36bedSjoris ctnew++; 7172dc36bedSjoris if ((c = getc(f1)) != (d = getc(f2))) { 7182dc36bedSjoris /* jackpot++; */ 7192dc36bedSjoris J[i] = 0; 7202dc36bedSjoris if (c != '\n' && c != EOF) 7212dc36bedSjoris ctold += skipline(f1); 7222dc36bedSjoris if (d != '\n' && c != EOF) 7232dc36bedSjoris ctnew += skipline(f2); 7242dc36bedSjoris break; 7252dc36bedSjoris } 7262dc36bedSjoris if (c == '\n' || c == EOF) 7272dc36bedSjoris break; 7282dc36bedSjoris } 7292dc36bedSjoris } 7302dc36bedSjoris ixold[i] = ctold; 7312dc36bedSjoris ixnew[j] = ctnew; 7322dc36bedSjoris j++; 7332dc36bedSjoris } 7342dc36bedSjoris for (; j <= diff_len[1]; j++) 7352dc36bedSjoris ixnew[j] = ctnew += skipline(f2); 7362dc36bedSjoris /* 7372dc36bedSjoris * if (jackpot != 0) 7382dc36bedSjoris * printf("jackpot\n"); 7392dc36bedSjoris */ 7402dc36bedSjoris } 7412dc36bedSjoris 7422dc36bedSjoris /* shellsort CACM #201 */ 7432dc36bedSjoris static void 7442dc36bedSjoris sort(struct line *a, int n) 7452dc36bedSjoris { 7462dc36bedSjoris struct line *ai, *aim, w; 7472dc36bedSjoris int j, m = 0, k; 7482dc36bedSjoris 7492dc36bedSjoris if (n == 0) 7502dc36bedSjoris return; 7512dc36bedSjoris for (j = 1; j <= n; j *= 2) 7522dc36bedSjoris m = 2 * j - 1; 7532dc36bedSjoris for (m /= 2; m != 0; m /= 2) { 7542dc36bedSjoris k = n - m; 7552dc36bedSjoris for (j = 1; j <= k; j++) { 7562dc36bedSjoris for (ai = &a[j]; ai > a; ai -= m) { 7572dc36bedSjoris aim = &ai[m]; 7582dc36bedSjoris if (aim < ai) 7592dc36bedSjoris break; /* wraparound */ 7602dc36bedSjoris if (aim->value > ai[0].value || 7612dc36bedSjoris (aim->value == ai[0].value && 7622dc36bedSjoris aim->serial > ai[0].serial)) 7632dc36bedSjoris break; 7642dc36bedSjoris w.value = ai[0].value; 7652dc36bedSjoris ai[0].value = aim->value; 7662dc36bedSjoris aim->value = w.value; 7672dc36bedSjoris w.serial = ai[0].serial; 7682dc36bedSjoris ai[0].serial = aim->serial; 7692dc36bedSjoris aim->serial = w.serial; 7702dc36bedSjoris } 7712dc36bedSjoris } 7722dc36bedSjoris } 7732dc36bedSjoris } 7742dc36bedSjoris 7752dc36bedSjoris static void 7762dc36bedSjoris unsort(struct line *f, int l, int *b) 7772dc36bedSjoris { 7782dc36bedSjoris int *a, i; 7792dc36bedSjoris 7802dc36bedSjoris a = xcalloc(l + 1, sizeof(*a)); 7812dc36bedSjoris for (i = 1; i <= l; i++) 7822dc36bedSjoris a[f[i].serial] = f[i].value; 7832dc36bedSjoris for (i = 1; i <= l; i++) 7842dc36bedSjoris b[i] = a[i]; 7852dc36bedSjoris xfree(a); 7862dc36bedSjoris } 7872dc36bedSjoris 7882dc36bedSjoris static int 7892dc36bedSjoris skipline(FILE *f) 7902dc36bedSjoris { 7912dc36bedSjoris int i, c; 7922dc36bedSjoris 7932dc36bedSjoris for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++) 7942dc36bedSjoris continue; 7952dc36bedSjoris return (i); 7962dc36bedSjoris } 7972dc36bedSjoris 7982dc36bedSjoris static void 799f5f501bbSmillert output(FILE *f1, FILE *f2, int flags) 8002dc36bedSjoris { 8012dc36bedSjoris int m, i0, i1, j0, j1; 8022dc36bedSjoris 8032dc36bedSjoris rewind(f1); 8042dc36bedSjoris rewind(f2); 8052dc36bedSjoris m = diff_len[0]; 8062dc36bedSjoris J[0] = 0; 8072dc36bedSjoris J[m + 1] = diff_len[1] + 1; 8082dc36bedSjoris for (i0 = 1; i0 <= m; i0 = i1 + 1) { 8092dc36bedSjoris while (i0 <= m && J[i0] == J[i0 - 1] + 1) 8102dc36bedSjoris i0++; 8112dc36bedSjoris j0 = J[i0 - 1] + 1; 8122dc36bedSjoris i1 = i0 - 1; 8132dc36bedSjoris while (i1 < m && J[i1 + 1] == 0) 8142dc36bedSjoris i1++; 8152dc36bedSjoris j1 = J[i1 + 1] - 1; 8162dc36bedSjoris J[i1] = j1; 817f5f501bbSmillert change(f1, f2, i0, i1, j0, j1, flags); 8182dc36bedSjoris } 8192dc36bedSjoris if (m == 0) 820f5f501bbSmillert change(f1, f2, 1, 0, 1, diff_len[1], flags); 8212dc36bedSjoris if (diff_format == D_IFDEF) { 8222dc36bedSjoris for (;;) { 8232dc36bedSjoris #define c i0 8242dc36bedSjoris if ((c = getc(f1)) == EOF) 8252dc36bedSjoris return; 8262dc36bedSjoris diff_output("%c", c); 8272dc36bedSjoris } 8282dc36bedSjoris #undef c 8292dc36bedSjoris } 8302dc36bedSjoris if (anychange != 0) { 8312dc36bedSjoris if (diff_format == D_CONTEXT) 832f5f501bbSmillert dump_context_vec(f1, f2, flags); 8332dc36bedSjoris else if (diff_format == D_UNIFIED) 834f5f501bbSmillert dump_unified_vec(f1, f2, flags); 8352dc36bedSjoris } 8362dc36bedSjoris } 8372dc36bedSjoris 838ccac42f6Sray static void 8392dc36bedSjoris range(int a, int b, char *separator) 8402dc36bedSjoris { 8412dc36bedSjoris diff_output("%d", a > b ? b : a); 8422dc36bedSjoris if (a < b) 8432dc36bedSjoris diff_output("%s%d", separator, b); 8442dc36bedSjoris } 8452dc36bedSjoris 846ccac42f6Sray static void 8472dc36bedSjoris uni_range(int a, int b) 8482dc36bedSjoris { 8492dc36bedSjoris if (a < b) 8502dc36bedSjoris diff_output("%d,%d", a, b - a + 1); 8512dc36bedSjoris else if (a == b) 8522dc36bedSjoris diff_output("%d", b); 8532dc36bedSjoris else 8542dc36bedSjoris diff_output("%d,0", b); 8552dc36bedSjoris } 8562dc36bedSjoris 8572dc36bedSjoris static char * 8582dc36bedSjoris preadline(int fd, size_t rlen, off_t off) 8592dc36bedSjoris { 8602dc36bedSjoris char *line; 8612dc36bedSjoris ssize_t nr; 8622dc36bedSjoris 8632dc36bedSjoris line = xmalloc(rlen + 1); 8642dc36bedSjoris if ((nr = pread(fd, line, rlen, off)) < 0) { 8652dc36bedSjoris warn("preadline failed"); 86610e28a1fSray xfree(line); 8672dc36bedSjoris return (NULL); 8682dc36bedSjoris } 8692dc36bedSjoris line[nr] = '\0'; 8702dc36bedSjoris return (line); 8712dc36bedSjoris } 8722dc36bedSjoris 8732dc36bedSjoris static int 8742dc36bedSjoris ignoreline(char *line) 8752dc36bedSjoris { 8762dc36bedSjoris int ret; 8772dc36bedSjoris 878f5f501bbSmillert ret = regexec(diff_ignore_re, line, 0, NULL, 0); 8792dc36bedSjoris xfree(line); 8802dc36bedSjoris return (ret == 0); /* if it matched, it should be ignored. */ 8812dc36bedSjoris } 8822dc36bedSjoris 8832dc36bedSjoris /* 8842dc36bedSjoris * Indicate that there is a difference between lines a and b of the from file 8852dc36bedSjoris * to get to lines c to d of the to file. If a is greater then b then there 8862dc36bedSjoris * are no lines in the from file involved and this means that there were 8872dc36bedSjoris * lines appended (beginning at b). If c is greater than d then there are 8882dc36bedSjoris * lines missing from the to file. 8892dc36bedSjoris */ 8902dc36bedSjoris static void 891f5f501bbSmillert change(FILE *f1, FILE *f2, int a, int b, int c, int d, int flags) 8922dc36bedSjoris { 8932dc36bedSjoris int i; 8942dc36bedSjoris static size_t max_context = 64; 8952dc36bedSjoris char buf[64]; 8962dc36bedSjoris struct tm *t; 8972dc36bedSjoris 8982dc36bedSjoris if (diff_format != D_IFDEF && a > b && c > d) 8992dc36bedSjoris return; 900f5f501bbSmillert if (diff_ignore_re != NULL) { 9012dc36bedSjoris char *line; 9022dc36bedSjoris /* 9032dc36bedSjoris * All lines in the change, insert, or delete must 9042dc36bedSjoris * match an ignore pattern for the change to be 9052dc36bedSjoris * ignored. 9062dc36bedSjoris */ 9072dc36bedSjoris if (a <= b) { /* Changes and deletes. */ 9082dc36bedSjoris for (i = a; i <= b; i++) { 9092dc36bedSjoris line = preadline(fileno(f1), 9102dc36bedSjoris ixold[i] - ixold[i - 1], ixold[i - 1]); 9112dc36bedSjoris if (!ignoreline(line)) 9122dc36bedSjoris goto proceed; 9132dc36bedSjoris } 9142dc36bedSjoris } 9152dc36bedSjoris if (a > b || c <= d) { /* Changes and inserts. */ 9162dc36bedSjoris for (i = c; i <= d; i++) { 9172dc36bedSjoris line = preadline(fileno(f2), 9182dc36bedSjoris ixnew[i] - ixnew[i - 1], ixnew[i - 1]); 9192dc36bedSjoris if (!ignoreline(line)) 9202dc36bedSjoris goto proceed; 9212dc36bedSjoris } 9222dc36bedSjoris } 9232dc36bedSjoris return; 9242dc36bedSjoris } 9252dc36bedSjoris proceed: 9262dc36bedSjoris if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) { 9272dc36bedSjoris /* 9282dc36bedSjoris * Allocate change records as needed. 9292dc36bedSjoris */ 9302dc36bedSjoris if (context_vec_ptr == context_vec_end - 1) { 9312dc36bedSjoris ptrdiff_t offset = context_vec_ptr - context_vec_start; 9322dc36bedSjoris max_context <<= 1; 93380566be2Sray context_vec_start = xrealloc(context_vec_start, 93480566be2Sray max_context, sizeof(*context_vec_start)); 9352dc36bedSjoris context_vec_end = context_vec_start + max_context; 9362dc36bedSjoris context_vec_ptr = context_vec_start + offset; 9372dc36bedSjoris } 9382dc36bedSjoris if (anychange == 0) { 9392dc36bedSjoris /* 9402dc36bedSjoris * Print the context/unidiff header first time through. 9412dc36bedSjoris */ 9422dc36bedSjoris t = localtime(&stb1.st_mtime); 9432dc36bedSjoris (void)strftime(buf, sizeof(buf), 9442dc36bedSjoris "%Y/%m/%d %H:%M:%S", t); 9452dc36bedSjoris 9462dc36bedSjoris diff_output("%s %s %s", 9472dc36bedSjoris diff_format == D_CONTEXT ? "***" : "---", diff_file, 9482dc36bedSjoris buf); 9492dc36bedSjoris 9502dc36bedSjoris if (diff_rev1 != NULL) { 9512dc36bedSjoris rcsnum_tostr(diff_rev1, buf, sizeof(buf)); 9522dc36bedSjoris diff_output("\t%s", buf); 9532dc36bedSjoris } 9542dc36bedSjoris 9552dc36bedSjoris printf("\n"); 9562dc36bedSjoris 9572dc36bedSjoris t = localtime(&stb2.st_mtime); 9582dc36bedSjoris (void)strftime(buf, sizeof(buf), 9592dc36bedSjoris "%Y/%m/%d %H:%M:%S", t); 9602dc36bedSjoris 9612dc36bedSjoris diff_output("%s %s %s", 9622dc36bedSjoris diff_format == D_CONTEXT ? "---" : "+++", diff_file, 9632dc36bedSjoris buf); 9642dc36bedSjoris 9652dc36bedSjoris if (diff_rev2 != NULL) { 9662dc36bedSjoris rcsnum_tostr(diff_rev2, buf, sizeof(buf)); 9672dc36bedSjoris diff_output("\t%s", buf); 9682dc36bedSjoris } 9692dc36bedSjoris 9702dc36bedSjoris printf("\n"); 9712dc36bedSjoris anychange = 1; 972f5f501bbSmillert } else if (a > context_vec_ptr->b + (2 * diff_context) + 1 && 973f5f501bbSmillert c > context_vec_ptr->d + (2 * diff_context) + 1) { 9742dc36bedSjoris /* 975f5f501bbSmillert * If this change is more than 'diff_context' lines 976f5f501bbSmillert * from the previous change, dump the record and reset it. 9772dc36bedSjoris */ 9782dc36bedSjoris if (diff_format == D_CONTEXT) 979f5f501bbSmillert dump_context_vec(f1, f2, flags); 9802dc36bedSjoris else 981f5f501bbSmillert dump_unified_vec(f1, f2, flags); 9822dc36bedSjoris } 9832dc36bedSjoris context_vec_ptr++; 9842dc36bedSjoris context_vec_ptr->a = a; 9852dc36bedSjoris context_vec_ptr->b = b; 9862dc36bedSjoris context_vec_ptr->c = c; 9872dc36bedSjoris context_vec_ptr->d = d; 9882dc36bedSjoris return; 9892dc36bedSjoris } 9902dc36bedSjoris if (anychange == 0) 9912dc36bedSjoris anychange = 1; 9922dc36bedSjoris switch (diff_format) { 9932dc36bedSjoris case D_BRIEF: 9942dc36bedSjoris return; 9952dc36bedSjoris case D_NORMAL: 9962dc36bedSjoris range(a, b, ","); 9972dc36bedSjoris diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c'); 9982dc36bedSjoris if (diff_format == D_NORMAL) 9992dc36bedSjoris range(c, d, ","); 10002dc36bedSjoris diff_output("\n"); 10012dc36bedSjoris break; 10022dc36bedSjoris case D_RCSDIFF: 10032dc36bedSjoris if (a > b) 10042dc36bedSjoris diff_output("a%d %d\n", b, d - c + 1); 10052dc36bedSjoris else { 10062dc36bedSjoris diff_output("d%d %d\n", a, b - a + 1); 10072dc36bedSjoris 10082dc36bedSjoris if (!(c > d)) /* add changed lines */ 10092dc36bedSjoris diff_output("a%d %d\n", b, d - c + 1); 10102dc36bedSjoris } 10112dc36bedSjoris break; 10122dc36bedSjoris } 10132dc36bedSjoris if (diff_format == D_NORMAL || diff_format == D_IFDEF) { 1014f5f501bbSmillert fetch(ixold, a, b, f1, '<', 1, flags); 10152dc36bedSjoris if (a <= b && c <= d && diff_format == D_NORMAL) 10162dc36bedSjoris diff_output("---\n"); 10172dc36bedSjoris } 1018f5f501bbSmillert fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, flags); 10192dc36bedSjoris if (inifdef) { 10202dc36bedSjoris diff_output("#endif /* %s */\n", ifdefname); 10212dc36bedSjoris inifdef = 0; 10222dc36bedSjoris } 10232dc36bedSjoris } 10242dc36bedSjoris 10252dc36bedSjoris static void 1026f5f501bbSmillert fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) 10272dc36bedSjoris { 10282dc36bedSjoris long j, nc; 10292dc36bedSjoris int i, c, col; 10302dc36bedSjoris 10312dc36bedSjoris /* 10322dc36bedSjoris * When doing #ifdef's, copy down to current line 10332dc36bedSjoris * if this is the first file, so that stuff makes it to output. 10342dc36bedSjoris */ 10352dc36bedSjoris if (diff_format == D_IFDEF && oldfile) { 10362dc36bedSjoris long curpos = ftell(lb); 10372dc36bedSjoris /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 10382dc36bedSjoris nc = f[a > b ? b : a - 1] - curpos; 10392dc36bedSjoris for (i = 0; i < nc; i++) 10402dc36bedSjoris diff_output("%c", getc(lb)); 10412dc36bedSjoris } 10422dc36bedSjoris if (a > b) 10432dc36bedSjoris return; 10442dc36bedSjoris if (diff_format == D_IFDEF) { 10452dc36bedSjoris if (inifdef) { 10462dc36bedSjoris diff_output("#else /* %s%s */\n", 10472dc36bedSjoris oldfile == 1 ? "!" : "", ifdefname); 10482dc36bedSjoris } else { 10492dc36bedSjoris if (oldfile) 10502dc36bedSjoris diff_output("#ifndef %s\n", ifdefname); 10512dc36bedSjoris else 10522dc36bedSjoris diff_output("#ifdef %s\n", ifdefname); 10532dc36bedSjoris } 10542dc36bedSjoris inifdef = 1 + oldfile; 10552dc36bedSjoris } 10562dc36bedSjoris for (i = a; i <= b; i++) { 10572dc36bedSjoris fseek(lb, f[i - 1], SEEK_SET); 10582dc36bedSjoris nc = f[i] - f[i - 1]; 10592dc36bedSjoris if (diff_format != D_IFDEF && ch != '\0') { 10602dc36bedSjoris diff_output("%c", ch); 1061f5f501bbSmillert if (diff_format != D_UNIFIED) 10622dc36bedSjoris diff_output(" "); 10632dc36bedSjoris } 10642dc36bedSjoris col = 0; 10652dc36bedSjoris for (j = 0; j < nc; j++) { 10662dc36bedSjoris if ((c = getc(lb)) == EOF) { 10672dc36bedSjoris if (diff_format == D_RCSDIFF) 10682dc36bedSjoris warn("No newline at end of file"); 10692dc36bedSjoris else 10702dc36bedSjoris diff_output("\n\\ No newline at end of " 10712dc36bedSjoris "file"); 10722dc36bedSjoris return; 10732dc36bedSjoris } 1074f5f501bbSmillert if (c == '\t' && (flags & D_EXPANDTABS)) { 10752dc36bedSjoris do { 10762dc36bedSjoris diff_output(" "); 10772dc36bedSjoris } while (++col & 7); 10782dc36bedSjoris } else { 10792dc36bedSjoris diff_output("%c", c); 10802dc36bedSjoris col++; 10812dc36bedSjoris } 10822dc36bedSjoris } 10832dc36bedSjoris } 10842dc36bedSjoris } 10852dc36bedSjoris 10862dc36bedSjoris /* 10872dc36bedSjoris * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. 10882dc36bedSjoris */ 10892dc36bedSjoris static int 1090f5f501bbSmillert readhash(FILE *f, int flags) 10912dc36bedSjoris { 10922dc36bedSjoris int i, t, space; 10932dc36bedSjoris int sum; 10942dc36bedSjoris 10952dc36bedSjoris sum = 1; 10962dc36bedSjoris space = 0; 1097f5f501bbSmillert if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) { 1098f5f501bbSmillert if (flags & D_IGNORECASE) 10992dc36bedSjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 11002dc36bedSjoris if (t == EOF) { 11012dc36bedSjoris if (i == 0) 11022dc36bedSjoris return (0); 11032dc36bedSjoris break; 11042dc36bedSjoris } 11052dc36bedSjoris sum = sum * 127 + chrtran[t]; 11062dc36bedSjoris } 11072dc36bedSjoris else 11082dc36bedSjoris for (i = 0; (t = getc(f)) != '\n'; i++) { 11092dc36bedSjoris if (t == EOF) { 11102dc36bedSjoris if (i == 0) 11112dc36bedSjoris return (0); 11122dc36bedSjoris break; 11132dc36bedSjoris } 11142dc36bedSjoris sum = sum * 127 + t; 11152dc36bedSjoris } 11162dc36bedSjoris } else { 11172dc36bedSjoris for (i = 0;;) { 11182dc36bedSjoris switch (t = getc(f)) { 11192dc36bedSjoris case '\t': 11202dc36bedSjoris case ' ': 11212dc36bedSjoris space++; 11222dc36bedSjoris continue; 11232dc36bedSjoris default: 1124f5f501bbSmillert if (space && (flags & D_IGNOREBLANKS) == 0) { 11252dc36bedSjoris i++; 11262dc36bedSjoris space = 0; 11272dc36bedSjoris } 11282dc36bedSjoris sum = sum * 127 + chrtran[t]; 11292dc36bedSjoris i++; 11302dc36bedSjoris continue; 11312dc36bedSjoris case EOF: 11322dc36bedSjoris if (i == 0) 11332dc36bedSjoris return (0); 11342dc36bedSjoris /* FALLTHROUGH */ 11352dc36bedSjoris case '\n': 11362dc36bedSjoris break; 11372dc36bedSjoris } 11382dc36bedSjoris break; 11392dc36bedSjoris } 11402dc36bedSjoris } 11412dc36bedSjoris /* 11422dc36bedSjoris * There is a remote possibility that we end up with a zero sum. 11432dc36bedSjoris * Zero is used as an EOF marker, so return 1 instead. 11442dc36bedSjoris */ 11452dc36bedSjoris return (sum == 0 ? 1 : sum); 11462dc36bedSjoris } 11472dc36bedSjoris 11482dc36bedSjoris static int 11492dc36bedSjoris asciifile(FILE *f) 11502dc36bedSjoris { 11512dc36bedSjoris char buf[BUFSIZ]; 11522dc36bedSjoris size_t i, cnt; 11532dc36bedSjoris 1154f5f501bbSmillert if (f == NULL) 11552dc36bedSjoris return (1); 11562dc36bedSjoris 11572dc36bedSjoris rewind(f); 115885ea658bSray cnt = fread(buf, 1, sizeof(buf), f); 11592dc36bedSjoris for (i = 0; i < cnt; i++) 11602dc36bedSjoris if (!isprint(buf[i]) && !isspace(buf[i])) 11612dc36bedSjoris return (0); 11622dc36bedSjoris return (1); 11632dc36bedSjoris } 11642dc36bedSjoris 1165e22e6974Sxsa #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0) 1166e22e6974Sxsa 11672dc36bedSjoris static char* 11682dc36bedSjoris match_function(const long *f, int pos, FILE *fp) 11692dc36bedSjoris { 11702dc36bedSjoris unsigned char buf[FUNCTION_CONTEXT_SIZE]; 11712dc36bedSjoris size_t nc; 11722dc36bedSjoris int last = lastline; 11732dc36bedSjoris char *p; 1174e22e6974Sxsa char *state = NULL; 11752dc36bedSjoris 11762dc36bedSjoris lastline = pos; 11772dc36bedSjoris while (pos > last) { 11782dc36bedSjoris fseek(fp, f[pos - 1], SEEK_SET); 11792dc36bedSjoris nc = f[pos] - f[pos - 1]; 11802dc36bedSjoris if (nc >= sizeof(buf)) 11812dc36bedSjoris nc = sizeof(buf) - 1; 118285ea658bSray nc = fread(buf, 1, nc, fp); 11832dc36bedSjoris if (nc > 0) { 11842dc36bedSjoris buf[nc] = '\0'; 11852dc36bedSjoris p = strchr((const char *)buf, '\n'); 11862dc36bedSjoris if (p != NULL) 11872dc36bedSjoris *p = '\0'; 11882dc36bedSjoris if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') { 1189e22e6974Sxsa if (begins_with(buf, "private:")) { 1190e22e6974Sxsa if (!state) 1191e22e6974Sxsa state = " (private)"; 1192e22e6974Sxsa } else if (begins_with(buf, "protected:")) { 1193e22e6974Sxsa if (!state) 1194e22e6974Sxsa state = " (protected)"; 1195e22e6974Sxsa } else if (begins_with(buf, "public:")) { 1196e22e6974Sxsa if (!state) 1197e22e6974Sxsa state = " (public)"; 1198e22e6974Sxsa } else { 11996b99bb86Sray if (strlcpy(lastbuf, (const char *)buf, 12006b99bb86Sray sizeof(lastbuf)) >= sizeof(lastbuf)) 1201e22e6974Sxsa errx(1, 1202e22e6974Sxsa "match_function: strlcpy"); 12032dc36bedSjoris lastmatchline = pos; 12042dc36bedSjoris return lastbuf; 12052dc36bedSjoris } 12062dc36bedSjoris } 1207e22e6974Sxsa } 12082dc36bedSjoris pos--; 12092dc36bedSjoris } 12102dc36bedSjoris return (lastmatchline > 0) ? lastbuf : NULL; 12112dc36bedSjoris } 12122dc36bedSjoris 12132dc36bedSjoris 12142dc36bedSjoris /* dump accumulated "context" diff changes */ 12152dc36bedSjoris static void 1216f5f501bbSmillert dump_context_vec(FILE *f1, FILE *f2, int flags) 12172dc36bedSjoris { 12182dc36bedSjoris struct context_vec *cvp = context_vec_start; 12192dc36bedSjoris int lowa, upb, lowc, upd, do_output; 12202dc36bedSjoris int a, b, c, d; 12212dc36bedSjoris char ch, *f; 12222dc36bedSjoris 12232dc36bedSjoris if (context_vec_start > context_vec_ptr) 12242dc36bedSjoris return; 12252dc36bedSjoris 12262dc36bedSjoris b = d = 0; /* gcc */ 1227f5f501bbSmillert lowa = MAX(1, cvp->a - diff_context); 1228f5f501bbSmillert upb = MIN(diff_len[0], context_vec_ptr->b + diff_context); 1229f5f501bbSmillert lowc = MAX(1, cvp->c - diff_context); 1230f5f501bbSmillert upd = MIN(diff_len[1], context_vec_ptr->d + diff_context); 12312dc36bedSjoris 12322dc36bedSjoris diff_output("***************"); 1233f5f501bbSmillert if ((flags & D_PROTOTYPE)) { 12342dc36bedSjoris f = match_function(ixold, lowa - 1, f1); 12352dc36bedSjoris if (f != NULL) { 12362dc36bedSjoris diff_output(" "); 12372dc36bedSjoris diff_output("%s", f); 12382dc36bedSjoris } 12392dc36bedSjoris } 12402dc36bedSjoris diff_output("\n*** "); 12412dc36bedSjoris range(lowa, upb, ","); 12422dc36bedSjoris diff_output(" ****\n"); 12432dc36bedSjoris 12442dc36bedSjoris /* 12452dc36bedSjoris * Output changes to the "old" file. The first loop suppresses 12462dc36bedSjoris * output if there were no changes to the "old" file (we'll see 12472dc36bedSjoris * the "old" lines as context in the "new" list). 12482dc36bedSjoris */ 12492dc36bedSjoris do_output = 0; 12502dc36bedSjoris for (; cvp <= context_vec_ptr; cvp++) 12512dc36bedSjoris if (cvp->a <= cvp->b) { 12522dc36bedSjoris cvp = context_vec_start; 12532dc36bedSjoris do_output++; 12542dc36bedSjoris break; 12552dc36bedSjoris } 12562dc36bedSjoris if (do_output != 0) { 12572dc36bedSjoris while (cvp <= context_vec_ptr) { 12582dc36bedSjoris a = cvp->a; 12592dc36bedSjoris b = cvp->b; 12602dc36bedSjoris c = cvp->c; 12612dc36bedSjoris d = cvp->d; 12622dc36bedSjoris 12632dc36bedSjoris if (a <= b && c <= d) 12642dc36bedSjoris ch = 'c'; 12652dc36bedSjoris else 12662dc36bedSjoris ch = (a <= b) ? 'd' : 'a'; 12672dc36bedSjoris 12682dc36bedSjoris if (ch == 'a') 1269f5f501bbSmillert fetch(ixold, lowa, b, f1, ' ', 0, flags); 12702dc36bedSjoris else { 1271f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 12722dc36bedSjoris fetch(ixold, a, b, f1, 1273f5f501bbSmillert ch == 'c' ? '!' : '-', 0, flags); 12742dc36bedSjoris } 12752dc36bedSjoris lowa = b + 1; 12762dc36bedSjoris cvp++; 12772dc36bedSjoris } 1278f5f501bbSmillert fetch(ixold, b + 1, upb, f1, ' ', 0, flags); 12792dc36bedSjoris } 12802dc36bedSjoris /* output changes to the "new" file */ 12812dc36bedSjoris diff_output("--- "); 12822dc36bedSjoris range(lowc, upd, ","); 12832dc36bedSjoris diff_output(" ----\n"); 12842dc36bedSjoris 12852dc36bedSjoris do_output = 0; 12862dc36bedSjoris for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 12872dc36bedSjoris if (cvp->c <= cvp->d) { 12882dc36bedSjoris cvp = context_vec_start; 12892dc36bedSjoris do_output++; 12902dc36bedSjoris break; 12912dc36bedSjoris } 12922dc36bedSjoris if (do_output != 0) { 12932dc36bedSjoris while (cvp <= context_vec_ptr) { 12942dc36bedSjoris a = cvp->a; 12952dc36bedSjoris b = cvp->b; 12962dc36bedSjoris c = cvp->c; 12972dc36bedSjoris d = cvp->d; 12982dc36bedSjoris 12992dc36bedSjoris if (a <= b && c <= d) 13002dc36bedSjoris ch = 'c'; 13012dc36bedSjoris else 13022dc36bedSjoris ch = (a <= b) ? 'd' : 'a'; 13032dc36bedSjoris 13042dc36bedSjoris if (ch == 'd') 1305f5f501bbSmillert fetch(ixnew, lowc, d, f2, ' ', 0, flags); 13062dc36bedSjoris else { 1307f5f501bbSmillert fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); 13082dc36bedSjoris fetch(ixnew, c, d, f2, 1309f5f501bbSmillert ch == 'c' ? '!' : '+', 0, flags); 13102dc36bedSjoris } 13112dc36bedSjoris lowc = d + 1; 13122dc36bedSjoris cvp++; 13132dc36bedSjoris } 1314f5f501bbSmillert fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); 13152dc36bedSjoris } 13162dc36bedSjoris context_vec_ptr = context_vec_start - 1; 13172dc36bedSjoris } 13182dc36bedSjoris 13192dc36bedSjoris /* dump accumulated "unified" diff changes */ 13202dc36bedSjoris static void 1321f5f501bbSmillert dump_unified_vec(FILE *f1, FILE *f2, int flags) 13222dc36bedSjoris { 13232dc36bedSjoris struct context_vec *cvp = context_vec_start; 13242dc36bedSjoris int lowa, upb, lowc, upd; 13252dc36bedSjoris int a, b, c, d; 13262dc36bedSjoris char ch, *f; 13272dc36bedSjoris 13282dc36bedSjoris if (context_vec_start > context_vec_ptr) 13292dc36bedSjoris return; 13302dc36bedSjoris 13312dc36bedSjoris b = d = 0; /* gcc */ 1332f5f501bbSmillert lowa = MAX(1, cvp->a - diff_context); 1333f5f501bbSmillert upb = MIN(diff_len[0], context_vec_ptr->b + diff_context); 1334f5f501bbSmillert lowc = MAX(1, cvp->c - diff_context); 1335f5f501bbSmillert upd = MIN(diff_len[1], context_vec_ptr->d + diff_context); 13362dc36bedSjoris 13372dc36bedSjoris diff_output("@@ -"); 13382dc36bedSjoris uni_range(lowa, upb); 13392dc36bedSjoris diff_output(" +"); 13402dc36bedSjoris uni_range(lowc, upd); 13412dc36bedSjoris diff_output(" @@"); 1342f5f501bbSmillert if ((flags & D_PROTOTYPE)) { 13432dc36bedSjoris f = match_function(ixold, lowa - 1, f1); 13442dc36bedSjoris if (f != NULL) { 13452dc36bedSjoris diff_output(" "); 13462dc36bedSjoris diff_output("%s", f); 13472dc36bedSjoris } 13482dc36bedSjoris } 13492dc36bedSjoris diff_output("\n"); 13502dc36bedSjoris 13512dc36bedSjoris /* 13522dc36bedSjoris * Output changes in "unified" diff format--the old and new lines 13532dc36bedSjoris * are printed together. 13542dc36bedSjoris */ 13552dc36bedSjoris for (; cvp <= context_vec_ptr; cvp++) { 13562dc36bedSjoris a = cvp->a; 13572dc36bedSjoris b = cvp->b; 13582dc36bedSjoris c = cvp->c; 13592dc36bedSjoris d = cvp->d; 13602dc36bedSjoris 13612dc36bedSjoris /* 13622dc36bedSjoris * c: both new and old changes 13632dc36bedSjoris * d: only changes in the old file 13642dc36bedSjoris * a: only changes in the new file 13652dc36bedSjoris */ 13662dc36bedSjoris if (a <= b && c <= d) 13672dc36bedSjoris ch = 'c'; 13682dc36bedSjoris else 13692dc36bedSjoris ch = (a <= b) ? 'd' : 'a'; 13702dc36bedSjoris 13712dc36bedSjoris switch (ch) { 13722dc36bedSjoris case 'c': 1373f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 1374f5f501bbSmillert fetch(ixold, a, b, f1, '-', 0, flags); 1375f5f501bbSmillert fetch(ixnew, c, d, f2, '+', 0, flags); 13762dc36bedSjoris break; 13772dc36bedSjoris case 'd': 1378f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags); 1379f5f501bbSmillert fetch(ixold, a, b, f1, '-', 0, flags); 13802dc36bedSjoris break; 13812dc36bedSjoris case 'a': 1382f5f501bbSmillert fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags); 1383f5f501bbSmillert fetch(ixnew, c, d, f2, '+', 0, flags); 13842dc36bedSjoris break; 13852dc36bedSjoris } 13862dc36bedSjoris lowa = b + 1; 13872dc36bedSjoris lowc = d + 1; 13882dc36bedSjoris } 1389f5f501bbSmillert fetch(ixnew, d + 1, upd, f2, ' ', 0, flags); 13902dc36bedSjoris 13912dc36bedSjoris context_vec_ptr = context_vec_start - 1; 13922dc36bedSjoris } 13932dc36bedSjoris 13942dc36bedSjoris void 13952dc36bedSjoris diff_output(const char *fmt, ...) 13962dc36bedSjoris { 13972dc36bedSjoris va_list vap; 13982dc36bedSjoris int i; 13992dc36bedSjoris char *str; 14002dc36bedSjoris 14012dc36bedSjoris va_start(vap, fmt); 14022dc36bedSjoris i = vasprintf(&str, fmt, vap); 14032dc36bedSjoris va_end(vap); 14042dc36bedSjoris if (i == -1) 1405d4625ebbSxsa err(1, "diff_output"); 14062dc36bedSjoris if (diffbuf != NULL) 14072dc36bedSjoris rcs_buf_append(diffbuf, str, strlen(str)); 14082dc36bedSjoris else 14092dc36bedSjoris printf("%s", str); 14102dc36bedSjoris xfree(str); 14112dc36bedSjoris } 1412