xref: /freebsd/usr.bin/diff/diffreg.c (revision 3bbe3f672e37e4f609adb3be3a6476edce2243ec)
1*3bbe3f67SBaptiste Daroussin /*	$OpenBSD: diffreg.c,v 1.91 2016/03/01 20:57:35 natano Exp $	*/
2*3bbe3f67SBaptiste Daroussin 
3*3bbe3f67SBaptiste Daroussin /*
4*3bbe3f67SBaptiste Daroussin  * Copyright (C) Caldera International Inc.  2001-2002.
5*3bbe3f67SBaptiste Daroussin  * All rights reserved.
6*3bbe3f67SBaptiste Daroussin  *
7*3bbe3f67SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
8*3bbe3f67SBaptiste Daroussin  * modification, are permitted provided that the following conditions
9*3bbe3f67SBaptiste Daroussin  * are met:
10*3bbe3f67SBaptiste Daroussin  * 1. Redistributions of source code and documentation must retain the above
11*3bbe3f67SBaptiste Daroussin  *    copyright notice, this list of conditions and the following disclaimer.
12*3bbe3f67SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
13*3bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
14*3bbe3f67SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
15*3bbe3f67SBaptiste Daroussin  * 3. All advertising materials mentioning features or use of this software
16*3bbe3f67SBaptiste Daroussin  *    must display the following acknowledgement:
17*3bbe3f67SBaptiste Daroussin  *	This product includes software developed or owned by Caldera
18*3bbe3f67SBaptiste Daroussin  *	International, Inc.
19*3bbe3f67SBaptiste Daroussin  * 4. Neither the name of Caldera International, Inc. nor the names of other
20*3bbe3f67SBaptiste Daroussin  *    contributors may be used to endorse or promote products derived from
21*3bbe3f67SBaptiste Daroussin  *    this software without specific prior written permission.
22*3bbe3f67SBaptiste Daroussin  *
23*3bbe3f67SBaptiste Daroussin  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
24*3bbe3f67SBaptiste Daroussin  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
25*3bbe3f67SBaptiste Daroussin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26*3bbe3f67SBaptiste Daroussin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27*3bbe3f67SBaptiste Daroussin  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
28*3bbe3f67SBaptiste Daroussin  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29*3bbe3f67SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30*3bbe3f67SBaptiste Daroussin  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*3bbe3f67SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32*3bbe3f67SBaptiste Daroussin  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33*3bbe3f67SBaptiste Daroussin  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34*3bbe3f67SBaptiste Daroussin  * POSSIBILITY OF SUCH DAMAGE.
35*3bbe3f67SBaptiste Daroussin  */
36*3bbe3f67SBaptiste Daroussin /*-
37*3bbe3f67SBaptiste Daroussin  * Copyright (c) 1991, 1993
38*3bbe3f67SBaptiste Daroussin  *	The Regents of the University of California.  All rights reserved.
39*3bbe3f67SBaptiste Daroussin  *
40*3bbe3f67SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
41*3bbe3f67SBaptiste Daroussin  * modification, are permitted provided that the following conditions
42*3bbe3f67SBaptiste Daroussin  * are met:
43*3bbe3f67SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
44*3bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
45*3bbe3f67SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
46*3bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
47*3bbe3f67SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
48*3bbe3f67SBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
49*3bbe3f67SBaptiste Daroussin  *    may be used to endorse or promote products derived from this software
50*3bbe3f67SBaptiste Daroussin  *    without specific prior written permission.
51*3bbe3f67SBaptiste Daroussin  *
52*3bbe3f67SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53*3bbe3f67SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54*3bbe3f67SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55*3bbe3f67SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56*3bbe3f67SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57*3bbe3f67SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58*3bbe3f67SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59*3bbe3f67SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60*3bbe3f67SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61*3bbe3f67SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62*3bbe3f67SBaptiste Daroussin  * SUCH DAMAGE.
63*3bbe3f67SBaptiste Daroussin  *
64*3bbe3f67SBaptiste Daroussin  *	@(#)diffreg.c   8.1 (Berkeley) 6/6/93
65*3bbe3f67SBaptiste Daroussin  */
66*3bbe3f67SBaptiste Daroussin 
67*3bbe3f67SBaptiste Daroussin #include <sys/cdefs.h>
68*3bbe3f67SBaptiste Daroussin __FBSDID("$FreeBSD$");
69*3bbe3f67SBaptiste Daroussin 
70*3bbe3f67SBaptiste Daroussin #include <sys/capsicum.h>
71*3bbe3f67SBaptiste Daroussin #include <sys/procdesc.h>
72*3bbe3f67SBaptiste Daroussin #include <sys/stat.h>
73*3bbe3f67SBaptiste Daroussin #include <sys/types.h>
74*3bbe3f67SBaptiste Daroussin #include <sys/event.h>
75*3bbe3f67SBaptiste Daroussin #include <sys/wait.h>
76*3bbe3f67SBaptiste Daroussin 
77*3bbe3f67SBaptiste Daroussin #include <capsicum_helpers.h>
78*3bbe3f67SBaptiste Daroussin #include <ctype.h>
79*3bbe3f67SBaptiste Daroussin #include <err.h>
80*3bbe3f67SBaptiste Daroussin #include <errno.h>
81*3bbe3f67SBaptiste Daroussin #include <fcntl.h>
82*3bbe3f67SBaptiste Daroussin #include <paths.h>
83*3bbe3f67SBaptiste Daroussin #include <stddef.h>
84*3bbe3f67SBaptiste Daroussin #include <stdint.h>
85*3bbe3f67SBaptiste Daroussin #include <stdio.h>
86*3bbe3f67SBaptiste Daroussin #include <stdlib.h>
87*3bbe3f67SBaptiste Daroussin #include <string.h>
88*3bbe3f67SBaptiste Daroussin #include <unistd.h>
89*3bbe3f67SBaptiste Daroussin #include <limits.h>
90*3bbe3f67SBaptiste Daroussin #include <signal.h>
91*3bbe3f67SBaptiste Daroussin 
92*3bbe3f67SBaptiste Daroussin #include "diff.h"
93*3bbe3f67SBaptiste Daroussin #include "xmalloc.h"
94*3bbe3f67SBaptiste Daroussin 
95*3bbe3f67SBaptiste Daroussin #define _PATH_PR "/usr/bin/pr"
96*3bbe3f67SBaptiste Daroussin 
97*3bbe3f67SBaptiste Daroussin #ifdef ST_MTIM_NSEC
98*3bbe3f67SBaptiste Daroussin # define TIMESPEC_NS(timespec) ((timespec).ST_MTIM_NSEC)
99*3bbe3f67SBaptiste Daroussin #else
100*3bbe3f67SBaptiste Daroussin # define TIMESPEC_NS(timespec) 0
101*3bbe3f67SBaptiste Daroussin #endif
102*3bbe3f67SBaptiste Daroussin 
103*3bbe3f67SBaptiste Daroussin #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
104*3bbe3f67SBaptiste Daroussin #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
105*3bbe3f67SBaptiste Daroussin 
106*3bbe3f67SBaptiste Daroussin /*
107*3bbe3f67SBaptiste Daroussin  * diff - compare two files.
108*3bbe3f67SBaptiste Daroussin  */
109*3bbe3f67SBaptiste Daroussin 
110*3bbe3f67SBaptiste Daroussin /*
111*3bbe3f67SBaptiste Daroussin  *	Uses an algorithm due to Harold Stone, which finds
112*3bbe3f67SBaptiste Daroussin  *	a pair of longest identical subsequences in the two
113*3bbe3f67SBaptiste Daroussin  *	files.
114*3bbe3f67SBaptiste Daroussin  *
115*3bbe3f67SBaptiste Daroussin  *	The major goal is to generate the match vector J.
116*3bbe3f67SBaptiste Daroussin  *	J[i] is the index of the line in file1 corresponding
117*3bbe3f67SBaptiste Daroussin  *	to line i file0. J[i] = 0 if there is no
118*3bbe3f67SBaptiste Daroussin  *	such line in file1.
119*3bbe3f67SBaptiste Daroussin  *
120*3bbe3f67SBaptiste Daroussin  *	Lines are hashed so as to work in core. All potential
121*3bbe3f67SBaptiste Daroussin  *	matches are located by sorting the lines of each file
122*3bbe3f67SBaptiste Daroussin  *	on the hash (called ``value''). In particular, this
123*3bbe3f67SBaptiste Daroussin  *	collects the equivalence classes in file1 together.
124*3bbe3f67SBaptiste Daroussin  *	Subroutine equiv replaces the value of each line in
125*3bbe3f67SBaptiste Daroussin  *	file0 by the index of the first element of its
126*3bbe3f67SBaptiste Daroussin  *	matching equivalence in (the reordered) file1.
127*3bbe3f67SBaptiste Daroussin  *	To save space equiv squeezes file1 into a single
128*3bbe3f67SBaptiste Daroussin  *	array member in which the equivalence classes
129*3bbe3f67SBaptiste Daroussin  *	are simply concatenated, except that their first
130*3bbe3f67SBaptiste Daroussin  *	members are flagged by changing sign.
131*3bbe3f67SBaptiste Daroussin  *
132*3bbe3f67SBaptiste Daroussin  *	Next the indices that point into member are unsorted into
133*3bbe3f67SBaptiste Daroussin  *	array class according to the original order of file0.
134*3bbe3f67SBaptiste Daroussin  *
135*3bbe3f67SBaptiste Daroussin  *	The cleverness lies in routine stone. This marches
136*3bbe3f67SBaptiste Daroussin  *	through the lines of file0, developing a vector klist
137*3bbe3f67SBaptiste Daroussin  *	of "k-candidates". At step i a k-candidate is a matched
138*3bbe3f67SBaptiste Daroussin  *	pair of lines x,y (x in file0 y in file1) such that
139*3bbe3f67SBaptiste Daroussin  *	there is a common subsequence of length k
140*3bbe3f67SBaptiste Daroussin  *	between the first i lines of file0 and the first y
141*3bbe3f67SBaptiste Daroussin  *	lines of file1, but there is no such subsequence for
142*3bbe3f67SBaptiste Daroussin  *	any smaller y. x is the earliest possible mate to y
143*3bbe3f67SBaptiste Daroussin  *	that occurs in such a subsequence.
144*3bbe3f67SBaptiste Daroussin  *
145*3bbe3f67SBaptiste Daroussin  *	Whenever any of the members of the equivalence class of
146*3bbe3f67SBaptiste Daroussin  *	lines in file1 matable to a line in file0 has serial number
147*3bbe3f67SBaptiste Daroussin  *	less than the y of some k-candidate, that k-candidate
148*3bbe3f67SBaptiste Daroussin  *	with the smallest such y is replaced. The new
149*3bbe3f67SBaptiste Daroussin  *	k-candidate is chained (via pred) to the current
150*3bbe3f67SBaptiste Daroussin  *	k-1 candidate so that the actual subsequence can
151*3bbe3f67SBaptiste Daroussin  *	be recovered. When a member has serial number greater
152*3bbe3f67SBaptiste Daroussin  *	that the y of all k-candidates, the klist is extended.
153*3bbe3f67SBaptiste Daroussin  *	At the end, the longest subsequence is pulled out
154*3bbe3f67SBaptiste Daroussin  *	and placed in the array J by unravel
155*3bbe3f67SBaptiste Daroussin  *
156*3bbe3f67SBaptiste Daroussin  *	With J in hand, the matches there recorded are
157*3bbe3f67SBaptiste Daroussin  *	check'ed against reality to assure that no spurious
158*3bbe3f67SBaptiste Daroussin  *	matches have crept in due to hashing. If they have,
159*3bbe3f67SBaptiste Daroussin  *	they are broken, and "jackpot" is recorded--a harmless
160*3bbe3f67SBaptiste Daroussin  *	matter except that a true match for a spuriously
161*3bbe3f67SBaptiste Daroussin  *	mated line may now be unnecessarily reported as a change.
162*3bbe3f67SBaptiste Daroussin  *
163*3bbe3f67SBaptiste Daroussin  *	Much of the complexity of the program comes simply
164*3bbe3f67SBaptiste Daroussin  *	from trying to minimize core utilization and
165*3bbe3f67SBaptiste Daroussin  *	maximize the range of doable problems by dynamically
166*3bbe3f67SBaptiste Daroussin  *	allocating what is needed and reusing what is not.
167*3bbe3f67SBaptiste Daroussin  *	The core requirements for problems larger than somewhat
168*3bbe3f67SBaptiste Daroussin  *	are (in words) 2*length(file0) + length(file1) +
169*3bbe3f67SBaptiste Daroussin  *	3*(number of k-candidates installed),  typically about
170*3bbe3f67SBaptiste Daroussin  *	6n words for files of length n.
171*3bbe3f67SBaptiste Daroussin  */
172*3bbe3f67SBaptiste Daroussin 
173*3bbe3f67SBaptiste Daroussin struct cand {
174*3bbe3f67SBaptiste Daroussin 	int	x;
175*3bbe3f67SBaptiste Daroussin 	int	y;
176*3bbe3f67SBaptiste Daroussin 	int	pred;
177*3bbe3f67SBaptiste Daroussin };
178*3bbe3f67SBaptiste Daroussin 
179*3bbe3f67SBaptiste Daroussin static struct line {
180*3bbe3f67SBaptiste Daroussin 	int	serial;
181*3bbe3f67SBaptiste Daroussin 	int	value;
182*3bbe3f67SBaptiste Daroussin } *file[2];
183*3bbe3f67SBaptiste Daroussin 
184*3bbe3f67SBaptiste Daroussin /*
185*3bbe3f67SBaptiste Daroussin  * The following struct is used to record change information when
186*3bbe3f67SBaptiste Daroussin  * doing a "context" or "unified" diff.  (see routine "change" to
187*3bbe3f67SBaptiste Daroussin  * understand the highly mnemonic field names)
188*3bbe3f67SBaptiste Daroussin  */
189*3bbe3f67SBaptiste Daroussin struct context_vec {
190*3bbe3f67SBaptiste Daroussin 	int	a;		/* start line in old file */
191*3bbe3f67SBaptiste Daroussin 	int	b;		/* end line in old file */
192*3bbe3f67SBaptiste Daroussin 	int	c;		/* start line in new file */
193*3bbe3f67SBaptiste Daroussin 	int	d;		/* end line in new file */
194*3bbe3f67SBaptiste Daroussin };
195*3bbe3f67SBaptiste Daroussin 
196*3bbe3f67SBaptiste Daroussin #define	diff_output	printf
197*3bbe3f67SBaptiste Daroussin static void	 output(char *, FILE *, char *, FILE *, int);
198*3bbe3f67SBaptiste Daroussin static void	 check(FILE *, FILE *, int);
199*3bbe3f67SBaptiste Daroussin static void	 range(int, int, const char *);
200*3bbe3f67SBaptiste Daroussin static void	 uni_range(int, int);
201*3bbe3f67SBaptiste Daroussin static void	 dump_context_vec(FILE *, FILE *, int);
202*3bbe3f67SBaptiste Daroussin static void	 dump_unified_vec(FILE *, FILE *, int);
203*3bbe3f67SBaptiste Daroussin static void	 prepare(int, FILE *, off_t, int);
204*3bbe3f67SBaptiste Daroussin static void	 prune(void);
205*3bbe3f67SBaptiste Daroussin static void	 equiv(struct line *, int, struct line *, int, int *);
206*3bbe3f67SBaptiste Daroussin static void	 unravel(int);
207*3bbe3f67SBaptiste Daroussin static void	 unsort(struct line *, int, int *);
208*3bbe3f67SBaptiste Daroussin static void	 change(char *, FILE *, char *, FILE *, int, int, int, int, int *);
209*3bbe3f67SBaptiste Daroussin static void	 sort(struct line *, int);
210*3bbe3f67SBaptiste Daroussin static void	 print_header(const char *, const char *);
211*3bbe3f67SBaptiste Daroussin static int	 ignoreline(char *);
212*3bbe3f67SBaptiste Daroussin static int	 asciifile(FILE *);
213*3bbe3f67SBaptiste Daroussin static int	 fetch(long *, int, int, FILE *, int, int, int);
214*3bbe3f67SBaptiste Daroussin static int	 newcand(int, int, int);
215*3bbe3f67SBaptiste Daroussin static int	 search(int *, int, int);
216*3bbe3f67SBaptiste Daroussin static int	 skipline(FILE *);
217*3bbe3f67SBaptiste Daroussin static int	 isqrt(int);
218*3bbe3f67SBaptiste Daroussin static int	 stone(int *, int, int *, int *, int);
219*3bbe3f67SBaptiste Daroussin static int	 readhash(FILE *, int);
220*3bbe3f67SBaptiste Daroussin static int	 files_differ(FILE *, FILE *, int);
221*3bbe3f67SBaptiste Daroussin static char	*match_function(const long *, int, FILE *);
222*3bbe3f67SBaptiste Daroussin static char	*preadline(int, size_t, off_t);
223*3bbe3f67SBaptiste Daroussin 
224*3bbe3f67SBaptiste Daroussin static int  *J;			/* will be overlaid on class */
225*3bbe3f67SBaptiste Daroussin static int  *class;		/* will be overlaid on file[0] */
226*3bbe3f67SBaptiste Daroussin static int  *klist;		/* will be overlaid on file[0] after class */
227*3bbe3f67SBaptiste Daroussin static int  *member;		/* will be overlaid on file[1] */
228*3bbe3f67SBaptiste Daroussin static int   clen;
229*3bbe3f67SBaptiste Daroussin static int   inifdef;		/* whether or not we are in a #ifdef block */
230*3bbe3f67SBaptiste Daroussin static int   len[2];
231*3bbe3f67SBaptiste Daroussin static int   pref, suff;	/* length of prefix and suffix */
232*3bbe3f67SBaptiste Daroussin static int   slen[2];
233*3bbe3f67SBaptiste Daroussin static int   anychange;
234*3bbe3f67SBaptiste Daroussin static long *ixnew;		/* will be overlaid on file[1] */
235*3bbe3f67SBaptiste Daroussin static long *ixold;		/* will be overlaid on klist */
236*3bbe3f67SBaptiste Daroussin static struct cand *clist;	/* merely a free storage pot for candidates */
237*3bbe3f67SBaptiste Daroussin static int   clistlen;		/* the length of clist */
238*3bbe3f67SBaptiste Daroussin static struct line *sfile[2];	/* shortened by pruning common prefix/suffix */
239*3bbe3f67SBaptiste Daroussin static u_char *chrtran;		/* translation table for case-folding */
240*3bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_start;
241*3bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_end;
242*3bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_ptr;
243*3bbe3f67SBaptiste Daroussin 
244*3bbe3f67SBaptiste Daroussin #define FUNCTION_CONTEXT_SIZE	55
245*3bbe3f67SBaptiste Daroussin static char lastbuf[FUNCTION_CONTEXT_SIZE];
246*3bbe3f67SBaptiste Daroussin static int lastline;
247*3bbe3f67SBaptiste Daroussin static int lastmatchline;
248*3bbe3f67SBaptiste Daroussin 
249*3bbe3f67SBaptiste Daroussin 
250*3bbe3f67SBaptiste Daroussin /*
251*3bbe3f67SBaptiste Daroussin  * chrtran points to one of 2 translation tables: cup2low if folding upper to
252*3bbe3f67SBaptiste Daroussin  * lower case clow2low if not folding case
253*3bbe3f67SBaptiste Daroussin  */
254*3bbe3f67SBaptiste Daroussin static u_char clow2low[256] = {
255*3bbe3f67SBaptiste Daroussin 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
256*3bbe3f67SBaptiste Daroussin 	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
257*3bbe3f67SBaptiste Daroussin 	0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
258*3bbe3f67SBaptiste Daroussin 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
259*3bbe3f67SBaptiste Daroussin 	0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
260*3bbe3f67SBaptiste Daroussin 	0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
261*3bbe3f67SBaptiste Daroussin 	0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
262*3bbe3f67SBaptiste Daroussin 	0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
263*3bbe3f67SBaptiste Daroussin 	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
264*3bbe3f67SBaptiste Daroussin 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
265*3bbe3f67SBaptiste Daroussin 	0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
266*3bbe3f67SBaptiste Daroussin 	0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
267*3bbe3f67SBaptiste Daroussin 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
268*3bbe3f67SBaptiste Daroussin 	0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
269*3bbe3f67SBaptiste Daroussin 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
270*3bbe3f67SBaptiste Daroussin 	0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
271*3bbe3f67SBaptiste Daroussin 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
272*3bbe3f67SBaptiste Daroussin 	0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
273*3bbe3f67SBaptiste Daroussin 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
274*3bbe3f67SBaptiste Daroussin 	0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
275*3bbe3f67SBaptiste Daroussin 	0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
276*3bbe3f67SBaptiste Daroussin 	0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
277*3bbe3f67SBaptiste Daroussin 	0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
278*3bbe3f67SBaptiste Daroussin 	0xfd, 0xfe, 0xff
279*3bbe3f67SBaptiste Daroussin };
280*3bbe3f67SBaptiste Daroussin 
281*3bbe3f67SBaptiste Daroussin static u_char cup2low[256] = {
282*3bbe3f67SBaptiste Daroussin 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
283*3bbe3f67SBaptiste Daroussin 	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
284*3bbe3f67SBaptiste Daroussin 	0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
285*3bbe3f67SBaptiste Daroussin 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
286*3bbe3f67SBaptiste Daroussin 	0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
287*3bbe3f67SBaptiste Daroussin 	0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
288*3bbe3f67SBaptiste Daroussin 	0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
289*3bbe3f67SBaptiste Daroussin 	0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
290*3bbe3f67SBaptiste Daroussin 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
291*3bbe3f67SBaptiste Daroussin 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
292*3bbe3f67SBaptiste Daroussin 	0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
293*3bbe3f67SBaptiste Daroussin 	0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
294*3bbe3f67SBaptiste Daroussin 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
295*3bbe3f67SBaptiste Daroussin 	0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
296*3bbe3f67SBaptiste Daroussin 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
297*3bbe3f67SBaptiste Daroussin 	0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
298*3bbe3f67SBaptiste Daroussin 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
299*3bbe3f67SBaptiste Daroussin 	0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
300*3bbe3f67SBaptiste Daroussin 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
301*3bbe3f67SBaptiste Daroussin 	0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
302*3bbe3f67SBaptiste Daroussin 	0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
303*3bbe3f67SBaptiste Daroussin 	0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
304*3bbe3f67SBaptiste Daroussin 	0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
305*3bbe3f67SBaptiste Daroussin 	0xfd, 0xfe, 0xff
306*3bbe3f67SBaptiste Daroussin };
307*3bbe3f67SBaptiste Daroussin 
308*3bbe3f67SBaptiste Daroussin int
309*3bbe3f67SBaptiste Daroussin diffreg(char *file1, char *file2, int flags, int capsicum)
310*3bbe3f67SBaptiste Daroussin {
311*3bbe3f67SBaptiste Daroussin 	FILE *f1, *f2;
312*3bbe3f67SBaptiste Daroussin 	int i, rval;
313*3bbe3f67SBaptiste Daroussin 	int	ostdout = -1;
314*3bbe3f67SBaptiste Daroussin 	int pr_pd, kq;
315*3bbe3f67SBaptiste Daroussin 	struct kevent *e;
316*3bbe3f67SBaptiste Daroussin 	cap_rights_t rights_ro;
317*3bbe3f67SBaptiste Daroussin 
318*3bbe3f67SBaptiste Daroussin 	f1 = f2 = NULL;
319*3bbe3f67SBaptiste Daroussin 	rval = D_SAME;
320*3bbe3f67SBaptiste Daroussin 	anychange = 0;
321*3bbe3f67SBaptiste Daroussin 	lastline = 0;
322*3bbe3f67SBaptiste Daroussin 	lastmatchline = 0;
323*3bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
324*3bbe3f67SBaptiste Daroussin 	if (flags & D_IGNORECASE)
325*3bbe3f67SBaptiste Daroussin 		chrtran = cup2low;
326*3bbe3f67SBaptiste Daroussin 	else
327*3bbe3f67SBaptiste Daroussin 		chrtran = clow2low;
328*3bbe3f67SBaptiste Daroussin 	if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode))
329*3bbe3f67SBaptiste Daroussin 		return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2);
330*3bbe3f67SBaptiste Daroussin 	if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0)
331*3bbe3f67SBaptiste Daroussin 		goto closem;
332*3bbe3f67SBaptiste Daroussin 
333*3bbe3f67SBaptiste Daroussin 	if (flags & D_EMPTY1)
334*3bbe3f67SBaptiste Daroussin 		f1 = fopen(_PATH_DEVNULL, "r");
335*3bbe3f67SBaptiste Daroussin 	else {
336*3bbe3f67SBaptiste Daroussin 		if (strcmp(file1, "-") == 0)
337*3bbe3f67SBaptiste Daroussin 			f1 = stdin;
338*3bbe3f67SBaptiste Daroussin 		else
339*3bbe3f67SBaptiste Daroussin 			f1 = fopen(file1, "r");
340*3bbe3f67SBaptiste Daroussin 	}
341*3bbe3f67SBaptiste Daroussin 	if (f1 == NULL) {
342*3bbe3f67SBaptiste Daroussin 		warn("%s", file1);
343*3bbe3f67SBaptiste Daroussin 		status |= 2;
344*3bbe3f67SBaptiste Daroussin 		goto closem;
345*3bbe3f67SBaptiste Daroussin 	}
346*3bbe3f67SBaptiste Daroussin 
347*3bbe3f67SBaptiste Daroussin 	if (flags & D_EMPTY2)
348*3bbe3f67SBaptiste Daroussin 		f2 = fopen(_PATH_DEVNULL, "r");
349*3bbe3f67SBaptiste Daroussin 	else {
350*3bbe3f67SBaptiste Daroussin 		if (strcmp(file2, "-") == 0)
351*3bbe3f67SBaptiste Daroussin 			f2 = stdin;
352*3bbe3f67SBaptiste Daroussin 		else
353*3bbe3f67SBaptiste Daroussin 			f2 = fopen(file2, "r");
354*3bbe3f67SBaptiste Daroussin 	}
355*3bbe3f67SBaptiste Daroussin 	if (f2 == NULL) {
356*3bbe3f67SBaptiste Daroussin 		warn("%s", file2);
357*3bbe3f67SBaptiste Daroussin 		status |= 2;
358*3bbe3f67SBaptiste Daroussin 		goto closem;
359*3bbe3f67SBaptiste Daroussin 	}
360*3bbe3f67SBaptiste Daroussin 
361*3bbe3f67SBaptiste Daroussin 	if (lflag) {
362*3bbe3f67SBaptiste Daroussin 		/* redirect stdout to pr */
363*3bbe3f67SBaptiste Daroussin 		int	 pfd[2];
364*3bbe3f67SBaptiste Daroussin 		pid_t	pid;
365*3bbe3f67SBaptiste Daroussin 		char	*header;
366*3bbe3f67SBaptiste Daroussin 
367*3bbe3f67SBaptiste Daroussin 		xasprintf(&header, "%s %s %s", diffargs, file1, file2);
368*3bbe3f67SBaptiste Daroussin 		signal(SIGPIPE, SIG_IGN);
369*3bbe3f67SBaptiste Daroussin 		fflush(stdout);
370*3bbe3f67SBaptiste Daroussin 		rewind(stdout);
371*3bbe3f67SBaptiste Daroussin 		pipe(pfd);
372*3bbe3f67SBaptiste Daroussin 		switch ((pid = pdfork(&pr_pd, PD_CLOEXEC))) {
373*3bbe3f67SBaptiste Daroussin 		case -1:
374*3bbe3f67SBaptiste Daroussin 			status |= 2;
375*3bbe3f67SBaptiste Daroussin 			free(header);
376*3bbe3f67SBaptiste Daroussin 			err(2, "No more processes");
377*3bbe3f67SBaptiste Daroussin 		case 0:
378*3bbe3f67SBaptiste Daroussin 			/* child */
379*3bbe3f67SBaptiste Daroussin 			if (pfd[0] != STDIN_FILENO) {
380*3bbe3f67SBaptiste Daroussin 				dup2(pfd[0], STDIN_FILENO);
381*3bbe3f67SBaptiste Daroussin 				close(pfd[0]);
382*3bbe3f67SBaptiste Daroussin 			}
383*3bbe3f67SBaptiste Daroussin 			close(pfd[1]);
384*3bbe3f67SBaptiste Daroussin 			execl(_PATH_PR, _PATH_PR, "-h", header, (char *)0);
385*3bbe3f67SBaptiste Daroussin 			_exit(127);
386*3bbe3f67SBaptiste Daroussin 		default:
387*3bbe3f67SBaptiste Daroussin 
388*3bbe3f67SBaptiste Daroussin 			/* parent */
389*3bbe3f67SBaptiste Daroussin 			if (pfd[1] != STDOUT_FILENO) {
390*3bbe3f67SBaptiste Daroussin 				ostdout = dup(STDOUT_FILENO);
391*3bbe3f67SBaptiste Daroussin 				dup2(pfd[1], STDOUT_FILENO);
392*3bbe3f67SBaptiste Daroussin 				close(pfd[1]);
393*3bbe3f67SBaptiste Daroussin 			}
394*3bbe3f67SBaptiste Daroussin 			close(pfd[0]);
395*3bbe3f67SBaptiste Daroussin 			rewind(stdout);
396*3bbe3f67SBaptiste Daroussin 			free(header);
397*3bbe3f67SBaptiste Daroussin 			kq = kqueue();
398*3bbe3f67SBaptiste Daroussin 			if (kq == -1)
399*3bbe3f67SBaptiste Daroussin 				err(2, "kqueue");
400*3bbe3f67SBaptiste Daroussin 			e = xmalloc(sizeof(struct kevent));
401*3bbe3f67SBaptiste Daroussin 			EV_SET(e, pr_pd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0,
402*3bbe3f67SBaptiste Daroussin 			    NULL);
403*3bbe3f67SBaptiste Daroussin 			if (kevent(kq, e, 1, NULL, 0, NULL) == -1)
404*3bbe3f67SBaptiste Daroussin 				err(2, "kevent");
405*3bbe3f67SBaptiste Daroussin 		}
406*3bbe3f67SBaptiste Daroussin 	}
407*3bbe3f67SBaptiste Daroussin 
408*3bbe3f67SBaptiste Daroussin 	if (capsicum) {
409*3bbe3f67SBaptiste Daroussin 		cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK);
410*3bbe3f67SBaptiste Daroussin 		if (cap_rights_limit(fileno(f1), &rights_ro) < 0)
411*3bbe3f67SBaptiste Daroussin 			err(2, "unable to limit rights on: %s", file1);
412*3bbe3f67SBaptiste Daroussin 		if (cap_rights_limit(fileno(f2), &rights_ro) < 0)
413*3bbe3f67SBaptiste Daroussin 			err(2, "unable to limit rights on: %s", file2);
414*3bbe3f67SBaptiste Daroussin 		if (fileno(f1) == STDIN_FILENO || fileno(f2) == STDIN_FILENO) {
415*3bbe3f67SBaptiste Daroussin 			/* stding has already been limited */
416*3bbe3f67SBaptiste Daroussin 			if (caph_limit_stderr() == -1)
417*3bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stderr");
418*3bbe3f67SBaptiste Daroussin 			if (caph_limit_stdout() == -1)
419*3bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stdout");
420*3bbe3f67SBaptiste Daroussin 		} else if (caph_limit_stdio() == -1)
421*3bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stdio");
422*3bbe3f67SBaptiste Daroussin 
423*3bbe3f67SBaptiste Daroussin 		caph_cache_catpages();
424*3bbe3f67SBaptiste Daroussin 		if (cap_enter() < 0 && errno != ENOSYS)
425*3bbe3f67SBaptiste Daroussin 			err(2, "unable to enter capability mode");
426*3bbe3f67SBaptiste Daroussin 	}
427*3bbe3f67SBaptiste Daroussin 
428*3bbe3f67SBaptiste Daroussin 	switch (files_differ(f1, f2, flags)) {
429*3bbe3f67SBaptiste Daroussin 	case 0:
430*3bbe3f67SBaptiste Daroussin 		goto closem;
431*3bbe3f67SBaptiste Daroussin 	case 1:
432*3bbe3f67SBaptiste Daroussin 		break;
433*3bbe3f67SBaptiste Daroussin 	default:
434*3bbe3f67SBaptiste Daroussin 		/* error */
435*3bbe3f67SBaptiste Daroussin 		status |= 2;
436*3bbe3f67SBaptiste Daroussin 		goto closem;
437*3bbe3f67SBaptiste Daroussin 	}
438*3bbe3f67SBaptiste Daroussin 
439*3bbe3f67SBaptiste Daroussin 	if ((flags & D_FORCEASCII) == 0 &&
440*3bbe3f67SBaptiste Daroussin 	    (!asciifile(f1) || !asciifile(f2))) {
441*3bbe3f67SBaptiste Daroussin 		rval = D_BINARY;
442*3bbe3f67SBaptiste Daroussin 		status |= 1;
443*3bbe3f67SBaptiste Daroussin 		goto closem;
444*3bbe3f67SBaptiste Daroussin 	}
445*3bbe3f67SBaptiste Daroussin 	prepare(0, f1, stb1.st_size, flags);
446*3bbe3f67SBaptiste Daroussin 	prepare(1, f2, stb2.st_size, flags);
447*3bbe3f67SBaptiste Daroussin 
448*3bbe3f67SBaptiste Daroussin 	prune();
449*3bbe3f67SBaptiste Daroussin 	sort(sfile[0], slen[0]);
450*3bbe3f67SBaptiste Daroussin 	sort(sfile[1], slen[1]);
451*3bbe3f67SBaptiste Daroussin 
452*3bbe3f67SBaptiste Daroussin 	member = (int *)file[1];
453*3bbe3f67SBaptiste Daroussin 	equiv(sfile[0], slen[0], sfile[1], slen[1], member);
454*3bbe3f67SBaptiste Daroussin 	member = xreallocarray(member, slen[1] + 2, sizeof(*member));
455*3bbe3f67SBaptiste Daroussin 
456*3bbe3f67SBaptiste Daroussin 	class = (int *)file[0];
457*3bbe3f67SBaptiste Daroussin 	unsort(sfile[0], slen[0], class);
458*3bbe3f67SBaptiste Daroussin 	class = xreallocarray(class, slen[0] + 2, sizeof(*class));
459*3bbe3f67SBaptiste Daroussin 
460*3bbe3f67SBaptiste Daroussin 	klist = xcalloc(slen[0] + 2, sizeof(*klist));
461*3bbe3f67SBaptiste Daroussin 	clen = 0;
462*3bbe3f67SBaptiste Daroussin 	clistlen = 100;
463*3bbe3f67SBaptiste Daroussin 	clist = xcalloc(clistlen, sizeof(*clist));
464*3bbe3f67SBaptiste Daroussin 	i = stone(class, slen[0], member, klist, flags);
465*3bbe3f67SBaptiste Daroussin 	free(member);
466*3bbe3f67SBaptiste Daroussin 	free(class);
467*3bbe3f67SBaptiste Daroussin 
468*3bbe3f67SBaptiste Daroussin 	J = xreallocarray(J, len[0] + 2, sizeof(*J));
469*3bbe3f67SBaptiste Daroussin 	unravel(klist[i]);
470*3bbe3f67SBaptiste Daroussin 	free(clist);
471*3bbe3f67SBaptiste Daroussin 	free(klist);
472*3bbe3f67SBaptiste Daroussin 
473*3bbe3f67SBaptiste Daroussin 	ixold = xreallocarray(ixold, len[0] + 2, sizeof(*ixold));
474*3bbe3f67SBaptiste Daroussin 	ixnew = xreallocarray(ixnew, len[1] + 2, sizeof(*ixnew));
475*3bbe3f67SBaptiste Daroussin 	check(f1, f2, flags);
476*3bbe3f67SBaptiste Daroussin 	output(file1, f1, file2, f2, flags);
477*3bbe3f67SBaptiste Daroussin 	if (ostdout != -1) {
478*3bbe3f67SBaptiste Daroussin 		/* close the pipe to pr and restore stdout */
479*3bbe3f67SBaptiste Daroussin 		int wstatus;
480*3bbe3f67SBaptiste Daroussin 
481*3bbe3f67SBaptiste Daroussin 		fflush(stdout);
482*3bbe3f67SBaptiste Daroussin 		if (ostdout != STDOUT_FILENO) {
483*3bbe3f67SBaptiste Daroussin 			close(STDOUT_FILENO);
484*3bbe3f67SBaptiste Daroussin 			dup2(ostdout, STDOUT_FILENO);
485*3bbe3f67SBaptiste Daroussin 			close(ostdout);
486*3bbe3f67SBaptiste Daroussin 		}
487*3bbe3f67SBaptiste Daroussin 		if (kevent(kq, NULL, 0, e, 1, NULL) == -1)
488*3bbe3f67SBaptiste Daroussin 			err(2, "kevent");
489*3bbe3f67SBaptiste Daroussin 		wstatus = e[0].data;
490*3bbe3f67SBaptiste Daroussin 		close(kq);
491*3bbe3f67SBaptiste Daroussin 		if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0)
492*3bbe3f67SBaptiste Daroussin 			errx(2, "pr exited abnormally");
493*3bbe3f67SBaptiste Daroussin 		else if (WIFSIGNALED(wstatus))
494*3bbe3f67SBaptiste Daroussin 			errx(2, "pr killed by signal %d",
495*3bbe3f67SBaptiste Daroussin 			    WTERMSIG(wstatus));
496*3bbe3f67SBaptiste Daroussin 	}
497*3bbe3f67SBaptiste Daroussin 
498*3bbe3f67SBaptiste Daroussin closem:
499*3bbe3f67SBaptiste Daroussin 	if (anychange) {
500*3bbe3f67SBaptiste Daroussin 		status |= 1;
501*3bbe3f67SBaptiste Daroussin 		if (rval == D_SAME)
502*3bbe3f67SBaptiste Daroussin 			rval = D_DIFFER;
503*3bbe3f67SBaptiste Daroussin 	}
504*3bbe3f67SBaptiste Daroussin 	if (f1 != NULL)
505*3bbe3f67SBaptiste Daroussin 		fclose(f1);
506*3bbe3f67SBaptiste Daroussin 	if (f2 != NULL)
507*3bbe3f67SBaptiste Daroussin 		fclose(f2);
508*3bbe3f67SBaptiste Daroussin 
509*3bbe3f67SBaptiste Daroussin 	return (rval);
510*3bbe3f67SBaptiste Daroussin }
511*3bbe3f67SBaptiste Daroussin 
512*3bbe3f67SBaptiste Daroussin /*
513*3bbe3f67SBaptiste Daroussin  * Check to see if the given files differ.
514*3bbe3f67SBaptiste Daroussin  * Returns 0 if they are the same, 1 if different, and -1 on error.
515*3bbe3f67SBaptiste Daroussin  * XXX - could use code from cmp(1) [faster]
516*3bbe3f67SBaptiste Daroussin  */
517*3bbe3f67SBaptiste Daroussin static int
518*3bbe3f67SBaptiste Daroussin files_differ(FILE *f1, FILE *f2, int flags)
519*3bbe3f67SBaptiste Daroussin {
520*3bbe3f67SBaptiste Daroussin 	char buf1[BUFSIZ], buf2[BUFSIZ];
521*3bbe3f67SBaptiste Daroussin 	size_t i, j;
522*3bbe3f67SBaptiste Daroussin 
523*3bbe3f67SBaptiste Daroussin 	if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size ||
524*3bbe3f67SBaptiste Daroussin 	    (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT))
525*3bbe3f67SBaptiste Daroussin 		return (1);
526*3bbe3f67SBaptiste Daroussin 	for (;;) {
527*3bbe3f67SBaptiste Daroussin 		i = fread(buf1, 1, sizeof(buf1), f1);
528*3bbe3f67SBaptiste Daroussin 		j = fread(buf2, 1, sizeof(buf2), f2);
529*3bbe3f67SBaptiste Daroussin 		if ((!i && ferror(f1)) || (!j && ferror(f2)))
530*3bbe3f67SBaptiste Daroussin 			return (-1);
531*3bbe3f67SBaptiste Daroussin 		if (i != j)
532*3bbe3f67SBaptiste Daroussin 			return (1);
533*3bbe3f67SBaptiste Daroussin 		if (i == 0)
534*3bbe3f67SBaptiste Daroussin 			return (0);
535*3bbe3f67SBaptiste Daroussin 		if (memcmp(buf1, buf2, i) != 0)
536*3bbe3f67SBaptiste Daroussin 			return (1);
537*3bbe3f67SBaptiste Daroussin 	}
538*3bbe3f67SBaptiste Daroussin }
539*3bbe3f67SBaptiste Daroussin 
540*3bbe3f67SBaptiste Daroussin char *
541*3bbe3f67SBaptiste Daroussin splice(char *dir, char *path)
542*3bbe3f67SBaptiste Daroussin {
543*3bbe3f67SBaptiste Daroussin 	char *tail, *buf;
544*3bbe3f67SBaptiste Daroussin 	size_t dirlen;
545*3bbe3f67SBaptiste Daroussin 
546*3bbe3f67SBaptiste Daroussin 	dirlen = strlen(dir);
547*3bbe3f67SBaptiste Daroussin 	while (dirlen != 0 && dir[dirlen - 1] == '/')
548*3bbe3f67SBaptiste Daroussin 	    dirlen--;
549*3bbe3f67SBaptiste Daroussin 	if ((tail = strrchr(path, '/')) == NULL)
550*3bbe3f67SBaptiste Daroussin 		tail = path;
551*3bbe3f67SBaptiste Daroussin 	else
552*3bbe3f67SBaptiste Daroussin 		tail++;
553*3bbe3f67SBaptiste Daroussin 	xasprintf(&buf, "%.*s/%s", (int)dirlen, dir, tail);
554*3bbe3f67SBaptiste Daroussin 	return (buf);
555*3bbe3f67SBaptiste Daroussin }
556*3bbe3f67SBaptiste Daroussin 
557*3bbe3f67SBaptiste Daroussin static void
558*3bbe3f67SBaptiste Daroussin prepare(int i, FILE *fd, off_t filesize, int flags)
559*3bbe3f67SBaptiste Daroussin {
560*3bbe3f67SBaptiste Daroussin 	struct line *p;
561*3bbe3f67SBaptiste Daroussin 	int h;
562*3bbe3f67SBaptiste Daroussin 	size_t sz, j;
563*3bbe3f67SBaptiste Daroussin 
564*3bbe3f67SBaptiste Daroussin 	rewind(fd);
565*3bbe3f67SBaptiste Daroussin 
566*3bbe3f67SBaptiste Daroussin 	sz = ((unsigned long)filesize <= SIZE_MAX ? filesize : SIZE_MAX) / 25;
567*3bbe3f67SBaptiste Daroussin 	if (sz < 100)
568*3bbe3f67SBaptiste Daroussin 		sz = 100;
569*3bbe3f67SBaptiste Daroussin 
570*3bbe3f67SBaptiste Daroussin 	p = xcalloc(sz + 3, sizeof(*p));
571*3bbe3f67SBaptiste Daroussin 	for (j = 0; (h = readhash(fd, flags));) {
572*3bbe3f67SBaptiste Daroussin 		if (j == sz) {
573*3bbe3f67SBaptiste Daroussin 			sz = sz * 3 / 2;
574*3bbe3f67SBaptiste Daroussin 			p = xreallocarray(p, sz + 3, sizeof(*p));
575*3bbe3f67SBaptiste Daroussin 		}
576*3bbe3f67SBaptiste Daroussin 		p[++j].value = h;
577*3bbe3f67SBaptiste Daroussin 	}
578*3bbe3f67SBaptiste Daroussin 	len[i] = j;
579*3bbe3f67SBaptiste Daroussin 	file[i] = p;
580*3bbe3f67SBaptiste Daroussin }
581*3bbe3f67SBaptiste Daroussin 
582*3bbe3f67SBaptiste Daroussin static void
583*3bbe3f67SBaptiste Daroussin prune(void)
584*3bbe3f67SBaptiste Daroussin {
585*3bbe3f67SBaptiste Daroussin 	int i, j;
586*3bbe3f67SBaptiste Daroussin 
587*3bbe3f67SBaptiste Daroussin 	for (pref = 0; pref < len[0] && pref < len[1] &&
588*3bbe3f67SBaptiste Daroussin 	    file[0][pref + 1].value == file[1][pref + 1].value;
589*3bbe3f67SBaptiste Daroussin 	    pref++)
590*3bbe3f67SBaptiste Daroussin 		;
591*3bbe3f67SBaptiste Daroussin 	for (suff = 0; suff < len[0] - pref && suff < len[1] - pref &&
592*3bbe3f67SBaptiste Daroussin 	    file[0][len[0] - suff].value == file[1][len[1] - suff].value;
593*3bbe3f67SBaptiste Daroussin 	    suff++)
594*3bbe3f67SBaptiste Daroussin 		;
595*3bbe3f67SBaptiste Daroussin 	for (j = 0; j < 2; j++) {
596*3bbe3f67SBaptiste Daroussin 		sfile[j] = file[j] + pref;
597*3bbe3f67SBaptiste Daroussin 		slen[j] = len[j] - pref - suff;
598*3bbe3f67SBaptiste Daroussin 		for (i = 0; i <= slen[j]; i++)
599*3bbe3f67SBaptiste Daroussin 			sfile[j][i].serial = i;
600*3bbe3f67SBaptiste Daroussin 	}
601*3bbe3f67SBaptiste Daroussin }
602*3bbe3f67SBaptiste Daroussin 
603*3bbe3f67SBaptiste Daroussin static void
604*3bbe3f67SBaptiste Daroussin equiv(struct line *a, int n, struct line *b, int m, int *c)
605*3bbe3f67SBaptiste Daroussin {
606*3bbe3f67SBaptiste Daroussin 	int i, j;
607*3bbe3f67SBaptiste Daroussin 
608*3bbe3f67SBaptiste Daroussin 	i = j = 1;
609*3bbe3f67SBaptiste Daroussin 	while (i <= n && j <= m) {
610*3bbe3f67SBaptiste Daroussin 		if (a[i].value < b[j].value)
611*3bbe3f67SBaptiste Daroussin 			a[i++].value = 0;
612*3bbe3f67SBaptiste Daroussin 		else if (a[i].value == b[j].value)
613*3bbe3f67SBaptiste Daroussin 			a[i++].value = j;
614*3bbe3f67SBaptiste Daroussin 		else
615*3bbe3f67SBaptiste Daroussin 			j++;
616*3bbe3f67SBaptiste Daroussin 	}
617*3bbe3f67SBaptiste Daroussin 	while (i <= n)
618*3bbe3f67SBaptiste Daroussin 		a[i++].value = 0;
619*3bbe3f67SBaptiste Daroussin 	b[m + 1].value = 0;
620*3bbe3f67SBaptiste Daroussin 	j = 0;
621*3bbe3f67SBaptiste Daroussin 	while (++j <= m) {
622*3bbe3f67SBaptiste Daroussin 		c[j] = -b[j].serial;
623*3bbe3f67SBaptiste Daroussin 		while (b[j + 1].value == b[j].value) {
624*3bbe3f67SBaptiste Daroussin 			j++;
625*3bbe3f67SBaptiste Daroussin 			c[j] = b[j].serial;
626*3bbe3f67SBaptiste Daroussin 		}
627*3bbe3f67SBaptiste Daroussin 	}
628*3bbe3f67SBaptiste Daroussin 	c[j] = -1;
629*3bbe3f67SBaptiste Daroussin }
630*3bbe3f67SBaptiste Daroussin 
631*3bbe3f67SBaptiste Daroussin /* Code taken from ping.c */
632*3bbe3f67SBaptiste Daroussin static int
633*3bbe3f67SBaptiste Daroussin isqrt(int n)
634*3bbe3f67SBaptiste Daroussin {
635*3bbe3f67SBaptiste Daroussin 	int y, x = 1;
636*3bbe3f67SBaptiste Daroussin 
637*3bbe3f67SBaptiste Daroussin 	if (n == 0)
638*3bbe3f67SBaptiste Daroussin 		return (0);
639*3bbe3f67SBaptiste Daroussin 
640*3bbe3f67SBaptiste Daroussin 	do { /* newton was a stinker */
641*3bbe3f67SBaptiste Daroussin 		y = x;
642*3bbe3f67SBaptiste Daroussin 		x = n / x;
643*3bbe3f67SBaptiste Daroussin 		x += y;
644*3bbe3f67SBaptiste Daroussin 		x /= 2;
645*3bbe3f67SBaptiste Daroussin 	} while ((x - y) > 1 || (x - y) < -1);
646*3bbe3f67SBaptiste Daroussin 
647*3bbe3f67SBaptiste Daroussin 	return (x);
648*3bbe3f67SBaptiste Daroussin }
649*3bbe3f67SBaptiste Daroussin 
650*3bbe3f67SBaptiste Daroussin static int
651*3bbe3f67SBaptiste Daroussin stone(int *a, int n, int *b, int *c, int flags)
652*3bbe3f67SBaptiste Daroussin {
653*3bbe3f67SBaptiste Daroussin 	int i, k, y, j, l;
654*3bbe3f67SBaptiste Daroussin 	int oldc, tc, oldl, sq;
655*3bbe3f67SBaptiste Daroussin 	u_int numtries, bound;
656*3bbe3f67SBaptiste Daroussin 
657*3bbe3f67SBaptiste Daroussin 	if (flags & D_MINIMAL)
658*3bbe3f67SBaptiste Daroussin 		bound = UINT_MAX;
659*3bbe3f67SBaptiste Daroussin 	else {
660*3bbe3f67SBaptiste Daroussin 		sq = isqrt(n);
661*3bbe3f67SBaptiste Daroussin 		bound = MAXIMUM(256, sq);
662*3bbe3f67SBaptiste Daroussin 	}
663*3bbe3f67SBaptiste Daroussin 
664*3bbe3f67SBaptiste Daroussin 	k = 0;
665*3bbe3f67SBaptiste Daroussin 	c[0] = newcand(0, 0, 0);
666*3bbe3f67SBaptiste Daroussin 	for (i = 1; i <= n; i++) {
667*3bbe3f67SBaptiste Daroussin 		j = a[i];
668*3bbe3f67SBaptiste Daroussin 		if (j == 0)
669*3bbe3f67SBaptiste Daroussin 			continue;
670*3bbe3f67SBaptiste Daroussin 		y = -b[j];
671*3bbe3f67SBaptiste Daroussin 		oldl = 0;
672*3bbe3f67SBaptiste Daroussin 		oldc = c[0];
673*3bbe3f67SBaptiste Daroussin 		numtries = 0;
674*3bbe3f67SBaptiste Daroussin 		do {
675*3bbe3f67SBaptiste Daroussin 			if (y <= clist[oldc].y)
676*3bbe3f67SBaptiste Daroussin 				continue;
677*3bbe3f67SBaptiste Daroussin 			l = search(c, k, y);
678*3bbe3f67SBaptiste Daroussin 			if (l != oldl + 1)
679*3bbe3f67SBaptiste Daroussin 				oldc = c[l - 1];
680*3bbe3f67SBaptiste Daroussin 			if (l <= k) {
681*3bbe3f67SBaptiste Daroussin 				if (clist[c[l]].y <= y)
682*3bbe3f67SBaptiste Daroussin 					continue;
683*3bbe3f67SBaptiste Daroussin 				tc = c[l];
684*3bbe3f67SBaptiste Daroussin 				c[l] = newcand(i, y, oldc);
685*3bbe3f67SBaptiste Daroussin 				oldc = tc;
686*3bbe3f67SBaptiste Daroussin 				oldl = l;
687*3bbe3f67SBaptiste Daroussin 				numtries++;
688*3bbe3f67SBaptiste Daroussin 			} else {
689*3bbe3f67SBaptiste Daroussin 				c[l] = newcand(i, y, oldc);
690*3bbe3f67SBaptiste Daroussin 				k++;
691*3bbe3f67SBaptiste Daroussin 				break;
692*3bbe3f67SBaptiste Daroussin 			}
693*3bbe3f67SBaptiste Daroussin 		} while ((y = b[++j]) > 0 && numtries < bound);
694*3bbe3f67SBaptiste Daroussin 	}
695*3bbe3f67SBaptiste Daroussin 	return (k);
696*3bbe3f67SBaptiste Daroussin }
697*3bbe3f67SBaptiste Daroussin 
698*3bbe3f67SBaptiste Daroussin static int
699*3bbe3f67SBaptiste Daroussin newcand(int x, int y, int pred)
700*3bbe3f67SBaptiste Daroussin {
701*3bbe3f67SBaptiste Daroussin 	struct cand *q;
702*3bbe3f67SBaptiste Daroussin 
703*3bbe3f67SBaptiste Daroussin 	if (clen == clistlen) {
704*3bbe3f67SBaptiste Daroussin 		clistlen = clistlen * 11 / 10;
705*3bbe3f67SBaptiste Daroussin 		clist = xreallocarray(clist, clistlen, sizeof(*clist));
706*3bbe3f67SBaptiste Daroussin 	}
707*3bbe3f67SBaptiste Daroussin 	q = clist + clen;
708*3bbe3f67SBaptiste Daroussin 	q->x = x;
709*3bbe3f67SBaptiste Daroussin 	q->y = y;
710*3bbe3f67SBaptiste Daroussin 	q->pred = pred;
711*3bbe3f67SBaptiste Daroussin 	return (clen++);
712*3bbe3f67SBaptiste Daroussin }
713*3bbe3f67SBaptiste Daroussin 
714*3bbe3f67SBaptiste Daroussin static int
715*3bbe3f67SBaptiste Daroussin search(int *c, int k, int y)
716*3bbe3f67SBaptiste Daroussin {
717*3bbe3f67SBaptiste Daroussin 	int i, j, l, t;
718*3bbe3f67SBaptiste Daroussin 
719*3bbe3f67SBaptiste Daroussin 	if (clist[c[k]].y < y)	/* quick look for typical case */
720*3bbe3f67SBaptiste Daroussin 		return (k + 1);
721*3bbe3f67SBaptiste Daroussin 	i = 0;
722*3bbe3f67SBaptiste Daroussin 	j = k + 1;
723*3bbe3f67SBaptiste Daroussin 	for (;;) {
724*3bbe3f67SBaptiste Daroussin 		l = (i + j) / 2;
725*3bbe3f67SBaptiste Daroussin 		if (l <= i)
726*3bbe3f67SBaptiste Daroussin 			break;
727*3bbe3f67SBaptiste Daroussin 		t = clist[c[l]].y;
728*3bbe3f67SBaptiste Daroussin 		if (t > y)
729*3bbe3f67SBaptiste Daroussin 			j = l;
730*3bbe3f67SBaptiste Daroussin 		else if (t < y)
731*3bbe3f67SBaptiste Daroussin 			i = l;
732*3bbe3f67SBaptiste Daroussin 		else
733*3bbe3f67SBaptiste Daroussin 			return (l);
734*3bbe3f67SBaptiste Daroussin 	}
735*3bbe3f67SBaptiste Daroussin 	return (l + 1);
736*3bbe3f67SBaptiste Daroussin }
737*3bbe3f67SBaptiste Daroussin 
738*3bbe3f67SBaptiste Daroussin static void
739*3bbe3f67SBaptiste Daroussin unravel(int p)
740*3bbe3f67SBaptiste Daroussin {
741*3bbe3f67SBaptiste Daroussin 	struct cand *q;
742*3bbe3f67SBaptiste Daroussin 	int i;
743*3bbe3f67SBaptiste Daroussin 
744*3bbe3f67SBaptiste Daroussin 	for (i = 0; i <= len[0]; i++)
745*3bbe3f67SBaptiste Daroussin 		J[i] = i <= pref ? i :
746*3bbe3f67SBaptiste Daroussin 		    i > len[0] - suff ? i + len[1] - len[0] : 0;
747*3bbe3f67SBaptiste Daroussin 	for (q = clist + p; q->y != 0; q = clist + q->pred)
748*3bbe3f67SBaptiste Daroussin 		J[q->x + pref] = q->y + pref;
749*3bbe3f67SBaptiste Daroussin }
750*3bbe3f67SBaptiste Daroussin 
751*3bbe3f67SBaptiste Daroussin /*
752*3bbe3f67SBaptiste Daroussin  * Check does double duty:
753*3bbe3f67SBaptiste Daroussin  *  1.	ferret out any fortuitous correspondences due
754*3bbe3f67SBaptiste Daroussin  *	to confounding by hashing (which result in "jackpot")
755*3bbe3f67SBaptiste Daroussin  *  2.  collect random access indexes to the two files
756*3bbe3f67SBaptiste Daroussin  */
757*3bbe3f67SBaptiste Daroussin static void
758*3bbe3f67SBaptiste Daroussin check(FILE *f1, FILE *f2, int flags)
759*3bbe3f67SBaptiste Daroussin {
760*3bbe3f67SBaptiste Daroussin 	int i, j, jackpot, c, d;
761*3bbe3f67SBaptiste Daroussin 	long ctold, ctnew;
762*3bbe3f67SBaptiste Daroussin 
763*3bbe3f67SBaptiste Daroussin 	rewind(f1);
764*3bbe3f67SBaptiste Daroussin 	rewind(f2);
765*3bbe3f67SBaptiste Daroussin 	j = 1;
766*3bbe3f67SBaptiste Daroussin 	ixold[0] = ixnew[0] = 0;
767*3bbe3f67SBaptiste Daroussin 	jackpot = 0;
768*3bbe3f67SBaptiste Daroussin 	ctold = ctnew = 0;
769*3bbe3f67SBaptiste Daroussin 	for (i = 1; i <= len[0]; i++) {
770*3bbe3f67SBaptiste Daroussin 		if (J[i] == 0) {
771*3bbe3f67SBaptiste Daroussin 			ixold[i] = ctold += skipline(f1);
772*3bbe3f67SBaptiste Daroussin 			continue;
773*3bbe3f67SBaptiste Daroussin 		}
774*3bbe3f67SBaptiste Daroussin 		while (j < J[i]) {
775*3bbe3f67SBaptiste Daroussin 			ixnew[j] = ctnew += skipline(f2);
776*3bbe3f67SBaptiste Daroussin 			j++;
777*3bbe3f67SBaptiste Daroussin 		}
778*3bbe3f67SBaptiste Daroussin 		if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE|D_STRIPCR)) {
779*3bbe3f67SBaptiste Daroussin 			for (;;) {
780*3bbe3f67SBaptiste Daroussin 				c = getc(f1);
781*3bbe3f67SBaptiste Daroussin 				d = getc(f2);
782*3bbe3f67SBaptiste Daroussin 				/*
783*3bbe3f67SBaptiste Daroussin 				 * GNU diff ignores a missing newline
784*3bbe3f67SBaptiste Daroussin 				 * in one file for -b or -w.
785*3bbe3f67SBaptiste Daroussin 				 */
786*3bbe3f67SBaptiste Daroussin 				if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) {
787*3bbe3f67SBaptiste Daroussin 					if (c == EOF && d == '\n') {
788*3bbe3f67SBaptiste Daroussin 						ctnew++;
789*3bbe3f67SBaptiste Daroussin 						break;
790*3bbe3f67SBaptiste Daroussin 					} else if (c == '\n' && d == EOF) {
791*3bbe3f67SBaptiste Daroussin 						ctold++;
792*3bbe3f67SBaptiste Daroussin 						break;
793*3bbe3f67SBaptiste Daroussin 					}
794*3bbe3f67SBaptiste Daroussin 				}
795*3bbe3f67SBaptiste Daroussin 				ctold++;
796*3bbe3f67SBaptiste Daroussin 				ctnew++;
797*3bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR) {
798*3bbe3f67SBaptiste Daroussin 					if (c == '\r') {
799*3bbe3f67SBaptiste Daroussin 						if ((c = getc(f1)) == '\n') {
800*3bbe3f67SBaptiste Daroussin 							ctnew++;
801*3bbe3f67SBaptiste Daroussin 							break;
802*3bbe3f67SBaptiste Daroussin 						}
803*3bbe3f67SBaptiste Daroussin 					}
804*3bbe3f67SBaptiste Daroussin 					if (d == '\r') {
805*3bbe3f67SBaptiste Daroussin 						if ((d = getc(f2)) == '\n') {
806*3bbe3f67SBaptiste Daroussin 							ctold++;
807*3bbe3f67SBaptiste Daroussin 							break;
808*3bbe3f67SBaptiste Daroussin 						}
809*3bbe3f67SBaptiste Daroussin 					}
810*3bbe3f67SBaptiste Daroussin 				}
811*3bbe3f67SBaptiste Daroussin 				if ((flags & D_FOLDBLANKS) && isspace(c) &&
812*3bbe3f67SBaptiste Daroussin 				    isspace(d)) {
813*3bbe3f67SBaptiste Daroussin 					do {
814*3bbe3f67SBaptiste Daroussin 						if (c == '\n')
815*3bbe3f67SBaptiste Daroussin 							break;
816*3bbe3f67SBaptiste Daroussin 						ctold++;
817*3bbe3f67SBaptiste Daroussin 					} while (isspace(c = getc(f1)));
818*3bbe3f67SBaptiste Daroussin 					do {
819*3bbe3f67SBaptiste Daroussin 						if (d == '\n')
820*3bbe3f67SBaptiste Daroussin 							break;
821*3bbe3f67SBaptiste Daroussin 						ctnew++;
822*3bbe3f67SBaptiste Daroussin 					} while (isspace(d = getc(f2)));
823*3bbe3f67SBaptiste Daroussin 				} else if ((flags & D_IGNOREBLANKS)) {
824*3bbe3f67SBaptiste Daroussin 					while (isspace(c) && c != '\n') {
825*3bbe3f67SBaptiste Daroussin 						c = getc(f1);
826*3bbe3f67SBaptiste Daroussin 						ctold++;
827*3bbe3f67SBaptiste Daroussin 					}
828*3bbe3f67SBaptiste Daroussin 					while (isspace(d) && d != '\n') {
829*3bbe3f67SBaptiste Daroussin 						d = getc(f2);
830*3bbe3f67SBaptiste Daroussin 						ctnew++;
831*3bbe3f67SBaptiste Daroussin 					}
832*3bbe3f67SBaptiste Daroussin 				}
833*3bbe3f67SBaptiste Daroussin 				if (chrtran[c] != chrtran[d]) {
834*3bbe3f67SBaptiste Daroussin 					jackpot++;
835*3bbe3f67SBaptiste Daroussin 					J[i] = 0;
836*3bbe3f67SBaptiste Daroussin 					if (c != '\n' && c != EOF)
837*3bbe3f67SBaptiste Daroussin 						ctold += skipline(f1);
838*3bbe3f67SBaptiste Daroussin 					if (d != '\n' && c != EOF)
839*3bbe3f67SBaptiste Daroussin 						ctnew += skipline(f2);
840*3bbe3f67SBaptiste Daroussin 					break;
841*3bbe3f67SBaptiste Daroussin 				}
842*3bbe3f67SBaptiste Daroussin 				if (c == '\n' || c == EOF)
843*3bbe3f67SBaptiste Daroussin 					break;
844*3bbe3f67SBaptiste Daroussin 			}
845*3bbe3f67SBaptiste Daroussin 		} else {
846*3bbe3f67SBaptiste Daroussin 			for (;;) {
847*3bbe3f67SBaptiste Daroussin 				ctold++;
848*3bbe3f67SBaptiste Daroussin 				ctnew++;
849*3bbe3f67SBaptiste Daroussin 				if ((c = getc(f1)) != (d = getc(f2))) {
850*3bbe3f67SBaptiste Daroussin 					/* jackpot++; */
851*3bbe3f67SBaptiste Daroussin 					J[i] = 0;
852*3bbe3f67SBaptiste Daroussin 					if (c != '\n' && c != EOF)
853*3bbe3f67SBaptiste Daroussin 						ctold += skipline(f1);
854*3bbe3f67SBaptiste Daroussin 					if (d != '\n' && c != EOF)
855*3bbe3f67SBaptiste Daroussin 						ctnew += skipline(f2);
856*3bbe3f67SBaptiste Daroussin 					break;
857*3bbe3f67SBaptiste Daroussin 				}
858*3bbe3f67SBaptiste Daroussin 				if (c == '\n' || c == EOF)
859*3bbe3f67SBaptiste Daroussin 					break;
860*3bbe3f67SBaptiste Daroussin 			}
861*3bbe3f67SBaptiste Daroussin 		}
862*3bbe3f67SBaptiste Daroussin 		ixold[i] = ctold;
863*3bbe3f67SBaptiste Daroussin 		ixnew[j] = ctnew;
864*3bbe3f67SBaptiste Daroussin 		j++;
865*3bbe3f67SBaptiste Daroussin 	}
866*3bbe3f67SBaptiste Daroussin 	for (; j <= len[1]; j++) {
867*3bbe3f67SBaptiste Daroussin 		ixnew[j] = ctnew += skipline(f2);
868*3bbe3f67SBaptiste Daroussin 	}
869*3bbe3f67SBaptiste Daroussin 	/*
870*3bbe3f67SBaptiste Daroussin 	 * if (jackpot)
871*3bbe3f67SBaptiste Daroussin 	 *	fprintf(stderr, "jackpot\n");
872*3bbe3f67SBaptiste Daroussin 	 */
873*3bbe3f67SBaptiste Daroussin }
874*3bbe3f67SBaptiste Daroussin 
875*3bbe3f67SBaptiste Daroussin /* shellsort CACM #201 */
876*3bbe3f67SBaptiste Daroussin static void
877*3bbe3f67SBaptiste Daroussin sort(struct line *a, int n)
878*3bbe3f67SBaptiste Daroussin {
879*3bbe3f67SBaptiste Daroussin 	struct line *ai, *aim, w;
880*3bbe3f67SBaptiste Daroussin 	int j, m = 0, k;
881*3bbe3f67SBaptiste Daroussin 
882*3bbe3f67SBaptiste Daroussin 	if (n == 0)
883*3bbe3f67SBaptiste Daroussin 		return;
884*3bbe3f67SBaptiste Daroussin 	for (j = 1; j <= n; j *= 2)
885*3bbe3f67SBaptiste Daroussin 		m = 2 * j - 1;
886*3bbe3f67SBaptiste Daroussin 	for (m /= 2; m != 0; m /= 2) {
887*3bbe3f67SBaptiste Daroussin 		k = n - m;
888*3bbe3f67SBaptiste Daroussin 		for (j = 1; j <= k; j++) {
889*3bbe3f67SBaptiste Daroussin 			for (ai = &a[j]; ai > a; ai -= m) {
890*3bbe3f67SBaptiste Daroussin 				aim = &ai[m];
891*3bbe3f67SBaptiste Daroussin 				if (aim < ai)
892*3bbe3f67SBaptiste Daroussin 					break;	/* wraparound */
893*3bbe3f67SBaptiste Daroussin 				if (aim->value > ai[0].value ||
894*3bbe3f67SBaptiste Daroussin 				    (aim->value == ai[0].value &&
895*3bbe3f67SBaptiste Daroussin 					aim->serial > ai[0].serial))
896*3bbe3f67SBaptiste Daroussin 					break;
897*3bbe3f67SBaptiste Daroussin 				w.value = ai[0].value;
898*3bbe3f67SBaptiste Daroussin 				ai[0].value = aim->value;
899*3bbe3f67SBaptiste Daroussin 				aim->value = w.value;
900*3bbe3f67SBaptiste Daroussin 				w.serial = ai[0].serial;
901*3bbe3f67SBaptiste Daroussin 				ai[0].serial = aim->serial;
902*3bbe3f67SBaptiste Daroussin 				aim->serial = w.serial;
903*3bbe3f67SBaptiste Daroussin 			}
904*3bbe3f67SBaptiste Daroussin 		}
905*3bbe3f67SBaptiste Daroussin 	}
906*3bbe3f67SBaptiste Daroussin }
907*3bbe3f67SBaptiste Daroussin 
908*3bbe3f67SBaptiste Daroussin static void
909*3bbe3f67SBaptiste Daroussin unsort(struct line *f, int l, int *b)
910*3bbe3f67SBaptiste Daroussin {
911*3bbe3f67SBaptiste Daroussin 	int *a, i;
912*3bbe3f67SBaptiste Daroussin 
913*3bbe3f67SBaptiste Daroussin 	a = xcalloc(l + 1, sizeof(*a));
914*3bbe3f67SBaptiste Daroussin 	for (i = 1; i <= l; i++)
915*3bbe3f67SBaptiste Daroussin 		a[f[i].serial] = f[i].value;
916*3bbe3f67SBaptiste Daroussin 	for (i = 1; i <= l; i++)
917*3bbe3f67SBaptiste Daroussin 		b[i] = a[i];
918*3bbe3f67SBaptiste Daroussin 	free(a);
919*3bbe3f67SBaptiste Daroussin }
920*3bbe3f67SBaptiste Daroussin 
921*3bbe3f67SBaptiste Daroussin static int
922*3bbe3f67SBaptiste Daroussin skipline(FILE *f)
923*3bbe3f67SBaptiste Daroussin {
924*3bbe3f67SBaptiste Daroussin 	int i, c;
925*3bbe3f67SBaptiste Daroussin 
926*3bbe3f67SBaptiste Daroussin 	for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
927*3bbe3f67SBaptiste Daroussin 		continue;
928*3bbe3f67SBaptiste Daroussin 	return (i);
929*3bbe3f67SBaptiste Daroussin }
930*3bbe3f67SBaptiste Daroussin 
931*3bbe3f67SBaptiste Daroussin static void
932*3bbe3f67SBaptiste Daroussin output(char *file1, FILE *f1, char *file2, FILE *f2, int flags)
933*3bbe3f67SBaptiste Daroussin {
934*3bbe3f67SBaptiste Daroussin 	int m, i0, i1, j0, j1;
935*3bbe3f67SBaptiste Daroussin 
936*3bbe3f67SBaptiste Daroussin 	rewind(f1);
937*3bbe3f67SBaptiste Daroussin 	rewind(f2);
938*3bbe3f67SBaptiste Daroussin 	m = len[0];
939*3bbe3f67SBaptiste Daroussin 	J[0] = 0;
940*3bbe3f67SBaptiste Daroussin 	J[m + 1] = len[1] + 1;
941*3bbe3f67SBaptiste Daroussin 	if (diff_format != D_EDIT) {
942*3bbe3f67SBaptiste Daroussin 		for (i0 = 1; i0 <= m; i0 = i1 + 1) {
943*3bbe3f67SBaptiste Daroussin 			while (i0 <= m && J[i0] == J[i0 - 1] + 1)
944*3bbe3f67SBaptiste Daroussin 				i0++;
945*3bbe3f67SBaptiste Daroussin 			j0 = J[i0 - 1] + 1;
946*3bbe3f67SBaptiste Daroussin 			i1 = i0 - 1;
947*3bbe3f67SBaptiste Daroussin 			while (i1 < m && J[i1 + 1] == 0)
948*3bbe3f67SBaptiste Daroussin 				i1++;
949*3bbe3f67SBaptiste Daroussin 			j1 = J[i1 + 1] - 1;
950*3bbe3f67SBaptiste Daroussin 			J[i1] = j1;
951*3bbe3f67SBaptiste Daroussin 			change(file1, f1, file2, f2, i0, i1, j0, j1, &flags);
952*3bbe3f67SBaptiste Daroussin 		}
953*3bbe3f67SBaptiste Daroussin 	} else {
954*3bbe3f67SBaptiste Daroussin 		for (i0 = m; i0 >= 1; i0 = i1 - 1) {
955*3bbe3f67SBaptiste Daroussin 			while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0)
956*3bbe3f67SBaptiste Daroussin 				i0--;
957*3bbe3f67SBaptiste Daroussin 			j0 = J[i0 + 1] - 1;
958*3bbe3f67SBaptiste Daroussin 			i1 = i0 + 1;
959*3bbe3f67SBaptiste Daroussin 			while (i1 > 1 && J[i1 - 1] == 0)
960*3bbe3f67SBaptiste Daroussin 				i1--;
961*3bbe3f67SBaptiste Daroussin 			j1 = J[i1 - 1] + 1;
962*3bbe3f67SBaptiste Daroussin 			J[i1] = j1;
963*3bbe3f67SBaptiste Daroussin 			change(file1, f1, file2, f2, i1, i0, j1, j0, &flags);
964*3bbe3f67SBaptiste Daroussin 		}
965*3bbe3f67SBaptiste Daroussin 	}
966*3bbe3f67SBaptiste Daroussin 	if (m == 0)
967*3bbe3f67SBaptiste Daroussin 		change(file1, f1, file2, f2, 1, 0, 1, len[1], &flags);
968*3bbe3f67SBaptiste Daroussin 	if (diff_format == D_IFDEF) {
969*3bbe3f67SBaptiste Daroussin 		for (;;) {
970*3bbe3f67SBaptiste Daroussin #define	c i0
971*3bbe3f67SBaptiste Daroussin 			if ((c = getc(f1)) == EOF)
972*3bbe3f67SBaptiste Daroussin 				return;
973*3bbe3f67SBaptiste Daroussin 			diff_output("%c", c);
974*3bbe3f67SBaptiste Daroussin 		}
975*3bbe3f67SBaptiste Daroussin #undef c
976*3bbe3f67SBaptiste Daroussin 	}
977*3bbe3f67SBaptiste Daroussin 	if (anychange != 0) {
978*3bbe3f67SBaptiste Daroussin 		if (diff_format == D_CONTEXT)
979*3bbe3f67SBaptiste Daroussin 			dump_context_vec(f1, f2, flags);
980*3bbe3f67SBaptiste Daroussin 		else if (diff_format == D_UNIFIED)
981*3bbe3f67SBaptiste Daroussin 			dump_unified_vec(f1, f2, flags);
982*3bbe3f67SBaptiste Daroussin 	}
983*3bbe3f67SBaptiste Daroussin }
984*3bbe3f67SBaptiste Daroussin 
985*3bbe3f67SBaptiste Daroussin static void
986*3bbe3f67SBaptiste Daroussin range(int a, int b, const char *separator)
987*3bbe3f67SBaptiste Daroussin {
988*3bbe3f67SBaptiste Daroussin 	diff_output("%d", a > b ? b : a);
989*3bbe3f67SBaptiste Daroussin 	if (a < b)
990*3bbe3f67SBaptiste Daroussin 		diff_output("%s%d", separator, b);
991*3bbe3f67SBaptiste Daroussin }
992*3bbe3f67SBaptiste Daroussin 
993*3bbe3f67SBaptiste Daroussin static void
994*3bbe3f67SBaptiste Daroussin uni_range(int a, int b)
995*3bbe3f67SBaptiste Daroussin {
996*3bbe3f67SBaptiste Daroussin 	if (a < b)
997*3bbe3f67SBaptiste Daroussin 		diff_output("%d,%d", a, b - a + 1);
998*3bbe3f67SBaptiste Daroussin 	else if (a == b)
999*3bbe3f67SBaptiste Daroussin 		diff_output("%d", b);
1000*3bbe3f67SBaptiste Daroussin 	else
1001*3bbe3f67SBaptiste Daroussin 		diff_output("%d,0", b);
1002*3bbe3f67SBaptiste Daroussin }
1003*3bbe3f67SBaptiste Daroussin 
1004*3bbe3f67SBaptiste Daroussin static char *
1005*3bbe3f67SBaptiste Daroussin preadline(int fd, size_t rlen, off_t off)
1006*3bbe3f67SBaptiste Daroussin {
1007*3bbe3f67SBaptiste Daroussin 	char *line;
1008*3bbe3f67SBaptiste Daroussin 	ssize_t nr;
1009*3bbe3f67SBaptiste Daroussin 
1010*3bbe3f67SBaptiste Daroussin 	line = xmalloc(rlen + 1);
1011*3bbe3f67SBaptiste Daroussin 	if ((nr = pread(fd, line, rlen, off)) < 0)
1012*3bbe3f67SBaptiste Daroussin 		err(2, "preadline");
1013*3bbe3f67SBaptiste Daroussin 	if (nr > 0 && line[nr-1] == '\n')
1014*3bbe3f67SBaptiste Daroussin 		nr--;
1015*3bbe3f67SBaptiste Daroussin 	line[nr] = '\0';
1016*3bbe3f67SBaptiste Daroussin 	return (line);
1017*3bbe3f67SBaptiste Daroussin }
1018*3bbe3f67SBaptiste Daroussin 
1019*3bbe3f67SBaptiste Daroussin static int
1020*3bbe3f67SBaptiste Daroussin ignoreline(char *line)
1021*3bbe3f67SBaptiste Daroussin {
1022*3bbe3f67SBaptiste Daroussin 	int ret;
1023*3bbe3f67SBaptiste Daroussin 
1024*3bbe3f67SBaptiste Daroussin 	ret = regexec(&ignore_re, line, 0, NULL, 0);
1025*3bbe3f67SBaptiste Daroussin 	free(line);
1026*3bbe3f67SBaptiste Daroussin 	return (ret == 0);	/* if it matched, it should be ignored. */
1027*3bbe3f67SBaptiste Daroussin }
1028*3bbe3f67SBaptiste Daroussin 
1029*3bbe3f67SBaptiste Daroussin /*
1030*3bbe3f67SBaptiste Daroussin  * Indicate that there is a difference between lines a and b of the from file
1031*3bbe3f67SBaptiste Daroussin  * to get to lines c to d of the to file.  If a is greater then b then there
1032*3bbe3f67SBaptiste Daroussin  * are no lines in the from file involved and this means that there were
1033*3bbe3f67SBaptiste Daroussin  * lines appended (beginning at b).  If c is greater than d then there are
1034*3bbe3f67SBaptiste Daroussin  * lines missing from the to file.
1035*3bbe3f67SBaptiste Daroussin  */
1036*3bbe3f67SBaptiste Daroussin static void
1037*3bbe3f67SBaptiste Daroussin change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d,
1038*3bbe3f67SBaptiste Daroussin     int *pflags)
1039*3bbe3f67SBaptiste Daroussin {
1040*3bbe3f67SBaptiste Daroussin 	static size_t max_context = 64;
1041*3bbe3f67SBaptiste Daroussin 	int i;
1042*3bbe3f67SBaptiste Daroussin 
1043*3bbe3f67SBaptiste Daroussin restart:
1044*3bbe3f67SBaptiste Daroussin 	if (diff_format != D_IFDEF && a > b && c > d)
1045*3bbe3f67SBaptiste Daroussin 		return;
1046*3bbe3f67SBaptiste Daroussin 	if (ignore_pats != NULL) {
1047*3bbe3f67SBaptiste Daroussin 		char *line;
1048*3bbe3f67SBaptiste Daroussin 		/*
1049*3bbe3f67SBaptiste Daroussin 		 * All lines in the change, insert, or delete must
1050*3bbe3f67SBaptiste Daroussin 		 * match an ignore pattern for the change to be
1051*3bbe3f67SBaptiste Daroussin 		 * ignored.
1052*3bbe3f67SBaptiste Daroussin 		 */
1053*3bbe3f67SBaptiste Daroussin 		if (a <= b) {		/* Changes and deletes. */
1054*3bbe3f67SBaptiste Daroussin 			for (i = a; i <= b; i++) {
1055*3bbe3f67SBaptiste Daroussin 				line = preadline(fileno(f1),
1056*3bbe3f67SBaptiste Daroussin 				    ixold[i] - ixold[i - 1], ixold[i - 1]);
1057*3bbe3f67SBaptiste Daroussin 				if (!ignoreline(line))
1058*3bbe3f67SBaptiste Daroussin 					goto proceed;
1059*3bbe3f67SBaptiste Daroussin 			}
1060*3bbe3f67SBaptiste Daroussin 		}
1061*3bbe3f67SBaptiste Daroussin 		if (a > b || c <= d) {	/* Changes and inserts. */
1062*3bbe3f67SBaptiste Daroussin 			for (i = c; i <= d; i++) {
1063*3bbe3f67SBaptiste Daroussin 				line = preadline(fileno(f2),
1064*3bbe3f67SBaptiste Daroussin 				    ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
1065*3bbe3f67SBaptiste Daroussin 				if (!ignoreline(line))
1066*3bbe3f67SBaptiste Daroussin 					goto proceed;
1067*3bbe3f67SBaptiste Daroussin 			}
1068*3bbe3f67SBaptiste Daroussin 		}
1069*3bbe3f67SBaptiste Daroussin 		return;
1070*3bbe3f67SBaptiste Daroussin 	}
1071*3bbe3f67SBaptiste Daroussin proceed:
1072*3bbe3f67SBaptiste Daroussin 	if (*pflags & D_HEADER) {
1073*3bbe3f67SBaptiste Daroussin 		diff_output("%s %s %s\n", diffargs, file1, file2);
1074*3bbe3f67SBaptiste Daroussin 		*pflags &= ~D_HEADER;
1075*3bbe3f67SBaptiste Daroussin 	}
1076*3bbe3f67SBaptiste Daroussin 	if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
1077*3bbe3f67SBaptiste Daroussin 		/*
1078*3bbe3f67SBaptiste Daroussin 		 * Allocate change records as needed.
1079*3bbe3f67SBaptiste Daroussin 		 */
1080*3bbe3f67SBaptiste Daroussin 		if (context_vec_ptr == context_vec_end - 1) {
1081*3bbe3f67SBaptiste Daroussin 			ptrdiff_t offset = context_vec_ptr - context_vec_start;
1082*3bbe3f67SBaptiste Daroussin 			max_context <<= 1;
1083*3bbe3f67SBaptiste Daroussin 			context_vec_start = xreallocarray(context_vec_start,
1084*3bbe3f67SBaptiste Daroussin 			    max_context, sizeof(*context_vec_start));
1085*3bbe3f67SBaptiste Daroussin 			context_vec_end = context_vec_start + max_context;
1086*3bbe3f67SBaptiste Daroussin 			context_vec_ptr = context_vec_start + offset;
1087*3bbe3f67SBaptiste Daroussin 		}
1088*3bbe3f67SBaptiste Daroussin 		if (anychange == 0) {
1089*3bbe3f67SBaptiste Daroussin 			/*
1090*3bbe3f67SBaptiste Daroussin 			 * Print the context/unidiff header first time through.
1091*3bbe3f67SBaptiste Daroussin 			 */
1092*3bbe3f67SBaptiste Daroussin 			print_header(file1, file2);
1093*3bbe3f67SBaptiste Daroussin 			anychange = 1;
1094*3bbe3f67SBaptiste Daroussin 		} else if (a > context_vec_ptr->b + (2 * diff_context) + 1 &&
1095*3bbe3f67SBaptiste Daroussin 		    c > context_vec_ptr->d + (2 * diff_context) + 1) {
1096*3bbe3f67SBaptiste Daroussin 			/*
1097*3bbe3f67SBaptiste Daroussin 			 * If this change is more than 'diff_context' lines from the
1098*3bbe3f67SBaptiste Daroussin 			 * previous change, dump the record and reset it.
1099*3bbe3f67SBaptiste Daroussin 			 */
1100*3bbe3f67SBaptiste Daroussin 			if (diff_format == D_CONTEXT)
1101*3bbe3f67SBaptiste Daroussin 				dump_context_vec(f1, f2, *pflags);
1102*3bbe3f67SBaptiste Daroussin 			else
1103*3bbe3f67SBaptiste Daroussin 				dump_unified_vec(f1, f2, *pflags);
1104*3bbe3f67SBaptiste Daroussin 		}
1105*3bbe3f67SBaptiste Daroussin 		context_vec_ptr++;
1106*3bbe3f67SBaptiste Daroussin 		context_vec_ptr->a = a;
1107*3bbe3f67SBaptiste Daroussin 		context_vec_ptr->b = b;
1108*3bbe3f67SBaptiste Daroussin 		context_vec_ptr->c = c;
1109*3bbe3f67SBaptiste Daroussin 		context_vec_ptr->d = d;
1110*3bbe3f67SBaptiste Daroussin 		return;
1111*3bbe3f67SBaptiste Daroussin 	}
1112*3bbe3f67SBaptiste Daroussin 	if (anychange == 0)
1113*3bbe3f67SBaptiste Daroussin 		anychange = 1;
1114*3bbe3f67SBaptiste Daroussin 	switch (diff_format) {
1115*3bbe3f67SBaptiste Daroussin 	case D_BRIEF:
1116*3bbe3f67SBaptiste Daroussin 		return;
1117*3bbe3f67SBaptiste Daroussin 	case D_NORMAL:
1118*3bbe3f67SBaptiste Daroussin 	case D_EDIT:
1119*3bbe3f67SBaptiste Daroussin 		range(a, b, ",");
1120*3bbe3f67SBaptiste Daroussin 		diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
1121*3bbe3f67SBaptiste Daroussin 		if (diff_format == D_NORMAL)
1122*3bbe3f67SBaptiste Daroussin 			range(c, d, ",");
1123*3bbe3f67SBaptiste Daroussin 		diff_output("\n");
1124*3bbe3f67SBaptiste Daroussin 		break;
1125*3bbe3f67SBaptiste Daroussin 	case D_REVERSE:
1126*3bbe3f67SBaptiste Daroussin 		diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
1127*3bbe3f67SBaptiste Daroussin 		range(a, b, " ");
1128*3bbe3f67SBaptiste Daroussin 		diff_output("\n");
1129*3bbe3f67SBaptiste Daroussin 		break;
1130*3bbe3f67SBaptiste Daroussin 	case D_NREVERSE:
1131*3bbe3f67SBaptiste Daroussin 		if (a > b)
1132*3bbe3f67SBaptiste Daroussin 			diff_output("a%d %d\n", b, d - c + 1);
1133*3bbe3f67SBaptiste Daroussin 		else {
1134*3bbe3f67SBaptiste Daroussin 			diff_output("d%d %d\n", a, b - a + 1);
1135*3bbe3f67SBaptiste Daroussin 			if (!(c > d))
1136*3bbe3f67SBaptiste Daroussin 				/* add changed lines */
1137*3bbe3f67SBaptiste Daroussin 				diff_output("a%d %d\n", b, d - c + 1);
1138*3bbe3f67SBaptiste Daroussin 		}
1139*3bbe3f67SBaptiste Daroussin 		break;
1140*3bbe3f67SBaptiste Daroussin 	}
1141*3bbe3f67SBaptiste Daroussin 	if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
1142*3bbe3f67SBaptiste Daroussin 		fetch(ixold, a, b, f1, '<', 1, *pflags);
1143*3bbe3f67SBaptiste Daroussin 		if (a <= b && c <= d && diff_format == D_NORMAL)
1144*3bbe3f67SBaptiste Daroussin 			diff_output("---\n");
1145*3bbe3f67SBaptiste Daroussin 	}
1146*3bbe3f67SBaptiste Daroussin 	i = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, *pflags);
1147*3bbe3f67SBaptiste Daroussin 	if (i != 0 && diff_format == D_EDIT) {
1148*3bbe3f67SBaptiste Daroussin 		/*
1149*3bbe3f67SBaptiste Daroussin 		 * A non-zero return value for D_EDIT indicates that the
1150*3bbe3f67SBaptiste Daroussin 		 * last line printed was a bare dot (".") that has been
1151*3bbe3f67SBaptiste Daroussin 		 * escaped as ".." to prevent ed(1) from misinterpreting
1152*3bbe3f67SBaptiste Daroussin 		 * it.  We have to add a substitute command to change this
1153*3bbe3f67SBaptiste Daroussin 		 * back and restart where we left off.
1154*3bbe3f67SBaptiste Daroussin 		 */
1155*3bbe3f67SBaptiste Daroussin 		diff_output(".\n");
1156*3bbe3f67SBaptiste Daroussin 		diff_output("%ds/.//\n", a + i - 1);
1157*3bbe3f67SBaptiste Daroussin 		b = a + i - 1;
1158*3bbe3f67SBaptiste Daroussin 		a = b + 1;
1159*3bbe3f67SBaptiste Daroussin 		c += i;
1160*3bbe3f67SBaptiste Daroussin 		goto restart;
1161*3bbe3f67SBaptiste Daroussin 	}
1162*3bbe3f67SBaptiste Daroussin 	if ((diff_format == D_EDIT || diff_format == D_REVERSE) && c <= d)
1163*3bbe3f67SBaptiste Daroussin 		diff_output(".\n");
1164*3bbe3f67SBaptiste Daroussin 	if (inifdef) {
1165*3bbe3f67SBaptiste Daroussin 		diff_output("#endif /* %s */\n", ifdefname);
1166*3bbe3f67SBaptiste Daroussin 		inifdef = 0;
1167*3bbe3f67SBaptiste Daroussin 	}
1168*3bbe3f67SBaptiste Daroussin }
1169*3bbe3f67SBaptiste Daroussin 
1170*3bbe3f67SBaptiste Daroussin static int
1171*3bbe3f67SBaptiste Daroussin fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags)
1172*3bbe3f67SBaptiste Daroussin {
1173*3bbe3f67SBaptiste Daroussin 	int i, j, c, lastc, col, nc;
1174*3bbe3f67SBaptiste Daroussin 	int	newcol;
1175*3bbe3f67SBaptiste Daroussin 
1176*3bbe3f67SBaptiste Daroussin 	/*
1177*3bbe3f67SBaptiste Daroussin 	 * When doing #ifdef's, copy down to current line
1178*3bbe3f67SBaptiste Daroussin 	 * if this is the first file, so that stuff makes it to output.
1179*3bbe3f67SBaptiste Daroussin 	 */
1180*3bbe3f67SBaptiste Daroussin 	if (diff_format == D_IFDEF && oldfile) {
1181*3bbe3f67SBaptiste Daroussin 		long curpos = ftell(lb);
1182*3bbe3f67SBaptiste Daroussin 		/* print through if append (a>b), else to (nb: 0 vs 1 orig) */
1183*3bbe3f67SBaptiste Daroussin 		nc = f[a > b ? b : a - 1] - curpos;
1184*3bbe3f67SBaptiste Daroussin 		for (i = 0; i < nc; i++)
1185*3bbe3f67SBaptiste Daroussin 			diff_output("%c", getc(lb));
1186*3bbe3f67SBaptiste Daroussin 	}
1187*3bbe3f67SBaptiste Daroussin 	if (a > b)
1188*3bbe3f67SBaptiste Daroussin 		return (0);
1189*3bbe3f67SBaptiste Daroussin 	if (diff_format == D_IFDEF) {
1190*3bbe3f67SBaptiste Daroussin 		if (inifdef) {
1191*3bbe3f67SBaptiste Daroussin 			diff_output("#else /* %s%s */\n",
1192*3bbe3f67SBaptiste Daroussin 			    oldfile == 1 ? "!" : "", ifdefname);
1193*3bbe3f67SBaptiste Daroussin 		} else {
1194*3bbe3f67SBaptiste Daroussin 			if (oldfile)
1195*3bbe3f67SBaptiste Daroussin 				diff_output("#ifndef %s\n", ifdefname);
1196*3bbe3f67SBaptiste Daroussin 			else
1197*3bbe3f67SBaptiste Daroussin 				diff_output("#ifdef %s\n", ifdefname);
1198*3bbe3f67SBaptiste Daroussin 		}
1199*3bbe3f67SBaptiste Daroussin 		inifdef = 1 + oldfile;
1200*3bbe3f67SBaptiste Daroussin 	}
1201*3bbe3f67SBaptiste Daroussin 	for (i = a; i <= b; i++) {
1202*3bbe3f67SBaptiste Daroussin 		fseek(lb, f[i - 1], SEEK_SET);
1203*3bbe3f67SBaptiste Daroussin 		nc = f[i] - f[i - 1];
1204*3bbe3f67SBaptiste Daroussin 		if (diff_format != D_IFDEF && ch != '\0') {
1205*3bbe3f67SBaptiste Daroussin 			diff_output("%c", ch);
1206*3bbe3f67SBaptiste Daroussin 			if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT
1207*3bbe3f67SBaptiste Daroussin 			    || diff_format == D_UNIFIED))
1208*3bbe3f67SBaptiste Daroussin 				diff_output("\t");
1209*3bbe3f67SBaptiste Daroussin 			else if (diff_format != D_UNIFIED)
1210*3bbe3f67SBaptiste Daroussin 				diff_output(" ");
1211*3bbe3f67SBaptiste Daroussin 		}
1212*3bbe3f67SBaptiste Daroussin 		col = 0;
1213*3bbe3f67SBaptiste Daroussin 		for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) {
1214*3bbe3f67SBaptiste Daroussin 			if ((c = getc(lb)) == EOF) {
1215*3bbe3f67SBaptiste Daroussin 				if (diff_format == D_EDIT || diff_format == D_REVERSE ||
1216*3bbe3f67SBaptiste Daroussin 				    diff_format == D_NREVERSE)
1217*3bbe3f67SBaptiste Daroussin 					warnx("No newline at end of file");
1218*3bbe3f67SBaptiste Daroussin 				else
1219*3bbe3f67SBaptiste Daroussin 					diff_output("\n\\ No newline at end of "
1220*3bbe3f67SBaptiste Daroussin 					    "file\n");
1221*3bbe3f67SBaptiste Daroussin 				return (0);
1222*3bbe3f67SBaptiste Daroussin 			}
1223*3bbe3f67SBaptiste Daroussin 			if (c == '\t' && (flags & D_EXPANDTABS)) {
1224*3bbe3f67SBaptiste Daroussin 				newcol = ((col/tabsize)+1)*tabsize;
1225*3bbe3f67SBaptiste Daroussin 				do {
1226*3bbe3f67SBaptiste Daroussin 					diff_output(" ");
1227*3bbe3f67SBaptiste Daroussin 				} while (++col < newcol);
1228*3bbe3f67SBaptiste Daroussin 			} else {
1229*3bbe3f67SBaptiste Daroussin 				if (diff_format == D_EDIT && j == 1 && c == '\n'
1230*3bbe3f67SBaptiste Daroussin 				    && lastc == '.') {
1231*3bbe3f67SBaptiste Daroussin 					/*
1232*3bbe3f67SBaptiste Daroussin 					 * Don't print a bare "." line
1233*3bbe3f67SBaptiste Daroussin 					 * since that will confuse ed(1).
1234*3bbe3f67SBaptiste Daroussin 					 * Print ".." instead and return,
1235*3bbe3f67SBaptiste Daroussin 					 * giving the caller an offset
1236*3bbe3f67SBaptiste Daroussin 					 * from which to restart.
1237*3bbe3f67SBaptiste Daroussin 					 */
1238*3bbe3f67SBaptiste Daroussin 					diff_output(".\n");
1239*3bbe3f67SBaptiste Daroussin 					return (i - a + 1);
1240*3bbe3f67SBaptiste Daroussin 				}
1241*3bbe3f67SBaptiste Daroussin 				diff_output("%c", c);
1242*3bbe3f67SBaptiste Daroussin 				col++;
1243*3bbe3f67SBaptiste Daroussin 			}
1244*3bbe3f67SBaptiste Daroussin 		}
1245*3bbe3f67SBaptiste Daroussin 	}
1246*3bbe3f67SBaptiste Daroussin 	return (0);
1247*3bbe3f67SBaptiste Daroussin }
1248*3bbe3f67SBaptiste Daroussin 
1249*3bbe3f67SBaptiste Daroussin /*
1250*3bbe3f67SBaptiste Daroussin  * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
1251*3bbe3f67SBaptiste Daroussin  */
1252*3bbe3f67SBaptiste Daroussin static int
1253*3bbe3f67SBaptiste Daroussin readhash(FILE *f, int flags)
1254*3bbe3f67SBaptiste Daroussin {
1255*3bbe3f67SBaptiste Daroussin 	int i, t, space;
1256*3bbe3f67SBaptiste Daroussin 	int sum;
1257*3bbe3f67SBaptiste Daroussin 
1258*3bbe3f67SBaptiste Daroussin 	sum = 1;
1259*3bbe3f67SBaptiste Daroussin 	space = 0;
1260*3bbe3f67SBaptiste Daroussin 	if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) {
1261*3bbe3f67SBaptiste Daroussin 		if (flags & D_IGNORECASE)
1262*3bbe3f67SBaptiste Daroussin 			for (i = 0; (t = getc(f)) != '\n'; i++) {
1263*3bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR && t == '\r') {
1264*3bbe3f67SBaptiste Daroussin 					t = getc(f);
1265*3bbe3f67SBaptiste Daroussin 					if (t == '\n')
1266*3bbe3f67SBaptiste Daroussin 						break;
1267*3bbe3f67SBaptiste Daroussin 					ungetc(t, f);
1268*3bbe3f67SBaptiste Daroussin 				}
1269*3bbe3f67SBaptiste Daroussin 				if (t == EOF) {
1270*3bbe3f67SBaptiste Daroussin 					if (i == 0)
1271*3bbe3f67SBaptiste Daroussin 						return (0);
1272*3bbe3f67SBaptiste Daroussin 					break;
1273*3bbe3f67SBaptiste Daroussin 				}
1274*3bbe3f67SBaptiste Daroussin 				sum = sum * 127 + chrtran[t];
1275*3bbe3f67SBaptiste Daroussin 			}
1276*3bbe3f67SBaptiste Daroussin 		else
1277*3bbe3f67SBaptiste Daroussin 			for (i = 0; (t = getc(f)) != '\n'; i++) {
1278*3bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR && t == '\r') {
1279*3bbe3f67SBaptiste Daroussin 					t = getc(f);
1280*3bbe3f67SBaptiste Daroussin 					if (t == '\n')
1281*3bbe3f67SBaptiste Daroussin 						break;
1282*3bbe3f67SBaptiste Daroussin 					ungetc(t, f);
1283*3bbe3f67SBaptiste Daroussin 				}
1284*3bbe3f67SBaptiste Daroussin 				if (t == EOF) {
1285*3bbe3f67SBaptiste Daroussin 					if (i == 0)
1286*3bbe3f67SBaptiste Daroussin 						return (0);
1287*3bbe3f67SBaptiste Daroussin 					break;
1288*3bbe3f67SBaptiste Daroussin 				}
1289*3bbe3f67SBaptiste Daroussin 				sum = sum * 127 + t;
1290*3bbe3f67SBaptiste Daroussin 			}
1291*3bbe3f67SBaptiste Daroussin 	} else {
1292*3bbe3f67SBaptiste Daroussin 		for (i = 0;;) {
1293*3bbe3f67SBaptiste Daroussin 			switch (t = getc(f)) {
1294*3bbe3f67SBaptiste Daroussin 			case '\r':
1295*3bbe3f67SBaptiste Daroussin 			case '\t':
1296*3bbe3f67SBaptiste Daroussin 			case '\v':
1297*3bbe3f67SBaptiste Daroussin 			case '\f':
1298*3bbe3f67SBaptiste Daroussin 			case ' ':
1299*3bbe3f67SBaptiste Daroussin 				space++;
1300*3bbe3f67SBaptiste Daroussin 				continue;
1301*3bbe3f67SBaptiste Daroussin 			default:
1302*3bbe3f67SBaptiste Daroussin 				if (space && (flags & D_IGNOREBLANKS) == 0) {
1303*3bbe3f67SBaptiste Daroussin 					i++;
1304*3bbe3f67SBaptiste Daroussin 					space = 0;
1305*3bbe3f67SBaptiste Daroussin 				}
1306*3bbe3f67SBaptiste Daroussin 				sum = sum * 127 + chrtran[t];
1307*3bbe3f67SBaptiste Daroussin 				i++;
1308*3bbe3f67SBaptiste Daroussin 				continue;
1309*3bbe3f67SBaptiste Daroussin 			case EOF:
1310*3bbe3f67SBaptiste Daroussin 				if (i == 0)
1311*3bbe3f67SBaptiste Daroussin 					return (0);
1312*3bbe3f67SBaptiste Daroussin 				/* FALLTHROUGH */
1313*3bbe3f67SBaptiste Daroussin 			case '\n':
1314*3bbe3f67SBaptiste Daroussin 				break;
1315*3bbe3f67SBaptiste Daroussin 			}
1316*3bbe3f67SBaptiste Daroussin 			break;
1317*3bbe3f67SBaptiste Daroussin 		}
1318*3bbe3f67SBaptiste Daroussin 	}
1319*3bbe3f67SBaptiste Daroussin 	/*
1320*3bbe3f67SBaptiste Daroussin 	 * There is a remote possibility that we end up with a zero sum.
1321*3bbe3f67SBaptiste Daroussin 	 * Zero is used as an EOF marker, so return 1 instead.
1322*3bbe3f67SBaptiste Daroussin 	 */
1323*3bbe3f67SBaptiste Daroussin 	return (sum == 0 ? 1 : sum);
1324*3bbe3f67SBaptiste Daroussin }
1325*3bbe3f67SBaptiste Daroussin 
1326*3bbe3f67SBaptiste Daroussin static int
1327*3bbe3f67SBaptiste Daroussin asciifile(FILE *f)
1328*3bbe3f67SBaptiste Daroussin {
1329*3bbe3f67SBaptiste Daroussin 	unsigned char buf[BUFSIZ];
1330*3bbe3f67SBaptiste Daroussin 	size_t cnt;
1331*3bbe3f67SBaptiste Daroussin 
1332*3bbe3f67SBaptiste Daroussin 	if (f == NULL)
1333*3bbe3f67SBaptiste Daroussin 		return (1);
1334*3bbe3f67SBaptiste Daroussin 
1335*3bbe3f67SBaptiste Daroussin 	rewind(f);
1336*3bbe3f67SBaptiste Daroussin 	cnt = fread(buf, 1, sizeof(buf), f);
1337*3bbe3f67SBaptiste Daroussin 	return (memchr(buf, '\0', cnt) == NULL);
1338*3bbe3f67SBaptiste Daroussin }
1339*3bbe3f67SBaptiste Daroussin 
1340*3bbe3f67SBaptiste Daroussin #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
1341*3bbe3f67SBaptiste Daroussin 
1342*3bbe3f67SBaptiste Daroussin static char *
1343*3bbe3f67SBaptiste Daroussin match_function(const long *f, int pos, FILE *fp)
1344*3bbe3f67SBaptiste Daroussin {
1345*3bbe3f67SBaptiste Daroussin 	unsigned char buf[FUNCTION_CONTEXT_SIZE];
1346*3bbe3f67SBaptiste Daroussin 	size_t nc;
1347*3bbe3f67SBaptiste Daroussin 	int last = lastline;
1348*3bbe3f67SBaptiste Daroussin 	const char *state = NULL;
1349*3bbe3f67SBaptiste Daroussin 
1350*3bbe3f67SBaptiste Daroussin 	lastline = pos;
1351*3bbe3f67SBaptiste Daroussin 	while (pos > last) {
1352*3bbe3f67SBaptiste Daroussin 		fseek(fp, f[pos - 1], SEEK_SET);
1353*3bbe3f67SBaptiste Daroussin 		nc = f[pos] - f[pos - 1];
1354*3bbe3f67SBaptiste Daroussin 		if (nc >= sizeof(buf))
1355*3bbe3f67SBaptiste Daroussin 			nc = sizeof(buf) - 1;
1356*3bbe3f67SBaptiste Daroussin 		nc = fread(buf, 1, nc, fp);
1357*3bbe3f67SBaptiste Daroussin 		if (nc > 0) {
1358*3bbe3f67SBaptiste Daroussin 			buf[nc] = '\0';
1359*3bbe3f67SBaptiste Daroussin 			buf[strcspn(buf, "\n")] = '\0';
1360*3bbe3f67SBaptiste Daroussin 			if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
1361*3bbe3f67SBaptiste Daroussin 				if (begins_with(buf, "private:")) {
1362*3bbe3f67SBaptiste Daroussin 					if (!state)
1363*3bbe3f67SBaptiste Daroussin 						state = " (private)";
1364*3bbe3f67SBaptiste Daroussin 				} else if (begins_with(buf, "protected:")) {
1365*3bbe3f67SBaptiste Daroussin 					if (!state)
1366*3bbe3f67SBaptiste Daroussin 						state = " (protected)";
1367*3bbe3f67SBaptiste Daroussin 				} else if (begins_with(buf, "public:")) {
1368*3bbe3f67SBaptiste Daroussin 					if (!state)
1369*3bbe3f67SBaptiste Daroussin 						state = " (public)";
1370*3bbe3f67SBaptiste Daroussin 				} else {
1371*3bbe3f67SBaptiste Daroussin 					strlcpy(lastbuf, buf, sizeof lastbuf);
1372*3bbe3f67SBaptiste Daroussin 					if (state)
1373*3bbe3f67SBaptiste Daroussin 						strlcat(lastbuf, state,
1374*3bbe3f67SBaptiste Daroussin 						    sizeof lastbuf);
1375*3bbe3f67SBaptiste Daroussin 					lastmatchline = pos;
1376*3bbe3f67SBaptiste Daroussin 					return lastbuf;
1377*3bbe3f67SBaptiste Daroussin 				}
1378*3bbe3f67SBaptiste Daroussin 			}
1379*3bbe3f67SBaptiste Daroussin 		}
1380*3bbe3f67SBaptiste Daroussin 		pos--;
1381*3bbe3f67SBaptiste Daroussin 	}
1382*3bbe3f67SBaptiste Daroussin 	return lastmatchline > 0 ? lastbuf : NULL;
1383*3bbe3f67SBaptiste Daroussin }
1384*3bbe3f67SBaptiste Daroussin 
1385*3bbe3f67SBaptiste Daroussin /* dump accumulated "context" diff changes */
1386*3bbe3f67SBaptiste Daroussin static void
1387*3bbe3f67SBaptiste Daroussin dump_context_vec(FILE *f1, FILE *f2, int flags)
1388*3bbe3f67SBaptiste Daroussin {
1389*3bbe3f67SBaptiste Daroussin 	struct context_vec *cvp = context_vec_start;
1390*3bbe3f67SBaptiste Daroussin 	int lowa, upb, lowc, upd, do_output;
1391*3bbe3f67SBaptiste Daroussin 	int a, b, c, d;
1392*3bbe3f67SBaptiste Daroussin 	char ch, *f;
1393*3bbe3f67SBaptiste Daroussin 
1394*3bbe3f67SBaptiste Daroussin 	if (context_vec_start > context_vec_ptr)
1395*3bbe3f67SBaptiste Daroussin 		return;
1396*3bbe3f67SBaptiste Daroussin 
1397*3bbe3f67SBaptiste Daroussin 	b = d = 0;		/* gcc */
1398*3bbe3f67SBaptiste Daroussin 	lowa = MAXIMUM(1, cvp->a - diff_context);
1399*3bbe3f67SBaptiste Daroussin 	upb = MINIMUM(len[0], context_vec_ptr->b + diff_context);
1400*3bbe3f67SBaptiste Daroussin 	lowc = MAXIMUM(1, cvp->c - diff_context);
1401*3bbe3f67SBaptiste Daroussin 	upd = MINIMUM(len[1], context_vec_ptr->d + diff_context);
1402*3bbe3f67SBaptiste Daroussin 
1403*3bbe3f67SBaptiste Daroussin 	diff_output("***************");
1404*3bbe3f67SBaptiste Daroussin 	if ((flags & D_PROTOTYPE)) {
1405*3bbe3f67SBaptiste Daroussin 		f = match_function(ixold, lowa-1, f1);
1406*3bbe3f67SBaptiste Daroussin 		if (f != NULL)
1407*3bbe3f67SBaptiste Daroussin 			diff_output(" %s", f);
1408*3bbe3f67SBaptiste Daroussin 	}
1409*3bbe3f67SBaptiste Daroussin 	diff_output("\n*** ");
1410*3bbe3f67SBaptiste Daroussin 	range(lowa, upb, ",");
1411*3bbe3f67SBaptiste Daroussin 	diff_output(" ****\n");
1412*3bbe3f67SBaptiste Daroussin 
1413*3bbe3f67SBaptiste Daroussin 	/*
1414*3bbe3f67SBaptiste Daroussin 	 * Output changes to the "old" file.  The first loop suppresses
1415*3bbe3f67SBaptiste Daroussin 	 * output if there were no changes to the "old" file (we'll see
1416*3bbe3f67SBaptiste Daroussin 	 * the "old" lines as context in the "new" list).
1417*3bbe3f67SBaptiste Daroussin 	 */
1418*3bbe3f67SBaptiste Daroussin 	do_output = 0;
1419*3bbe3f67SBaptiste Daroussin 	for (; cvp <= context_vec_ptr; cvp++)
1420*3bbe3f67SBaptiste Daroussin 		if (cvp->a <= cvp->b) {
1421*3bbe3f67SBaptiste Daroussin 			cvp = context_vec_start;
1422*3bbe3f67SBaptiste Daroussin 			do_output++;
1423*3bbe3f67SBaptiste Daroussin 			break;
1424*3bbe3f67SBaptiste Daroussin 		}
1425*3bbe3f67SBaptiste Daroussin 	if (do_output) {
1426*3bbe3f67SBaptiste Daroussin 		while (cvp <= context_vec_ptr) {
1427*3bbe3f67SBaptiste Daroussin 			a = cvp->a;
1428*3bbe3f67SBaptiste Daroussin 			b = cvp->b;
1429*3bbe3f67SBaptiste Daroussin 			c = cvp->c;
1430*3bbe3f67SBaptiste Daroussin 			d = cvp->d;
1431*3bbe3f67SBaptiste Daroussin 
1432*3bbe3f67SBaptiste Daroussin 			if (a <= b && c <= d)
1433*3bbe3f67SBaptiste Daroussin 				ch = 'c';
1434*3bbe3f67SBaptiste Daroussin 			else
1435*3bbe3f67SBaptiste Daroussin 				ch = (a <= b) ? 'd' : 'a';
1436*3bbe3f67SBaptiste Daroussin 
1437*3bbe3f67SBaptiste Daroussin 			if (ch == 'a')
1438*3bbe3f67SBaptiste Daroussin 				fetch(ixold, lowa, b, f1, ' ', 0, flags);
1439*3bbe3f67SBaptiste Daroussin 			else {
1440*3bbe3f67SBaptiste Daroussin 				fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
1441*3bbe3f67SBaptiste Daroussin 				fetch(ixold, a, b, f1,
1442*3bbe3f67SBaptiste Daroussin 				    ch == 'c' ? '!' : '-', 0, flags);
1443*3bbe3f67SBaptiste Daroussin 			}
1444*3bbe3f67SBaptiste Daroussin 			lowa = b + 1;
1445*3bbe3f67SBaptiste Daroussin 			cvp++;
1446*3bbe3f67SBaptiste Daroussin 		}
1447*3bbe3f67SBaptiste Daroussin 		fetch(ixold, b + 1, upb, f1, ' ', 0, flags);
1448*3bbe3f67SBaptiste Daroussin 	}
1449*3bbe3f67SBaptiste Daroussin 	/* output changes to the "new" file */
1450*3bbe3f67SBaptiste Daroussin 	diff_output("--- ");
1451*3bbe3f67SBaptiste Daroussin 	range(lowc, upd, ",");
1452*3bbe3f67SBaptiste Daroussin 	diff_output(" ----\n");
1453*3bbe3f67SBaptiste Daroussin 
1454*3bbe3f67SBaptiste Daroussin 	do_output = 0;
1455*3bbe3f67SBaptiste Daroussin 	for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
1456*3bbe3f67SBaptiste Daroussin 		if (cvp->c <= cvp->d) {
1457*3bbe3f67SBaptiste Daroussin 			cvp = context_vec_start;
1458*3bbe3f67SBaptiste Daroussin 			do_output++;
1459*3bbe3f67SBaptiste Daroussin 			break;
1460*3bbe3f67SBaptiste Daroussin 		}
1461*3bbe3f67SBaptiste Daroussin 	if (do_output) {
1462*3bbe3f67SBaptiste Daroussin 		while (cvp <= context_vec_ptr) {
1463*3bbe3f67SBaptiste Daroussin 			a = cvp->a;
1464*3bbe3f67SBaptiste Daroussin 			b = cvp->b;
1465*3bbe3f67SBaptiste Daroussin 			c = cvp->c;
1466*3bbe3f67SBaptiste Daroussin 			d = cvp->d;
1467*3bbe3f67SBaptiste Daroussin 
1468*3bbe3f67SBaptiste Daroussin 			if (a <= b && c <= d)
1469*3bbe3f67SBaptiste Daroussin 				ch = 'c';
1470*3bbe3f67SBaptiste Daroussin 			else
1471*3bbe3f67SBaptiste Daroussin 				ch = (a <= b) ? 'd' : 'a';
1472*3bbe3f67SBaptiste Daroussin 
1473*3bbe3f67SBaptiste Daroussin 			if (ch == 'd')
1474*3bbe3f67SBaptiste Daroussin 				fetch(ixnew, lowc, d, f2, ' ', 0, flags);
1475*3bbe3f67SBaptiste Daroussin 			else {
1476*3bbe3f67SBaptiste Daroussin 				fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
1477*3bbe3f67SBaptiste Daroussin 				fetch(ixnew, c, d, f2,
1478*3bbe3f67SBaptiste Daroussin 				    ch == 'c' ? '!' : '+', 0, flags);
1479*3bbe3f67SBaptiste Daroussin 			}
1480*3bbe3f67SBaptiste Daroussin 			lowc = d + 1;
1481*3bbe3f67SBaptiste Daroussin 			cvp++;
1482*3bbe3f67SBaptiste Daroussin 		}
1483*3bbe3f67SBaptiste Daroussin 		fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
1484*3bbe3f67SBaptiste Daroussin 	}
1485*3bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
1486*3bbe3f67SBaptiste Daroussin }
1487*3bbe3f67SBaptiste Daroussin 
1488*3bbe3f67SBaptiste Daroussin /* dump accumulated "unified" diff changes */
1489*3bbe3f67SBaptiste Daroussin static void
1490*3bbe3f67SBaptiste Daroussin dump_unified_vec(FILE *f1, FILE *f2, int flags)
1491*3bbe3f67SBaptiste Daroussin {
1492*3bbe3f67SBaptiste Daroussin 	struct context_vec *cvp = context_vec_start;
1493*3bbe3f67SBaptiste Daroussin 	int lowa, upb, lowc, upd;
1494*3bbe3f67SBaptiste Daroussin 	int a, b, c, d;
1495*3bbe3f67SBaptiste Daroussin 	char ch, *f;
1496*3bbe3f67SBaptiste Daroussin 
1497*3bbe3f67SBaptiste Daroussin 	if (context_vec_start > context_vec_ptr)
1498*3bbe3f67SBaptiste Daroussin 		return;
1499*3bbe3f67SBaptiste Daroussin 
1500*3bbe3f67SBaptiste Daroussin 	b = d = 0;		/* gcc */
1501*3bbe3f67SBaptiste Daroussin 	lowa = MAXIMUM(1, cvp->a - diff_context);
1502*3bbe3f67SBaptiste Daroussin 	upb = MINIMUM(len[0], context_vec_ptr->b + diff_context);
1503*3bbe3f67SBaptiste Daroussin 	lowc = MAXIMUM(1, cvp->c - diff_context);
1504*3bbe3f67SBaptiste Daroussin 	upd = MINIMUM(len[1], context_vec_ptr->d + diff_context);
1505*3bbe3f67SBaptiste Daroussin 
1506*3bbe3f67SBaptiste Daroussin 	diff_output("@@ -");
1507*3bbe3f67SBaptiste Daroussin 	uni_range(lowa, upb);
1508*3bbe3f67SBaptiste Daroussin 	diff_output(" +");
1509*3bbe3f67SBaptiste Daroussin 	uni_range(lowc, upd);
1510*3bbe3f67SBaptiste Daroussin 	diff_output(" @@");
1511*3bbe3f67SBaptiste Daroussin 	if ((flags & D_PROTOTYPE)) {
1512*3bbe3f67SBaptiste Daroussin 		f = match_function(ixold, lowa-1, f1);
1513*3bbe3f67SBaptiste Daroussin 		if (f != NULL)
1514*3bbe3f67SBaptiste Daroussin 			diff_output(" %s", f);
1515*3bbe3f67SBaptiste Daroussin 	}
1516*3bbe3f67SBaptiste Daroussin 	diff_output("\n");
1517*3bbe3f67SBaptiste Daroussin 
1518*3bbe3f67SBaptiste Daroussin 	/*
1519*3bbe3f67SBaptiste Daroussin 	 * Output changes in "unified" diff format--the old and new lines
1520*3bbe3f67SBaptiste Daroussin 	 * are printed together.
1521*3bbe3f67SBaptiste Daroussin 	 */
1522*3bbe3f67SBaptiste Daroussin 	for (; cvp <= context_vec_ptr; cvp++) {
1523*3bbe3f67SBaptiste Daroussin 		a = cvp->a;
1524*3bbe3f67SBaptiste Daroussin 		b = cvp->b;
1525*3bbe3f67SBaptiste Daroussin 		c = cvp->c;
1526*3bbe3f67SBaptiste Daroussin 		d = cvp->d;
1527*3bbe3f67SBaptiste Daroussin 
1528*3bbe3f67SBaptiste Daroussin 		/*
1529*3bbe3f67SBaptiste Daroussin 		 * c: both new and old changes
1530*3bbe3f67SBaptiste Daroussin 		 * d: only changes in the old file
1531*3bbe3f67SBaptiste Daroussin 		 * a: only changes in the new file
1532*3bbe3f67SBaptiste Daroussin 		 */
1533*3bbe3f67SBaptiste Daroussin 		if (a <= b && c <= d)
1534*3bbe3f67SBaptiste Daroussin 			ch = 'c';
1535*3bbe3f67SBaptiste Daroussin 		else
1536*3bbe3f67SBaptiste Daroussin 			ch = (a <= b) ? 'd' : 'a';
1537*3bbe3f67SBaptiste Daroussin 
1538*3bbe3f67SBaptiste Daroussin 		switch (ch) {
1539*3bbe3f67SBaptiste Daroussin 		case 'c':
1540*3bbe3f67SBaptiste Daroussin 			fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
1541*3bbe3f67SBaptiste Daroussin 			fetch(ixold, a, b, f1, '-', 0, flags);
1542*3bbe3f67SBaptiste Daroussin 			fetch(ixnew, c, d, f2, '+', 0, flags);
1543*3bbe3f67SBaptiste Daroussin 			break;
1544*3bbe3f67SBaptiste Daroussin 		case 'd':
1545*3bbe3f67SBaptiste Daroussin 			fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
1546*3bbe3f67SBaptiste Daroussin 			fetch(ixold, a, b, f1, '-', 0, flags);
1547*3bbe3f67SBaptiste Daroussin 			break;
1548*3bbe3f67SBaptiste Daroussin 		case 'a':
1549*3bbe3f67SBaptiste Daroussin 			fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
1550*3bbe3f67SBaptiste Daroussin 			fetch(ixnew, c, d, f2, '+', 0, flags);
1551*3bbe3f67SBaptiste Daroussin 			break;
1552*3bbe3f67SBaptiste Daroussin 		}
1553*3bbe3f67SBaptiste Daroussin 		lowa = b + 1;
1554*3bbe3f67SBaptiste Daroussin 		lowc = d + 1;
1555*3bbe3f67SBaptiste Daroussin 	}
1556*3bbe3f67SBaptiste Daroussin 	fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
1557*3bbe3f67SBaptiste Daroussin 
1558*3bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
1559*3bbe3f67SBaptiste Daroussin }
1560*3bbe3f67SBaptiste Daroussin 
1561*3bbe3f67SBaptiste Daroussin static void
1562*3bbe3f67SBaptiste Daroussin print_header(const char *file1, const char *file2)
1563*3bbe3f67SBaptiste Daroussin {
1564*3bbe3f67SBaptiste Daroussin 	const char *time_format;
1565*3bbe3f67SBaptiste Daroussin 	char buf1[256];
1566*3bbe3f67SBaptiste Daroussin 	char buf2[256];
1567*3bbe3f67SBaptiste Daroussin 	char end1[10];
1568*3bbe3f67SBaptiste Daroussin 	char end2[10];
1569*3bbe3f67SBaptiste Daroussin 	struct tm *tm_ptr1, *tm_ptr2;
1570*3bbe3f67SBaptiste Daroussin 	int nsec1 = TIMESPEC_NS (stb1.st_mtime);
1571*3bbe3f67SBaptiste Daroussin 	int nsec2 = TIMESPEC_NS (stb2.st_mtime);
1572*3bbe3f67SBaptiste Daroussin 
1573*3bbe3f67SBaptiste Daroussin #ifdef ST_MTIM_NSEC
1574*3bbe3f67SBaptiste Daroussin 		time_format = "%Y-%m-%d %H:%M:%S.%N";
1575*3bbe3f67SBaptiste Daroussin #else
1576*3bbe3f67SBaptiste Daroussin 		time_format = "%Y-%m-%d %H:%M:%S";
1577*3bbe3f67SBaptiste Daroussin #endif
1578*3bbe3f67SBaptiste Daroussin 
1579*3bbe3f67SBaptiste Daroussin 	if (cflag)
1580*3bbe3f67SBaptiste Daroussin 		time_format = "%c";
1581*3bbe3f67SBaptiste Daroussin 	tm_ptr1 = localtime(&stb1.st_mtime);
1582*3bbe3f67SBaptiste Daroussin 	tm_ptr2 = localtime(&stb2.st_mtime);
1583*3bbe3f67SBaptiste Daroussin 	strftime(buf1, 256, time_format, tm_ptr1);
1584*3bbe3f67SBaptiste Daroussin 	strftime(buf2, 256, time_format, tm_ptr2);
1585*3bbe3f67SBaptiste Daroussin 	if (!cflag) {
1586*3bbe3f67SBaptiste Daroussin 		strftime(end1, 10, "%z", tm_ptr1);
1587*3bbe3f67SBaptiste Daroussin 		strftime(end2, 10, "%z", tm_ptr2);
1588*3bbe3f67SBaptiste Daroussin 		sprintf(buf1, "%s.%.9d %s", buf1, nsec1, end1);
1589*3bbe3f67SBaptiste Daroussin 		sprintf(buf2, "%s.%.9d %s", buf2, nsec2, end2);
1590*3bbe3f67SBaptiste Daroussin 	}
1591*3bbe3f67SBaptiste Daroussin 	if (label[0] != NULL)
1592*3bbe3f67SBaptiste Daroussin 		diff_output("%s %s\n", diff_format == D_CONTEXT ? "***" : "---",
1593*3bbe3f67SBaptiste Daroussin 		    label[0]);
1594*3bbe3f67SBaptiste Daroussin 	else
1595*3bbe3f67SBaptiste Daroussin 		diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "***" : "---",
1596*3bbe3f67SBaptiste Daroussin 		    file1, buf1);
1597*3bbe3f67SBaptiste Daroussin 	if (label[1] != NULL)
1598*3bbe3f67SBaptiste Daroussin 		diff_output("%s %s\n", diff_format == D_CONTEXT ? "---" : "+++",
1599*3bbe3f67SBaptiste Daroussin 		    label[1]);
1600*3bbe3f67SBaptiste Daroussin 	else
1601*3bbe3f67SBaptiste Daroussin 		diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "---" : "+++",
1602*3bbe3f67SBaptiste Daroussin 		    file2, buf2);
1603*3bbe3f67SBaptiste Daroussin }
1604