1*3aaa63ebSderaadt /* $OpenBSD: diff.c,v 1.40 2019/06/28 13:35:03 deraadt 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 */
66af90d6d1Sray
67af90d6d1Sray #include <sys/stat.h>
68af90d6d1Sray
69af90d6d1Sray #include <ctype.h>
70af90d6d1Sray #include <err.h>
71af90d6d1Sray #include <stdarg.h>
72b9fc9a72Sderaadt #include <stdint.h>
73af90d6d1Sray #include <stddef.h>
74af90d6d1Sray #include <stdio.h>
758ac837e5Snicm #include <stdlib.h>
76af90d6d1Sray #include <string.h>
77af90d6d1Sray #include <unistd.h>
78b9fc9a72Sderaadt #include <limits.h>
79af90d6d1Sray
80af90d6d1Sray #include "buf.h"
81af90d6d1Sray #include "diff.h"
82af90d6d1Sray #include "xmalloc.h"
83af90d6d1Sray
84b9fc9a72Sderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
85b9fc9a72Sderaadt #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
86b9fc9a72Sderaadt
87af90d6d1Sray /*
88af90d6d1Sray * diff - compare two files.
89af90d6d1Sray */
90af90d6d1Sray
912dc36bedSjoris /*
922dc36bedSjoris * Uses an algorithm due to Harold Stone, which finds
932dc36bedSjoris * a pair of longest identical subsequences in the two
942dc36bedSjoris * files.
952dc36bedSjoris *
962dc36bedSjoris * The major goal is to generate the match vector J.
972dc36bedSjoris * J[i] is the index of the line in file1 corresponding
982dc36bedSjoris * to line i file0. J[i] = 0 if there is no
992dc36bedSjoris * such line in file1.
1002dc36bedSjoris *
1012dc36bedSjoris * Lines are hashed so as to work in core. All potential
1022dc36bedSjoris * matches are located by sorting the lines of each file
1032dc36bedSjoris * on the hash (called ``value''). In particular, this
1042dc36bedSjoris * collects the equivalence classes in file1 together.
1052dc36bedSjoris * Subroutine equiv replaces the value of each line in
1062dc36bedSjoris * file0 by the index of the first element of its
1072dc36bedSjoris * matching equivalence in (the reordered) file1.
1082dc36bedSjoris * To save space equiv squeezes file1 into a single
1092dc36bedSjoris * array member in which the equivalence classes
1102dc36bedSjoris * are simply concatenated, except that their first
1112dc36bedSjoris * members are flagged by changing sign.
1122dc36bedSjoris *
1132dc36bedSjoris * Next the indices that point into member are unsorted into
1142dc36bedSjoris * array class according to the original order of file0.
1152dc36bedSjoris *
1162dc36bedSjoris * The cleverness lies in routine stone. This marches
1172dc36bedSjoris * through the lines of file0, developing a vector klist
1182dc36bedSjoris * of "k-candidates". At step i a k-candidate is a matched
1192dc36bedSjoris * pair of lines x,y (x in file0 y in file1) such that
1202dc36bedSjoris * there is a common subsequence of length k
1212dc36bedSjoris * between the first i lines of file0 and the first y
1222dc36bedSjoris * lines of file1, but there is no such subsequence for
1232dc36bedSjoris * any smaller y. x is the earliest possible mate to y
1242dc36bedSjoris * that occurs in such a subsequence.
1252dc36bedSjoris *
1262dc36bedSjoris * Whenever any of the members of the equivalence class of
1272dc36bedSjoris * lines in file1 matable to a line in file0 has serial number
1282dc36bedSjoris * less than the y of some k-candidate, that k-candidate
1292dc36bedSjoris * with the smallest such y is replaced. The new
1302dc36bedSjoris * k-candidate is chained (via pred) to the current
1312dc36bedSjoris * k-1 candidate so that the actual subsequence can
1322dc36bedSjoris * be recovered. When a member has serial number greater
1332dc36bedSjoris * that the y of all k-candidates, the klist is extended.
1342dc36bedSjoris * At the end, the longest subsequence is pulled out
1352dc36bedSjoris * and placed in the array J by unravel
1362dc36bedSjoris *
1372dc36bedSjoris * With J in hand, the matches there recorded are
1382dc36bedSjoris * check'ed against reality to assure that no spurious
1392dc36bedSjoris * matches have crept in due to hashing. If they have,
1402dc36bedSjoris * they are broken, and "jackpot" is recorded--a harmless
1412dc36bedSjoris * matter except that a true match for a spuriously
1422dc36bedSjoris * mated line may now be unnecessarily reported as a change.
1432dc36bedSjoris *
1442dc36bedSjoris * Much of the complexity of the program comes simply
1452dc36bedSjoris * from trying to minimize core utilization and
1462dc36bedSjoris * maximize the range of doable problems by dynamically
1472dc36bedSjoris * allocating what is needed and reusing what is not.
1482dc36bedSjoris * The core requirements for problems larger than somewhat
1492dc36bedSjoris * are (in words) 2*length(file0) + length(file1) +
1502dc36bedSjoris * 3*(number of k-candidates installed), typically about
1512dc36bedSjoris * 6n words for files of length n.
1522dc36bedSjoris */
1532dc36bedSjoris
1542dc36bedSjoris struct cand {
1552dc36bedSjoris int x;
1562dc36bedSjoris int y;
1572dc36bedSjoris int pred;
158ccf8fb4cSray };
1592dc36bedSjoris
1602dc36bedSjoris struct line {
1612dc36bedSjoris int serial;
1622dc36bedSjoris int value;
1632dc36bedSjoris } *file[2];
1642dc36bedSjoris
1652dc36bedSjoris /*
1662dc36bedSjoris * The following struct is used to record change information when
1672dc36bedSjoris * doing a "context" or "unified" diff. (see routine "change" to
1682dc36bedSjoris * understand the highly mnemonic field names)
1692dc36bedSjoris */
1702dc36bedSjoris struct context_vec {
1712dc36bedSjoris int a; /* start line in old file */
1722dc36bedSjoris int b; /* end line in old file */
1732dc36bedSjoris int c; /* start line in new file */
1742dc36bedSjoris int d; /* end line in new file */
1752dc36bedSjoris };
1762dc36bedSjoris
177f5f501bbSmillert static void output(FILE *, FILE *, int);
178f5f501bbSmillert static void check(FILE *, FILE *, int);
1792dc36bedSjoris static void range(int, int, char *);
1802dc36bedSjoris static void uni_range(int, int);
181f5f501bbSmillert static void dump_context_vec(FILE *, FILE *, int);
182f5f501bbSmillert static void dump_unified_vec(FILE *, FILE *, int);
183d2c2f9b1Sray static void prepare(int, FILE *, off_t, int);
1842dc36bedSjoris static void prune(void);
1852dc36bedSjoris static void equiv(struct line *, int, struct line *, int, int *);
1862dc36bedSjoris static void unravel(int);
1872dc36bedSjoris static void unsort(struct line *, int, int *);
188f5f501bbSmillert static void change(FILE *, FILE *, int, int, int, int, int);
1892dc36bedSjoris static void sort(struct line *, int);
1902dc36bedSjoris static int ignoreline(char *);
1912dc36bedSjoris static int asciifile(FILE *);
192f5f501bbSmillert static void fetch(long *, int, int, FILE *, int, int, int);
1932dc36bedSjoris static int newcand(int, int, int);
1942dc36bedSjoris static int search(int *, int, int);
1952dc36bedSjoris static int skipline(FILE *);
1962dc36bedSjoris static int isqrt(int);
197f5f501bbSmillert static int stone(int *, int, int *, int *, int);
198f5f501bbSmillert static int readhash(FILE *, int);
1992dc36bedSjoris static int files_differ(FILE *, FILE *);
2002dc36bedSjoris static char *match_function(const long *, int, FILE *);
2012dc36bedSjoris static char *preadline(int, size_t, off_t);
2022dc36bedSjoris
2032dc36bedSjoris
204f5f501bbSmillert int diff_context = 3;
2052dc36bedSjoris int diff_format = D_NORMAL;
2062dc36bedSjoris char *diff_file = NULL;
2072dc36bedSjoris RCSNUM *diff_rev1 = NULL;
2082dc36bedSjoris RCSNUM *diff_rev2 = NULL;
209f5f501bbSmillert char diffargs[512]; /* XXX */
2102dc36bedSjoris static struct stat stb1, stb2;
211f5f501bbSmillert static char *ifdefname;
212f5f501bbSmillert regex_t *diff_ignore_re;
2132dc36bedSjoris
2142dc36bedSjoris static int *J; /* will be overlaid on class */
2152dc36bedSjoris static int *class; /* will be overlaid on file[0] */
2162dc36bedSjoris static int *klist; /* will be overlaid on file[0] after class */
2172dc36bedSjoris static int *member; /* will be overlaid on file[1] */
2182dc36bedSjoris static int clen;
2192dc36bedSjoris static int inifdef; /* whether or not we are in a #ifdef block */
220d2c2f9b1Sray static int len[2];
2212dc36bedSjoris static int pref, suff; /* length of prefix and suffix */
2222dc36bedSjoris static int slen[2];
2232dc36bedSjoris static int anychange;
2242dc36bedSjoris static long *ixnew; /* will be overlaid on file[1] */
2252dc36bedSjoris static long *ixold; /* will be overlaid on klist */
2262dc36bedSjoris static struct cand *clist; /* merely a free storage pot for candidates */
2272dc36bedSjoris static int clistlen; /* the length of clist */
2282dc36bedSjoris static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */
2292dc36bedSjoris static u_char *chrtran; /* translation table for case-folding */
2302dc36bedSjoris static struct context_vec *context_vec_start;
2312dc36bedSjoris static struct context_vec *context_vec_end;
2322dc36bedSjoris static struct context_vec *context_vec_ptr;
2332dc36bedSjoris
234e22e6974Sxsa #define FUNCTION_CONTEXT_SIZE 55
2352dc36bedSjoris static char lastbuf[FUNCTION_CONTEXT_SIZE];
2362dc36bedSjoris static int lastline;
2372dc36bedSjoris static int lastmatchline;
2382dc36bedSjoris BUF *diffbuf = NULL;
2392dc36bedSjoris
240af90d6d1Sray
2412dc36bedSjoris /*
2422dc36bedSjoris * chrtran points to one of 2 translation tables: cup2low if folding upper to
2432dc36bedSjoris * lower case clow2low if not folding case
2442dc36bedSjoris */
2452dc36bedSjoris u_char clow2low[256] = {
2462dc36bedSjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
2472dc36bedSjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
2482dc36bedSjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
2492dc36bedSjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
2502dc36bedSjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
2512dc36bedSjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
2522dc36bedSjoris 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
2532dc36bedSjoris 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
2542dc36bedSjoris 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
2552dc36bedSjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
2562dc36bedSjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
2572dc36bedSjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
2582dc36bedSjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
2592dc36bedSjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
2602dc36bedSjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
2612dc36bedSjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
2622dc36bedSjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
2632dc36bedSjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2642dc36bedSjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
2652dc36bedSjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
2662dc36bedSjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
2672dc36bedSjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
2682dc36bedSjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
2692dc36bedSjoris 0xfd, 0xfe, 0xff
2702dc36bedSjoris };
2712dc36bedSjoris
2722dc36bedSjoris u_char cup2low[256] = {
2732dc36bedSjoris 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
2742dc36bedSjoris 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
2752dc36bedSjoris 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
2762dc36bedSjoris 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
2772dc36bedSjoris 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
2782dc36bedSjoris 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
2792dc36bedSjoris 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
2802dc36bedSjoris 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
2812dc36bedSjoris 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
2822dc36bedSjoris 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
2832dc36bedSjoris 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
2842dc36bedSjoris 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
2852dc36bedSjoris 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
2862dc36bedSjoris 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
2872dc36bedSjoris 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
2882dc36bedSjoris 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
2892dc36bedSjoris 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
2902dc36bedSjoris 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2912dc36bedSjoris 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
2922dc36bedSjoris 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
2932dc36bedSjoris 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
2942dc36bedSjoris 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
2952dc36bedSjoris 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
2962dc36bedSjoris 0xfd, 0xfe, 0xff
2972dc36bedSjoris };
2982dc36bedSjoris
2992dc36bedSjoris int
diffreg(const char * file1,const char * file2,BUF * out,int flags)300f049f428Sray diffreg(const char *file1, const char *file2, BUF *out, int flags)
3012dc36bedSjoris {
3022dc36bedSjoris FILE *f1, *f2;
3032dc36bedSjoris int i, rval;
3042dc36bedSjoris
3052dc36bedSjoris f1 = f2 = NULL;
3062dc36bedSjoris rval = D_SAME;
3072dc36bedSjoris anychange = 0;
3082dc36bedSjoris lastline = 0;
3092dc36bedSjoris lastmatchline = 0;
3102dc36bedSjoris context_vec_ptr = context_vec_start - 1;
311f5f501bbSmillert if (flags & D_IGNORECASE)
312f5f501bbSmillert chrtran = cup2low;
313f5f501bbSmillert else
314f5f501bbSmillert chrtran = clow2low;
3152dc36bedSjoris if (out != NULL)
3162dc36bedSjoris diffbuf = out;
3172dc36bedSjoris
3182dc36bedSjoris f1 = fopen(file1, "r");
3192dc36bedSjoris if (f1 == NULL) {
3202dc36bedSjoris warn("%s", file1);
3212dc36bedSjoris goto closem;
3222dc36bedSjoris }
3232dc36bedSjoris
3242dc36bedSjoris f2 = fopen(file2, "r");
3252dc36bedSjoris if (f2 == NULL) {
3262dc36bedSjoris warn("%s", file2);
3272dc36bedSjoris goto closem;
3282dc36bedSjoris }
3292dc36bedSjoris
330*3aaa63ebSderaadt if (fstat(fileno(f1), &stb1) == -1) {
3312dc36bedSjoris warn("%s", file1);
3322dc36bedSjoris goto closem;
3332dc36bedSjoris }
3342dc36bedSjoris
335*3aaa63ebSderaadt if (fstat(fileno(f2), &stb2) == -1) {
3362dc36bedSjoris warn("%s", file2);
3372dc36bedSjoris goto closem;
3382dc36bedSjoris }
3392dc36bedSjoris
340616468a8Sray switch (files_differ(f1, f2)) {
341616468a8Sray case 1:
342616468a8Sray break;
343616468a8Sray case -1:
344616468a8Sray rval = D_ERROR;
345616468a8Sray /* FALLTHROUGH */
346616468a8Sray case 0:
3472dc36bedSjoris goto closem;
348616468a8Sray default:
349616468a8Sray errx(D_ERROR, "files_differ: invalid case");
350616468a8Sray }
3512dc36bedSjoris
352f5f501bbSmillert if ((flags & D_FORCEASCII) == 0 &&
353f5f501bbSmillert (!asciifile(f1) || !asciifile(f2))) {
3541fb625bfSxsa rval = D_ERROR;
3552dc36bedSjoris goto closem;
3562dc36bedSjoris }
3572dc36bedSjoris
358d2c2f9b1Sray prepare(0, f1, stb1.st_size, flags);
359d2c2f9b1Sray prepare(1, f2, stb2.st_size, flags);
3602dc36bedSjoris
3612dc36bedSjoris prune();
3622dc36bedSjoris sort(sfile[0], slen[0]);
3632dc36bedSjoris sort(sfile[1], slen[1]);
3642dc36bedSjoris
3652dc36bedSjoris member = (int *)file[1];
3662dc36bedSjoris equiv(sfile[0], slen[0], sfile[1], slen[1], member);
367caa2ffb0Sderaadt member = xreallocarray(member, slen[1] + 2, sizeof(*member));
3682dc36bedSjoris
3692dc36bedSjoris class = (int *)file[0];
3702dc36bedSjoris unsort(sfile[0], slen[0], class);
371caa2ffb0Sderaadt class = xreallocarray(class, slen[0] + 2, sizeof(*class));
3722dc36bedSjoris
3732dc36bedSjoris klist = xcalloc(slen[0] + 2, sizeof(*klist));
3742dc36bedSjoris clen = 0;
3752dc36bedSjoris clistlen = 100;
3762dc36bedSjoris clist = xcalloc(clistlen, sizeof(*clist));
377af90d6d1Sray i = stone(class, slen[0], member, klist, flags);
3788ac837e5Snicm free(member);
3798ac837e5Snicm free(class);
3802dc36bedSjoris
381caa2ffb0Sderaadt J = xreallocarray(J, len[0] + 2, sizeof(*J));
3822dc36bedSjoris unravel(klist[i]);
3838ac837e5Snicm free(clist);
3848ac837e5Snicm free(klist);
3852dc36bedSjoris
386caa2ffb0Sderaadt ixold = xreallocarray(ixold, len[0] + 2, sizeof(*ixold));
387caa2ffb0Sderaadt ixnew = xreallocarray(ixnew, len[1] + 2, sizeof(*ixnew));
388f5f501bbSmillert check(f1, f2, flags);
389f5f501bbSmillert output(f1, f2, flags);
3902dc36bedSjoris
3912dc36bedSjoris closem:
392af90d6d1Sray if (anychange) {
3932dc36bedSjoris if (rval == D_SAME)
3942dc36bedSjoris rval = D_DIFFER;
3952dc36bedSjoris }
3962dc36bedSjoris if (f1 != NULL)
3972dc36bedSjoris fclose(f1);
3982dc36bedSjoris if (f2 != NULL)
3992dc36bedSjoris fclose(f2);
4002dc36bedSjoris
4012dc36bedSjoris return (rval);
4022dc36bedSjoris }
4032dc36bedSjoris
4042dc36bedSjoris /*
4052dc36bedSjoris * Check to see if the given files differ.
4062dc36bedSjoris * Returns 0 if they are the same, 1 if different, and -1 on error.
4072dc36bedSjoris * XXX - could use code from cmp(1) [faster]
4082dc36bedSjoris */
4092dc36bedSjoris static int
files_differ(FILE * f1,FILE * f2)4102dc36bedSjoris files_differ(FILE *f1, FILE *f2)
4112dc36bedSjoris {
4122dc36bedSjoris char buf1[BUFSIZ], buf2[BUFSIZ];
4132dc36bedSjoris size_t i, j;
4142dc36bedSjoris
4152dc36bedSjoris if (stb1.st_size != stb2.st_size)
4162dc36bedSjoris return (1);
4172dc36bedSjoris for (;;) {
41885ea658bSray i = fread(buf1, 1, sizeof(buf1), f1);
41985ea658bSray j = fread(buf2, 1, sizeof(buf2), f2);
42009523d6fSray if ((!i && ferror(f1)) || (!j && ferror(f2)))
42109523d6fSray return (-1);
4222dc36bedSjoris if (i != j)
4232dc36bedSjoris return (1);
42409523d6fSray if (i == 0)
4252dc36bedSjoris return (0);
4262dc36bedSjoris if (memcmp(buf1, buf2, i) != 0)
4272dc36bedSjoris return (1);
4282dc36bedSjoris }
4292dc36bedSjoris }
4302dc36bedSjoris
431d2c2f9b1Sray static void
prepare(int i,FILE * fd,off_t filesize,int flags)432f5f501bbSmillert prepare(int i, FILE *fd, off_t filesize, int flags)
4332dc36bedSjoris {
4342dc36bedSjoris struct line *p;
4352dc36bedSjoris int j, h;
4362dc36bedSjoris size_t sz;
4372dc36bedSjoris
4382dc36bedSjoris rewind(fd);
4392dc36bedSjoris
440257be878Sokan sz = ((uintmax_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25;
4412dc36bedSjoris if (sz < 100)
4422dc36bedSjoris sz = 100;
4432dc36bedSjoris
4442dc36bedSjoris p = xcalloc(sz + 3, sizeof(*p));
445f5f501bbSmillert for (j = 0; (h = readhash(fd, flags));) {
446257be878Sokan if ((size_t)j == sz) {
4472dc36bedSjoris sz = sz * 3 / 2;
448caa2ffb0Sderaadt p = xreallocarray(p, sz + 3, sizeof(*p));
4492dc36bedSjoris }
4502dc36bedSjoris p[++j].value = h;
4512dc36bedSjoris }
452d2c2f9b1Sray len[i] = j;
4532dc36bedSjoris file[i] = p;
4542dc36bedSjoris }
4552dc36bedSjoris
4562dc36bedSjoris static void
prune(void)4572dc36bedSjoris prune(void)
4582dc36bedSjoris {
4592dc36bedSjoris int i, j;
4602dc36bedSjoris
461d2c2f9b1Sray for (pref = 0; pref < len[0] && pref < len[1] &&
4622dc36bedSjoris file[0][pref + 1].value == file[1][pref + 1].value;
4632dc36bedSjoris pref++)
4642dc36bedSjoris ;
465af90d6d1Sray for (suff = 0; suff < len[0] - pref && suff < len[1] - pref &&
466af90d6d1Sray file[0][len[0] - suff].value == file[1][len[1] - suff].value;
4672dc36bedSjoris suff++)
4682dc36bedSjoris ;
4692dc36bedSjoris for (j = 0; j < 2; j++) {
4702dc36bedSjoris sfile[j] = file[j] + pref;
471d2c2f9b1Sray slen[j] = len[j] - pref - suff;
4722dc36bedSjoris for (i = 0; i <= slen[j]; i++)
4732dc36bedSjoris sfile[j][i].serial = i;
4742dc36bedSjoris }
4752dc36bedSjoris }
4762dc36bedSjoris
4772dc36bedSjoris static void
equiv(struct line * a,int n,struct line * b,int m,int * c)4782dc36bedSjoris equiv(struct line *a, int n, struct line *b, int m, int *c)
4792dc36bedSjoris {
4802dc36bedSjoris int i, j;
4812dc36bedSjoris
4822dc36bedSjoris i = j = 1;
4832dc36bedSjoris while (i <= n && j <= m) {
4842dc36bedSjoris if (a[i].value < b[j].value)
4852dc36bedSjoris a[i++].value = 0;
4862dc36bedSjoris else if (a[i].value == b[j].value)
4872dc36bedSjoris a[i++].value = j;
4882dc36bedSjoris else
4892dc36bedSjoris j++;
4902dc36bedSjoris }
4912dc36bedSjoris while (i <= n)
4922dc36bedSjoris a[i++].value = 0;
4932dc36bedSjoris b[m + 1].value = 0;
4942dc36bedSjoris j = 0;
4952dc36bedSjoris while (++j <= m) {
4962dc36bedSjoris c[j] = -b[j].serial;
4972dc36bedSjoris while (b[j + 1].value == b[j].value) {
4982dc36bedSjoris j++;
4992dc36bedSjoris c[j] = b[j].serial;
5002dc36bedSjoris }
5012dc36bedSjoris }
5022dc36bedSjoris c[j] = -1;
5032dc36bedSjoris }
5042dc36bedSjoris
5052dc36bedSjoris /* Code taken from ping.c */
5062dc36bedSjoris static int
isqrt(int n)5072dc36bedSjoris isqrt(int n)
5082dc36bedSjoris {
5092dc36bedSjoris int y, x = 1;
5102dc36bedSjoris
5112dc36bedSjoris if (n == 0)
5122dc36bedSjoris return (0);
5132dc36bedSjoris
5142dc36bedSjoris do { /* newton was a stinker */
5152dc36bedSjoris y = x;
5162dc36bedSjoris x = n / x;
5172dc36bedSjoris x += y;
5182dc36bedSjoris x /= 2;
519af90d6d1Sray } while ((x - y) > 1 || (x - y) < -1);
5202dc36bedSjoris
5212dc36bedSjoris return (x);
5222dc36bedSjoris }
5232dc36bedSjoris
5242dc36bedSjoris static int
stone(int * a,int n,int * b,int * c,int flags)525f5f501bbSmillert stone(int *a, int n, int *b, int *c, int flags)
5262dc36bedSjoris {
5272dc36bedSjoris int i, k, y, j, l;
528df890a16Snicm int oldc, tc, oldl, sq;
529df890a16Snicm u_int numtries, bound;
5302dc36bedSjoris
531df890a16Snicm if (flags & D_MINIMAL)
532df890a16Snicm bound = UINT_MAX;
533df890a16Snicm else {
534df890a16Snicm sq = isqrt(n);
535b9fc9a72Sderaadt bound = MAXIMUM(256, sq);
536df890a16Snicm }
5372dc36bedSjoris
5382dc36bedSjoris k = 0;
539af90d6d1Sray c[0] = newcand(0, 0, 0);
5402dc36bedSjoris for (i = 1; i <= n; i++) {
5412dc36bedSjoris j = a[i];
5422dc36bedSjoris if (j == 0)
5432dc36bedSjoris continue;
5442dc36bedSjoris y = -b[j];
5452dc36bedSjoris oldl = 0;
5462dc36bedSjoris oldc = c[0];
5472dc36bedSjoris numtries = 0;
5482dc36bedSjoris do {
5492dc36bedSjoris if (y <= clist[oldc].y)
5502dc36bedSjoris continue;
5512dc36bedSjoris l = search(c, k, y);
5522dc36bedSjoris if (l != oldl + 1)
5532dc36bedSjoris oldc = c[l - 1];
5542dc36bedSjoris if (l <= k) {
5552dc36bedSjoris if (clist[c[l]].y <= y)
5562dc36bedSjoris continue;
5572dc36bedSjoris tc = c[l];
558af90d6d1Sray c[l] = newcand(i, y, oldc);
5592dc36bedSjoris oldc = tc;
5602dc36bedSjoris oldl = l;
5612dc36bedSjoris numtries++;
5622dc36bedSjoris } else {
563af90d6d1Sray c[l] = newcand(i, y, oldc);
5642dc36bedSjoris k++;
5652dc36bedSjoris break;
5662dc36bedSjoris }
5672dc36bedSjoris } while ((y = b[++j]) > 0 && numtries < bound);
5682dc36bedSjoris }
5692dc36bedSjoris return (k);
5702dc36bedSjoris }
5712dc36bedSjoris
5722dc36bedSjoris static int
newcand(int x,int y,int pred)5732dc36bedSjoris newcand(int x, int y, int pred)
5742dc36bedSjoris {
57580566be2Sray struct cand *q;
5762dc36bedSjoris
5772dc36bedSjoris if (clen == clistlen) {
578f74aa433Sray clistlen = clistlen * 11 / 10;
579caa2ffb0Sderaadt clist = xreallocarray(clist, clistlen, sizeof(*clist));
5802dc36bedSjoris }
5812dc36bedSjoris q = clist + clen;
5822dc36bedSjoris q->x = x;
5832dc36bedSjoris q->y = y;
5842dc36bedSjoris q->pred = pred;
5852dc36bedSjoris return (clen++);
5862dc36bedSjoris }
5872dc36bedSjoris
5882dc36bedSjoris static int
search(int * c,int k,int y)5892dc36bedSjoris search(int *c, int k, int y)
5902dc36bedSjoris {
5912dc36bedSjoris int i, j, l, t;
5922dc36bedSjoris
5932dc36bedSjoris if (clist[c[k]].y < y) /* quick look for typical case */
5942dc36bedSjoris return (k + 1);
5952dc36bedSjoris i = 0;
5962dc36bedSjoris j = k + 1;
5972dc36bedSjoris for (;;) {
5982dc36bedSjoris l = (i + j) / 2;
5992dc36bedSjoris if (l <= i)
6002dc36bedSjoris break;
6012dc36bedSjoris t = clist[c[l]].y;
6022dc36bedSjoris if (t > y)
6032dc36bedSjoris j = l;
6042dc36bedSjoris else if (t < y)
6052dc36bedSjoris i = l;
6062dc36bedSjoris else
6072dc36bedSjoris return (l);
6082dc36bedSjoris }
6092dc36bedSjoris return (l + 1);
6102dc36bedSjoris }
6112dc36bedSjoris
6122dc36bedSjoris static void
unravel(int p)6132dc36bedSjoris unravel(int p)
6142dc36bedSjoris {
6152dc36bedSjoris struct cand *q;
6162dc36bedSjoris int i;
6172dc36bedSjoris
618d2c2f9b1Sray for (i = 0; i <= len[0]; i++)
6192dc36bedSjoris J[i] = i <= pref ? i :
620d2c2f9b1Sray i > len[0] - suff ? i + len[1] - len[0] : 0;
6212dc36bedSjoris for (q = clist + p; q->y != 0; q = clist + q->pred)
6222dc36bedSjoris J[q->x + pref] = q->y + pref;
6232dc36bedSjoris }
6242dc36bedSjoris
6252dc36bedSjoris /*
6262dc36bedSjoris * Check does double duty:
6272dc36bedSjoris * 1. ferret out any fortuitous correspondences due
6282dc36bedSjoris * to confounding by hashing (which result in "jackpot")
6292dc36bedSjoris * 2. collect random access indexes to the two files
6302dc36bedSjoris */
6312dc36bedSjoris static void
check(FILE * f1,FILE * f2,int flags)632f5f501bbSmillert check(FILE *f1, FILE *f2, int flags)
6332dc36bedSjoris {
6342dc36bedSjoris int i, j, jackpot, c, d;
6352dc36bedSjoris long ctold, ctnew;
6362dc36bedSjoris
6372dc36bedSjoris rewind(f1);
6382dc36bedSjoris rewind(f2);
6392dc36bedSjoris j = 1;
6402dc36bedSjoris ixold[0] = ixnew[0] = 0;
6412dc36bedSjoris jackpot = 0;
6422dc36bedSjoris ctold = ctnew = 0;
643d2c2f9b1Sray for (i = 1; i <= len[0]; i++) {
6442dc36bedSjoris if (J[i] == 0) {
6452dc36bedSjoris ixold[i] = ctold += skipline(f1);
6462dc36bedSjoris continue;
6472dc36bedSjoris }
6482dc36bedSjoris while (j < J[i]) {
6492dc36bedSjoris ixnew[j] = ctnew += skipline(f2);
6502dc36bedSjoris j++;
6512dc36bedSjoris }
652f5f501bbSmillert if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE)) {
6532dc36bedSjoris for (;;) {
6542dc36bedSjoris c = getc(f1);
6552dc36bedSjoris d = getc(f2);
6562dc36bedSjoris /*
6572dc36bedSjoris * GNU diff ignores a missing newline
658f5f501bbSmillert * in one file for -b or -w.
6592dc36bedSjoris */
660f5f501bbSmillert if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) &&
6612dc36bedSjoris ((c == EOF && d == '\n') ||
6622dc36bedSjoris (c == '\n' && d == EOF))) {
6632dc36bedSjoris break;
6642dc36bedSjoris }
6652dc36bedSjoris ctold++;
6662dc36bedSjoris ctnew++;
667f5f501bbSmillert if ((flags & D_FOLDBLANKS) && isspace(c) &&
668f5f501bbSmillert isspace(d)) {
6692dc36bedSjoris do {
6702dc36bedSjoris if (c == '\n')
6712dc36bedSjoris break;
6722dc36bedSjoris ctold++;
6732dc36bedSjoris } while (isspace(c = getc(f1)));
6742dc36bedSjoris do {
6752dc36bedSjoris if (d == '\n')
6762dc36bedSjoris break;
6772dc36bedSjoris ctnew++;
6782dc36bedSjoris } while (isspace(d = getc(f2)));
679f5f501bbSmillert } else if ((flags & D_IGNOREBLANKS)) {
6802dc36bedSjoris while (isspace(c) && c != '\n') {
6812dc36bedSjoris c = getc(f1);
6822dc36bedSjoris ctold++;
6832dc36bedSjoris }
6842dc36bedSjoris while (isspace(d) && d != '\n') {
6852dc36bedSjoris d = getc(f2);
6862dc36bedSjoris ctnew++;
6872dc36bedSjoris }
6882dc36bedSjoris }
6892dc36bedSjoris if (chrtran[c] != chrtran[d]) {
6902dc36bedSjoris jackpot++;
6912dc36bedSjoris J[i] = 0;
6922dc36bedSjoris if (c != '\n' && c != EOF)
6932dc36bedSjoris ctold += skipline(f1);
6942dc36bedSjoris if (d != '\n' && c != EOF)
6952dc36bedSjoris ctnew += skipline(f2);
6962dc36bedSjoris break;
6972dc36bedSjoris }
6982dc36bedSjoris if (c == '\n' || c == EOF)
6992dc36bedSjoris break;
7002dc36bedSjoris }
7012dc36bedSjoris } else {
7022dc36bedSjoris for (;;) {
7032dc36bedSjoris ctold++;
7042dc36bedSjoris ctnew++;
7052dc36bedSjoris if ((c = getc(f1)) != (d = getc(f2))) {
7062dc36bedSjoris /* jackpot++; */
7072dc36bedSjoris J[i] = 0;
7082dc36bedSjoris if (c != '\n' && c != EOF)
7092dc36bedSjoris ctold += skipline(f1);
7102dc36bedSjoris if (d != '\n' && c != EOF)
7112dc36bedSjoris ctnew += skipline(f2);
7122dc36bedSjoris break;
7132dc36bedSjoris }
7142dc36bedSjoris if (c == '\n' || c == EOF)
7152dc36bedSjoris break;
7162dc36bedSjoris }
7172dc36bedSjoris }
7182dc36bedSjoris ixold[i] = ctold;
7192dc36bedSjoris ixnew[j] = ctnew;
7202dc36bedSjoris j++;
7212dc36bedSjoris }
722d2c2f9b1Sray for (; j <= len[1]; j++)
7232dc36bedSjoris ixnew[j] = ctnew += skipline(f2);
7242dc36bedSjoris /*
725af90d6d1Sray * if (jackpot)
726af90d6d1Sray * fprintf(stderr, "jackpot\n");
7272dc36bedSjoris */
7282dc36bedSjoris }
7292dc36bedSjoris
7302dc36bedSjoris /* shellsort CACM #201 */
7312dc36bedSjoris static void
sort(struct line * a,int n)7322dc36bedSjoris sort(struct line *a, int n)
7332dc36bedSjoris {
7342dc36bedSjoris struct line *ai, *aim, w;
7352dc36bedSjoris int j, m = 0, k;
7362dc36bedSjoris
7372dc36bedSjoris if (n == 0)
7382dc36bedSjoris return;
7392dc36bedSjoris for (j = 1; j <= n; j *= 2)
7402dc36bedSjoris m = 2 * j - 1;
7412dc36bedSjoris for (m /= 2; m != 0; m /= 2) {
7422dc36bedSjoris k = n - m;
7432dc36bedSjoris for (j = 1; j <= k; j++) {
7442dc36bedSjoris for (ai = &a[j]; ai > a; ai -= m) {
7452dc36bedSjoris aim = &ai[m];
7462dc36bedSjoris if (aim < ai)
7472dc36bedSjoris break; /* wraparound */
7482dc36bedSjoris if (aim->value > ai[0].value ||
7492dc36bedSjoris (aim->value == ai[0].value &&
7502dc36bedSjoris aim->serial > ai[0].serial))
7512dc36bedSjoris break;
7522dc36bedSjoris w.value = ai[0].value;
7532dc36bedSjoris ai[0].value = aim->value;
7542dc36bedSjoris aim->value = w.value;
7552dc36bedSjoris w.serial = ai[0].serial;
7562dc36bedSjoris ai[0].serial = aim->serial;
7572dc36bedSjoris aim->serial = w.serial;
7582dc36bedSjoris }
7592dc36bedSjoris }
7602dc36bedSjoris }
7612dc36bedSjoris }
7622dc36bedSjoris
7632dc36bedSjoris static void
unsort(struct line * f,int l,int * b)7642dc36bedSjoris unsort(struct line *f, int l, int *b)
7652dc36bedSjoris {
7662dc36bedSjoris int *a, i;
7672dc36bedSjoris
7682dc36bedSjoris a = xcalloc(l + 1, sizeof(*a));
7692dc36bedSjoris for (i = 1; i <= l; i++)
7702dc36bedSjoris a[f[i].serial] = f[i].value;
7712dc36bedSjoris for (i = 1; i <= l; i++)
7722dc36bedSjoris b[i] = a[i];
7738ac837e5Snicm free(a);
7742dc36bedSjoris }
7752dc36bedSjoris
7762dc36bedSjoris static int
skipline(FILE * f)7772dc36bedSjoris skipline(FILE *f)
7782dc36bedSjoris {
7792dc36bedSjoris int i, c;
7802dc36bedSjoris
7812dc36bedSjoris for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
7822dc36bedSjoris continue;
7832dc36bedSjoris return (i);
7842dc36bedSjoris }
7852dc36bedSjoris
7862dc36bedSjoris static void
output(FILE * f1,FILE * f2,int flags)787f5f501bbSmillert output(FILE *f1, FILE *f2, int flags)
7882dc36bedSjoris {
7892dc36bedSjoris int m, i0, i1, j0, j1;
7902dc36bedSjoris
7912dc36bedSjoris rewind(f1);
7922dc36bedSjoris rewind(f2);
793d2c2f9b1Sray m = len[0];
7942dc36bedSjoris J[0] = 0;
795d2c2f9b1Sray J[m + 1] = len[1] + 1;
7962dc36bedSjoris for (i0 = 1; i0 <= m; i0 = i1 + 1) {
7972dc36bedSjoris while (i0 <= m && J[i0] == J[i0 - 1] + 1)
7982dc36bedSjoris i0++;
7992dc36bedSjoris j0 = J[i0 - 1] + 1;
8002dc36bedSjoris i1 = i0 - 1;
8012dc36bedSjoris while (i1 < m && J[i1 + 1] == 0)
8022dc36bedSjoris i1++;
8032dc36bedSjoris j1 = J[i1 + 1] - 1;
8042dc36bedSjoris J[i1] = j1;
805f5f501bbSmillert change(f1, f2, i0, i1, j0, j1, flags);
8062dc36bedSjoris }
8072dc36bedSjoris if (m == 0)
808d2c2f9b1Sray change(f1, f2, 1, 0, 1, len[1], flags);
8092dc36bedSjoris if (diff_format == D_IFDEF) {
8102dc36bedSjoris for (;;) {
8112dc36bedSjoris #define c i0
8122dc36bedSjoris if ((c = getc(f1)) == EOF)
8132dc36bedSjoris return;
8142dc36bedSjoris diff_output("%c", c);
8152dc36bedSjoris }
8162dc36bedSjoris #undef c
8172dc36bedSjoris }
8182dc36bedSjoris if (anychange != 0) {
8192dc36bedSjoris if (diff_format == D_CONTEXT)
820f5f501bbSmillert dump_context_vec(f1, f2, flags);
8212dc36bedSjoris else if (diff_format == D_UNIFIED)
822f5f501bbSmillert dump_unified_vec(f1, f2, flags);
8232dc36bedSjoris }
8242dc36bedSjoris }
8252dc36bedSjoris
826ccac42f6Sray static void
range(int a,int b,char * separator)8272dc36bedSjoris range(int a, int b, char *separator)
8282dc36bedSjoris {
8292dc36bedSjoris diff_output("%d", a > b ? b : a);
8302dc36bedSjoris if (a < b)
8312dc36bedSjoris diff_output("%s%d", separator, b);
8322dc36bedSjoris }
8332dc36bedSjoris
834ccac42f6Sray static void
uni_range(int a,int b)8352dc36bedSjoris uni_range(int a, int b)
8362dc36bedSjoris {
8372dc36bedSjoris if (a < b)
8382dc36bedSjoris diff_output("%d,%d", a, b - a + 1);
8392dc36bedSjoris else if (a == b)
8402dc36bedSjoris diff_output("%d", b);
8412dc36bedSjoris else
8422dc36bedSjoris diff_output("%d,0", b);
8432dc36bedSjoris }
8442dc36bedSjoris
8452dc36bedSjoris static char *
preadline(int fd,size_t rlen,off_t off)8462dc36bedSjoris preadline(int fd, size_t rlen, off_t off)
8472dc36bedSjoris {
8482dc36bedSjoris char *line;
8492dc36bedSjoris ssize_t nr;
8502dc36bedSjoris
8512dc36bedSjoris line = xmalloc(rlen + 1);
852*3aaa63ebSderaadt if ((nr = pread(fd, line, rlen, off)) == -1)
8537a6efebcSray err(D_ERROR, "preadline");
8542dc36bedSjoris line[nr] = '\0';
8552dc36bedSjoris return (line);
8562dc36bedSjoris }
8572dc36bedSjoris
8582dc36bedSjoris static int
ignoreline(char * line)8592dc36bedSjoris ignoreline(char *line)
8602dc36bedSjoris {
8612dc36bedSjoris int ret;
8622dc36bedSjoris
863f5f501bbSmillert ret = regexec(diff_ignore_re, line, 0, NULL, 0);
8648ac837e5Snicm free(line);
8652dc36bedSjoris return (ret == 0); /* if it matched, it should be ignored. */
8662dc36bedSjoris }
8672dc36bedSjoris
8682dc36bedSjoris /*
8692dc36bedSjoris * Indicate that there is a difference between lines a and b of the from file
8702dc36bedSjoris * to get to lines c to d of the to file. If a is greater then b then there
8712dc36bedSjoris * are no lines in the from file involved and this means that there were
8722dc36bedSjoris * lines appended (beginning at b). If c is greater than d then there are
8732dc36bedSjoris * lines missing from the to file.
8742dc36bedSjoris */
8752dc36bedSjoris static void
change(FILE * f1,FILE * f2,int a,int b,int c,int d,int flags)876f5f501bbSmillert change(FILE *f1, FILE *f2, int a, int b, int c, int d, int flags)
8772dc36bedSjoris {
8782dc36bedSjoris static size_t max_context = 64;
8792dc36bedSjoris char buf[64];
8802dc36bedSjoris struct tm *t;
881af90d6d1Sray int i;
8822dc36bedSjoris
8832dc36bedSjoris if (diff_format != D_IFDEF && a > b && c > d)
8842dc36bedSjoris return;
885f5f501bbSmillert if (diff_ignore_re != NULL) {
8862dc36bedSjoris char *line;
8872dc36bedSjoris /*
8882dc36bedSjoris * All lines in the change, insert, or delete must
8892dc36bedSjoris * match an ignore pattern for the change to be
8902dc36bedSjoris * ignored.
8912dc36bedSjoris */
8922dc36bedSjoris if (a <= b) { /* Changes and deletes. */
8932dc36bedSjoris for (i = a; i <= b; i++) {
8942dc36bedSjoris line = preadline(fileno(f1),
8952dc36bedSjoris ixold[i] - ixold[i - 1], ixold[i - 1]);
8962dc36bedSjoris if (!ignoreline(line))
8972dc36bedSjoris goto proceed;
8982dc36bedSjoris }
8992dc36bedSjoris }
9002dc36bedSjoris if (a > b || c <= d) { /* Changes and inserts. */
9012dc36bedSjoris for (i = c; i <= d; i++) {
9022dc36bedSjoris line = preadline(fileno(f2),
9032dc36bedSjoris ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
9042dc36bedSjoris if (!ignoreline(line))
9052dc36bedSjoris goto proceed;
9062dc36bedSjoris }
9072dc36bedSjoris }
9082dc36bedSjoris return;
9092dc36bedSjoris }
9102dc36bedSjoris proceed:
9112dc36bedSjoris if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
9122dc36bedSjoris /*
9132dc36bedSjoris * Allocate change records as needed.
9142dc36bedSjoris */
9152dc36bedSjoris if (context_vec_ptr == context_vec_end - 1) {
9162dc36bedSjoris ptrdiff_t offset = context_vec_ptr - context_vec_start;
9172dc36bedSjoris max_context <<= 1;
918caa2ffb0Sderaadt context_vec_start = xreallocarray(context_vec_start,
91980566be2Sray max_context, sizeof(*context_vec_start));
9202dc36bedSjoris context_vec_end = context_vec_start + max_context;
9212dc36bedSjoris context_vec_ptr = context_vec_start + offset;
9222dc36bedSjoris }
9232dc36bedSjoris if (anychange == 0) {
9242dc36bedSjoris /*
9252dc36bedSjoris * Print the context/unidiff header first time through.
9262dc36bedSjoris */
9272dc36bedSjoris t = localtime(&stb1.st_mtime);
9282dc36bedSjoris (void)strftime(buf, sizeof(buf),
9292dc36bedSjoris "%Y/%m/%d %H:%M:%S", t);
9302dc36bedSjoris
9312dc36bedSjoris diff_output("%s %s %s",
9322dc36bedSjoris diff_format == D_CONTEXT ? "***" : "---", diff_file,
9332dc36bedSjoris buf);
9342dc36bedSjoris
9352dc36bedSjoris if (diff_rev1 != NULL) {
9362dc36bedSjoris rcsnum_tostr(diff_rev1, buf, sizeof(buf));
9372dc36bedSjoris diff_output("\t%s", buf);
9382dc36bedSjoris }
9392dc36bedSjoris
9402dc36bedSjoris printf("\n");
9412dc36bedSjoris
9422dc36bedSjoris t = localtime(&stb2.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_rev2 != NULL) {
9512dc36bedSjoris rcsnum_tostr(diff_rev2, buf, sizeof(buf));
9522dc36bedSjoris diff_output("\t%s", buf);
9532dc36bedSjoris }
9542dc36bedSjoris
9552dc36bedSjoris printf("\n");
9562dc36bedSjoris anychange = 1;
957f5f501bbSmillert } else if (a > context_vec_ptr->b + (2 * diff_context) + 1 &&
958f5f501bbSmillert c > context_vec_ptr->d + (2 * diff_context) + 1) {
9592dc36bedSjoris /*
960af90d6d1Sray * If this change is more than 'diff_context' lines from the
961af90d6d1Sray * previous change, dump the record and reset it.
9622dc36bedSjoris */
9632dc36bedSjoris if (diff_format == D_CONTEXT)
964f5f501bbSmillert dump_context_vec(f1, f2, flags);
9652dc36bedSjoris else
966f5f501bbSmillert dump_unified_vec(f1, f2, flags);
9672dc36bedSjoris }
9682dc36bedSjoris context_vec_ptr++;
9692dc36bedSjoris context_vec_ptr->a = a;
9702dc36bedSjoris context_vec_ptr->b = b;
9712dc36bedSjoris context_vec_ptr->c = c;
9722dc36bedSjoris context_vec_ptr->d = d;
9732dc36bedSjoris return;
9742dc36bedSjoris }
9752dc36bedSjoris if (anychange == 0)
9762dc36bedSjoris anychange = 1;
9772dc36bedSjoris switch (diff_format) {
9782dc36bedSjoris case D_BRIEF:
9792dc36bedSjoris return;
9802dc36bedSjoris case D_NORMAL:
9812dc36bedSjoris range(a, b, ",");
9822dc36bedSjoris diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
9832dc36bedSjoris if (diff_format == D_NORMAL)
9842dc36bedSjoris range(c, d, ",");
9852dc36bedSjoris diff_output("\n");
9862dc36bedSjoris break;
9872dc36bedSjoris case D_RCSDIFF:
9882dc36bedSjoris if (a > b)
9892dc36bedSjoris diff_output("a%d %d\n", b, d - c + 1);
9902dc36bedSjoris else {
9912dc36bedSjoris diff_output("d%d %d\n", a, b - a + 1);
9922dc36bedSjoris
9932dc36bedSjoris if (!(c > d)) /* add changed lines */
9942dc36bedSjoris diff_output("a%d %d\n", b, d - c + 1);
9952dc36bedSjoris }
9962dc36bedSjoris break;
9972dc36bedSjoris }
9982dc36bedSjoris if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
999f5f501bbSmillert fetch(ixold, a, b, f1, '<', 1, flags);
10002dc36bedSjoris if (a <= b && c <= d && diff_format == D_NORMAL)
10012dc36bedSjoris diff_output("---\n");
10022dc36bedSjoris }
1003f5f501bbSmillert fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, flags);
10042dc36bedSjoris if (inifdef) {
10052dc36bedSjoris diff_output("#endif /* %s */\n", ifdefname);
10062dc36bedSjoris inifdef = 0;
10072dc36bedSjoris }
10082dc36bedSjoris }
10092dc36bedSjoris
10102dc36bedSjoris static void
fetch(long * f,int a,int b,FILE * lb,int ch,int oldfile,int flags)1011f5f501bbSmillert fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags)
10122dc36bedSjoris {
10132dc36bedSjoris long j, nc;
10142dc36bedSjoris int i, c, col;
10152dc36bedSjoris
10162dc36bedSjoris /*
10172dc36bedSjoris * When doing #ifdef's, copy down to current line
10182dc36bedSjoris * if this is the first file, so that stuff makes it to output.
10192dc36bedSjoris */
10202dc36bedSjoris if (diff_format == D_IFDEF && oldfile) {
10212dc36bedSjoris long curpos = ftell(lb);
10222dc36bedSjoris /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
10232dc36bedSjoris nc = f[a > b ? b : a - 1] - curpos;
10242dc36bedSjoris for (i = 0; i < nc; i++)
10252dc36bedSjoris diff_output("%c", getc(lb));
10262dc36bedSjoris }
10272dc36bedSjoris if (a > b)
10282dc36bedSjoris return;
10292dc36bedSjoris if (diff_format == D_IFDEF) {
10302dc36bedSjoris if (inifdef) {
10312dc36bedSjoris diff_output("#else /* %s%s */\n",
10322dc36bedSjoris oldfile == 1 ? "!" : "", ifdefname);
10332dc36bedSjoris } else {
10342dc36bedSjoris if (oldfile)
10352dc36bedSjoris diff_output("#ifndef %s\n", ifdefname);
10362dc36bedSjoris else
10372dc36bedSjoris diff_output("#ifdef %s\n", ifdefname);
10382dc36bedSjoris }
10392dc36bedSjoris inifdef = 1 + oldfile;
10402dc36bedSjoris }
10412dc36bedSjoris for (i = a; i <= b; i++) {
10422dc36bedSjoris fseek(lb, f[i - 1], SEEK_SET);
10432dc36bedSjoris nc = f[i] - f[i - 1];
10442dc36bedSjoris if (diff_format != D_IFDEF && ch != '\0') {
10452dc36bedSjoris diff_output("%c", ch);
1046f5f501bbSmillert if (diff_format != D_UNIFIED)
10472dc36bedSjoris diff_output(" ");
10482dc36bedSjoris }
10492dc36bedSjoris col = 0;
10502dc36bedSjoris for (j = 0; j < nc; j++) {
10512dc36bedSjoris if ((c = getc(lb)) == EOF) {
10522dc36bedSjoris if (diff_format == D_RCSDIFF)
1053300eb659Sray warnx("No newline at end of file");
10542dc36bedSjoris else
10552dc36bedSjoris diff_output("\n\\ No newline at end of "
10562dc36bedSjoris "file");
10572dc36bedSjoris return;
10582dc36bedSjoris }
1059f5f501bbSmillert if (c == '\t' && (flags & D_EXPANDTABS)) {
10602dc36bedSjoris do {
10612dc36bedSjoris diff_output(" ");
10622dc36bedSjoris } while (++col & 7);
10632dc36bedSjoris } else {
10642dc36bedSjoris diff_output("%c", c);
10652dc36bedSjoris col++;
10662dc36bedSjoris }
10672dc36bedSjoris }
10682dc36bedSjoris }
10692dc36bedSjoris }
10702dc36bedSjoris
10712dc36bedSjoris /*
10722dc36bedSjoris * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
10732dc36bedSjoris */
10742dc36bedSjoris static int
readhash(FILE * f,int flags)1075f5f501bbSmillert readhash(FILE *f, int flags)
10762dc36bedSjoris {
10772dc36bedSjoris int i, t, space;
10782dc36bedSjoris int sum;
10792dc36bedSjoris
10802dc36bedSjoris sum = 1;
10812dc36bedSjoris space = 0;
1082f5f501bbSmillert if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) {
1083f5f501bbSmillert if (flags & D_IGNORECASE)
10842dc36bedSjoris for (i = 0; (t = getc(f)) != '\n'; i++) {
10852dc36bedSjoris if (t == EOF) {
10862dc36bedSjoris if (i == 0)
10872dc36bedSjoris return (0);
10882dc36bedSjoris break;
10892dc36bedSjoris }
10902dc36bedSjoris sum = sum * 127 + chrtran[t];
10912dc36bedSjoris }
10922dc36bedSjoris else
10932dc36bedSjoris for (i = 0; (t = getc(f)) != '\n'; i++) {
10942dc36bedSjoris if (t == EOF) {
10952dc36bedSjoris if (i == 0)
10962dc36bedSjoris return (0);
10972dc36bedSjoris break;
10982dc36bedSjoris }
10992dc36bedSjoris sum = sum * 127 + t;
11002dc36bedSjoris }
11012dc36bedSjoris } else {
11022dc36bedSjoris for (i = 0;;) {
11032dc36bedSjoris switch (t = getc(f)) {
11042dc36bedSjoris case '\t':
1105af90d6d1Sray case '\r':
1106af90d6d1Sray case '\v':
1107af90d6d1Sray case '\f':
11082dc36bedSjoris case ' ':
11092dc36bedSjoris space++;
11102dc36bedSjoris continue;
11112dc36bedSjoris default:
1112f5f501bbSmillert if (space && (flags & D_IGNOREBLANKS) == 0) {
11132dc36bedSjoris i++;
11142dc36bedSjoris space = 0;
11152dc36bedSjoris }
11162dc36bedSjoris sum = sum * 127 + chrtran[t];
11172dc36bedSjoris i++;
11182dc36bedSjoris continue;
11192dc36bedSjoris case EOF:
11202dc36bedSjoris if (i == 0)
11212dc36bedSjoris return (0);
11222dc36bedSjoris /* FALLTHROUGH */
11232dc36bedSjoris case '\n':
11242dc36bedSjoris break;
11252dc36bedSjoris }
11262dc36bedSjoris break;
11272dc36bedSjoris }
11282dc36bedSjoris }
11292dc36bedSjoris /*
11302dc36bedSjoris * There is a remote possibility that we end up with a zero sum.
11312dc36bedSjoris * Zero is used as an EOF marker, so return 1 instead.
11322dc36bedSjoris */
11332dc36bedSjoris return (sum == 0 ? 1 : sum);
11342dc36bedSjoris }
11352dc36bedSjoris
11362dc36bedSjoris static int
asciifile(FILE * f)11372dc36bedSjoris asciifile(FILE *f)
11382dc36bedSjoris {
1139af90d6d1Sray unsigned char buf[BUFSIZ];
11400a91b02cSstsp size_t cnt;
11412dc36bedSjoris
1142f5f501bbSmillert if (f == NULL)
11432dc36bedSjoris return (1);
11442dc36bedSjoris
11452dc36bedSjoris rewind(f);
114685ea658bSray cnt = fread(buf, 1, sizeof(buf), f);
11470a91b02cSstsp return (memchr(buf, '\0', cnt) == NULL);
11482dc36bedSjoris }
11492dc36bedSjoris
1150e22e6974Sxsa #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
1151e22e6974Sxsa
11522dc36bedSjoris static char *
match_function(const long * f,int pos,FILE * fp)11532dc36bedSjoris match_function(const long *f, int pos, FILE *fp)
11542dc36bedSjoris {
11552dc36bedSjoris unsigned char buf[FUNCTION_CONTEXT_SIZE];
11562dc36bedSjoris size_t nc;
11572dc36bedSjoris int last = lastline;
1158e22e6974Sxsa char *state = NULL;
11592dc36bedSjoris
11602dc36bedSjoris lastline = pos;
11612dc36bedSjoris while (pos > last) {
11622dc36bedSjoris fseek(fp, f[pos - 1], SEEK_SET);
11632dc36bedSjoris nc = f[pos] - f[pos - 1];
11642dc36bedSjoris if (nc >= sizeof(buf))
11652dc36bedSjoris nc = sizeof(buf) - 1;
116685ea658bSray nc = fread(buf, 1, nc, fp);
11672dc36bedSjoris if (nc > 0) {
11682dc36bedSjoris buf[nc] = '\0';
11694fd6ed32Sgilles buf[strcspn(buf, "\n")] = '\0';
11702dc36bedSjoris if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
1171e22e6974Sxsa if (begins_with(buf, "private:")) {
1172e22e6974Sxsa if (!state)
1173e22e6974Sxsa state = " (private)";
1174e22e6974Sxsa } else if (begins_with(buf, "protected:")) {
1175e22e6974Sxsa if (!state)
1176e22e6974Sxsa state = " (protected)";
1177e22e6974Sxsa } else if (begins_with(buf, "public:")) {
1178e22e6974Sxsa if (!state)
1179e22e6974Sxsa state = " (public)";
1180e22e6974Sxsa } else {
1181eea21b3cSray if (strlcpy(lastbuf, buf,
11826b99bb86Sray sizeof(lastbuf)) >= sizeof(lastbuf))
1183e22e6974Sxsa errx(1,
1184e22e6974Sxsa "match_function: strlcpy");
11852dc36bedSjoris lastmatchline = pos;
11862dc36bedSjoris return lastbuf;
11872dc36bedSjoris }
11882dc36bedSjoris }
1189e22e6974Sxsa }
11902dc36bedSjoris pos--;
11912dc36bedSjoris }
1192af90d6d1Sray return lastmatchline > 0 ? lastbuf : NULL;
11932dc36bedSjoris }
11942dc36bedSjoris
11952dc36bedSjoris /* dump accumulated "context" diff changes */
11962dc36bedSjoris static void
dump_context_vec(FILE * f1,FILE * f2,int flags)1197f5f501bbSmillert dump_context_vec(FILE *f1, FILE *f2, int flags)
11982dc36bedSjoris {
11992dc36bedSjoris struct context_vec *cvp = context_vec_start;
12002dc36bedSjoris int lowa, upb, lowc, upd, do_output;
12012dc36bedSjoris int a, b, c, d;
12022dc36bedSjoris char ch, *f;
12032dc36bedSjoris
12042dc36bedSjoris if (context_vec_start > context_vec_ptr)
12052dc36bedSjoris return;
12062dc36bedSjoris
12072dc36bedSjoris b = d = 0; /* gcc */
1208b9fc9a72Sderaadt lowa = MAXIMUM(1, cvp->a - diff_context);
1209b9fc9a72Sderaadt upb = MINIMUM(len[0], context_vec_ptr->b + diff_context);
1210b9fc9a72Sderaadt lowc = MAXIMUM(1, cvp->c - diff_context);
1211b9fc9a72Sderaadt upd = MINIMUM(len[1], context_vec_ptr->d + diff_context);
12122dc36bedSjoris
12132dc36bedSjoris diff_output("***************");
1214f5f501bbSmillert if ((flags & D_PROTOTYPE)) {
12152dc36bedSjoris f = match_function(ixold, lowa-1, f1);
1216d5d01609Sray if (f != NULL)
12172dc36bedSjoris diff_output(" %s", f);
12182dc36bedSjoris }
12192dc36bedSjoris diff_output("\n*** ");
12202dc36bedSjoris range(lowa, upb, ",");
12212dc36bedSjoris diff_output(" ****\n");
12222dc36bedSjoris
12232dc36bedSjoris /*
12242dc36bedSjoris * Output changes to the "old" file. The first loop suppresses
12252dc36bedSjoris * output if there were no changes to the "old" file (we'll see
12262dc36bedSjoris * the "old" lines as context in the "new" list).
12272dc36bedSjoris */
12282dc36bedSjoris do_output = 0;
12292dc36bedSjoris for (; cvp <= context_vec_ptr; cvp++)
12302dc36bedSjoris if (cvp->a <= cvp->b) {
12312dc36bedSjoris cvp = context_vec_start;
12322dc36bedSjoris do_output++;
12332dc36bedSjoris break;
12342dc36bedSjoris }
1235af90d6d1Sray if (do_output) {
12362dc36bedSjoris while (cvp <= context_vec_ptr) {
12372dc36bedSjoris a = cvp->a;
12382dc36bedSjoris b = cvp->b;
12392dc36bedSjoris c = cvp->c;
12402dc36bedSjoris d = cvp->d;
12412dc36bedSjoris
12422dc36bedSjoris if (a <= b && c <= d)
12432dc36bedSjoris ch = 'c';
12442dc36bedSjoris else
12452dc36bedSjoris ch = (a <= b) ? 'd' : 'a';
12462dc36bedSjoris
12472dc36bedSjoris if (ch == 'a')
1248f5f501bbSmillert fetch(ixold, lowa, b, f1, ' ', 0, flags);
12492dc36bedSjoris else {
1250f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
12512dc36bedSjoris fetch(ixold, a, b, f1,
1252f5f501bbSmillert ch == 'c' ? '!' : '-', 0, flags);
12532dc36bedSjoris }
12542dc36bedSjoris lowa = b + 1;
12552dc36bedSjoris cvp++;
12562dc36bedSjoris }
1257f5f501bbSmillert fetch(ixold, b + 1, upb, f1, ' ', 0, flags);
12582dc36bedSjoris }
12592dc36bedSjoris /* output changes to the "new" file */
12602dc36bedSjoris diff_output("--- ");
12612dc36bedSjoris range(lowc, upd, ",");
12622dc36bedSjoris diff_output(" ----\n");
12632dc36bedSjoris
12642dc36bedSjoris do_output = 0;
12652dc36bedSjoris for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
12662dc36bedSjoris if (cvp->c <= cvp->d) {
12672dc36bedSjoris cvp = context_vec_start;
12682dc36bedSjoris do_output++;
12692dc36bedSjoris break;
12702dc36bedSjoris }
1271af90d6d1Sray if (do_output) {
12722dc36bedSjoris while (cvp <= context_vec_ptr) {
12732dc36bedSjoris a = cvp->a;
12742dc36bedSjoris b = cvp->b;
12752dc36bedSjoris c = cvp->c;
12762dc36bedSjoris d = cvp->d;
12772dc36bedSjoris
12782dc36bedSjoris if (a <= b && c <= d)
12792dc36bedSjoris ch = 'c';
12802dc36bedSjoris else
12812dc36bedSjoris ch = (a <= b) ? 'd' : 'a';
12822dc36bedSjoris
12832dc36bedSjoris if (ch == 'd')
1284f5f501bbSmillert fetch(ixnew, lowc, d, f2, ' ', 0, flags);
12852dc36bedSjoris else {
1286f5f501bbSmillert fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
12872dc36bedSjoris fetch(ixnew, c, d, f2,
1288f5f501bbSmillert ch == 'c' ? '!' : '+', 0, flags);
12892dc36bedSjoris }
12902dc36bedSjoris lowc = d + 1;
12912dc36bedSjoris cvp++;
12922dc36bedSjoris }
1293f5f501bbSmillert fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
12942dc36bedSjoris }
12952dc36bedSjoris context_vec_ptr = context_vec_start - 1;
12962dc36bedSjoris }
12972dc36bedSjoris
12982dc36bedSjoris /* dump accumulated "unified" diff changes */
12992dc36bedSjoris static void
dump_unified_vec(FILE * f1,FILE * f2,int flags)1300f5f501bbSmillert dump_unified_vec(FILE *f1, FILE *f2, int flags)
13012dc36bedSjoris {
13022dc36bedSjoris struct context_vec *cvp = context_vec_start;
13032dc36bedSjoris int lowa, upb, lowc, upd;
13042dc36bedSjoris int a, b, c, d;
13052dc36bedSjoris char ch, *f;
13062dc36bedSjoris
13072dc36bedSjoris if (context_vec_start > context_vec_ptr)
13082dc36bedSjoris return;
13092dc36bedSjoris
131093443395Sotto d = 0; /* gcc */
1311b9fc9a72Sderaadt lowa = MAXIMUM(1, cvp->a - diff_context);
1312b9fc9a72Sderaadt upb = MINIMUM(len[0], context_vec_ptr->b + diff_context);
1313b9fc9a72Sderaadt lowc = MAXIMUM(1, cvp->c - diff_context);
1314b9fc9a72Sderaadt upd = MINIMUM(len[1], context_vec_ptr->d + diff_context);
13152dc36bedSjoris
13162dc36bedSjoris diff_output("@@ -");
13172dc36bedSjoris uni_range(lowa, upb);
13182dc36bedSjoris diff_output(" +");
13192dc36bedSjoris uni_range(lowc, upd);
13202dc36bedSjoris diff_output(" @@");
1321f5f501bbSmillert if ((flags & D_PROTOTYPE)) {
13222dc36bedSjoris f = match_function(ixold, lowa-1, f1);
1323d5d01609Sray if (f != NULL)
13242dc36bedSjoris diff_output(" %s", f);
13252dc36bedSjoris }
13262dc36bedSjoris diff_output("\n");
13272dc36bedSjoris
13282dc36bedSjoris /*
13292dc36bedSjoris * Output changes in "unified" diff format--the old and new lines
13302dc36bedSjoris * are printed together.
13312dc36bedSjoris */
13322dc36bedSjoris for (; cvp <= context_vec_ptr; cvp++) {
13332dc36bedSjoris a = cvp->a;
13342dc36bedSjoris b = cvp->b;
13352dc36bedSjoris c = cvp->c;
13362dc36bedSjoris d = cvp->d;
13372dc36bedSjoris
13382dc36bedSjoris /*
13392dc36bedSjoris * c: both new and old changes
13402dc36bedSjoris * d: only changes in the old file
13412dc36bedSjoris * a: only changes in the new file
13422dc36bedSjoris */
13432dc36bedSjoris if (a <= b && c <= d)
13442dc36bedSjoris ch = 'c';
13452dc36bedSjoris else
13462dc36bedSjoris ch = (a <= b) ? 'd' : 'a';
13472dc36bedSjoris
13482dc36bedSjoris switch (ch) {
13492dc36bedSjoris case 'c':
1350f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
1351f5f501bbSmillert fetch(ixold, a, b, f1, '-', 0, flags);
1352f5f501bbSmillert fetch(ixnew, c, d, f2, '+', 0, flags);
13532dc36bedSjoris break;
13542dc36bedSjoris case 'd':
1355f5f501bbSmillert fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
1356f5f501bbSmillert fetch(ixold, a, b, f1, '-', 0, flags);
13572dc36bedSjoris break;
13582dc36bedSjoris case 'a':
1359f5f501bbSmillert fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
1360f5f501bbSmillert fetch(ixnew, c, d, f2, '+', 0, flags);
13612dc36bedSjoris break;
13622dc36bedSjoris }
13632dc36bedSjoris lowa = b + 1;
13642dc36bedSjoris lowc = d + 1;
13652dc36bedSjoris }
1366f5f501bbSmillert fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
13672dc36bedSjoris
13682dc36bedSjoris context_vec_ptr = context_vec_start - 1;
13692dc36bedSjoris }
13702dc36bedSjoris
13712dc36bedSjoris void
diff_output(const char * fmt,...)13722dc36bedSjoris diff_output(const char *fmt, ...)
13732dc36bedSjoris {
13742dc36bedSjoris va_list vap;
13752dc36bedSjoris int i;
13762dc36bedSjoris char *str;
13772dc36bedSjoris
13782dc36bedSjoris va_start(vap, fmt);
13792dc36bedSjoris i = vasprintf(&str, fmt, vap);
13802dc36bedSjoris va_end(vap);
13812dc36bedSjoris if (i == -1)
1382d4625ebbSxsa err(1, "diff_output");
13832dc36bedSjoris if (diffbuf != NULL)
13847bb3ddb0Sray buf_append(diffbuf, str, strlen(str));
13852dc36bedSjoris else
13862dc36bedSjoris printf("%s", str);
13878ac837e5Snicm free(str);
13882dc36bedSjoris }
1389