hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

diffdir.c (23544B)


      1 /*
      2  * This code contains changes by
      3  * Gunnar Ritter, Freiburg i. Br., Germany, March 2003. All rights reserved.
      4  *
      5  * Conditions 1, 2, and 4 and the no-warranty notice below apply
      6  * to these changes.
      7  *
      8  *
      9  * Copyright (c) 1991
     10  * 	The Regents of the University of California.  All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  * 	This product includes software developed by the University of
     23  * 	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  *
     40  *
     41  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  *   Redistributions of source code and documentation must retain the
     47  *    above copyright notice, this list of conditions and the following
     48  *    disclaimer.
     49  *   Redistributions in binary form must reproduce the above copyright
     50  *    notice, this list of conditions and the following disclaimer in the
     51  *    documentation and/or other materials provided with the distribution.
     52  *   All advertising materials mentioning features or use of this software
     53  *    must display the following acknowledgement:
     54  *      This product includes software developed or owned by Caldera
     55  *      International, Inc.
     56  *   Neither the name of Caldera International, Inc. nor the names of
     57  *    other contributors may be used to endorse or promote products
     58  *    derived from this software without specific prior written permission.
     59  *
     60  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
     61  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
     62  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     63  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     64  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
     65  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
     66  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     67  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     68  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     69  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     70  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     71  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     72  */
     73 
     74 /*	Sccsid @(#)diffdir.c	1.30 (gritter) 1/22/06>	*/
     75 /*	from 4.3BSD diffdir.c	4.9 (Berkeley) 8/28/84	*/
     76 
     77 #include "diff.h"
     78 #include <sys/types.h>
     79 #include <sys/stat.h>
     80 #include <sys/wait.h>
     81 #include <fcntl.h>
     82 #include <unistd.h>
     83 #include <time.h>
     84 #include <signal.h>
     85 #include "sigset.h"
     86 #include "pathconf.h"
     87 
     88 #ifdef	__GLIBC__	/* old glibcs don't know _XOPEN_SOURCE=600L yet */
     89 #ifndef	S_IFSOCK
     90 #ifdef	__S_IFSOCK
     91 #define	S_IFSOCK	__S_IFSOCK
     92 #endif	/* __S_IFSOCK */
     93 #endif	/* !S_IFSOCK */
     94 #endif	/* __GLIBC__ */
     95 
     96 /*
     97  * diff - directory comparison
     98  */
     99 #define	d_flags	d_ino
    100 
    101 #define	ONLY	1		/* Only in this directory */
    102 #define	SAME	2		/* Both places and same */
    103 #define	DIFFER	4		/* Both places and different */
    104 #define	DIRECT	8		/* Directory */
    105 
    106 struct dir {
    107 	unsigned long long	d_ino;
    108 	char	*d_entry;
    109 };
    110 
    111 static int	header;
    112 static char	*title, *etitle;
    113 static size_t	titlesize;
    114 static char	procself[40];
    115 
    116 static void	setfile(char **, char **, const char *);
    117 static void	scanpr(register struct dir *, int, const char *, const char *,
    118 			const char *, const char *, const char *);
    119 static void	only(struct dir *, int);
    120 static struct dir	*setupdir(const char *);
    121 static int	entcmp(const struct dir *, const struct dir *);
    122 static void	compare(struct dir *, char **);
    123 static void	calldiff(const char *, char **);
    124 static int	useless(register const char *);
    125 static const char	*mtof(mode_t mode);
    126 static void	putN(const char *, const char *, const char *, int);
    127 static void	putNreg(const char *, const char *, time_t, int);
    128 static void	putNnorm(FILE *, const char *, const char *,
    129 			FILE *, long long, int);
    130 static void	putNedit(FILE *, const char *, const char *,
    131 			FILE *, long long, int, int);
    132 static void	putNcntx(FILE *, const char *, const char *,
    133 			time_t, FILE *, long long, int);
    134 static void	putNunif(FILE *, const char *, const char *,
    135 			time_t, FILE *, long long, int);
    136 static void	putNhead(FILE *, const char *, const char *, time_t, int,
    137 			const char *, const char *);
    138 static void	putNdata(FILE *, FILE *, int, int);
    139 static void	putNdir(const char *, const char *, int);
    140 static long long	linec(const char *, FILE *);
    141 static char	*mkpath(const char *, const char *);
    142 static void	mktitle(void);
    143 static int	xclude(const char *);
    144 
    145 void
    146 diffdir(char **argv)
    147 {
    148 	register struct dir *d1, *d2;
    149 	struct dir *dir1, *dir2;
    150 	register int i, n;
    151 	int cmp;
    152 
    153 	if (opt == D_IFDEF) {
    154 		fprintf(stderr, "%s: can't specify -I with directories\n",
    155 				progname);
    156 		done();
    157 	}
    158 	status = 0;
    159 	if (opt == D_EDIT && (sflag || lflag))
    160 		fprintf(stderr,
    161 		    "%s: warning: shouldn't give -s or -l with -e\n",
    162 		    progname);
    163 	for (n = 6, i = 1; diffargv[i+2]; i++)
    164 		n += strlen(diffargv[i]) + 1;
    165 	if (n > titlesize)
    166 		title = ralloc(title, titlesize = n);
    167 	title[0] = 0;
    168 	strcpy(title, "diff ");
    169 	for (i = 1; diffargv[i+2]; i++) {
    170 		if (!strcmp(diffargv[i], "-"))
    171 			continue;	/* was -S, dont look silly */
    172 		strcat(title, diffargv[i]);
    173 		strcat(title, " ");
    174 	}
    175 	for (etitle = title; *etitle; etitle++)
    176 		;
    177 	/*
    178 	 * This works around a bug present in (at least) Solaris 8 and
    179 	 * 9: If exec() is called with /proc/self/object/a.out, the
    180 	 * process hangs. It is possible, though, to use the executable
    181 	 * of another process. So the parent diff is used instead of the
    182 	 * forked child.
    183 	 */
    184 	i = getpid();
    185 	snprintf(procself, sizeof procself,
    186 #if defined (__linux__)
    187 			"/proc/%d/exe",
    188 #elif defined (__FreeBSD__) || defined (__DragonFly__) || defined (__APPLE__)
    189 			"/proc/%d/file",
    190 #else	/* !__linux__, !__FreeBSD__, !__APPLE__ */
    191 			"/proc/%d/object/a.out",
    192 #endif	/* !__linux__, !__FreeBSD__, !__APPLE__ */
    193 			i);
    194 	setfile(&file1, &efile1, file1);
    195 	setfile(&file2, &efile2, file2);
    196 	argv[0] = file1;
    197 	argv[1] = file2;
    198 	dir1 = setupdir(file1);
    199 	dir2 = setupdir(file2);
    200 	d1 = dir1; d2 = dir2;
    201 	while (d1->d_entry != 0 || d2->d_entry != 0) {
    202 		if (d1->d_entry && useless(d1->d_entry)) {
    203 			d1++;
    204 			continue;
    205 		}
    206 		if (d2->d_entry && useless(d2->d_entry)) {
    207 			d2++;
    208 			continue;
    209 		}
    210 		if (d1->d_entry == 0)
    211 			cmp = 1;
    212 		else if (d2->d_entry == 0)
    213 			cmp = -1;
    214 		else
    215 			cmp = strcmp(d1->d_entry, d2->d_entry);
    216 		if (cmp < 0) {
    217 			if (lflag && !(Nflag&1))
    218 				d1->d_flags |= ONLY;
    219 			else if (Nflag&1 || opt == D_NORMAL ||
    220 					opt == D_CONTEXT || opt == D_UNIFIED)
    221 				only(d1, 1);
    222 			d1++;
    223 		} else if (cmp == 0) {
    224 			compare(d1, argv);
    225 			d1++;
    226 			d2++;
    227 		} else {
    228 			if (lflag && !(Nflag&2))
    229 				d2->d_flags |= ONLY;
    230 			else if (Nflag&2 || opt == D_NORMAL ||
    231 					opt == D_CONTEXT || opt == D_UNIFIED)
    232 				only(d2, 2);
    233 			d2++;
    234 		}
    235 	}
    236 	if (lflag) {
    237 		scanpr(dir1, ONLY, "Only in %.*s", file1, efile1, 0, 0);
    238 		scanpr(dir2, ONLY, "Only in %.*s", file2, efile2, 0, 0);
    239 		scanpr(dir1, SAME, "Common identical files in %.*s and %.*s",
    240 		    file1, efile1, file2, efile2);
    241 		scanpr(dir1, DIFFER, "Binary files which differ in %.*s and %.*s",
    242 		    file1, efile1, file2, efile2);
    243 		scanpr(dir1, DIRECT, "Common subdirectories of %.*s and %.*s",
    244 		    file1, efile1, file2, efile2);
    245 	}
    246 	if (rflag) {
    247 		if (header && lflag)
    248 			printf("\f");
    249 		for (d1 = dir1; d1->d_entry; d1++)  {
    250 			if ((d1->d_flags & DIRECT) == 0)
    251 				continue;
    252 			strcpy(efile1, d1->d_entry);
    253 			strcpy(efile2, d1->d_entry);
    254 			calldiff(0, argv);
    255 		}
    256 	}
    257 }
    258 
    259 static void
    260 setfile(char **fpp, char **epp, const char *file)
    261 {
    262 	register char *cp;
    263 	int	n;
    264 
    265 	if ((n = pathconf(file, _PC_PATH_MAX)) < 1024)
    266 		n = 1024;
    267 	*fpp = dalloc(strlen(file) + 2 + n);
    268 	if (*fpp == 0) {
    269 		oomsg(": ran out of memory\n");
    270 		exit(1);
    271 	}
    272 	strcpy(*fpp, file);
    273 	for (cp = *fpp; *cp; cp++)
    274 		continue;
    275 	*cp++ = '/';
    276 	*cp = '\0';
    277 	*epp = cp;
    278 }
    279 
    280 static void
    281 scanpr(register struct dir *dp, int test, const char *title,
    282 		const char *file1, const char *efile1,
    283 		const char *file2, const char *efile2)
    284 {
    285 	int titled = 0;
    286 
    287 	for (; dp->d_entry; dp++) {
    288 		if ((dp->d_flags & test) == 0)
    289 			continue;
    290 		if (titled == 0) {
    291 			if (header == 0)
    292 				header = 1;
    293 			else
    294 				printf("\n");
    295 			printf(title,
    296 			    efile1 - file1 - 1, file1,
    297 			    efile2 - file2 - 1, file2);
    298 			printf(":\n");
    299 			titled = 1;
    300 		}
    301 		printf("\t%s\n", dp->d_entry);
    302 	}
    303 }
    304 
    305 static void
    306 only(struct dir *dp, int which)
    307 {
    308 	char *file = which == 1 ? file1 : file2;
    309 	char *other = which == 1 ? file2 : file1;
    310 	char *efile = which == 1 ? efile1 : efile2;
    311 	char *eother = which == 1 ? efile2 : efile1;
    312 
    313 	if (Nflag&which) {
    314 		char	c = file[efile - file - 1];
    315 		char	d = other[eother - other - 1];
    316 		file[efile - file - 1] = '\0';
    317 		other[eother - other - 1] = '\0';
    318 		putN(file, other, dp->d_entry, which);
    319 		file[efile - file - 1] = c;
    320 		other[eother - other - 1] = d;
    321 	} else
    322 		printf("Only in %.*s: %s\n", (int)(efile - file - 1), file,
    323 				dp->d_entry);
    324 	status = 1;
    325 }
    326 
    327 static struct dir *
    328 setupdir(const char *cp)
    329 {
    330 	register struct dir *dp = 0, *ep;
    331 	register struct dirent *rp;
    332 	register int nitems;
    333 	DIR *dirp;
    334 
    335 	dirp = opendir(cp);
    336 	if (dirp == NULL) {
    337 		fprintf(stderr, "%s: %s: %s\n", progname, cp, strerror(errno));
    338 		done();
    339 	}
    340 	nitems = 0;
    341 	dp = dalloc(sizeof (struct dir));
    342 	if (dp == 0) {
    343 		oomsg(": ran out of memory\n");
    344 		status = 2;
    345 		done();
    346 	}
    347 	while (rp = readdir(dirp)) {
    348 		if (xflag && xclude(rp->d_name))
    349 			continue;
    350 		ep = &dp[nitems++];
    351 		ep->d_entry = 0;
    352 		ep->d_flags = 0;
    353 		ep->d_entry = dalloc(strlen(rp->d_name) + 1);
    354 		if (ep->d_entry == 0) {
    355 			oomsg(": out of memory\n");
    356 			status = 2;
    357 			done();
    358 		}
    359 		strcpy(ep->d_entry, rp->d_name);
    360 		dp = ralloc(dp, (nitems + 1) * sizeof (struct dir));
    361 	}
    362 	dp[nitems].d_entry = 0;		/* delimiter */
    363 	closedir(dirp);
    364 	qsort(dp, nitems, sizeof (struct dir),
    365 			(int (*)(const void *, const void *))entcmp);
    366 	return (dp);
    367 }
    368 
    369 static int
    370 entcmp(const struct dir *d1, const struct dir *d2)
    371 {
    372 	return (strcmp(d1->d_entry, d2->d_entry));
    373 }
    374 
    375 static void
    376 compare(struct dir *dp, char **argv)
    377 {
    378 	register int i, j;
    379 	int f1 = -1, f2 = -1;
    380 	mode_t fmt1, fmt2;
    381 	struct stat stb1, stb2;
    382 	char buf1[BUFSIZ], buf2[BUFSIZ];
    383 
    384 	strcpy(efile1, dp->d_entry);
    385 	strcpy(efile2, dp->d_entry);
    386 	if (stat(file1, &stb1) < 0 || (fmt1 = stb1.st_mode&S_IFMT) == S_IFREG &&
    387 			(f1 = open(file1, O_RDONLY)) < 0) {
    388 		perror(file1);
    389 		status = 2;
    390 		return;
    391 	}
    392 	if (stat(file2, &stb2) < 0 || (fmt2 = stb2.st_mode&S_IFMT) == S_IFREG &&
    393 			(f2 = open(file2, O_RDONLY)) < 0) {
    394 		perror(file2);
    395 		close(f1);
    396 		status = 2;
    397 		return;
    398 	}
    399 	if (fmt1 != S_IFREG || fmt2 != S_IFREG) {
    400 		if (fmt1 == fmt2) {
    401 			switch (fmt1) {
    402 			case S_IFDIR:
    403 				dp->d_flags = DIRECT;
    404 				if (lflag || opt == D_EDIT)
    405 					goto closem;
    406 				if (opt != D_UNIFIED)
    407 					printf("Common subdirectories: "
    408 						"%s and %s\n",
    409 				    		file1, file2);
    410 				goto closem;
    411 			case S_IFBLK:
    412 			case S_IFCHR:
    413 				if (stb1.st_rdev == stb2.st_rdev)
    414 					goto same;
    415 				printf("Special files %s and %s differ\n",
    416 						file1, file2);
    417 				break;
    418 			case S_IFIFO:
    419 				if (stb1.st_dev == stb2.st_dev &&
    420 						stb1.st_ino == stb2.st_ino)
    421 					goto same;
    422 				printf("Named pipes %s and %s differ\n",
    423 						file1, file2);
    424 				break;
    425 			default:
    426 				printf("Don't know how to compare "
    427 						"%ss %s and %s\n",
    428 						mtof(fmt1), file1, file2);
    429 			}
    430 		} else
    431 			printf("File %s is a %s while file %s is a %s\n",
    432 					file1, mtof(fmt1), file2, mtof(fmt2));
    433 		if (lflag)
    434 			dp->d_flags |= DIFFER;
    435 		status = 1;
    436 		goto closem;
    437 	}
    438 	if (stb1.st_size != stb2.st_size)
    439 		goto notsame;
    440 	if (stb1.st_dev == stb2.st_dev && stb1.st_ino == stb2.st_ino)
    441 		goto same;
    442 	for (;;) {
    443 		i = read(f1, buf1, BUFSIZ);
    444 		j = read(f2, buf2, BUFSIZ);
    445 		if (i < 0 || j < 0 || i != j)
    446 			goto notsame;
    447 		if (i == 0 && j == 0)
    448 			goto same;
    449 		for (j = 0; j < i; j++)
    450 			if (buf1[j] != buf2[j])
    451 				goto notsame;
    452 	}
    453 same:
    454 	if (sflag == 0)
    455 		goto closem;
    456 	if (lflag)
    457 		dp->d_flags = SAME;
    458 	else
    459 		printf("Files %s and %s are identical\n", file1, file2);
    460 	goto closem;
    461 notsame:
    462 	if (!aflag && (!ascii(f1) || !ascii(f2))) {
    463 		if (lflag)
    464 			dp->d_flags |= DIFFER;
    465 		else if (opt == D_NORMAL || opt == D_CONTEXT ||
    466 				opt == D_UNIFIED)
    467 			printf("Binary files %s and %s differ\n",
    468 			    file1, file2);
    469 		status = 1;
    470 		goto closem;
    471 	}
    472 	close(f1); close(f2);
    473 	anychange = 1;
    474 	if (lflag)
    475 		calldiff(title, argv);
    476 	else {
    477 		if (opt == D_EDIT) {
    478 			printf("ed - %s << '-*-END-*-'\n", dp->d_entry);
    479 			calldiff(0, argv);
    480 		} else {
    481 			printf("%s%s %s\n", title, file1, file2);
    482 			calldiff(0, argv);
    483 		}
    484 		if (opt == D_EDIT)
    485 			printf("w\nq\n-*-END-*-\n");
    486 	}
    487 	return;
    488 closem:
    489 	close(f1); close(f2);
    490 }
    491 
    492 static void
    493 stackdiff(char **argv)
    494 {
    495 	int	oanychange;
    496 	char	*ofile1, *ofile2, *oefile1, *oefile2;
    497 	struct stat	ostb1, ostb2;
    498 	struct stackblk	*ocurstack;
    499 	char	*oargv[2];
    500 	int	oheader;
    501 	char	*otitle, *oetitle;
    502 	size_t	otitlesize;
    503 	jmp_buf	orecenv;
    504 
    505 	(void)&oargv;
    506 	recdepth++;
    507 	oanychange = anychange;
    508 	ofile1 = file1;
    509 	ofile2 = file2;
    510 	oefile1 = efile1;
    511 	oefile2 = efile2;
    512 	ostb1 = stb1;
    513 	ostb2 = stb2;
    514 	ocurstack = curstack;
    515 	oargv[0] = argv[0];
    516 	oargv[1] = argv[1];
    517 	oheader = header;
    518 	otitle = title;
    519 	oetitle = etitle;
    520 	otitlesize = titlesize;
    521 	memcpy(orecenv, recenv, sizeof orecenv);
    522 
    523 	anychange = 0;
    524 	file1 = argv[0];
    525 	file2 = argv[1];
    526 	efile1 = NULL;
    527 	efile2 = NULL;
    528 	curstack = NULL;
    529 	header = 0;
    530 	title = NULL;
    531 	etitle = NULL;
    532 	titlesize = 0;
    533 
    534 	if (setjmp(recenv) == 0)
    535 		diffany(argv);
    536 	purgestack();
    537 
    538 	anychange = oanychange;
    539 	file1 = ofile1;
    540 	file2 = ofile2;
    541 	efile1 = oefile1;
    542 	efile2 = oefile2;
    543 	stb1 = ostb1;
    544 	stb2 = ostb2;
    545 	curstack = ocurstack;
    546 	argv[0] = oargv[0];
    547 	argv[1] = oargv[1];
    548 	header = oheader;
    549 	title = otitle;
    550 	etitle = oetitle;
    551 	titlesize = otitlesize;
    552 	memcpy(recenv, orecenv, sizeof recenv);
    553 	recdepth--;
    554 }
    555 
    556 static const char	*prargs[] = { "pr", "-h", 0, "-f", 0, 0 };
    557 
    558 static void
    559 calldiff(const char *wantpr, char **argv)
    560 {
    561 	int pid, cstatus, cstatus2, pv[2];
    562 
    563 	if (wantpr == NULL && hflag == 0) {
    564 		stackdiff(argv);
    565 		return;
    566 	}
    567 	prargs[2] = wantpr;
    568 	fflush(stdout);
    569 	if (wantpr) {
    570 		mktitle();
    571 		pipe(pv);
    572 		pid = fork();
    573 		if (pid == -1) {
    574 			fprintf(stderr, "No more processes\n");
    575 			done();
    576 		}
    577 		if (pid == 0) {
    578 			close(0);
    579 			dup(pv[0]);
    580 			close(pv[0]);
    581 			close(pv[1]);
    582 			execvp(pr, (char **)prargs);
    583 			perror(pr);
    584 			done();
    585 		}
    586 	}
    587 	pid = fork();
    588 	if (pid == -1) {
    589 		fprintf(stderr, "%s: No more processes\n", progname);
    590 		done();
    591 	}
    592 	if (pid == 0) {
    593 		if (wantpr) {
    594 			close(1);
    595 			dup(pv[1]);
    596 			close(pv[0]);
    597 			close(pv[1]);
    598 		}
    599 		execv(procself, diffargv);
    600 		execv(argv0, diffargv);
    601 		execvp(diff, diffargv);
    602 		perror(diff);
    603 		done();
    604 	}
    605 	if (wantpr) {
    606 		close(pv[0]);
    607 		close(pv[1]);
    608 	}
    609 	while (wait(&cstatus) != pid)
    610 		continue;
    611 	if (cstatus != 0) {
    612 		if (WIFEXITED(cstatus) && WEXITSTATUS(cstatus) == 1)
    613 			status = 1;
    614 		else
    615 			status = 2;
    616 	}
    617 	while (wait(&cstatus2) != -1)
    618 		continue;
    619 /*
    620 	if ((status >> 8) >= 2)
    621 		done();
    622 */
    623 }
    624 
    625 int
    626 ascii(int f)
    627 {
    628 	char buf[BUFSIZ];
    629 	register int cnt;
    630 	register char *cp;
    631 
    632 	lseek(f, 0, 0);
    633 	cnt = read(f, buf, BUFSIZ);
    634 	cp = buf;
    635 	while (--cnt >= 0)
    636 		if (*cp++ == '\0')
    637 			return (0);
    638 	return (1);
    639 }
    640 
    641 /*
    642  * THIS IS CRUDE.
    643  */
    644 static int
    645 useless(register const char *cp)
    646 {
    647 
    648 	if (cp[0] == '.') {
    649 		if (cp[1] == '\0')
    650 			return (1);	/* directory "." */
    651 		if (cp[1] == '.' && cp[2] == '\0')
    652 			return (1);	/* directory ".." */
    653 	}
    654 	if (start && strcmp(start, cp) > 0)
    655 		return (1);
    656 	return (0);
    657 }
    658 
    659 static const char *
    660 mtof(mode_t mode)
    661 {
    662 	switch (mode) {
    663 	case S_IFDIR:
    664 		return "directory";
    665 	case S_IFCHR:
    666 		return "character special file";
    667 	case S_IFBLK:
    668 		return "block special file";
    669 	case S_IFREG:
    670 		return "plain file";
    671 	case S_IFIFO:
    672 		return "named pipe";
    673 #ifdef	S_IFSOCK
    674 	case S_IFSOCK:
    675 		return "socket";
    676 #endif	/* S_IFSOCK */
    677 	default:
    678 		return "unknown type";
    679 	}
    680 }
    681 
    682 static void
    683 putN(const char *dir, const char *odir, const char *file, int which)
    684 {
    685 	struct stat	st;
    686 	char	*path;
    687 	char	*opath;
    688 
    689 	path = mkpath(dir, file);
    690 	opath = mkpath(odir, file);
    691 	if (stat(path, &st) < 0) {
    692 		fprintf(stderr, "%s: %s: %s\n", progname, path,
    693 				strerror(errno));
    694 		status = 2;
    695 		goto out;
    696 	}
    697 	switch (st.st_mode & S_IFMT) {
    698 	case S_IFREG:
    699 		putNreg(path, opath, st.st_mtime, which);
    700 		break;
    701 	case S_IFDIR:
    702 		putNdir(path, opath, which);
    703 		break;
    704 	default:
    705 		printf("Only in %s: %s\n", dir, file);
    706 	}
    707 out:	tfree(path);
    708 	tfree(opath);
    709 }
    710 
    711 static void
    712 putNreg(const char *fn, const char *on, time_t mtime, int which)
    713 {
    714 	long long	lines;
    715 	FILE	*fp;
    716 	FILE	*op;
    717 	void	(*opipe)(int) = SIG_DFL;
    718 	pid_t	pid = 0;
    719 
    720 	if ((fp = fopen(fn, "r")) == NULL) {
    721 		fprintf(stderr, "%s: %s: %s\n", progname, fn, strerror(errno));
    722 		status = 2;
    723 		return;
    724 	}
    725 	if ((lines = linec(fn, fp)) == 0 || fseek(fp, 0, SEEK_SET) != 0)
    726 		goto out;
    727 	if (lflag) {
    728 		int	pv[2];
    729 		opipe = sigset(SIGPIPE, SIG_IGN);
    730 		fflush(stdout);
    731 		prargs[2] = title;
    732 		pipe(pv);
    733 		switch (pid = fork()) {
    734 		case -1:
    735 			fprintf(stderr, "No more processes\n");
    736 			done();
    737 			/*NOTREACHED*/
    738 		case 0:
    739 			close(0);
    740 			dup(pv[0]);
    741 			close(pv[0]);
    742 			close(pv[1]);
    743 			execvp(pr, (char **)prargs);
    744 			perror(pr);
    745 			done();
    746 		}
    747 		close(pv[0]);
    748 		op = fdopen(pv[1], "w");
    749 	} else
    750 		op = stdout;
    751 	fprintf(op, "%.*s %s %s\n", (int)(etitle - title - 1), title,
    752 			which == 1 ? fn : on,
    753 			which == 1 ? on : fn);
    754 	switch (opt) {
    755 	case D_NORMAL:
    756 		putNnorm(op, fn, on, fp, lines, which);
    757 		break;
    758 	case D_EDIT:
    759 		putNedit(op, fn, on, fp, lines, which, 0);
    760 		break;
    761 	case D_REVERSE:
    762 		putNedit(op, fn, on, fp, lines, which, 1);
    763 		break;
    764 	case D_CONTEXT:
    765 		putNcntx(op, fn, on, mtime, fp, lines, which);
    766 		break;
    767 	case D_NREVERSE:
    768 		putNedit(op, fn, on, fp, lines, which, 2);
    769 		break;
    770 	case D_UNIFIED:
    771 		putNunif(op, fn, on, mtime, fp, lines, which);
    772 		break;
    773 	}
    774 	if (lflag) {
    775 		fclose(op);
    776 		while (wait(NULL) != pid);
    777 		sigset(SIGPIPE, opipe);
    778 	}
    779 out:	fclose(fp);
    780 }
    781 
    782 static void
    783 putNnorm(FILE *op, const char *fn, const char *on,
    784 		FILE *fp, long long lines, int which)
    785 {
    786 	int	pfx;
    787 
    788 	if (which == 1) {
    789 		fprintf(op, "1,%lldd0\n", lines);
    790 		pfx = '<';
    791 	} else {
    792 		fprintf(op, "0a1,%lld\n", lines);
    793 		pfx = '>';
    794 	}
    795 	putNdata(op, fp, pfx, ' ');
    796 }
    797 
    798 static void
    799 putNedit(FILE *op, const char *fn, const char *on,
    800 		FILE *fp, long long lines, int which, int reverse)
    801 {
    802 	switch (reverse) {
    803 	case 0:
    804 		if (which == 1)
    805 			fprintf(op, "1,%lldd\n", lines);
    806 		else {
    807 			fprintf(op, "0a\n");
    808 			putNdata(op, fp, 0, 0);
    809 			fprintf(op, ".\n");
    810 		}
    811 		break;
    812 	case 1:
    813 		if (which == 1)
    814 			fprintf(op, "d1 %lld\n", lines);
    815 		else {
    816 			fprintf(op, "a0\n");
    817 			putNdata(op, fp, 0, 0);
    818 			fprintf(op, ".\n");
    819 		}
    820 		break;
    821 	case 2:
    822 		if (which == 1)
    823 			fprintf(op, "d1 %lld\n", lines);
    824 		else {
    825 			fprintf(op, "a0 %lld\n", lines);
    826 			putNdata(op, fp, 0, 0);
    827 		}
    828 		break;
    829 	}
    830 }
    831 
    832 static void
    833 putNcntx(FILE *op, const char *fn, const char *on, time_t mtime,
    834 		FILE *fp, long long lines, int which)
    835 {
    836 	putNhead(op, fn, on, mtime, which, "***", "---");
    837 	fprintf(op, "***************\n*** ");
    838 	if (which == 1)
    839 		fprintf(op, "1,%lld", lines);
    840 	else
    841 		putc('0', op);
    842 	fprintf(op, " ****\n");
    843 	if (which != 1)
    844 		fprintf(op, "--- 1,%lld ----\n", lines);
    845 	putNdata(op, fp, which == 1 ? '-' : '+', ' ');
    846 	if (which == 1)
    847 		fprintf(op, "--- 0 ----\n");
    848 }
    849 
    850 static void
    851 putNunif(FILE *op, const char *fn, const char *on, time_t mtime,
    852 		FILE *fp, long long lines, int which)
    853 {
    854 	putNhead(op, fn, on, mtime, which, "---", "+++");
    855 	fprintf(op, "@@ ");
    856 	fprintf(op, which == 1 ? "-1,%lld +0,0" : "-0,0 +1,%lld", lines);
    857 	fprintf(op, " @@\n");
    858 	putNdata(op, fp, which == 1 ? '-' : '+', 0);
    859 }
    860 
    861 static void
    862 putNhead(FILE *op, const char *fn, const char *on, time_t mtime, int which,
    863 		const char *p1, const char *p2)
    864 {
    865 	time_t	t1, t2;
    866 	const char	*f1, *f2;
    867 
    868 	t1 = which == 1 ? mtime : 0;
    869 	t2 = which == 1 ? 0 : mtime;
    870 	f1 = which == 1 ? fn : on;
    871 	f2 = which == 1 ? on : fn;
    872 	fprintf(op, "%s %s\t%s", p1, f1, ctime(&t1));
    873 	fprintf(op, "%s %s\t%s", p2, f2, ctime(&t2));
    874 }
    875 
    876 static void
    877 putNdata(FILE *op, FILE *fp, int pfx, int sec)
    878 {
    879 	int	c, lastc = '\n', col = 0;
    880 
    881 	while ((c = getc(fp)) != EOF) {
    882 		if (lastc == '\n') {
    883 			col = 0;
    884 			if (pfx)
    885 				putc(pfx, op);
    886 			if (sec)
    887 				putc(sec, op);
    888 		}
    889 		if (c == '\t' && tflag) {
    890 			do
    891 				putc(' ', op);
    892 			while (++col & 7);
    893 		} else {
    894 			putc(c, op);
    895 			col++;
    896 		}
    897 		lastc = c;
    898 	}
    899 	if (lastc != '\n') {
    900 		if (aflag)
    901 			fprintf(op, "\n\\ No newline at end of file\n");
    902 		else
    903 			putc('\n', op);
    904 	}
    905 }
    906 
    907 static void
    908 putNdir(const char *fn, const char *on, int which)
    909 {
    910 	DIR	*Dp;
    911 	struct dirent	*dp;
    912 
    913 	if ((Dp = opendir(fn)) == NULL) {
    914 		fprintf(stderr, "%s: %s: %s\n", progname, fn, strerror(errno));
    915 		status = 2;
    916 		return;
    917 	}
    918 	while ((dp = readdir(Dp)) != NULL) {
    919 		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
    920 					dp->d_name[1] == '.' &&
    921 					dp->d_name[2] == '\0'))
    922 			continue;
    923 		if (xflag && xclude(dp->d_name))
    924 			continue;
    925 		putN(fn, on, dp->d_name, which);
    926 	}
    927 	closedir(Dp);
    928 }
    929 
    930 static long long
    931 linec(const char *fn, FILE *fp)
    932 {
    933 	int	c, lastc = '\n';
    934 	long long	cnt = 0;
    935 
    936 	while ((c = getc(fp)) != EOF) {
    937 		if (c == '\n')
    938 			cnt++;
    939 		lastc = c;
    940 	}
    941 	if (lastc != '\n') {
    942 		if (!aflag)
    943 			fprintf(stderr,
    944 				"Warning: missing newline at end of file %s\n",
    945 				fn);
    946 		cnt++;
    947 	}
    948 	return cnt;
    949 }
    950 
    951 static char *
    952 mkpath(const char *dir, const char *file)
    953 {
    954 	char	*path, *pp;
    955 	const char	*cp;
    956 
    957 	pp = path = talloc(strlen(dir) + strlen(file) + 2);
    958 	for (cp = dir; *cp; cp++)
    959 		*pp++ = *cp;
    960 	if (pp > path && pp[-1] != '/')
    961 		*pp++ = '/';
    962 	for (cp = file; *cp; cp++)
    963 		*pp++ = *cp;
    964 	*pp = '\0';
    965 	return path;
    966 }
    967 
    968 static void
    969 mktitle(void)
    970 {
    971 	int	n;
    972 
    973 	n = strlen(file1) + strlen(file2) + 2;
    974 	if (etitle - title + n < titlesize) {
    975 		titlesize = n;
    976 		n = etitle - title;
    977 		title = ralloc(title, titlesize);
    978 		etitle = &title[n];
    979 	}
    980 	sprintf(etitle, "%s %s", file1, file2);
    981 }
    982 
    983 static int
    984 xclude(const char *fn)
    985 {
    986 	extern int	gmatch(const char *, const char *);
    987 	struct xclusion	*xp;
    988 
    989 	for (xp = xflag; xp; xp = xp->x_nxt)
    990 		if (gmatch(fn, xp->x_pat))
    991 			return 1;
    992 	return 0;
    993 }