From uunet!rsalz Tue May 19 14:14:07 1992
Received: from uunet.UUCP by sparky.IMD.Sterling.COM (5.65c/IDA-1.4.4)
	id AA03474; Tue, 19 May 1992 14:14:02 -0500
Return-Path: <uunet!rsalz>
Received: by rodan.UU.NET (5.61/UUNET-mail-drop)
	id AA17553; Tue, 19 May 92 14:34:59 -0400
Date: Tue, 19 May 92 14:34:59 -0400
From: uunet!rsalz (Rich Salz)
Message-Id: <9205191834.AA17553@rodan.UU.NET>
To: kent@imd.sterling.com
Subject: cshar/Part02
Status: O

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  config.x38 findsrc.c maniscan.c shar.c unshar.c
# Wrapped by rsalz@rodan on Tue Apr  7 23:54:46 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 2 (of 6)."'
if test -f 'config.x38' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config.x38'\"
else
  echo shar: Extracting \"'config.x38'\" \(6993 characters\)
  sed "s/^X//" >'config.x38' <<'END_OF_FILE'
X/*
X**  Configuration file for shar and friends.
X**
X**  This config file is for Xenix on a 386 (and 286).
X**  In the Makefile, set DIRLIB=-lx, and tweak the MANDIR and 1 variables.
X**
X**  For a 286, you need '-F 2000' for unshar, and don't forget to use
X** '-M2' in the CFLAGS.
X**
X**  $Header: config.x386,v 2.1 88/06/06 22:05:52 rsalz Locked $
X*/
X/* SUPPRESS 460 *//* '/*' occurred inside a comment */
X
X
X/*
X**  Higher-level controls for which operating system we're running on.
X*/
X#define UNIX				/* Works			*/
X/*efine MSDOS				/* Should work			*/
X/*efine VMS				/* Doesn't work			*/
X
X
X/*
X**  A dense section of one-line compilation controls.  If you're confused,
X**  your best bet is to search through the source to see where and how
X**  each one of these is used.
X*/
X#define IDX		strchr		/* Maybe strchr?		*/
X#define RDX		strrchr		/* Maybe strrchr?		*/
X#define NEED_CTERMID			/* Don't have ctermid(3)?	*/
X#define NEED_MKDIR			/* Don't have mkdir(2)?		*/
X/*efine UNOS_MKDIR			/* Use makedir, not mkdir?	*/
X/*efine NEED_QSORT			/* Don't have qsort(3)?		*/
X/*efine NEED_GETOPT			/* Don't have getopt(3)?	*/
X#define NEED_STRERROR			/* Don't have strerror(3)?	*/
X#define HAVE_SYSTEM			/* Have system(3)?		*/
X#define CAN_POPEN			/* Can invoke file(1) command?	*/
X/*efine USE_MY_SHELL			/* Don't popen("/bin/sh")?	*/
X/*efine void		int		/* If you don't have void	*/
X/*pedef void		 sigret_t;	/* What a signal handler returns */
Xtypedef int		 sigret_t;	/* What a signal handler returns */
Xtypedef int		*align_t;	/* Worst-case alignment, for lint */
X/*pedef long		time_t		/* Needed for non-BSD sites?	*/
X/*pedef long		off_t		/* Needed for non-BSD sites?	*/
X/*efine SYS_WAIT			/* Have <sys/wait.h> and vfork?	*/
X/*efine HAS_VFORK			/* Have vfork but no <sys/wait.h> */
X/*efine USE_SYSTEM			/* Use system(3), not exec(2)?	*/
X/*efine USE_LONGJMP			/* Don't exit() within parser?	*/
X#define USE_SYSERRLIST			/* Have sys_errlist[], sys_nerr? */
X#define USE_GETPWUID			/* Use getpwuid(3)?		*/
X#define DEF_SAVEIT	TRUE		/* Save headers by default?	*/
X#define UNIX_FILES			/* stat(file) gives true size?	*/
X#define NAME_FORMAT	"%s%2.2d"	/* To get things like Part02	*/
X/*efine NAME_FORMAT	"%s%02.2d"	/* To get things like Part02	*/
X#define NUMB_FORMAT	"%02d"		/* To get things like 03	*/
X#define MANI_FORMAT	"%-25s %2d\t%s\n"	/* This should be safe	*/
X#define MAX_LEVELS	6		/* Levels for findsrc to walk	*/
X#define THE_TTY		"/dev/tty"	/* Maybe "con:" for MS-DOS?	*/
X#define RCSID				/* Compile in the RCS strings?	*/
X#define USERNAME	"Someone"	/* Your name, if not in environ	*/
X#define PTR_SPRINTF			/* Need extern char *sprinf()?	*/
X/*efine DECLARE_PROTOTYPES		/* Use prototypes in our decls?	*/
X/*efine ANSI_HDRS			/* Use <stdlib.h>, etc.?	*/
X#define REGISTER	register	/* Do you trust your compiler?	*/
X#define PEDAGOGY			/* Advertise tools?		*/
X
X
X/*
X**  How do we test to see if a character is okay to pass to one of
X**  the macros in <ctype.h>?  Note that we never give it EOF.
X*/
X#define CTYPE(c)	(isascii((c)))	/* Common			*/
X/*efine CTYPE(c)	((c) > 0)	/* Less common			*/
X/*efine CTYPE(c)	(TRUE)		/* Uncommon			*/
X
X
X/*
X**  We often want to make a backup copy of a file (usually a manifest).
X**  The following sets of #define's control how the copying is done.
X*/
X/*efine BU_VIA_RENAME			/* Use rename call?		*/
X#define BU_VIA_LINK			/* Use link/unlink calls?	*/
X/*efine BU_VIA_COPY			/* Use fopen() and such?	*/
X/*efine BU_NONE				/* System has generations?	*/
X/*efine BU_PREFIX	"B-"		/* Instead of ".BAK" suffix?	*/
X#define BU_SUFFIX	".BAK"		/* Instead of "B-" prefix?	*/
X#define BU_NAME_LEN	14		/* For non-BSD filesystems	*/
X
X
X/*
X**  The programs create up to two temporary files at one time, using
X**  mktemp(3).  Decide where you want the files to go, and if you wanna
X**  use a special directory for them (see MakeTempName).
X*/
X#define TEMP_NAME1	"/tmp/csharXXXXXX"	/* Unix			*/
X#define TEMP_NAME2	"/tmp/csharXXXXXX"	/* Unix			*/
X/*efine TEMP_NAME1	"csharXXXXXX"		/* MS-DOS		*/
X/*efine TEMP_NAME2	"csharXXXXXX"		/* MS-DOS		*/
X/*efine TEMP_NAME1	"sys$login:csharXXXXXX"	/* VMS			*/
X/*efine TEMP_NAME2	"sys$login:csharXXXXXX"	/* VMS			*/
X#define TEMPSIZE	40		/* Size of temp file name	*/
X/*efine TEMPVAR		"TMPDIR"	/* Place for temp files		*/
X
X
X/*
X**  There are several ways to get the current machine name.  Enable just one
X**  of one of the following lines.
X*/
X/*efine GETHOSTNAME			/* Use gethostname(2) call	*/
X#define UNAME				/* Use uname(2) call		*/
X/*efine UUNAME				/* Invoke "uuname -l"		*/
X/*efine	WHOAMI		"/etc/whoami"	/* Try /etc/whoami & <whoami.h>	*/
X/*efine HOST_STRING			/* Just use DEF_HOST		*/
X#define DEF_HOST	"SITE"		/* If all else fails		*/
X
X
X/*
X**  There are several different ways to get the current working directory.
X**  Enable just one of the following lines.
X*/
X/*efine GETWD				/* Use getwd(3) routine		*/
X#define GETCWD				/* Use getcwd(3) routine	*/
X/*efine PWDPOPEN			/* Invoke "pwd"			*/
X/*efine PWDGETENV	"PWD"		/* Get $PWD from environment	*/
X
X
X/*
X**  If you're a notes site, you might have to tweak these two #define's.
X**  If you don't care, then set them equal to something that doesn't
X**  start with the comment-begin sequence and they'll be effectively no-ops
X**  at the cost of an extra strcmp.  I've also heard of broken MS-DOS
X**  compilers that don't ignore slash-star inside comments!  Anyhow, for
X**  more details see unshar.c
X*/
X/*efine NOTES1		"/* Written "	/* This is what notes 1.7 uses	*/
X/*efine NOTES2		"/* ---"	/* This is what notes 1.7 uses	*/
X#define NOTES1		"$$"		/* This is a don't care		*/
X#define NOTES2		"$$"		/* This is a don't care		*/
X
X
X/*
X**  The findsrc program uses the readdir() routines to read directories.
X**  If your system doesn't have this interface, there are public domain
X**  implementations available for Unix from the comp.sources.unix archives,
X**  GNU has a VMS one inside EMACS, and this package comes with kits for
X**  MS-DOS and the Amiga.  Help save the world and use or write a readdir()
X**  package for your system!
X*/
X
X/* Now then, where did I put that header file?   Pick one. */
X/*efine IN_SYS_DIR			/* <sys/dir.h>			*/
X#define IN_SYS_NDIR			/* <sys/ndir.h>			*/
X/*efine IN_DIR				/* <dir.h>			*/
X/*efine IN_DIRECT			/* <direct.h>			*/
X/*efine IN_NDIR				/* "ndir.h"			*/
X/*efine IN_DIRENT			/* <dirent.h>			*/
X
X/*  What readdir() returns.  Must be a #define because of #include order. */
X#ifdef	IN_DIRENT
X#define DIRENTRY	struct dirent
X#else
X#define DIRENTRY	struct direct
X#endif	/* IN_DIRENT */
X
X
X/*
X**  Limits.  The shell parser can be compiled with some safety-checks.
X**  This includes creating too many files, or writing long ones, creating
X**  too many directories, overwriting existing files, etc.
X*/
X/*efine NAME_CHECK			/* Munge names of files?	*/
X/*efine PATH_CHECK			/* Check filenames in shars?	*/
X/*efine MAX_FOPENS	40		/* Max # of files/archive	*/
X/*efine MAX_LINES	1200		/* Max # of lines in a file	*/
X/*efine MAX_MKDIRS	10		/* Max directory depth		*/
X
X
X/*
X**  Congratulations, you're done!
X*/
END_OF_FILE
  if test 6993 -ne `wc -c <'config.x38'`; then
    echo shar: \"'config.x38'\" unpacked with wrong size!
  fi
  # end of 'config.x38'
fi
if test -f 'findsrc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'findsrc.c'\"
else
  echo shar: Extracting \"'findsrc.c'\" \(11194 characters\)
  sed "s/^X//" >'findsrc.c' <<'END_OF_FILE'
X/*
X**  FINDSRC
X**
X**  Walk directories, trying to find source files.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header: findsrc.c,v 2.2 88/06/06 22:04:03 rsalz Exp $";
X
X/*
X**  Wildcard patterns, and whether or not to include these things.
X*/
Xtypedef struct _table {
X    char	*Pattern;
X    int		*Value;
X    int		FullPath;
X} TABLE;
X
X
X/*
X**  Global variables.
X*/
Xstatic int	DoRCS;			/* Do RCS and SCCS files?	*/
Xstatic int	False;			/* A FALSE value		*/
Xstatic int	True = 1;		/* A TRUE value			*/
Xstatic int	Default;		/* Default answer from user	*/
Xstatic int	Verbose;		/* List rejected files, too?	*/
Xstatic char	Dname[TEMPSIZE];	/* Filename of directory list	*/
Xstatic char	Fname[TEMPSIZE];	/* Filename of file list	*/
Xstatic FILE	*Dfile;			/* List of directories found	*/
Xstatic FILE	*Ffile;			/* List of files found		*/
Xstatic FILE	*DEVTTY;		/* The tty, if in filter mode	*/
Xstatic TABLE	*EndTable;		/* End of pattern table		*/
X
X
XTABLE	Table[MAX_PATTERNS] = {
X	/* Common cruft we never want. */
X    { "TAGS",	&False, FALSE },	{ "core",	&False, FALSE },
X    { "tags",	&False, FALSE },	{ "lint",	&False, FALSE },
X    { "*.out",	&False, FALSE },	{ "*.orig",	&False, FALSE },
X    { "*.rej",	&False, FALSE },	{ "*.BAK",	&False, FALSE },
X    { "*.CKP",	&False, FALSE },	{ "*.old",	&False, FALSE },
X    { "*.o",	&False, FALSE },	{ "*.EXE",	&False, FALSE },
X    { "*.OBJ",	&False, FALSE },	{ "*~",		&False, FALSE },
X    { "*.ln",	&False, FALSE },	{ "*.dvi",	&False, FALSE },
X    { "Part[0-9][0-9]", &False, FALSE },
X
X	/* RCS or SCCS file or directory. */
X    { "RCS",	&DoRCS, FALSE },	{ "*,v",	&DoRCS, FALSE },
X    { "SCCS",	&DoRCS, FALSE },	{ "s.*",	&DoRCS, FALSE },
X    { "CVS.adm", &False, FALSE },
X
X	/* GNU Emacs elisp. */
X    { "*.elc",	&False, FALSE },	{ "*.el*",	&True, FALSE },
X
X	/* C, lex, yacc, C++, and shell source. */
X    { "*.[Cchyl]", &True, FALSE },	{ "*.cc",	&True, FALSE },
X    { "*.sh",	&True, FALSE },		{ "*.csh",	&True, FALSE },
X    { "*.asm",	&True, FALSE },		{ "*.pas",	&True, FALSE },
X
X	/* Documentation. */
X    { "*.[1-9]", &True, FALSE },	{ "*.man",	&True, FALSE },
X    { "*.txt", &True, FALSE },		{ "*.doc",	&True, FALSE },
X    { "*.[1-9][lmcx]", &True, FALSE },	{ "*.tex",	&True, FALSE },
X    { "*.sty",	&True, FALSE },
X    { "*.texinfo", &True, FALSE },	{ "*.texi", &True, FALSE },
X
X    /* README, READ.ME, read_me, etc. */
X    { "[rR][eE][aA][dD]*", &True, FALSE },
X    { ":[rR][eE][aA][dD]*", &True, FALSE },
X
X    /* Files this package uses/creates. */
X    { "MANIFEST", &True, FALSE },	{ "PACKNOTES",	&True, FALSE },
X
X	/* Make control file. */
X    { "[Mm]akefile", &True, FALSE },	{ "descrip.mms", &True, FALSE },
X    { "GNUmakefile", &True, FALSE },
X
X	/* Larry Wall-style configuration stuff. */
X    { "Configure", &True, FALSE },	{ "*.SH",	&True, FALSE },
X
X	/* Mlisp sources, m4. */
X    { "*.mo",	&False, FALSE },	{ "*.m[4a-z]",	&True, FALSE },
X
X    { NULL }
X};
X
X
X/*
X**  Signal handler.  Clean up and die.
X*/
Xstatic sigret_t
XFCatch(s)
X    int		s;
X{
X    int		e;
X
X    e = errno;
X    if (Dname[0])
X	(void)unlink(Dname);
X    if (Fname[0])
X	(void)unlink(Fname);
X    Fprintf(stderr, "Got signal %d, %s.\n", s, strerror(e));
X    exit(1);
X    /* NOTREACHED */
X}
X
X
X/*
X**  Given a filename, apply heuristics to see if we want it.
X*/
Xstatic int
XWanted(Name)
X    REGISTER char	*Name;
X{
X    REGISTER FILE	*F;
X    REGISTER TABLE	*Tp;
X    REGISTER char	*p;
X    char		*Tail;
X    char		buff[BUFSIZ];
X    int			Executable;
X    int			Script;
X
X    /* Get down to brass tacks. */
X    if ((Tail = RDX(Name, '/')) == NULL)
X	Tail = Name;
X    else
X	Tail++;
X    if (*Tail == '\0')
X	return FALSE;
X
X    /* Only do directories if they're not the hidden ones. */
X    switch (Ftype(Name)) {
X    default:
X	return FALSE;
X    case F_DIR:
X	if (EQ(Tail, ".") || EQ(Tail, ".."))
X	    return FALSE;
X	break;
X    case F_FILE:
X	break;
X    }
X
X    /* Scan the table. */
X    for (Tp = Table; Tp < EndTable; Tp++)
X	if (wildmat(Tp->FullPath ? Name : Tail, Tp->Pattern) == TRUE)
X	    return *Tp->Value;
X
X    /* If we have a default, give it back. */
X    if (Default)
X	return Default == 'y';
X
X#ifdef	CAN_POPEN
X    /* See what file(1) has to say; if it says executable, punt. */
X    Sprintf(buff, "exec file '%s'", Name);
X    if ((F = popen(buff, "r")) != NULL) {
X	(void)fgets(buff, sizeof buff, F);
X	(void)pclose(F);
X	for (Executable = FALSE, p = buff; (p = IDX(p, 'e')) != NULL; p++)
X	    if (PREFIX(p, "executable"))
X		Executable = TRUE;
X	for (Script = FALSE, p = buff; (p = IDX(p, 's')) != NULL; p++)
X	    if (PREFIX(p, "script"))
X		Script = TRUE;
X	if (Executable && !Script)
X	    return FALSE;
X	(void)fputs(buff, stdout);
X    }
X    else
X	Fprintf(stdout, "%s -- ", Name);
X#else
X    Fprintf(stdout, "%s -- ", Name);
X#endif	/* CAN_POPEN */
X
X    /* Add it? */
X    for ( ; ; ) {
X	if (DEVTTY == NULL)
X	    DEVTTY = fopen(ctermid((char *)NULL), "r");
X	Fprintf(stdout, "Add this one (y or n)[y]?  ");
X	(void)fflush(stdout);
X	if (fgets(buff, sizeof buff, DEVTTY) == NULL
X	 || buff[0] == '\n' || buff[0] == 'y' || buff[0] == 'Y')
X	    break;
X	if (buff[0] == 'n' || buff[0] == 'N')
X	    return FALSE;
X	if (buff[0] == '!' ) {
X	    (void)system(&buff[1]);
X	    Fprintf(stdout, "--------------------\n");
X	}
X	Fprintf(stdout, "%s:  ", Name);
X	clearerr(DEVTTY);
X    }
X    return TRUE;
X}
X
X
X/*
X**  Quick and dirty recursive routine to walk down directory tree.
X**  Could be made more general, but why bother?
X*/
Xstatic void
XProcess(p, level)
X    REGISTER char	*p;
X    REGISTER int	level;
X{
X    REGISTER char	*q;
X    DIR			*Dp;
X    DIRENTRY		*E;
X    char		buff[BUFSIZ];
X
X#if	0
X#ifdef	MSDOS
X    /* Downcase the path.  I dunno why, somebody told me to. */
X    for (q = p; *q; q++)
X	if (CTYPE(*q) && isupper(*q))
X	    *q = tolower(*q);
X#endif	/* MSDOS */
X#endif	/* 0 */
X
X    if (!GetStat(p))
X	Fprintf(stderr, "Can't walk down %s, %s.\n", p, strerror(errno));
X    else {
X	/* Skip leading ./ which find(1), e.g., likes to put out. */
X	if (p[0] == '.' && p[1] == '/')
X	    p += 2;
X
X	if (Wanted(p))
X	    Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "%s\n", p);
X	else if (Verbose)
X	    Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "REJECTED %s\n", p);
X
X	if (Ftype(p) == F_DIR)
X	    if (++level == MAX_LEVELS)
X		Fprintf(stderr, "Won't walk down %s -- more than %d levels.\n",
X			p, level);
X	    else if ((Dp = opendir(p)) != NULL) {
X		q = buff + strlen(strcpy(buff, p));
X		for (*q++ = '/'; (E = readdir(Dp)) != NULL; )
X		    if (!EQ(E->d_name, ".") && !EQ(E->d_name, "..")) {
X			(void)strcpy(q, E->d_name);
X			Process(buff, level);
X		    }
X		(void)closedir(Dp);
X	    }
X	    else
X		Fprintf(stderr, "Can't open directory %s, %s.\n",
X			p, strerror(errno));
X    }
X}
X
X
X/*
X**  Try to insert a pattern to the table; return FALSE if it failed.
X*/
Xstatic int
XAddPattern(Pattern, Value, FullPath)
X    char		*Pattern;
X    int			*Value;
X    int			FullPath;
X{
X    register TABLE	*Tp;
X
X    if (EndTable == &Table[sizeof Table / sizeof Table[0] - 1]) {
X	Fprintf(stderr, "Not enough space in pattern table, sorry.\n");
X	return FALSE;
X    }
X
X    /* Move everyone down, then insert the new pattern. */
X    for (Tp = EndTable; Tp > Table; Tp--) {
X	Tp[0].Pattern = Tp[-1].Pattern;
X	Tp[0].Value = Tp[-1].Value;
X	Tp[0].FullPath = Tp[-1].FullPath;
X    }
X    Table[0].Pattern = Pattern;
X    Table[0].Value = Value;
X    Table[0].FullPath = FullPath;
X    EndTable++;
X    return TRUE;
X}
X
X
Xint
Xmain(ac, av)
X    REGISTER int	ac;
X    REGISTER char	*av[];
X{
X    REGISTER FILE	*F;
X    REGISTER char	*p;
X    REGISTER int	i;
X    REGISTER int	Oops;
X    register TABLE	*Tp;
X    int			Header;
X    int			Dumpit;
X    char		*Outfile;
X    char		buff[BUFSIZ];
X
X    /* Find the end of the pattern table. */
X    for (EndTable = Table; EndTable->Pattern; EndTable++)
X	continue;
X
X    /* Parse JCL. */
X    Header = 0;
X    Dumpit = FALSE;
X    Outfile = NULL;
X    for (Oops = FALSE; (i = getopt(ac, av, "d:h:lmN:n:o:rsvxY:y:")) != EOF; )
X	switch (i) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'd':		/* Default answer			*/
X	    switch (optarg[0]) {
X	    default:
X		Oops = TRUE;
X		break;
X	    case 'y': case 'Y':
X		Default = 'y';
X		break;
X	    case 'n': case 'N':
X		Default = 'n';
X		break;
X	    }
X	    break;
X	case 'h':		/* Lines of header to skip		*/
X	    Header = atoi(optarg);
X	    break;
X	case 'l':		/* Log output				*/
X	    Verbose = TRUE;
X	    break;
X	case 'm':		/* Convenient option shorthand		*/
X	    Outfile = "MANIFEST";
X	    Header = 2;
X	    break;
X	case 'N':		/* Add a reject pattern			*/
X	case 'n':		/* Add a reject pattern			*/
X	    if (AddPattern(optarg, &False, i == 'N') == FALSE)
X		Oops = TRUE;
X	    break;
X	case 'o':		/* Output file name			*/
X	    Outfile = optarg;
X	    break;
X	case 'r':		/* Take RCS and SCCS files		*/
X	case 's':		/* Take RCS and SCCS files		*/
X	    DoRCS = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X	case 'x':		/* Dump the pattern database		*/
X	    Dumpit = TRUE;
X	    break;
X	case 'Y':		/* Add an accept pattern		*/
X	case 'y':		/* Add an accept pattern		*/
X	    if (AddPattern(optarg, &True, i == 'Y') == FALSE)
X		Oops = TRUE;
X	    break;
X	}
X    ac -= optind;
X    av += optind;
X
X    if (Oops) {
X	Fprintf(stdout, "Usage:\n  findsrc %s\n          %s files...\n",
X		"[-d{yn}] [-{yYnN} pattern] [-r] [-s] [-v] [-x]",
X		"[-m | -o MANIFEST -h 2]");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Open the output file. */
X    if (Outfile == NULL)
X	F = stdout;
X    else {
X	if (Fexists(Outfile))
X	    SafeRename(Outfile);
X	if ((F = fopen(Outfile, "w")) == NULL) {
X	    Fprintf(stderr, "Can't open %s for output, %s.\n",
X		    optarg, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X    }
X
X    /* Dump the pattern table. */
X    if (Dumpit) {
X	Fprintf(F, "  Pattern               Included?\n");
X	Fprintf(F, "  --------------------  ---------\n");
X	for (i = 0, Tp = Table; Tp < EndTable; Tp++, i++)
X	    Fprintf(F, "  %-20s  %s\n",
X		    Tp->Pattern, *Tp->Value ? "yes" : "no");
X	Printf("There are a total of %d patterns\n", i);
X	(void)fclose(F);
X	exit(0);
X    }
X
X    /* Open temp files, set signal catcher. */
X    MakeTempName(Dname, TEMP_NAME1);
X    Dfile = fopen(Dname, "w");
X    MakeTempName(Fname, TEMP_NAME2);
X    Ffile = fopen(Fname, "w");
X    SetSigs(FCatch);
X
X    /* Read list of files, determine their status. */
X    if (*av)
X	for (DEVTTY = stdin; *av; av++)
X	    Process(*av, 0);
X    else
X	while (fgets(buff, sizeof buff, stdin)) {
X	    if ((p = IDX(buff, '\n')) == NULL)
X		Fprintf(stderr, "Warning, line too long:\n\t%s\n", buff);
X	    else
X		*p = '\0';
X	    Process(buff, 0);
X	}
X
X    /* Print the header. */
X    if (Header >= 2) {
X	Fprintf(F, "Name\tDescription\n");
X	Fprintf(F, "----\t-----------\n");
X	Header -= 2;
X    }
X    while (--Header >= 0)
X	Fprintf(F, "\n");
X
X    /* First print directories. */
X    if (freopen(Dname, "r", Dfile)) {
X	while (fgets(buff, sizeof buff, Dfile))
X	    if ((p = IDX(buff, '\n')) != NULL)
X		*p = '\0';
X	    Fprintf(F, "%s (Directory)\n");
X	(void)fclose(Dfile);
X    }
X
X    /* Now print regular files. */
X    if (freopen(Fname, "r", Ffile)) {
X	while (fgets(buff, sizeof buff, Ffile))
X	    (void)fputs(buff, F);
X	(void)fclose(Ffile);
X    }
X
X    /* That's all she wrote. */
X    (void)unlink(Dname);
X    (void)unlink(Fname);
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 11194 -ne `wc -c <'findsrc.c'`; then
    echo shar: \"'findsrc.c'\" unpacked with wrong size!
  fi
  # end of 'findsrc.c'
fi
if test -f 'maniscan.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'maniscan.c'\"
else
  echo shar: Extracting \"'maniscan.c'\" \(12395 characters\)
  sed "s/^X//" >'maniscan.c' <<'END_OF_FILE'
X/*
X**  MANISCAN
X**
X**  Read a manifest, looking for large files and those with binary data.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header$";
X
X#ifdef	HAVE_SYSTEM
X#define ARGS	"vc:ef:h:i:l:mno:s:t:w:"
X#else
X#define ARGS	"vef:h:i:l:mno:s:t:w:"
X#endif	/* HAVE_SYSTEM */
X
X/*
X**  Global variables.
X*/
Xstatic long	Size;			/* Bigger than this is bad	*/
X#ifdef	HAVE_SYSTEM
Xstatic char	*Command;		/* Command to create file	*/
X#endif	/* HAVE_SYSTEM */
Xstatic int	Width = SAFE_WIDTH + 1; /* Longest safe linelength	*/
Xstatic int	TrailWhite = TRUE;	/* Check for trailing spaces?	*/
Xstatic FILE	*Logfile;		/* Where to record problems	*/
Xstatic int	NameLength;		/* Limit length of filenames?	*/
Xstatic char	TempName[TEMPSIZE];	/* Temporary output file	*/
X
X
X/*
X**  Safely add an extension to a filename.
X*/
Xstatic void
XAddExtension(Name, Suffix, Buffer)
X    char	*Name;
X    char	*Suffix;
X    char	*Buffer;
X{
X    if (NameLength == 0 || strlen(Name) + 1 + strlen(Suffix) < NameLength)
X	Sprintf(Buffer, "%s.%s", Name, Suffix);
X    else
X	Sprintf(Buffer, "%.*s%s", NameLength - strlen(Suffix), Name, Suffix);
X}
X
X
X/*
X**  Note that we have to run uudecode.
X*/
Xstatic int
XUUnote(Smudged, Name, Newname)
X    int			Smudged;
X    char		*Name;
X    char		*Newname;
X{
X    if (Logfile) {
X	if (!Smudged) {
X	    Smudged = TRUE;
X	    Fprintf(Logfile, "\n");
X	}
X	Fprintf(Logfile, "# Run uudecode to create \"%s\":\n", Name);
X	Fprintf(Logfile, "\tuudecode %s\n", Newname);
X    }
X    return Smudged;
X}
X
X
X/*
X**  Do the grunge work of checking a file.  Note that we scan stuff more
X**  than once because, e.g., after it's been uuencoded and edited it
X**  might be too long.
X*/
Xstatic int
XCheckUp(Mfile, Name, Commentary)
X    register FILE	*Mfile;
X    char		*Name;
X    char		*Commentary;
X{
X    REGISTER FILE	*F;
X    REGISTER FILE	*Sfile;
X    REGISTER char	*p;
X    REGISTER int	i;
X    REGISTER int	n;
X    REGISTER long	s;
X    char		buff[READ_CHUNK];
X    char		Newname[LINE_SIZE];
X    char		Oldname[LINE_SIZE];
X    char		Digits[10];
X    int			Encoded;
X    int			Smudged;
X
X    /* Does file exist? */
X    n = !Fexists(Name);
X#ifdef	HAVE_SYSTEM
X    if (n && Command) {
X	/* No -- try to make it. */
X	(void)sprintf(buff, Command, Name);
X	(void)system(buff);
X	n = !Fexists(Name);
X    }
X#endif	/* HAVE_SYSTEM */
X    if (n) {
X	Fprintf(stderr, "File \"%s\" doesn't exist.\n",
X		Name);
X	return FALSE;
X    }
X
X    /* For now, we do nothing about directories. */
X    if (Ftype(Name) == F_DIR) {
X	Fprintf(Mfile, "%s%s\n", Name, Commentary);
X	return FALSE;
X    }
X
X    /* Open file, read a chunk. */
X    if ((F = fopen(Name, "r")) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" to check it, %s.\n",
X		Name, strerror(errno));
X	return FALSE;
X    }
X    if ((n = fread(buff, sizeof buff[0], READ_CHUNK, F)) <= 0) {
X	if (n < 0)
X	    Fprintf(stderr, "Can't read \"%s\" to check it, %s.\n",
X		    Name, strerror(errno));
X	(void)fclose(F);
X	return FALSE;
X    }
X
X    /* Is it binary?  Rough hueristic -- one third of the chunk isn't
X     * printable. */
X    for (Smudged = FALSE, p = buff, i = 0; p < &buff[n]; p++)
X	if (!CTYPE(*p) || !isprint(*p))
X	    i++;
X    Encoded = i > n / 3;
X    if (Encoded) {
X	AddExtension(Name, "UU", Newname);
X	uuencode(Name, Newname);
X	(void)strcpy(Oldname, Name);
X	(void)strcpy(Name, Newname);
X	(void)fclose(F);
X	if ((F = fopen(Name, "r")) == NULL) {
X	    Fprintf(stderr, "Can't open \"%s\" to check it, %s.\n",
X		    Name, strerror(errno));
X	    return UUnote(Smudged, Oldname, Newname);
X	}
X    }
X
X    /* See if the input has any long lines, or bad characters. */
X    if (!Encoded) {
X	rewind(F);
X	for (i = 1; fgets(buff, sizeof buff, F); i++) {
X	    if ((p = IDX(buff, '\n')) != NULL)
X		*p = '\0';
X	    if (Width && (p == NULL || p >= &buff[Width]))
X		if (Logfile) {
X		    if (!Smudged) {
X			Smudged = TRUE;
X			Fprintf(Logfile, "\n");
X		    }
X		    Fprintf(Logfile, "# \"%s\", line %d: line too long\n",
X			    Name, i);
X		}
X
X	    for (p = buff; *p; p++)
X		if (!CTYPE(*p) || !(isprint(*p) || isspace(*p)))
X		    if (Logfile) {
X			if (!Smudged) {
X			    Smudged = TRUE;
X			    Fprintf(Logfile, "\n");
X			}
X			Fprintf(Logfile,
X			"# \"%s\", line %d: non-printable character 0%o (%s)\n",
X				Name, i, *p, Seechar(*p));
X		    }
X
X	    /* Is last character whitespace?  BITNET will choke. */
X	    if (TrailWhite && p > buff) {
X		p--;
X		if (!CTYPE(*p) || isspace(*p))
X		    if (Logfile) {
X			if (!Smudged) {
X			    Smudged = TRUE;
X			    Fprintf(Logfile, "\n");
X			}
X			Fprintf(Logfile,
X				"# \"%s\", line %d: ends with whitespace 0%o\n",
X				Name, i, *p);
X		    }
X	    }
X	}
X    }
X
X    (void)fclose(F);
X
X    /* Small enough to fit? */
X    if (Fsize(Name) <= Size) {
X	Fprintf(Mfile, "%s%s\n", Name, Commentary);
X	return Encoded ? UUnote(Smudged, Oldname, Newname) : Smudged;
X    }
X
X    /* Open input. */
X    if ((F = fopen(Name, "r")) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" to split it, %s.\n",
X		Name, strerror(errno));
X	return Encoded ? UUnote(Smudged, Oldname, Newname) : Smudged;
X    }
X
X    /* Open first output, write commentary. */
X    i = 0;
X    Sprintf(Digits, NUMB_FORMAT, ++i);
X    AddExtension(Name, Digits, Newname);
X    if ((Sfile = fopen(Newname, "w")) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" for writing, %s.\n",
X		Newname, strerror(errno));
X	(void)fclose(F);
X	return Encoded ? UUnote(Smudged, Oldname, Newname) : Smudged;
X    }
X    Fprintf(Mfile, "%s%s (part %d)\n", Newname, Commentary, i);
X
X    /* Read input, when current output gets too big, start a new file. */
X    for (s = 0; fgets(buff, sizeof buff, F); ) {
X	s += strlen(buff);
X	if (s > Size) {
X	    /* Start a new file. */
X	    (void)fclose(Sfile);
X	    Sprintf(Digits, NUMB_FORMAT, ++i);
X	    AddExtension(Name, Digits, Newname);
X	    if ((Sfile = fopen(Newname, "w")) == NULL) {
X		Fprintf(stderr, "Can't open \"%s\" for writing, %s.\n",
X			Newname, strerror(errno));
X		(void)fclose(F);
X		return Encoded ? UUnote(Smudged, Oldname, Newname) : Smudged;
X	    }
X	    Fprintf(Mfile, "%s%s (part %d)\n", Newname, Commentary, i);
X	    s = strlen(buff);
X	}
X	(void)fputs(buff, Sfile);
X    }
X
X    /* Close input and current output, remove temporary if we made one. */
X    (void)fclose(F);
X    (void)fclose(Sfile);
X    if (Encoded)
X	(void)unlink(Name);
X
X    /* Write summary message. */
X    if (Logfile) {
X	if (!Smudged) {
X	    Smudged = TRUE;
X	    Fprintf(Logfile, "\n");
X	}
X	Fprintf(Logfile,
X	    "# \"%s\" was split into %d parts; to create it, do\n",
X	    Name, i);
X	if (i < 10)
X	    Fprintf(Logfile, "\tcat %s.0[1-9] >%s\n", Name, Name);
X	else if (i < 100)
X	    Fprintf(Logfile, "\tcat %s.[1-9] %s.[1-9][0-9] >%s\n",
X		    Name, Name, Name);
X	else
X	    Fprintf(Logfile, "\tWhatever is appropriate\n");
X    }
X    return Encoded ? UUnote(Smudged, Oldname, Newname) : Smudged;
X}
X
X
X/*
X**  Signal handler.  Clean up and die.
X*/
Xstatic sigret_t
XCatch(s)
X    int		s;
X{
X    int		e;
X
X    e = errno;
X    if (TempName[0])
X	(void)unlink(TempName);
X    Fprintf(stderr, "Got signal %d, %s.\n", s, strerror(e));
X    exit(1);
X    /* NOTREACHED */
X}
X
X
Xint
Xmain(ac, av)
X    REGISTER int	ac;
X    REGISTER char	*av[];
X{
X    REGISTER FILE	*F;
X    REGISTER char	*p;
X    REGISTER int	i;
X    REGISTER int	Header;
X    REGISTER int	LogDirty;
X    char		*InName;
X    char		*OutName;
X    char		*LogName;
X    char		*NameStart;
X    char		*Trailer;
X    char		buff[BUFSIZ];
X    char		Rest[LINE_SIZE];
X    char		Name[LINE_SIZE];
X    int			ExcludeIt;
X    int			Oops;
X
X    /* Parse JCL. */
X    ExcludeIt = FALSE;
X    InName = NULL;
X    OutName = NULL;
X    LogName = NULL;
X    Header = 0;
X    Size = 50000;
X    Trailer = NULL;
X    for (Oops = FALSE; (i = getopt(ac, av, ARGS)) != EOF; )
X	switch (i) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X#ifdef	HAVE_SYSTEM
X	case 'c':		/* Command to run if file doesn't exist	*/
X	    Command = optarg;
X	    break;
X#endif	/* HAVE_SYSTEM */
X	case 'e':		/* Don't include manifest in manifest	*/
X	    ExcludeIt = TRUE;
X	    break;
X	case 'f':		/* Limit length of generated filenames	*/
X	    NameLength = atoi(optarg);
X	    break;
X	case 'h':		/* Lines of header to skip		*/
X	    Header = atoi(optarg);
X	    break;
X	case 'i':		/* Name of input manifest		*/
X	    InName = optarg;
X	    break;
X	case 'l':		/* Name of packnotes log file		*/
X	    LogName = optarg;
X	    break;
X	case 'm':		/* Convenient option shorthand		*/
X	    LogName = "PACKNOTES";
X	    InName = OutName = "MANIFEST";
X	    Header = 2;
X	    break;
X	case 'n':		/* Don't check for trailing whitespace	*/
X	    TrailWhite = FALSE;
X	    break;
X	case 'o':		/* Name for generated manifest file	*/
X	    OutName = optarg;
X	    break;
X	case 's':		/* Maximum file size			*/
X	    Size = (long)atoi(optarg);
X	    if (IDX(optarg, 'k') || IDX(optarg, 'K'))
X		Size *= 1024;
X	    break;
X	case 't':		/* Final note after unpacking		*/
X	    Trailer = optarg;
X	    break;
X	case 'w':		/* Maximum line width			*/
X	    if ((Width = atoi(optarg)) > READ_CHUNK) {
X		Fprintf(stderr,
X		    "Can't check widths greater than %d, option ignored.\n",
X		    READ_CHUNK);
X		Width = 0;
X	    }
X	    break;
X	}
X    ac -= optind;
X    av += optind;
X
X    if (ac != 0 || Oops) {
X	Fprintf(stderr, "Usage:\n  maniscan %s          %s\n",
X#ifdef	HAVE_SYSTEM
X		"[-e] [-n] [-s#[k]] [-ttext] [-w#]",
X#else
X		"[-e] [-n] [-s#[k]] [-ttext] [-w#] [-c command]",
X#endif	/* HAVE_SYSTEM */
X		"[-m | -iMANIFEST -oMANIFEST -h2 -lPACKNOTES]");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Open the input file. */
X    if (InName && freopen(InName, "r", stdin) == NULL) {
X	Fprintf(stderr, "Can't read %s as manifest, %s.\n",
X		InName, strerror(errno));
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Open the output file. */
X    if (OutName == NULL)
X	F = stdout;
X    else {
X	MakeTempName(TempName, TEMP_NAME1);
X	if ((F = fopen(TempName, "w")) == NULL) {
X	    Fprintf(stderr, "Can't open '%s' for output, %s.\n",
X		    TempName, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X	SetSigs(Catch);
X    }
X
X    /* Open the log file. */
X    LogDirty = FALSE;
X    if (LogName) {
X	if (EQ(LogName, "-")) {
X	    Logfile = stderr;
X	    ExcludeIt = TRUE;
X	}
X	else if ((Logfile = fopen(LogName, "w")) == NULL) {
X	    Fprintf(stderr, "Can't open \"%s\" for output, %s.\n",
X		    LogName, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X    }
X
X    /* Reduce size by slop so last line doesn't make us too long. */
X    Size -= 2 * Width;
X
X    /* Skip any possible prolog, then output rest of file. */
X    while (--Header >= 0 && fgets(buff, sizeof buff, stdin))
X	(void)fputs(buff, F);
X    if (feof(stdin)) {
X	Fprintf(stderr, "Nothing but header lines in the manifest.\n");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Scan rest of file. */
X    while (fgets(buff, sizeof buff, stdin)) {
X	if ((p = IDX(buff, '\n')) == NULL)
X	    Fprintf(stderr, "Warning, line too long:\n\t%s\n", buff);
X	else
X	    *p = '\0';
X
X	/* Skip leading whitespace and ignore all-blank lines. */
X	for (p = buff; *p && CTYPE(*p) && isspace(*p); )
X	    p++;
X	if (*p == '\0')
X	    continue;
X	/* Save name, find end of it, stuff rest of line away. */
X	for (NameStart = p; *++p && CTYPE(*p) && !isspace(*p); )
X	    continue;
X	i = *p;
X	*p = '\0';
X	(void)strcpy(Name, NameStart);
X	*p = i;
X	(void)strcpy(Rest, p);
X
X	if (LogName && EQ(Name, LogName))
X	    continue;
X
X	if (CheckUp(F, Name, Rest))
X	    LogDirty = TRUE;
X    }
X
X    /* Close logfile, possibly add it to the manifest. */
X    if (Logfile) {
X	if (Trailer && *Trailer) {
X	    Fprintf(F, "# Follow these instructions:\n");
X	    Fprintf(F, "\techo \"%s\"\n", Trailer);
X	}
X	if (Logfile != stderr)
X	    (void)fclose(Logfile);
X	if (LogDirty && !ExcludeIt)
X	    Fprintf(F, MANI_FORMAT,
X		    LogName, 1, "Warnings about long lines, etc");
X    }
X
X    /* Move temp file to new file? */
X    if (OutName) {
X	/* Open new file. */
X	(void)fclose(F);
X	if ((F = fopen(TempName, "r")) == NULL) {
X	    Fprintf(stderr, "Can't open \"%s\" for reading, %s.\n",
X		    Name, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X
X	/* Save old manifest. */
X	if (Fexists(OutName))
X	    SafeRename(OutName);
X	if (freopen(OutName, "w", stdout) == NULL) {
X	    Fprintf(stderr, "Can't open \"%s\" for writing, %s.\n",
X		    OutName, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X
X	/* Copy. */
X	while (fgets(buff, sizeof buff, F))
X	    (void)fputs(buff, stdout);
X    }
X
X    /* That's all she wrote. */
X    if (TempName[0])
X	(void)unlink(TempName);
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 12395 -ne `wc -c <'maniscan.c'`; then
    echo shar: \"'maniscan.c'\" unpacked with wrong size!
  fi
  # end of 'maniscan.c'
fi
if test -f 'shar.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shar.c'\"
else
  echo shar: Extracting \"'shar.c'\" \(9202 characters\)
  sed "s/^X//" >'shar.c' <<'END_OF_FILE'
X/*
X**  SHAR
X**
X**  Make a shell archive of a list of files.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header: shar.c,v 2.1 88/06/03 11:51:12 rsalz Locked $";
X
X/*
X**  Minimum allocation of file name pointers used in "-i" option processing.
X*/
X#define	MIN_FILES	50
X
X
X/*
X**  This prolog is output before the archive.
X*/
Xstatic char	 *Prolog[] = {
X  "! /bin/sh",
X  " This is a shell archive.  Remove anything before this line, then feed it",
X  " into a shell via \"sh file\" or similar.  To overwrite existing files,",
X  " type \"sh file -c\".",
X#ifdef	PEDAGOGY
X  " The tool that generated this appeared in the comp.sources.unix newsgroup;",
X  " send mail to comp-sources-unix@uunet.uu.net if you want that tool.",
X#endif	/* PEDAGOGY */
X  NULL
X};
X
X
X/*
X**  Package up one file or directory.
X*/
Xstatic void
Xshar(file, Basename)
X    char		*file;
X    int			Basename;
X{
X    REGISTER FILE	*F;
X    REGISTER char	*s;
X    REGISTER char	*Name;
X    REGISTER int	Bads;
X    REGISTER off_t	Size;
X    REGISTER long	l;
X    int			Fixit;
X    int			FixedCount;
X    char		buff[BUFSIZ];
X
X    /* Just in case. */
X    if (EQ(file, ".") || EQ(file, "..") || file[0] == '\0')
X	return;
X
X    Size = Fsize(file);
X    Name = Basename && (Name = RDX(file, '/')) ? Name + 1 : file;
X
X    /* Making a directory? */
X    if (Ftype(file) == F_DIR) {
X	s = &file[strlen(file) - 1];
X	if (*s == '/')
X	    *s = '\0';
X	Printf("if test ! -d '%s' ; then\n", Name);
X	Printf("    echo shar: Creating directory \\\"'%s'\\\"\n", Name);
X	Printf("    mkdir '%s'\n", Name);
X	Printf("fi\n");
X    }
X    else {
X	if ((F = fopen(file, "r")) == NULL) {
X	    Fprintf(stderr, "Can't open \"%s\" %s\n", file, strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X
X	/* Emit the per-file prolog. */
X	Printf("if test -f '%s' -a \"${1}\" != \"-c\" ; then \n", Name);
X	Printf("  echo shar: Will not clobber existing file \\\"'%s'\\\"\n",
X	    Name);
X	Printf("else\n");
X	Printf("  echo shar: Extracting \\\"'%s'\\\" \\(%ld character%s\\)\n",
X	       Name, (long)Size, Size == 1 ? "" : "s");
X	Printf("  sed \"s/^X//\" >'%s' <<'END_OF_FILE'\n", Name);
X
X	/* Output the file contents. */
X	FixedCount = 0;
X	for (l = 1, Bads = 0; fgets(buff, sizeof buff, F); l++) {
X	    s = IDX(buff, '\n');
X	    Fixit = s == NULL;
X	    if (Fixit)
X		Fprintf(stderr, "Warning, newline missing:\n\t%s\n", buff);
X
X	    (void)putchar('X');
X	    for (s = buff; *s; s++) {
X		if (BADCHAR(*s)) {
X		    Fprintf(stderr,
X			"Non-printable character 0%o in line %ld of \"%s\".\n",
X			*s, l, Name);
X		    Bads++;
X		}
X		(void)putchar(*s);
X	    }
X	    if (Fixit) {
X		(void)putchar('\n');
X		FixedCount++;
X	    }
X	}
X	(void)fclose(F);
X
X	/* Check for missing \n at end of file. */
X	Printf("END_OF_FILE\n",Name);
X	if (FixedCount) {
X	    Printf("  echo shar: appended %d NEWLINEs to \\\"'%s'\\\"\n",
X		    FixedCount, Name);
X	    Fprintf(stderr, "appended %d NEWLINEs appended to \"%s\"\n",
X		    FixedCount, Name);
X	    Size += FixedCount;
X	 }
X
X	/* Tell about any control characters. */
X	if (Bads) {
X	    Printf(
X    "  echo shar: %d control character%s may be missing from \\\"'%s'\\\"\n",
X		   Bads, Bads == 1 ? "" : "s", Name);
X	    Fprintf(stderr, "Found %d control char%s in \"%s\"\n",
X		    Bads, Bads == 1 ? "" : "s", Name);
X	}
X
X	/* Output size check. */
X	Printf("  if test %ld -ne `wc -c <'%s'`; then\n", (long)Size, Name);
X	Printf("    echo shar: \\\"'%s'\\\" unpacked with wrong size!\n", Name);
X	Printf("  fi\n");
X
X	/* Executable? */
X	if (Fexecute(file))
X	    Printf("  chmod +x '%s'\n", Name);
X
X	Printf("  # end of '%s'\nfi\n", Name);
X    }
X}
X
X
X/*
X**  Read list of files from file.
X*/
Xstatic char **
XGetFiles(Name)
X    char		*Name;
X{
X    REGISTER FILE	*F;
X    REGISTER int	i;
X    REGISTER int	count;
X    REGISTER char	**files;
X    REGISTER char	**temp;
X    REGISTER int	j;
X    char		buff[BUFSIZ];
X    char		*p;
X
X    /* Open the file. */
X    if (EQ(Name, "-"))
X	F = stdin;
X    else if ((F = fopen(Name, "r")) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" for input.\n", Name);
X	return NULL;
X    }
X
X    /* Get space. */
X    count = MIN_FILES;
X    files = NEW(char*, count);
X
X    /* Read lines. */
X    for (i = 0; fgets(buff, sizeof buff, F); ) {
X	if ((p = IDX(buff, '\n')) != NULL)
X	    *p = '\0';
X	files[i] = COPY(buff);
X	if (++i == count - 2) {
X	    /* Get more space; some systems don't have realloc()... */
X	    count += MIN_FILES;
X	    for (temp = NEW(char*, count), j = 0; j < i; j++)
X		temp[j] = files[j];
X	    files = temp;
X	}
X    }
X
X    /* Clean up, close up, return. */
X    files[i] = NULL;
X    (void)fclose(F);
X    return files;
X}
X
X
Xint
Xmain(ac, av)
X    int			ac;
X    REGISTER char	*av[];
X{
X    REGISTER char	*Trailer;
X    REGISTER char	*p;
X    REGISTER char	*q;
X    REGISTER int	i;
X    REGISTER int	length;
X    REGISTER int	Oops;
X    REGISTER int	Knum;
X    REGISTER int	Kmax;
X    REGISTER int	Basename;
X    REGISTER int	j;
X    REGISTER FILE	*F;
X    time_t		clock;
X    char		**Flist;
X    int			WithinSomething;
X
X    /* Parse JCL. */
X    Basename = 0;
X    Knum = 0;
X    Kmax = 0;
X    Trailer = NULL;
X    Flist = NULL;
X    WithinSomething = FALSE;
X    for (Oops = FALSE; (i = getopt(ac, av, "vbe:i:n:o:t:w")) != EOF; )
X	switch (i) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X	case 'b':		/* Just use basenames of files		*/
X	    Basename = TRUE;
X	    break;
X	case 'e':		/* Ending kit number, the last kit	*/
X	    Kmax = atoi(optarg);
X	    break;
X	case 'i':		/* File containing the list of files	*/
X	    Flist = GetFiles(optarg);
X	    break;
X	case 'n':		/* Number of this shar in the kit	*/
X	    Knum = atoi(optarg);
X	    break;
X	case 'o':		/* Output file name			*/
X	    if (freopen(optarg, "w", stdout) == NULL) {
X		Fprintf(stderr, "Can't open \"%s\" for output, %s.\n",
X			optarg, strerror(errno));
X		exit(1);
X		/* NOTREACHED */
X	    }
X	    break;
X	case 't':		/* Final note after unpacking		*/
X	    Trailer = optarg;
X	    break;
X	}
X    ac -= optind;
X    av += optind;
X
X    /* If user hasn't screwed up yet, make sure we exactly one of
X     * the -i flag or files named on the command line. */
X    if (!Oops
X     && ((Flist == NULL && ac == 0) || (Flist != NULL && ac != 0))) {
X	Fprintf(stderr,
X		"What files to shar?  Use -i or command line, not both.\n");
X	Oops = TRUE;
X    }
X
X    if (Oops) {
X	Fprintf(stderr, "Usage:\n  shar %s [files...]\n",
X		"[-v] [-b] [-o outfile] [-i infile] [-n# -e# -t'text']");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* If we didn't get the list from -i, rest of argv is the file list. */
X    if (Flist == NULL)
X	/* Rest of arguments are files. */
X	Flist = av;
X
X    /* Everything readable and reasonably-named? */
X    for (Oops = FALSE, i = 0; (p = Flist[i]) != NULL; i++)
X	if ((F = fopen(p, "r")) == NULL) {
X	    Fprintf(stderr, "Can't read \"%s\", %s.\n", p, strerror(errno));
X	    Oops = TRUE;
X	}
X	else {
X	    (void)fclose(F);
X	    for (; *p; p++)
X		if (!CTYPE(*p)) {
X		    Fprintf(stderr, "Bad character '%c' in \"%s\".\n",
X			    *p, Flist[i]);
X		    Oops = TRUE;
X		}
X	}
X    if (Oops)
X	exit(1);
X	/* NOTREACHED */
X
X    if (!WithinSomething) {
X	/* Prolog. */
X	for (i = 0; (p = Prolog[i]) != NULL; i++)
X	    Printf("#%s\n", p);
X	Printf("# Contents: ");
X	for (length = 12, i = 0; (p = Flist[i++]) != NULL; length += j) {
X	    if (Basename && (q = RDX(p, '/')))
X		p = q + 1;
X	    j = strlen(p) + 1;
X	    if (length + j < WIDTH)
X		Printf(" %s", p);
X	    else {
X		Printf("\n#   %s", p);
X		length = 4;
X	    }
X	}
X	Printf("\n");
X	clock = time((time_t *)NULL);
X	Printf("# Wrapped by %s@%s on %s", User(), Host(), ctime(&clock));
X	Printf("PATH=/bin:/usr/bin:/usr/ucb ; export PATH\n");
X	Printf("echo %s:\n",
X	    "If this archive is complete, you will see the following message");
X	if (Knum && Kmax)
X	    Printf("echo '          \"shar: End of archive %d (of %d).\"'\n",
X		Knum, Kmax);
X	else
X	    Printf("echo '          \"shar: End of archive.\"'\n");
X    }
X
X    /* Do it. */
X    while (*Flist)
X	shar(*Flist++, Basename);
X
X    /* Epilog. */
X    if (!WithinSomething) {
X	if (Knum && Kmax) {
X	    Printf("echo shar: End of archive %d \\(of %d\\).\n", Knum, Kmax);
X	    Printf("cp /dev/null ark%disdone\n", Knum);
X	    Printf("MISSING=\"\"\n");
X	    Printf("for I in");
X	    for (i = 0; i < Kmax; i++)
X		Printf(" %d", i + 1);
X	    Printf(" ; do\n");
X	    Printf("    if test ! -f ark${I}isdone ; then\n");
X	    Printf("\tMISSING=\"${MISSING} ${I}\"\n");
X	    Printf("    fi\n");
X	    Printf("done\n");
X	    Printf("if test \"${MISSING}\" = \"\" ; then\n");
X	    if (Kmax == 1)
X		Printf("    echo You have the archive.\n");
X	    else if (Kmax == 2)
X		Printf("    echo You have unpacked both archives.\n");
X	    else
X		Printf("    echo You have unpacked all %d archives.\n", Kmax);
X	    if (Trailer && *Trailer)
X		Printf("    echo \"%s\"\n", Trailer);
X	    Printf("    rm -f ark[1-9]isdone%s\n",
X		   Kmax >= 9 ? " ark[1-9][0-9]isdone" : "");
X	    Printf("else\n");
X	    Printf("    echo You still must unpack the following archives:\n");
X	    Printf("    echo \"        \" ${MISSING}\n");
X	    Printf("fi\n");
X	}
X	else {
X	    Printf("echo shar: End of archive.\n");
X	    if (Trailer && *Trailer)
X		Printf("echo \"%s\"\n", Trailer);
X	}
X
X	Printf("exit 0\n");
X    }
X
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 9202 -ne `wc -c <'shar.c'`; then
    echo shar: \"'shar.c'\" unpacked with wrong size!
  fi
  # end of 'shar.c'
fi
if test -f 'unshar.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unshar.c'\"
else
  echo shar: Extracting \"'unshar.c'\" \(9811 characters\)
  sed "s/^X//" >'unshar.c' <<'END_OF_FILE'
X/*
X**  UNSHAR
X**
X**  Unpack shell archives that might have gone through mail, notes, news, etc.
X**  This is Michael Mauldin's code which I have usurped and heavily modified.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header: unshar.c,v 2.2 88/06/03 16:08:14 rsalz Locked $";
X
Xstatic int	KillReturns;
X
X/*
X**  Print error message and die.
X*/
Xstatic void
XQuit(text)
X    char	*text;
X{
X    Fprintf(stderr, "unshar:  %s, %s.\n", text, strerror(errno));
X    exit(1);
X    /* NOTREACHED */
X}
X
X
X/*
X**  Does this look like a mail header line?
X*/
Xstatic int
XIsHeader(p)
X    REGISTER char	*p;
X{
X    REGISTER int	i;
X
X    if (*p == '\0' || *p == '\n')
X	return FALSE;
X    if (WHITE(*p))
X	return TRUE;
X    for (i = 0; (CTYPE(*p) && isalnum(*p)) || HDRCHAR(*p); i++)
X	p++;
X    return i && *p == ':';
X}
X
X
X/*
X**  Is this a /bin/sh comment line?  We check that because some shars
X**  output comments before the CUT line.
X*/
Xstatic int
XIsSHcomment(p)
X    REGISTER char	*p;
X{
X    while (CTYPE(*p) &&
X      (isalpha(*p) || WHITE(*p) || *p == '\n' || *p == ',' || *p == '.'))
X	p++;
X    return *p == '\0';
X}
X
X
X/*
X**  Return TRUE if p has wd1 and wd2 as words (i.e., no preceeding or
X**  following letters).  Clever code, Michael.
X*/
Xstatic int
XHas(p, wd1, wd2)
X    REGISTER char	*p;
X    REGISTER char	*wd1;
X    REGISTER char	*wd2;
X{
X    REGISTER char	*wd;
X    REGISTER int	first;
X
X    wd = wd1;
X    first = TRUE;
Xagain: 
X    while (*p) {
X	if (!CTYPE(*p) || !isalpha(*p)) {
X	    p++;
X	    continue;
X	}
X	while (*p++ == *wd++) {
X	    if (*wd == '\0') {
X		if (!CTYPE(*p) || !isalpha(*p)) {
X		    if (!first)
X			return TRUE;
X		    first = FALSE;
X		    wd = wd2;
X		    goto again;
X		}
X		break;
X	    }
X	}
X	while (CTYPE(*p) && isalpha(*p))
X	    p++;
X	wd = first ? wd1 : wd2;
X    }
X    return FALSE;
X}
X
X/*
X**  Clean up the line read from fgets so that trailing \r\n becomes
X**  just \n.
X*/
Xstatic void
XFixline(p)
X    REGISTER char	*p;
X{
X    REGISTER char	*q;
X
X    q = p + strlen(p);
X    if (q > &p[2] && *--q == '\n' && *--q == '\r') {
X	*q = '\n';
X	*++q = '\0';
X    }
X}
X
X
X/*
X**  Here's where the work gets done.  Skip headers and try to intuit
X**  if the file is, e.g., C code, etc.
X*/
Xstatic int
XFound(Name, buff, Forced, Stream, Header)
X    REGISTER char	*Name;
X    REGISTER char	*buff;
X    REGISTER int	Forced;
X    REGISTER FILE	*Stream;
X    REGISTER FILE	*Header;
X{
X    REGISTER char	*p;
X    REGISTER int	InHeader;
X    char		lower[BUFSIZ];
X
X    if (Header)
X	InHeader = TRUE;
X
X    for ( ; ; ) {
X	/* Read next line, fail if no more */
X	if (fgets(buff, BUFSIZ, Stream) == NULL) {
X	    Fprintf(stderr, "unshar:  No shell commands in %s.\n", Name);
X	    return FALSE;
X	}
X	if (KillReturns)
X	    Fixline(buff);
X
X	/* See if it looks like another language. */
X	if (!Forced) {
X	    if (PREFIX(buff, "#include") || PREFIX(buff, "# include")
X	     || PREFIX(buff, "#define") || PREFIX(buff, "# define")
X	     || PREFIX(buff, "#ifdef") || PREFIX(buff, "# ifdef")
X	     || PREFIX(buff, "#ifndef") || PREFIX(buff, "# ifndef")
X	     || (PREFIX(buff, "/*")
X	      && !PREFIX(buff, NOTES1) && !PREFIX(buff, NOTES2)))
X		p = "C code";
X	    else if (PREFIX(buff, "(*"))		/* For vi :-) */
X		p = "PASCAL code";
X	    else if (buff[0] == '.'
X		  && CTYPE(buff[1]) && isalpha(buff[1])
X		  && CTYPE(buff[2]) && isalpha(buff[2])
X		  && CTYPE(buff[3]) && !isalpha(buff[3]))
X		p = "TROFF source";
X	    else
X		p = NULL;
X	    if (p) {
X		Fprintf(stderr,
X			"unshar:  %s is apparently %s, not a shell archive.\n",
X			Name, p);
X		return FALSE;
X	    }
X	}
X
X	/* Does this line start with a shell command or comment? */
X	if ((buff[0] == '#' && !IsSHcomment(buff + 1))
X	 || buff[0] == ':' || PREFIX(buff, "echo ")
X	 || PREFIX(buff, "sed ") || PREFIX(buff, "cat ")) {
X	    return TRUE;
X	}
X
X	/* Does this line say "Cut here"? */
X	for (p = strcpy(lower, buff); *p; p++)
X	    if (CTYPE(*p) && islower(*p))
X		*p = toupper(*p);
X	if (PREFIX(buff, "-----") || Has(lower, "cut", "here")
X	 || Has(lower, "cut", "cut") || Has(lower, "tear", "here")) {
X	    /* Get next non-blank line. */
X	    do {
X		if (fgets(buff, BUFSIZ, Stream) == NULL) {
X		    Fprintf(stderr, "unshar:  cut line is last line of %s\n",
X			    Name);
X		    return FALSE;
X		}
X		if (KillReturns)
X		    Fixline(buff);
X	    } while (*buff == '\n');
X
X	    /* If it starts with a comment or lower-case letter we win. */
X	    if (*buff == '#' || *buff == ':'
X	     || (CTYPE(*buff) && islower(*buff)))
X		return TRUE;
X
X	    /* The cut message lied. */
X	    Fprintf(stderr, "unshar: %s is not a shell archive,\n", Name);
X	    Fprintf(stderr, "        the 'cut' line was followed by: %s", buff);
X	    return FALSE;
X	}
X
X	if (Header) {
X	    (void)fputs(buff, Header);
X	    if (InHeader && !IsHeader(buff))
X		InHeader = FALSE;
X	}
X    }
X}
X
X
X/*
X**  Create file for the header, find true start of the archive,
X**  and send it off to the shell.
X*/
Xstatic void
XUnshar(Name, HdrFile, Stream, Saveit, Forced)
X    char		*Name;
X    char		*HdrFile;
X    REGISTER FILE 	*Stream;
X    int			Saveit;
X    int			Forced;
X{
X    REGISTER FILE	*Header;
X#ifndef	USE_MY_SHELL
X    REGISTER FILE	*Pipe;
X#endif	/* USE_MY_SHELL */
X    char		*p;
X    char		buff[BUFSIZ];
X
X    if (Saveit) {
X	/* Create a name for the saved header. */
X	if (HdrFile)
X	    (void)strcpy(buff, HdrFile);
X	else if (Name) {
X	    p = RDX(Name, '/');
X#ifdef	BU_NAME_LEN
X	    (void)strncpy(buff, p ? p + 1 : Name, BU_NAME_LEN);
X	    buff[BU_NAME_LEN - 4] = '\0';
X#else
X	    (void)strcpy(buff, p ? p + 1 : Name);
X#endif	/* BU_NAME_LEN */
X	    (void)strcat(buff, ".hdr");
X	}
X	else
X	    (void)strcpy(buff, "UNSHAR.HDR");
X
X	/* Tell user, and open the file. */
X	Fprintf(stderr, "unshar:  Sending header to %s.\n", buff);
X	if ((Header = fopen(buff, "a")) == NULL)
X	    Quit("Can't open file for header");
X    }
X    else
X	Header = NULL;
X
X    /* If name is NULL, we're being piped into... */
X    p = Name ? Name : "the standard input";
X#ifdef	USE_MY_SHELL
X    Printf("unshar:  Doing %s (with builtin interpreter)\n", p);
X#else
X    Printf("unshar:  Doing %s (with /bin/sh)\n", p);
X#endif	/* USE_MY_SHELL */
X
X    if (Found(p, buff, Forced, Stream, Header)) {
X#ifdef	USE_MY_SHELL
X	BinSh(Name, Stream, buff, KillReturns);
X#else
X	if ((Pipe = popen("/bin/sh", "w")) == NULL)
X	    Quit("Can't open pipe to /bin/sh process");
X
X	(void)fputs(buff, Pipe);
X	while (fgets(buff, sizeof buff, Stream)) {
X	    if (KillReturns)
X		Fixline(buff);
X	    (void)fputs(buff, Pipe);
X	}
X
X	(void)pclose(Pipe);
X#endif	/* USE_MY_SHELL */
X    }
X
X    /* Close the headers. */
X    if (Saveit)
X	(void)fclose(Header);
X}
X
X
Xint
Xmain(ac, av)
X    REGISTER int	ac;
X    REGISTER char	*av[];
X{
X    REGISTER FILE	*Stream;
X    REGISTER int	i;
X    char		*p;
X    char		*Home;
X    char		*HdrFile;
X    char		cwd[BUFSIZ];
X    char		dir[BUFSIZ];
X    char		buff[BUFSIZ];
X    int			Saveit;
X    int			Forced;
X    int			Oops;
X
X    /* Parse JCL. */
X    p = getenv("UNSHARDIR");
X    Saveit = DEF_SAVEIT;
X#ifdef	UNIX
X    HdrFile = NULL;
X#else
X    HdrFile = "UNSHAR.HDR";
X#endif	/* UNIX */
X    Forced = FALSE;
X    for (Oops = FALSE; (i = getopt(ac, av, "vc:d:fh:nrs")) != EOF; )
X	switch (i) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X	case 'c': 		/* Change to directory first		*/
X	case 'd': 		/* Change to directory first		*/
X	    p = optarg;
X	    break;
X	case 'f':		/* "Force" input to be a shar		*/
X	    Forced = TRUE;
X	    break;
X	case 'h':		/* Save shar header to named file	*/
X	    HdrFile = optarg;
X	    /* FALLTHROUGH */
X	case 's': 		/* Save shar header			*/
X	    Saveit = TRUE;
X	    break;
X	case 'n':		/* Don't save shar header		*/
X	    Saveit = FALSE;
X	    break;
X	case 'r':		/* Kill trailing \r characters		*/
X	    KillReturns = TRUE;
X	    break;
X	}
X    ac -= optind;
X    av += optind;
X
X    if (Oops) {
X	Fprintf(stderr, "Usage:\n  unshar %s [files...]\n",
X		"[-f] [-s] [-n] [-c dir] [-d dir] [-h file]");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Going somewhere? */
X    if (p) {
X	if (*p == '?') {
X	    /* Ask for name. */
X	    Stream = isatty(fileno(stdin))
X		    ? stdin : fopen(ctermid((char *)NULL), "r");
X	    if (Stream == NULL)
X		Quit("Can't open tty to ask for directory");
X	    Printf("unshar:  what directory?  ");
X	    (void)fflush(stdout);
X	    if (fgets(buff, sizeof buff, Stream) == NULL
X	     || buff[0] == '\n'
X	     || (p = IDX(buff, '\n')) == NULL)
X		Quit("Okay, cancelled");
X	    *p = '\0';
X	    p = buff;
X	    if (Stream != stdin)
X		(void)fclose(Stream);
X	}
X
X	/* If name is ~/blah, he means $HOME/blah. */
X	if (*p == '~') {
X#ifdef	VMS
X	    Sprintf(dir, "sys$login:[%s]", p + 1);
X#else
X	    Home = getenv("HOME");
X	    if (Home == NULL) {
X		Home = "/tmp";
X		Fprintf(stderr, "Unshar warning, no $HOME; using \"%s\".\n",
X			Home);
X	    }
X	    Sprintf(dir, "%s/%s", Home, p + 1);
X#endif	/* VMS */
X	    p = dir;
X	}
X
X	/* If we're gonna move, first remember where we were. */
X	if (GetDir(cwd, sizeof cwd) == NULL) {
X	    Fprintf(stderr, "Unshar warning, Can't get current directory.\n");
X	    cwd[0] = '\0';
X	}
X
X	/* Got directory; try to go there.  Only make last component. */
X	if (chdir(p) < 0 && (mkdir(p, 0777) < 0 || chdir(p) < 0))
X	    Quit("Cannot chdir nor mkdir desired directory");
X    }
X    else
X	cwd[0] = '\0';
X
X    /* No buffering. */
X    (void)setbuf(stdout, (char *)NULL);
X    (void)setbuf(stderr, (char *)NULL);
X
X    if (*av)
X	/* Process filenames from command line. */
X	for (; *av; av++) {
X	    if (cwd[0] && av[0][0] != '/') {
X		Sprintf(buff, "%s/%s", cwd, *av);
X		*av = buff;
X	    }
X	    if ((Stream = fopen(*av, "r")) == NULL)
X		Fprintf(stderr, "unshar:  Can't open file '%s'.\n", *av);
X	    else {
X		Unshar(*av, HdrFile, Stream, Saveit, Forced);
X		(void)fclose(Stream);
X	    }
X	}
X    else
X	/* Do standard input. */
X	Unshar((char *)NULL, HdrFile, stdin, Saveit, Forced);
X
X    /* That's all she wrote. */
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 9811 -ne `wc -c <'unshar.c'`; then
    echo shar: \"'unshar.c'\" unpacked with wrong size!
  fi
  # end of 'unshar.c'
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0

