[comp.sources.unix] v24i058: Purdue shell turbo charger and manual installer, Part02/06

rsalz@uunet.uu.net (Rich Salz) (03/20/91)

Submitted-by: Kevin Braunsdorf <ksb@cc.purdue.edu>
Posting-number: Volume 24, Issue 58
Archive-name: pucc-mk/part02

#!/bin/sh
# This is part 02 of pucc-1c
# ============= mk/mk.c ==============
if test ! -d 'mk'; then
    echo 'x - creating directory mk'
    mkdir 'mk'
fi
if test -f 'mk/mk.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mk/mk.c (File already exists)'
else
echo 'x - extracting mk/mk.c (Text)'
sed 's/^X//' << 'Purdue' > 'mk/mk.c' &&
/*
X * mk: detect and execute a compilation command 
X *	(formerly called 'compile')
X *
X * example marker line:
X *	$Compile: cc -c -O %f
X *	$Compile (TEKECS): cc -c -DLOG -O %f
X *	$Compile (DEBUG): cc -c -g -DDEBUG %f
X *	$Compile=1: cc ....
X *	$Compile,cpu=100: ....
X *
X * marker lines can also be drawn from a standard template
X *
X * This program searches for the first occurence of a marker (DEFLTMARK)
X * in the first block of the named file(s), grabs the line on which
X * the marker occurs, performs some filename substitutions on the line,
X * and prints the line (typically a shell command line) on the stdout.
X * It can also set resource limits for valid(1L).
X *
X * this programs currently makes lots of substitutions (see the man page).
X *
X * command-line switches:
X *	see mk.m or main.c (or run mk -h)
X *
X * (c) Copyright 1983, Steven McGeady.  All rights reserved.
X *
X * Written by S. McGeady, Intel, Inc., mcg@mipon2.intel.com		(sm)
X *	      Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb		(ksb)
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. The authors are not held responsible for any consequences of the
X *    use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors must appear
X *    in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X *
X * All bug fixes and improvements should be mailed to the authors,
X * if you can find them.
X */
X
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
X
#include "machine.h"
#include "getopt.h"
#include "main.h"
#include "mk.h"
#include "rlimsys.h"
X
#if !defined(MAXPATHLEN)
#define MAXPATHLEN	1024
#endif
X
#if RESOURCE
#include <sys/resource.h>
#include <sys/wait.h>
#endif
X
#if defined(S_IFLNK)
#define LSTAT lstat
#else
#define LSTAT stat
#endif
X
extern char *strcpy(), *strrchr(), *strchr();
extern char *getenv(), *rcsname();
extern int errno;
extern char *sys_errlist[];
#define strerror(Me) (sys_errlist[Me])
X
char acOutMem[] = "%s: out of memory!\n";
static int marklen, sublen;
static char *curfile, chFType;
static char acSearch[MAXPATHLEN+1];
X
#define	MAXLINE		BUFSIZ
#define	LEADCHAR	'$'
X
#if defined(AUXDIR)
static char acAuxDir[] = AUXDIR;
#endif	/* mk's default home	*/
X
#if defined(BEFORE)
static char acDefBefore[] = BEFORE;
#endif	/* default pre-scan	*/
X
#if defined(TEMPL)
static char acDefAfter[] = TEMPL;
#endif	/* default post-scan	*/
X
/*
X * option a good version description					(ksb)
X */
void
Version()
{
X	fprintf(stdout, "%s: %s\n", progname, "$Id: mk.c,v 4.6 90/11/19 14:06:30 ksb Exp $");
X	fprintf(stdout, "%s: %%~ `%s\'\n", progname, acAuxDir);
X	fprintf(stdout, "%s: -e `%s\'\n", progname,
X		(char *)0 != pchExamine ? pchExamine :
X	
#if defined(BEFORE)
X		acDefBefore
#else
X		""
#endif	/* default pre-scan	*/
X	);
X	fprintf(stdout, "%s: -t `%s\'\n", progname,
X		(char *)0 != pchTemplates ? pchTemplates :
#if defined(TEMPL)
X		acDefAfter
#else
X		""
#endif	/* default post-scan	*/
X	);
}
X
/*
X * strip the case from an ident upto len or a char in pchStop		(ksb)
X */
void
stripc(pchIdent, len, pchStop)
char *pchIdent, *pchStop;
int len;
{
X	register int i;
X
X	for (i = 0; i < len; ++i, ++pchIdent) {
X		if ((char *)0 != strchr(pchStop, *pchIdent))
X			break;
X		if (isupper(*pchIdent))
X			*pchIdent = tolower(*pchIdent);
X	}
}
X
/*
X * eat the submark portion 						(sm)
X */
char *
eatsub(pch, smark)
char *pch;
char *smark;
{
X	while (isspace(*pch)) {
X		++pch;
X	}
X
X	if ((char *)0 != smark) {
X		if ('(' != *pch) {
X			return (char *)0;
X		}
X
X		do
X			++pch;
X		while (isspace(*pch));
X		if (fCase)
X			stripc(pch, sublen, "):");
X		if ('*' == smark[0] && '\000' == smark[1]) {
X			while (')' != pch[0] && '\000' != pch[0])
X				++pch;
X		} else if ('*' == pch[0]) {
X			++pch;
X		} else if (0 != strncmp(pch, smark, sublen)) {
X			return (char *)0;
X		} else {
X			pch += sublen;
X		}
X
X		while (isspace(*pch)) {
X			++pch;
X		}
X		if (')' != *pch) {
X			return (char *)0;
X		}
X		do {
X			++pch;
X		} while (isspace(*pch));
X	} else if ('(' == *pch) {
X		while (')' != *pch)
X			++pch;
X		++pch;
X		while (isspace(*pch))
X			++pch;
X	}
X	return pch;
}
X
/*
X * find the end of the command string					(ksb)
X */
void
cut(pch)
char *pch;
{
X	register char *q;
X	register int c;
X
X	for (q = pch; '\000' != (c = *q); ++q) {
X		switch (c) {
X		case LEADCHAR:
X			if (LEADCHAR == q[1]) {
X		case '\n':
X				q[0] = '\000';
X				return;
X			}
X			break;
X		case '\\':
X			if ('\000' != q[1])
X				++q;
X			break;
X		default:
X			break;
X		}
X	}
}
X
/*
X * copy chars with C escapes etc...					(sm/ksb)
X * since ANSI C won't let us write on constant strings we need fColon
X * to stop on a colon durring template expansions
X */
char *
translit(dst, src, fColon)
register char *dst;
register char *src;
int fColon;
{
X	register char *tp;
X	register char *xp, *pcParam;
X	auto char sbPath[MAXPATHLEN+1];
X	auto char acTemp[8];		/* buf for recursive calls	*/
X	register int i;
X	register int num;
X	auto int fGrave;		/* change %`name` into ${name}	*/
X
#ifdef DEBUG
X	fprintf(stderr, "translit(%s)\n", src);
#endif
X
X	fGrave = 0;
X	pcParam = (char *)0;
X	while (*src) {
X		switch (*src) {
X		case '%':
X			switch (*++src) {
X			case 'A':
X			case 'a':
X				if (fAll || fFirst) {
X					if ('a' == *src)
X						*dst++ = '-';
X					*dst++ = fFirst ? 'A' : 'a';
X				}
X				break;
X
X			case 'B':
X				strcpy(dst, progname);
X				dst += strlen(dst);
X				break;
X
X			case 'b':
X				strcpy(dst, pathname);
X				dst += strlen(dst);
X				break;
X
X			case 'C':
X			case 'c':	/* mk command line flags */
X				if (fConfirm) {
X					if ('c' == *src)
X						*dst++ = '-';
X					*dst++ = 'c';
X				}
X				break;
X
X			case 'D':	/* if not remote, fail	*/
X			case 'd':	/* directory part	*/
X				if ((tp = strrchr(curfile, '/')) == NULL) {
X					if ('D' == *src)
X						if (debug)
X							fprintf(stderr, "%s: %s is not remote\n", progname, curfile);
X						return (char*)0;
X					break;
X				}
X				*tp = '\000';
X				strcpy(dst, curfile);
X				dst += strlen(curfile);
X				*tp = '/';
X				break;
X
X			case 'e':
X				if ((char *)0 == pchExamine)
X					break;
X				*dst++ = '-';
X				*dst++ = 'e';
X			case 'E':
X				if ((char *)0 == pchExamine)
X					break;
X				strcpy(dst, pchExamine);
X				dst += strlen(dst);
X				break;
X
X			case 'f':	/* full filename */
X				strcpy(dst, curfile);
X				dst += strlen(dst);
X				break;
X
X			case 'F':	/* file part only */
X				if ((tp = strrchr(curfile, '/')) != NULL) {
X					tp++;
X				} else {
X					tp = curfile;
X				}
X				if ((xp = strrchr(tp, '.')) != NULL) {
X					*xp = '\000';
X					strcpy(dst, tp);
X					*xp = '.';
X				} else {
X					strcpy(dst, tp);
X				}
X				dst += strlen(dst);
X				break;
X
X			case 'I':
X			case 'i':
X				if (fCase) {
X					if ('i' == *src)
X						*dst++ = '-';
X					*dst++ = 'i';
X				}
X				break;
X
X			case 'l':
X				*dst++ = '-';
X				*dst++ = 'l';
X			case 'L':
X				sprintf(dst, "%d", lines);
X				dst += strlen(dst);
X				break;
X
X			case 'm':	/* marker we need */
X			case 'M':	/* lower case marker for make rules */
X				if ('*' == markstr[0])
X					*dst++ = '\\';
X				strcpy(dst, markstr);
X				if ('M' == *src && !fCase)
X					stripc(dst, marklen, "");
X				dst += marklen;
X				break;
X
X			case 'N':
X			case 'n':
X				if (!fExec) {
X					if ('n' == *src)
X						*dst++ = '-';
X					*dst++ = 'n';
X				}
X				break;
X
X			case 'o':
X				*dst++ = '-';
X			case 'O': /* all switches, none can fail */
X				(void)translit(dst, "%A%C%I%N%V", 0);
X				dst += strlen(dst);
X				break;
X
X			case 'P':
X			case 'p':	/* prefix		*/
X				acTemp[0] = '%';
X				acTemp[1] = *src + ('Q' - 'P');
X				acTemp[2] = '.';
X				acTemp[3] = '\000';
X				if ((tp = translit(dst, acTemp, 0)) == NULL) {
X					return (char *)0;
X				}
X				dst += strlen(dst);
X				break;
X
X			case 'Q':
X			case 'q':	/* prefix-x, mostly internal	*/
X				if ((tp = strrchr(curfile, '/')) != NULL) {
X					++tp;
X				} else {
X					tp = curfile;
X				}
X				if ('\000' == *++src)
X					break;
X				if ((xp = strrchr(tp, *src)) != NULL) {
X					*xp = '\000';
X					strcpy(dst, curfile);
X					*xp = *src;
X				} else {
X					if ('Q' == src[-1])
X						return (char *)0;
X					strcpy(dst, curfile);
X				}
X				dst += strlen(dst);
X				break;
X
X			case 'R':	/* rcsbasename	*/
X				if ((tp = strrchr(curfile, '/')) != NULL) {
X					tp++;
X				} else {
X			case 'r':	/* rcsname	*/
X					tp = curfile;
X				}
X				tp = rcsname(tp);
X				if ((char *)0 == tp) {
X					if (debug)
X						fprintf(stderr, "%s: no rcsfile for %s\n", progname, curfile);
X					return (char *)0;
X				}
X				strcpy(dst, tp);
X				dst += strlen(dst);
X				break;
X
X			case 's': /* submarker we need */
X			case 'S': /* lower case submarker for make rules */
X				if ((char *)0 == submark) {
X					if (debug)
X						fprintf(stderr, "%s: no submarker for %s\n", progname, curfile);
X					return (char *)0;
X				}
X				if ('*' == submark[0])
X					*dst++ = '\\';
X				strcpy(dst, submark);
X				if ('S' == *src && !fCase)
X					stripc(dst, sublen, "");
X				dst += sublen;
X				break;
X
X			case 't':
X				if ((char *)0 == pchTemplates)
X					break;
X				*dst++ = '-';
X				*dst++ = 't';
X			case 'T':
X				if ((char *)0 == pchTemplates)
X					break;
X				strcpy(dst, pchTemplates);
X				dst += strlen(dst);
X				break;
X
X			case 'U':
X			case 'u':	/* extender-x, mostly internal	*/
X				if ((tp = strrchr(curfile, '/')) != NULL) {
X					++tp;
X				} else {
X					tp = curfile;
X				}
X				if ('\000' == *++src)
X					break;
X				if ((xp = strrchr(tp, *src)) != NULL) {
X					++xp;
X					strcpy(dst, xp);
X					dst += strlen(dst);
X				} else if ('U' == src[-1]) {
X					return (char *)0;
X				}
X				break;
X
X			case 'v':
X				*dst++ = '-';
X			case 'V':
X				*dst++ = fVerbose ? 'v' : 's';
X				if (debug)
X					*dst++ = 'V';
X				break;
X
X			case 'W':
X			case 'w':
X				if ((tp = strrchr(acSearch, '/')) == NULL) {
X					if ('W' == *src)
X						if (debug)
X							fprintf(stderr, "%s: %s is not remote\n", progname, acSearch);
X						return (char*)0;
X					break;
X				}
X				*tp = '\000';
X				strcpy(dst, acSearch);
X				dst += strlen(dst);
X				*tp = '/';
X				break;
X
X			case 'X':
X			case 'x':	/* extension		*/
X				acTemp[0] = '%';
X				acTemp[1] = *src + ('U' - 'X');
X				acTemp[2] = '.';
X				acTemp[3] = '\000';
X				if ((tp = translit(dst, acTemp, 0)) == NULL) {
X					return (char *)0;
X				}
X				dst += strlen(dst);
X				break;
X
X			case 'Y':
X				if ((*++src == '~') ? *++src == chFType : *src != chFType) {
X					if (debug)
X						fprintf(stderr, "%s: %s fails file type\n", progname, curfile);
X					return (char*)0;
X				}
X				break;
X
X			case 'y':	/* file type checks	*/
X				*dst++ = chFType;
X				break;
X
X			case 'Z':
X			case 'z':
X				if ((char *)0 == (tp = strrchr(acSearch, '/'))) {
X					tp = acSearch;
X				} else {
X					++tp;
X				}
X				if ('\000' == *tp) {
X					if (debug)
X						fprintf(stderr, "%s: %s: not a template\n", progname, curfile);
X					return (char*)0;
X				}
X				strcpy(dst, tp);
X				dst += strlen(dst);
X				break;
X
X			case '~':	/* mk's home directory, so to speak */
X				strcpy(dst, acAuxDir);
X				dst += strlen(dst);
X				break;
X				
X			case '\"':
X			case '`':
X				fGrave = 1;
X				/* FALLTHROUGH */
X			case '{':	/* } */
X				*dst++ = '$';
X				*dst++ = '{';	/* } */
X				pcParam = dst;
X				break;
X			default:	/* unrecognized chars are copied thru */
X				*dst++ = *src;
X				break;
X			}
X			src++;
X			break;
X
X		case '\\':
X			switch (*++src) {
X			case '\n':	/* how would this happen? */
X				++src;
X				break;
X			case 'n':	/* newline */
X				*dst++ = '\n';
X				++src;
X				break;
X			case 't':
X				*dst++ = '\t';
X				++src;
X				break;
X			case 'b':
X				*dst++ = '\b';
X				++src;
X				break;
X			case 'r':
X				*dst++ = '\r';
X				++src;
X				break;
X			case 'f':
X				*dst++ = '\f';
X				++src;
X				break;
X			case 'v':
X				*dst++ = '\013';
X				++src;
X				break;
X			case '\\':
X				++src;
X			case '\000':
X				*dst++ = '\\';
X				break;
X
X			case '0': case '1': case '2': case '3':
X			case '4': case '5': case '6': case '7':
X				num = *src++ - '0';
X				for (i = 0; i < 2; i++) {
X					if (! isdigit(*src)) {
X						break;
X					}
X					num <<= 3;
X					num += *src++ - '0';
X				}
X				*dst++ = num;
X				break;
X			case '8': case '9':
X				/* 8 & 9 are bogus octals,
X				 * cc makes them literals
X				 */
X				/*fallthrough*/
X			default:
X				*dst++ = *src++;
X				break;
X			}
X			break;
X		case '\"':
X		case '`':
X			if (fGrave) {
X		case /*{*/ '}':
X				*dst = '\000';
X				if ((char *)0 != pcParam && (char *)0 == getenv(pcParam)) {
X					if (debug)
X						fprintf(stderr, "%s: %s: %s: not set\n", progname, curfile, pcParam);
X					return (char *)0;
X				}
X				pcParam = (char *)0;
X				*dst++ = /*{*/ '}';
X				++src, fGrave = 0;
X				break;
X			}
X			*dst++ = *src++;
X			break;
X		case ':':
X			if (fColon) {
X				src = "";
X				break;
X			}
X			/*FALLTHROUGH*/
X		default:
X			*dst++ = *src++;
X			break;
X		}
X	}
X
X	*dst = '\000';
X	return dst;
}
X
#define EXIT_EXACT	0x00	/* an exact match			*/
#define EXIT_ANY	0x01	/* any value				*/
#define EXIT_NOT	0x02	/* not what was given			*/
typedef struct ECnode {
X	int ekey;		/* key for a match			*/
X	int ivalue;		/* value to match			*/
} CODE;
X
/*
X * Find a marker line in the given file, put it in a buffer and		(sm/ksb)
X * return a pointer to it.  Limitted to count lines.
X */
char *
findmarker(fin, buf, pexitcode, count)
register FILE *fin;
char *buf;
int count;
CODE *pexitcode;
{
X	register char *pch;
X	extern long atol();
X
X	if ((FILE *)0 == fin)
X		return (char *)0;
X	while ((char *)0 != (pch = fgets(buf, MAXLINE, fin))) {
X		if (--count < 0) {
X			pch = (char *)0;
X			if (debug)
X				fprintf(stderr, "%s: out of lines\n", progname);
X			break;
X		}
X		pch = strchr(buf, LEADCHAR);
X		if ((char *)0 == pch)
X			continue;
X
X		do {
X			++pch;
X		} while (isspace(*pch));
X
X		if (fCase)
X			stripc(pch, marklen, ":("/*)*/);
X		if ('*' == markstr[0] && '\000' == markstr[1]) {
X			while ('(' != pch[0] && ':' != pch[0] && '\000' != pch[0])
X				++pch;
X		} else if ('*' == pch[0]) {
X			++pch;
X		} else if (0 != strncmp(markstr, pch, marklen)) {
X			continue;
X		} else {
X			pch += marklen;
X		}
X
X		pch = eatsub(pch, submark);
X		if ((char *)0 == pch) {
X			continue;
X		}
X
X		/* set exit code */
X		pexitcode->ekey = EXIT_EXACT;
X		if ('=' == *pch) {
X			++pch;
X			while (isspace(*pch))
X				++pch;
X			if ('~' == *pch) { 	/* ~code	*/
X				pexitcode->ekey = EXIT_NOT;
X				++pch;
X			}
X			while (isspace(*pch))
X				++pch;
X			if ('*' == *pch) { 	/* any code	*/
X				pexitcode->ekey |= EXIT_ANY;
X				++pch;
X			} else {
X				pexitcode->ivalue = atol(pch);
X				if ('-' == *pch || '+' == *pch)
X					++pch;
X				while (isdigit(*pch))
X					++pch;
X			}
X			while (isspace(*pch))
X				++pch;
X		} else {
X			pexitcode->ivalue = 0;
X		}
X
#if RESOURCE
X		/* get resource limits		*/
X		do {
X			if (',' == *pch)
X				++pch;
X			stripc(pch, MAXLINE, ",:");
X			pch = rparse(pch);
X		} while (',' == *pch);
#else
X		/* try to eat resource limits	*/
X		pch = strchr(pch, ':');
X		if ((char *)0 == pch)
X			continue;
#endif /* resource limits */
X
X		if (':' != *pch)
X			continue;
X
X		/* found mk marker */
X		do {
X			++pch;
X		} while (isspace(*pch));
X		cut(pch);
X		break;
X	}
X	return pch;
}
X
/*
X * place a variable in the environment					(ksb)
X */
int
define(pch)
char *pch;
{
X	register char *p;
X
X	p = strchr(pch, '=');
X	if ((char *)0 == p) {
X		fprintf(stderr, "%s: missing `=\' for define of %s\n", progname, pch);
X		return;
X	}
X	p[0] = '\000';
X	setenv(pch, p+1);
X	p[0] = '=';
}
X
/*
X * remove a variable from the environment				(ksb)
X */
int
undefine(pch)
char *pch;
{
X	setenv(pch, (char *)0);
}
X
/*
X * we have a filename and are ready to open and find a marker in it	(sm/ksb)
X */
int
process(arg)
char *arg;
{
X	auto FILE *fin, *fpSrc;
X	auto char *pch, *pchSecond, *pchBefore, *pchLoop, *pchTrans;
X	auto int count, fFoundOne;
X	auto CODE exitcode;
X	auto char buf[MAXLINE];
X	auto char combuf[MAXLINE];
X	auto struct stat stIn;
X
#if RESOURCE
X	rinit();
X	r_fTrace = debug;
#endif /* resource limits */
X
X	curfile = arg;
X	if ('-' == curfile[0] && '\000' == curfile[1]) {
X		fprintf(stderr, "%s: stdin not supported\n", progname);
X		return 1;
X	}
X	if (-1 == LSTAT(curfile, & stIn)) {
X		fprintf(stderr, "%s: stat: %s: %s\n", progname, curfile, strerror(errno));
X		return 1;
X	}
X	switch (stIn.st_mode & S_IFMT) {
#if defined(S_IFLNK)
X	case S_IFLNK:	/* symbolic link */
X		chFType = 'l';
X		break;
#endif
#if defined(S_IFIFO)
X	case S_IFIFO:	/* fifo */
X		chFType = 'p';
X		break;
#endif	/* no fifos */
#if defined(S_IFSOCK)
X	case S_IFSOCK:	/* socket */
X		chFType = 's';
X		break;
#endif	/* no sockets */
X	case S_IFDIR:	/* directory */
X		chFType = 'd';
X		break;
X	case S_IFCHR:	/* character special */
X		chFType = 'c';
X		break;
X	case S_IFBLK:	/* block special */
X		chFType = 'b';
X		break;
X	case 0:
X	case S_IFREG:	/* regular */
X		chFType = 'f';
X		break;
X	default:
X		fprintf(stderr, "%s: stat: %s: unknown file type?\n", progname, curfile);
X		return 1;
X	}
X	if ('s' == chFType || 'd' == chFType) {
X		/* dirs and sockets don't have text to read */
X		fpSrc = (FILE *)0;
X	} else if (NULL == (fpSrc = fopen(curfile, "r"))) {
X		fprintf(stderr, "%s: fopen: %s: %s\n", progname, curfile, strerror(errno));
X		return 1;
X	}
X
X	if ((char *)0 == markstr) {
X		if ('m' == progname[0] && 'k' == progname[1] && '\000' == progname[2])
X			markstr = /*0m*/"Compile";
X		else
X			markstr = progname;
X	}
X	while (isspace(*markstr)) {
X		++markstr;
X	}
X	marklen = strlen(markstr);
X	if (fCase)
X		stripc(markstr, marklen, "");
X
X	if ((char *)0 != submark) {
X		while (isspace(*submark)) {
X			++submark;
X		}
X		sublen = strlen(submark);
X		if (fCase)
X			stripc(submark, sublen, "");
X	} else {
X		sublen = 0;
X	}
X
X	pchBefore = pchExamine;
#if defined(BEFORE)
X	if ((char *)0 == pchBefore) {
X		pchBefore = acDefBefore;
X	}
#endif	/* default pre-scan	*/
X	pchSecond = pchTemplates;
#if defined(TEMPL)
X	if ((char *)0 == pchSecond) {
X		pchSecond = acDefAfter;
X	}
#endif /* default templates	*/
X
X	if (! fExec)
X		fVerbose = 1;
X	count = fFoundOne = 0;
X	fin = (FILE *)0;
X	do {
X		pch = findmarker(fin, & buf[0], & exitcode, lines);
X		if ((char *)0 == pch && (char *)0 != pchBefore) {
X			do {
X				pchLoop = strchr(pchBefore, ':');
X				if ((char *)0 != pchLoop)
X					++pchLoop;
X				pchTrans = translit(acSearch, pchBefore, 1);
X				pchBefore = pchLoop;
X				if ((FILE *)0 != fin)
X					fclose(fin);
X				fin = (char *)0 == pchTrans ? (FILE *)0 : fopen(acSearch, "r");
X			} while ((FILE *)0 == fin && (char *)0 != pchBefore);
X			if (debug && (FILE *)0 != fin) {
X				fprintf(stderr, "%s: searching template %s\n", progname, acSearch);
X			}
X			if ((FILE *)0 != fin)
X				continue;
X		}
X		if ((char *)0 == pch && (FILE *)0 != fpSrc) {
X			if ((FILE*)0 != fin)
X				fclose(fin);
X			fin = fpSrc;
X			fpSrc = (FILE *)0;
X			acSearch[0] = '\000';
X			if (debug) {
X				fprintf(stderr, "%s: searching file %s\n", progname, curfile);
X			}
X			continue;
X		}
X		if ((char *)0 == pch && (char *)0 != pchSecond) {
X			do {
X				pchLoop = strchr(pchSecond, ':');
X				if ((char *)0 != pchLoop)
X					++pchLoop;
X				pchTrans = translit(acSearch, pchSecond, 1);
X				pchSecond = pchLoop;
X				if ((FILE *)0 != fin)
X					fclose(fin);
X				fin = (char *)0 == pchTrans ? (FILE *)0 : fopen(acSearch, "r");
X			} while ((FILE *)0 == fin && (char *)0 != pchSecond);
X			if (debug && (FILE *)0 != fin) {
X				fprintf(stderr, "%s: searching template %s\n", progname, acSearch);
X			}
X			continue;
X		}
X		if ((char *)0 == pch) {
X			break;
X		}
X		if ((char *)0 == translit(combuf, pch, 0)) {
X			continue;
X		}
X		fFoundOne = 1;
X		if (fConfirm) {
X			fprintf(stderr, "\t%s  [fnyq]? ", combuf);
X			fflush(stderr);
X			gets(buf);
X
X			for (pch = buf; '\000' != *pch && isspace(*pch); ++pch)
X				/* empty */;
X			switch (*pch) {
X			case 'q':
X			case 'Q':
X				exit(0);
X			case 'y':
X			case 'Y':
X				break;
X			case 'f':
X			case 'F':
X			default:
X				continue;
X			case 'n':
X			case 'N':
X				if ((FILE *)0 != fin)
X					fclose(fin);
X				return 0;
X			}
X		} else if (fVerbose) {
X			fprintf(stderr, "\t%s\n", combuf);
X		}
X		fflush(stderr);
X		if (fExec) {
X			auto int cur, code;
#if RESOURCE
X			code = rlimsys(combuf);
#else /* use vanilla system */
X			code = system(combuf);
X			if (0177 == (code & 0xff)) {		/* stopped */
X				code = (code >> 8) & 0xff;
X			} else if (0 != (code & 0xff)) {	/* killed */
X				code = code & 0x7f;
X			} else {				/* exit */
X				code = (code >> 8) & 0xff;
X			}
#endif /* check for resource limits */
X			if (debug)
X				fprintf(stderr, "%s: command exits %d\n", progname, code);
X			switch (exitcode.ekey) {
X			case EXIT_EXACT:
X				cur = code != exitcode.ivalue;
X				break;
X			case EXIT_EXACT|EXIT_NOT:
X				cur = code == exitcode.ivalue;
X				break;
X			case EXIT_ANY:
X				cur = 0;
X				break;
X			case EXIT_ANY|EXIT_NOT:
X				cur = 1;
X				break;
X			}
X			if (fFirst && 0 == cur) {
X				if ((FILE *)0 != fin)
X					fclose(fin);
X				return 0;
X			}
X			count += cur;
X		}
X		if (fAll || fFirst) {
X			continue;
X		}
X		if ((FILE *)0 != fin) {
X			fclose(fin);
X		}
X		return count;
X	} while ((FILE *)0 != fin);
X	if (fVerbose && !fFoundOne) {
X		fprintf(stderr, "%s: no marker \"%c%s", progname, LEADCHAR, markstr);
X		if ((char *)0 != submark) {
X			fprintf(stderr, "(%s)", submark);
X		}
X		fprintf(stderr, ":\" %s %s\n", fFoundOne ? "selected from" : "in", curfile);
X	}
X	if (!fFoundOne)
X		++count;
X	return count;
}
Purdue
chmod 0444 mk/mk.c ||
echo 'restore of mk/mk.c failed'
Wc_c="`wc -c < 'mk/mk.c'`"
test 21421 -eq "$Wc_c" ||
	echo 'mk/mk.c: original size 21421, current size' "$Wc_c"
fi
# ============= mk/Makefile ==============
if test -f 'mk/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping mk/Makefile (File already exists)'
else
echo 'x - extracting mk/Makefile (Text)'
sed 's/^X//' << 'Purdue' > 'mk/Makefile' &&
# Written by S. McGeady, Intel, Inc., mcg@mipon2.intel.com		(sm)
#	     Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb		(ksb)
#
# This software is not subject to any license of the American Telephone
# and Telegraph Company or the Regents of the University of California.
#
# Permission is granted to anyone to use this software for any purpose on
# any computer system, and to alter it and redistribute it freely, subject
# to the following restrictions:
#
# 1. The authors are not held responsible for any consequences of the
#    use of this software.
#
# 2. The origin of this software must not be misrepresented, either by
#    explicit claim or by omission.  Credit to the authors must appear
#    in documentation and sources.
#
# 3. Altered versions must be plainly marked as such, and must not be
#    misrepresented as being the original software.
#
# 4. This notice may not be removed or altered.
#
# Makefile for mk
#
# $Id: Makefile.plain,v 4.6 90/11/19 13:57:12 ksb Exp $
X
PROG=	mk
BIN=	${DESTDIR}/usr/local/bin
X
L=../libopt
#L=/usr/include/local
I=/usr/include
S=/usr/include/sys
P=
X
INCLUDE= -I$L
DEBUG=	-O
CDEFS= 	
CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
X
HDR=	main.h mk.h optaccum.h machine.h rlimsys.h
SRC=	main.c mk.c rcsname.c setenv.c optaccum.c rlimsys.c
GENc=
GENh=
GEN=	${GENh} ${GENc}
DEP=	${SRC} ${GENc}
OBJ=	main.o mk.o rcsname.o setenv.o optaccum.o rlimsys.o
MAN=	mk.1l
SOURCE=	Makefile Makefile.mkcmd README mk.m ${MAN} ${HDR} ${SRC}
X
all: ${PROG}
X
${PROG}:$P ${OBJ}
#	${CC} -o $@ ${CFLAGS} ${OBJ} -lopt
#	${CC} -o $@ ${CFLAGS} ${OBJ} -L /usr/local/lib -lopt
X	${CC} -o $@ ${CFLAGS} ${OBJ} ../libopt/libopt.a
X
self-test: ${PROG}
X	cd Tests; ../${PROG} -mCompile *
X
swap: ${HDR} ${SRC} ${GEN} Makefile.mkcmd
X	mkcmd std_help.m mk.m
X	-(cmp -s prog.c main.c || echo main.c changed)
X	-(cmp -s prog.h main.h || echo main.h changed)
X	mv Makefile Makefile.plain
X	mv Makefile.mkcmd Makefile
X
clean: FRC
X	rm -f Makefile.bak *.o prog.[ch] ${GEN} ${PROG} a.out core errs tags
X
depend: ${HDR} ${SRC} ${GEN} FRC
X	maketd ${CDEFS} ${INCLUDE} ${DEP}
X
install: all FRC
X	install -cs ${PROG} ${BIN}/${PROG}
X
lint: ${HDR} ${SRC} ${GEN} FRC
X	lint -h ${CDEFS} ${INCLUDE} ${DEP}
X
mkcat: ${MAN}
X	mkcat ${MAN}
X
print: source FRC
X	lpr -J'${PROG} source' ${SOURCE}
X
source: ${SOURCE}
X
spotless: clean
X	rcsclean ${SOURCE}
X
tags: ${HDR} ${SRC} ${GEN}
X	ctags -t ${HDR} ${SRC} ${GEN}
X
${SOURCE}:
X	co -q $@
X
FRC:
X
# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
X
main.o: machine.h main.c optaccum.h
X
mk.o: machine.h main.h mk.c mk.h rlimsys.h
X
rcsname.o: machine.h rcsname.c
X
setenv.o: machine.h setenv.c
X
optaccum.o: machine.h optaccum.c
X
rlimsys.o: machine.h mk.h rlimsys.c rlimsys.h
X
# *** Do not add anything here - It will go away. ***
Purdue
chmod 0644 mk/Makefile ||
echo 'restore of mk/Makefile failed'
Wc_c="`wc -c < 'mk/Makefile'`"
test 2737 -eq "$Wc_c" ||
	echo 'mk/Makefile: original size 2737, current size' "$Wc_c"
fi
# ============= mk/Tests/ExitCodes ==============
if test ! -d 'mk/Tests'; then
    echo 'x - creating directory mk/Tests'
    mkdir 'mk/Tests'
fi
if test -f 'mk/Tests/ExitCodes' -a X"$1" != X"-c"; then
	echo 'x - skipping mk/Tests/ExitCodes (File already exists)'
else
echo 'x - extracting mk/Tests/ExitCodes (Text)'
sed 's/^X//' << 'Purdue' > 'mk/Tests/ExitCodes' &&
# This file checks mk's exit code traps				(ksb)
# $Id$
X
mk -s $0
exit $?
X
$Compile:\nfor group in True False Any None Number Sig;\ndo\n\t%b %v -m$group %f || (echo failed $group );\ndone\necho OK
X
X
These tests check for the different ways to say `zero is a good value'
X
$True=0: \n%b -a%V -t/dev/null -mOK %f
$OK(1)   : :
$OK(2)=0 : :
$OK(3)=1 : exit 1
$OK(4)=~0: exit 1
$OK(5)=~1: :
$OK(6)   : :
$OK(7)=0 : :
$OK(8)=~1: :
X
These thests check for the different fail under `zero is a good value'
$False=7: \n%b -a%V -t/dev/null -mBAD %f
$BAD(1)   : exit 1
$BAD(2)=0 : exit 1
$BAD(3)=1 : :
$BAD(4)=~0: :
$BAD(5)=~1: exit 1
$BAD(6)=1 : exit 0
$BAD(7)=~0: exit 0
X
These tests must all always succeed
$Any=0: \n%b -a%V -t/dev/null -mANY %f
$ANY(1)=*: :
$ANY(2)=*: exit 0
$ANY(3)=*: exit 1
$ANY(4)=*: exit 5
X
These tests should all always fail
$None=4: \n%b -a%V -t/dev/null -mNONE %f
$NONE(1)=~*: :
$NONE(2)=~*: exit 0
$NONE(3)=~*: exit 1
$NONE(4)=~*: exit 5
X
$Number=0: \n%b -a%V -t/dev/null -mVALUE %f
$VALUE(0)=0: exit 0
$VALUE(1)=1: exit 1
$VALUE(2)=2: exit 2
$VALUE(3)=3: exit 3
$VALUE(4)=4: exit 4
X
$Sig=0: \n%b -a%V -t/dev/null -mSIG %f
$SIG=1: kill -1 \$$
$SIG=15: kill -15 \$$
Purdue
chmod 0644 mk/Tests/ExitCodes ||
echo 'restore of mk/Tests/ExitCodes failed'
Wc_c="`wc -c < 'mk/Tests/ExitCodes'`"
test 1182 -eq "$Wc_c" ||
	echo 'mk/Tests/ExitCodes: original size 1182, current size' "$Wc_c"
fi
# ============= mk/Tests/compat ==============
if test -f 'mk/Tests/compat' -a X"$1" != X"-c"; then
	echo 'x - skipping mk/Tests/compat (File already exists)'
else
echo 'x - extracting mk/Tests/compat (Text)'
sed 's/^X//' << 'Purdue' > 'mk/Tests/compat' &&
$Compile:  MK=-t/dev/null %b -a%C%I%N%V -mVars -Dfalse="exit 0" %f && echo Vars test OK
X
# the OLD mk used to expand shell variable and some other strange
# command line variables.  These have been passed off to the shell
# to do.  This test makes sure OLD style calls get converted into
# shell variable substitutions correctly.  (ksb)
X
$Vars(1): %`false`
$Vars(2): %{false}
Purdue
chmod 0644 mk/Tests/compat ||
echo 'restore of mk/Tests/compat failed'
Wc_c="`wc -c < 'mk/Tests/compat'`"
test 376 -eq "$Wc_c" ||
	echo 'mk/Tests/compat: original size 376, current size' "$Wc_c"
fi
# ============= mk/rlimsys.h ==============
if test -f 'mk/rlimsys.h' -a X"$1" != X"-c"; then
	echo 'x - skipping mk/rlimsys.h (File already exists)'
else
echo 'x - extracting mk/rlimsys.h (Text)'
sed 's/^X//' << 'Purdue' > 'mk/rlimsys.h' &&
/*
X * include file for rlimited system
X */
X
#if RESOURCE
extern int rlimsys();
extern char *rparse();
extern void rinit();
extern int r_fTrace;	/* use shell -cx for verbose trace		*/
#endif
Purdue
chmod 0444 mk/rlimsys.h ||
echo 'restore of mk/rlimsys.h failed'
Wc_c="`wc -c < 'mk/rlimsys.h'`"
test 190 -eq "$Wc_c" ||
	echo 'mk/rlimsys.h: original size 190, current size' "$Wc_c"
fi
# ============= mkcat/scan.c ==============
if test ! -d 'mkcat'; then
    echo 'x - creating directory mkcat'
    mkdir 'mkcat'
fi
if test -f 'mkcat/scan.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mkcat/scan.c (File already exists)'
else
echo 'x - extracting mkcat/scan.c (Text)'
sed 's/^X//' << 'Purdue' > 'mkcat/scan.c' &&
/*
X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
X * 47907.  All rights reserved.
X *
X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. Neither the authors nor Purdue University are responsible for any
X *    consequences of the use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors and Purdue
X *    University must appear in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X */
X
/*  $Id: scan.c,v 3.7 90/11/28 09:54:33 ksb Exp $
X *
X * scan -- look for trouble in the cat dirs (mostly)			(ksb)
X */
#include "machine.h"
X
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/param.h>
#if defined(SYSV)
#include <ndir.h>
#else
#include <sys/dir.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>
X
#if !defined(MAXPATHLEN)
#define MAXPATHLEN	1024
#endif
X
#include "main.h"
#include "pt.h"
#include "genwhatis.h"
#include "format.h"
#include "readman.h"
#include "mkcat.h"
X
extern FILE *popen();
extern long atol();
extern int errno;
extern char *sys_errlist[];
#define strerror(Me) sys_errlist[Me]
X
extern char *strrchr(), *strcat(), *strcpy(), *malloc(), *realloc();
X
#if !defined(F_OK)
#define F_OK	0
#endif
X
#if !defined(R_OK)
#define R_OK	4
#endif
X
X
/*
X * are these two files the same?					(ksb)
X *	same inode
X *		return yes
X *	same compress status?
X *		return system("cmp -s file1 file2");
X *	diff compress status
X *		return system("zcat file.Z | cmp -s - file");
X */
int
CmpFile(pcFile1, pcFile2)
char *pcFile1, *pcFile2;
{
X	register char *pcComp1, *pcComp2;
X	auto struct stat stat1, stat2;
X	auto char acCmd[MAXPATHLEN*4];
X
X	if (-1 == stat(pcFile1, & stat1) || -1 == stat(pcFile2, & stat2)) {
X		return 0;
X	}
X	if (stat1.st_ino == stat2.st_ino && stat1.st_dev == stat2.st_dev) {
X		return 1;
X	}
X	pcComp1 = strrchr(pcFile1, acDotZ[0]);
X	if ((char *)0 != pcComp1 && 0 != strcmp(acDotZ, pcComp1)) {
X		pcComp1 = (char *)0;
X	}
X	pcComp2 = strrchr(pcFile2, acDotZ[0]);
X	if ((char *)0 != pcComp2 && 0 != strcmp(acDotZ, pcComp2)) {
X		pcComp2 = (char *)0;
X	}
X	if (((char *)0 != pcComp1) == ((char *)0 != pcComp2)) {
X		sprintf(acCmd, "exec cmp -s \'%s\' \'%s\'", pcFile1, pcFile2);
X	} else if ((char *)0 == pcComp2) {
X		sprintf(acCmd, "zcat \'%s\' |exec cmp -s - \'%s\'", pcFile1, pcFile2);
X	} else {
X		sprintf(acCmd, "zcat \'%s\' |exec cmp -s - \'%s\'", pcFile2, pcFile1);
X	}
X	return 0 == system(acCmd);
}
X
/*
X * if we find a compress'd file uncompress if (fCompress)		(ksb)
X * if we find an uncompress'd file coompress if (!fCompress)
X * make symboliclinks point to correct version.
X *
X * piNeed is a count of how many we would change
X */
static int
FixCompress(npg, ppDE, piNeed)
int npg, *piNeed;
struct direct **ppDE;
{
X	auto char acOther[MAXPATHLEN+1];
X	auto char acCmd[MAXPATHLEN*2+100];
X	auto char acLink[MAXPATHLEN+1];
X	struct direct *pDEThis;
X	register int i, j;
X	auto int iLinkLen;
X	auto PATH PTThis, PTLink;
X	auto struct stat stThis;
X
X	*piNeed = 0;
X	for (i = 0; i < npg; ++i) {
X		if ((struct direct *)0 == (pDEThis = ppDE[i]))
X			continue;
X		ppDE[i] = (struct direct *)0;
X		PTInit(&PTThis, pDEThis->d_name);
X		if (fCompress) {
X			if (PTIsComp(&PTThis))
X				continue;
X			(void)strcpy(acOther, PTFull(&PTThis));
X			(void)PTComp(&PTThis);
X		} else {
X			if (!PTIsComp(&PTThis))
X				continue;
X			(void)strcpy(acOther, PTFull(&PTThis));
X			(void)PTUnComp(&PTThis);
X		}
X
X		/* now Other has the wrong one, and PTThis is correct
X		 */
X		if (-1 == LSTAT(acOther, & stThis)) {
X			/* someone removed it, ouch */
X			continue;
X		}
X		if (0 == access(PTFull(&PTThis), F_OK)) {
X			if (0 == CmpFile(PTFull(&PTThis), acOther)) {
X				if (fVerbose) {
X					(void)printf("%s: rm -f %s\n", progname, acOther);
X				}
X				if (fExec && -1 == unlink(acOther)) {
X					fprintf(stderr, "%s: unlink: %s: %s\n", progname, acOther, strerror(errno));
X					exit(22);
X				}
X			} else {
X				(void)printf("%s: %s ~ %s, both exist; delete one and retry\n", progname, PTFull(&PTThis), acOther);
X				exit(88);
X			}
X		}
X		switch (stThis.st_mode & S_IFMT) {
X		case S_IFREG:
X			(void)sprintf(acCmd, "%scompress -f -c \"%s\" >\"%s\"", fCompress ? "" : "un", acOther, PTFull(&PTThis));
X			if (fVerbose)
X				printf("%s: %s\n", progname, acCmd);
X			if (fExec && 0 != system(acCmd))
X				continue;
X			++*piNeed;
X			for (j = i+1; j < npg; ++j) {
X				if ((struct direct *)0 == ppDE[j])
X					continue;
X				if (ppDE[j]->d_ino != pDEThis->d_ino)
X					continue;
X				PTInit(&PTLink, ppDE[j]->d_name);
X				if (fVerbose)
X					printf("%s: rm -f %s\n", progname, PTFull(&PTLink));
X				if (fExec)
X					(void)unlink(PTFull(&PTLink));
X				if (fCompress)
X					(void)PTComp(&PTLink);
X				else
X					(void)PTUnComp(&PTLink);
X				if (fVerbose)
X					printf("%s: ln %s %s\n", progname, PTFull(&PTThis), PTFull(&PTLink));
X				if (fExec && 0 != link(PTFull(&PTThis), PTFull(&PTLink))) {
X					fprintf(stderr, "%s: link: %s: %s\n", progname, PTFull(&PTLink), strerror(errno));
X				}
X				ppDE[j] = (struct direct *)0;
X			}
X			if (fVerbose) {
X				printf("%s: rm -f %s\n", progname, acOther);
X			}
X			if (fExec && 0 != unlink(acOther)) {
X				fprintf(stderr, "%s: unlink: %s: %s\n", progname, acOther, strerror(errno));
X			}
X			break;
#if HAVE_SLINKS
X		case S_IFLNK:
X			if (-1 == (iLinkLen = readlink(acOther, acLink, MAXPATHLEN))) {
X				fprintf(stderr, "%s: readlink: %s: %s\n", progname, acOther, strerror(errno));
X				continue;
X			}
X			acLink[iLinkLen] = '\000';
X			printf("%s: %s -> %s\n", progname, acOther, acLink);
X			if ('/' == acLink[0])
X				continue;
X			PTInit(& PTLink, acLink);
X			if (fCompress)
X				(void)PTComp(&PTLink);
X			else
X				(void)PTUnComp(&PTLink);
X			if (fVerbose)
X				(void)printf("%s: rm -f \"%s\"\n", progname, acOther);
X			if (fExec && 0 != unlink(acOther))
X				fprintf(stderr, "%s: unlink: %s: %s\n", progname, acOther, strerror(errno));
X			if (fVerbose)
X				(void)printf("%s: ln -s \"%s\" \"%s\"\n", progname, PTFull(&PTLink), PTFull(&PTThis));
X			if (fExec && symlink(PTFull(&PTThis), PTFull(&PTLink)))
X				fprintf(stderr, "%s: link: %s\n", progname, strerror(errno));;
X			break;
#endif
X		case S_IFDIR:
X			/* OLD, for instance */
X			continue;
X		default:
X			(void)fprintf(stderr, "%s: %s: unknown file type\n", progname, PTFull(&PTThis));
X			continue;
X		}
X	}
X	return 0;
}
X
/*
X * In this alphasorted list of (struct direct *) [some nil] find	(ksb)
X * (via a binary search) the named file... return a pointer to
X * the entry so we may remove it in the caller
X *
X * This allows the caller to `shoot' the return array from scandir
X * a few files at a time and still have a list of the files left.
X */
static struct direct **
FindDEnt(pcName, ppDE, n)
char *pcName;
struct direct **ppDE;
int n;
{
X	register int i, mid;
X	register int cmp;
X
X	if (0 == n)
X		return (struct direct **)0;
X	for (i = 0; i < n; ++i) {
X		if ((struct direct *)0 != ppDE[i])
X			break;
X	}
X	if (n == i) {
X		return (struct direct **)0;
X	}
X
X	if (0 == strcmp(pcName, (ppDE[i])->d_name)) {
X		return & ppDE[i];
X	}
X
X	do {
X		--n;
X		if ((struct direct *)0 != ppDE[n])
X			break;
X	} while (n > i);
X	if (0 == strcmp(pcName, (ppDE[n])->d_name)) {
X		return & ppDE[n];
X	}
X
X	while (i != n) {
X		mid = (n+i)/2;
X		while (mid < n && (struct direct *)0 == ppDE[mid])
X			++mid;
X		if (mid == n) {
X			mid = (n+i)/2;
X			while (mid > i && (struct direct *)0 == ppDE[mid])
X				--mid;
X			if (mid == i)
X				break;
X		}
X		cmp = strcmp(pcName, (ppDE[mid])->d_name);
X		if (cmp == 0) {
X			return & ppDE[mid];
X		}
X		if (cmp < 0) {
X			n = mid;
X		} else {
X			i = mid;
X		}
X		if (i+1 == n)
X			break;
X	}
X	return (struct direct **)0;
}
X
/*
X * remove a link entry from something					(ksb)
X *	 1 == OK to build
X *	 0 == done for us already
X *	-1 == error on rm
X *	 2 == just struke link from list, fMkLinks is not set!
X */
static int
FixLink(pcEnt, ppDEPages, npg, pcDest, pstCat)
char *pcEnt, *pcDest;	/* ZZZ where the link points */
struct direct **ppDEPages;
int npg;
struct stat *pstCat;
{
X	register struct direct **ppDE;
X	int iLinkLen;
X	auto char acContents[MAXPATHLEN+1];
X	auto struct stat stDest;
X
X	if ((struct direct **)0 != ppDEPages && (struct direct **)0 != (ppDE = FindDEnt(pcEnt, ppDEPages, npg))) {
X		*ppDE = (struct direct *)0;
X	}
X	if (!fMkLinks)
X		return 2;
X
X	if (-1 == LSTAT(pcEnt, & stDest)) {
X		if (ENOENT != errno) {
X			fprintf(stderr, "%s: stat: %s: %s\n", progname, pcEnt, strerror(errno));
X			return -1;
X		}
X		return 1;
X	}
X	switch (stDest.st_mode & S_IFMT) {
X	case 0:
X	case S_IFREG:	/* regular */
X		if (fUseHards) {
X			if ((struct stat *)0 != pstCat && stDest.st_ino == pstCat->st_ino && stDest.st_dev == pstCat->st_dev) {
X				/* OK */
X				return 0;
X			}
X			if (stDest.st_nlink < 2) {
X				fprintf(fpOut, "%s: `%s\' is a unique file, not removed\n", progname, pcEnt);
X				return -1;
X			}
X			fprintf(fpOut, "%s: hard moved: %s@ -> %s\n", progname, pcEnt, pcDest);
X		} else {
X			/* if this is not the old cat page, and
X			 * a unique file that is not a clone of the page
X			 * remove it.
X			 */
X			if ((struct stat *)0 != pstCat && (stDest.st_ino == pstCat->st_ino && stDest.st_dev == pstCat->st_dev)) {
X				/* it is an OK hard link, dink it */;
X			} else if (stDest.st_nlink < 2 && 0 != CmpFile(pcEnt, acCat)) {
X				fprintf(fpOut, "%s: `%s\' is a unique file, not removed\n", progname, pcEnt);
X				return -1;
X			}
X			fprintf(fpOut, "%s: hard link changed to symbolic link: %s@ -> %s\n", progname, pcEnt, pcDest);
X		}
X		break;
X
#if HAVE_SLINKS
X	case S_IFLNK:	/* symbolic link */
X		if (-1 == (iLinkLen = readlink(pcEnt, acContents, MAXPATHLEN))) {
X			fprintf(stderr, "%s: readlink: %s: %s\n", progname, pcEnt, strerror(errno));
X			return -1;
X		}
X		acContents[iLinkLen] = '\000';
X		if (fUseHards) {
X			if (0 != strcmp(acContents, pcDest) && 0 != CmpFile(pcEnt, acContents)) {
X				return -1;
X			}
X			fprintf(fpOut, "%s: symbolic link changed to a hard link: %s -> %s\n", progname, pcEnt, pcDest);
X		} else {
X			if (0 == strcmp(acContents, pcDest)) {
X				return 0;
X			}
X			fprintf(fpOut, "%s: symbolic link moved: %s@ -> %s\n", progname, pcEnt, pcDest);
X		}
X		break;
X	default:
X		fprintf(fpOut, "%s: `%s\' is a special file, cannot change to a symlink\n", progname, pcEnt);
X		return -1;
X
#else
X	default:
X		fprintf(fpOut, "%s: `%s\' is a special file, cannot change to a link\n", progname, pcEnt);
X		return -1;
#endif
X	}
X	/* link was ok to remove and pointed the wrong place
X	 */
X	if (fVerbose) {
X		fprintf(fpOut, "%s: rm -f \"%s\"\n", progname, pcEnt);
X	}
X	if (fExec) {
X		(void)unlink(pcEnt);
X	}
X	return 1;
}
X
/*
X * update all the links that point to this page				(ksb)
X *
X * We chdir() to the target dir and chdir back when done.
X *
X * Passed a list of links to make, a file to link them to,
X * the stat buffer for an `OK' previous file that links may
X * have been hard linked to, and a list of files in that directory
X * that we should `punch out' as they are claimed as links
X * (so we don't have to do this again).
X *
X * Optionally, remove the links...
X */
static void
MkLinks(pcBase, pWU, ppDEPages, npg, pstCat, fRemove)
WHATIS *pWU;
char *pcBase;
struct direct **ppDEPages;
int npg, fRemove;
struct stat *pstCat;
{
X	extern char *getwd();
X	register int k;
X	auto char acCLink[MAXPATHLEN+1];
X
X	for (k = 0; k < pWU->ilen; ++k) {
X		/* do not link file to itself */
X		(void)sprintf(acCLink, "%s.%s%s", pWU->ppclist[k], pWU->pcext, fCompress ? acDotZ : "");
X		if (0 == strcmp(pcBase, acCLink)) {
X			continue;
X		}
X
X		switch (FixLink(acCLink, ppDEPages, npg, pcBase, pstCat)) {
X		case 1:	/* make it -- it is not there			*/
X			if (fRemove) {
X				continue;
X			}
X			/* make it below */
X			break;
X
X		case 0: /* it is there already				*/
X			if (!fRemove) {
X				continue;
X			}
X			if (fVerbose) {
X				fprintf(fpOut, "%s: rm -f \"%s\"\n", progname, acCLink);
X			}
X			if (fExec) {
X				(void)unlink(acCLink);
X			}
X			continue;
X
X		case -1: /* error on remove/check of link -- forget it	*/
X			continue;
X		case 2:	/* fMkLinks is 0 */
X			continue;
X		}
X
X		/* make a link
X		 */
X		if (fUseHards) {
X			if (fVerbose) {
X				fprintf(fpOut, "%s: ln \"%s\" \"%s\"\n", progname, pcBase, acCLink);
X			}
X			if (fExec && 0 != link(pcBase, acCLink)) {
X				fprintf(stderr, "%s: link: %s to %s: %s\n", progname, pcBase, acCLink, strerror(errno));
X				continue;
X			}
X		} else {
X			if (fVerbose) {
X				fprintf(fpOut, "%s: ln -s \"%s\" \"%s\"\n", progname, pcBase, acCLink);
X			}
X			if (fExec && 0 != symlink(pcBase, acCLink)) {
X				fprintf(stderr, "%s: symlink: %s to %s: %s\n", progname, pcBase, acCLink, strerror(errno));
X				continue;
X			}
X		}
X	}
}
X
/*
X * select routine for scandir						(ksb)
X */
static int
catSelect(pEnt)
struct direct *pEnt;
{
X	if ('.' == pEnt->d_name[0] && ('\000' == pEnt->d_name[1] ||
X	    ('.' == pEnt->d_name[1] && '\000' == pEnt->d_name[2]))) {
X		return 0;
X	}
X	return 1;
}
X
/*
X * scan the read directory for pages that differ only			(ksb)
X * in extender or case
X */
static void
ScanDups(npg, ppDEPages, pWU)
int npg;
register struct direct **ppDEPages;
register WHATIS *pWU;
{
X	register int k, l;
X	register int ck, cl;
X	register char *pcCompk, *pcCompl;
X	register char *pcSectionk, *pcSectionl;
X
X	for (k = 0; k < npg; ++k) {
X		pWU[k].isection = 1;
X	}
X
X	pcSectionk = pcCompk = (char *)0;
X	pcSectionl = pcCompl = (char *)0;
X	for (k = 0; k < npg;
X	     ((char *)0 != pcCompk && (*pcCompk = acDotZ[0])),
X	     ((char *)0 != pcSectionk && (*pcSectionk = '.')),
X	     (pWU[k++].isection = 0)) {
X		if ((struct direct *)0 == ppDEPages[k]) {
X			continue;
X		}
X		pcCompk = strrchr(ppDEPages[k]->d_name, acDotZ[0]);
X		if ((char *)0 != pcCompk && 0 != strcmp(pcCompk, acDotZ)) {
X			pcCompk = (char *)0;
X		}
X		if ((char *)0 != pcCompk) {
X			*pcCompk = '\000';
X		}
X		pcSectionk = strrchr(ppDEPages[k]->d_name, '.');
X		if ((char *)0 == pcSectionk) {
X			continue;
X		}
X		*pcSectionk = '\000';
X		if (IsOKBase(ppDEPages[k]->d_name)) {
X			continue;
X		}
X		ck = ppDEPages[k]->d_name[0];
X		if (isalpha(ck) && isupper(ck)) {
X			ck = tolower(ck);
X		}
X
X		for (l = k+1; l < npg;
X		     ((char *)0 != pcCompl && (*pcCompl = acDotZ[0])),
X		     ((char *)0 != pcSectionl && (*pcSectionl = '.')),
X		     ++l) {
X			if ((struct direct *)0 == ppDEPages[l] || 0 == pWU[l].isection)
X				continue;
X			cl = ppDEPages[l]->d_name[0];
X			if (isalpha(cl) && isupper(cl))
X				cl = tolower(cl);
X			if (cl != ck) {
X				continue;
X			}
X			pcCompl = strrchr(ppDEPages[l]->d_name, acDotZ[0]);
X			if ((char *)0 != pcCompl && 0 != strcmp(pcCompl, acDotZ)) {
X				pcCompl = (char *)0;
X			}
X			if ((char *)0 != pcCompl) {
X				*pcCompl = '\000';
X			}
X			pcSectionl = strrchr(ppDEPages[l]->d_name, '.');
X			if ((char *)0 == pcSectionl) {
X				continue;
X			}
X			*pcSectionl = '\000';
X			if (0 != strcasecmp(ppDEPages[k]->d_name, ppDEPages[l]->d_name)) {
X				continue;
X			}
X			fprintf(fpOut, "%s: `%s.%s%s\' and `%s.%s%s\' differ ", progname,
X			    ppDEPages[k]->d_name, pcSectionk+1, (char *)0 != pcCompk ? acDotZ : "",
X			    ppDEPages[l]->d_name, pcSectionl+1, (char *)0 != pcCompl ? acDotZ : "");
X			pWU[l].isection = 0;
X			if (0 == strcmp(ppDEPages[k]->d_name, ppDEPages[l]->d_name) && 0 == strcmp(pcSectionk+1, pcSectionl+1)) {
X				fprintf(fpOut, "only in compression\n");
X			} else if (0 == strcasecmp(pcSectionk+1, pcSectionl+1)) {
X				if (((char *)0 == pcCompl) == ((char *)0 == pcCompk)) {
X					fprintf(fpOut, "only in case\n");
X				} else {
X					fprintf(fpOut, "in case and compression\n");
X				}
X			} else if (((char *)0 == pcCompl) == ((char *)0 == pcCompk)) {
X				fprintf(fpOut, "only in section\n");
X			} else {
X				fprintf(fpOut, "in section and compression\n");
X			}
X		}
X	}
}
X
/* remove the case from a file name, but don't touch the acDotZ if	(ksb)
X * it has one
X */
void
DropCase(pc, fComp)
char *pc;
int fComp;
{
X	for (/* done*/; '\000' != *pc; ++pc) {
X		if (fComp && *pc == acDotZ[0] && 0 == strcmp(acDotZ, pc))
X			break;
X		if (isalpha(*pc) && isupper(*pc))
X			*pc = tolower(*pc);
X	}
}
X
/*
X * check a SEE ALSO entry for format, then check the manual page	(ksb)
X * it points to (if the format is correct).
X */
void
AlsoCheck(pWUThis, pcSee)
WHATIS *pWUThis;
char *pcSee;
{
X	register char *pcOpen, *pcClose, *pcTail, *pcDot;
X	register DIR *pDI;
X	register struct direct *pDE;
X	register int iBase;
X	extern char *strchr();
X	auto struct stat stPage;
X	auto char acLookFor[2*MAXPATHLEN+4];
X	auto char acWrong[MAXPATHLEN+1];
X
X	if ((char *)0 == (pcOpen = strchr(pcSee, '('/*)*/)) || pcSee == pcOpen || !isdigit(pcOpen[1]))
X		return;
X	if ((char *)0 == (pcClose = strchr(pcSee, /*(*/')')) || '\000' != pcClose[1])
X		return;
X	*pcOpen++ = '\000';
X	*pcClose = '\000';
X
X	if ('/' == pcCat[0] || ('.' == pcCat[0] && '/' == pcCat[1]))
X		sprintf(acLookFor, "%s%ld/", pcCat, atol(pcOpen));
X	else
X		sprintf(acLookFor, "%s/%s%ld/", pcRoot, pcCat, atol(pcOpen));
X	StripFmt(acLookFor);
X	pcTail = acLookFor + strlen(acLookFor);
X
X	sprintf(pcTail, "%s.%s", pcSee, pcOpen);
X	StripFmt(pcTail);
X	if ((char *)0 == (pcDot = strrchr(pcTail, '.'))) {
X		fprintf(stderr, "%s: %s: no dot in this string?\n", progname, pcTail);
X		exit(60);
X	}
X	iBase = pcDot - pcTail;
X	if (fCompress) {
X		(void)strcat(pcTail, acDotZ);
X	}
X
X	if (-1 != stat(acLookFor, &stPage) && S_IFREG == (stPage.st_mode&S_IFMT)) {
X		/* found it */;
X	} else if (DropCase(pcTail, fCompress), -1 != stat(acLookFor, &stPage) && S_IFREG == (stPage.st_mode&S_IFMT)) {
X		/* found it */;
X	} else if (pcTail[-1] = '\000', (DIR *)0 == (pDI = opendir(acLookFor))) {
X		fprintf(stderr, "%s: opendir: %s: %s\n", progname, acLookFor, strerror(errno));
X	} else {
X		/* printf("\tscan for %s in %s:\n", pcTail, acLookFor); */
X		/* if the name appears in any case we quit,
X		 * if it has the wrong section we record it,
X		 */
X		if (fCompress && (char *)0 != (pcDot = strrchr(pcTail, acDotZ[0])) && 0 == strcmp(acDotZ, pcDot)) {
X			*pcDot = '\000';
X		}
X		acWrong[0] = '\000';
X		while ((struct direct *)0 != (pDE = readdir(pDI))) {
X			if ((char *)0 != (pcDot = strrchr(pDE->d_name, acDotZ[0])) && 0 == strcmp(acDotZ, pcDot))
X				*pcDot = '\000';
X			else
X				pcDot = (char *)0;
X			if (0 == strcasecmp(pcTail, pDE->d_name)) {
X				break;
X			}
X			if (0 == strncasecmp(pcTail, pDE->d_name, iBase) && '.' == pDE->d_name[iBase]) {
X				(void)strcpy(acWrong, pDE->d_name);
X			}
X		}
X		closedir(pDI);
X		if ((struct direct *)0 != pDE) {
X			/* found it*/ ;
X		} else if ('\000' != acWrong[0]) {
X			printf("%s: %s.%s: SEE ALSO sites `%s\' found `%s\'\n", progname, pWUThis->pcbase, pWUThis->pcext, pcTail, acWrong);
X		
X		} else {
X			printf("%s: %s.%s: SEE ALSO sites `%s\', no such page\n", progname, pWUThis->pcbase, pWUThis->pcext, pcTail);
X		}
X	}
X
X	*--pcOpen = '(';
X	*pcClose = ')';
}
X
/*
X * scan the whatis structures for manual pages that don't exist		(ksb)
X * that are referenced in SEE ALSO lines
X */
int
AlsoScan(pWU, iCount)
WHATIS *pWU;
int iCount;
{
X	register int i, ch;
X	register char *pcAlso, *pcStart;
X
X	for (i = 0; i < iCount; ++i) {
X		if ((char *)0 == pWU[i].pcalso) {
X			/* no see also line in this page, skip it */
X			continue;
X		}
X		
X		pcStart = (char *)0;
X		/* printf("%s.%s:\n", pWU[i].pcbase, pWU[i].pcext); */
X		for (pcAlso = pWU[i].pcalso; '\000' != *pcAlso; ++pcAlso) {
X			if (',' != *pcAlso && !isspace(*pcAlso)) {
X				if ((char *)0 == pcStart) {
X					pcStart = pcAlso;
X				}
X				continue;
X			}
X			if ((char *)0 == pcStart) {
X				continue;
X			}
X			ch = *pcAlso;
X			*pcAlso = '\000';
X			AlsoCheck(& pWU[i], pcStart);
X			*pcAlso = ch;
X			pcStart = (char *)0;
X		}
X		if ((char *)0 != pcStart) {
X			AlsoCheck(& pWU[i], pcStart);
X		}
X	}
X	return 1;
}
X
X
/*
X * look at all the manual pages in a directory				(ksb)
X *
X * Make sure they are compress'd or not...
X * When we find a symbolic link we verify it.
X * When we find a file we read it for makelinks, with that list in
X * hand we will rebuild the hard an symbols links later.
X * We delete lost links.
X */
int
AllDir(iSection, ppWU, piCount)
WHATIS **ppWU;
int iSection, *piCount;
{
X	extern int alphasort();
X	static char acDir[] = ".";
X	register struct direct *pDEPage, **ppDE;
X	register char *pcBase;
X	auto int i, l, k, npg;
X	auto FILE *fpFmt;
X	auto struct direct **ppDEPages;
X	auto char acLink[MAXPATHLEN+1];
X	auto char acName[MAXPATHLEN+1];
X	auto struct stat stCat;
X	auto int iw, iNeedFix;
X	auto WHATIS *pWU;
X	auto PATH PTTemp;
X
X	*ppWU = (WHATIS *)0;
X	*piCount = iw = 0;
X	if (-1 == (npg = scandir(acDir, & ppDEPages, catSelect, alphasort))) {
X		fprintf(stderr, "%s: scandir: %s: %s\n", progname, acDir, strerror(errno));
X		return 1;
X	}
X	if (0 == npg) {
#if 0
X		/* we don't output this because it makes all inits look broken
X		 */
X		fprintf(fpOut, "%s: no pages in section %d\n", progname, iSection);
#endif
X		return 1;
X	}
X
X	if (0 != FixCompress(npg, ppDEPages, & iNeedFix) || fJustComp) {
X		free((char *)ppDEPages);
X		return 0;
X	}
X	free((char *)ppDEPages);
X
X	/* we cannot do the rest becuase FixCompress need to exec something
X	 */
X	if (!fExec && 0 != iNeedFix) {
X		return 0;
X	}
X
X	if (-1 == (i = scandir(acDir, & ppDEPages, catSelect, alphasort))) {
X		fprintf(stderr, "%s: scandir: %s: %s\n", progname, acDir, strerror(errno));
X		return 1;
X	}
X
X	if (i > npg) {
X		fprintf(stderr, "%s: active manual system number of pages grew (%d > %d)\n", progname, i, npg);
X	}
X	npg = i;
X
X	/* this might be a gross over allocation, sigh
X	 * we will patch it with realloc later...
X	 */
X	if (0 == (pWU = (WHATIS *)malloc((unsigned)sizeof(WHATIS)*npg))) {
X		free((char *)ppDEPages);
X		fprintf(stderr, acNoMem, progname);
X		return 0;
X	}
X
X	if (fVerbose) {
X		ScanDups(npg, ppDEPages, pWU);
X	}
X
X	for (k = 0; k < npg; ++k) {
X		if ((struct direct *)0 == (pDEPage = ppDEPages[k])) {
X			continue;
X		}
X		if (-1 == LSTAT(pDEPage->d_name, & stCat)) {
X			continue;
X		}
X		/* ignore or bitch aboutr special files */
X		switch (stCat.st_mode & S_IFMT) {
#if defined(S_IFIFO)
X		case S_IFIFO:	/* fifo */
X			(void)fprintf(stderr, "%s: `%s\' is a fifo\n", progname, pDEPage->d_name);
X			ppDEPages[k] = 0;
X			free((char *)pDEPage);
X			continue;
#endif	/* no fifos		*/
X
#if defined(S_IFSOCK)
X		case S_IFSOCK:	/* socket */
X			(void)fprintf(stderr, "%s: `%s\' is a socket\n", progname, pDEPage->d_name);
X			ppDEPages[k] = 0;
X			free((char *)pDEPage);
X			continue;
#endif	/* no sockets		*/
X		case S_IFCHR:	/* character special */
X		case S_IFBLK:	/* block special */
X			fprintf(stderr, "%s: `%s\' is a special device\n", progname, pDEPage->d_name);
X			ppDEPages[k] = 0;
X			free((char *)pDEPage);
X			continue;
X		case S_IFDIR:	/* directory */
X			/* should get ., .., and OLD */
X			ppDEPages[k] = 0;
X			free((char *)pDEPage);
X			continue;
X
#if defined(S_IFLNK)
X		case S_IFLNK:	/* symbolic link */
X			/* check later... */
X			continue;
#endif	/* we can catch symbolic links for other reasons		*/
X
X		case 0:
X		case S_IFREG:	/* regular */
X			pcBase = pDEPage->d_name;
X			ppDEPages[k] = 0;
X			break;
X		}
X
X		PTInit(&PTTemp, pcBase);
X
X		/* skip bad extenders		*/
X		if (! PTHasExt(&PTTemp)) {
X			fprintf(stdout, "%s: `%s\' has no section extension\n", progname, pcBase);
X			continue;
X		}
X
X		/* open and read link info	*/
X		if (PTIsComp(&PTTemp)) {
X			auto char acCmd[MAXPATHLEN+200];
X
X			sprintf(acCmd, "exec zcat \'%s\'", pcBase);
X			(void)fflush(stderr);
X			(void)fflush(stdout);
X			if (NULL == (fpFmt = popen(acCmd, "r"))) {
X				fprintf(stderr, "%s: popen: %s: %s\n", progname, acCmd, strerror(errno));
X				continue;
X			}
X			i = WUGrok(fpFmt, &PTTemp, & pWU[iw]);
X			(void)pclose(fpFmt);
X		} else {
X			if (NULL == (fpFmt = fopen(pcBase, "r"))) {
X				fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcBase, strerror(errno));
X				continue;
X			}
X			i = WUGrok(fpFmt, &PTTemp, & pWU[iw]);
X			(void)fclose(fpFmt);
X		}
X		if (i != 0) {
X			/* cannot grok this page, skip it */
X			continue;
X		}
X
X		(void)sprintf(acName, "%s.%s%s", pWU[iw].pcbase, pWU[iw].pcext, fCompress ? acDotZ : "");
X
X		if (pWU[iw].isection != iSection) {
X			fprintf(fpOut, "%s: `%s\' might be in the wrong section\n", progname, pcBase);
X		}
X
X
X		/* here we've found (in pcBase) either
X		 *	a/ the primary link to a page (good)
X		 *	b/ a hard link to a page (fair)
X		 *	c/ link to out of date page (yucko)
X		 *	d/ a page whoose primary link is gone? (ouch!)
X		 */
X		if (0 != strcmp(pcBase, acName)) {	/* (b)? */
X			ppDE = FindDEnt(acName, ppDEPages, npg);
X			if ((struct direct **)0 != ppDE) {
#if HAVE_SLINKS
X				if (0 == LSTAT(acName, &stCat)) {
X					switch ((stCat.st_mode & S_IFMT)) {
X					case S_IFLNK:
X						if (fExec && fMkLinks) {
X							sym2Hard(acName);
X						}
X						break;
X					case S_IFREG:
X						break;
X					default:
X						fprintf(stderr, "%s: type type error\n", progname);
X						abort();
X					}
X				}
#endif
X				if (!CmpFile(pcBase, acName)) {
X					fprintf(fpOut, "%s: would have scanned `%s\' as `%s\', but they are not identical\n", progname, pcBase, acName);
X				} else {
X					fprintf(fpOut, "%s: scan `%s\' as `%s\'\n", progname, pcBase, acName);
X					ppDEPages[k] = pDEPage;
X					pDEPage = *ppDE;
X					*ppDE = 0;
X					pcBase = pDEPage->d_name;
X				}
X			} else { /* (d) */
X				fprintf(stderr, "%s: primary link to %s should be %s\n", progname, pcBase, acName);
X				if (fVerbose) {
X					(void)printf("%s: ln \"%s\" \"%s\"\n", progname, pcBase, acName);
X				}
X				if (fExec && fMkLinks && -1 == link(pcBase, acName)) {
X					fprintf(stderr, "%s: link: %s: %s\n", progname, acName, strerror(errno));
X				}
X			}
X		}
X		MkLinks(acName, pWU+iw, ppDEPages, npg, &stCat, 0);
X		++iw;
X	}
X
#if HAVE_SLINKS
X	/* the files left are links that point nowhere, or to files
X	 * that do not what them (lost a subcommand?)
X	 */
X	for (l = 0; l < npg; ++l) {
X		if ((struct direct *)0 == (pDEPage = ppDEPages[l])) {
X			continue;
X		}
X		if (-1 == (i = readlink(pDEPage->d_name, acLink, MAXPATHLEN))) {
X			if (errno == EINVAL) {
X				(void)printf("%s: %s: manual page under the wrong name?\n", progname, pDEPage->d_name);
X				continue;
X			}
X			fprintf(stderr, "%s: readlink: %s: %s\n", progname, pDEPage->d_name, strerror(errno));
X			continue;
X		}
X		acLink[i] = '\000';
X		fprintf(fpOut, "%s: `%s\' is an unclaimed symbolic link", progname, pDEPage->d_name);
X		if (0 == access(acLink, R_OK)) {
X			fprintf(fpOut, " to `%s\'\n", acLink);
X		} else {
X			fprintf(fpOut, ", leading nowhere\n");
X		}
X	}
#endif
X
X	/* now we can realloc the WHATIS array to the correct size
X	 */
X	if (iw < npg) {
X		if (0 == (pWU = (WHATIS *)realloc((char *)pWU, (unsigned)sizeof(WHATIS)*iw))) {
X			fprintf(stderr, "%s: realloc compression failed\n", progname);
X			return 0;
X		}
X		*ppWU = pWU;
X	}
X	*piCount = iw;
X
X	return 1;
}
X
/*
X * this routine is kinda kludge.  MkLinks wants to be in the dir it	(ksb)
X * is making the links for, so be cd there, do it, and come back.
X *
X * We could fork and wait if that would be more `safe'
X * (this breaks if we are in a directory we cannot read, for example)
X */
void
ModLinks(pPTDest, pWU, ppDEPages, npg, pstCat, fRemove)
PATH *pPTDest;
WHATIS *pWU;
struct direct **ppDEPages;
int npg, fRemove;
struct stat *pstCat;
{
X	extern char *getwd();
X	auto char acPwd[MAXPATHLEN+1];
X	auto int fSave;
X
X	(void)fflush(stdout);
X	if ((char *)0 == getwd(acPwd)) {
X		fprintf(stderr, "%s: %s\n", progname, acPwd);
X		return;
X	}
X	if (-1 == chdir(PTDir(pPTDest))) {
X		fprintf(stderr, "%s: chdir: %s: %s\n", progname, PTDir(pPTDest), strerror(errno));
X		return;
X	}
X
X	fSave = fMkLinks;
X	fMkLinks = 1;
X	MkLinks(PTLocal(pPTDest), pWU, ppDEPages, npg, pstCat, fRemove);
X	fMkLinks = fSave;
X
X	if (-1 == chdir(acPwd)) {
X		fprintf(stderr, "%s: chdir: %s: %s\n", progname, acPwd, strerror(errno));
X		exit(1);
X	}
}
Purdue
chmod 0444 mkcat/scan.c ||
echo 'restore of mkcat/scan.c failed'
Wc_c="`wc -c < 'mkcat/scan.c'`"
test 27828 -eq "$Wc_c" ||
	echo 'mkcat/scan.c: original size 27828, current size' "$Wc_c"
fi
true || echo 'restore of mkcat/genwhatis.c failed'
echo End of part 2, continue with part 3
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.