xref: /freebsd/usr.bin/diff/diffreg.c (revision df57947f083046d50552e99b91074927d2458708)
13bbe3f67SBaptiste Daroussin /*	$OpenBSD: diffreg.c,v 1.91 2016/03/01 20:57:35 natano Exp $	*/
23bbe3f67SBaptiste Daroussin 
3*df57947fSPedro F. Giffuni /*-
4*df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
5*df57947fSPedro F. Giffuni  *
63bbe3f67SBaptiste Daroussin  * Copyright (C) Caldera International Inc.  2001-2002.
73bbe3f67SBaptiste Daroussin  * All rights reserved.
83bbe3f67SBaptiste Daroussin  *
93bbe3f67SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
103bbe3f67SBaptiste Daroussin  * modification, are permitted provided that the following conditions
113bbe3f67SBaptiste Daroussin  * are met:
123bbe3f67SBaptiste Daroussin  * 1. Redistributions of source code and documentation must retain the above
133bbe3f67SBaptiste Daroussin  *    copyright notice, this list of conditions and the following disclaimer.
143bbe3f67SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
153bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
163bbe3f67SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
173bbe3f67SBaptiste Daroussin  * 3. All advertising materials mentioning features or use of this software
183bbe3f67SBaptiste Daroussin  *    must display the following acknowledgement:
193bbe3f67SBaptiste Daroussin  *	This product includes software developed or owned by Caldera
203bbe3f67SBaptiste Daroussin  *	International, Inc.
213bbe3f67SBaptiste Daroussin  * 4. Neither the name of Caldera International, Inc. nor the names of other
223bbe3f67SBaptiste Daroussin  *    contributors may be used to endorse or promote products derived from
233bbe3f67SBaptiste Daroussin  *    this software without specific prior written permission.
243bbe3f67SBaptiste Daroussin  *
253bbe3f67SBaptiste Daroussin  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
263bbe3f67SBaptiste Daroussin  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
273bbe3f67SBaptiste Daroussin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
283bbe3f67SBaptiste Daroussin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
293bbe3f67SBaptiste Daroussin  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
303bbe3f67SBaptiste Daroussin  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
313bbe3f67SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
323bbe3f67SBaptiste Daroussin  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
333bbe3f67SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
343bbe3f67SBaptiste Daroussin  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
353bbe3f67SBaptiste Daroussin  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
363bbe3f67SBaptiste Daroussin  * POSSIBILITY OF SUCH DAMAGE.
373bbe3f67SBaptiste Daroussin  */
383bbe3f67SBaptiste Daroussin /*-
393bbe3f67SBaptiste Daroussin  * Copyright (c) 1991, 1993
403bbe3f67SBaptiste Daroussin  *	The Regents of the University of California.  All rights reserved.
413bbe3f67SBaptiste Daroussin  *
423bbe3f67SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
433bbe3f67SBaptiste Daroussin  * modification, are permitted provided that the following conditions
443bbe3f67SBaptiste Daroussin  * are met:
453bbe3f67SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
463bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
473bbe3f67SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
483bbe3f67SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
493bbe3f67SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
503bbe3f67SBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
513bbe3f67SBaptiste Daroussin  *    may be used to endorse or promote products derived from this software
523bbe3f67SBaptiste Daroussin  *    without specific prior written permission.
533bbe3f67SBaptiste Daroussin  *
543bbe3f67SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
553bbe3f67SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
563bbe3f67SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
573bbe3f67SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
583bbe3f67SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
593bbe3f67SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
603bbe3f67SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
613bbe3f67SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
623bbe3f67SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
633bbe3f67SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
643bbe3f67SBaptiste Daroussin  * SUCH DAMAGE.
653bbe3f67SBaptiste Daroussin  *
663bbe3f67SBaptiste Daroussin  *	@(#)diffreg.c   8.1 (Berkeley) 6/6/93
673bbe3f67SBaptiste Daroussin  */
683bbe3f67SBaptiste Daroussin 
693bbe3f67SBaptiste Daroussin #include <sys/cdefs.h>
703bbe3f67SBaptiste Daroussin __FBSDID("$FreeBSD$");
713bbe3f67SBaptiste Daroussin 
723bbe3f67SBaptiste Daroussin #include <sys/capsicum.h>
733bbe3f67SBaptiste Daroussin #include <sys/procdesc.h>
743bbe3f67SBaptiste Daroussin #include <sys/stat.h>
753bbe3f67SBaptiste Daroussin #include <sys/types.h>
763bbe3f67SBaptiste Daroussin #include <sys/event.h>
773bbe3f67SBaptiste Daroussin #include <sys/wait.h>
783bbe3f67SBaptiste Daroussin 
793bbe3f67SBaptiste Daroussin #include <capsicum_helpers.h>
803bbe3f67SBaptiste Daroussin #include <ctype.h>
813bbe3f67SBaptiste Daroussin #include <err.h>
823bbe3f67SBaptiste Daroussin #include <errno.h>
833bbe3f67SBaptiste Daroussin #include <fcntl.h>
843bbe3f67SBaptiste Daroussin #include <paths.h>
857752043cSBaptiste Daroussin #include <regex.h>
863bbe3f67SBaptiste Daroussin #include <stddef.h>
873bbe3f67SBaptiste Daroussin #include <stdint.h>
883bbe3f67SBaptiste Daroussin #include <stdio.h>
893bbe3f67SBaptiste Daroussin #include <stdlib.h>
903bbe3f67SBaptiste Daroussin #include <string.h>
913bbe3f67SBaptiste Daroussin #include <unistd.h>
923bbe3f67SBaptiste Daroussin #include <limits.h>
933bbe3f67SBaptiste Daroussin #include <signal.h>
943bbe3f67SBaptiste Daroussin 
953bbe3f67SBaptiste Daroussin #include "diff.h"
963bbe3f67SBaptiste Daroussin #include "xmalloc.h"
973bbe3f67SBaptiste Daroussin 
983bbe3f67SBaptiste Daroussin #define _PATH_PR "/usr/bin/pr"
993bbe3f67SBaptiste Daroussin 
1003bbe3f67SBaptiste Daroussin /*
1013bbe3f67SBaptiste Daroussin  * diff - compare two files.
1023bbe3f67SBaptiste Daroussin  */
1033bbe3f67SBaptiste Daroussin 
1043bbe3f67SBaptiste Daroussin /*
1053bbe3f67SBaptiste Daroussin  *	Uses an algorithm due to Harold Stone, which finds
1063bbe3f67SBaptiste Daroussin  *	a pair of longest identical subsequences in the two
1073bbe3f67SBaptiste Daroussin  *	files.
1083bbe3f67SBaptiste Daroussin  *
1093bbe3f67SBaptiste Daroussin  *	The major goal is to generate the match vector J.
1103bbe3f67SBaptiste Daroussin  *	J[i] is the index of the line in file1 corresponding
1113bbe3f67SBaptiste Daroussin  *	to line i file0. J[i] = 0 if there is no
1123bbe3f67SBaptiste Daroussin  *	such line in file1.
1133bbe3f67SBaptiste Daroussin  *
1143bbe3f67SBaptiste Daroussin  *	Lines are hashed so as to work in core. All potential
1153bbe3f67SBaptiste Daroussin  *	matches are located by sorting the lines of each file
1163bbe3f67SBaptiste Daroussin  *	on the hash (called ``value''). In particular, this
1173bbe3f67SBaptiste Daroussin  *	collects the equivalence classes in file1 together.
1183bbe3f67SBaptiste Daroussin  *	Subroutine equiv replaces the value of each line in
1193bbe3f67SBaptiste Daroussin  *	file0 by the index of the first element of its
1203bbe3f67SBaptiste Daroussin  *	matching equivalence in (the reordered) file1.
1213bbe3f67SBaptiste Daroussin  *	To save space equiv squeezes file1 into a single
1223bbe3f67SBaptiste Daroussin  *	array member in which the equivalence classes
1233bbe3f67SBaptiste Daroussin  *	are simply concatenated, except that their first
1243bbe3f67SBaptiste Daroussin  *	members are flagged by changing sign.
1253bbe3f67SBaptiste Daroussin  *
1263bbe3f67SBaptiste Daroussin  *	Next the indices that point into member are unsorted into
1273bbe3f67SBaptiste Daroussin  *	array class according to the original order of file0.
1283bbe3f67SBaptiste Daroussin  *
1293bbe3f67SBaptiste Daroussin  *	The cleverness lies in routine stone. This marches
1303bbe3f67SBaptiste Daroussin  *	through the lines of file0, developing a vector klist
1313bbe3f67SBaptiste Daroussin  *	of "k-candidates". At step i a k-candidate is a matched
1323bbe3f67SBaptiste Daroussin  *	pair of lines x,y (x in file0 y in file1) such that
1333bbe3f67SBaptiste Daroussin  *	there is a common subsequence of length k
1343bbe3f67SBaptiste Daroussin  *	between the first i lines of file0 and the first y
1353bbe3f67SBaptiste Daroussin  *	lines of file1, but there is no such subsequence for
1363bbe3f67SBaptiste Daroussin  *	any smaller y. x is the earliest possible mate to y
1373bbe3f67SBaptiste Daroussin  *	that occurs in such a subsequence.
1383bbe3f67SBaptiste Daroussin  *
1393bbe3f67SBaptiste Daroussin  *	Whenever any of the members of the equivalence class of
1403bbe3f67SBaptiste Daroussin  *	lines in file1 matable to a line in file0 has serial number
1413bbe3f67SBaptiste Daroussin  *	less than the y of some k-candidate, that k-candidate
1423bbe3f67SBaptiste Daroussin  *	with the smallest such y is replaced. The new
1433bbe3f67SBaptiste Daroussin  *	k-candidate is chained (via pred) to the current
1443bbe3f67SBaptiste Daroussin  *	k-1 candidate so that the actual subsequence can
1453bbe3f67SBaptiste Daroussin  *	be recovered. When a member has serial number greater
1463bbe3f67SBaptiste Daroussin  *	that the y of all k-candidates, the klist is extended.
1473bbe3f67SBaptiste Daroussin  *	At the end, the longest subsequence is pulled out
1483bbe3f67SBaptiste Daroussin  *	and placed in the array J by unravel
1493bbe3f67SBaptiste Daroussin  *
1503bbe3f67SBaptiste Daroussin  *	With J in hand, the matches there recorded are
1513bbe3f67SBaptiste Daroussin  *	check'ed against reality to assure that no spurious
1523bbe3f67SBaptiste Daroussin  *	matches have crept in due to hashing. If they have,
1533bbe3f67SBaptiste Daroussin  *	they are broken, and "jackpot" is recorded--a harmless
1543bbe3f67SBaptiste Daroussin  *	matter except that a true match for a spuriously
1553bbe3f67SBaptiste Daroussin  *	mated line may now be unnecessarily reported as a change.
1563bbe3f67SBaptiste Daroussin  *
1573bbe3f67SBaptiste Daroussin  *	Much of the complexity of the program comes simply
1583bbe3f67SBaptiste Daroussin  *	from trying to minimize core utilization and
1593bbe3f67SBaptiste Daroussin  *	maximize the range of doable problems by dynamically
1603bbe3f67SBaptiste Daroussin  *	allocating what is needed and reusing what is not.
1613bbe3f67SBaptiste Daroussin  *	The core requirements for problems larger than somewhat
1623bbe3f67SBaptiste Daroussin  *	are (in words) 2*length(file0) + length(file1) +
1633bbe3f67SBaptiste Daroussin  *	3*(number of k-candidates installed),  typically about
1643bbe3f67SBaptiste Daroussin  *	6n words for files of length n.
1653bbe3f67SBaptiste Daroussin  */
1663bbe3f67SBaptiste Daroussin 
1673bbe3f67SBaptiste Daroussin struct cand {
1683bbe3f67SBaptiste Daroussin 	int	x;
1693bbe3f67SBaptiste Daroussin 	int	y;
1703bbe3f67SBaptiste Daroussin 	int	pred;
1713bbe3f67SBaptiste Daroussin };
1723bbe3f67SBaptiste Daroussin 
1733bbe3f67SBaptiste Daroussin static struct line {
1743bbe3f67SBaptiste Daroussin 	int	serial;
1753bbe3f67SBaptiste Daroussin 	int	value;
1763bbe3f67SBaptiste Daroussin } *file[2];
1773bbe3f67SBaptiste Daroussin 
1783bbe3f67SBaptiste Daroussin /*
1793bbe3f67SBaptiste Daroussin  * The following struct is used to record change information when
1803bbe3f67SBaptiste Daroussin  * doing a "context" or "unified" diff.  (see routine "change" to
1813bbe3f67SBaptiste Daroussin  * understand the highly mnemonic field names)
1823bbe3f67SBaptiste Daroussin  */
1833bbe3f67SBaptiste Daroussin struct context_vec {
1843bbe3f67SBaptiste Daroussin 	int	a;		/* start line in old file */
1853bbe3f67SBaptiste Daroussin 	int	b;		/* end line in old file */
1863bbe3f67SBaptiste Daroussin 	int	c;		/* start line in new file */
1873bbe3f67SBaptiste Daroussin 	int	d;		/* end line in new file */
1883bbe3f67SBaptiste Daroussin };
1893bbe3f67SBaptiste Daroussin 
1903bbe3f67SBaptiste Daroussin #define	diff_output	printf
191ff807815SBaptiste Daroussin static FILE	*opentemp(const char *);
1923bbe3f67SBaptiste Daroussin static void	 output(char *, FILE *, char *, FILE *, int);
1933bbe3f67SBaptiste Daroussin static void	 check(FILE *, FILE *, int);
1943bbe3f67SBaptiste Daroussin static void	 range(int, int, const char *);
1953bbe3f67SBaptiste Daroussin static void	 uni_range(int, int);
1963bbe3f67SBaptiste Daroussin static void	 dump_context_vec(FILE *, FILE *, int);
1973bbe3f67SBaptiste Daroussin static void	 dump_unified_vec(FILE *, FILE *, int);
198d5b187aeSBaptiste Daroussin static void	 prepare(int, FILE *, size_t, int);
1993bbe3f67SBaptiste Daroussin static void	 prune(void);
2003bbe3f67SBaptiste Daroussin static void	 equiv(struct line *, int, struct line *, int, int *);
2013bbe3f67SBaptiste Daroussin static void	 unravel(int);
2023bbe3f67SBaptiste Daroussin static void	 unsort(struct line *, int, int *);
2033bbe3f67SBaptiste Daroussin static void	 change(char *, FILE *, char *, FILE *, int, int, int, int, int *);
2043bbe3f67SBaptiste Daroussin static void	 sort(struct line *, int);
2053bbe3f67SBaptiste Daroussin static void	 print_header(const char *, const char *);
2063bbe3f67SBaptiste Daroussin static int	 ignoreline(char *);
2073bbe3f67SBaptiste Daroussin static int	 asciifile(FILE *);
2083bbe3f67SBaptiste Daroussin static int	 fetch(long *, int, int, FILE *, int, int, int);
2093bbe3f67SBaptiste Daroussin static int	 newcand(int, int, int);
2103bbe3f67SBaptiste Daroussin static int	 search(int *, int, int);
2113bbe3f67SBaptiste Daroussin static int	 skipline(FILE *);
2123bbe3f67SBaptiste Daroussin static int	 isqrt(int);
2133bbe3f67SBaptiste Daroussin static int	 stone(int *, int, int *, int *, int);
2143bbe3f67SBaptiste Daroussin static int	 readhash(FILE *, int);
2153bbe3f67SBaptiste Daroussin static int	 files_differ(FILE *, FILE *, int);
2163bbe3f67SBaptiste Daroussin static char	*match_function(const long *, int, FILE *);
2173bbe3f67SBaptiste Daroussin static char	*preadline(int, size_t, off_t);
2183bbe3f67SBaptiste Daroussin 
2193bbe3f67SBaptiste Daroussin static int  *J;			/* will be overlaid on class */
2203bbe3f67SBaptiste Daroussin static int  *class;		/* will be overlaid on file[0] */
2213bbe3f67SBaptiste Daroussin static int  *klist;		/* will be overlaid on file[0] after class */
2223bbe3f67SBaptiste Daroussin static int  *member;		/* will be overlaid on file[1] */
2233bbe3f67SBaptiste Daroussin static int   clen;
2243bbe3f67SBaptiste Daroussin static int   inifdef;		/* whether or not we are in a #ifdef block */
2253bbe3f67SBaptiste Daroussin static int   len[2];
2263bbe3f67SBaptiste Daroussin static int   pref, suff;	/* length of prefix and suffix */
2273bbe3f67SBaptiste Daroussin static int   slen[2];
2283bbe3f67SBaptiste Daroussin static int   anychange;
2293bbe3f67SBaptiste Daroussin static long *ixnew;		/* will be overlaid on file[1] */
2303bbe3f67SBaptiste Daroussin static long *ixold;		/* will be overlaid on klist */
2313bbe3f67SBaptiste Daroussin static struct cand *clist;	/* merely a free storage pot for candidates */
2323bbe3f67SBaptiste Daroussin static int   clistlen;		/* the length of clist */
2333bbe3f67SBaptiste Daroussin static struct line *sfile[2];	/* shortened by pruning common prefix/suffix */
2343bbe3f67SBaptiste Daroussin static u_char *chrtran;		/* translation table for case-folding */
2353bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_start;
2363bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_end;
2373bbe3f67SBaptiste Daroussin static struct context_vec *context_vec_ptr;
2383bbe3f67SBaptiste Daroussin 
2393bbe3f67SBaptiste Daroussin #define FUNCTION_CONTEXT_SIZE	55
2403bbe3f67SBaptiste Daroussin static char lastbuf[FUNCTION_CONTEXT_SIZE];
2413bbe3f67SBaptiste Daroussin static int lastline;
2423bbe3f67SBaptiste Daroussin static int lastmatchline;
2433bbe3f67SBaptiste Daroussin 
2443bbe3f67SBaptiste Daroussin 
2453bbe3f67SBaptiste Daroussin /*
2463bbe3f67SBaptiste Daroussin  * chrtran points to one of 2 translation tables: cup2low if folding upper to
2473bbe3f67SBaptiste Daroussin  * lower case clow2low if not folding case
2483bbe3f67SBaptiste Daroussin  */
2493bbe3f67SBaptiste Daroussin static u_char clow2low[256] = {
2503bbe3f67SBaptiste Daroussin 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
2513bbe3f67SBaptiste Daroussin 	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
2523bbe3f67SBaptiste Daroussin 	0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
2533bbe3f67SBaptiste Daroussin 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
2543bbe3f67SBaptiste Daroussin 	0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
2553bbe3f67SBaptiste Daroussin 	0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
2563bbe3f67SBaptiste Daroussin 	0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
2573bbe3f67SBaptiste Daroussin 	0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
2583bbe3f67SBaptiste Daroussin 	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
2593bbe3f67SBaptiste Daroussin 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
2603bbe3f67SBaptiste Daroussin 	0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
2613bbe3f67SBaptiste Daroussin 	0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
2623bbe3f67SBaptiste Daroussin 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
2633bbe3f67SBaptiste Daroussin 	0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
2643bbe3f67SBaptiste Daroussin 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
2653bbe3f67SBaptiste Daroussin 	0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
2663bbe3f67SBaptiste Daroussin 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
2673bbe3f67SBaptiste Daroussin 	0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2683bbe3f67SBaptiste Daroussin 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
2693bbe3f67SBaptiste Daroussin 	0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
2703bbe3f67SBaptiste Daroussin 	0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
2713bbe3f67SBaptiste Daroussin 	0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
2723bbe3f67SBaptiste Daroussin 	0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
2733bbe3f67SBaptiste Daroussin 	0xfd, 0xfe, 0xff
2743bbe3f67SBaptiste Daroussin };
2753bbe3f67SBaptiste Daroussin 
2763bbe3f67SBaptiste Daroussin static u_char cup2low[256] = {
2773bbe3f67SBaptiste Daroussin 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
2783bbe3f67SBaptiste Daroussin 	0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
2793bbe3f67SBaptiste Daroussin 	0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
2803bbe3f67SBaptiste Daroussin 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
2813bbe3f67SBaptiste Daroussin 	0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
2823bbe3f67SBaptiste Daroussin 	0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
2833bbe3f67SBaptiste Daroussin 	0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
2843bbe3f67SBaptiste Daroussin 	0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
2853bbe3f67SBaptiste Daroussin 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
2863bbe3f67SBaptiste Daroussin 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
2873bbe3f67SBaptiste Daroussin 	0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
2883bbe3f67SBaptiste Daroussin 	0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
2893bbe3f67SBaptiste Daroussin 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
2903bbe3f67SBaptiste Daroussin 	0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
2913bbe3f67SBaptiste Daroussin 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
2923bbe3f67SBaptiste Daroussin 	0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
2933bbe3f67SBaptiste Daroussin 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
2943bbe3f67SBaptiste Daroussin 	0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2953bbe3f67SBaptiste Daroussin 	0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
2963bbe3f67SBaptiste Daroussin 	0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
2973bbe3f67SBaptiste Daroussin 	0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
2983bbe3f67SBaptiste Daroussin 	0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
2993bbe3f67SBaptiste Daroussin 	0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
3003bbe3f67SBaptiste Daroussin 	0xfd, 0xfe, 0xff
3013bbe3f67SBaptiste Daroussin };
3023bbe3f67SBaptiste Daroussin 
3033bbe3f67SBaptiste Daroussin int
3043bbe3f67SBaptiste Daroussin diffreg(char *file1, char *file2, int flags, int capsicum)
3053bbe3f67SBaptiste Daroussin {
3063bbe3f67SBaptiste Daroussin 	FILE *f1, *f2;
3073bbe3f67SBaptiste Daroussin 	int i, rval;
3083bbe3f67SBaptiste Daroussin 	int	ostdout = -1;
3093bbe3f67SBaptiste Daroussin 	int pr_pd, kq;
3103bbe3f67SBaptiste Daroussin 	struct kevent *e;
3113bbe3f67SBaptiste Daroussin 	cap_rights_t rights_ro;
3123bbe3f67SBaptiste Daroussin 
313d5b187aeSBaptiste Daroussin 	e = NULL;
314d5b187aeSBaptiste Daroussin 	kq = -1;
3153bbe3f67SBaptiste Daroussin 	f1 = f2 = NULL;
3163bbe3f67SBaptiste Daroussin 	rval = D_SAME;
3173bbe3f67SBaptiste Daroussin 	anychange = 0;
3183bbe3f67SBaptiste Daroussin 	lastline = 0;
3193bbe3f67SBaptiste Daroussin 	lastmatchline = 0;
3203bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
3213bbe3f67SBaptiste Daroussin 	if (flags & D_IGNORECASE)
3223bbe3f67SBaptiste Daroussin 		chrtran = cup2low;
3233bbe3f67SBaptiste Daroussin 	else
3243bbe3f67SBaptiste Daroussin 		chrtran = clow2low;
3253bbe3f67SBaptiste Daroussin 	if (S_ISDIR(stb1.st_mode) != S_ISDIR(stb2.st_mode))
3263bbe3f67SBaptiste Daroussin 		return (S_ISDIR(stb1.st_mode) ? D_MISMATCH1 : D_MISMATCH2);
3273bbe3f67SBaptiste Daroussin 	if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0)
3283bbe3f67SBaptiste Daroussin 		goto closem;
3293bbe3f67SBaptiste Daroussin 
3303bbe3f67SBaptiste Daroussin 	if (flags & D_EMPTY1)
3313bbe3f67SBaptiste Daroussin 		f1 = fopen(_PATH_DEVNULL, "r");
3323bbe3f67SBaptiste Daroussin 	else {
333ff807815SBaptiste Daroussin 		if (!S_ISREG(stb1.st_mode)) {
334ff807815SBaptiste Daroussin 			if ((f1 = opentemp(file1)) == NULL ||
335ff807815SBaptiste Daroussin 			    fstat(fileno(f1), &stb1) < 0) {
336ff807815SBaptiste Daroussin 				warn("%s", file1);
337ff807815SBaptiste Daroussin 				status |= 2;
338ff807815SBaptiste Daroussin 				goto closem;
339ff807815SBaptiste Daroussin 			}
340ff807815SBaptiste Daroussin 		} else if (strcmp(file1, "-") == 0)
3413bbe3f67SBaptiste Daroussin 			f1 = stdin;
3423bbe3f67SBaptiste Daroussin 		else
3433bbe3f67SBaptiste Daroussin 			f1 = fopen(file1, "r");
3443bbe3f67SBaptiste Daroussin 	}
3453bbe3f67SBaptiste Daroussin 	if (f1 == NULL) {
3463bbe3f67SBaptiste Daroussin 		warn("%s", file1);
3473bbe3f67SBaptiste Daroussin 		status |= 2;
3483bbe3f67SBaptiste Daroussin 		goto closem;
3493bbe3f67SBaptiste Daroussin 	}
3503bbe3f67SBaptiste Daroussin 
3513bbe3f67SBaptiste Daroussin 	if (flags & D_EMPTY2)
3523bbe3f67SBaptiste Daroussin 		f2 = fopen(_PATH_DEVNULL, "r");
3533bbe3f67SBaptiste Daroussin 	else {
354ff807815SBaptiste Daroussin 		if (!S_ISREG(stb2.st_mode)) {
355ff807815SBaptiste Daroussin 			if ((f2 = opentemp(file2)) == NULL ||
356ff807815SBaptiste Daroussin 			    fstat(fileno(f2), &stb2) < 0) {
357ff807815SBaptiste Daroussin 				warn("%s", file2);
358ff807815SBaptiste Daroussin 				status |= 2;
359ff807815SBaptiste Daroussin 				goto closem;
360ff807815SBaptiste Daroussin 			}
361ff807815SBaptiste Daroussin 		} else if (strcmp(file2, "-") == 0)
3623bbe3f67SBaptiste Daroussin 			f2 = stdin;
3633bbe3f67SBaptiste Daroussin 		else
3643bbe3f67SBaptiste Daroussin 			f2 = fopen(file2, "r");
3653bbe3f67SBaptiste Daroussin 	}
3663bbe3f67SBaptiste Daroussin 	if (f2 == NULL) {
3673bbe3f67SBaptiste Daroussin 		warn("%s", file2);
3683bbe3f67SBaptiste Daroussin 		status |= 2;
3693bbe3f67SBaptiste Daroussin 		goto closem;
3703bbe3f67SBaptiste Daroussin 	}
3713bbe3f67SBaptiste Daroussin 
3723bbe3f67SBaptiste Daroussin 	if (lflag) {
3733bbe3f67SBaptiste Daroussin 		/* redirect stdout to pr */
3743bbe3f67SBaptiste Daroussin 		int	 pfd[2];
3753bbe3f67SBaptiste Daroussin 		pid_t	pid;
3763bbe3f67SBaptiste Daroussin 		char	*header;
3773bbe3f67SBaptiste Daroussin 
3783bbe3f67SBaptiste Daroussin 		xasprintf(&header, "%s %s %s", diffargs, file1, file2);
3793bbe3f67SBaptiste Daroussin 		signal(SIGPIPE, SIG_IGN);
3803bbe3f67SBaptiste Daroussin 		fflush(stdout);
3813bbe3f67SBaptiste Daroussin 		rewind(stdout);
3823bbe3f67SBaptiste Daroussin 		pipe(pfd);
3833bbe3f67SBaptiste Daroussin 		switch ((pid = pdfork(&pr_pd, PD_CLOEXEC))) {
3843bbe3f67SBaptiste Daroussin 		case -1:
3853bbe3f67SBaptiste Daroussin 			status |= 2;
3863bbe3f67SBaptiste Daroussin 			free(header);
3873bbe3f67SBaptiste Daroussin 			err(2, "No more processes");
3883bbe3f67SBaptiste Daroussin 		case 0:
3893bbe3f67SBaptiste Daroussin 			/* child */
3903bbe3f67SBaptiste Daroussin 			if (pfd[0] != STDIN_FILENO) {
3913bbe3f67SBaptiste Daroussin 				dup2(pfd[0], STDIN_FILENO);
3923bbe3f67SBaptiste Daroussin 				close(pfd[0]);
3933bbe3f67SBaptiste Daroussin 			}
3943bbe3f67SBaptiste Daroussin 			close(pfd[1]);
3953bbe3f67SBaptiste Daroussin 			execl(_PATH_PR, _PATH_PR, "-h", header, (char *)0);
3963bbe3f67SBaptiste Daroussin 			_exit(127);
3973bbe3f67SBaptiste Daroussin 		default:
3983bbe3f67SBaptiste Daroussin 
3993bbe3f67SBaptiste Daroussin 			/* parent */
4003bbe3f67SBaptiste Daroussin 			if (pfd[1] != STDOUT_FILENO) {
4013bbe3f67SBaptiste Daroussin 				ostdout = dup(STDOUT_FILENO);
4023bbe3f67SBaptiste Daroussin 				dup2(pfd[1], STDOUT_FILENO);
4033bbe3f67SBaptiste Daroussin 				close(pfd[1]);
4043bbe3f67SBaptiste Daroussin 			}
4053bbe3f67SBaptiste Daroussin 			close(pfd[0]);
4063bbe3f67SBaptiste Daroussin 			rewind(stdout);
4073bbe3f67SBaptiste Daroussin 			free(header);
4083bbe3f67SBaptiste Daroussin 			kq = kqueue();
4093bbe3f67SBaptiste Daroussin 			if (kq == -1)
4103bbe3f67SBaptiste Daroussin 				err(2, "kqueue");
4113bbe3f67SBaptiste Daroussin 			e = xmalloc(sizeof(struct kevent));
4123bbe3f67SBaptiste Daroussin 			EV_SET(e, pr_pd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0,
4133bbe3f67SBaptiste Daroussin 			    NULL);
4143bbe3f67SBaptiste Daroussin 			if (kevent(kq, e, 1, NULL, 0, NULL) == -1)
4153bbe3f67SBaptiste Daroussin 				err(2, "kevent");
4163bbe3f67SBaptiste Daroussin 		}
4173bbe3f67SBaptiste Daroussin 	}
4183bbe3f67SBaptiste Daroussin 
4193bbe3f67SBaptiste Daroussin 	if (capsicum) {
4203bbe3f67SBaptiste Daroussin 		cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK);
42178f6a0c1SBaptiste Daroussin 		if (cap_rights_limit(fileno(f1), &rights_ro) < 0
42278f6a0c1SBaptiste Daroussin 		    && errno != ENOSYS)
4233bbe3f67SBaptiste Daroussin 			err(2, "unable to limit rights on: %s", file1);
42478f6a0c1SBaptiste Daroussin 		if (cap_rights_limit(fileno(f2), &rights_ro) < 0 &&
42578f6a0c1SBaptiste Daroussin 		    errno != ENOSYS)
4263bbe3f67SBaptiste Daroussin 			err(2, "unable to limit rights on: %s", file2);
4273bbe3f67SBaptiste Daroussin 		if (fileno(f1) == STDIN_FILENO || fileno(f2) == STDIN_FILENO) {
4283bbe3f67SBaptiste Daroussin 			/* stding has already been limited */
4293bbe3f67SBaptiste Daroussin 			if (caph_limit_stderr() == -1)
4303bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stderr");
4313bbe3f67SBaptiste Daroussin 			if (caph_limit_stdout() == -1)
4323bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stdout");
4333bbe3f67SBaptiste Daroussin 		} else if (caph_limit_stdio() == -1)
4343bbe3f67SBaptiste Daroussin 				err(2, "unable to limit stdio");
4353bbe3f67SBaptiste Daroussin 
4363bbe3f67SBaptiste Daroussin 		caph_cache_catpages();
4375bbffb00SBaptiste Daroussin 		caph_cache_tzdata();
4383bbe3f67SBaptiste Daroussin 		if (cap_enter() < 0 && errno != ENOSYS)
4393bbe3f67SBaptiste Daroussin 			err(2, "unable to enter capability mode");
4403bbe3f67SBaptiste Daroussin 	}
4413bbe3f67SBaptiste Daroussin 
4423bbe3f67SBaptiste Daroussin 	switch (files_differ(f1, f2, flags)) {
4433bbe3f67SBaptiste Daroussin 	case 0:
4443bbe3f67SBaptiste Daroussin 		goto closem;
4453bbe3f67SBaptiste Daroussin 	case 1:
4463bbe3f67SBaptiste Daroussin 		break;
4473bbe3f67SBaptiste Daroussin 	default:
4483bbe3f67SBaptiste Daroussin 		/* error */
4493bbe3f67SBaptiste Daroussin 		status |= 2;
4503bbe3f67SBaptiste Daroussin 		goto closem;
4513bbe3f67SBaptiste Daroussin 	}
4523bbe3f67SBaptiste Daroussin 
4533bbe3f67SBaptiste Daroussin 	if ((flags & D_FORCEASCII) == 0 &&
4543bbe3f67SBaptiste Daroussin 	    (!asciifile(f1) || !asciifile(f2))) {
4553bbe3f67SBaptiste Daroussin 		rval = D_BINARY;
4563bbe3f67SBaptiste Daroussin 		status |= 1;
4573bbe3f67SBaptiste Daroussin 		goto closem;
4583bbe3f67SBaptiste Daroussin 	}
4593bbe3f67SBaptiste Daroussin 	prepare(0, f1, stb1.st_size, flags);
4603bbe3f67SBaptiste Daroussin 	prepare(1, f2, stb2.st_size, flags);
4613bbe3f67SBaptiste Daroussin 
4623bbe3f67SBaptiste Daroussin 	prune();
4633bbe3f67SBaptiste Daroussin 	sort(sfile[0], slen[0]);
4643bbe3f67SBaptiste Daroussin 	sort(sfile[1], slen[1]);
4653bbe3f67SBaptiste Daroussin 
4663bbe3f67SBaptiste Daroussin 	member = (int *)file[1];
4673bbe3f67SBaptiste Daroussin 	equiv(sfile[0], slen[0], sfile[1], slen[1], member);
4683bbe3f67SBaptiste Daroussin 	member = xreallocarray(member, slen[1] + 2, sizeof(*member));
4693bbe3f67SBaptiste Daroussin 
4703bbe3f67SBaptiste Daroussin 	class = (int *)file[0];
4713bbe3f67SBaptiste Daroussin 	unsort(sfile[0], slen[0], class);
4723bbe3f67SBaptiste Daroussin 	class = xreallocarray(class, slen[0] + 2, sizeof(*class));
4733bbe3f67SBaptiste Daroussin 
4743bbe3f67SBaptiste Daroussin 	klist = xcalloc(slen[0] + 2, sizeof(*klist));
4753bbe3f67SBaptiste Daroussin 	clen = 0;
4763bbe3f67SBaptiste Daroussin 	clistlen = 100;
4773bbe3f67SBaptiste Daroussin 	clist = xcalloc(clistlen, sizeof(*clist));
4783bbe3f67SBaptiste Daroussin 	i = stone(class, slen[0], member, klist, flags);
4793bbe3f67SBaptiste Daroussin 	free(member);
4803bbe3f67SBaptiste Daroussin 	free(class);
4813bbe3f67SBaptiste Daroussin 
4823bbe3f67SBaptiste Daroussin 	J = xreallocarray(J, len[0] + 2, sizeof(*J));
4833bbe3f67SBaptiste Daroussin 	unravel(klist[i]);
4843bbe3f67SBaptiste Daroussin 	free(clist);
4853bbe3f67SBaptiste Daroussin 	free(klist);
4863bbe3f67SBaptiste Daroussin 
4873bbe3f67SBaptiste Daroussin 	ixold = xreallocarray(ixold, len[0] + 2, sizeof(*ixold));
4883bbe3f67SBaptiste Daroussin 	ixnew = xreallocarray(ixnew, len[1] + 2, sizeof(*ixnew));
4893bbe3f67SBaptiste Daroussin 	check(f1, f2, flags);
4903bbe3f67SBaptiste Daroussin 	output(file1, f1, file2, f2, flags);
491d5b187aeSBaptiste Daroussin 	if (ostdout != -1 && e != NULL) {
4923bbe3f67SBaptiste Daroussin 		/* close the pipe to pr and restore stdout */
4933bbe3f67SBaptiste Daroussin 		int wstatus;
4943bbe3f67SBaptiste Daroussin 
4953bbe3f67SBaptiste Daroussin 		fflush(stdout);
4963bbe3f67SBaptiste Daroussin 		if (ostdout != STDOUT_FILENO) {
4973bbe3f67SBaptiste Daroussin 			close(STDOUT_FILENO);
4983bbe3f67SBaptiste Daroussin 			dup2(ostdout, STDOUT_FILENO);
4993bbe3f67SBaptiste Daroussin 			close(ostdout);
5003bbe3f67SBaptiste Daroussin 		}
5013bbe3f67SBaptiste Daroussin 		if (kevent(kq, NULL, 0, e, 1, NULL) == -1)
5023bbe3f67SBaptiste Daroussin 			err(2, "kevent");
5033bbe3f67SBaptiste Daroussin 		wstatus = e[0].data;
5043bbe3f67SBaptiste Daroussin 		close(kq);
5053bbe3f67SBaptiste Daroussin 		if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0)
5063bbe3f67SBaptiste Daroussin 			errx(2, "pr exited abnormally");
5073bbe3f67SBaptiste Daroussin 		else if (WIFSIGNALED(wstatus))
5083bbe3f67SBaptiste Daroussin 			errx(2, "pr killed by signal %d",
5093bbe3f67SBaptiste Daroussin 			    WTERMSIG(wstatus));
5103bbe3f67SBaptiste Daroussin 	}
5113bbe3f67SBaptiste Daroussin 
5123bbe3f67SBaptiste Daroussin closem:
5133bbe3f67SBaptiste Daroussin 	if (anychange) {
5143bbe3f67SBaptiste Daroussin 		status |= 1;
5153bbe3f67SBaptiste Daroussin 		if (rval == D_SAME)
5163bbe3f67SBaptiste Daroussin 			rval = D_DIFFER;
5173bbe3f67SBaptiste Daroussin 	}
5183bbe3f67SBaptiste Daroussin 	if (f1 != NULL)
5193bbe3f67SBaptiste Daroussin 		fclose(f1);
5203bbe3f67SBaptiste Daroussin 	if (f2 != NULL)
5213bbe3f67SBaptiste Daroussin 		fclose(f2);
5223bbe3f67SBaptiste Daroussin 
5233bbe3f67SBaptiste Daroussin 	return (rval);
5243bbe3f67SBaptiste Daroussin }
5253bbe3f67SBaptiste Daroussin 
5263bbe3f67SBaptiste Daroussin /*
5273bbe3f67SBaptiste Daroussin  * Check to see if the given files differ.
5283bbe3f67SBaptiste Daroussin  * Returns 0 if they are the same, 1 if different, and -1 on error.
5293bbe3f67SBaptiste Daroussin  * XXX - could use code from cmp(1) [faster]
5303bbe3f67SBaptiste Daroussin  */
5313bbe3f67SBaptiste Daroussin static int
5323bbe3f67SBaptiste Daroussin files_differ(FILE *f1, FILE *f2, int flags)
5333bbe3f67SBaptiste Daroussin {
5343bbe3f67SBaptiste Daroussin 	char buf1[BUFSIZ], buf2[BUFSIZ];
5353bbe3f67SBaptiste Daroussin 	size_t i, j;
5363bbe3f67SBaptiste Daroussin 
5373bbe3f67SBaptiste Daroussin 	if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size ||
5383bbe3f67SBaptiste Daroussin 	    (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT))
5393bbe3f67SBaptiste Daroussin 		return (1);
5403bbe3f67SBaptiste Daroussin 	for (;;) {
5413bbe3f67SBaptiste Daroussin 		i = fread(buf1, 1, sizeof(buf1), f1);
5423bbe3f67SBaptiste Daroussin 		j = fread(buf2, 1, sizeof(buf2), f2);
5433bbe3f67SBaptiste Daroussin 		if ((!i && ferror(f1)) || (!j && ferror(f2)))
5443bbe3f67SBaptiste Daroussin 			return (-1);
5453bbe3f67SBaptiste Daroussin 		if (i != j)
5463bbe3f67SBaptiste Daroussin 			return (1);
5473bbe3f67SBaptiste Daroussin 		if (i == 0)
5483bbe3f67SBaptiste Daroussin 			return (0);
5493bbe3f67SBaptiste Daroussin 		if (memcmp(buf1, buf2, i) != 0)
5503bbe3f67SBaptiste Daroussin 			return (1);
5513bbe3f67SBaptiste Daroussin 	}
5523bbe3f67SBaptiste Daroussin }
5533bbe3f67SBaptiste Daroussin 
554ff807815SBaptiste Daroussin static FILE *
555ff807815SBaptiste Daroussin opentemp(const char *f)
556ff807815SBaptiste Daroussin {
557ff807815SBaptiste Daroussin 	char buf[BUFSIZ], tempfile[PATH_MAX];
558ff807815SBaptiste Daroussin 	ssize_t nread;
559ff807815SBaptiste Daroussin 	int ifd, ofd;
560ff807815SBaptiste Daroussin 
561ff807815SBaptiste Daroussin 	if (strcmp(f, "-") == 0)
562ff807815SBaptiste Daroussin 		ifd = STDIN_FILENO;
563ff807815SBaptiste Daroussin 	else if ((ifd = open(f, O_RDONLY, 0644)) < 0)
564ff807815SBaptiste Daroussin 		return (NULL);
565ff807815SBaptiste Daroussin 
566ff807815SBaptiste Daroussin 	(void)strlcpy(tempfile, _PATH_TMP "/diff.XXXXXXXX", sizeof(tempfile));
567ff807815SBaptiste Daroussin 
568ff807815SBaptiste Daroussin 	if ((ofd = mkstemp(tempfile)) < 0) {
569ff807815SBaptiste Daroussin 		close(ifd);
570ff807815SBaptiste Daroussin 		return (NULL);
571ff807815SBaptiste Daroussin 	}
572ff807815SBaptiste Daroussin 	unlink(tempfile);
573ff807815SBaptiste Daroussin 	while ((nread = read(ifd, buf, BUFSIZ)) > 0) {
574ff807815SBaptiste Daroussin 		if (write(ofd, buf, nread) != nread) {
575ff807815SBaptiste Daroussin 			close(ifd);
576ff807815SBaptiste Daroussin 			close(ofd);
577ff807815SBaptiste Daroussin 			return (NULL);
578ff807815SBaptiste Daroussin 		}
579ff807815SBaptiste Daroussin 	}
580ff807815SBaptiste Daroussin 	close(ifd);
581ff807815SBaptiste Daroussin 	lseek(ofd, (off_t)0, SEEK_SET);
582ff807815SBaptiste Daroussin 	return (fdopen(ofd, "r"));
583ff807815SBaptiste Daroussin }
584ff807815SBaptiste Daroussin 
5853bbe3f67SBaptiste Daroussin char *
5863bbe3f67SBaptiste Daroussin splice(char *dir, char *path)
5873bbe3f67SBaptiste Daroussin {
5883bbe3f67SBaptiste Daroussin 	char *tail, *buf;
5893bbe3f67SBaptiste Daroussin 	size_t dirlen;
5903bbe3f67SBaptiste Daroussin 
5913bbe3f67SBaptiste Daroussin 	dirlen = strlen(dir);
5923bbe3f67SBaptiste Daroussin 	while (dirlen != 0 && dir[dirlen - 1] == '/')
5933bbe3f67SBaptiste Daroussin 	    dirlen--;
5943bbe3f67SBaptiste Daroussin 	if ((tail = strrchr(path, '/')) == NULL)
5953bbe3f67SBaptiste Daroussin 		tail = path;
5963bbe3f67SBaptiste Daroussin 	else
5973bbe3f67SBaptiste Daroussin 		tail++;
5983bbe3f67SBaptiste Daroussin 	xasprintf(&buf, "%.*s/%s", (int)dirlen, dir, tail);
5993bbe3f67SBaptiste Daroussin 	return (buf);
6003bbe3f67SBaptiste Daroussin }
6013bbe3f67SBaptiste Daroussin 
6023bbe3f67SBaptiste Daroussin static void
603d5b187aeSBaptiste Daroussin prepare(int i, FILE *fd, size_t filesize, int flags)
6043bbe3f67SBaptiste Daroussin {
6053bbe3f67SBaptiste Daroussin 	struct line *p;
6063bbe3f67SBaptiste Daroussin 	int h;
6073bbe3f67SBaptiste Daroussin 	size_t sz, j;
6083bbe3f67SBaptiste Daroussin 
6093bbe3f67SBaptiste Daroussin 	rewind(fd);
6103bbe3f67SBaptiste Daroussin 
6116b8059c4SBaptiste Daroussin 	sz = MIN(filesize, SIZE_MAX) / 25;
6123bbe3f67SBaptiste Daroussin 	if (sz < 100)
6133bbe3f67SBaptiste Daroussin 		sz = 100;
6143bbe3f67SBaptiste Daroussin 
6153bbe3f67SBaptiste Daroussin 	p = xcalloc(sz + 3, sizeof(*p));
6163bbe3f67SBaptiste Daroussin 	for (j = 0; (h = readhash(fd, flags));) {
6173bbe3f67SBaptiste Daroussin 		if (j == sz) {
6183bbe3f67SBaptiste Daroussin 			sz = sz * 3 / 2;
6193bbe3f67SBaptiste Daroussin 			p = xreallocarray(p, sz + 3, sizeof(*p));
6203bbe3f67SBaptiste Daroussin 		}
6213bbe3f67SBaptiste Daroussin 		p[++j].value = h;
6223bbe3f67SBaptiste Daroussin 	}
6233bbe3f67SBaptiste Daroussin 	len[i] = j;
6243bbe3f67SBaptiste Daroussin 	file[i] = p;
6253bbe3f67SBaptiste Daroussin }
6263bbe3f67SBaptiste Daroussin 
6273bbe3f67SBaptiste Daroussin static void
6283bbe3f67SBaptiste Daroussin prune(void)
6293bbe3f67SBaptiste Daroussin {
6303bbe3f67SBaptiste Daroussin 	int i, j;
6313bbe3f67SBaptiste Daroussin 
6323bbe3f67SBaptiste Daroussin 	for (pref = 0; pref < len[0] && pref < len[1] &&
6333bbe3f67SBaptiste Daroussin 	    file[0][pref + 1].value == file[1][pref + 1].value;
6343bbe3f67SBaptiste Daroussin 	    pref++)
6353bbe3f67SBaptiste Daroussin 		;
6363bbe3f67SBaptiste Daroussin 	for (suff = 0; suff < len[0] - pref && suff < len[1] - pref &&
6373bbe3f67SBaptiste Daroussin 	    file[0][len[0] - suff].value == file[1][len[1] - suff].value;
6383bbe3f67SBaptiste Daroussin 	    suff++)
6393bbe3f67SBaptiste Daroussin 		;
6403bbe3f67SBaptiste Daroussin 	for (j = 0; j < 2; j++) {
6413bbe3f67SBaptiste Daroussin 		sfile[j] = file[j] + pref;
6423bbe3f67SBaptiste Daroussin 		slen[j] = len[j] - pref - suff;
6433bbe3f67SBaptiste Daroussin 		for (i = 0; i <= slen[j]; i++)
6443bbe3f67SBaptiste Daroussin 			sfile[j][i].serial = i;
6453bbe3f67SBaptiste Daroussin 	}
6463bbe3f67SBaptiste Daroussin }
6473bbe3f67SBaptiste Daroussin 
6483bbe3f67SBaptiste Daroussin static void
6493bbe3f67SBaptiste Daroussin equiv(struct line *a, int n, struct line *b, int m, int *c)
6503bbe3f67SBaptiste Daroussin {
6513bbe3f67SBaptiste Daroussin 	int i, j;
6523bbe3f67SBaptiste Daroussin 
6533bbe3f67SBaptiste Daroussin 	i = j = 1;
6543bbe3f67SBaptiste Daroussin 	while (i <= n && j <= m) {
6553bbe3f67SBaptiste Daroussin 		if (a[i].value < b[j].value)
6563bbe3f67SBaptiste Daroussin 			a[i++].value = 0;
6573bbe3f67SBaptiste Daroussin 		else if (a[i].value == b[j].value)
6583bbe3f67SBaptiste Daroussin 			a[i++].value = j;
6593bbe3f67SBaptiste Daroussin 		else
6603bbe3f67SBaptiste Daroussin 			j++;
6613bbe3f67SBaptiste Daroussin 	}
6623bbe3f67SBaptiste Daroussin 	while (i <= n)
6633bbe3f67SBaptiste Daroussin 		a[i++].value = 0;
6643bbe3f67SBaptiste Daroussin 	b[m + 1].value = 0;
6653bbe3f67SBaptiste Daroussin 	j = 0;
6663bbe3f67SBaptiste Daroussin 	while (++j <= m) {
6673bbe3f67SBaptiste Daroussin 		c[j] = -b[j].serial;
6683bbe3f67SBaptiste Daroussin 		while (b[j + 1].value == b[j].value) {
6693bbe3f67SBaptiste Daroussin 			j++;
6703bbe3f67SBaptiste Daroussin 			c[j] = b[j].serial;
6713bbe3f67SBaptiste Daroussin 		}
6723bbe3f67SBaptiste Daroussin 	}
6733bbe3f67SBaptiste Daroussin 	c[j] = -1;
6743bbe3f67SBaptiste Daroussin }
6753bbe3f67SBaptiste Daroussin 
6763bbe3f67SBaptiste Daroussin /* Code taken from ping.c */
6773bbe3f67SBaptiste Daroussin static int
6783bbe3f67SBaptiste Daroussin isqrt(int n)
6793bbe3f67SBaptiste Daroussin {
6803bbe3f67SBaptiste Daroussin 	int y, x = 1;
6813bbe3f67SBaptiste Daroussin 
6823bbe3f67SBaptiste Daroussin 	if (n == 0)
6833bbe3f67SBaptiste Daroussin 		return (0);
6843bbe3f67SBaptiste Daroussin 
6853bbe3f67SBaptiste Daroussin 	do { /* newton was a stinker */
6863bbe3f67SBaptiste Daroussin 		y = x;
6873bbe3f67SBaptiste Daroussin 		x = n / x;
6883bbe3f67SBaptiste Daroussin 		x += y;
6893bbe3f67SBaptiste Daroussin 		x /= 2;
6903bbe3f67SBaptiste Daroussin 	} while ((x - y) > 1 || (x - y) < -1);
6913bbe3f67SBaptiste Daroussin 
6923bbe3f67SBaptiste Daroussin 	return (x);
6933bbe3f67SBaptiste Daroussin }
6943bbe3f67SBaptiste Daroussin 
6953bbe3f67SBaptiste Daroussin static int
6963bbe3f67SBaptiste Daroussin stone(int *a, int n, int *b, int *c, int flags)
6973bbe3f67SBaptiste Daroussin {
6983bbe3f67SBaptiste Daroussin 	int i, k, y, j, l;
6993bbe3f67SBaptiste Daroussin 	int oldc, tc, oldl, sq;
7003bbe3f67SBaptiste Daroussin 	u_int numtries, bound;
7013bbe3f67SBaptiste Daroussin 
7023bbe3f67SBaptiste Daroussin 	if (flags & D_MINIMAL)
7033bbe3f67SBaptiste Daroussin 		bound = UINT_MAX;
7043bbe3f67SBaptiste Daroussin 	else {
7053bbe3f67SBaptiste Daroussin 		sq = isqrt(n);
70642c88c41SBaptiste Daroussin 		bound = MAX(256, sq);
7073bbe3f67SBaptiste Daroussin 	}
7083bbe3f67SBaptiste Daroussin 
7093bbe3f67SBaptiste Daroussin 	k = 0;
7103bbe3f67SBaptiste Daroussin 	c[0] = newcand(0, 0, 0);
7113bbe3f67SBaptiste Daroussin 	for (i = 1; i <= n; i++) {
7123bbe3f67SBaptiste Daroussin 		j = a[i];
7133bbe3f67SBaptiste Daroussin 		if (j == 0)
7143bbe3f67SBaptiste Daroussin 			continue;
7153bbe3f67SBaptiste Daroussin 		y = -b[j];
7163bbe3f67SBaptiste Daroussin 		oldl = 0;
7173bbe3f67SBaptiste Daroussin 		oldc = c[0];
7183bbe3f67SBaptiste Daroussin 		numtries = 0;
7193bbe3f67SBaptiste Daroussin 		do {
7203bbe3f67SBaptiste Daroussin 			if (y <= clist[oldc].y)
7213bbe3f67SBaptiste Daroussin 				continue;
7223bbe3f67SBaptiste Daroussin 			l = search(c, k, y);
7233bbe3f67SBaptiste Daroussin 			if (l != oldl + 1)
7243bbe3f67SBaptiste Daroussin 				oldc = c[l - 1];
7253bbe3f67SBaptiste Daroussin 			if (l <= k) {
7263bbe3f67SBaptiste Daroussin 				if (clist[c[l]].y <= y)
7273bbe3f67SBaptiste Daroussin 					continue;
7283bbe3f67SBaptiste Daroussin 				tc = c[l];
7293bbe3f67SBaptiste Daroussin 				c[l] = newcand(i, y, oldc);
7303bbe3f67SBaptiste Daroussin 				oldc = tc;
7313bbe3f67SBaptiste Daroussin 				oldl = l;
7323bbe3f67SBaptiste Daroussin 				numtries++;
7333bbe3f67SBaptiste Daroussin 			} else {
7343bbe3f67SBaptiste Daroussin 				c[l] = newcand(i, y, oldc);
7353bbe3f67SBaptiste Daroussin 				k++;
7363bbe3f67SBaptiste Daroussin 				break;
7373bbe3f67SBaptiste Daroussin 			}
7383bbe3f67SBaptiste Daroussin 		} while ((y = b[++j]) > 0 && numtries < bound);
7393bbe3f67SBaptiste Daroussin 	}
7403bbe3f67SBaptiste Daroussin 	return (k);
7413bbe3f67SBaptiste Daroussin }
7423bbe3f67SBaptiste Daroussin 
7433bbe3f67SBaptiste Daroussin static int
7443bbe3f67SBaptiste Daroussin newcand(int x, int y, int pred)
7453bbe3f67SBaptiste Daroussin {
7463bbe3f67SBaptiste Daroussin 	struct cand *q;
7473bbe3f67SBaptiste Daroussin 
7483bbe3f67SBaptiste Daroussin 	if (clen == clistlen) {
7493bbe3f67SBaptiste Daroussin 		clistlen = clistlen * 11 / 10;
7503bbe3f67SBaptiste Daroussin 		clist = xreallocarray(clist, clistlen, sizeof(*clist));
7513bbe3f67SBaptiste Daroussin 	}
7523bbe3f67SBaptiste Daroussin 	q = clist + clen;
7533bbe3f67SBaptiste Daroussin 	q->x = x;
7543bbe3f67SBaptiste Daroussin 	q->y = y;
7553bbe3f67SBaptiste Daroussin 	q->pred = pred;
7563bbe3f67SBaptiste Daroussin 	return (clen++);
7573bbe3f67SBaptiste Daroussin }
7583bbe3f67SBaptiste Daroussin 
7593bbe3f67SBaptiste Daroussin static int
7603bbe3f67SBaptiste Daroussin search(int *c, int k, int y)
7613bbe3f67SBaptiste Daroussin {
7623bbe3f67SBaptiste Daroussin 	int i, j, l, t;
7633bbe3f67SBaptiste Daroussin 
7643bbe3f67SBaptiste Daroussin 	if (clist[c[k]].y < y)	/* quick look for typical case */
7653bbe3f67SBaptiste Daroussin 		return (k + 1);
7663bbe3f67SBaptiste Daroussin 	i = 0;
7673bbe3f67SBaptiste Daroussin 	j = k + 1;
7683bbe3f67SBaptiste Daroussin 	for (;;) {
7693bbe3f67SBaptiste Daroussin 		l = (i + j) / 2;
7703bbe3f67SBaptiste Daroussin 		if (l <= i)
7713bbe3f67SBaptiste Daroussin 			break;
7723bbe3f67SBaptiste Daroussin 		t = clist[c[l]].y;
7733bbe3f67SBaptiste Daroussin 		if (t > y)
7743bbe3f67SBaptiste Daroussin 			j = l;
7753bbe3f67SBaptiste Daroussin 		else if (t < y)
7763bbe3f67SBaptiste Daroussin 			i = l;
7773bbe3f67SBaptiste Daroussin 		else
7783bbe3f67SBaptiste Daroussin 			return (l);
7793bbe3f67SBaptiste Daroussin 	}
7803bbe3f67SBaptiste Daroussin 	return (l + 1);
7813bbe3f67SBaptiste Daroussin }
7823bbe3f67SBaptiste Daroussin 
7833bbe3f67SBaptiste Daroussin static void
7843bbe3f67SBaptiste Daroussin unravel(int p)
7853bbe3f67SBaptiste Daroussin {
7863bbe3f67SBaptiste Daroussin 	struct cand *q;
7873bbe3f67SBaptiste Daroussin 	int i;
7883bbe3f67SBaptiste Daroussin 
7893bbe3f67SBaptiste Daroussin 	for (i = 0; i <= len[0]; i++)
7903bbe3f67SBaptiste Daroussin 		J[i] = i <= pref ? i :
7913bbe3f67SBaptiste Daroussin 		    i > len[0] - suff ? i + len[1] - len[0] : 0;
7923bbe3f67SBaptiste Daroussin 	for (q = clist + p; q->y != 0; q = clist + q->pred)
7933bbe3f67SBaptiste Daroussin 		J[q->x + pref] = q->y + pref;
7943bbe3f67SBaptiste Daroussin }
7953bbe3f67SBaptiste Daroussin 
7963bbe3f67SBaptiste Daroussin /*
7973bbe3f67SBaptiste Daroussin  * Check does double duty:
7983bbe3f67SBaptiste Daroussin  *  1.	ferret out any fortuitous correspondences due
7993bbe3f67SBaptiste Daroussin  *	to confounding by hashing (which result in "jackpot")
8003bbe3f67SBaptiste Daroussin  *  2.  collect random access indexes to the two files
8013bbe3f67SBaptiste Daroussin  */
8023bbe3f67SBaptiste Daroussin static void
8033bbe3f67SBaptiste Daroussin check(FILE *f1, FILE *f2, int flags)
8043bbe3f67SBaptiste Daroussin {
8053bbe3f67SBaptiste Daroussin 	int i, j, jackpot, c, d;
8063bbe3f67SBaptiste Daroussin 	long ctold, ctnew;
8073bbe3f67SBaptiste Daroussin 
8083bbe3f67SBaptiste Daroussin 	rewind(f1);
8093bbe3f67SBaptiste Daroussin 	rewind(f2);
8103bbe3f67SBaptiste Daroussin 	j = 1;
8113bbe3f67SBaptiste Daroussin 	ixold[0] = ixnew[0] = 0;
8123bbe3f67SBaptiste Daroussin 	jackpot = 0;
8133bbe3f67SBaptiste Daroussin 	ctold = ctnew = 0;
8143bbe3f67SBaptiste Daroussin 	for (i = 1; i <= len[0]; i++) {
8153bbe3f67SBaptiste Daroussin 		if (J[i] == 0) {
8163bbe3f67SBaptiste Daroussin 			ixold[i] = ctold += skipline(f1);
8173bbe3f67SBaptiste Daroussin 			continue;
8183bbe3f67SBaptiste Daroussin 		}
8193bbe3f67SBaptiste Daroussin 		while (j < J[i]) {
8203bbe3f67SBaptiste Daroussin 			ixnew[j] = ctnew += skipline(f2);
8213bbe3f67SBaptiste Daroussin 			j++;
8223bbe3f67SBaptiste Daroussin 		}
8233bbe3f67SBaptiste Daroussin 		if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS|D_IGNORECASE|D_STRIPCR)) {
8243bbe3f67SBaptiste Daroussin 			for (;;) {
8253bbe3f67SBaptiste Daroussin 				c = getc(f1);
8263bbe3f67SBaptiste Daroussin 				d = getc(f2);
8273bbe3f67SBaptiste Daroussin 				/*
8283bbe3f67SBaptiste Daroussin 				 * GNU diff ignores a missing newline
8293bbe3f67SBaptiste Daroussin 				 * in one file for -b or -w.
8303bbe3f67SBaptiste Daroussin 				 */
8313bbe3f67SBaptiste Daroussin 				if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) {
8323bbe3f67SBaptiste Daroussin 					if (c == EOF && d == '\n') {
8333bbe3f67SBaptiste Daroussin 						ctnew++;
8343bbe3f67SBaptiste Daroussin 						break;
8353bbe3f67SBaptiste Daroussin 					} else if (c == '\n' && d == EOF) {
8363bbe3f67SBaptiste Daroussin 						ctold++;
8373bbe3f67SBaptiste Daroussin 						break;
8383bbe3f67SBaptiste Daroussin 					}
8393bbe3f67SBaptiste Daroussin 				}
8403bbe3f67SBaptiste Daroussin 				ctold++;
8413bbe3f67SBaptiste Daroussin 				ctnew++;
8423bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR) {
8433bbe3f67SBaptiste Daroussin 					if (c == '\r') {
8443bbe3f67SBaptiste Daroussin 						if ((c = getc(f1)) == '\n') {
8453bbe3f67SBaptiste Daroussin 							ctnew++;
8463bbe3f67SBaptiste Daroussin 							break;
8473bbe3f67SBaptiste Daroussin 						}
8483bbe3f67SBaptiste Daroussin 					}
8493bbe3f67SBaptiste Daroussin 					if (d == '\r') {
8503bbe3f67SBaptiste Daroussin 						if ((d = getc(f2)) == '\n') {
8513bbe3f67SBaptiste Daroussin 							ctold++;
8523bbe3f67SBaptiste Daroussin 							break;
8533bbe3f67SBaptiste Daroussin 						}
8543bbe3f67SBaptiste Daroussin 					}
8553bbe3f67SBaptiste Daroussin 				}
8563bbe3f67SBaptiste Daroussin 				if ((flags & D_FOLDBLANKS) && isspace(c) &&
8573bbe3f67SBaptiste Daroussin 				    isspace(d)) {
8583bbe3f67SBaptiste Daroussin 					do {
8593bbe3f67SBaptiste Daroussin 						if (c == '\n')
8603bbe3f67SBaptiste Daroussin 							break;
8613bbe3f67SBaptiste Daroussin 						ctold++;
8623bbe3f67SBaptiste Daroussin 					} while (isspace(c = getc(f1)));
8633bbe3f67SBaptiste Daroussin 					do {
8643bbe3f67SBaptiste Daroussin 						if (d == '\n')
8653bbe3f67SBaptiste Daroussin 							break;
8663bbe3f67SBaptiste Daroussin 						ctnew++;
8673bbe3f67SBaptiste Daroussin 					} while (isspace(d = getc(f2)));
8683bbe3f67SBaptiste Daroussin 				} else if ((flags & D_IGNOREBLANKS)) {
8693bbe3f67SBaptiste Daroussin 					while (isspace(c) && c != '\n') {
8703bbe3f67SBaptiste Daroussin 						c = getc(f1);
8713bbe3f67SBaptiste Daroussin 						ctold++;
8723bbe3f67SBaptiste Daroussin 					}
8733bbe3f67SBaptiste Daroussin 					while (isspace(d) && d != '\n') {
8743bbe3f67SBaptiste Daroussin 						d = getc(f2);
8753bbe3f67SBaptiste Daroussin 						ctnew++;
8763bbe3f67SBaptiste Daroussin 					}
8773bbe3f67SBaptiste Daroussin 				}
8783bbe3f67SBaptiste Daroussin 				if (chrtran[c] != chrtran[d]) {
8793bbe3f67SBaptiste Daroussin 					jackpot++;
8803bbe3f67SBaptiste Daroussin 					J[i] = 0;
8813bbe3f67SBaptiste Daroussin 					if (c != '\n' && c != EOF)
8823bbe3f67SBaptiste Daroussin 						ctold += skipline(f1);
8833bbe3f67SBaptiste Daroussin 					if (d != '\n' && c != EOF)
8843bbe3f67SBaptiste Daroussin 						ctnew += skipline(f2);
8853bbe3f67SBaptiste Daroussin 					break;
8863bbe3f67SBaptiste Daroussin 				}
8873bbe3f67SBaptiste Daroussin 				if (c == '\n' || c == EOF)
8883bbe3f67SBaptiste Daroussin 					break;
8893bbe3f67SBaptiste Daroussin 			}
8903bbe3f67SBaptiste Daroussin 		} else {
8913bbe3f67SBaptiste Daroussin 			for (;;) {
8923bbe3f67SBaptiste Daroussin 				ctold++;
8933bbe3f67SBaptiste Daroussin 				ctnew++;
8943bbe3f67SBaptiste Daroussin 				if ((c = getc(f1)) != (d = getc(f2))) {
8953bbe3f67SBaptiste Daroussin 					/* jackpot++; */
8963bbe3f67SBaptiste Daroussin 					J[i] = 0;
8973bbe3f67SBaptiste Daroussin 					if (c != '\n' && c != EOF)
8983bbe3f67SBaptiste Daroussin 						ctold += skipline(f1);
8993bbe3f67SBaptiste Daroussin 					if (d != '\n' && c != EOF)
9003bbe3f67SBaptiste Daroussin 						ctnew += skipline(f2);
9013bbe3f67SBaptiste Daroussin 					break;
9023bbe3f67SBaptiste Daroussin 				}
9033bbe3f67SBaptiste Daroussin 				if (c == '\n' || c == EOF)
9043bbe3f67SBaptiste Daroussin 					break;
9053bbe3f67SBaptiste Daroussin 			}
9063bbe3f67SBaptiste Daroussin 		}
9073bbe3f67SBaptiste Daroussin 		ixold[i] = ctold;
9083bbe3f67SBaptiste Daroussin 		ixnew[j] = ctnew;
9093bbe3f67SBaptiste Daroussin 		j++;
9103bbe3f67SBaptiste Daroussin 	}
9113bbe3f67SBaptiste Daroussin 	for (; j <= len[1]; j++) {
9123bbe3f67SBaptiste Daroussin 		ixnew[j] = ctnew += skipline(f2);
9133bbe3f67SBaptiste Daroussin 	}
9143bbe3f67SBaptiste Daroussin 	/*
9153bbe3f67SBaptiste Daroussin 	 * if (jackpot)
9163bbe3f67SBaptiste Daroussin 	 *	fprintf(stderr, "jackpot\n");
9173bbe3f67SBaptiste Daroussin 	 */
9183bbe3f67SBaptiste Daroussin }
9193bbe3f67SBaptiste Daroussin 
9203bbe3f67SBaptiste Daroussin /* shellsort CACM #201 */
9213bbe3f67SBaptiste Daroussin static void
9223bbe3f67SBaptiste Daroussin sort(struct line *a, int n)
9233bbe3f67SBaptiste Daroussin {
9243bbe3f67SBaptiste Daroussin 	struct line *ai, *aim, w;
9253bbe3f67SBaptiste Daroussin 	int j, m = 0, k;
9263bbe3f67SBaptiste Daroussin 
9273bbe3f67SBaptiste Daroussin 	if (n == 0)
9283bbe3f67SBaptiste Daroussin 		return;
9293bbe3f67SBaptiste Daroussin 	for (j = 1; j <= n; j *= 2)
9303bbe3f67SBaptiste Daroussin 		m = 2 * j - 1;
9313bbe3f67SBaptiste Daroussin 	for (m /= 2; m != 0; m /= 2) {
9323bbe3f67SBaptiste Daroussin 		k = n - m;
9333bbe3f67SBaptiste Daroussin 		for (j = 1; j <= k; j++) {
9343bbe3f67SBaptiste Daroussin 			for (ai = &a[j]; ai > a; ai -= m) {
9353bbe3f67SBaptiste Daroussin 				aim = &ai[m];
9363bbe3f67SBaptiste Daroussin 				if (aim < ai)
9373bbe3f67SBaptiste Daroussin 					break;	/* wraparound */
9383bbe3f67SBaptiste Daroussin 				if (aim->value > ai[0].value ||
9393bbe3f67SBaptiste Daroussin 				    (aim->value == ai[0].value &&
9403bbe3f67SBaptiste Daroussin 					aim->serial > ai[0].serial))
9413bbe3f67SBaptiste Daroussin 					break;
9423bbe3f67SBaptiste Daroussin 				w.value = ai[0].value;
9433bbe3f67SBaptiste Daroussin 				ai[0].value = aim->value;
9443bbe3f67SBaptiste Daroussin 				aim->value = w.value;
9453bbe3f67SBaptiste Daroussin 				w.serial = ai[0].serial;
9463bbe3f67SBaptiste Daroussin 				ai[0].serial = aim->serial;
9473bbe3f67SBaptiste Daroussin 				aim->serial = w.serial;
9483bbe3f67SBaptiste Daroussin 			}
9493bbe3f67SBaptiste Daroussin 		}
9503bbe3f67SBaptiste Daroussin 	}
9513bbe3f67SBaptiste Daroussin }
9523bbe3f67SBaptiste Daroussin 
9533bbe3f67SBaptiste Daroussin static void
9543bbe3f67SBaptiste Daroussin unsort(struct line *f, int l, int *b)
9553bbe3f67SBaptiste Daroussin {
9563bbe3f67SBaptiste Daroussin 	int *a, i;
9573bbe3f67SBaptiste Daroussin 
9583bbe3f67SBaptiste Daroussin 	a = xcalloc(l + 1, sizeof(*a));
9593bbe3f67SBaptiste Daroussin 	for (i = 1; i <= l; i++)
9603bbe3f67SBaptiste Daroussin 		a[f[i].serial] = f[i].value;
9613bbe3f67SBaptiste Daroussin 	for (i = 1; i <= l; i++)
9623bbe3f67SBaptiste Daroussin 		b[i] = a[i];
9633bbe3f67SBaptiste Daroussin 	free(a);
9643bbe3f67SBaptiste Daroussin }
9653bbe3f67SBaptiste Daroussin 
9663bbe3f67SBaptiste Daroussin static int
9673bbe3f67SBaptiste Daroussin skipline(FILE *f)
9683bbe3f67SBaptiste Daroussin {
9693bbe3f67SBaptiste Daroussin 	int i, c;
9703bbe3f67SBaptiste Daroussin 
9713bbe3f67SBaptiste Daroussin 	for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
9723bbe3f67SBaptiste Daroussin 		continue;
9733bbe3f67SBaptiste Daroussin 	return (i);
9743bbe3f67SBaptiste Daroussin }
9753bbe3f67SBaptiste Daroussin 
9763bbe3f67SBaptiste Daroussin static void
9773bbe3f67SBaptiste Daroussin output(char *file1, FILE *f1, char *file2, FILE *f2, int flags)
9783bbe3f67SBaptiste Daroussin {
9793bbe3f67SBaptiste Daroussin 	int m, i0, i1, j0, j1;
9803bbe3f67SBaptiste Daroussin 
9813bbe3f67SBaptiste Daroussin 	rewind(f1);
9823bbe3f67SBaptiste Daroussin 	rewind(f2);
9833bbe3f67SBaptiste Daroussin 	m = len[0];
9843bbe3f67SBaptiste Daroussin 	J[0] = 0;
9853bbe3f67SBaptiste Daroussin 	J[m + 1] = len[1] + 1;
9863bbe3f67SBaptiste Daroussin 	if (diff_format != D_EDIT) {
9873bbe3f67SBaptiste Daroussin 		for (i0 = 1; i0 <= m; i0 = i1 + 1) {
9883bbe3f67SBaptiste Daroussin 			while (i0 <= m && J[i0] == J[i0 - 1] + 1)
9893bbe3f67SBaptiste Daroussin 				i0++;
9903bbe3f67SBaptiste Daroussin 			j0 = J[i0 - 1] + 1;
9913bbe3f67SBaptiste Daroussin 			i1 = i0 - 1;
9923bbe3f67SBaptiste Daroussin 			while (i1 < m && J[i1 + 1] == 0)
9933bbe3f67SBaptiste Daroussin 				i1++;
9943bbe3f67SBaptiste Daroussin 			j1 = J[i1 + 1] - 1;
9953bbe3f67SBaptiste Daroussin 			J[i1] = j1;
9963bbe3f67SBaptiste Daroussin 			change(file1, f1, file2, f2, i0, i1, j0, j1, &flags);
9973bbe3f67SBaptiste Daroussin 		}
9983bbe3f67SBaptiste Daroussin 	} else {
9993bbe3f67SBaptiste Daroussin 		for (i0 = m; i0 >= 1; i0 = i1 - 1) {
10003bbe3f67SBaptiste Daroussin 			while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0)
10013bbe3f67SBaptiste Daroussin 				i0--;
10023bbe3f67SBaptiste Daroussin 			j0 = J[i0 + 1] - 1;
10033bbe3f67SBaptiste Daroussin 			i1 = i0 + 1;
10043bbe3f67SBaptiste Daroussin 			while (i1 > 1 && J[i1 - 1] == 0)
10053bbe3f67SBaptiste Daroussin 				i1--;
10063bbe3f67SBaptiste Daroussin 			j1 = J[i1 - 1] + 1;
10073bbe3f67SBaptiste Daroussin 			J[i1] = j1;
10083bbe3f67SBaptiste Daroussin 			change(file1, f1, file2, f2, i1, i0, j1, j0, &flags);
10093bbe3f67SBaptiste Daroussin 		}
10103bbe3f67SBaptiste Daroussin 	}
10113bbe3f67SBaptiste Daroussin 	if (m == 0)
10123bbe3f67SBaptiste Daroussin 		change(file1, f1, file2, f2, 1, 0, 1, len[1], &flags);
1013fddcb7b8SBaptiste Daroussin 	if (diff_format == D_IFDEF || diff_format == D_GFORMAT) {
10143bbe3f67SBaptiste Daroussin 		for (;;) {
10153bbe3f67SBaptiste Daroussin #define	c i0
10163bbe3f67SBaptiste Daroussin 			if ((c = getc(f1)) == EOF)
10173bbe3f67SBaptiste Daroussin 				return;
10183bbe3f67SBaptiste Daroussin 			diff_output("%c", c);
10193bbe3f67SBaptiste Daroussin 		}
10203bbe3f67SBaptiste Daroussin #undef c
10213bbe3f67SBaptiste Daroussin 	}
10223bbe3f67SBaptiste Daroussin 	if (anychange != 0) {
10233bbe3f67SBaptiste Daroussin 		if (diff_format == D_CONTEXT)
10243bbe3f67SBaptiste Daroussin 			dump_context_vec(f1, f2, flags);
10253bbe3f67SBaptiste Daroussin 		else if (diff_format == D_UNIFIED)
10263bbe3f67SBaptiste Daroussin 			dump_unified_vec(f1, f2, flags);
10273bbe3f67SBaptiste Daroussin 	}
10283bbe3f67SBaptiste Daroussin }
10293bbe3f67SBaptiste Daroussin 
10303bbe3f67SBaptiste Daroussin static void
10313bbe3f67SBaptiste Daroussin range(int a, int b, const char *separator)
10323bbe3f67SBaptiste Daroussin {
10333bbe3f67SBaptiste Daroussin 	diff_output("%d", a > b ? b : a);
10343bbe3f67SBaptiste Daroussin 	if (a < b)
10353bbe3f67SBaptiste Daroussin 		diff_output("%s%d", separator, b);
10363bbe3f67SBaptiste Daroussin }
10373bbe3f67SBaptiste Daroussin 
10383bbe3f67SBaptiste Daroussin static void
10393bbe3f67SBaptiste Daroussin uni_range(int a, int b)
10403bbe3f67SBaptiste Daroussin {
10413bbe3f67SBaptiste Daroussin 	if (a < b)
10423bbe3f67SBaptiste Daroussin 		diff_output("%d,%d", a, b - a + 1);
10433bbe3f67SBaptiste Daroussin 	else if (a == b)
10443bbe3f67SBaptiste Daroussin 		diff_output("%d", b);
10453bbe3f67SBaptiste Daroussin 	else
10463bbe3f67SBaptiste Daroussin 		diff_output("%d,0", b);
10473bbe3f67SBaptiste Daroussin }
10483bbe3f67SBaptiste Daroussin 
10493bbe3f67SBaptiste Daroussin static char *
10503bbe3f67SBaptiste Daroussin preadline(int fd, size_t rlen, off_t off)
10513bbe3f67SBaptiste Daroussin {
10523bbe3f67SBaptiste Daroussin 	char *line;
10533bbe3f67SBaptiste Daroussin 	ssize_t nr;
10543bbe3f67SBaptiste Daroussin 
10553bbe3f67SBaptiste Daroussin 	line = xmalloc(rlen + 1);
10563bbe3f67SBaptiste Daroussin 	if ((nr = pread(fd, line, rlen, off)) < 0)
10573bbe3f67SBaptiste Daroussin 		err(2, "preadline");
10583bbe3f67SBaptiste Daroussin 	if (nr > 0 && line[nr-1] == '\n')
10593bbe3f67SBaptiste Daroussin 		nr--;
10603bbe3f67SBaptiste Daroussin 	line[nr] = '\0';
10613bbe3f67SBaptiste Daroussin 	return (line);
10623bbe3f67SBaptiste Daroussin }
10633bbe3f67SBaptiste Daroussin 
10643bbe3f67SBaptiste Daroussin static int
10653bbe3f67SBaptiste Daroussin ignoreline(char *line)
10663bbe3f67SBaptiste Daroussin {
10673bbe3f67SBaptiste Daroussin 	int ret;
10683bbe3f67SBaptiste Daroussin 
10693bbe3f67SBaptiste Daroussin 	ret = regexec(&ignore_re, line, 0, NULL, 0);
10703bbe3f67SBaptiste Daroussin 	free(line);
10713bbe3f67SBaptiste Daroussin 	return (ret == 0);	/* if it matched, it should be ignored. */
10723bbe3f67SBaptiste Daroussin }
10733bbe3f67SBaptiste Daroussin 
10743bbe3f67SBaptiste Daroussin /*
10753bbe3f67SBaptiste Daroussin  * Indicate that there is a difference between lines a and b of the from file
10763bbe3f67SBaptiste Daroussin  * to get to lines c to d of the to file.  If a is greater then b then there
10773bbe3f67SBaptiste Daroussin  * are no lines in the from file involved and this means that there were
10783bbe3f67SBaptiste Daroussin  * lines appended (beginning at b).  If c is greater than d then there are
10793bbe3f67SBaptiste Daroussin  * lines missing from the to file.
10803bbe3f67SBaptiste Daroussin  */
10813bbe3f67SBaptiste Daroussin static void
10823bbe3f67SBaptiste Daroussin change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d,
10833bbe3f67SBaptiste Daroussin     int *pflags)
10843bbe3f67SBaptiste Daroussin {
10853bbe3f67SBaptiste Daroussin 	static size_t max_context = 64;
1086fddcb7b8SBaptiste Daroussin 	long curpos;
10877ef35d05SDimitry Andric 	int i, nc, f;
1088fddcb7b8SBaptiste Daroussin 	const char *walk;
10893bbe3f67SBaptiste Daroussin 
10903bbe3f67SBaptiste Daroussin restart:
1091fddcb7b8SBaptiste Daroussin 	if ((diff_format != D_IFDEF || diff_format == D_GFORMAT) &&
1092fddcb7b8SBaptiste Daroussin 	    a > b && c > d)
10933bbe3f67SBaptiste Daroussin 		return;
10943bbe3f67SBaptiste Daroussin 	if (ignore_pats != NULL) {
10953bbe3f67SBaptiste Daroussin 		char *line;
10963bbe3f67SBaptiste Daroussin 		/*
10973bbe3f67SBaptiste Daroussin 		 * All lines in the change, insert, or delete must
10983bbe3f67SBaptiste Daroussin 		 * match an ignore pattern for the change to be
10993bbe3f67SBaptiste Daroussin 		 * ignored.
11003bbe3f67SBaptiste Daroussin 		 */
11013bbe3f67SBaptiste Daroussin 		if (a <= b) {		/* Changes and deletes. */
11023bbe3f67SBaptiste Daroussin 			for (i = a; i <= b; i++) {
11033bbe3f67SBaptiste Daroussin 				line = preadline(fileno(f1),
11043bbe3f67SBaptiste Daroussin 				    ixold[i] - ixold[i - 1], ixold[i - 1]);
11053bbe3f67SBaptiste Daroussin 				if (!ignoreline(line))
11063bbe3f67SBaptiste Daroussin 					goto proceed;
11073bbe3f67SBaptiste Daroussin 			}
11083bbe3f67SBaptiste Daroussin 		}
11093bbe3f67SBaptiste Daroussin 		if (a > b || c <= d) {	/* Changes and inserts. */
11103bbe3f67SBaptiste Daroussin 			for (i = c; i <= d; i++) {
11113bbe3f67SBaptiste Daroussin 				line = preadline(fileno(f2),
11123bbe3f67SBaptiste Daroussin 				    ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
11133bbe3f67SBaptiste Daroussin 				if (!ignoreline(line))
11143bbe3f67SBaptiste Daroussin 					goto proceed;
11153bbe3f67SBaptiste Daroussin 			}
11163bbe3f67SBaptiste Daroussin 		}
11173bbe3f67SBaptiste Daroussin 		return;
11183bbe3f67SBaptiste Daroussin 	}
11193bbe3f67SBaptiste Daroussin proceed:
11204d8c5790SEnji Cooper 	if (*pflags & D_HEADER && diff_format != D_BRIEF) {
11213bbe3f67SBaptiste Daroussin 		diff_output("%s %s %s\n", diffargs, file1, file2);
11223bbe3f67SBaptiste Daroussin 		*pflags &= ~D_HEADER;
11233bbe3f67SBaptiste Daroussin 	}
11243bbe3f67SBaptiste Daroussin 	if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
11253bbe3f67SBaptiste Daroussin 		/*
11263bbe3f67SBaptiste Daroussin 		 * Allocate change records as needed.
11273bbe3f67SBaptiste Daroussin 		 */
11283bbe3f67SBaptiste Daroussin 		if (context_vec_ptr == context_vec_end - 1) {
11293bbe3f67SBaptiste Daroussin 			ptrdiff_t offset = context_vec_ptr - context_vec_start;
11303bbe3f67SBaptiste Daroussin 			max_context <<= 1;
11313bbe3f67SBaptiste Daroussin 			context_vec_start = xreallocarray(context_vec_start,
11323bbe3f67SBaptiste Daroussin 			    max_context, sizeof(*context_vec_start));
11333bbe3f67SBaptiste Daroussin 			context_vec_end = context_vec_start + max_context;
11343bbe3f67SBaptiste Daroussin 			context_vec_ptr = context_vec_start + offset;
11353bbe3f67SBaptiste Daroussin 		}
11363bbe3f67SBaptiste Daroussin 		if (anychange == 0) {
11373bbe3f67SBaptiste Daroussin 			/*
11383bbe3f67SBaptiste Daroussin 			 * Print the context/unidiff header first time through.
11393bbe3f67SBaptiste Daroussin 			 */
11403bbe3f67SBaptiste Daroussin 			print_header(file1, file2);
11413bbe3f67SBaptiste Daroussin 			anychange = 1;
11423bbe3f67SBaptiste Daroussin 		} else if (a > context_vec_ptr->b + (2 * diff_context) + 1 &&
11433bbe3f67SBaptiste Daroussin 		    c > context_vec_ptr->d + (2 * diff_context) + 1) {
11443bbe3f67SBaptiste Daroussin 			/*
11453bbe3f67SBaptiste Daroussin 			 * If this change is more than 'diff_context' lines from the
11463bbe3f67SBaptiste Daroussin 			 * previous change, dump the record and reset it.
11473bbe3f67SBaptiste Daroussin 			 */
11483bbe3f67SBaptiste Daroussin 			if (diff_format == D_CONTEXT)
11493bbe3f67SBaptiste Daroussin 				dump_context_vec(f1, f2, *pflags);
11503bbe3f67SBaptiste Daroussin 			else
11513bbe3f67SBaptiste Daroussin 				dump_unified_vec(f1, f2, *pflags);
11523bbe3f67SBaptiste Daroussin 		}
11533bbe3f67SBaptiste Daroussin 		context_vec_ptr++;
11543bbe3f67SBaptiste Daroussin 		context_vec_ptr->a = a;
11553bbe3f67SBaptiste Daroussin 		context_vec_ptr->b = b;
11563bbe3f67SBaptiste Daroussin 		context_vec_ptr->c = c;
11573bbe3f67SBaptiste Daroussin 		context_vec_ptr->d = d;
11583bbe3f67SBaptiste Daroussin 		return;
11593bbe3f67SBaptiste Daroussin 	}
11603bbe3f67SBaptiste Daroussin 	if (anychange == 0)
11613bbe3f67SBaptiste Daroussin 		anychange = 1;
11623bbe3f67SBaptiste Daroussin 	switch (diff_format) {
11633bbe3f67SBaptiste Daroussin 	case D_BRIEF:
11643bbe3f67SBaptiste Daroussin 		return;
11653bbe3f67SBaptiste Daroussin 	case D_NORMAL:
11663bbe3f67SBaptiste Daroussin 	case D_EDIT:
11673bbe3f67SBaptiste Daroussin 		range(a, b, ",");
11683bbe3f67SBaptiste Daroussin 		diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
11693bbe3f67SBaptiste Daroussin 		if (diff_format == D_NORMAL)
11703bbe3f67SBaptiste Daroussin 			range(c, d, ",");
11713bbe3f67SBaptiste Daroussin 		diff_output("\n");
11723bbe3f67SBaptiste Daroussin 		break;
11733bbe3f67SBaptiste Daroussin 	case D_REVERSE:
11743bbe3f67SBaptiste Daroussin 		diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
11753bbe3f67SBaptiste Daroussin 		range(a, b, " ");
11763bbe3f67SBaptiste Daroussin 		diff_output("\n");
11773bbe3f67SBaptiste Daroussin 		break;
11783bbe3f67SBaptiste Daroussin 	case D_NREVERSE:
11793bbe3f67SBaptiste Daroussin 		if (a > b)
11803bbe3f67SBaptiste Daroussin 			diff_output("a%d %d\n", b, d - c + 1);
11813bbe3f67SBaptiste Daroussin 		else {
11823bbe3f67SBaptiste Daroussin 			diff_output("d%d %d\n", a, b - a + 1);
11833bbe3f67SBaptiste Daroussin 			if (!(c > d))
11843bbe3f67SBaptiste Daroussin 				/* add changed lines */
11853bbe3f67SBaptiste Daroussin 				diff_output("a%d %d\n", b, d - c + 1);
11863bbe3f67SBaptiste Daroussin 		}
11873bbe3f67SBaptiste Daroussin 		break;
11883bbe3f67SBaptiste Daroussin 	}
1189fddcb7b8SBaptiste Daroussin 	if (diff_format == D_GFORMAT) {
1190fddcb7b8SBaptiste Daroussin 		curpos = ftell(f1);
1191fddcb7b8SBaptiste Daroussin 		/* print through if append (a>b), else to (nb: 0 vs 1 orig) */
1192fddcb7b8SBaptiste Daroussin 		nc = ixold[a > b ? b : a - 1] - curpos;
1193fddcb7b8SBaptiste Daroussin 		for (i = 0; i < nc; i++)
1194fddcb7b8SBaptiste Daroussin 			diff_output("%c", getc(f1));
1195fddcb7b8SBaptiste Daroussin 		for (walk = group_format; *walk != '\0'; walk++) {
1196fddcb7b8SBaptiste Daroussin 			if (*walk == '%') {
1197fddcb7b8SBaptiste Daroussin 				walk++;
1198fddcb7b8SBaptiste Daroussin 				switch (*walk) {
1199fddcb7b8SBaptiste Daroussin 				case '<':
1200fddcb7b8SBaptiste Daroussin 					fetch(ixold, a, b, f1, '<', 1, *pflags);
1201fddcb7b8SBaptiste Daroussin 					break;
1202fddcb7b8SBaptiste Daroussin 				case '>':
1203fddcb7b8SBaptiste Daroussin 					fetch(ixnew, c, d, f2, '>', 0, *pflags);
1204fddcb7b8SBaptiste Daroussin 					break;
1205fddcb7b8SBaptiste Daroussin 				default:
1206fddcb7b8SBaptiste Daroussin 					diff_output("%%%c", *walk);
1207fddcb7b8SBaptiste Daroussin 					break;
1208fddcb7b8SBaptiste Daroussin 				}
1209fddcb7b8SBaptiste Daroussin 				continue;
1210fddcb7b8SBaptiste Daroussin 			}
1211fddcb7b8SBaptiste Daroussin 			diff_output("%c", *walk);
1212fddcb7b8SBaptiste Daroussin 		}
1213fddcb7b8SBaptiste Daroussin 	}
12143bbe3f67SBaptiste Daroussin 	if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
12153bbe3f67SBaptiste Daroussin 		fetch(ixold, a, b, f1, '<', 1, *pflags);
12163bbe3f67SBaptiste Daroussin 		if (a <= b && c <= d && diff_format == D_NORMAL)
12173bbe3f67SBaptiste Daroussin 			diff_output("---\n");
12183bbe3f67SBaptiste Daroussin 	}
12197ef35d05SDimitry Andric 	f = 0;
1220fddcb7b8SBaptiste Daroussin 	if (diff_format != D_GFORMAT)
12217ef35d05SDimitry Andric 		f = fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0, *pflags);
12227ef35d05SDimitry Andric 	if (f != 0 && diff_format == D_EDIT) {
12233bbe3f67SBaptiste Daroussin 		/*
12243bbe3f67SBaptiste Daroussin 		 * A non-zero return value for D_EDIT indicates that the
12253bbe3f67SBaptiste Daroussin 		 * last line printed was a bare dot (".") that has been
12263bbe3f67SBaptiste Daroussin 		 * escaped as ".." to prevent ed(1) from misinterpreting
12273bbe3f67SBaptiste Daroussin 		 * it.  We have to add a substitute command to change this
12283bbe3f67SBaptiste Daroussin 		 * back and restart where we left off.
12293bbe3f67SBaptiste Daroussin 		 */
12303bbe3f67SBaptiste Daroussin 		diff_output(".\n");
12317ef35d05SDimitry Andric 		diff_output("%ds/.//\n", a + f - 1);
12327ef35d05SDimitry Andric 		b = a + f - 1;
12333bbe3f67SBaptiste Daroussin 		a = b + 1;
12347ef35d05SDimitry Andric 		c += f;
12353bbe3f67SBaptiste Daroussin 		goto restart;
12363bbe3f67SBaptiste Daroussin 	}
12373bbe3f67SBaptiste Daroussin 	if ((diff_format == D_EDIT || diff_format == D_REVERSE) && c <= d)
12383bbe3f67SBaptiste Daroussin 		diff_output(".\n");
12393bbe3f67SBaptiste Daroussin 	if (inifdef) {
12403bbe3f67SBaptiste Daroussin 		diff_output("#endif /* %s */\n", ifdefname);
12413bbe3f67SBaptiste Daroussin 		inifdef = 0;
12423bbe3f67SBaptiste Daroussin 	}
12433bbe3f67SBaptiste Daroussin }
12443bbe3f67SBaptiste Daroussin 
12453bbe3f67SBaptiste Daroussin static int
12463bbe3f67SBaptiste Daroussin fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags)
12473bbe3f67SBaptiste Daroussin {
12483bbe3f67SBaptiste Daroussin 	int i, j, c, lastc, col, nc;
12493bbe3f67SBaptiste Daroussin 	int	newcol;
12503bbe3f67SBaptiste Daroussin 
12513bbe3f67SBaptiste Daroussin 	/*
12523bbe3f67SBaptiste Daroussin 	 * When doing #ifdef's, copy down to current line
12533bbe3f67SBaptiste Daroussin 	 * if this is the first file, so that stuff makes it to output.
12543bbe3f67SBaptiste Daroussin 	 */
1255fddcb7b8SBaptiste Daroussin 	if ((diff_format == D_IFDEF) && oldfile) {
12563bbe3f67SBaptiste Daroussin 		long curpos = ftell(lb);
12573bbe3f67SBaptiste Daroussin 		/* print through if append (a>b), else to (nb: 0 vs 1 orig) */
12583bbe3f67SBaptiste Daroussin 		nc = f[a > b ? b : a - 1] - curpos;
12593bbe3f67SBaptiste Daroussin 		for (i = 0; i < nc; i++)
12603bbe3f67SBaptiste Daroussin 			diff_output("%c", getc(lb));
12613bbe3f67SBaptiste Daroussin 	}
12623bbe3f67SBaptiste Daroussin 	if (a > b)
12633bbe3f67SBaptiste Daroussin 		return (0);
12643bbe3f67SBaptiste Daroussin 	if (diff_format == D_IFDEF) {
12653bbe3f67SBaptiste Daroussin 		if (inifdef) {
12663bbe3f67SBaptiste Daroussin 			diff_output("#else /* %s%s */\n",
12673bbe3f67SBaptiste Daroussin 			    oldfile == 1 ? "!" : "", ifdefname);
12683bbe3f67SBaptiste Daroussin 		} else {
12693bbe3f67SBaptiste Daroussin 			if (oldfile)
12703bbe3f67SBaptiste Daroussin 				diff_output("#ifndef %s\n", ifdefname);
12713bbe3f67SBaptiste Daroussin 			else
12723bbe3f67SBaptiste Daroussin 				diff_output("#ifdef %s\n", ifdefname);
12733bbe3f67SBaptiste Daroussin 		}
12743bbe3f67SBaptiste Daroussin 		inifdef = 1 + oldfile;
12753bbe3f67SBaptiste Daroussin 	}
12763bbe3f67SBaptiste Daroussin 	for (i = a; i <= b; i++) {
12773bbe3f67SBaptiste Daroussin 		fseek(lb, f[i - 1], SEEK_SET);
12783bbe3f67SBaptiste Daroussin 		nc = f[i] - f[i - 1];
1279fddcb7b8SBaptiste Daroussin 		if ((diff_format != D_IFDEF && diff_format != D_GFORMAT) &&
1280fddcb7b8SBaptiste Daroussin 		    ch != '\0') {
12813bbe3f67SBaptiste Daroussin 			diff_output("%c", ch);
12823bbe3f67SBaptiste Daroussin 			if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT
12833bbe3f67SBaptiste Daroussin 			    || diff_format == D_UNIFIED))
12843bbe3f67SBaptiste Daroussin 				diff_output("\t");
12853bbe3f67SBaptiste Daroussin 			else if (diff_format != D_UNIFIED)
12863bbe3f67SBaptiste Daroussin 				diff_output(" ");
12873bbe3f67SBaptiste Daroussin 		}
12883bbe3f67SBaptiste Daroussin 		col = 0;
12893bbe3f67SBaptiste Daroussin 		for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) {
12903bbe3f67SBaptiste Daroussin 			if ((c = getc(lb)) == EOF) {
12913bbe3f67SBaptiste Daroussin 				if (diff_format == D_EDIT || diff_format == D_REVERSE ||
12923bbe3f67SBaptiste Daroussin 				    diff_format == D_NREVERSE)
12933bbe3f67SBaptiste Daroussin 					warnx("No newline at end of file");
12943bbe3f67SBaptiste Daroussin 				else
12953bbe3f67SBaptiste Daroussin 					diff_output("\n\\ No newline at end of "
12963bbe3f67SBaptiste Daroussin 					    "file\n");
12973bbe3f67SBaptiste Daroussin 				return (0);
12983bbe3f67SBaptiste Daroussin 			}
12993bbe3f67SBaptiste Daroussin 			if (c == '\t' && (flags & D_EXPANDTABS)) {
13003bbe3f67SBaptiste Daroussin 				newcol = ((col/tabsize)+1)*tabsize;
13013bbe3f67SBaptiste Daroussin 				do {
13023bbe3f67SBaptiste Daroussin 					diff_output(" ");
13033bbe3f67SBaptiste Daroussin 				} while (++col < newcol);
13043bbe3f67SBaptiste Daroussin 			} else {
13053bbe3f67SBaptiste Daroussin 				if (diff_format == D_EDIT && j == 1 && c == '\n'
13063bbe3f67SBaptiste Daroussin 				    && lastc == '.') {
13073bbe3f67SBaptiste Daroussin 					/*
13083bbe3f67SBaptiste Daroussin 					 * Don't print a bare "." line
13093bbe3f67SBaptiste Daroussin 					 * since that will confuse ed(1).
13103bbe3f67SBaptiste Daroussin 					 * Print ".." instead and return,
13113bbe3f67SBaptiste Daroussin 					 * giving the caller an offset
13123bbe3f67SBaptiste Daroussin 					 * from which to restart.
13133bbe3f67SBaptiste Daroussin 					 */
13143bbe3f67SBaptiste Daroussin 					diff_output(".\n");
13153bbe3f67SBaptiste Daroussin 					return (i - a + 1);
13163bbe3f67SBaptiste Daroussin 				}
13173bbe3f67SBaptiste Daroussin 				diff_output("%c", c);
13183bbe3f67SBaptiste Daroussin 				col++;
13193bbe3f67SBaptiste Daroussin 			}
13203bbe3f67SBaptiste Daroussin 		}
13213bbe3f67SBaptiste Daroussin 	}
13223bbe3f67SBaptiste Daroussin 	return (0);
13233bbe3f67SBaptiste Daroussin }
13243bbe3f67SBaptiste Daroussin 
13253bbe3f67SBaptiste Daroussin /*
13263bbe3f67SBaptiste Daroussin  * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
13273bbe3f67SBaptiste Daroussin  */
13283bbe3f67SBaptiste Daroussin static int
13293bbe3f67SBaptiste Daroussin readhash(FILE *f, int flags)
13303bbe3f67SBaptiste Daroussin {
13313bbe3f67SBaptiste Daroussin 	int i, t, space;
13323bbe3f67SBaptiste Daroussin 	int sum;
13333bbe3f67SBaptiste Daroussin 
13343bbe3f67SBaptiste Daroussin 	sum = 1;
13353bbe3f67SBaptiste Daroussin 	space = 0;
13363bbe3f67SBaptiste Daroussin 	if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) == 0) {
13373bbe3f67SBaptiste Daroussin 		if (flags & D_IGNORECASE)
13383bbe3f67SBaptiste Daroussin 			for (i = 0; (t = getc(f)) != '\n'; i++) {
13393bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR && t == '\r') {
13403bbe3f67SBaptiste Daroussin 					t = getc(f);
13413bbe3f67SBaptiste Daroussin 					if (t == '\n')
13423bbe3f67SBaptiste Daroussin 						break;
13433bbe3f67SBaptiste Daroussin 					ungetc(t, f);
13443bbe3f67SBaptiste Daroussin 				}
13453bbe3f67SBaptiste Daroussin 				if (t == EOF) {
13463bbe3f67SBaptiste Daroussin 					if (i == 0)
13473bbe3f67SBaptiste Daroussin 						return (0);
13483bbe3f67SBaptiste Daroussin 					break;
13493bbe3f67SBaptiste Daroussin 				}
13503bbe3f67SBaptiste Daroussin 				sum = sum * 127 + chrtran[t];
13513bbe3f67SBaptiste Daroussin 			}
13523bbe3f67SBaptiste Daroussin 		else
13533bbe3f67SBaptiste Daroussin 			for (i = 0; (t = getc(f)) != '\n'; i++) {
13543bbe3f67SBaptiste Daroussin 				if (flags & D_STRIPCR && t == '\r') {
13553bbe3f67SBaptiste Daroussin 					t = getc(f);
13563bbe3f67SBaptiste Daroussin 					if (t == '\n')
13573bbe3f67SBaptiste Daroussin 						break;
13583bbe3f67SBaptiste Daroussin 					ungetc(t, f);
13593bbe3f67SBaptiste Daroussin 				}
13603bbe3f67SBaptiste Daroussin 				if (t == EOF) {
13613bbe3f67SBaptiste Daroussin 					if (i == 0)
13623bbe3f67SBaptiste Daroussin 						return (0);
13633bbe3f67SBaptiste Daroussin 					break;
13643bbe3f67SBaptiste Daroussin 				}
13653bbe3f67SBaptiste Daroussin 				sum = sum * 127 + t;
13663bbe3f67SBaptiste Daroussin 			}
13673bbe3f67SBaptiste Daroussin 	} else {
13683bbe3f67SBaptiste Daroussin 		for (i = 0;;) {
13693bbe3f67SBaptiste Daroussin 			switch (t = getc(f)) {
13703bbe3f67SBaptiste Daroussin 			case '\r':
13713bbe3f67SBaptiste Daroussin 			case '\t':
13723bbe3f67SBaptiste Daroussin 			case '\v':
13733bbe3f67SBaptiste Daroussin 			case '\f':
13743bbe3f67SBaptiste Daroussin 			case ' ':
13753bbe3f67SBaptiste Daroussin 				space++;
13763bbe3f67SBaptiste Daroussin 				continue;
13773bbe3f67SBaptiste Daroussin 			default:
13783bbe3f67SBaptiste Daroussin 				if (space && (flags & D_IGNOREBLANKS) == 0) {
13793bbe3f67SBaptiste Daroussin 					i++;
13803bbe3f67SBaptiste Daroussin 					space = 0;
13813bbe3f67SBaptiste Daroussin 				}
13823bbe3f67SBaptiste Daroussin 				sum = sum * 127 + chrtran[t];
13833bbe3f67SBaptiste Daroussin 				i++;
13843bbe3f67SBaptiste Daroussin 				continue;
13853bbe3f67SBaptiste Daroussin 			case EOF:
13863bbe3f67SBaptiste Daroussin 				if (i == 0)
13873bbe3f67SBaptiste Daroussin 					return (0);
13883bbe3f67SBaptiste Daroussin 				/* FALLTHROUGH */
13893bbe3f67SBaptiste Daroussin 			case '\n':
13903bbe3f67SBaptiste Daroussin 				break;
13913bbe3f67SBaptiste Daroussin 			}
13923bbe3f67SBaptiste Daroussin 			break;
13933bbe3f67SBaptiste Daroussin 		}
13943bbe3f67SBaptiste Daroussin 	}
13953bbe3f67SBaptiste Daroussin 	/*
13963bbe3f67SBaptiste Daroussin 	 * There is a remote possibility that we end up with a zero sum.
13973bbe3f67SBaptiste Daroussin 	 * Zero is used as an EOF marker, so return 1 instead.
13983bbe3f67SBaptiste Daroussin 	 */
13993bbe3f67SBaptiste Daroussin 	return (sum == 0 ? 1 : sum);
14003bbe3f67SBaptiste Daroussin }
14013bbe3f67SBaptiste Daroussin 
14023bbe3f67SBaptiste Daroussin static int
14033bbe3f67SBaptiste Daroussin asciifile(FILE *f)
14043bbe3f67SBaptiste Daroussin {
14053bbe3f67SBaptiste Daroussin 	unsigned char buf[BUFSIZ];
14063bbe3f67SBaptiste Daroussin 	size_t cnt;
14073bbe3f67SBaptiste Daroussin 
14083bbe3f67SBaptiste Daroussin 	if (f == NULL)
14093bbe3f67SBaptiste Daroussin 		return (1);
14103bbe3f67SBaptiste Daroussin 
14113bbe3f67SBaptiste Daroussin 	rewind(f);
14123bbe3f67SBaptiste Daroussin 	cnt = fread(buf, 1, sizeof(buf), f);
14133bbe3f67SBaptiste Daroussin 	return (memchr(buf, '\0', cnt) == NULL);
14143bbe3f67SBaptiste Daroussin }
14153bbe3f67SBaptiste Daroussin 
14163bbe3f67SBaptiste Daroussin #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
14173bbe3f67SBaptiste Daroussin 
14183bbe3f67SBaptiste Daroussin static char *
14193bbe3f67SBaptiste Daroussin match_function(const long *f, int pos, FILE *fp)
14203bbe3f67SBaptiste Daroussin {
14213bbe3f67SBaptiste Daroussin 	unsigned char buf[FUNCTION_CONTEXT_SIZE];
14223bbe3f67SBaptiste Daroussin 	size_t nc;
14233bbe3f67SBaptiste Daroussin 	int last = lastline;
14243bbe3f67SBaptiste Daroussin 	const char *state = NULL;
14253bbe3f67SBaptiste Daroussin 
14263bbe3f67SBaptiste Daroussin 	lastline = pos;
14273bbe3f67SBaptiste Daroussin 	while (pos > last) {
14283bbe3f67SBaptiste Daroussin 		fseek(fp, f[pos - 1], SEEK_SET);
14293bbe3f67SBaptiste Daroussin 		nc = f[pos] - f[pos - 1];
14303bbe3f67SBaptiste Daroussin 		if (nc >= sizeof(buf))
14313bbe3f67SBaptiste Daroussin 			nc = sizeof(buf) - 1;
14323bbe3f67SBaptiste Daroussin 		nc = fread(buf, 1, nc, fp);
14333bbe3f67SBaptiste Daroussin 		if (nc > 0) {
14343bbe3f67SBaptiste Daroussin 			buf[nc] = '\0';
14353bbe3f67SBaptiste Daroussin 			buf[strcspn(buf, "\n")] = '\0';
14363bbe3f67SBaptiste Daroussin 			if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
14373bbe3f67SBaptiste Daroussin 				if (begins_with(buf, "private:")) {
14383bbe3f67SBaptiste Daroussin 					if (!state)
14393bbe3f67SBaptiste Daroussin 						state = " (private)";
14403bbe3f67SBaptiste Daroussin 				} else if (begins_with(buf, "protected:")) {
14413bbe3f67SBaptiste Daroussin 					if (!state)
14423bbe3f67SBaptiste Daroussin 						state = " (protected)";
14433bbe3f67SBaptiste Daroussin 				} else if (begins_with(buf, "public:")) {
14443bbe3f67SBaptiste Daroussin 					if (!state)
14453bbe3f67SBaptiste Daroussin 						state = " (public)";
14463bbe3f67SBaptiste Daroussin 				} else {
14473bbe3f67SBaptiste Daroussin 					strlcpy(lastbuf, buf, sizeof lastbuf);
14483bbe3f67SBaptiste Daroussin 					if (state)
14493bbe3f67SBaptiste Daroussin 						strlcat(lastbuf, state,
14503bbe3f67SBaptiste Daroussin 						    sizeof lastbuf);
14513bbe3f67SBaptiste Daroussin 					lastmatchline = pos;
14523bbe3f67SBaptiste Daroussin 					return lastbuf;
14533bbe3f67SBaptiste Daroussin 				}
14543bbe3f67SBaptiste Daroussin 			}
14553bbe3f67SBaptiste Daroussin 		}
14563bbe3f67SBaptiste Daroussin 		pos--;
14573bbe3f67SBaptiste Daroussin 	}
14583bbe3f67SBaptiste Daroussin 	return lastmatchline > 0 ? lastbuf : NULL;
14593bbe3f67SBaptiste Daroussin }
14603bbe3f67SBaptiste Daroussin 
14613bbe3f67SBaptiste Daroussin /* dump accumulated "context" diff changes */
14623bbe3f67SBaptiste Daroussin static void
14633bbe3f67SBaptiste Daroussin dump_context_vec(FILE *f1, FILE *f2, int flags)
14643bbe3f67SBaptiste Daroussin {
14653bbe3f67SBaptiste Daroussin 	struct context_vec *cvp = context_vec_start;
14663bbe3f67SBaptiste Daroussin 	int lowa, upb, lowc, upd, do_output;
14673bbe3f67SBaptiste Daroussin 	int a, b, c, d;
14683bbe3f67SBaptiste Daroussin 	char ch, *f;
14693bbe3f67SBaptiste Daroussin 
14703bbe3f67SBaptiste Daroussin 	if (context_vec_start > context_vec_ptr)
14713bbe3f67SBaptiste Daroussin 		return;
14723bbe3f67SBaptiste Daroussin 
14733bbe3f67SBaptiste Daroussin 	b = d = 0;		/* gcc */
147442c88c41SBaptiste Daroussin 	lowa = MAX(1, cvp->a - diff_context);
147542c88c41SBaptiste Daroussin 	upb = MIN(len[0], context_vec_ptr->b + diff_context);
147642c88c41SBaptiste Daroussin 	lowc = MAX(1, cvp->c - diff_context);
147742c88c41SBaptiste Daroussin 	upd = MIN(len[1], context_vec_ptr->d + diff_context);
14783bbe3f67SBaptiste Daroussin 
14793bbe3f67SBaptiste Daroussin 	diff_output("***************");
14803bbe3f67SBaptiste Daroussin 	if ((flags & D_PROTOTYPE)) {
14813bbe3f67SBaptiste Daroussin 		f = match_function(ixold, lowa-1, f1);
14823bbe3f67SBaptiste Daroussin 		if (f != NULL)
14833bbe3f67SBaptiste Daroussin 			diff_output(" %s", f);
14843bbe3f67SBaptiste Daroussin 	}
14853bbe3f67SBaptiste Daroussin 	diff_output("\n*** ");
14863bbe3f67SBaptiste Daroussin 	range(lowa, upb, ",");
14873bbe3f67SBaptiste Daroussin 	diff_output(" ****\n");
14883bbe3f67SBaptiste Daroussin 
14893bbe3f67SBaptiste Daroussin 	/*
14903bbe3f67SBaptiste Daroussin 	 * Output changes to the "old" file.  The first loop suppresses
14913bbe3f67SBaptiste Daroussin 	 * output if there were no changes to the "old" file (we'll see
14923bbe3f67SBaptiste Daroussin 	 * the "old" lines as context in the "new" list).
14933bbe3f67SBaptiste Daroussin 	 */
14943bbe3f67SBaptiste Daroussin 	do_output = 0;
14953bbe3f67SBaptiste Daroussin 	for (; cvp <= context_vec_ptr; cvp++)
14963bbe3f67SBaptiste Daroussin 		if (cvp->a <= cvp->b) {
14973bbe3f67SBaptiste Daroussin 			cvp = context_vec_start;
14983bbe3f67SBaptiste Daroussin 			do_output++;
14993bbe3f67SBaptiste Daroussin 			break;
15003bbe3f67SBaptiste Daroussin 		}
15013bbe3f67SBaptiste Daroussin 	if (do_output) {
15023bbe3f67SBaptiste Daroussin 		while (cvp <= context_vec_ptr) {
15033bbe3f67SBaptiste Daroussin 			a = cvp->a;
15043bbe3f67SBaptiste Daroussin 			b = cvp->b;
15053bbe3f67SBaptiste Daroussin 			c = cvp->c;
15063bbe3f67SBaptiste Daroussin 			d = cvp->d;
15073bbe3f67SBaptiste Daroussin 
15083bbe3f67SBaptiste Daroussin 			if (a <= b && c <= d)
15093bbe3f67SBaptiste Daroussin 				ch = 'c';
15103bbe3f67SBaptiste Daroussin 			else
15113bbe3f67SBaptiste Daroussin 				ch = (a <= b) ? 'd' : 'a';
15123bbe3f67SBaptiste Daroussin 
15133bbe3f67SBaptiste Daroussin 			if (ch == 'a')
15143bbe3f67SBaptiste Daroussin 				fetch(ixold, lowa, b, f1, ' ', 0, flags);
15153bbe3f67SBaptiste Daroussin 			else {
15163bbe3f67SBaptiste Daroussin 				fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
15173bbe3f67SBaptiste Daroussin 				fetch(ixold, a, b, f1,
15183bbe3f67SBaptiste Daroussin 				    ch == 'c' ? '!' : '-', 0, flags);
15193bbe3f67SBaptiste Daroussin 			}
15203bbe3f67SBaptiste Daroussin 			lowa = b + 1;
15213bbe3f67SBaptiste Daroussin 			cvp++;
15223bbe3f67SBaptiste Daroussin 		}
15233bbe3f67SBaptiste Daroussin 		fetch(ixold, b + 1, upb, f1, ' ', 0, flags);
15243bbe3f67SBaptiste Daroussin 	}
15253bbe3f67SBaptiste Daroussin 	/* output changes to the "new" file */
15263bbe3f67SBaptiste Daroussin 	diff_output("--- ");
15273bbe3f67SBaptiste Daroussin 	range(lowc, upd, ",");
15283bbe3f67SBaptiste Daroussin 	diff_output(" ----\n");
15293bbe3f67SBaptiste Daroussin 
15303bbe3f67SBaptiste Daroussin 	do_output = 0;
15313bbe3f67SBaptiste Daroussin 	for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
15323bbe3f67SBaptiste Daroussin 		if (cvp->c <= cvp->d) {
15333bbe3f67SBaptiste Daroussin 			cvp = context_vec_start;
15343bbe3f67SBaptiste Daroussin 			do_output++;
15353bbe3f67SBaptiste Daroussin 			break;
15363bbe3f67SBaptiste Daroussin 		}
15373bbe3f67SBaptiste Daroussin 	if (do_output) {
15383bbe3f67SBaptiste Daroussin 		while (cvp <= context_vec_ptr) {
15393bbe3f67SBaptiste Daroussin 			a = cvp->a;
15403bbe3f67SBaptiste Daroussin 			b = cvp->b;
15413bbe3f67SBaptiste Daroussin 			c = cvp->c;
15423bbe3f67SBaptiste Daroussin 			d = cvp->d;
15433bbe3f67SBaptiste Daroussin 
15443bbe3f67SBaptiste Daroussin 			if (a <= b && c <= d)
15453bbe3f67SBaptiste Daroussin 				ch = 'c';
15463bbe3f67SBaptiste Daroussin 			else
15473bbe3f67SBaptiste Daroussin 				ch = (a <= b) ? 'd' : 'a';
15483bbe3f67SBaptiste Daroussin 
15493bbe3f67SBaptiste Daroussin 			if (ch == 'd')
15503bbe3f67SBaptiste Daroussin 				fetch(ixnew, lowc, d, f2, ' ', 0, flags);
15513bbe3f67SBaptiste Daroussin 			else {
15523bbe3f67SBaptiste Daroussin 				fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
15533bbe3f67SBaptiste Daroussin 				fetch(ixnew, c, d, f2,
15543bbe3f67SBaptiste Daroussin 				    ch == 'c' ? '!' : '+', 0, flags);
15553bbe3f67SBaptiste Daroussin 			}
15563bbe3f67SBaptiste Daroussin 			lowc = d + 1;
15573bbe3f67SBaptiste Daroussin 			cvp++;
15583bbe3f67SBaptiste Daroussin 		}
15593bbe3f67SBaptiste Daroussin 		fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
15603bbe3f67SBaptiste Daroussin 	}
15613bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
15623bbe3f67SBaptiste Daroussin }
15633bbe3f67SBaptiste Daroussin 
15643bbe3f67SBaptiste Daroussin /* dump accumulated "unified" diff changes */
15653bbe3f67SBaptiste Daroussin static void
15663bbe3f67SBaptiste Daroussin dump_unified_vec(FILE *f1, FILE *f2, int flags)
15673bbe3f67SBaptiste Daroussin {
15683bbe3f67SBaptiste Daroussin 	struct context_vec *cvp = context_vec_start;
15693bbe3f67SBaptiste Daroussin 	int lowa, upb, lowc, upd;
15703bbe3f67SBaptiste Daroussin 	int a, b, c, d;
15713bbe3f67SBaptiste Daroussin 	char ch, *f;
15723bbe3f67SBaptiste Daroussin 
15733bbe3f67SBaptiste Daroussin 	if (context_vec_start > context_vec_ptr)
15743bbe3f67SBaptiste Daroussin 		return;
15753bbe3f67SBaptiste Daroussin 
15763bbe3f67SBaptiste Daroussin 	b = d = 0;		/* gcc */
157742c88c41SBaptiste Daroussin 	lowa = MAX(1, cvp->a - diff_context);
157842c88c41SBaptiste Daroussin 	upb = MIN(len[0], context_vec_ptr->b + diff_context);
157942c88c41SBaptiste Daroussin 	lowc = MAX(1, cvp->c - diff_context);
158042c88c41SBaptiste Daroussin 	upd = MIN(len[1], context_vec_ptr->d + diff_context);
15813bbe3f67SBaptiste Daroussin 
15823bbe3f67SBaptiste Daroussin 	diff_output("@@ -");
15833bbe3f67SBaptiste Daroussin 	uni_range(lowa, upb);
15843bbe3f67SBaptiste Daroussin 	diff_output(" +");
15853bbe3f67SBaptiste Daroussin 	uni_range(lowc, upd);
15863bbe3f67SBaptiste Daroussin 	diff_output(" @@");
15873bbe3f67SBaptiste Daroussin 	if ((flags & D_PROTOTYPE)) {
15883bbe3f67SBaptiste Daroussin 		f = match_function(ixold, lowa-1, f1);
15893bbe3f67SBaptiste Daroussin 		if (f != NULL)
15903bbe3f67SBaptiste Daroussin 			diff_output(" %s", f);
15913bbe3f67SBaptiste Daroussin 	}
15923bbe3f67SBaptiste Daroussin 	diff_output("\n");
15933bbe3f67SBaptiste Daroussin 
15943bbe3f67SBaptiste Daroussin 	/*
15953bbe3f67SBaptiste Daroussin 	 * Output changes in "unified" diff format--the old and new lines
15963bbe3f67SBaptiste Daroussin 	 * are printed together.
15973bbe3f67SBaptiste Daroussin 	 */
15983bbe3f67SBaptiste Daroussin 	for (; cvp <= context_vec_ptr; cvp++) {
15993bbe3f67SBaptiste Daroussin 		a = cvp->a;
16003bbe3f67SBaptiste Daroussin 		b = cvp->b;
16013bbe3f67SBaptiste Daroussin 		c = cvp->c;
16023bbe3f67SBaptiste Daroussin 		d = cvp->d;
16033bbe3f67SBaptiste Daroussin 
16043bbe3f67SBaptiste Daroussin 		/*
16053bbe3f67SBaptiste Daroussin 		 * c: both new and old changes
16063bbe3f67SBaptiste Daroussin 		 * d: only changes in the old file
16073bbe3f67SBaptiste Daroussin 		 * a: only changes in the new file
16083bbe3f67SBaptiste Daroussin 		 */
16093bbe3f67SBaptiste Daroussin 		if (a <= b && c <= d)
16103bbe3f67SBaptiste Daroussin 			ch = 'c';
16113bbe3f67SBaptiste Daroussin 		else
16123bbe3f67SBaptiste Daroussin 			ch = (a <= b) ? 'd' : 'a';
16133bbe3f67SBaptiste Daroussin 
16143bbe3f67SBaptiste Daroussin 		switch (ch) {
16153bbe3f67SBaptiste Daroussin 		case 'c':
16163bbe3f67SBaptiste Daroussin 			fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
16173bbe3f67SBaptiste Daroussin 			fetch(ixold, a, b, f1, '-', 0, flags);
16183bbe3f67SBaptiste Daroussin 			fetch(ixnew, c, d, f2, '+', 0, flags);
16193bbe3f67SBaptiste Daroussin 			break;
16203bbe3f67SBaptiste Daroussin 		case 'd':
16213bbe3f67SBaptiste Daroussin 			fetch(ixold, lowa, a - 1, f1, ' ', 0, flags);
16223bbe3f67SBaptiste Daroussin 			fetch(ixold, a, b, f1, '-', 0, flags);
16233bbe3f67SBaptiste Daroussin 			break;
16243bbe3f67SBaptiste Daroussin 		case 'a':
16253bbe3f67SBaptiste Daroussin 			fetch(ixnew, lowc, c - 1, f2, ' ', 0, flags);
16263bbe3f67SBaptiste Daroussin 			fetch(ixnew, c, d, f2, '+', 0, flags);
16273bbe3f67SBaptiste Daroussin 			break;
16283bbe3f67SBaptiste Daroussin 		}
16293bbe3f67SBaptiste Daroussin 		lowa = b + 1;
16303bbe3f67SBaptiste Daroussin 		lowc = d + 1;
16313bbe3f67SBaptiste Daroussin 	}
16323bbe3f67SBaptiste Daroussin 	fetch(ixnew, d + 1, upd, f2, ' ', 0, flags);
16333bbe3f67SBaptiste Daroussin 
16343bbe3f67SBaptiste Daroussin 	context_vec_ptr = context_vec_start - 1;
16353bbe3f67SBaptiste Daroussin }
16363bbe3f67SBaptiste Daroussin 
16373bbe3f67SBaptiste Daroussin static void
16383bbe3f67SBaptiste Daroussin print_header(const char *file1, const char *file2)
16393bbe3f67SBaptiste Daroussin {
16403bbe3f67SBaptiste Daroussin 	const char *time_format;
16413bbe3f67SBaptiste Daroussin 	char buf1[256];
16423bbe3f67SBaptiste Daroussin 	char buf2[256];
16433bbe3f67SBaptiste Daroussin 	char end1[10];
16443bbe3f67SBaptiste Daroussin 	char end2[10];
164558cf4d86SJilles Tjoelker 	struct tm tm1, tm2, *tm_ptr1, *tm_ptr2;
1646385a67dcSJilles Tjoelker 	int nsec1 = stb1.st_mtim.tv_nsec;
1647385a67dcSJilles Tjoelker 	int nsec2 = stb2.st_mtim.tv_nsec;
16483bbe3f67SBaptiste Daroussin 
16493bbe3f67SBaptiste Daroussin 	time_format = "%Y-%m-%d %H:%M:%S";
16503bbe3f67SBaptiste Daroussin 
16513bbe3f67SBaptiste Daroussin 	if (cflag)
16523bbe3f67SBaptiste Daroussin 		time_format = "%c";
165358cf4d86SJilles Tjoelker 	tm_ptr1 = localtime_r(&stb1.st_mtime, &tm1);
165458cf4d86SJilles Tjoelker 	tm_ptr2 = localtime_r(&stb2.st_mtime, &tm2);
16553bbe3f67SBaptiste Daroussin 	strftime(buf1, 256, time_format, tm_ptr1);
16563bbe3f67SBaptiste Daroussin 	strftime(buf2, 256, time_format, tm_ptr2);
16573bbe3f67SBaptiste Daroussin 	if (!cflag) {
16583bbe3f67SBaptiste Daroussin 		strftime(end1, 10, "%z", tm_ptr1);
16593bbe3f67SBaptiste Daroussin 		strftime(end2, 10, "%z", tm_ptr2);
16603bbe3f67SBaptiste Daroussin 		sprintf(buf1, "%s.%.9d %s", buf1, nsec1, end1);
16613bbe3f67SBaptiste Daroussin 		sprintf(buf2, "%s.%.9d %s", buf2, nsec2, end2);
16623bbe3f67SBaptiste Daroussin 	}
16633bbe3f67SBaptiste Daroussin 	if (label[0] != NULL)
16643bbe3f67SBaptiste Daroussin 		diff_output("%s %s\n", diff_format == D_CONTEXT ? "***" : "---",
16653bbe3f67SBaptiste Daroussin 		    label[0]);
16663bbe3f67SBaptiste Daroussin 	else
16673bbe3f67SBaptiste Daroussin 		diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "***" : "---",
16683bbe3f67SBaptiste Daroussin 		    file1, buf1);
16693bbe3f67SBaptiste Daroussin 	if (label[1] != NULL)
16703bbe3f67SBaptiste Daroussin 		diff_output("%s %s\n", diff_format == D_CONTEXT ? "---" : "+++",
16713bbe3f67SBaptiste Daroussin 		    label[1]);
16723bbe3f67SBaptiste Daroussin 	else
16733bbe3f67SBaptiste Daroussin 		diff_output("%s %s\t%s\n", diff_format == D_CONTEXT ? "---" : "+++",
16743bbe3f67SBaptiste Daroussin 		    file2, buf2);
16753bbe3f67SBaptiste Daroussin }
1676