xref: /onnv-gate/usr/src/cmd/diff/diff.c (revision 236:cc3576010d16)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*236Schin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
320Sstevel@tonic-gate  * The Regents of the University of California
330Sstevel@tonic-gate  * All Rights Reserved
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
360Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
370Sstevel@tonic-gate  * contributors.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  *	diff - differential file comparison
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  *	Uses an algorithm  which finds
460Sstevel@tonic-gate  *	a pair of longest identical subsequences in the two
470Sstevel@tonic-gate  *	files.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  *	The major goal is to generate the match vector J.
500Sstevel@tonic-gate  *	J[i] is the index of the line in file1 corresponding
510Sstevel@tonic-gate  *	to line i file0. J[i] = 0 if there is no
520Sstevel@tonic-gate  *	such line in file1.
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  *	Lines are hashed so as to work in core. All potential
550Sstevel@tonic-gate  *	matches are located by sorting the lines of each file
560Sstevel@tonic-gate  *	on the hash (called value). In particular, this
570Sstevel@tonic-gate  *	collects the equivalence classes in file1 together.
580Sstevel@tonic-gate  *	Subroutine equiv  replaces the value of each line in
590Sstevel@tonic-gate  *	file0 by the index of the first element of its
600Sstevel@tonic-gate  *	matching equivalence in (the reordered) file1.
610Sstevel@tonic-gate  *	To save space equiv squeezes file1 into a single
620Sstevel@tonic-gate  *	array member in which the equivalence classes
630Sstevel@tonic-gate  *	are simply concatenated, except that their first
640Sstevel@tonic-gate  *	members are flagged by changing sign.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  *	Next the indices that point into member are unsorted into
670Sstevel@tonic-gate  *	array class according to the original order of file0.
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  *	The cleverness lies in routine stone. This marches
700Sstevel@tonic-gate  *	through the lines of file0, developing a vector klist
710Sstevel@tonic-gate  *	of "k-candidates". At step i a k-candidate is a matched
720Sstevel@tonic-gate  *	pair of lines x,y (x in file0 y in file1) such that
730Sstevel@tonic-gate  *	there is a common subsequence of lenght k
740Sstevel@tonic-gate  *	between the first i lines of file0 and the first y
750Sstevel@tonic-gate  *	lines of file1, but there is no such subsequence for
760Sstevel@tonic-gate  *	any smaller y. x is the earliest possible mate to y
770Sstevel@tonic-gate  *	that occurs in such a subsequence.
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  *	Whenever any of the members of the equivalence class of
800Sstevel@tonic-gate  *	lines in file1 matable to a line in file0 has serial number
810Sstevel@tonic-gate  *	less than the y of some k-candidate, that k-candidate
820Sstevel@tonic-gate  *	with the smallest such y is replaced. The new
830Sstevel@tonic-gate  *	k-candidate is chained (via pred) to the current
840Sstevel@tonic-gate  *	k-1 candidate so that the actual subsequence can
850Sstevel@tonic-gate  *	be recovered. When a member has serial number greater
860Sstevel@tonic-gate  *	that the y of all k-candidates, the klist is extended.
870Sstevel@tonic-gate  *	At the end, the longest subsequence is pulled out
880Sstevel@tonic-gate  *	and placed in the array J by unravel.
890Sstevel@tonic-gate  *
900Sstevel@tonic-gate  *	With J in hand, the matches there recorded are
910Sstevel@tonic-gate  *	checked against reality to assure that no spurious
920Sstevel@tonic-gate  *	matches have crept in due to hashing. If they have,
930Sstevel@tonic-gate  *	they are broken, and "jackpot " is recorded--a harmless
940Sstevel@tonic-gate  *	matter except that a true match for a spuriously
950Sstevel@tonic-gate  *	mated line may now be unnecessarily reported as a change.
960Sstevel@tonic-gate  *
970Sstevel@tonic-gate  *	Much of the complexity of the program comes simply
980Sstevel@tonic-gate  *	from trying to minimize core utilization and
990Sstevel@tonic-gate  *	maximize the range of doable problems by dynamically
1000Sstevel@tonic-gate  *	allocating what is needed and reusing what is not.
1010Sstevel@tonic-gate  *	The core requirements for problems larger than somewhat
1020Sstevel@tonic-gate  *	are (in words) 2*length(file0) + length(file1) +
1030Sstevel@tonic-gate  *	3*(number of k-candidates installed),  typically about
1040Sstevel@tonic-gate  *	6n words for files of length n.
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate #include <stdio.h>
1070Sstevel@tonic-gate #include <wchar.h>
1080Sstevel@tonic-gate #include <ctype.h>
1090Sstevel@tonic-gate #include <stdlib.h>
1100Sstevel@tonic-gate #include <limits.h>
1110Sstevel@tonic-gate #include <sys/types.h>
1120Sstevel@tonic-gate #include <sys/stat.h>
1130Sstevel@tonic-gate #include <sys/wait.h>
1140Sstevel@tonic-gate #include <unistd.h>
1150Sstevel@tonic-gate #include <signal.h>
1160Sstevel@tonic-gate #include <fcntl.h>
1170Sstevel@tonic-gate #include <dirent.h>
1180Sstevel@tonic-gate #include <locale.h>
1190Sstevel@tonic-gate #include <stdarg.h>
1200Sstevel@tonic-gate #include <errno.h>
1210Sstevel@tonic-gate #include <string.h>
1220Sstevel@tonic-gate #include "diff.h"
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate #define	CHRTRAN(x)	(iflag ? (iswupper(x) ? towlower(x) : (x)) : (x))
1250Sstevel@tonic-gate #define	NCCHRTRAN(x)	(iswupper(x) ? towlower(x) : (x))
1260Sstevel@tonic-gate #define	max(a, b)	((a) < (b) ? (b) : (a))
1270Sstevel@tonic-gate #define	min(a, b)	((a) > (b) ? (b) : (a))
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate int pref, suff;		/* length of prefix and suffix */
1300Sstevel@tonic-gate int *class;		/* will be overlaid on file[0] */
1310Sstevel@tonic-gate int *member;		/* will be overlaid on file[1] */
1320Sstevel@tonic-gate int *klist;		/* will be overlaid on file[0] after class */
1330Sstevel@tonic-gate struct cand *clist;	/* merely a free storage pot for candidates */
1340Sstevel@tonic-gate int clen = 0;
1350Sstevel@tonic-gate int *J;			/* will be overlaid on class */
1360Sstevel@tonic-gate long *ixold;		/* will be overlaid on klist */
1370Sstevel@tonic-gate long *ixnew;		/* will be overlaid on file[1] */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static int	mbcurmax;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate static void error(const char *);
1420Sstevel@tonic-gate static void unravel(int);
1430Sstevel@tonic-gate static void	check(void);
1440Sstevel@tonic-gate static void	output(void);
1450Sstevel@tonic-gate static void	change(int, int, int, int);
1460Sstevel@tonic-gate static void	range(int, int, char *);
1470Sstevel@tonic-gate static void	fetch(long *, int, int, int, char *, int);
1480Sstevel@tonic-gate static void	dump_context_vec(void);
1490Sstevel@tonic-gate static void	diffdir(char **);
1500Sstevel@tonic-gate static void	setfile(char **, char **, char *);
1510Sstevel@tonic-gate static void	scanpr(struct dir *, int, char *, char *,
1520Sstevel@tonic-gate 	char *, char *, char *);
1530Sstevel@tonic-gate static void	only(struct dir *, int);
1540Sstevel@tonic-gate static void	sort(struct line *, int);
1550Sstevel@tonic-gate static void	unsort(struct line *, int, int *);
1560Sstevel@tonic-gate static void	filename(char **, char **, struct stat *, char **);
1570Sstevel@tonic-gate static void	prepare(int, char *);
1580Sstevel@tonic-gate static void	prune(void);
1590Sstevel@tonic-gate static void	equiv(struct line *, int, struct line *, int, int *);
1600Sstevel@tonic-gate static void	done(void);
1610Sstevel@tonic-gate static void	noroom(void);
1620Sstevel@tonic-gate static void	usage(void);
1630Sstevel@tonic-gate static void	initbuf(FILE *, int, long);
1640Sstevel@tonic-gate static void	resetbuf(int);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static int	stone(int *, int, int *, int *);
1670Sstevel@tonic-gate static int	newcand(int, int, int);
1680Sstevel@tonic-gate static int	search(int *, int, int);
1690Sstevel@tonic-gate static int	skipline(int);
1700Sstevel@tonic-gate static int	readhash(FILE *, int, char *);
1710Sstevel@tonic-gate static int	entcmp(struct dir *, struct dir *);
1720Sstevel@tonic-gate static int	compare(struct dir *);
1730Sstevel@tonic-gate static int	calldiff(char *);
1740Sstevel@tonic-gate static int	binary(int);
1750Sstevel@tonic-gate static int	filebinary(FILE *);
1760Sstevel@tonic-gate static int	isbinary(char *, int);
1770Sstevel@tonic-gate static int	useless(char *);
1780Sstevel@tonic-gate static char	*copytemp(char *);
1790Sstevel@tonic-gate static char *pfiletype(mode_t);
1800Sstevel@tonic-gate static struct dir *setupdir(char *);
1810Sstevel@tonic-gate static wint_t	getbufwchar(int, int *);
1820Sstevel@tonic-gate static wint_t	wcput(wint_t);
1830Sstevel@tonic-gate static long	ftellbuf(int);
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  * error message string constants
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate #define	BAD_MB_ERR	"invalid multibyte character encountered"
1900Sstevel@tonic-gate #define	NO_PROCS_ERR	"no more processes"
1910Sstevel@tonic-gate #define	NO_MEM_ERR	"out of memory"
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static void *
talloc(size_t n)1940Sstevel@tonic-gate talloc(size_t n)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	void *p;
1970Sstevel@tonic-gate 	p = malloc(n);
1980Sstevel@tonic-gate 	if (p == NULL)
1990Sstevel@tonic-gate 		noroom();
2000Sstevel@tonic-gate 	return (p);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate static void *
ralloc(void * p,size_t n)2040Sstevel@tonic-gate ralloc(void *p, size_t n)	/* compacting reallocation */
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	void	*q;
2070Sstevel@tonic-gate #if 0
2080Sstevel@tonic-gate 	free(p);
2090Sstevel@tonic-gate #endif
2100Sstevel@tonic-gate 	q = realloc(p, n);
2110Sstevel@tonic-gate 	if (q == NULL)
2120Sstevel@tonic-gate 		noroom();
2130Sstevel@tonic-gate 	return (q);
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 
217*236Schin int
main(int argc,char ** argv)2180Sstevel@tonic-gate main(int argc, char **argv)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	int k;
2210Sstevel@tonic-gate 	char *argp;
2220Sstevel@tonic-gate 	int flag;			/* option flag read by getopt() */
2230Sstevel@tonic-gate 	int i, j;
2240Sstevel@tonic-gate 	char buf1[BUFSIZ], buf2[BUFSIZ];
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2280Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
2290Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
2300Sstevel@tonic-gate #endif
2310Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	mbcurmax = MB_CUR_MAX;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	diffargv = argv;
2360Sstevel@tonic-gate 	whichtemp = 0;
2370Sstevel@tonic-gate 	while ((flag = getopt(argc, argv, "bitwcuefhnlrsC:D:S:U:")) != EOF) {
2380Sstevel@tonic-gate 		switch (flag) {
2390Sstevel@tonic-gate 		case 'D':
2400Sstevel@tonic-gate 			opt = D_IFDEF;
2410Sstevel@tonic-gate 			wantelses = 1;
2420Sstevel@tonic-gate 			ifdef1 = "";
2430Sstevel@tonic-gate 			ifdef2 = optarg;
2440Sstevel@tonic-gate 			break;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		case 'b':
2470Sstevel@tonic-gate 			bflag = 1;
2480Sstevel@tonic-gate 			break;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		case 'C':
2510Sstevel@tonic-gate 		case 'U':
2520Sstevel@tonic-gate 			opt = D_CONTEXT;
2530Sstevel@tonic-gate 			argp = optarg;
2540Sstevel@tonic-gate 			context = 0;
2550Sstevel@tonic-gate 			while (*argp >= '0' && *argp <= '9')
2560Sstevel@tonic-gate 				context *= 10, context += *argp++ - '0';
2570Sstevel@tonic-gate 			if (*argp)
2580Sstevel@tonic-gate 				error(gettext("use [ -C num | -U num ]"));
2590Sstevel@tonic-gate 			if (flag == 'U')
2600Sstevel@tonic-gate 				uflag++;
2610Sstevel@tonic-gate 			else
2620Sstevel@tonic-gate 				uflag = 0;
2630Sstevel@tonic-gate 			break;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		case 'c':
2660Sstevel@tonic-gate 		case 'u':
2670Sstevel@tonic-gate 			opt = D_CONTEXT;
2680Sstevel@tonic-gate 			context = 3;
2690Sstevel@tonic-gate 			if (flag == 'u')
2700Sstevel@tonic-gate 				uflag++;
2710Sstevel@tonic-gate 			else
2720Sstevel@tonic-gate 				uflag = 0;
2730Sstevel@tonic-gate 			break;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		case 'e':
2760Sstevel@tonic-gate 			opt = D_EDIT;
2770Sstevel@tonic-gate 			break;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		case 'f':
2800Sstevel@tonic-gate 			opt = D_REVERSE;
2810Sstevel@tonic-gate 			break;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 		case 'h':
2840Sstevel@tonic-gate 			hflag++;
2850Sstevel@tonic-gate 			break;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		case 'i':
2880Sstevel@tonic-gate 			iflag = 1;
2890Sstevel@tonic-gate 			break;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		case 'l':
2920Sstevel@tonic-gate 			lflag = 1;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		case 'n':
2960Sstevel@tonic-gate 			opt = D_NREVERSE;
2970Sstevel@tonic-gate 			break;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 		case 'r':
3000Sstevel@tonic-gate 			rflag = 1;
3010Sstevel@tonic-gate 			break;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		case 'S':
3040Sstevel@tonic-gate 			(void) strcpy(start, optarg);
3050Sstevel@tonic-gate 			break;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		case 's':
3080Sstevel@tonic-gate 			sflag = 1;
3090Sstevel@tonic-gate 			break;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 		case 't':
3120Sstevel@tonic-gate 			tflag = 1;
3130Sstevel@tonic-gate 			break;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		case 'w':
3160Sstevel@tonic-gate 			wflag = 1;
3170Sstevel@tonic-gate 			break;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		case '?':
3200Sstevel@tonic-gate 			usage();
3210Sstevel@tonic-gate 			break;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		default:
3240Sstevel@tonic-gate 			/* Not sure how it would get here, but just in case */
3250Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
3260Sstevel@tonic-gate 			(void) fprintf(stderr,
3270Sstevel@tonic-gate 				gettext("invalid option -%c\n"), flag);
3280Sstevel@tonic-gate 			usage();
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	argc -= optind;
3330Sstevel@tonic-gate 	argv = &argv[optind];
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	if (opt != D_CONTEXT && uflag)
3360Sstevel@tonic-gate 		uflag = 0;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	if (argc != 2)
3390Sstevel@tonic-gate 		error(gettext("two filename arguments required"));
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	file1 = argv[0];
3420Sstevel@tonic-gate 	file2 = argv[1];
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (hflag) {
3450Sstevel@tonic-gate 		if (opt) {
3460Sstevel@tonic-gate 			error(
3470Sstevel@tonic-gate gettext("-h doesn't support -e, -f, -n, -c, or -I"));
3480Sstevel@tonic-gate 		} else {
3490Sstevel@tonic-gate 			diffargv[0] = "diffh";
3500Sstevel@tonic-gate 			(void) execv(diffh, diffargv);
3510Sstevel@tonic-gate 			(void) fprintf(stderr, "diffh: ");
3520Sstevel@tonic-gate 			perror(diffh);
3530Sstevel@tonic-gate 			status = 2;
3540Sstevel@tonic-gate 			done();
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (strcmp(file1, "-") == 0) {
3600Sstevel@tonic-gate 		if (fstat(fileno(stdin), &stb1) == 0)
3610Sstevel@tonic-gate 			stb1.st_mode = S_IFREG;
3620Sstevel@tonic-gate 		else {
3630Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
3640Sstevel@tonic-gate 			perror("stdin");
3650Sstevel@tonic-gate 			done();
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 	} else if (stat(file1, &stb1) < 0) {
3680Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
3690Sstevel@tonic-gate 		perror(file1);
3700Sstevel@tonic-gate 		done();
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (strcmp(file2, "-") == 0) {
3740Sstevel@tonic-gate 		if (strcmp(file1, "-") == 0)
3750Sstevel@tonic-gate 			error(gettext("cannot specify - -"));
3760Sstevel@tonic-gate 		else {
3770Sstevel@tonic-gate 			if (fstat(fileno(stdin), &stb2) == 0)
3780Sstevel@tonic-gate 				stb2.st_mode = S_IFREG;
3790Sstevel@tonic-gate 			else {
3800Sstevel@tonic-gate 				(void) fprintf(stderr, "diff: ");
3810Sstevel@tonic-gate 				perror("stdin");
3820Sstevel@tonic-gate 				done();
3830Sstevel@tonic-gate 			}
3840Sstevel@tonic-gate 		}
3850Sstevel@tonic-gate 	} else if (stat(file2, &stb2) < 0) {
3860Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
3870Sstevel@tonic-gate 		perror(file2);
3880Sstevel@tonic-gate 		done();
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	if ((stb1.st_mode & S_IFMT) == S_IFDIR &&
3920Sstevel@tonic-gate 	    (stb2.st_mode & S_IFMT) == S_IFDIR) {
3930Sstevel@tonic-gate 		diffdir(argv);
3940Sstevel@tonic-gate 		done();
3950Sstevel@tonic-gate 	    }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	filename(&file1, &file2, &stb1, &input_file1);
3980Sstevel@tonic-gate 	filename(&file2, &file1, &stb2, &input_file2);
3990Sstevel@tonic-gate 	if ((input[0] = fopen(file1, "r")) == NULL) {
4000Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
4010Sstevel@tonic-gate 		perror(file1);
4020Sstevel@tonic-gate 		status = 2;
4030Sstevel@tonic-gate 		done();
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 	initbuf(input[0], 0, 0);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if ((input[1] = fopen(file2, "r")) == NULL) {
4080Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
4090Sstevel@tonic-gate 		perror(file2);
4100Sstevel@tonic-gate 		status = 2;
4110Sstevel@tonic-gate 		done();
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 	initbuf(input[1], 1, 0);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if (stb1.st_size != stb2.st_size)
4160Sstevel@tonic-gate 		goto notsame;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	for (;;) {
4190Sstevel@tonic-gate 		i = fread(buf1, 1, BUFSIZ, input[0]);
4200Sstevel@tonic-gate 		j = fread(buf2, 1, BUFSIZ, input[1]);
4210Sstevel@tonic-gate 		if (ferror(input[0]) || ferror(input[1])) {
4220Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
4230Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Error reading "));
4240Sstevel@tonic-gate 			perror(ferror(input[0])? file1:file2);
4250Sstevel@tonic-gate 			(void) fclose(input[0]);
4260Sstevel@tonic-gate 			(void) fclose(input[1]);
4270Sstevel@tonic-gate 			status = 2;
4280Sstevel@tonic-gate 			done();
4290Sstevel@tonic-gate 		}
4300Sstevel@tonic-gate 		if (i != j)
4310Sstevel@tonic-gate 			goto notsame;
4320Sstevel@tonic-gate 		if (i == 0 && j == 0) {
4330Sstevel@tonic-gate 			/* files are the same; diff -D needs to print one */
4340Sstevel@tonic-gate 			if (opt == D_IFDEF) {
4350Sstevel@tonic-gate 				rewind(input[0]);
4360Sstevel@tonic-gate 				while (i = fread(buf1, 1, BUFSIZ, input[0]))
4370Sstevel@tonic-gate 					(void) fwrite(buf1, 1, i, stdout);
4380Sstevel@tonic-gate 			}
4390Sstevel@tonic-gate 			(void) fclose(input[0]);
4400Sstevel@tonic-gate 			(void) fclose(input[1]);
4410Sstevel@tonic-gate 			status = 0;
4420Sstevel@tonic-gate 			goto same;		/* files don't differ */
4430Sstevel@tonic-gate 		}
4440Sstevel@tonic-gate 		for (j = 0; j < i; j++)
4450Sstevel@tonic-gate 			if (buf1[j] != buf2[j])
4460Sstevel@tonic-gate 				goto notsame;
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate notsame:
4500Sstevel@tonic-gate 	status = 1;
4510Sstevel@tonic-gate 	if (filebinary(input[0]) || filebinary(input[1])) {
4520Sstevel@tonic-gate 		if (ferror(input[0]) || ferror(input[1])) {
4530Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
4540Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Error reading "));
4550Sstevel@tonic-gate 			perror(ferror(input[0])? file1:file2);
4560Sstevel@tonic-gate 			(void) fclose(input[0]);
4570Sstevel@tonic-gate 			(void) fclose(input[1]);
4580Sstevel@tonic-gate 			status = 2;
4590Sstevel@tonic-gate 			done();
4600Sstevel@tonic-gate 		}
4610Sstevel@tonic-gate 		(void) printf(gettext("Binary files %s and %s differ\n"),
4620Sstevel@tonic-gate 		    file1, file2);
4630Sstevel@tonic-gate 		(void) fclose(input[0]);
4640Sstevel@tonic-gate 		(void) fclose(input[1]);
4650Sstevel@tonic-gate 		done();
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 	prepare(0, file1);
4680Sstevel@tonic-gate 	prepare(1, file2);
4690Sstevel@tonic-gate 	prune();
4700Sstevel@tonic-gate 	sort(sfile[0], slen[0]);
4710Sstevel@tonic-gate 	sort(sfile[1], slen[1]);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	member = (int *)file[1];
4740Sstevel@tonic-gate 	equiv(sfile[0], slen[0], sfile[1], slen[1], member);
4750Sstevel@tonic-gate 	member = (int *)ralloc((void *)member, (slen[1] + 2) * sizeof (int));
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	class = (int *)file[0];
4780Sstevel@tonic-gate 	unsort(sfile[0], slen[0], class);
4790Sstevel@tonic-gate 	class = (int *)ralloc((void *)class, (slen[0] + 2) * sizeof (int));
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	klist = (int *)talloc((slen[0] + 2) * sizeof (int));
4820Sstevel@tonic-gate 	clist = (struct cand *)talloc(sizeof (cand));
4830Sstevel@tonic-gate 	k = stone(class, slen[0], member, klist);
4840Sstevel@tonic-gate 	free((void *)member);
4850Sstevel@tonic-gate 	free((void *)class);
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	J = (int *)talloc((len[0] + 2) * sizeof (int));
4880Sstevel@tonic-gate 	unravel(klist[k]);
4890Sstevel@tonic-gate 	free((char *)clist);
4900Sstevel@tonic-gate 	free((char *)klist);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	ixold = (long *)talloc((len[0] + 2) * sizeof (long));
4930Sstevel@tonic-gate 	ixnew = (long *)talloc((len[1] + 2) * sizeof (long));
4940Sstevel@tonic-gate 	check();
4950Sstevel@tonic-gate 	output();
4960Sstevel@tonic-gate 	status = anychange;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate same:
4990Sstevel@tonic-gate 	if (opt == D_CONTEXT && anychange == 0)
5000Sstevel@tonic-gate 		(void) printf(gettext("No differences encountered\n"));
5010Sstevel@tonic-gate 	done();
5020Sstevel@tonic-gate 	/*NOTREACHED*/
503*236Schin 	return (0);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate static int
stone(int * a,int n,int * b,int * c)5070Sstevel@tonic-gate stone(int *a, int n, int *b, int *c)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate 	int i, k, y;
5100Sstevel@tonic-gate 	int j, l;
5110Sstevel@tonic-gate 	int oldc, tc;
5120Sstevel@tonic-gate 	int oldl;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	k = 0;
5150Sstevel@tonic-gate 	c[0] = newcand(0, 0, 0);
5160Sstevel@tonic-gate 	for (i = 1; i <= n; i++) {
5170Sstevel@tonic-gate 		j = a[i];
5180Sstevel@tonic-gate 		if (j == 0)
5190Sstevel@tonic-gate 			continue;
5200Sstevel@tonic-gate 		y = -b[j];
5210Sstevel@tonic-gate 		oldl = 0;
5220Sstevel@tonic-gate 		oldc = c[0];
5230Sstevel@tonic-gate 		do {
5240Sstevel@tonic-gate 			if (y <= clist[oldc].y)
5250Sstevel@tonic-gate 				continue;
5260Sstevel@tonic-gate 			l = search(c, k, y);
5270Sstevel@tonic-gate 			if (l != oldl+1)
5280Sstevel@tonic-gate 				oldc = c[l-1];
5290Sstevel@tonic-gate 			if (l <= k) {
5300Sstevel@tonic-gate 				if (clist[c[l]].y <= y)
5310Sstevel@tonic-gate 					continue;
5320Sstevel@tonic-gate 				tc = c[l];
5330Sstevel@tonic-gate 				c[l] = newcand(i, y, oldc);
5340Sstevel@tonic-gate 				oldc = tc;
5350Sstevel@tonic-gate 				oldl = l;
5360Sstevel@tonic-gate 			} else {
5370Sstevel@tonic-gate 				c[l] = newcand(i, y, oldc);
5380Sstevel@tonic-gate 				k++;
5390Sstevel@tonic-gate 				break;
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 		} while ((y = b[++j]) > 0);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 	return (k);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate static int
newcand(int x,int y,int pred)5470Sstevel@tonic-gate newcand(int x, int y, int pred)
5480Sstevel@tonic-gate {
5490Sstevel@tonic-gate 	struct cand *q;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	clist = (struct cand *)ralloc((void *)clist, ++clen * sizeof (cand));
5520Sstevel@tonic-gate 	q = clist + clen -1;
5530Sstevel@tonic-gate 	q->x = x;
5540Sstevel@tonic-gate 	q->y = y;
5550Sstevel@tonic-gate 	q->pred = pred;
5560Sstevel@tonic-gate 	return (clen - 1);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate static int
search(int * c,int k,int y)5600Sstevel@tonic-gate search(int *c, int k, int y)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	int i, j, l;
5630Sstevel@tonic-gate 	int t;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	if (clist[c[k]].y < y)	/* quick look for typical case */
5660Sstevel@tonic-gate 		return (k + 1);
5670Sstevel@tonic-gate 	i = 0;
5680Sstevel@tonic-gate 	j = k+1;
5690Sstevel@tonic-gate 	while ((l = (i + j) / 2) > i) {
5700Sstevel@tonic-gate 		t = clist[c[l]].y;
5710Sstevel@tonic-gate 		if (t > y)
5720Sstevel@tonic-gate 			j = l;
5730Sstevel@tonic-gate 		else if (t < y)
5740Sstevel@tonic-gate 			i = l;
5750Sstevel@tonic-gate 		else
5760Sstevel@tonic-gate 			return (l);
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate 	return (l + 1);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static void
unravel(int p)5820Sstevel@tonic-gate unravel(int p)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	int i;
5850Sstevel@tonic-gate 	struct cand *q;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	for (i = 0; i <= len[0]; i++)
5880Sstevel@tonic-gate 		J[i] = i <= pref ? i :
5890Sstevel@tonic-gate 			i > len[0] - suff ? i + len[1] - len[0]:
5900Sstevel@tonic-gate 			0;
5910Sstevel@tonic-gate 	for (q = clist + p; q->y != 0; q = clist + q->pred)
5920Sstevel@tonic-gate 		J[q->x + pref] = q->y + pref;
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * check does double duty:
5970Sstevel@tonic-gate  * 1. ferret out any fortuitous correspondences due to confounding by
5980Sstevel@tonic-gate  * hashing (which result in "jackpot")
5990Sstevel@tonic-gate  * 2. collect random access indexes to the two files
6000Sstevel@tonic-gate  */
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate static void
check(void)6030Sstevel@tonic-gate check(void)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	wint_t	c, d;
6060Sstevel@tonic-gate 	int i, j;
6070Sstevel@tonic-gate 	/* int jackpot; */
6080Sstevel@tonic-gate 	int	mlen;
6090Sstevel@tonic-gate 	long ctold, ctnew;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	resetbuf(0);
6120Sstevel@tonic-gate 	resetbuf(1);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	j = 1;
6150Sstevel@tonic-gate 	ixold[0] = ixnew[0] = 0;
6160Sstevel@tonic-gate 	/* jackpot = 0; */
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/*
6190Sstevel@tonic-gate 	 * ctold and ctnew are byte positions within the file (suitable for
6200Sstevel@tonic-gate 	 * lseek()).  After we get a character with getwc(), instead of
6210Sstevel@tonic-gate 	 * just incrementing the byte position by 1, we have to determine
6220Sstevel@tonic-gate 	 * how many bytes the character actually is.  This is the reason for
6230Sstevel@tonic-gate 	 * the wctomb() calls here and in skipline().
6240Sstevel@tonic-gate 	 */
6250Sstevel@tonic-gate 	ctold = ctnew = 0;
6260Sstevel@tonic-gate 	for (i = 1; i <= len[0]; i++) {
6270Sstevel@tonic-gate 		if (J[i] == 0) {
6280Sstevel@tonic-gate 			ixold[i] = ctold += skipline(0);
6290Sstevel@tonic-gate 			continue;
6300Sstevel@tonic-gate 		}
6310Sstevel@tonic-gate 		while (j < J[i]) {
6320Sstevel@tonic-gate 			ixnew[j] = ctnew += skipline(1);
6330Sstevel@tonic-gate 			j++;
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 		if (bflag || wflag || iflag) {
6360Sstevel@tonic-gate 			for (;;) {
6370Sstevel@tonic-gate 				c = getbufwchar(0, &mlen);
6380Sstevel@tonic-gate 				ctold += mlen;
6390Sstevel@tonic-gate 				d = getbufwchar(1, &mlen);
6400Sstevel@tonic-gate 				ctnew += mlen;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 				if (bflag && iswspace(c) && iswspace(d)) {
6430Sstevel@tonic-gate 					while (iswspace(c)) {
6440Sstevel@tonic-gate 						if (c == '\n' || c == WEOF)
6450Sstevel@tonic-gate 							break;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 						c = getbufwchar(0, &mlen);
6480Sstevel@tonic-gate 						ctold += mlen;
6490Sstevel@tonic-gate 					}
6500Sstevel@tonic-gate 					while (iswspace(d)) {
6510Sstevel@tonic-gate 						if (d == '\n' || d == WEOF)
6520Sstevel@tonic-gate 							break;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 						d = getbufwchar(1, &mlen);
6550Sstevel@tonic-gate 						ctnew += mlen;
6560Sstevel@tonic-gate 					}
6570Sstevel@tonic-gate 				} else if (wflag) {
6580Sstevel@tonic-gate 					while (iswspace(c) && c != '\n') {
6590Sstevel@tonic-gate 						c = getbufwchar(0, &mlen);
6600Sstevel@tonic-gate 						ctold += mlen;
6610Sstevel@tonic-gate 					}
6620Sstevel@tonic-gate 					while (iswspace(d) && d != '\n') {
6630Sstevel@tonic-gate 						d = getbufwchar(1, &mlen);
6640Sstevel@tonic-gate 						ctnew += mlen;
6650Sstevel@tonic-gate 					}
6660Sstevel@tonic-gate 				}
6670Sstevel@tonic-gate 				if (c == WEOF || d == WEOF) {
6680Sstevel@tonic-gate 					if (c != d) {
6690Sstevel@tonic-gate 						/* jackpot++; */
6700Sstevel@tonic-gate 						J[i] = 0;
6710Sstevel@tonic-gate 						if (c != '\n' && c != WEOF)
6720Sstevel@tonic-gate 							ctold += skipline(0);
6730Sstevel@tonic-gate 						if (d != '\n' && d != WEOF)
6740Sstevel@tonic-gate 							ctnew += skipline(1);
6750Sstevel@tonic-gate 						break;
6760Sstevel@tonic-gate 					}
6770Sstevel@tonic-gate 					break;
6780Sstevel@tonic-gate 				} else {
6790Sstevel@tonic-gate 					if (CHRTRAN(c) != CHRTRAN(d)) {
6800Sstevel@tonic-gate 						/* jackpot++; */
6810Sstevel@tonic-gate 						J[i] = 0;
6820Sstevel@tonic-gate 						if (c != '\n')
6830Sstevel@tonic-gate 							ctold += skipline(0);
6840Sstevel@tonic-gate 						if (d != '\n')
6850Sstevel@tonic-gate 							ctnew += skipline(1);
6860Sstevel@tonic-gate 						break;
6870Sstevel@tonic-gate 					}
6880Sstevel@tonic-gate 					if (c == '\n')
6890Sstevel@tonic-gate 						break;
6900Sstevel@tonic-gate 				}
6910Sstevel@tonic-gate 			}
6920Sstevel@tonic-gate 		} else {
6930Sstevel@tonic-gate 			for (;;) {
6940Sstevel@tonic-gate 				c = getbufwchar(0, &mlen);
6950Sstevel@tonic-gate 				ctold += mlen;
6960Sstevel@tonic-gate 				d = getbufwchar(1, &mlen);
6970Sstevel@tonic-gate 				ctnew += mlen;
6980Sstevel@tonic-gate 				if (c != d) {
6990Sstevel@tonic-gate 					/* jackpot++; */
7000Sstevel@tonic-gate 					J[i] = 0;
7010Sstevel@tonic-gate 					if (c != '\n' && c != WEOF)
7020Sstevel@tonic-gate 						ctold += skipline(0);
7030Sstevel@tonic-gate 					if (d != '\n' && d != WEOF)
7040Sstevel@tonic-gate 						ctnew += skipline(1);
7050Sstevel@tonic-gate 					break;
7060Sstevel@tonic-gate 				}
7070Sstevel@tonic-gate 				if (c == '\n' || c == WEOF)
7080Sstevel@tonic-gate 					break;
7090Sstevel@tonic-gate 			}
7100Sstevel@tonic-gate 		}
7110Sstevel@tonic-gate 		ixold[i] = ctold;
7120Sstevel@tonic-gate 		ixnew[j] = ctnew;
7130Sstevel@tonic-gate 		j++;
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 	for (; j <= len[1]; j++) {
7160Sstevel@tonic-gate 		ixnew[j] = ctnew += skipline(1);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate /*	if(jackpot)			*/
7200Sstevel@tonic-gate /*		fprintf(stderr, "diff: jackpot\n");	*/
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate static int
skipline(int f)7240Sstevel@tonic-gate skipline(int f)
7250Sstevel@tonic-gate {
7260Sstevel@tonic-gate 	int i;
7270Sstevel@tonic-gate 	wint_t c;
7280Sstevel@tonic-gate 	int	mlen;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	for (i = 1; c = getbufwchar(f, &mlen); ) {
7310Sstevel@tonic-gate 		if (c == '\n' || c == WEOF)
7320Sstevel@tonic-gate 			return (i);
7330Sstevel@tonic-gate 		i += mlen;
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 	return (i);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate static void
output(void)7390Sstevel@tonic-gate output(void)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	int m;
7420Sstevel@tonic-gate 	wint_t	wc;
7430Sstevel@tonic-gate 	int i0, i1, j1;
7440Sstevel@tonic-gate 	int j0;
7450Sstevel@tonic-gate 	int	mlen;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	resetbuf(0);
7480Sstevel@tonic-gate 	resetbuf(1);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	m = len[0];
7510Sstevel@tonic-gate 	J[0] = 0;
7520Sstevel@tonic-gate 	J[m + 1] = len[1] + 1;
7530Sstevel@tonic-gate 	if (opt != D_EDIT)
7540Sstevel@tonic-gate 		for (i0 = 1; i0 <= m; i0 = i1+1) {
7550Sstevel@tonic-gate 			while (i0 <= m && J[i0] == J[i0 - 1] + 1)
7560Sstevel@tonic-gate 				i0++;
7570Sstevel@tonic-gate 			j0 = J[i0 - 1] + 1;
7580Sstevel@tonic-gate 			i1 = i0 - 1;
7590Sstevel@tonic-gate 			while (i1 < m && J[i1 + 1] == 0)
7600Sstevel@tonic-gate 				i1++;
7610Sstevel@tonic-gate 			j1 = J[i1 + 1] - 1;
7620Sstevel@tonic-gate 			J[i1] = j1;
7630Sstevel@tonic-gate 			change(i0, i1, j0, j1);
7640Sstevel@tonic-gate 		} else for (i0 = m; i0 >= 1; i0 = i1 - 1) {
7650Sstevel@tonic-gate 			while (i0 >= 1 && J[i0] == J[i0 + 1] - 1 && J[i0] != 0)
7660Sstevel@tonic-gate 				i0--;
7670Sstevel@tonic-gate 			j0 = J[i0 + 1] - 1;
7680Sstevel@tonic-gate 			i1 = i0 + 1;
7690Sstevel@tonic-gate 			while (i1 > 1 && J[i1 - 1] == 0)
7700Sstevel@tonic-gate 				i1--;
7710Sstevel@tonic-gate 			j1 = J[i1 - 1] + 1;
7720Sstevel@tonic-gate 			J[i1] = j1;
7730Sstevel@tonic-gate 			change(i1, i0, j1, j0);
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 	if (m == 0)
7760Sstevel@tonic-gate 		change(1, 0, 1, len[1]);
7770Sstevel@tonic-gate 	if (opt == D_IFDEF) {
7780Sstevel@tonic-gate 		for (;;) {
7790Sstevel@tonic-gate 			wc = getbufwchar(0, &mlen);
7800Sstevel@tonic-gate 			if (wc == WEOF)
7810Sstevel@tonic-gate 				return;
7820Sstevel@tonic-gate 			(void) wcput(wc);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 	if (anychange && opt == D_CONTEXT)
7860Sstevel@tonic-gate 		dump_context_vec();
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate  * indicate that there is a difference between lines a and b of the from file
7920Sstevel@tonic-gate  * to get to lines c to d of the to file.
7930Sstevel@tonic-gate  * If a is greater then b then there are no lines in the from file involved
7940Sstevel@tonic-gate  * and this means that there were lines appended (beginning at b).
7950Sstevel@tonic-gate  * If c is greater than d then there are lines missing from the to file.
7960Sstevel@tonic-gate  */
7970Sstevel@tonic-gate static void
change(int a,int b,int c,int d)7980Sstevel@tonic-gate change(int a, int b, int c, int d)
7990Sstevel@tonic-gate {
8000Sstevel@tonic-gate 	char	time_buf[BUFSIZ];
8010Sstevel@tonic-gate 	char	*dcmsg;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	if (opt != D_IFDEF && a > b && c > d)
8040Sstevel@tonic-gate 		return;
8050Sstevel@tonic-gate 	if (anychange == 0) {
8060Sstevel@tonic-gate 		anychange = 1;
8070Sstevel@tonic-gate 		if (opt == D_CONTEXT) {
8080Sstevel@tonic-gate 			/*
8090Sstevel@tonic-gate 			 * TRANSLATION_NOTE_FOR_DC
8100Sstevel@tonic-gate 			 * This message is the format of file
8110Sstevel@tonic-gate 			 * timestamps written with the -C and
8120Sstevel@tonic-gate 			 * -c options.
8130Sstevel@tonic-gate 			 * %a -- locale's abbreviated weekday name
8140Sstevel@tonic-gate 			 * %b -- locale's abbreviated month name
8150Sstevel@tonic-gate 			 * %e -- day of month [1,31]
8160Sstevel@tonic-gate 			 * %T -- Time as %H:%M:%S
8170Sstevel@tonic-gate 			 * %Y -- Year, including the century
8180Sstevel@tonic-gate 			 */
8190Sstevel@tonic-gate 			dcmsg = dcgettext(NULL, "%a %b %e %T %Y", LC_TIME);
8200Sstevel@tonic-gate 			(void) cftime(time_buf, dcmsg, &stb1.st_mtime);
8210Sstevel@tonic-gate 			if (uflag)
8220Sstevel@tonic-gate 				(void) printf("--- %s	%s\n", input_file1,
8230Sstevel@tonic-gate 				    time_buf);
8240Sstevel@tonic-gate 			else
8250Sstevel@tonic-gate 				(void) printf("*** %s	%s\n", input_file1,
8260Sstevel@tonic-gate 				    time_buf);
8270Sstevel@tonic-gate 			(void) cftime(time_buf, dcmsg, &stb2.st_mtime);
8280Sstevel@tonic-gate 			if (uflag)
8290Sstevel@tonic-gate 				(void) printf("+++ %s	%s\n", input_file2,
8300Sstevel@tonic-gate 				    time_buf);
8310Sstevel@tonic-gate 			else
8320Sstevel@tonic-gate 				(void) printf("--- %s	%s\n", input_file2,
8330Sstevel@tonic-gate 				    time_buf);
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 			context_vec_start = (struct context_vec *)
8360Sstevel@tonic-gate 					    malloc(MAX_CONTEXT *
8370Sstevel@tonic-gate 					    sizeof (struct context_vec));
8380Sstevel@tonic-gate 			if (context_vec_start == NULL)
8390Sstevel@tonic-gate 				error(gettext(NO_MEM_ERR));
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 			context_vec_end = context_vec_start + (MAX_CONTEXT - 1);
8420Sstevel@tonic-gate 			context_vec_ptr = context_vec_start - 1;
8430Sstevel@tonic-gate 		}
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	if (opt == D_CONTEXT) {
8470Sstevel@tonic-gate 		/*
8480Sstevel@tonic-gate 		 * if this new change is within 'context' lines of
8490Sstevel@tonic-gate 		 * the previous change, just add it to the change
8500Sstevel@tonic-gate 		 * record.  If the record is full or if this
8510Sstevel@tonic-gate 		 * change is more than 'context' lines from the previous
8520Sstevel@tonic-gate 		 * change, dump the record, reset it & add the new change.
8530Sstevel@tonic-gate 		 */
8540Sstevel@tonic-gate 		if (context_vec_ptr >= context_vec_end ||
8550Sstevel@tonic-gate 		    (context_vec_ptr >= context_vec_start &&
8560Sstevel@tonic-gate 		    a > (context_vec_ptr->b + 2 * context) &&
8570Sstevel@tonic-gate 		    c > (context_vec_ptr->d + 2 * context)))
8580Sstevel@tonic-gate 			dump_context_vec();
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		context_vec_ptr++;
8610Sstevel@tonic-gate 		context_vec_ptr->a = a;
8620Sstevel@tonic-gate 		context_vec_ptr->b = b;
8630Sstevel@tonic-gate 		context_vec_ptr->c = c;
8640Sstevel@tonic-gate 		context_vec_ptr->d = d;
8650Sstevel@tonic-gate 		return;
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	switch (opt) {
8690Sstevel@tonic-gate 	case D_NORMAL:
8700Sstevel@tonic-gate 	case D_EDIT:
8710Sstevel@tonic-gate 		range(a, b, ",");
8720Sstevel@tonic-gate 		(void) putchar(a > b ? 'a' : c > d ? 'd' : 'c');
8730Sstevel@tonic-gate 		if (opt == D_NORMAL) range(c, d, ",");
8740Sstevel@tonic-gate 		(void) printf("\n");
8750Sstevel@tonic-gate 		break;
8760Sstevel@tonic-gate 	case D_REVERSE:
8770Sstevel@tonic-gate 		(void) putchar(a > b ? 'a' : c > d ? 'd' : 'c');
8780Sstevel@tonic-gate 		range(a, b, " ");
8790Sstevel@tonic-gate 		(void) printf("\n");
8800Sstevel@tonic-gate 		break;
8810Sstevel@tonic-gate 	case D_NREVERSE:
8820Sstevel@tonic-gate 		if (a > b)
8830Sstevel@tonic-gate 			(void) printf("a%d %d\n", b, d - c + 1);
8840Sstevel@tonic-gate 		else {
8850Sstevel@tonic-gate 			(void) printf("d%d %d\n", a, b - a + 1);
8860Sstevel@tonic-gate 			if (!(c > d))
8870Sstevel@tonic-gate 				/* add changed lines */
8880Sstevel@tonic-gate 				(void) printf("a%d %d\n", b, d - c + 1);
8890Sstevel@tonic-gate 		}
8900Sstevel@tonic-gate 		break;
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 	if (opt == D_NORMAL || opt == D_IFDEF) {
8930Sstevel@tonic-gate 		fetch(ixold, a, b, 0, "< ", 1);
8940Sstevel@tonic-gate 		if (a <= b && c <= d && opt == D_NORMAL)
8950Sstevel@tonic-gate 			(void) prints("---\n");
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate 	fetch(ixnew, c, d, 1, opt == D_NORMAL?"> ":empty, 0);
8980Sstevel@tonic-gate 	if ((opt == D_EDIT || opt == D_REVERSE) && c <= d)
8990Sstevel@tonic-gate 		(void) prints(".\n");
9000Sstevel@tonic-gate 	if (inifdef) {
9010Sstevel@tonic-gate 		(void) fprintf(stdout, "#endif /* %s */\n", endifname);
9020Sstevel@tonic-gate 		inifdef = 0;
9030Sstevel@tonic-gate 	}
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate static void
range(int a,int b,char * separator)9070Sstevel@tonic-gate range(int a, int b, char *separator)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate 	(void) printf("%d", a > b ? b : a);
9100Sstevel@tonic-gate 	if (a < b) {
9110Sstevel@tonic-gate 		(void) printf("%s%d", separator, b);
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate static void
fetch(long * f,int a,int b,int filen,char * s,int oldfile)9160Sstevel@tonic-gate fetch(long *f, int a, int b, int filen, char *s, int oldfile)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate 	int i;
9190Sstevel@tonic-gate 	int col;
9200Sstevel@tonic-gate 	int nc;
9210Sstevel@tonic-gate 	int mlen = 0;
9220Sstevel@tonic-gate 	wint_t	ch;
9230Sstevel@tonic-gate 	FILE	*lb;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	lb = input[filen];
9260Sstevel@tonic-gate 	/*
9270Sstevel@tonic-gate 	 * When doing #ifdef's, copy down to current line
9280Sstevel@tonic-gate 	 * if this is the first file, so that stuff makes it to output.
9290Sstevel@tonic-gate 	 */
9300Sstevel@tonic-gate 	if (opt == D_IFDEF && oldfile) {
9310Sstevel@tonic-gate 		long curpos = ftellbuf(filen);
9320Sstevel@tonic-gate 		/* print through if append (a>b), else to (nb: 0 vs 1 orig) */
9330Sstevel@tonic-gate 		nc = f[(a > b) ? b : (a - 1) ] - curpos;
9340Sstevel@tonic-gate 		for (i = 0; i < nc; i += mlen) {
9350Sstevel@tonic-gate 			ch = getbufwchar(filen, &mlen);
9360Sstevel@tonic-gate 			if (ch == WEOF) {
9370Sstevel@tonic-gate 				(void) putchar('\n');
9380Sstevel@tonic-gate 				break;
9390Sstevel@tonic-gate 			} else {
9400Sstevel@tonic-gate 				(void) wcput(ch);
9410Sstevel@tonic-gate 			}
9420Sstevel@tonic-gate 		}
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	if (a > b)
9450Sstevel@tonic-gate 		return;
9460Sstevel@tonic-gate 	if (opt == D_IFDEF) {
9470Sstevel@tonic-gate 		int oneflag = (*ifdef1 != '\0') != (*ifdef2 != '\0');
9480Sstevel@tonic-gate 		if (inifdef)
9490Sstevel@tonic-gate 			(void) fprintf(stdout, "#else /* %s%s */\n",
9500Sstevel@tonic-gate 			    oneflag && oldfile == 1 ? "!" : "", ifdef2);
9510Sstevel@tonic-gate 		else {
9520Sstevel@tonic-gate 			if (oneflag) {
9530Sstevel@tonic-gate 				/* There was only one ifdef given */
9540Sstevel@tonic-gate 				endifname = ifdef2;
9550Sstevel@tonic-gate 				if (oldfile)
9560Sstevel@tonic-gate 					(void) fprintf(stdout,
9570Sstevel@tonic-gate 					    "#ifndef %s\n", endifname);
9580Sstevel@tonic-gate 				else
9590Sstevel@tonic-gate 					(void) fprintf(stdout,
9600Sstevel@tonic-gate 					    "#ifdef %s\n", endifname);
9610Sstevel@tonic-gate 			} else {
9620Sstevel@tonic-gate 				endifname = oldfile ? ifdef1 : ifdef2;
9630Sstevel@tonic-gate 				(void) fprintf(stdout,
9640Sstevel@tonic-gate 					"#ifdef %s\n", endifname);
9650Sstevel@tonic-gate 			}
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 		inifdef = 1 + oldfile;
9680Sstevel@tonic-gate 	}
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	for (i = a; i <= b; i++) {
9710Sstevel@tonic-gate 		(void) fseek(lb, f[i - 1], SEEK_SET);
9720Sstevel@tonic-gate 		initbuf(lb, filen, f[i - 1]);
9730Sstevel@tonic-gate 		if (opt != D_IFDEF)
9740Sstevel@tonic-gate 			(void) prints(s);
9750Sstevel@tonic-gate 		col = 0;
9760Sstevel@tonic-gate 		while (ch = getbufwchar(filen, &mlen)) {
9770Sstevel@tonic-gate 			if (ch != '\n' && ch != WEOF) {
9780Sstevel@tonic-gate 				if (ch == '\t' && tflag)
9790Sstevel@tonic-gate 					do
9800Sstevel@tonic-gate 						(void) putchar(' ');
9810Sstevel@tonic-gate 					while (++col & 7);
9820Sstevel@tonic-gate 				else {
9830Sstevel@tonic-gate 					(void) wcput(ch);
9840Sstevel@tonic-gate 					col++;
9850Sstevel@tonic-gate 				}
9860Sstevel@tonic-gate 			} else
9870Sstevel@tonic-gate 				break;
9880Sstevel@tonic-gate 		}
9890Sstevel@tonic-gate 		(void) putchar('\n');
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate /*
9940Sstevel@tonic-gate  * hashing has the effect of
9950Sstevel@tonic-gate  * arranging line in 7-bit bytes and then
9960Sstevel@tonic-gate  * summing 1-s complement in 16-bit hunks
9970Sstevel@tonic-gate  */
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate static int
readhash(FILE * f,int filen,char * str)10000Sstevel@tonic-gate readhash(FILE *f, int filen, char *str)
10010Sstevel@tonic-gate {
10020Sstevel@tonic-gate 	long sum;
10030Sstevel@tonic-gate 	unsigned int	shift;
10040Sstevel@tonic-gate 	int space;
10050Sstevel@tonic-gate 	int t;
10060Sstevel@tonic-gate 	wint_t	wt;
10070Sstevel@tonic-gate 	int	mlen;
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	sum = 1;
10100Sstevel@tonic-gate 	space = 0;
10110Sstevel@tonic-gate 	if (!bflag && !wflag) {
10120Sstevel@tonic-gate 		if (iflag)
10130Sstevel@tonic-gate 			if (mbcurmax == 1) {
10140Sstevel@tonic-gate 				/* In this case, diff doesn't have to take */
10150Sstevel@tonic-gate 				/* care of multibyte characters. */
10160Sstevel@tonic-gate 				for (shift = 0; (t = getc(f)) != '\n';
10170Sstevel@tonic-gate 					shift += 7) {
10180Sstevel@tonic-gate 					if (t == EOF) {
10190Sstevel@tonic-gate 						if (shift) {
10200Sstevel@tonic-gate 							(void) fprintf(stderr,
10210Sstevel@tonic-gate 	gettext("Warning: missing newline at end of file %s\n"), str);
10220Sstevel@tonic-gate 							break;
10230Sstevel@tonic-gate 						} else
10240Sstevel@tonic-gate 							return (0);
10250Sstevel@tonic-gate 					}
10260Sstevel@tonic-gate 					sum += (isupper(t) ? tolower(t) : t) <<
10270Sstevel@tonic-gate 						(shift &= HALFMASK);
10280Sstevel@tonic-gate 				}
10290Sstevel@tonic-gate 			} else {
10300Sstevel@tonic-gate 				/* In this case, diff needs to take care of */
10310Sstevel@tonic-gate 				/* multibyte characters. */
10320Sstevel@tonic-gate 				for (shift = 0;
10330Sstevel@tonic-gate 				(wt = getbufwchar(filen, &mlen)) != '\n';
10340Sstevel@tonic-gate 					shift += 7) {
10350Sstevel@tonic-gate 					if (wt == WEOF) {
10360Sstevel@tonic-gate 						if (shift) {
10370Sstevel@tonic-gate 							(void) fprintf(stderr,
10380Sstevel@tonic-gate 	gettext("Warning: missing newline at end of file %s\n"), str);
10390Sstevel@tonic-gate 							break;
10400Sstevel@tonic-gate 						} else
10410Sstevel@tonic-gate 							return (0);
10420Sstevel@tonic-gate 					}
10430Sstevel@tonic-gate 					sum += NCCHRTRAN(wt) <<
10440Sstevel@tonic-gate 						(shift &= HALFMASK);
10450Sstevel@tonic-gate 				}
10460Sstevel@tonic-gate 			}
10470Sstevel@tonic-gate 		else
10480Sstevel@tonic-gate 			/* In this case, diff doesn't have to take care of */
10490Sstevel@tonic-gate 			/* multibyte characters. */
10500Sstevel@tonic-gate 			for (shift = 0; (t = getc(f)) != '\n'; shift += 7) {
10510Sstevel@tonic-gate 				if (t == EOF) {
10520Sstevel@tonic-gate 					if (shift) {
10530Sstevel@tonic-gate 						(void) fprintf(stderr,
10540Sstevel@tonic-gate 	gettext("Warning: missing newline at end of file %s\n"), str);
10550Sstevel@tonic-gate 						break;
10560Sstevel@tonic-gate 					} else
10570Sstevel@tonic-gate 						return (0);
10580Sstevel@tonic-gate 				}
10590Sstevel@tonic-gate 				sum += (long)t << (shift &= HALFMASK);
10600Sstevel@tonic-gate 			}
10610Sstevel@tonic-gate 	} else {
10620Sstevel@tonic-gate 		/* In this case, diff needs to take care of */
10630Sstevel@tonic-gate 		/* multibyte characters. */
10640Sstevel@tonic-gate 		for (shift = 0; ; ) {
10650Sstevel@tonic-gate 			wt = getbufwchar(filen, &mlen);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 			if (wt != '\n' && iswspace(wt)) {
10680Sstevel@tonic-gate 				space++;
10690Sstevel@tonic-gate 				continue;
10700Sstevel@tonic-gate 			} else {
10710Sstevel@tonic-gate 				switch (wt) {
10720Sstevel@tonic-gate 				case WEOF:
10730Sstevel@tonic-gate 					if (shift) {
10740Sstevel@tonic-gate 						(void) fprintf(stderr,
10750Sstevel@tonic-gate 	gettext("Warning: missing newline at end of file %s\n"), str);
10760Sstevel@tonic-gate 						break;
10770Sstevel@tonic-gate 					} else
10780Sstevel@tonic-gate 						return (0);
10790Sstevel@tonic-gate 				default:
10800Sstevel@tonic-gate 					if (space && !wflag) {
10810Sstevel@tonic-gate 						shift += 7;
10820Sstevel@tonic-gate 						space = 0;
10830Sstevel@tonic-gate 					}
10840Sstevel@tonic-gate 					sum += CHRTRAN(wt) <<
10850Sstevel@tonic-gate 						(shift &= HALFMASK);
10860Sstevel@tonic-gate 					shift += 7;
10870Sstevel@tonic-gate 					continue;
10880Sstevel@tonic-gate 				case L'\n':
10890Sstevel@tonic-gate 					break;
10900Sstevel@tonic-gate 				}
10910Sstevel@tonic-gate 			}
10920Sstevel@tonic-gate 			break;
10930Sstevel@tonic-gate 		}
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 	return (sum);
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate /* dump accumulated "context" diff changes */
11000Sstevel@tonic-gate static void
dump_context_vec(void)11010Sstevel@tonic-gate dump_context_vec(void)
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate 	int	a, b, c, d;
11040Sstevel@tonic-gate 	char	ch;
11050Sstevel@tonic-gate 	struct	context_vec *cvp = context_vec_start;
11060Sstevel@tonic-gate 	int	lowa, upb, lowc, upd;
11070Sstevel@tonic-gate 	int	do_output;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	if (cvp > context_vec_ptr)
11100Sstevel@tonic-gate 		return;
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	lowa = max(1, cvp->a - context);
11130Sstevel@tonic-gate 	upb  = min(len[0], context_vec_ptr->b + context);
11140Sstevel@tonic-gate 	lowc = max(1, cvp->c - context);
11150Sstevel@tonic-gate 	upd  = min(len[1], context_vec_ptr->d + context);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	if (uflag) {
11180Sstevel@tonic-gate 		(void) printf("@@ -%d,%d +%d,%d @@\n",
11190Sstevel@tonic-gate 		    lowa, upb - lowa + 1,
11200Sstevel@tonic-gate 		    lowc, upd - lowc + 1);
11210Sstevel@tonic-gate 	} else {
11220Sstevel@tonic-gate 		(void) printf("***************\n*** ");
11230Sstevel@tonic-gate 		range(lowa, upb, ",");
11240Sstevel@tonic-gate 		(void) printf(" ****\n");
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	/*
11280Sstevel@tonic-gate 	 * output changes to the "old" file.  The first loop suppresses
11290Sstevel@tonic-gate 	 * output if there were no changes to the "old" file (we'll see
11300Sstevel@tonic-gate 	 * the "old" lines as context in the "new" list).
11310Sstevel@tonic-gate 	 */
11320Sstevel@tonic-gate 	if (uflag)
11330Sstevel@tonic-gate 		do_output = 1;
11340Sstevel@tonic-gate 	else
11350Sstevel@tonic-gate 		for (do_output = 0; cvp <= context_vec_ptr; cvp++)
11360Sstevel@tonic-gate 			if (cvp->a <= cvp->b) {
11370Sstevel@tonic-gate 				cvp = context_vec_start;
11380Sstevel@tonic-gate 				do_output++;
11390Sstevel@tonic-gate 				break;
11400Sstevel@tonic-gate 			}
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	if (do_output) {
11430Sstevel@tonic-gate 		while (cvp <= context_vec_ptr) {
11440Sstevel@tonic-gate 			a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 			if (a <= b && c <= d)
11470Sstevel@tonic-gate 				ch = 'c';
11480Sstevel@tonic-gate 			else
11490Sstevel@tonic-gate 				ch = (a <= b) ? 'd' : 'a';
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 			if (ch == 'a') {
11520Sstevel@tonic-gate 				/* The last argument should not affect */
11530Sstevel@tonic-gate 				/* the behavior of fetch() */
11540Sstevel@tonic-gate 				fetch(ixold, lowa, b, 0, uflag ? " " : "  ", 1);
11550Sstevel@tonic-gate 				if (uflag)
11560Sstevel@tonic-gate 					fetch(ixnew, c, d, 1, "+", 0);
11570Sstevel@tonic-gate 			} else if (ch == 'd') {
11580Sstevel@tonic-gate 				fetch(ixold, lowa, a - 1, 0, uflag ? " " :
11590Sstevel@tonic-gate 					    "  ", 1);
11600Sstevel@tonic-gate 				fetch(ixold, a, b, 0, uflag ? "-" : "- ", 1);
11610Sstevel@tonic-gate 			} else {
11620Sstevel@tonic-gate 				/* The last argument should not affect */
11630Sstevel@tonic-gate 				/* the behavior of fetch() */
11640Sstevel@tonic-gate 				fetch(ixold, lowa, a-1, 0, uflag ? " " : "  ",
11650Sstevel@tonic-gate 				    1);
11660Sstevel@tonic-gate 				if (uflag) {
11670Sstevel@tonic-gate 					fetch(ixold, a, b, 0, "-", 1);
11680Sstevel@tonic-gate 					fetch(ixnew, c, d, 1, "+", 0);
11690Sstevel@tonic-gate 				} else
11700Sstevel@tonic-gate 					fetch(ixold, a, b, 0, "! ", 1);
11710Sstevel@tonic-gate 			}
11720Sstevel@tonic-gate 			lowa = b + 1;
11730Sstevel@tonic-gate 			cvp++;
11740Sstevel@tonic-gate 		}
11750Sstevel@tonic-gate 		/* The last argument should not affect the behavior */
11760Sstevel@tonic-gate 		/* of fetch() */
11770Sstevel@tonic-gate 		fetch(ixold, b+1, upb, 0, uflag ? " " : "  ", 1);
11780Sstevel@tonic-gate 	}
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	if (uflag) {
11810Sstevel@tonic-gate 		context_vec_ptr = context_vec_start - 1;
11820Sstevel@tonic-gate 		return;
11830Sstevel@tonic-gate 	}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	/* output changes to the "new" file */
11860Sstevel@tonic-gate 	(void) printf("--- ");
11870Sstevel@tonic-gate 	range(lowc, upd, ",");
11880Sstevel@tonic-gate 	(void) printf(" ----\n");
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	do_output = 0;
11910Sstevel@tonic-gate 	for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
11920Sstevel@tonic-gate 		if (cvp->c <= cvp->d) {
11930Sstevel@tonic-gate 			cvp = context_vec_start;
11940Sstevel@tonic-gate 			do_output++;
11950Sstevel@tonic-gate 			break;
11960Sstevel@tonic-gate 		}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	if (do_output) {
11990Sstevel@tonic-gate 		while (cvp <= context_vec_ptr) {
12000Sstevel@tonic-gate 			a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 			if (a <= b && c <= d)
12030Sstevel@tonic-gate 				ch = 'c';
12040Sstevel@tonic-gate 			else
12050Sstevel@tonic-gate 				ch = (a <= b) ? 'd' : 'a';
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 			if (ch == 'd')
12080Sstevel@tonic-gate 				/* The last argument should not affect */
12090Sstevel@tonic-gate 				/* the behavior of fetch() */
12100Sstevel@tonic-gate 				fetch(ixnew, lowc, d, 1, "  ", 0);
12110Sstevel@tonic-gate 			else {
12120Sstevel@tonic-gate 				/* The last argument should not affect */
12130Sstevel@tonic-gate 				/* the behavior of fetch() */
12140Sstevel@tonic-gate 				fetch(ixnew, lowc, c - 1, 1, "  ", 0);
12150Sstevel@tonic-gate 				fetch(ixnew, c, d, 1,
12160Sstevel@tonic-gate 				    ch == 'c' ? "! " : "+ ", 0);
12170Sstevel@tonic-gate 			}
12180Sstevel@tonic-gate 			lowc = d + 1;
12190Sstevel@tonic-gate 			cvp++;
12200Sstevel@tonic-gate 		}
12210Sstevel@tonic-gate 		/* The last argument should not affect the behavior */
12220Sstevel@tonic-gate 		/* of fetch() */
12230Sstevel@tonic-gate 		fetch(ixnew, d + 1, upd, 1, "  ", 0);
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 	context_vec_ptr = context_vec_start - 1;
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate  * diff - directory comparison
12320Sstevel@tonic-gate  */
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate struct	dir *setupdir();
12350Sstevel@tonic-gate int	header;
12360Sstevel@tonic-gate char	title[2 * BUFSIZ], *etitle;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate static void
diffdir(char ** argv)12390Sstevel@tonic-gate diffdir(char **argv)
12400Sstevel@tonic-gate {
12410Sstevel@tonic-gate 	struct dir *d1, *d2;
12420Sstevel@tonic-gate 	struct dir *dir1, *dir2;
12430Sstevel@tonic-gate 	int i;
12440Sstevel@tonic-gate 	int cmp;
12450Sstevel@tonic-gate 	int result, dirstatus;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	if (opt == D_IFDEF)
12480Sstevel@tonic-gate 		error(gettext("cannot specify -D with directories"));
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	if (opt == D_EDIT && (sflag || lflag)) {
12510Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
12520Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
12530Sstevel@tonic-gate 			"warning: should not give -s or -l with -e\n"));
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 	dirstatus = 0;
12560Sstevel@tonic-gate 	title[0] = 0;
12570Sstevel@tonic-gate 	(void) strcpy(title, "diff ");
12580Sstevel@tonic-gate 	for (i = 1; diffargv[i + 2]; i++) {
12590Sstevel@tonic-gate 		if (strcmp(diffargv[i], "-") == 0) {
12600Sstevel@tonic-gate 			continue;	/* Skip -S and its argument */
12610Sstevel@tonic-gate 		}
12620Sstevel@tonic-gate 		(void) strcat(title, diffargv[i]);
12630Sstevel@tonic-gate 		(void) strcat(title, " ");
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 	for (etitle = title; *etitle; etitle++)
12660Sstevel@tonic-gate 		;
12670Sstevel@tonic-gate 	setfile(&file1, &efile1, file1);
12680Sstevel@tonic-gate 	setfile(&file2, &efile2, file2);
12690Sstevel@tonic-gate 	argv[0] = file1;
12700Sstevel@tonic-gate 	argv[1] = file2;
12710Sstevel@tonic-gate 	dir1 = setupdir(file1);
12720Sstevel@tonic-gate 	dir2 = setupdir(file2);
12730Sstevel@tonic-gate 	d1 = dir1; d2 = dir2;
12740Sstevel@tonic-gate 	while (d1->d_entry != 0 || d2->d_entry != 0) {
12750Sstevel@tonic-gate 		if (d1->d_entry && useless(d1->d_entry)) {
12760Sstevel@tonic-gate 			d1++;
12770Sstevel@tonic-gate 			continue;
12780Sstevel@tonic-gate 		}
12790Sstevel@tonic-gate 		if (d2->d_entry && useless(d2->d_entry)) {
12800Sstevel@tonic-gate 			d2++;
12810Sstevel@tonic-gate 			continue;
12820Sstevel@tonic-gate 		}
12830Sstevel@tonic-gate 		if (d1->d_entry == 0)
12840Sstevel@tonic-gate 			cmp = 1;
12850Sstevel@tonic-gate 		else if (d2->d_entry == 0)
12860Sstevel@tonic-gate 			cmp = -1;
12870Sstevel@tonic-gate 		else
12880Sstevel@tonic-gate 			cmp = strcmp(d1->d_entry, d2->d_entry);
12890Sstevel@tonic-gate 		if (cmp < 0) {
12900Sstevel@tonic-gate 			if (lflag)
12910Sstevel@tonic-gate 				d1->d_flags |= ONLY;
12920Sstevel@tonic-gate 			else if (opt == 0 || opt == 2)
12930Sstevel@tonic-gate 				only(d1, 1);
12940Sstevel@tonic-gate 			d1++;
12950Sstevel@tonic-gate 			if (dirstatus == 0)
12960Sstevel@tonic-gate 				dirstatus = 1;
12970Sstevel@tonic-gate 		} else if (cmp == 0) {
12980Sstevel@tonic-gate 			result = compare(d1);
12990Sstevel@tonic-gate 			if (result > dirstatus)
13000Sstevel@tonic-gate 				dirstatus = result;
13010Sstevel@tonic-gate 			d1++;
13020Sstevel@tonic-gate 			d2++;
13030Sstevel@tonic-gate 		} else {
13040Sstevel@tonic-gate 			if (lflag)
13050Sstevel@tonic-gate 				d2->d_flags |= ONLY;
13060Sstevel@tonic-gate 			else if (opt == 0 || opt == 2)
13070Sstevel@tonic-gate 				only(d2, 2);
13080Sstevel@tonic-gate 			d2++;
13090Sstevel@tonic-gate 			if (dirstatus == 0)
13100Sstevel@tonic-gate 				dirstatus = 1;
13110Sstevel@tonic-gate 		}
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 	if (lflag) {
13140Sstevel@tonic-gate 		scanpr(dir1, ONLY,
13150Sstevel@tonic-gate 			gettext("Only in %.*s"), file1, efile1, 0, 0);
13160Sstevel@tonic-gate 		scanpr(dir2, ONLY,
13170Sstevel@tonic-gate 			gettext("Only in %.*s"), file2, efile2, 0, 0);
13180Sstevel@tonic-gate 		scanpr(dir1, SAME,
13190Sstevel@tonic-gate 		    gettext("Common identical files in %.*s and %.*s"),
13200Sstevel@tonic-gate 		    file1, efile1, file2, efile2);
13210Sstevel@tonic-gate 		scanpr(dir1, DIFFER,
13220Sstevel@tonic-gate 		    gettext("Binary files which differ in %.*s and %.*s"),
13230Sstevel@tonic-gate 		    file1, efile1, file2, efile2);
13240Sstevel@tonic-gate 		scanpr(dir1, DIRECT,
13250Sstevel@tonic-gate 		    gettext("Common subdirectories of %.*s and %.*s"),
13260Sstevel@tonic-gate 		    file1, efile1, file2, efile2);
13270Sstevel@tonic-gate 	}
13280Sstevel@tonic-gate 	if (rflag) {
13290Sstevel@tonic-gate 		if (header && lflag)
13300Sstevel@tonic-gate 			(void) printf("\f");
13310Sstevel@tonic-gate 		for (d1 = dir1; d1->d_entry; d1++)  {
13320Sstevel@tonic-gate 			if ((d1->d_flags & DIRECT) == 0)
13330Sstevel@tonic-gate 				continue;
13340Sstevel@tonic-gate 			(void) strcpy(efile1, d1->d_entry);
13350Sstevel@tonic-gate 			(void) strcpy(efile2, d1->d_entry);
13360Sstevel@tonic-gate 			result = calldiff((char *)0);
13370Sstevel@tonic-gate 			if (result > dirstatus)
13380Sstevel@tonic-gate 				dirstatus = result;
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 	status = dirstatus;
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate static void
setfile(char ** fpp,char ** epp,char * file)13450Sstevel@tonic-gate setfile(char **fpp, char **epp, char *file)
13460Sstevel@tonic-gate {
13470Sstevel@tonic-gate 	char *cp;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	*fpp = (char *)malloc(BUFSIZ);
13500Sstevel@tonic-gate 	if (*fpp == 0) {
13510Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
13520Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("out of memory\n"));
13530Sstevel@tonic-gate 		exit(1);
13540Sstevel@tonic-gate 	}
13550Sstevel@tonic-gate 	(void) strcpy(*fpp, file);
13560Sstevel@tonic-gate 	for (cp = *fpp; *cp; cp++)
13570Sstevel@tonic-gate 		continue;
13580Sstevel@tonic-gate 	*cp++ = '/';
13590Sstevel@tonic-gate 	*cp = 0;
13600Sstevel@tonic-gate 	*epp = cp;
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate static void
scanpr(struct dir * dp,int test,char * title,char * file1,char * efile1,char * file2,char * efile2)13640Sstevel@tonic-gate scanpr(struct dir *dp, int test,
13650Sstevel@tonic-gate 	char *title, char *file1, char *efile1, char *file2, char *efile2)
13660Sstevel@tonic-gate {
13670Sstevel@tonic-gate 	int titled = 0;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	for (; dp->d_entry; dp++) {
13700Sstevel@tonic-gate 		if ((dp->d_flags & test) == 0)
13710Sstevel@tonic-gate 			continue;
13720Sstevel@tonic-gate 		if (titled == 0) {
13730Sstevel@tonic-gate 			if (header == 0)
13740Sstevel@tonic-gate 				header = 1;
13750Sstevel@tonic-gate 			else
13760Sstevel@tonic-gate 				(void) printf("\n");
13770Sstevel@tonic-gate 			(void) printf(title,
13780Sstevel@tonic-gate 			    efile1 - file1 - 1, file1,
13790Sstevel@tonic-gate 			    efile2 - file2 - 1, file2);
13800Sstevel@tonic-gate 			(void) printf(":\n");
13810Sstevel@tonic-gate 			titled = 1;
13820Sstevel@tonic-gate 		}
13830Sstevel@tonic-gate 		(void) printf("\t%s\n", dp->d_entry);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate static void
only(struct dir * dp,int which)13880Sstevel@tonic-gate only(struct dir *dp, int which)
13890Sstevel@tonic-gate {
13900Sstevel@tonic-gate 	char *file = which == 1 ? file1 : file2;
13910Sstevel@tonic-gate 	char *efile = which == 1 ? efile1 : efile2;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	(void) printf(gettext("Only in %.*s: %s\n"), efile - file - 1, file,
13940Sstevel@tonic-gate 	    dp->d_entry);
13950Sstevel@tonic-gate }
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate int	entcmp();
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate static struct dir *
setupdir(char * cp)14000Sstevel@tonic-gate setupdir(char *cp)
14010Sstevel@tonic-gate {
14020Sstevel@tonic-gate 	struct dir *dp = 0, *ep;
14030Sstevel@tonic-gate 	struct dirent64 *rp;
14040Sstevel@tonic-gate 	int nitems;
14050Sstevel@tonic-gate 	int size;
14060Sstevel@tonic-gate 	DIR *dirp;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	dirp = opendir(cp);
14090Sstevel@tonic-gate 	if (dirp == NULL) {
14100Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
14110Sstevel@tonic-gate 		perror(cp);
14120Sstevel@tonic-gate 		done();
14130Sstevel@tonic-gate 	}
14140Sstevel@tonic-gate 	nitems = 0;
14150Sstevel@tonic-gate 	dp = (struct dir *)malloc(sizeof (struct dir));
14160Sstevel@tonic-gate 	if (dp == 0)
14170Sstevel@tonic-gate 		error(gettext(NO_MEM_ERR));
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	while (rp = readdir64(dirp)) {
14200Sstevel@tonic-gate 		ep = &dp[nitems++];
14210Sstevel@tonic-gate 		ep->d_reclen = rp->d_reclen;
14220Sstevel@tonic-gate 		ep->d_entry = 0;
14230Sstevel@tonic-gate 		ep->d_flags = 0;
14240Sstevel@tonic-gate 		size = strlen(rp->d_name);
14250Sstevel@tonic-gate 		if (size > 0) {
14260Sstevel@tonic-gate 			ep->d_entry = (char *)malloc(size + 1);
14270Sstevel@tonic-gate 			if (ep->d_entry == 0)
14280Sstevel@tonic-gate 				error(gettext(NO_MEM_ERR));
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 			(void) strcpy(ep->d_entry, rp->d_name);
14310Sstevel@tonic-gate 		}
14320Sstevel@tonic-gate 		dp = (struct dir *)realloc((char *)dp,
14330Sstevel@tonic-gate 			(nitems + 1) * sizeof (struct dir));
14340Sstevel@tonic-gate 		if (dp == 0)
14350Sstevel@tonic-gate 			error(gettext(NO_MEM_ERR));
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 	dp[nitems].d_entry = 0;		/* delimiter */
14380Sstevel@tonic-gate 	(void) closedir(dirp);
14390Sstevel@tonic-gate 	qsort(dp, nitems, sizeof (struct dir),
14400Sstevel@tonic-gate 		(int (*)(const void *, const void *))entcmp);
14410Sstevel@tonic-gate 	return (dp);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate static int
entcmp(struct dir * d1,struct dir * d2)14450Sstevel@tonic-gate entcmp(struct dir *d1, struct dir *d2)
14460Sstevel@tonic-gate {
14470Sstevel@tonic-gate 	return (strcmp(d1->d_entry, d2->d_entry));
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate static int
compare(struct dir * dp)14510Sstevel@tonic-gate compare(struct dir *dp)
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate 	int i, j;
14540Sstevel@tonic-gate 	int f1 = -1, f2 = -1;
14550Sstevel@tonic-gate 	mode_t fmt1, fmt2;
14560Sstevel@tonic-gate 	struct stat stb1, stb2;
14570Sstevel@tonic-gate 	char buf1[BUFSIZ], buf2[BUFSIZ];
14580Sstevel@tonic-gate 	int result;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	(void) strcpy(efile1, dp->d_entry);
14610Sstevel@tonic-gate 	(void) strcpy(efile2, dp->d_entry);
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	if (stat(file1, &stb1) == -1) {
14640Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
14650Sstevel@tonic-gate 		perror(file1);
14660Sstevel@tonic-gate 		return (2);
14670Sstevel@tonic-gate 	}
14680Sstevel@tonic-gate 	if (stat(file2, &stb2) == -1) {
14690Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
14700Sstevel@tonic-gate 		perror(file2);
14710Sstevel@tonic-gate 		return (2);
14720Sstevel@tonic-gate 	}
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	fmt1 = stb1.st_mode & S_IFMT;
14750Sstevel@tonic-gate 	fmt2 = stb2.st_mode & S_IFMT;
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	if (fmt1 == S_IFREG) {
14780Sstevel@tonic-gate 		f1 = open(file1, O_RDONLY);
14790Sstevel@tonic-gate 		if (f1 < 0) {
14800Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
14810Sstevel@tonic-gate 			perror(file1);
14820Sstevel@tonic-gate 			return (2);
14830Sstevel@tonic-gate 		}
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	if (fmt2 == S_IFREG) {
14870Sstevel@tonic-gate 		f2 = open(file2, O_RDONLY);
14880Sstevel@tonic-gate 		if (f2 < 0) {
14890Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
14900Sstevel@tonic-gate 			perror(file2);
14910Sstevel@tonic-gate 			(void) close(f1);
14920Sstevel@tonic-gate 			return (2);
14930Sstevel@tonic-gate 		}
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	if (fmt1 != S_IFREG || fmt2 != S_IFREG) {
14970Sstevel@tonic-gate 		if (fmt1 == fmt2) {
14980Sstevel@tonic-gate 			switch (fmt1) {
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 			case S_IFDIR:
15010Sstevel@tonic-gate 				dp->d_flags = DIRECT;
15020Sstevel@tonic-gate 				if (lflag || opt == D_EDIT)
15030Sstevel@tonic-gate 					goto closem;
15040Sstevel@tonic-gate 				(void) printf(gettext(
15050Sstevel@tonic-gate 				    "Common subdirectories: %s and %s\n"),
15060Sstevel@tonic-gate 				    file1, file2);
15070Sstevel@tonic-gate 				goto closem;
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 			case S_IFCHR:
15100Sstevel@tonic-gate 			case S_IFBLK:
15110Sstevel@tonic-gate 				if (stb1.st_rdev == stb2.st_rdev)
15120Sstevel@tonic-gate 					goto same;
15130Sstevel@tonic-gate 				(void) printf(gettext(
15140Sstevel@tonic-gate 				    "Special files %s and %s differ\n"),
15150Sstevel@tonic-gate 				    file1, file2);
15160Sstevel@tonic-gate 				break;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 			case S_IFLNK:
15190Sstevel@tonic-gate 				if ((i = readlink(file1, buf1, BUFSIZ)) == -1) {
15200Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
15210Sstevel@tonic-gate 					    "diff: cannot read link\n"));
15220Sstevel@tonic-gate 					return (2);
15230Sstevel@tonic-gate 				}
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 				if ((j = readlink(file2, buf2, BUFSIZ)) == -1) {
15260Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
15270Sstevel@tonic-gate 					    "diff: cannot read link\n"));
15280Sstevel@tonic-gate 					return (2);
15290Sstevel@tonic-gate 				}
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 				if (i == j) {
15320Sstevel@tonic-gate 					if (strncmp(buf1, buf2, i) == 0)
15330Sstevel@tonic-gate 						goto same;
15340Sstevel@tonic-gate 				}
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 				(void) printf(gettext(
15370Sstevel@tonic-gate 				    "Symbolic links %s and %s differ\n"),
15380Sstevel@tonic-gate 				    file1, file2);
15390Sstevel@tonic-gate 				break;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 			case S_IFIFO:
15420Sstevel@tonic-gate 				if (stb1.st_ino == stb2.st_ino)
15430Sstevel@tonic-gate 					goto same;
15440Sstevel@tonic-gate 				(void) printf(gettext(
15450Sstevel@tonic-gate 				    "Named pipes %s and %s differ\n"),
15460Sstevel@tonic-gate 				    file1, file2);
15470Sstevel@tonic-gate 				break;
15480Sstevel@tonic-gate 			}
15490Sstevel@tonic-gate 		} else {
15500Sstevel@tonic-gate 			if (lflag)
15510Sstevel@tonic-gate 				dp->d_flags |= DIFFER;
15520Sstevel@tonic-gate 			else if (opt == D_NORMAL || opt == D_CONTEXT) {
15530Sstevel@tonic-gate /*
15540Sstevel@tonic-gate  * TRANSLATION_NOTE
15550Sstevel@tonic-gate  * The second and fourth parameters will take the gettext'ed string
15560Sstevel@tonic-gate  * of one of the following:
15570Sstevel@tonic-gate  * a directory
15580Sstevel@tonic-gate  * a character special file
15590Sstevel@tonic-gate  * a block special file
15600Sstevel@tonic-gate  * a plain file
15610Sstevel@tonic-gate  * a named pipe
15620Sstevel@tonic-gate  * a socket
15630Sstevel@tonic-gate  * a door
15640Sstevel@tonic-gate  * an event port
15650Sstevel@tonic-gate  * an unknown type
15660Sstevel@tonic-gate  */
15670Sstevel@tonic-gate 				(void) printf(
15680Sstevel@tonic-gate gettext("File %s is %s while file %s is %s\n"),
15690Sstevel@tonic-gate 					file1, pfiletype(fmt1),
15700Sstevel@tonic-gate 					file2, pfiletype(fmt2));
15710Sstevel@tonic-gate 			}
15720Sstevel@tonic-gate 		}
15730Sstevel@tonic-gate 		(void) close(f1); (void) close(f2);
15740Sstevel@tonic-gate 		return (1);
15750Sstevel@tonic-gate 	}
15760Sstevel@tonic-gate 	if (stb1.st_size != stb2.st_size)
15770Sstevel@tonic-gate 		goto notsame;
15780Sstevel@tonic-gate 	for (;;) {
15790Sstevel@tonic-gate 		i = read(f1, buf1, BUFSIZ);
15800Sstevel@tonic-gate 		j = read(f2, buf2, BUFSIZ);
15810Sstevel@tonic-gate 		if (i < 0 || j < 0) {
15820Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
15830Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Error reading "));
15840Sstevel@tonic-gate 			perror(i < 0 ? file1: file2);
15850Sstevel@tonic-gate 			(void) close(f1); (void) close(f2);
15860Sstevel@tonic-gate 			return (2);
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 		if (i != j)
15890Sstevel@tonic-gate 			goto notsame;
15900Sstevel@tonic-gate 		if (i == 0 && j == 0)
15910Sstevel@tonic-gate 			goto same;
15920Sstevel@tonic-gate 		for (j = 0; j < i; j++)
15930Sstevel@tonic-gate 			if (buf1[j] != buf2[j])
15940Sstevel@tonic-gate 				goto notsame;
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate same:
15970Sstevel@tonic-gate 	if (sflag == 0)
15980Sstevel@tonic-gate 		goto closem;
15990Sstevel@tonic-gate 	if (lflag)
16000Sstevel@tonic-gate 		dp->d_flags = SAME;
16010Sstevel@tonic-gate 	else
16020Sstevel@tonic-gate 		(void) printf(gettext("Files %s and %s are identical\n"),
16030Sstevel@tonic-gate 			file1, file2);
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate closem:
16060Sstevel@tonic-gate 	(void) close(f1); (void) close(f2);
16070Sstevel@tonic-gate 	return (0);
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate notsame:
16100Sstevel@tonic-gate 	if (binary(f1) || binary(f2)) {
16110Sstevel@tonic-gate 		if (lflag)
16120Sstevel@tonic-gate 			dp->d_flags |= DIFFER;
16130Sstevel@tonic-gate 		else if (opt == D_NORMAL || opt == D_CONTEXT)
16140Sstevel@tonic-gate 			(void) printf(
16150Sstevel@tonic-gate 				gettext("Binary files %s and %s differ\n"),
16160Sstevel@tonic-gate 			    file1, file2);
16170Sstevel@tonic-gate 		(void) close(f1); (void) close(f2);
16180Sstevel@tonic-gate 		return (1);
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 	(void) close(f1); (void) close(f2);
16210Sstevel@tonic-gate 	anychange = 1;
16220Sstevel@tonic-gate 	if (lflag) {
16230Sstevel@tonic-gate 		result = calldiff(title);
16240Sstevel@tonic-gate 	} else {
16250Sstevel@tonic-gate 		if (opt == D_EDIT)
16260Sstevel@tonic-gate 			(void) printf("ed - %s << '-*-END-*-'\n", dp->d_entry);
16270Sstevel@tonic-gate 		else
16280Sstevel@tonic-gate 			(void) printf("%s%s %s\n", title, file1, file2);
16290Sstevel@tonic-gate 		result = calldiff((char *)0);
16300Sstevel@tonic-gate 		if (opt == D_EDIT)
16310Sstevel@tonic-gate 			(void) printf("w\nq\n-*-END-*-\n");
16320Sstevel@tonic-gate 	}
16330Sstevel@tonic-gate 	return (result);
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate char	*prargs[] = { "pr", "-h", 0, 0, 0 };
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate static int
calldiff(char * wantpr)16390Sstevel@tonic-gate calldiff(char *wantpr)
16400Sstevel@tonic-gate {
16410Sstevel@tonic-gate 	pid_t pid;
16420Sstevel@tonic-gate 	int diffstatus, pv[2];
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	prargs[2] = wantpr;
16450Sstevel@tonic-gate 	(void) fflush(stdout);
16460Sstevel@tonic-gate 	if (wantpr) {
16470Sstevel@tonic-gate 		(void) sprintf(etitle, "%s %s", file1, file2);
16480Sstevel@tonic-gate 		(void) pipe(pv);
16490Sstevel@tonic-gate 		pid = fork();
16500Sstevel@tonic-gate 		if (pid == (pid_t)-1)
16510Sstevel@tonic-gate 			error(gettext(NO_PROCS_ERR));
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 		if (pid == 0) {
16540Sstevel@tonic-gate 			(void) close(0);
16550Sstevel@tonic-gate 			(void) dup(pv[0]);
16560Sstevel@tonic-gate 			(void) close(pv[0]);
16570Sstevel@tonic-gate 			(void) close(pv[1]);
16580Sstevel@tonic-gate 			(void) execv(pr+5, prargs);
16590Sstevel@tonic-gate 			(void) execv(pr, prargs);
16600Sstevel@tonic-gate 			perror(pr);
16610Sstevel@tonic-gate 			done();
16620Sstevel@tonic-gate 		}
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate 	pid = fork();
16650Sstevel@tonic-gate 	if (pid == (pid_t)-1)
16660Sstevel@tonic-gate 		error(gettext(NO_PROCS_ERR));
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if (pid == 0) {
16690Sstevel@tonic-gate 		if (wantpr) {
16700Sstevel@tonic-gate 			(void) close(1);
16710Sstevel@tonic-gate 			(void) dup(pv[1]);
16720Sstevel@tonic-gate 			(void) close(pv[0]);
16730Sstevel@tonic-gate 			(void) close(pv[1]);
16740Sstevel@tonic-gate 		}
16750Sstevel@tonic-gate 		(void) execv(diff+5, diffargv);
16760Sstevel@tonic-gate 		(void) execv(diff, diffargv);
16770Sstevel@tonic-gate 		perror(diff);
16780Sstevel@tonic-gate 		done();
16790Sstevel@tonic-gate 	}
16800Sstevel@tonic-gate 	if (wantpr)	{
16810Sstevel@tonic-gate 		(void) close(pv[0]);
16820Sstevel@tonic-gate 		(void) close(pv[1]);
16830Sstevel@tonic-gate 	}
16840Sstevel@tonic-gate 	while (wait(&diffstatus) != pid)
16850Sstevel@tonic-gate 		continue;
16860Sstevel@tonic-gate 	while (wait((int *)0) != (pid_t)-1)
16870Sstevel@tonic-gate 		continue;
16880Sstevel@tonic-gate 	if ((diffstatus&0177) != 0)
16890Sstevel@tonic-gate 		return (2);
16900Sstevel@tonic-gate 	else
16910Sstevel@tonic-gate 		return ((diffstatus>>8) & 0377);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate static char *
pfiletype(mode_t fmt)16950Sstevel@tonic-gate pfiletype(mode_t fmt)
16960Sstevel@tonic-gate {
16970Sstevel@tonic-gate /*
16980Sstevel@tonic-gate  * TRANSLATION_NOTE
16990Sstevel@tonic-gate  * The following 9 messages will be used in the second and
17000Sstevel@tonic-gate  * the fourth parameters of the message
17010Sstevel@tonic-gate  * "File %s is %s while file %s is %s\n"
17020Sstevel@tonic-gate  */
17030Sstevel@tonic-gate 	switch (fmt) {
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	case S_IFDIR:
17060Sstevel@tonic-gate 		return (gettext("a directory"));
17070Sstevel@tonic-gate 		break;
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	case S_IFCHR:
17100Sstevel@tonic-gate 		return (gettext("a character special file"));
17110Sstevel@tonic-gate 		break;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	case S_IFBLK:
17140Sstevel@tonic-gate 		return (gettext("a block special file"));
17150Sstevel@tonic-gate 		break;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	case S_IFREG:
17180Sstevel@tonic-gate 		return (gettext("a plain file"));
17190Sstevel@tonic-gate 		break;
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	case S_IFIFO:
17220Sstevel@tonic-gate 		return (gettext("a named pipe"));
17230Sstevel@tonic-gate 		break;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	case S_IFSOCK:
17260Sstevel@tonic-gate 		return (gettext("a socket"));
17270Sstevel@tonic-gate 		break;
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	case S_IFDOOR:
17300Sstevel@tonic-gate 		return (gettext("a door"));
17310Sstevel@tonic-gate 		break;
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 	case S_IFPORT:
17340Sstevel@tonic-gate 		return (gettext("an event port"));
17350Sstevel@tonic-gate 		break;
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	default:
17380Sstevel@tonic-gate 		return (gettext("an unknown type"));
17390Sstevel@tonic-gate 		break;
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate }
17420Sstevel@tonic-gate 
17430Sstevel@tonic-gate static int
binary(int f)17440Sstevel@tonic-gate binary(int f)
17450Sstevel@tonic-gate {
17460Sstevel@tonic-gate 	char buf[BUFSIZ];
17470Sstevel@tonic-gate 	int cnt;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	(void) lseek(f, (long)0, SEEK_SET);
17500Sstevel@tonic-gate 	cnt = read(f, buf, BUFSIZ);
17510Sstevel@tonic-gate 	if (cnt < 0)
17520Sstevel@tonic-gate 		return (1);
17530Sstevel@tonic-gate 	return (isbinary(buf, cnt));
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate static int
filebinary(FILE * f)17570Sstevel@tonic-gate filebinary(FILE *f)
17580Sstevel@tonic-gate {
17590Sstevel@tonic-gate 	char buf[BUFSIZ];
17600Sstevel@tonic-gate 	int cnt;
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 	(void) fseek(f, (long)0, SEEK_SET);
17630Sstevel@tonic-gate 	cnt = fread(buf, 1, BUFSIZ, f);
17640Sstevel@tonic-gate 	if (ferror(f))
17650Sstevel@tonic-gate 		return (1);
17660Sstevel@tonic-gate 	return (isbinary(buf, cnt));
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate /*
17710Sstevel@tonic-gate  * We consider a "binary" file to be one that:
17720Sstevel@tonic-gate  * contains a null character ("diff" doesn't handle them correctly, and
17730Sstevel@tonic-gate  *    neither do many other UNIX text-processing commands).
17740Sstevel@tonic-gate  * Characters with their 8th bit set do NOT make a file binary; they may be
17750Sstevel@tonic-gate  * legitimate text characters, or parts of same.
17760Sstevel@tonic-gate  */
17770Sstevel@tonic-gate static int
isbinary(char * buf,int cnt)17780Sstevel@tonic-gate isbinary(char *buf, int cnt)
17790Sstevel@tonic-gate {
17800Sstevel@tonic-gate 	char *cp;
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	cp = buf;
17830Sstevel@tonic-gate 	while (--cnt >= 0)
17840Sstevel@tonic-gate 		if (*cp++ == '\0')
17850Sstevel@tonic-gate 			return (1);
17860Sstevel@tonic-gate 	return (0);
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate /*
17910Sstevel@tonic-gate  * THIS IS CRUDE.
17920Sstevel@tonic-gate  */
17930Sstevel@tonic-gate static int
useless(char * cp)17940Sstevel@tonic-gate useless(char *cp)
17950Sstevel@tonic-gate {
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	if (cp[0] == '.') {
17980Sstevel@tonic-gate 		if (cp[1] == '\0')
17990Sstevel@tonic-gate 			return (1);	/* directory "." */
18000Sstevel@tonic-gate 		if (cp[1] == '.' && cp[2] == '\0')
18010Sstevel@tonic-gate 			return (1);	/* directory ".." */
18020Sstevel@tonic-gate 	}
18030Sstevel@tonic-gate 	if (start && strcmp(start, cp) > 0)
18040Sstevel@tonic-gate 		return (1);
18050Sstevel@tonic-gate 	return (0);
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate void
sort(struct line * a,int n)18100Sstevel@tonic-gate sort(struct line *a, int n)	/* shellsort CACM #201 */
18110Sstevel@tonic-gate {
18120Sstevel@tonic-gate 	struct line w;
18130Sstevel@tonic-gate 	int j, m;
18140Sstevel@tonic-gate 	struct line *ai;
18150Sstevel@tonic-gate 	struct line *aim;
18160Sstevel@tonic-gate 	int k;
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	for (j = 1, m = 0; j <= n; j *= 2)
18190Sstevel@tonic-gate 		m = 2 * j - 1;
18200Sstevel@tonic-gate 	for (m /= 2; m != 0; m /= 2) {
18210Sstevel@tonic-gate 		k = n - m;
18220Sstevel@tonic-gate 		for (j = 1; j <= k; j++) {
18230Sstevel@tonic-gate 			for (ai = &a[j]; ai > a; ai -= m) {
18240Sstevel@tonic-gate 				aim = &ai[m];
18250Sstevel@tonic-gate 				if (aim < ai)
18260Sstevel@tonic-gate 					break;	/* wraparound */
18270Sstevel@tonic-gate 				if (aim->value > ai[0].value ||
18280Sstevel@tonic-gate 				    aim->value == ai[0].value &&
18290Sstevel@tonic-gate 				    aim->serial > ai[0].serial)
18300Sstevel@tonic-gate 					break;
18310Sstevel@tonic-gate 				w.value = ai[0].value;
18320Sstevel@tonic-gate 				ai[0].value = aim->value;
18330Sstevel@tonic-gate 				aim->value = w.value;
18340Sstevel@tonic-gate 				w.serial = ai[0].serial;
18350Sstevel@tonic-gate 				ai[0].serial = aim->serial;
18360Sstevel@tonic-gate 				aim->serial = w.serial;
18370Sstevel@tonic-gate 			}
18380Sstevel@tonic-gate 		}
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate static void
unsort(struct line * f,int l,int * b)18430Sstevel@tonic-gate unsort(struct line *f, int l, int *b)
18440Sstevel@tonic-gate {
18450Sstevel@tonic-gate 	int *a;
18460Sstevel@tonic-gate 	int i;
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	a = (int *)talloc((l + 1) * sizeof (int));
18490Sstevel@tonic-gate 	for (i = 1; i <= l; i++)
18500Sstevel@tonic-gate 		a[f[i].serial] = f[i].value;
18510Sstevel@tonic-gate 	for (i = 1; i <= l; i++)
18520Sstevel@tonic-gate 		b[i] = a[i];
18530Sstevel@tonic-gate 	free((char *)a);
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate static void
filename(char ** pa1,char ** pa2,struct stat * st,char ** ifile)18570Sstevel@tonic-gate filename(char **pa1, char **pa2, struct stat *st, char **ifile)
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate 	char *a1, *b1, *a2;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	a1 = *pa1;
18620Sstevel@tonic-gate 	a2 = *pa2;
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 	if (strcmp(*pa1, "-") == 0)
18650Sstevel@tonic-gate 		*ifile = strdup("-");
18660Sstevel@tonic-gate 	else
18670Sstevel@tonic-gate 		*ifile = strdup(*pa1);
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	if (*ifile == (char *)NULL) {
18700Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
18710Sstevel@tonic-gate 			"no more memory - try again later\n"));
18720Sstevel@tonic-gate 		status = 2;
18730Sstevel@tonic-gate 		done();
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	if ((st->st_mode & S_IFMT) == S_IFDIR) {
18770Sstevel@tonic-gate 		b1 = *pa1 = (char *)malloc(PATH_MAX);
18780Sstevel@tonic-gate 		while (*b1++ = *a1++)
18790Sstevel@tonic-gate 			;
18800Sstevel@tonic-gate 		b1[-1] = '/';
18810Sstevel@tonic-gate 		a1 = b1;
18820Sstevel@tonic-gate 		while (*a1++ = *a2++)
18830Sstevel@tonic-gate 			if (*a2 && *a2 != '/' && a2[-1] == '/')
18840Sstevel@tonic-gate 				a1 = b1;
18850Sstevel@tonic-gate 		*ifile = strdup(*pa1);
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 		if (*ifile == (char *)NULL) {
18880Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
18890Sstevel@tonic-gate 				"no more memory - try again later\n"));
18900Sstevel@tonic-gate 			status = 2;
18910Sstevel@tonic-gate 			done();
18920Sstevel@tonic-gate 		}
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 		if (stat(*pa1, st) < 0) {
18950Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
18960Sstevel@tonic-gate 			perror(*pa1);
18970Sstevel@tonic-gate 			done();
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 	} else if ((st->st_mode & S_IFMT) == S_IFCHR)
19000Sstevel@tonic-gate 		*pa1 = copytemp(a1);
19010Sstevel@tonic-gate 	else if (a1[0] == '-' && a1[1] == 0) {
19020Sstevel@tonic-gate 		*pa1 = copytemp(a1);	/* hack! */
19030Sstevel@tonic-gate 		if (stat(*pa1, st) < 0) {
19040Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
19050Sstevel@tonic-gate 			perror(*pa1);
19060Sstevel@tonic-gate 			done();
19070Sstevel@tonic-gate 		}
19080Sstevel@tonic-gate 	}
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate static char *
copytemp(char * fn)19120Sstevel@tonic-gate copytemp(char *fn)
19130Sstevel@tonic-gate {
19140Sstevel@tonic-gate 	int ifd, ofd;	/* input and output file descriptors */
19150Sstevel@tonic-gate 	int i;
19160Sstevel@tonic-gate 	char template[13];	/* template for temp file name */
19170Sstevel@tonic-gate 	char buf[BUFSIZ];
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	/*
19200Sstevel@tonic-gate 	 * a "-" file is interpreted as fd 0 for pre-/dev/fd systems
19210Sstevel@tonic-gate 	 * ... let's hope this goes away soon!
19220Sstevel@tonic-gate 	 */
19230Sstevel@tonic-gate 	if ((ifd = (strcmp(fn, "-") ? open(fn, 0) : 0)) < 0) {
19240Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
19250Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cannot open %s\n"), fn);
19260Sstevel@tonic-gate 		done();
19270Sstevel@tonic-gate 	}
19280Sstevel@tonic-gate 	(void) signal(SIGHUP, (void (*)(int))done);
19290Sstevel@tonic-gate 	(void) signal(SIGINT, (void (*)(int))done);
19300Sstevel@tonic-gate 	(void) signal(SIGPIPE, (void (*)(int))done);
19310Sstevel@tonic-gate 	(void) signal(SIGTERM, (void (*)(int))done);
19320Sstevel@tonic-gate 	(void) strcpy(template, "/tmp/dXXXXXX");
19330Sstevel@tonic-gate 	if ((ofd = mkstemp(template)) < 0) {
19340Sstevel@tonic-gate 		(void) fprintf(stderr, "diff: ");
19350Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("cannot create %s\n"), template);
19360Sstevel@tonic-gate 		done();
19370Sstevel@tonic-gate 	}
19380Sstevel@tonic-gate 	(void) strcpy(tempfile[whichtemp++], template);
19390Sstevel@tonic-gate 	while ((i = read(ifd, buf, BUFSIZ)) > 0)
19400Sstevel@tonic-gate 		if (write(ofd, buf, i) != i) {
19410Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
19420Sstevel@tonic-gate 			(void) fprintf(stderr,
19430Sstevel@tonic-gate 				gettext("write failed %s\n"), template);
19440Sstevel@tonic-gate 			done();
19450Sstevel@tonic-gate 		}
19460Sstevel@tonic-gate 	(void) close(ifd); (void) close(ofd);
19470Sstevel@tonic-gate 	return (tempfile[whichtemp-1]);
19480Sstevel@tonic-gate }
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate static void
prepare(int i,char * arg)19510Sstevel@tonic-gate prepare(int i, char *arg)
19520Sstevel@tonic-gate {
19530Sstevel@tonic-gate 	struct line *p;
19540Sstevel@tonic-gate 	int j, h;
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	(void) fseek(input[i], (long)0, SEEK_SET);
19570Sstevel@tonic-gate 	p = (struct line *)talloc(3 * sizeof (line));
19580Sstevel@tonic-gate 	for (j = 0; h = readhash(input[i], i, arg); ) {
19590Sstevel@tonic-gate 		p = (struct line *)ralloc((void *)p, (++j + 3) * sizeof (line));
19600Sstevel@tonic-gate 		p[j].value = h;
19610Sstevel@tonic-gate 	}
19620Sstevel@tonic-gate 	len[i] = j;
19630Sstevel@tonic-gate 	file[i] = p;
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate static void
prune(void)19670Sstevel@tonic-gate prune(void)
19680Sstevel@tonic-gate {
19690Sstevel@tonic-gate 	int i, j;
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	for (pref = 0; pref < len[0] && pref < len[1] &&
19720Sstevel@tonic-gate 			file[0][pref + 1].value == file[1][pref + 1].value;
19730Sstevel@tonic-gate 	    pref++)
19740Sstevel@tonic-gate 		;
19750Sstevel@tonic-gate 	for (suff = 0; (suff < len[0] - pref) &&
19760Sstevel@tonic-gate 			(suff < len[1] - pref) &&
19770Sstevel@tonic-gate 			(file[0][len[0] - suff].value ==
19780Sstevel@tonic-gate 			file[1][len[1] - suff].value);
19790Sstevel@tonic-gate 	    suff++)
19800Sstevel@tonic-gate 		;
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate 	/* decremnt suff by 2 iff suff >= 2, ensure that suff is never < 0 */
19830Sstevel@tonic-gate 	if (suff >= 2)
19840Sstevel@tonic-gate 		suff -= 2;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	for (j = 0; j < 2; j++) {
19870Sstevel@tonic-gate 		sfile[j] = file[j] + pref;
19880Sstevel@tonic-gate 		slen[j] = len[j] - pref - suff;
19890Sstevel@tonic-gate 		for (i = 0; i <= slen[j]; i++)
19900Sstevel@tonic-gate 			sfile[j][i].serial = i;
19910Sstevel@tonic-gate 	}
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate static void
equiv(struct line * a,int n,struct line * b,int m,int * c)19950Sstevel@tonic-gate equiv(struct line *a, int n, struct line *b, int m, int *c)
19960Sstevel@tonic-gate {
19970Sstevel@tonic-gate 	int i, j;
19980Sstevel@tonic-gate 	i = j = 1;
19990Sstevel@tonic-gate 	while (i <= n && j <= m) {
20000Sstevel@tonic-gate 		if (a[i].value < b[j].value)
20010Sstevel@tonic-gate 			a[i++].value = 0;
20020Sstevel@tonic-gate 		else if (a[i].value == b[j].value)
20030Sstevel@tonic-gate 			a[i++].value = j;
20040Sstevel@tonic-gate 		else
20050Sstevel@tonic-gate 			j++;
20060Sstevel@tonic-gate 	}
20070Sstevel@tonic-gate 	while (i <= n)
20080Sstevel@tonic-gate 		a[i++].value = 0;
20090Sstevel@tonic-gate 	b[m+1].value = 0;	j = 0;
20100Sstevel@tonic-gate 	while (++j <= m) {
20110Sstevel@tonic-gate 		c[j] = -b[j].serial;
20120Sstevel@tonic-gate 		while (b[j + 1].value == b[j].value) {
20130Sstevel@tonic-gate 			j++;
20140Sstevel@tonic-gate 			c[j] = b[j].serial;
20150Sstevel@tonic-gate 		}
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate 	c[j] = -1;
20180Sstevel@tonic-gate }
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate static void
done(void)20210Sstevel@tonic-gate done(void)
20220Sstevel@tonic-gate {
20230Sstevel@tonic-gate 	if (whichtemp) (void) unlink(tempfile[0]);
20240Sstevel@tonic-gate 	if (whichtemp == 2) (void) unlink(tempfile[1]);
20250Sstevel@tonic-gate 	exit(status);
20260Sstevel@tonic-gate }
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate static void
noroom(void)20290Sstevel@tonic-gate noroom(void)
20300Sstevel@tonic-gate {
20310Sstevel@tonic-gate 	(void) fprintf(stderr, "diff: ");
20320Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("files too big, try -h\n"));
20330Sstevel@tonic-gate 	done();
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate static void
error(const char * s)20370Sstevel@tonic-gate error(const char *s)
20380Sstevel@tonic-gate {
20390Sstevel@tonic-gate 	(void) fprintf(stderr, "diff: ");
20400Sstevel@tonic-gate 	(void) fprintf(stderr, s);
20410Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
20420Sstevel@tonic-gate 	done();
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate static void
usage(void)20460Sstevel@tonic-gate usage(void)
20470Sstevel@tonic-gate {
20480Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
20490Sstevel@tonic-gate 		"usage: diff [-bitw] [-c | -e | -f | -h | -n | -u] file1 "
20500Sstevel@tonic-gate 			"file2\n"
20510Sstevel@tonic-gate 		"       diff [-bitw] [-C number | -U number] file1 file2\n"
20520Sstevel@tonic-gate 		"       diff [-bitw] [-D string] file1 file2\n"
20530Sstevel@tonic-gate 		"       diff [-bitw] [-c | -e | -f | -h | -n | -u] [-l] [-r] "
20540Sstevel@tonic-gate 			"[-s] [-S name] directory1 directory2\n"));
20550Sstevel@tonic-gate 	status = 2;
20560Sstevel@tonic-gate 	done();
20570Sstevel@tonic-gate }
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate #define	NW	1024
20600Sstevel@tonic-gate struct buff	{
20610Sstevel@tonic-gate 	FILE	*iop;	/* I/O stream */
20620Sstevel@tonic-gate 	char	buf[NW + MB_LEN_MAX];	/* buffer */
20630Sstevel@tonic-gate 	char	*ptr;	/* current pointer in the buffer */
20640Sstevel@tonic-gate 	int	buffered;	/* if non-zero, buffer has data */
20650Sstevel@tonic-gate 	long	offset;	/* offset in the file */
20660Sstevel@tonic-gate };
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate static struct buff bufwchar[2];
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate /*
20710Sstevel@tonic-gate  *	Initializes the buff structure for specified
20720Sstevel@tonic-gate  *	I/O stream.  Also sets the specified offset
20730Sstevel@tonic-gate  */
20740Sstevel@tonic-gate static void
initbuf(FILE * iop,int filen,long offset)20750Sstevel@tonic-gate initbuf(FILE *iop, int filen, long offset)
20760Sstevel@tonic-gate {
20770Sstevel@tonic-gate 	bufwchar[filen].iop = iop;
20780Sstevel@tonic-gate 	bufwchar[filen].ptr = NULL;
20790Sstevel@tonic-gate 	bufwchar[filen].buffered = 0;
20800Sstevel@tonic-gate 	bufwchar[filen].offset = offset;
20810Sstevel@tonic-gate }
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate /*
20840Sstevel@tonic-gate  * 	Reset a buff structure, and rewind the associated file.
20850Sstevel@tonic-gate  */
20860Sstevel@tonic-gate static void
resetbuf(int filen)20870Sstevel@tonic-gate resetbuf(int filen)
20880Sstevel@tonic-gate {
20890Sstevel@tonic-gate 	bufwchar[filen].ptr = NULL;
20900Sstevel@tonic-gate 	bufwchar[filen].buffered = bufwchar[filen].offset = 0;
20910Sstevel@tonic-gate 	rewind(bufwchar[filen].iop);
20920Sstevel@tonic-gate }
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate /*
20960Sstevel@tonic-gate  *	Returns the current offset in the file
20970Sstevel@tonic-gate  */
20980Sstevel@tonic-gate static long
ftellbuf(int filen)20990Sstevel@tonic-gate ftellbuf(int filen)
21000Sstevel@tonic-gate {
21010Sstevel@tonic-gate 	return (bufwchar[filen].offset);
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate static wint_t
wcput(wint_t wc)21050Sstevel@tonic-gate wcput(wint_t wc)
21060Sstevel@tonic-gate {
21070Sstevel@tonic-gate 	char	mbs[MB_LEN_MAX];
21080Sstevel@tonic-gate 	unsigned char	*p;
21090Sstevel@tonic-gate 	int	n;
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 	n = wctomb(mbs, (wchar_t)wc);
21120Sstevel@tonic-gate 	if (n > 0) {
21130Sstevel@tonic-gate 		p = (unsigned char *)mbs;
21140Sstevel@tonic-gate 		while (n--) {
21150Sstevel@tonic-gate 			(void) putc((*p++), stdout);
21160Sstevel@tonic-gate 		}
21170Sstevel@tonic-gate 		return (wc);
21180Sstevel@tonic-gate 	} else if (n < 0) {
21190Sstevel@tonic-gate 		(void) putc((int)(wc & 0xff), stdout);
21200Sstevel@tonic-gate 		return (wc & 0xff);
21210Sstevel@tonic-gate 	} else {
21220Sstevel@tonic-gate 		/* this should not happen */
21230Sstevel@tonic-gate 		return (WEOF);
21240Sstevel@tonic-gate 	}
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate /*
21280Sstevel@tonic-gate  *	Reads one wide-character from the file associated with filen.
21290Sstevel@tonic-gate  *	If multibyte locales, the input is buffered.
21300Sstevel@tonic-gate  *
21310Sstevel@tonic-gate  *	Input:	filen	the file number (0 or 1)
21320Sstevel@tonic-gate  *	Output:	*len	number of bytes to make wide-character
21330Sstevel@tonic-gate  *	Return:			wide-character
21340Sstevel@tonic-gate  */
21350Sstevel@tonic-gate static wint_t
getbufwchar(int filen,int * len)21360Sstevel@tonic-gate getbufwchar(int filen, int *len)
21370Sstevel@tonic-gate {
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	int	i, num, clen;
21400Sstevel@tonic-gate 	wchar_t	wc;
21410Sstevel@tonic-gate 	size_t	mxlen;
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	if (mbcurmax == 1) {
21440Sstevel@tonic-gate 		/* If sigle byte locale, use getc() */
21450Sstevel@tonic-gate 		int	ch;
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 		ch = getc(bufwchar[filen].iop);
21480Sstevel@tonic-gate 		bufwchar[filen].offset++;
21490Sstevel@tonic-gate 		*len = 1;
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 		if (isascii(ch) || (ch == EOF)) {
21520Sstevel@tonic-gate 			return ((wint_t)ch);
21530Sstevel@tonic-gate 		} else {
21540Sstevel@tonic-gate 			wchar_t	wc;
21550Sstevel@tonic-gate 			char	str[2] = {0, 0};
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 			str[0] = (char)ch;
21580Sstevel@tonic-gate 			if (mbtowc(&wc, str, 1) > 0) {
21590Sstevel@tonic-gate 				return ((wint_t)wc);
21600Sstevel@tonic-gate 			} else {
21610Sstevel@tonic-gate 				return ((wint_t)ch);
21620Sstevel@tonic-gate 			}
21630Sstevel@tonic-gate 		}
21640Sstevel@tonic-gate 	} else {
21650Sstevel@tonic-gate 		mxlen = mbcurmax;
21660Sstevel@tonic-gate 	}
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	if (bufwchar[filen].buffered == 0) {
21690Sstevel@tonic-gate 		/* Not buffered */
21700Sstevel@tonic-gate 		bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX]);
21710Sstevel@tonic-gate 		num = fread((void *)bufwchar[filen].ptr,
21720Sstevel@tonic-gate 			sizeof (char), NW, bufwchar[filen].iop);
21730Sstevel@tonic-gate 		if (ferror(bufwchar[filen].iop)) {
21740Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
21750Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Error reading "));
21760Sstevel@tonic-gate 			perror((filen == 0) ? file1 : file2);
21770Sstevel@tonic-gate 			status = 2;
21780Sstevel@tonic-gate 			done();
21790Sstevel@tonic-gate 		}
21800Sstevel@tonic-gate 		if (num == 0)
21810Sstevel@tonic-gate 			return (WEOF);
21820Sstevel@tonic-gate 		bufwchar[filen].buffered = num;
21830Sstevel@tonic-gate 	}
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	if (bufwchar[filen].buffered < mbcurmax) {
21860Sstevel@tonic-gate 		for (i = 0; i < bufwchar[filen].buffered; i++) {
21870Sstevel@tonic-gate 			bufwchar[filen].buf[MB_LEN_MAX -
21880Sstevel@tonic-gate 				(bufwchar[filen].buffered - i)] =
21890Sstevel@tonic-gate 				*(bufwchar[filen].ptr + i);
21900Sstevel@tonic-gate 		}
21910Sstevel@tonic-gate 		bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX]);
21920Sstevel@tonic-gate 		num = fread((void *)bufwchar[filen].ptr,
21930Sstevel@tonic-gate 			sizeof (char), NW, bufwchar[filen].iop);
21940Sstevel@tonic-gate 		if (ferror(bufwchar[filen].iop)) {
21950Sstevel@tonic-gate 			(void) fprintf(stderr, "diff: ");
21960Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Error reading "));
21970Sstevel@tonic-gate 			perror((filen == 0) ? file1 : file2);
21980Sstevel@tonic-gate 			status = 2;
21990Sstevel@tonic-gate 			done();
22000Sstevel@tonic-gate 		}
22010Sstevel@tonic-gate 		bufwchar[filen].ptr = &(bufwchar[filen].buf[MB_LEN_MAX -
22020Sstevel@tonic-gate 				bufwchar[filen].buffered]);
22030Sstevel@tonic-gate 		bufwchar[filen].buffered += num;
22040Sstevel@tonic-gate 		if (bufwchar[filen].buffered < mbcurmax) {
22050Sstevel@tonic-gate 			mxlen = bufwchar[filen].buffered;
22060Sstevel@tonic-gate 		}
22070Sstevel@tonic-gate 	}
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	clen = mbtowc(&wc, bufwchar[filen].ptr, mxlen);
22100Sstevel@tonic-gate 	if (clen <= 0) {
22110Sstevel@tonic-gate 		(bufwchar[filen].buffered)--;
22120Sstevel@tonic-gate 		*len = 1;
22130Sstevel@tonic-gate 		(bufwchar[filen].offset)++;
22140Sstevel@tonic-gate 		wc = (wchar_t)((unsigned char)*bufwchar[filen].ptr++);
22150Sstevel@tonic-gate 		return ((wint_t)wc);
22160Sstevel@tonic-gate 	} else {
22170Sstevel@tonic-gate 		bufwchar[filen].buffered -= clen;
22180Sstevel@tonic-gate 		bufwchar[filen].ptr += clen;
22190Sstevel@tonic-gate 		bufwchar[filen].offset += clen;
22200Sstevel@tonic-gate 		*len = clen;
22210Sstevel@tonic-gate 		return ((wint_t)wc);
22220Sstevel@tonic-gate 	}
22230Sstevel@tonic-gate }
2224