From uunet!rsalz Tue May 19 14:14:28 1992
Received: from uunet.UUCP by sparky.IMD.Sterling.COM (5.65c/IDA-1.4.4)
	id AA03492; Tue, 19 May 1992 14:14:23 -0500
Return-Path: <uunet!rsalz>
Received: by rodan.UU.NET (5.61/UUNET-mail-drop)
	id AA17558; Tue, 19 May 92 14:35:04 -0400
Date: Tue, 19 May 92 14:35:04 -0400
From: uunet!rsalz (Rich Salz)
Message-Id: <9205191835.AA17558@rodan.UU.NET>
To: kent@imd.sterling.com
Subject: cshar/Part04
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:  dirvms.c lexec.c llib.c makekit.man manipull.c
#   maniscan.man shar.h shar.man uudecode.c wildmat.c
# Wrapped by rsalz@rodan on Tue Apr  7 23:54:47 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 4 (of 6)."'
if test -f 'dirvms.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dirvms.c'\"
else
  echo shar: Extracting \"'dirvms.c'\" \(5854 characters\)
  sed "s/^X//" >'dirvms.c' <<'END_OF_FILE'
X/*
X**  VMS readdir() routines.
X**  Written by Rich $alz, <rsalz@bbn.com> in August, 1990.
X**  Thanks to Pat Rankin, <rankin@eql.caltech.edu> for feedback.
X**  This code has no copyright.
X**
X**  Should do better checking on lib$XXX routines and do something like
X**  	"errno = EVMSERR, vaxc$errno = status"
X**  when the unexpected happens.
X*/
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X#include <descrip.h>
X#include <rmsdef.h>
X#include "dirent.h"
X
X    /* Uncomment the next line to get a test routine. */
X/*#define TEST*/
X
X    /* Number of elements in vms_versions array */
X#define VERSIZE(e)	(sizeof e->vms_versions / sizeof e->vms_versions[0])
X
X    /* Linked in later. */
Xextern char	*malloc();
Xextern char	*strrchr();
Xextern char	*strcpy();
X
X
X/*
X**  Open a directory, return a handle for later use.
X*/
XDIR *
Xopendir(name)
X    char	*name;
X{
X    DIR		*dd;
X
X    /* Get memory for the handle, and the pattern. */
X    if ((dd = (DIR *)malloc(sizeof *dd)) == NULL) {
X	errno = ENOMEM;
X	return NULL;
X    }
X    dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1));
X    if (dd->pattern == NULL) {
X	free((char *)dd);
X	errno = ENOMEM;
X	return NULL;
X    }
X
X    /* Fill in the fields; mainly playing with the descriptor. */
X    (void)sprintf(dd->pattern, "%s*.*", name);
X    dd->context = 0;
X    dd->count = 0;
X    dd->vms_wantversions = 0;
X    dd->pat.dsc$a_pointer = dd->pattern;
X    dd->pat.dsc$w_length = strlen(dd->pattern);
X    dd->pat.dsc$b_dtype = DSC$K_DTYPE_T;
X    dd->pat.dsc$b_class = DSC$K_CLASS_S;
X
X    return dd;
X}
X
X
X/*
X**  Set the flag to indicate we want versions or not.
X*/
Xvoid
Xvmsreaddirversions(dd, flag)
X    DIR		*dd;
X    int		flag;
X{
X    dd->vms_wantversions = flag;
X}
X
X
X/*
X**  Free up an opened directory.
X*/
Xvoid
Xclosedir(dd)
X    DIR		*dd;
X{
X    /* Since closedir() is void, checking errors makes no sense. */
X    (void)lib$find_file_end(&dd->context);
X    free(dd->pattern);
X    free((char *)dd);
X}
X
X
X/*
X**  Collect all the version numbers for the current file.
X*/
Xstatic void
Xcollectversions(dd)
X    DIR				*dd;
X{
X    struct dsc$descriptor_s	pat;
X    struct dsc$descriptor_s	res;
X    struct dirent		*e;
X    char			*p;
X    char			buff[sizeof dd->entry.d_name];
X    int				i;
X    char			*text;
X    long			context;
X
X    /* Convenient shorthand. */
X    e = &dd->entry;
X
X    /* Add the version wildcard, ignoring the "*.*" put on before */
X    i = strlen(dd->pattern);
X    text = malloc((unsigned int)(i + strlen(e->d_name)+ 2 + 1));
X    if (text == NULL)
X	return;
X    (void)strcpy(text, dd->pattern);
X    (void)sprintf(&text[i - 3], "%s;*", e->d_name);
X
X    /* Set up the pattern descriptor. */
X    pat.dsc$a_pointer = text;
X    pat.dsc$w_length = strlen(text);
X    pat.dsc$b_dtype = DSC$K_DTYPE_T;
X    pat.dsc$b_class = DSC$K_CLASS_S;
X
X    /* Set up result descriptor. */
X    res.dsc$a_pointer = buff;
X    res.dsc$w_length = sizeof buff - 2;
X    res.dsc$b_dtype = DSC$K_DTYPE_T;
X    res.dsc$b_class = DSC$K_CLASS_S;
X
X    /* Read files, collecting versions. */
X    for (context = 0; e->vms_verscount < VERSIZE(e); e->vms_verscount++) {
X	if (lib$find_file(&pat, &res, &context) == RMS$_NMF || context == 0)
X	    break;
X	buff[sizeof buff - 1] = '\0';
X	if (p = strchr(buff, ';'))
X	    e->vms_versions[e->vms_verscount] = atoi(p + 1);
X	else
X	    e->vms_versions[e->vms_verscount] = -1;
X    }
X
X    (void)lib$find_file_end(&context);
X    free(text);
X}
X
X
X/*
X**  Read the next entry from the directory.
X*/
Xstruct dirent *
Xreaddir(dd)
X    DIR				*dd;
X{
X    struct dsc$descriptor_s	res;
X    char			*p;
X    char			buff[sizeof dd->entry.d_name];
X    int				i;
X
X    /* Set up result descriptor, and get next file. */
X    res.dsc$a_pointer = buff;
X    res.dsc$w_length = sizeof buff - 2;
X    res.dsc$b_dtype = DSC$K_DTYPE_T;
X    res.dsc$b_class = DSC$K_CLASS_S;
X    dd->count++;
X    if (lib$find_file(&dd->pat, &res, &dd->context) == RMS$_NMF
X     || dd->context == 0L)
X	/* None left... */
X	return NULL;
X
X    /* Force the buffer to end with a NUL. */
X    buff[sizeof buff - 1] = '\0';
X    for (p = buff; !isspace(*p); p++)
X	;
X    *p = '\0';
X
X    /* Skip any directory component and just copy the name. */
X    if (p = strchr(buff, ']'))
X	(void)strcpy(dd->entry.d_name, p + 1);
X    else
X	(void)strcpy(dd->entry.d_name, buff);
X
X    /* Clobber the version. */
X    if (p = strchr(dd->entry.d_name, ';'))
X	*p = '\0';
X
X    dd->entry.vms_verscount = 0;
X    if (dd->vms_wantversions)
X	collectversions(dd);
X    return &dd->entry;
X}
X
X
X/*
X**  Return something that can be used in a seekdir later.
X*/
Xlong
Xtelldir(dd)
X    DIR		*dd;
X{
X    return dd->count;
X}
X
X
X/*
X**  Return to a spot where we used to be.  Brute force.
X*/
Xvoid
Xseekdir(dd, count)
X    DIR		*dd;
X    long	count;
X{
X    int		vms_wantversions;
X
X    /* If we haven't done anything yet... */
X    if (dd->count == 0)
X	return;
X
X    /* Remember some state, and clear it. */
X    vms_wantversions = dd->vms_wantversions;
X    dd->vms_wantversions = 0;
X    (void)lib$find_file_end(&dd->context);
X    dd->context = 0;
X
X    /* The increment is in readdir(). */
X    for (dd->count = 0; dd->count < count; )
X	(void)readdir(dd);
X
X    dd->vms_wantversions = vms_wantversions;
X}
X
X
X#ifdef	TEST
Xmain()
X{
X    char		buff[256];
X    DIR			*dd;
X    struct dirent	*dp;
X    int			i;
X    int			j;
X
X    for ( ; ; ) {
X	printf("\n\nEnter dir:  ");
X	(void)fflush(stdout);
X	(void)gets(buff);
X	if (buff[0] == '\0')
X	    break;
X	if ((dd = opendir(buff)) == NULL) {
X	    perror(buff);
X	    continue;
X	}
X
X	/* Print the directory contents twice, the second time print
X	 * the versions. */
X	for (i = 0; i < 2; i++) {
X	    while (dp = readdir(dd)) {
X		printf("%s%s", i ? "\t" : "    ", dp->d_name);
X		for (j = 0; j < dp->vms_verscount; j++)
X		    printf("  %d", dp->vms_versions[j]);
X		printf("\n");
X	    }
X	    rewinddir(dd);
X	    vmsreaddirversions(dd, 1);
X	}
X	closedir(dd);
X    }
X    exit(0);
X}
X#endif	/* TEST */
END_OF_FILE
  if test 5854 -ne `wc -c <'dirvms.c'`; then
    echo shar: \"'dirvms.c'\" unpacked with wrong size!
  fi
  # end of 'dirvms.c'
fi
if test -f 'lexec.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lexec.c'\"
else
  echo shar: Extracting \"'lexec.c'\" \(2651 characters\)
  sed "s/^X//" >'lexec.c' <<'END_OF_FILE'
X/*
X**  Process stuff, like fork exec and wait.  Also signals.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#include <signal.h>
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: lexec.c,v 2.0 88/05/27 13:26:35 rsalz Exp $";
X#endif	/* RCSID */
X
X
X/* How to fork(), what to wait with. */
X#ifdef	SYS_WAIT
X
X#include <sys/wait.h>
X#define FORK()		 vfork()
X#define W_VAL(w)	 ((w).w_retcode)
Xtypedef union wait	 WAITER;
X
X#else
X
X#ifdef	HAS_VFORK
X#define FORK()		 vfork()
X#else
X#define FORK()		 fork()
X#endif	/* HAS_VFORK */
X
X#define W_VAL(w)	 ((w) >> 8)
Xtypedef int		 WAITER;
X
X#endif	/* SYS_WAIT */
X
X
X
X/*
X**  Set up a signal handler.
X*/
Xvoid
XSetSigs(Func)
X    sigret_t	(*Func)();
X{
X    if (Func == NULL)
X	Func = SIG_DFL;
X#ifdef	SIGINT
X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X	(void)signal(SIGINT, Func);
X#endif	/* SIGINT */
X#ifdef	SIGQUIT
X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X	(void)signal(SIGQUIT, Func);
X#endif	/* SIGQUIT */
X#ifdef	SIGTERM
X    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X	(void)signal(SIGTERM, Func);
X#endif	/* SIGTERM */
X}
X
X
X/*
X**  Return the process ID.
X*/
Xint
XPid()
X{
X#ifdef	UNIX
X    static int	 X;
X
X    if (X == 0)
X	X = getpid();
X    return X;
X#endif	/* UNIX */
X#ifdef	MSDOS
X    return 1;
X#endif	/* MSDOS */
X#ifdef	VMS
X    return 1;
X#endif	/* VMS */
X}
X
X
X#ifndef	USE_SYSTEM
X/*
X**  Fork off a command.
X*/
Xint
XExecute(av)
X    char		*av[];
X{
X    REGISTER int	i;
X    REGISTER int	j;
X    WAITER		W;
X
X    if ((i = FORK()) == 0) {
X	SetSigs((sigret_t (*)())NULL);
X	(void)execvp(av[0], av);
X	perror(av[0]);
X	_exit(1);
X	/* NOTREACHED */
X    }
X
X    /* We used to ignore signals around this wait, but that caused
X     * surprising behaviour when someone tried to kill makekit, e.g. */
X    while ((j = wait(&W)) < 0 && j != i)
X	continue;
X    return W_VAL(W);
X}
X
X#else
X
X/*
X**  Protect text from wildcard expansion, etc.
X*/
Xstatic char *
XProtect(p)
X    REGISTER char	*p;
X{
X    char		*save;
X
X    for (save = p; *p; p++)
X	if (CTYPE(*p) && !isalpha(*p))
X	    *p = '_';
X    return save;
X}
X
X
X/*
X**  Cons all the arguments together into a single command line and hand
X**  it off to the shell to execute.  Gotta quote each argument after
X**  the first one.
X*/
Xint
XExecute(av)
X    REGISTER char	*av[];
X{
X    REGISTER char	**v;
X    REGISTER char	*p;
X    REGISTER char	*q;
X    REGISTER int	i;
X
X    /* Get length of command line. */
X    for (i = 2, v = av; *v; v++)
X	i += strlen(*v) + 3;
X
X    /* Create command line and execute it. */
X    p = NEW(char, i);
X    q = p + strlen(strcpy(p, *v));
X    for (v = &av[1]; *v; v++) {
X	*q++ = ' ';
X	q += strlen(strcpy(q, Protect(*v)));
X    }
X    *q = '\0';
X
X    i = system(p);
X    free(p);
X    return i;
X}
X#endif	/* USE_SYSTEM */
END_OF_FILE
  if test 2651 -ne `wc -c <'lexec.c'`; then
    echo shar: \"'lexec.c'\" unpacked with wrong size!
  fi
  # end of 'lexec.c'
fi
if test -f 'llib.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'llib.c'\"
else
  echo shar: Extracting \"'llib.c'\" \(4909 characters\)
  sed "s/^X//" >'llib.c' <<'END_OF_FILE'
X/*
X**  Some systems will need these routines because they're missing from
X**  their C library.  This is also a catch-all for miscellaneous routines.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	RCSID
Xstatic char RCS[] =
X	"$Header: llib.c,v 2.1 88/06/06 22:05:14 rsalz Locked $";
X#endif	/* RCSID */
X
X
X/*
X**  Return the printable representation of a character.  Assumes ASCII,
X**  but that's ok, it's all we use for portability.
X*/
Xchar *
XSeechar(c)
X    register int	c;
X{
X    static char		buff1[20];
X    static char		buff2[20];
X    register char	*p;
X    int			meta;
X
X    meta = c & 0200;
X    c &= 0177;
X    if (c >= 001 && c <= 032) {
X	Sprintf(buff1, "CTRL-%c", c - 1 + 'A');
X	p = buff1;
X    }
X    else if (c >= 040 && c <= 0176) {
X	buff1[0] = c;
X	buff1[1] = '\0';
X	p = buff1;
X    }
X    else
X	switch (c) {
X	default:	p = "<BAD>";	break;
X	case 000:	p = "NUL";	break;
X	case 033:	p = "ESCAPE";	break;
X	case 034:	p = "CTRL-\\";	break;
X	case 035:	p = "CTRL-]";	break;
X	case 036:	p = "CTRL-^";	break;
X	case 037:	p = "CTRL-_";	break;
X	case 0177:	p = "DELETE";	break;
X	}
X    if (!meta)
X	return p;
X    Sprintf(buff2, "META-%s", p);
X    return buff2;
X}
X
X
X/*
X**  Return the text string that corresponds to errno.
X*/
X#ifdef	NEED_STRERROR
Xchar *
Xstrerror(e)
X    int			e;
X{
X    static char		buff[30];
X
X#ifdef	USE_SYSERRLIST
X    if (e > 0 && e < sys_nerr)
X	return sys_errlist[e];
X#endif	/* USE_SYSERRLIST */
X    Sprintf(buff, "Error code %d", e);
X    return buff;
X}
X#endif	/* NEED_STRERROR */
X
X
X#ifdef	NEED_CTERMID
X/*
X**  Return a pointer to a device that can be fopen'd to query the user,
X**  regardless of whether or not stdin is redirected.
X*/
Xchar *
Xctermid(p)
X    char	*p;
X{
X    static char	buff[L_ctermid];
X
X    return strcpy(p ? p : buff, THE_TTY);
X}
X#endif	/* NEED_CTERMID */
X
X
X#ifdef	NEED_MKDIR
X/*
X**  Quick and dirty mkdir routine for systems without one.
X*/
Xint
Xmkdir(name, mode)
X    char	*name;
X    int		mode;
X{
X    char	*av[3];
X    int		i;
X    int		U;
X
X    av[0] = "mkdir";
X    av[1] = name;
X    av[2] = NULL;
X    U = umask(~mode);
X    i = Execute(av);
X    (void)umask(U);
X    return i ? -1 : 0;
X}
X#endif	/* NEED_MKDIR */
X
X
X#ifdef	UNOS_MAKEDIR
X/*
X**  UNOS has makedir(), but not mkdir...
X*/
X#include <sys/stat.h>
X#include <errno.h>
X
X
Xint
Xmkdir(path, mode)
X    char	*path;
X    int		mode;
X{
X    struct stat	Sb;
X
X    /* See if it exists, or fails for other than non-existance. */
X    if (stat(path, &Sb) == 0) {
X	errno = EEXIST;
X	return -1;
X    }
X    if (errno != ENOENT)
X	return -1; 
X
X    /* UNOS makedir doesn't set the mode, so we have to do it. */
X    return makedir(path) == -1 ? -1 : chmod(path, mode);
X}
X#endif	/* UNOS_MAKEDIR */
X
X
X#ifdef	NEED_QSORT
X/*
X**  Bubble sort an array of arbitrarily-sized elements.  This routine
X**  can be used as an (inefficient) replacement for the Unix qsort
X**  routine.
X*/
Xqsort(Table, Number, Width, Compare)
X    REGISTER char	*Table;
X    REGISTER int	Number;
X    REGISTER int	Width;
X    REGISTER int	(*Compare)();
X{
X    REGISTER char	*i;
X    REGISTER char	*j;
X
X    for (i = &Table[Number * Width]; (i -= Width) >= &Table[Width]; )
X	for (j = i; (j -= Width) >= &Table[0]; )
X	    if ((*Compare)(i, j) < 0) {
X		REGISTER char	*p;
X		REGISTER char	*q;
X		REGISTER int	 t;
X		REGISTER int	 w;
X
X		/* Swap elements pointed to by i and j. */
X		for (w = Width, p = i, q = j; --w >= 0; *p++ = *q, *q++ = t)
X		    t = *p;
X	    }
X}
X#endif	/* NEED_QSORT */
X
X
X#ifdef	NEED_GETOPT
X
X#define TYPE	int
X
X#define ERR(s, c)					\
X    if (opterr) {					\
X	char buff[2];					\
X	buff[0] = c; buff[1] = '\n';			\
X	(void)write(2, av[0], (TYPE)strlen(av[0]));	\
X	(void)write(2, s, (TYPE)strlen(s));		\
X	(void)write(2, buff, 2);			\
X    }
X
Xint	 opterr = 1;
Xint	 optind = 1;
Xint	 optopt;
Xchar	*optarg;
X
X/*
X**  Return options and their values from the command line.
X**  This comes from the AT&T public-domain getopt published in mod.sources
X**  (i.e., comp.sources.unix before the great Usenet renaming).
X*/
Xint
Xgetopt(ac, av, opts)
X    int			ac;
X    char		*av[];
X    char		*opts;
X{
X    static int		i = 1;
X    REGISTER char	*p;
X
X    /* Move to next value from argv? */
X    if (i == 1) {
X	if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0')
X	    return EOF;
X	if (strcmp(av[optind], "--") == 0) {
X	    optind++;
X	    return EOF;
X	}
X    }
X
X    /* Get next option character. */
X    if ((optopt = av[optind][i]) == ':' || (p = IDX(opts,  optopt)) == NULL) {
X	ERR(": illegal option -- ", optopt);
X	if (av[optind][++i] == '\0') {
X	    optind++;
X	    i = 1;
X	}
X	return '?';
X    }
X
X    /* Snarf argument? */
X    if (*++p == ':') {
X	if (av[optind][i + 1] != '\0')
X	    optarg = &av[optind++][i + 1];
X	else {
X	    if (++optind >= ac) {
X		ERR(": option requires an argument -- ", optopt);
X		i = 1;
X		return '?';
X	    }
X	    optarg = av[optind++];
X	}
X	i = 1;
X    }
X    else {
X	if (av[optind][++i] == '\0') {
X	    i = 1;
X	    optind++;
X	}
X	optarg = NULL;
X    }
X
X    return optopt;
X}
X#endif	/* NEED_GETOPT */
END_OF_FILE
  if test 4909 -ne `wc -c <'llib.c'`; then
    echo shar: \"'llib.c'\" unpacked with wrong size!
  fi
  # end of 'llib.c'
fi
if test -f 'makekit.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makekit.man'\"
else
  echo shar: Extracting \"'makekit.man'\" \(5016 characters\)
  sed "s/^X//" >'makekit.man' <<'END_OF_FILE'
X.TH MAKEKIT 1L
X.\" $Header: makekit.man,v 2.2 88/06/06 22:05:01 rsalz Exp $
X.SH NAME
Xmakekit \- split files up into shell archive packages
X.SH SYNOPSIS
X.RS
X.na
X.ti -.5i
X.B makekit
X[
X.B \-1
X] [
X.B \-b
X] [
X.B \-e
X] [
X.B \-x
X] [
X.BI \-h\| #
X] [
X.BI \-i\| name
X] [
X.BI \-k\| #
X] [
X.B \-m
X] [
X.BI \-n\| name
X] [
X.BI \-o\| name
X] [
X.B \-p
X] [
X.BI \-s\| #[k]
X] [
X.BI \-t\| text
X] [
X.B \-v
X] [ file... ]
X.ad
X.RE
X.SH DESCRIPTION
X.I Makekit
Xreads a list of files and directories, determines their sizes,
Xand parcels them up into a series of shell archives such that all the
Xarchives are of reasonable size.
XIt then invokes
X.IR shar (1L)
Xto actually create the archives.
X.PP
XBy default, no archive will be larger than 55,000 bytes; this may be
Xchanged by using the ``\-s'' option.
XIf the number given with the ``\-s'' option ends with the letter ``k''
Xthen the size is multiplied by 1024, otherwise it is taken to be the
Xdesired maximum size, in bytes.
XEach archive will have a name that looks like
X.IR Part nn,
Xwhere ``nn'' represents the two-digit sequence number (with leading zero
Xif needed).
XThe leading part of the archive name may be changed with the ``\-n'' option.
XThis option is also useful when write permission to the directory being
Xarchived is denied; e.g., ``\-n/tmp/KERNEL.''
X.PP
X.I Makekit
Xreads its list of files on the command line, or from the standard input
Xif none are given.
XIt is also possible to specify an input filename with the ``\-i'' option.
XIt is not possible to specify files on the command line and read an
Xinput file.
XThe input should contain a list of files, one to a line.
XIn addition, if each input line looks like this:
X.RS
Xfilename\ \ \ spaces\ \ \ optional-digits\ \ \ spaces\ \ \ text
X.RE
Xthen
X.I makekit
Xwill ignore the spaces and digits, but remember the text associated with
Xeach file, and output it with the filename when generating the ``shipping
Xmanifest.''
XFurther, the ``\-h'' option may be given to have the program skip the
Xindicated number of lines in the input; this option is provided so that
X.I makekit
Xcan more easily re-parse the manifests it generates, as well as those
Xgenerated by
X.IR findsrc (1L)
Xor
X.IR maniscan (1L) .
X.PP
XThe generated manifest will be sent to the standard output.
XAn alternate output file may be given by using the ``\-o'' option; if
Xthe output file exists,
X.I makekit
Xwill try to rename it with an extension of
X.IR \&.BAK \&.
XIf the ``\-o'' option is used,
X.I makekit
Xwill add that name to the list of files to be archived; the ``\-e''
Xoption may be given to exclude the manifest from the list.
X.PP
XThe ``\-m'' option is the same as giving the options
X\&``-iMANIFEST -oMANIFEST -h2.''
XThis is a common way to regenerate a set of archives after the first
Xuse of
X.I makekit
Xin a directory.
X.PP
XTo recreate the archives from an existing manifest, use the ``\-b''
Xflag; this instructs
X.I makekit
Xto believe the part assignments in the manifest.
XSome extra work will be done to rewrite the manifest, but the assignment
Xof files into their kits will be as specified.
XThis option is also useful in tweaking a distribution to get a tighter fit.
X.PP
XIf a large number of kits has to be generated, you may need to give
Xthe ``\-k'' option to increase the maximum number of kits to be
Xgenerated.
XThe existence of this option can be taken as evidence that the program's
Xauthor is lazy.
X.PP
XAfter partitioning the files and directories,
X.I makekit
Xcalls
X.I shar
Xwith the proper options to generate archives in a series.
XEach resultant archive will, when executed, check to see if all the parts
Xare present.
XIf the ``\-1'' option is used, then
X.I makekit
Xwill not instruct
X.I shar
Xto generate the checks (by not passing on the ``\-n'' and ``\-e'' options).
XBy using the ``\-t'' option, you can specify a line of starting instructions
Xto display to the recipient when all pieces have been unpacked.
XThis is useful when resending part of a series that has probably already
Xbeen unpacked by the recipient.
XSee
X.I shar
Xfor more information on multi-part archives.
XIf the ``\-x'' option is used,
X.I shar
Xis not called, but the manifest is still created.
X.PP
X.I Makekit
Xnormally reorders its input so that the archives are as ``dense'' as
Xpossible, with the exception that directories are given priority over
Xfiles, and the files named
X.IR PACKNOTES ,
X.IR README ,
Xand then
X.I MANIFEST
Xappear first.
XThe manifest is also sorted in alphabetical order; this makes it easy
Xto locate ``missing'' files when the distribution is a large one.
XThe ``\-p'' option may be used to override both sortings, however,
Xand preserve the original order of the input list in generating
Xboth the manifest and the shell archives.
X(To preserve the actual assignments in the manifest, use the ``\-b''
Xoption.)
XIt also tries to partition the files so that all directories are in the
Xfirst archive.
XThis usually means the first archive must be the first one to be unpacked.
X.PP
XThe ``\-v'' option prints out the current version and exits.
X.SH "SEE ALSO"
Xfindsrc(1L), maniscan(1L), shar(1L).
END_OF_FILE
  if test 5016 -ne `wc -c <'makekit.man'`; then
    echo shar: \"'makekit.man'\" unpacked with wrong size!
  fi
  # end of 'makekit.man'
fi
if test -f 'manipull.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'manipull.c'\"
else
  echo shar: Extracting \"'manipull.c'\" \(4436 characters\)
  sed "s/^X//" >'manipull.c' <<'END_OF_FILE'
X/*
X**  MANIPULL
X**
X**  Extract entries out of an existing manifest.
X**  This is Phil Budne's code which I have usurped and heavily modified.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header$";
X
X
X/*
X**  Our block of information about the files we're doing.
X*/
Xtypedef struct _entry {
X    char	*Name;			/* Filename			*/
X    char	*Text;			/* What it is			*/
X    int		Wanted;			/* Does the user want this one?	*/
X} ENTRY;
X
X
X#define DEF_FILECOUNT	500		/* Seems like plenty		*/
X
X
Xint
Xmain(ac, av)
X    int			ac;
X    register char	*av[];
X{
X    REGISTER ENTRY	*E;
X    REGISTER char	*p;
X    REGISTER int	i;
X    REGISTER int	Count;
X    REGISTER int	Silent;
X    REGISTER int	Header;
X    ENTRY		*Entries;
X    int			FileCount;
X    int			Oops;
X    char		line[BUFSIZ];
X    char		*Infile;
X    char		*Outfile;
X
X    /* Parse JCL. */
X    Header = 0;
X    Silent = FALSE;
X    Infile = NULL;
X    Outfile = NULL;
X    FileCount = DEF_FILECOUNT;
X    for (Oops = FALSE; (i = getopt(ac, av, "vfh:i:mo:s")) != EOF; )
X	switch (i) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X	case 'f':		/* Maximum number of files to pull	*/
X	    FileCount = 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	    Infile = optarg;
X	    break;
X	case 'm':		/* Convenient option shorthand		*/
X	    Header = 2;
X	    Infile = "MANIFEST";
X	    Outfile = "MANIFEST.NEW";
X	    break;
X	case 'o':		/* Name of output manifest		*/
X	    Outfile = optarg;
X	    break;
X	case 's':		/* Don't list what we're doing		*/
X	    Silent = TRUE;
X	    break;
X	}
X    ac -= optind;
X    av += optind;
X
X    if (ac == 0 || Oops) {
X	Fprintf(stderr, "Usage:\n  manipull %s files...\n", 
X		"[-m | -h2 -i MANIFEST -o MANIFEST.NEW] -f# -s");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Open input and output streams as necessary. */
X    if (Infile && freopen(Infile, "r", stdin) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" for input, %s.\n",
X		Infile, strerror(errno));
X	exit(1);
X	/* NOTREACHED */
X    }
X    if (Outfile && freopen(Outfile, "w", stdout) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" for output, %s.\n",
X		Outfile, strerror(errno));
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Read and store the manifest. */
X    Entries = NEW(ENTRY, FileCount);
X    for (E = Entries, Count = 0; fgets(line, sizeof line, stdin); ) {
X	if (Header > 0) {
X	    Header--;
X	    continue;
X	}
X	if ((p = IDX(line, '\n')) == NULL)
X	    Fprintf(stderr, "Line truncated!\n");
X	else
X	    *p = '\0';
X
X	/* Skip leading whitespace; check for totally blank line. */
X	for (p = line; *p && CTYPE(*p) && isspace(*p); )
X	    p++;
X	if (*p == '\0')
X	    continue;
X
X	/* Got enough room? */
X	if (++Count == FileCount - 1) {
X	    Fprintf(stderr, "Need more than %d files; use -f flag.\n",
X		    FileCount);
X	    exit(1);
X	    /* NOTREACHED */
X	}
X
X	/* Copy the name, skip whitespace after it. */
X	E->Name = COPY(line);
X	for (p = E->Name; *p && CTYPE(*p) && !isspace(*p); )
X	    p++;
X	for (*p++ = '\0'; *p && CTYPE(*p) && isspace(*p); )
X	    p++;
X
X	/* Skip past the archive number. */
X	while (*p && CTYPE(*p) && isdigit(*p))
X	    p++;
X
X	/* Skip whitespace. */
X	while (*p && CTYPE(*p) && isspace(*p))
X	    p++;
X
X	/* Save description. */
X	E->Text = p;
X	E->Wanted = FALSE;
X	E++;
X    }
X
X    /* Rest of command line is files to pull out of the manifest. */
X    for (; *av; av++) {
X	/* Awful linear search. */
X	for (E = Entries, i = 0; i < Count; E++, i++)
X	    if (EQ(E->Name, *av)) {
X		E->Wanted = TRUE;
X		break;
X	    }
X	if (i == Count) {
X	    /* Not in MANIFEST; add it by hand. */
X	    if (!Silent)
X		Fprintf(stderr, "ADDING %s\n", *av);
X
X	    /* Got enough room? */
X	    if (++Count == FileCount - 1) {
X		Fprintf(stderr, "Need more than %d files; use -f flag.\n",
X			FileCount);
X		exit(1);
X		/* NOTREACHED */
X	    }
X	    E->Name = COPY(*av);
X	    E->Text = "";
X	    E->Wanted = TRUE;
X	}
X    }
X
X    /* Write header, then the entries. */
X    Printf("FEED THIS BACK INTO MAKEKIT FOR REAL PACKING...\n");
X    Printf("   File Name		Archive #	Description\n");
X    for (E = Entries, i = 0; i < Count; E++, i++)
X	if (E->Wanted) {
X	    if (E->Text[0])
X		Printf(" %s\t%d\t%s\n", E->Name, 0, E->Text);
X	    else
X		Printf(" %s\t%d\n", E->Name, 0);
X	}
X	else if (!Silent)
X	    Fprintf(stderr, "SKIPPING %s\n", E->Name);
X
X    /* That's all she wrote. */
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 4436 -ne `wc -c <'manipull.c'`; then
    echo shar: \"'manipull.c'\" unpacked with wrong size!
  fi
  # end of 'manipull.c'
fi
if test -f 'maniscan.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'maniscan.man'\"
else
  echo shar: Extracting \"'maniscan.man'\" \(5700 characters\)
  sed "s/^X//" >'maniscan.man' <<'END_OF_FILE'
X.TH MANISCAN 1L
X.\" $Header$
X.SH NAME
Xmaniscan \- scan a manifest for large or binary files
X.SH SYNOPSIS
X.RS
X.na
X.ti -.5i
X.B maniscan
X[
X.B \-e
X] [
X.BI \-f\| #
X] [
X.BI \-h\| #
X] [
X.BI \-i\| name
X] [
X.BI \-l\| name
X] [
X.BI \-w\| #
X] [
X.B \-m
X] [
X.BI \-o\| name
X] [
X.BI \-s\| #[k]
X] [
X.BI \-t\| text
X] [
X.BI \-c\| command
X] [
X.B \-v
X]
X.ad
X.RE
X.SH DESCRIPTION
X.I Maniscan
Xreads an existing ``manifest'' (usually created by
X.IR findsrc (1L)
Xand maintained by
X.IR makekit (1L))
Xand scans it for binary files, large files, and files with long
Xlines or that contain non-printing characters.
XLarge files are automatically split and binary files are run through
X.IR uuencode (1).
XAll problems can be recorded in a log file that should be shipped with
Xthe other sources being prepared.
X.PP
XA manifest consist of some header lines, followed by a series of lines
Xthat describe the files contained in the shell archives.
XEach line looks like this;
X.RS
Xfilename\ \ \ spaces\ \ \ optional-digits\ \ \ spaces\ \ \ text
X.RE
XFor more information on the interpretation of the file, see the
X.I makekit
Xdocumentation.
X.PP
XThe original manifest is read from the standard input.
XAn alternate input file may be given by using the ``\-i'' option.
XThe generated manifest will be sent to the standard output.
XAn alternate output file may be given by using the ``\-o'' option; if
Xthe output file exists,
X.I maniscan
Xwill try to rename it with an extension of
X.IR \&.BAK \&.
X.PP
XAs it scans the manifest,
X.I maniscan
Xcan generate a log of the problems it has found so that the recipient
Xwill know to run
X.IR uudecode (1),
Xuse
X.IR cat (1)
Xto re-create a large file, and so on.
XTo create the log file, use the ``\-l'' option to specify the name
Xof the file; if the name is ``\-'' the log will go to standard error.
XIf any problems are found, the log file will be added to the new
Xmanifest; use the ``\-e'' option to exclude it.
X.PP
XThe log file is written such that it can often be fed directly into a
XUnix shell for execution.
XIf a logfile is created, and the ``\-t'' option is used, then the
Xtext specified with the ``\-t'' flag will be echoed to the user's
Xterminal if the logfile is executed.
XThis has the same meaning as the ``\-t'' option of
X.IR shar (1L).
X.PP
XThe ``\-m'' option is the same as giving the options
X\&``\-iMANIFEST \-oMANIFEST \-h2 \-lPACKNOTES'' and is commonly used when
Xreading existing manifests.
X.PP
XAfter copying any header to the output,
X.I maniscan
Xscans each file specified in the manifest.
XIf a named file appears to be a binary file (more than a third
Xof the first 150 bytes are not printable characters),
X.I maniscan
Xwill create a
X.IR uuencode (1)'d
Xversion, update the manifest, and print a log message.
XIf the original file is named
X.IR foo.bar ,
Xthen the new file will be named
X.IR foo.bar.UU .
X.I Maniscan
Xnext scans for long lines or lines that have non-printable characters in
Xthem (most commonly ASCII control characters).
XThe default line length is 78 characters; this can be changed by using
Xthe ``\-w'' option; a width of zero skips this check.
XIt also checks for lines that end with a space or tab; to suppress this
Xcheck use the ``\-n'' option.
X(Some mailers (like those on BITNET) like to strip trailing spaces, while
Xsome editors (like GNU Emacs) seem to like to create lines with them;
Xuse the flag as it is appropriate for you.)
XEach time it finds one of these problems,
X.I maniscan
Xwill write a log entry.
X.PP
XIf a file named in the manifest is too large,
X.I maniscan
Xwill split it up into pieces.
XThe default limit is 50,000 bytes; this may be changed by using
Xthe ``\-s'' option.
XIf the number given with the ``\-s'' option ends with the letter ``k''
Xthen the size is multiplied by 1024, otherwise it is taken to be the
Xdesired maximum size in bytes.
XThe manifest will be updated to refer to the split pieces, and a log
Xentry will be written with instructions to merge the pieces.
XIf the original file is named
X.IR foo.bar ,
Xthen the pieces will be named
X.IR foo.bar.1 ,
X.IR foo.bar.2 ,
Xand so on.
X.PP
XThe scanning is done in the ``right'' way so that a single large executable
Xnamed
X.I a.out
Xwould end up being shipped as
X.IR a.out.UU.1 ,
X.I a.out.UU.2
X\&...
X.IR a.out.UU.n .
XIn no case does
X.I maniscan
Xedit or remove any files mentioned in a manifest (except for the manifest
Xitself).
X.PP
XIf running on a system where the filenames are of limited length,
X.I maniscan
Xwill automatically truncate the generated filename to fit inside the
Xlimit.
XTo help ensure portability, the ``\-f'' flag can be used on any system;
Xthis will limit the length of the generated filenames by truncating
Xthe base name.
XFor example, with ``\-f 14'' specified, the large file
X.I InternalDocumentation
Xwill be split into pieces named
X.IR InternalDocu01 ,
Xand so on.
XNote that the period is omitted.
X.PP
XIf a file named in the manifest does not exist,
X.I maniscan
Xcan try to create it.
XThe ``\-c'' option should be given the name of a command to run,
Xwith a single ``%s'' that will replace the filename.  For example,
X\&``-c "sccs get %s"'' can be used to do a simple checkout of files
Xfrom SCCS.
XThe command will be given the full filename as named in the manifest,
Xand will be invoked from within the same directory that
X.I maniscan
Xwas invoked from, so a wrapper script will often be needed to checkout
Xitems within sub-directories:
X.RS
X.nf
X#! /bin/sh
XDIR=`expr $1 : '\e(.*\e)/.*'`
Xif test "X${DIR}" != "X" ; then
X    cd $DIR
Xfi
XFILE=`expr $1 : '.*/\e(.*\e)'`
Xcheckout $FILE
X.fi
X.RE
XThis option may not be available on all systems.
X.PP
XThe ``\-v'' option prints out the current version and exits.
X.SH CAVEATS
XThe generated file names are not portable to all systems.
X.PP
X.SH "SEE ALSO"
Xmakekit(1L).
END_OF_FILE
  if test 5700 -ne `wc -c <'maniscan.man'`; then
    echo shar: \"'maniscan.man'\" unpacked with wrong size!
  fi
  # end of 'maniscan.man'
fi
if test -f 'shar.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shar.h'\"
else
  echo shar: Extracting \"'shar.h'\" \(4539 characters\)
  sed "s/^X//" >'shar.h' <<'END_OF_FILE'
X/*
X**  Header file for shar and friends.
X**
X**  If you have to edit this file, then I messed something up -- please
X**  let me know what.
X**
X**  $Header: shar.h,v 2.1 88/06/03 11:39:28 rsalz Locked $
X*/
X/* SUPPRESS 223 *//* Nested comment */
X#include "config.h"
X
X#ifdef	ANSI_HDRS
X#include <stdlib.h>
X#include <stddef.h>
X#include <string.h>
X#include <io.h>
X#include <time.h>
X#endif	/* ANSI_HDRS */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <setjmp.h>
X
X#ifdef	VMS
X#include <types.h>
X#else
X#include <sys/types.h>
X#endif	/* VMS */
X
X/*
X**  Let's play "find the header file."
X*/
X#ifdef	IN_SYS_DIR
X#include <sys/dir.h>
X#endif	/* IN_SYS_DIR */
X#ifdef	IN_DIR
X#include <dir.h>
X#endif	/* IN_DIR */
X#ifdef	IN_DIRECT
X#include <direct.h>
X#endif	/* IN_DIRECT */
X#ifdef	IN_SYS_NDIR
X#include <sys/ndir.h>
X#endif	/* IN_SYS_NDIR */
X#ifdef	IN_NDIR
X#include "ndir.h"
X#endif	/* IN_NDIR */
X#ifdef	IN_DIRENT
X#include <dirent.h>
X#endif	/* IN_DIRENT */
X
X
X/*
X**  Handy shorthands.
X*/
X#define TRUE		1		/* What I tell you three times	*/
X#define FALSE		0		/* ... is false			*/
X#define OOB_FALSE	3		/* "Emergency" exit from unshar	*/
X#define WIDTH		72		/* Contents lines in shar.c	*/
X#define F_DIR		36		/* Something is a directory	*/
X#define F_FILE		65		/* Something is a regular file	*/
X#define SAFE_WIDTH	78		/* Warn if longer than this	*/
X#define READ_CHUNK	150		/* Size of binary-test chunk	*/
X#define UULINE_SIZE	45		/* Size of uuencode chunk	*/
X#define UUTABLE_SIZE	127		/* Character mapping table	*/
X#define UUCHAR_DATA	64		/* Characters used in map	*/
X
X
X/*
X** These are used by the archive parser or findsrc.
X*/
X#define LINE_SIZE	200		/* Length of physical input line*/
X#define MAX_VARS	 20		/* Number of shell vars allowed	*/
X#define MAX_WORDS	 30		/* Make words in command lnes	*/
X#define VAR_NAME_SIZE	 30		/* Length of a variable's name	*/
X#define VAR_VALUE_SIZE	128		/* Length of a variable's value	*/
X#define MAX_PATTERNS	 60		/* Filename patterns in table	*/
X
X
X#ifndef	L_ctermid
X#define L_ctermid	50
X#endif	/* L_ctermid */
X
X/*
X**  Lint placation.
X*/
X#ifdef	lint
X#undef RCSID
X#undef putc
X#undef putchar
X#endif	/* lint */
X#define Printf		(void)printf
X#define Fprintf		(void)fprintf
X#define Sprintf		(void)sprintf
X
X
X/*
X**  Saber placation.
X*/
X#ifdef	SABER
X#undef RCSID
X#endif	/* SABER */
X
X/*
X**  Memory hacking.
X*/
X#define NEW(T, count)	((T *)shar_getmem(sizeof (T), (unsigned int)(count)))
X#define COPY(s)		strcpy(NEW(char, strlen((s)) + 1), (s))
X
X
X/*
X**  Macros.
X*/
X#define BADCHAR(c)	(!isascii((c)) || (iscntrl((c)) && !isspace((c))))
X#define HDRCHAR(c)	((c) == '-' || (c) == '_' || (c) == '.')
X#define EQ(a, b)	(strcmp((a), (b)) == 0)
X#define EQn(a, b, n)	(strncmp((a), (b), (n)) == 0)
X#define PREFIX(a, b)	(EQn((a), (b), sizeof b - 1))
X#define WHITE(c)	((c) == ' ' || (c) == '\t')
X
X
X/*
X**  Linked in later.
X*/
Xextern int	 optind;
Xextern char	*optarg;
X
X#ifndef	ANSI_HDRS
Xextern int	 errno;
X
X/* From your C run-time library. */
Xextern FILE	*popen();
Xextern time_t	time();
Xextern long	atol();
Xextern char	*IDX();
Xextern char	*RDX();
Xextern char	*ctime();
Xextern char	*gets();
Xextern char	*mktemp();
Xextern char	*strcat();
Xextern char	*strcpy();
Xextern char	*strncpy();
Xextern char   	*getenv();
X#ifdef	PTR_SPRINTF
Xextern char	*sprintf();
X#endif	/* PTR_SPRINTF */
X#ifdef	USE_SYSERRLIST
Xextern int	sys_nerr;
Xextern char	*sys_errlist[];
X#endif	/* USE_SYSERRLIST */
X
X#endif	/* ANSI_HDRS */
X
X
X/* From our local library. */
X
X#ifdef	DECLARE_PROTOTYPES
X#define PARMS(x)	(x)
X#else
X#define PARMS(x)	()
X#endif	/* DECLARE_PROTOTYPES */
X
Xextern char	*strerror PARMS( (int) );
Xextern char	*GetDir PARMS( (char *, int) );
Xextern char	*Host PARMS( (void) );
Xextern char	*Seechar PARMS( (int) );
Xextern char	*User PARMS( (void) );
Xextern align_t	shar_getmem PARMS( (int, unsigned int) );
Xextern off_t	Fsize PARMS( (char *) );
Xextern int	Argify PARMS( (char **) );
Xextern int	Exec PARMS( (char **) );
Xextern int	Execute PARMS( (char **) );
Xextern int	Fexecute PARMS( (char *) );
Xextern int	Fexists PARMS( (char *) );
Xextern int	Ftype PARMS( (char *) );
Xextern int	GetLine PARMS( (int) );
Xextern int	GetStat PARMS( (char *) );
Xextern int	IsProbablySource PARMS( (char *) );
Xextern void	MakeTempName PARMS( (char *, char *) );
Xextern int	Pid PARMS( (void) );
Xextern void	SafeRename PARMS( (char *) );
Xextern void	SetSigs PARMS( (sigret_t (*)()) );
Xextern int	getopt PARMS( (int, char **, char *) );
Xextern void	SetVar PARMS( (char *, char *) );
Xextern void	SynErr PARMS( (char *) );
Xextern void	Version PARMS( (char *) );
Xextern void	uuencode PARMS( (char *, char *) );
END_OF_FILE
  if test 4539 -ne `wc -c <'shar.h'`; then
    echo shar: \"'shar.h'\" unpacked with wrong size!
  fi
  # end of 'shar.h'
fi
if test -f 'shar.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shar.man'\"
else
  echo shar: Extracting \"'shar.man'\" \(6165 characters\)
  sed "s/^X//" >'shar.man' <<'END_OF_FILE'
X.TH SHAR 1L
X.\" $Header: shar.man,v 2.0 88/05/27 13:28:49 rsalz Exp $
X.SH NAME
Xshar \- create shell archive file for extraction by /bin/sh
X.SH SYNOPSIS
X.RS
X.na
X.ti -.5i
X.B shar
X[
X.B \-b
X] [
X.BI \-i\| name
X] [
X.BI \-n\| #
X] [
X.BI \-e\| #
X] [
X.BI \-o\| name
X] [
X.BI \-t\| text
X] [
X.B \-v
X] [
X.B \-w
X] [file...]
X.ad
X.RE
X.SH DESCRIPTION
X.I Shar
Xtakes a list of files, and generates a
X.IR /bin/sh
Xscript that, when executed, will re-create those files in a different
Xdirectory or on a different machine.
XThe resultant script will use
X.IR wc (1)
Xto do a mild error-check, and will warn about possibly-omitted
Xcontrol characters.
X.PP
X.I Shar
Xgenerates scripts that will make directories and plain files.
XIt will not try to generate intermediate filenames, however, so
X.RS
Xshar foo/bar/file
X.RE
Xwill not work.  Do
X.RS
Xshar foo foo/bar foo/bar/file
X.RE
Xinstead.
X.PP
XThe script is normally sent to standard output; the ``\-o'' option may be
Xused to specify an output filename.
XThis is designed to prevent filling up the disk if
X.RS
Xshar * >SHAR
X.RE
Xcommand is done; do
X.RS
Xshar -o SHAR *
X.RE
Xinstead.
X.PP
XThe list of files is normally specified on the command line; the ''\-i''
Xoption may be used instead, to specify a file that contains the list
Xof files to pack up, one per line.
XIf the file name is ``-'' the standard input is read.
X.PP
XThe ``\-b'' option says that all leading directory names should be stripped
Xfrom the file when they are packed into the archive.
XFor example,
X.RS
Xshar -b /etc/termcap
X.RE
Xcreates an archive that, when executed, creates a file named
X``termcap'' in the current directory, rather than overwrite the
Xhost system file.
XNote, however, that the scripts generated by
X.I shar
Xnormally refuse to overwrite pre-existing files.
X.PP
XThe scripts generated by
X.I shar
Xnormally contain comments indicating what is in the archive and
Xwho packaged it.
XThey also contain
Xas
X.IR echo(1)
Xcommands to print messages such as
X.RS
Xshar: End of archive.
X.RE
XIf the ``\-w'' flag is used, then
X.I shar
Xwill not generate the prolog and epilog.
XThis is useful when the shar's are within a larger software distribution
Xscheme.
X.PP
XThe ``\-v'' option prints out the current version and exits.
X.SS "Multi\-part Archives"
XMost larger software packages are usually sent out in two or more shell
Xarchives.
XThe ``\-n,'' ``\-e,'' and ``\-t'' options are used to make an archive
Xthat is part of a series.
XThe individual archives within such a series are often called ``kits.''
XThe ``\-n'' option specifies the archive number; the ``\-e'' option species
Xthe highest number in the series.
XFor example, if the options ``\-n 3 \-e 9'' are given, then archive
Xwill end with a message like this:
X.RS
Xshar: End of archive 3 (of 9).
X.RE
Xat the end.
X.PP
XIn addition, each shar will generate a file named
X.IR ark X isdone ,
Xwhere
X.I X
Xis the number given with the ``\-n'' option.
XEach script will contain a loop to check for the presence of these
Xfiles, and indicate to the recipient which archives still need to be
Xexecuted.
XThe ``\-t'' option may be used to give starting instructions to the recipient.
XWhen the kits determine that all the archives have been unpacked,
Xthe text specified with this flag is displayed.
XFor example,
X.RS
Xshar -n1 -e9 -t "Now do 'sh ./Configure'" *.c >SHAR
X.RE
XThis adds commands to output the following when all the archives have been
Xunpacked:
X.RS
X.nf
XYou have unpacked all 9 archives.
XNow do 'sh ./Configure'
X.fi
X.RE
X.PP
XThe
X.IR makekit (1L)
Xprogram is designed to create such multi-part kits.
X.SS "Usage Notes"
XThis program is part of a larger suite of programs that are used for
Xdistributing program sources.
XThe full set of programs are divided into three groups as follows:
X.RS
X.nf
X.ta \w'manipull  'u
Xfindsrc	Find source files within a directory tree
X	This prepares a preliminary manifest
Xmaniscan	Make all files in a manifest ``good''
X	This splits large files, uuencodes, etc.
Xmakekit	Create individual shar files from a Manifest
Xshar	Creates a single shell archive
Xuuencode	Skip headers, and re-create a binary file
X
Xunshar	Strip mail headers and unpack archives
Xuudecode	Convert binary files into a text format
X
Xmanipull	Create a manifest from an existing one
Xshell	Unpack archives
X.fi
X.RE
X.PP
XThe first set of tools are used to create source distributions.
X.PP
X.I Findsrc
Xis normally only used once at the top of a directory tree.
XThe normal use is to use the ``\-m'' option to create a manifest, using the
Xdefault rules for finding source files.
XIt is sometimes necessary to use the ``\-y'' or ``\-n'' options to add
Xnew patterns (almost always filename extensions) just as font files.
X.PP
X.I Maniscan
Xis normally run just after
X.IR findsrc .
XIt reads a manifest uuencodes any binary files it finds, as well as splitting
Xlarger files into smaller pieces.
XThe normal use is to use the ``\-m'' option.
X.PP
XOnce those first two steps have been done, the most commonly-used program is
X.IR makekit .
XThis reads the manifest, and invokes
X.I shar
Xto pack the individual kits.
XOccasionally, during editing, a file will become too large and
X.I makekit
Xwill complain.
XWhen this happens, re-run
X.IR maniscan.
XIf a binary file changes, you will have to edit the manifest to remove the
X\&``.UU'' version and re-run
X.I maniscan
Xso that it will re-invoke
X.I uuencode
Xto prepare the file.
X.PP
X.I Shar
Xis often used to quickly and easily mail a small set of files to a colleague.
XFor example,
X.RS
Xshar *.[ch] | mail rsalz@bbn.com
X.RE
X.PP
XThe second set of programs are used to unpack distributions.
X.I Unshar
Xis normally used from within a newsreader (or mail program) and is fed
Xindividual kits.
XNote that it cannot unpack multiple messages saved within a single file.
X.I Uuencode
Xwill be needed to convert binary files from their portable text form
Xback into their binary form.
X.PP
XThe third set of programs are for special cases.
X.I Manipull
Xcreates a subset manifest that can given to
X.IR makekit .
X.I Shell
Xis normally compiled into
X.I unshar
Xto interpret shell scripts that contain archives.
XIt is possible to compile it separately, primarily for testing.
X.SH "SEE ALSO"
Xecho(1), findsrc(1L), makekit(1L), mkdir(1), sh(1), test(1), unshar(1L), wc(1).
END_OF_FILE
  if test 6165 -ne `wc -c <'shar.man'`; then
    echo shar: \"'shar.man'\" unpacked with wrong size!
  fi
  # end of 'shar.man'
fi
if test -f 'uudecode.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uudecode.c'\"
else
  echo shar: Extracting \"'uudecode.c'\" \(4533 characters\)
  sed "s/^X//" >'uudecode.c' <<'END_OF_FILE'
X/*
X**  UUDECODE
X**
X**  Decode printable representation of binary data.  This is based on the
X**  public-domain implementation that Mark Horton released to mod.sources
X**  with the translation table written by Jean-Pierre H. Dumas.
X*/
X#include "shar.h"
Xstatic char RCS[] =
X	"$Header$";
X
X/* single character decode */
X#define DEC(c)		(((c) - ' ') & 077)
X
X#undef DEC
X#define DEC(c)		(Table[(c)])
X
Xstatic char		Table[UUTABLE_SIZE];
X
X
X/*
X**  Read in the translation table.
X*/
Xstatic void
XGetTable(F)
X    REGISTER FILE	*F;
X{
X    REGISTER char	*p;
X    REGISTER int	 c;
X    REGISTER int	 n;
X    char		 buff[BUFSIZ];
X
X    /* Clear it out; kinda messy, but one less config parameter... */
X    for (p = Table, n = sizeof Table; --n >= 0; p++)
X	*p = '\0';
X
X    /* Read lines until we hit the all the data elements. */
X    for (n = 0; ; ) {
X
X	/* Get a line. */
X	if (fgets(buff, sizeof buff, F) == NULL) {
X	    Fprintf(stderr, "EOF in translation table, %s\n", strerror(errno));
X	    exit(1);
X	}
X	if (EQn(buff, "begin", 5)) {
X	    Fprintf(stderr, "Incomplete translation table.\n");
X	    exit(1);
X	}
X
X	/* Strip trailing spaces. */
X	for (p = &buff[strlen(buff)]; p > buff && (*--p == '\n' || WHITE(*p)); )
X	    *p = '\0';
X	/* Rest of the line is part of our table. */
X	for (p = buff; (c = *p) != '\0'; p++) {
X	    if (Table[c]) {
X		Fprintf(stderr,
X		    "Duplicate character 0%0 (%s) in translation table.\n",
X		    Table[c], Seechar(Table[c]));
X		exit(1);
X	    }
X	    Table[c] = n;
X	    if (++n >= UUCHAR_DATA)
X		return;
X	}
X    }
X}
X
X
Xint
Xmain(ac, av)
X    int			ac;
X    char		*av[];
X{
X    REGISTER FILE	*Out;
X    REGISTER FILE	*F;
X    REGISTER char	*p;
X    REGISTER int	n;
X    REGISTER int	c;
X    char		Name[128];
X    char		buff[80];
X    int			mode;
X    int			Oops;
X
X    /* Parse JCL. */
X    for (Oops = FALSE; (n = getopt(ac, av, "v")) != EOF; )
X	switch (n) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 'v':		/* Print version			*/
X	    Version(RCS);
X	    /* NOTREACHED */
X	}
X    ac -= optind;
X    av += optind;
X
X    if (!Oops)
X	switch (ac) {
X	default:
X	    Oops = TRUE;
X	    break;
X	case 0:
X	    F = stdin;
X	    break;
X	case 1:
X	    if ((F = fopen(*av, "r")) == NULL) {
X		Fprintf(stderr, "Can't open \"%s\" for input, %s.\n",
X			*av, strerror(errno));
X		exit(1);
X		/* NOTREACHED */
X	    }
X	    break;
X	}
X
X    if (Oops) {
X	Fprintf(stderr, "Usage:\n  uudecode %s\n", "[infile]");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Set up default translation table. */
X    for (n = 0, p = &Table[n]; n < ' '; n++)
X	*p++ = '\0';
X    for (c = 0; n < ' ' + UUCHAR_DATA; n++)
X	*p++ = c++;
X    for (; n < UUTABLE_SIZE; n++)
X	*p++ = '\0';
X    /* Space and backquote are same; 4.3 started using backquote to avoid
X     * BITNET lossage of removing trailing spaces.  Uparrow and tilde are
X     * another common BITNET loss, which also luckily map to the same thing. */
X    Table['`'] = Table[' '];
X    Table['~'] = Table['^'];
X
X    /* Get header line. */
X    do {
X	if (fgets(buff, sizeof buff, F) == NULL) {
X	    Fprintf(stderr, "Can't find \"begin\" line, %s.\n",
X		    strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X	if (EQn(buff, "table", 5))
X	    GetTable(F);
X    } while (!EQn(buff, "begin ", 6));
X    if (sscanf(buff, "begin %o %s", &mode, Name) != 2) {
X	Fprintf(stderr, "Malformed \"begin\" line.\n");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* Create output file. */
X    if ((Out = fopen(Name, "w")) == NULL) {
X	Fprintf(stderr, "Can't open \"%s\" for output, %s.\n",
X		Name, strerror(errno));
X	perror(Name);
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    if (chmod(Name, mode) < 0)
X	Fprintf(stderr, "Warning, can't chmod(\"%s\", 0%o), %s.\n",
X		Name, mode, strerror(errno));
X
X    /* Read and munch. */
X    for ( ; ; ) {
X	/* Read a line; zero datacount means end of data. */
X	if (fgets(buff, sizeof buff, F) == NULL) {
X	    Fprintf(stderr, "Short file, %s.\n", strerror(errno));
X	    exit(1);
X	    /* NOTREACHED */
X	}
X	if ((n = DEC(buff[0])) <= 0)
X	    break;
X
X	/* Decode it. */
X	for (p = &buff[1]; n > 0; p += 4, n -= 3) {
X	    c = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
X	    (void)putc(c, Out);
X	    if (n >= 2) {
X		c = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
X		(void)putc(c, Out);
X		if (n >= 3) {
X		    c = DEC(p[2]) << 6 | DEC(p[3]);
X		    (void)putc(c, Out);
X		}
X	    }
X	}
X    }
X
X    /* Check for good ending. */
X    if (fgets(buff, sizeof buff, F) == NULL || !EQ(buff, "end\n")) {
X	Fprintf(stderr, "No end line\n");
X	exit(1);
X	/* NOTREACHED */
X    }
X
X    /* That's all she wrote. */
X    (void)fclose(Out);
X    (void)fclose(F);
X    exit(0);
X    /* NOTREACHED */
X}
END_OF_FILE
  if test 4533 -ne `wc -c <'uudecode.c'`; then
    echo shar: \"'uudecode.c'\" unpacked with wrong size!
  fi
  # end of 'uudecode.c'
fi
if test -f 'wildmat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wildmat.c'\"
else
  echo shar: Extracting \"'wildmat.c'\" \(4768 characters\)
  sed "s/^X//" >'wildmat.c' <<'END_OF_FILE'
X/*  $Revision: 1.6 $
X**
X**  Do shell-style pattern matching for ?, \, [], and * characters.
X**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
X**  could cause a segmentation violation.  It is 8bit clean.
X**
X**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
X**  Rich $alz is now <rsalz@bbn.com>.
X**  April, 1991:  Replaced mutually-recursive calls with in-line code
X**  for the star character.
X**
X**  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
X**  This can greatly speed up failing wildcard patterns.  For example:
X**	pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
X**	text 1:	 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
X**	text 2:	 -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
X**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
X**  the ABORT code, it takes 22310 calls to fail.  Ugh.  The following
X**  explanation is from Lars:
X**  The precondition that must be fulfilled is that DoMatch will consume
X**  at least one character in text.  This is true if *p is neither '*' nor
X**  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
X**  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
X**  FALSE, each star-loop has to run to the end of the text; with ABORT
X**  only the last one does.
X**
X**  Once the control of one instance of DoMatch enters the star-loop, that
X**  instance will return either TRUE or ABORT, and any calling instance
X**  will therefore return immediately after (without calling recursively
X**  again).  In effect, only one star-loop is ever active.  It would be
X**  possible to modify the code to maintain this context explicitly,
X**  eliminating all recursive calls at the cost of some complication and
X**  loss of clarity (and the ABORT stuff seems to be unclear enough by
X**  itself).  I think it would be unwise to try to get this into a
X**  released version unless you have a good test data base to try it out
X**  on.
X*/
X
X#define TRUE			1
X#define FALSE			0
X#define ABORT			-1
X
X
X    /* What character marks an inverted character class? */
X#define NEGATE_CLASS		'^'
X    /* Is "*" a common pattern? */
X#define OPTIMIZE_JUST_STAR
X    /* Do tar(1) matching rules, which ignore a trailing slash? */
X#undef MATCH_TAR_PATTERN
X
X
X/*
X**  Match text and p, return TRUE, FALSE, or ABORT.
X*/
Xstatic int
XDoMatch(text, p)
X    register char	*text;
X    register char	*p;
X{
X    register int	last;
X    register int	matched;
X    register int	reverse;
X
X    for ( ; *p; text++, p++) {
X	if (*text == '\0' && *p != '*')
X	    return ABORT;
X	switch (*p) {
X	case '\\':
X	    /* Literal match with following character. */
X	    p++;
X	    /* FALLTHROUGH */
X	default:
X	    if (*text != *p)
X		return FALSE;
X	    continue;
X	case '?':
X	    /* Match anything. */
X	    continue;
X	case '*':
X	    while (*++p == '*')
X		/* Consecutive stars act just like one. */
X		continue;
X	    if (*p == '\0')
X		/* Trailing star matches everything. */
X		return TRUE;
X	    while (*text)
X		if ((matched = DoMatch(text++, p)) != FALSE)
X		    return matched;
X	    return ABORT;
X	case '[':
X	    reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
X	    if (reverse)
X		/* Inverted character class. */
X		p++;
X	    matched = FALSE;
X	    if (p[1] == ']' || p[1] == '-')
X		if (*++p == *text)
X		    matched = TRUE;
X	    for (last = *p; *++p && *p != ']'; last = *p)
X		/* This next line requires a good C compiler. */
X		if (*p == '-' && p[1] != ']'
X		    ? *text <= *++p && *text >= last : *text == *p)
X		    matched = TRUE;
X	    if (matched == reverse)
X		return FALSE;
X	    continue;
X	}
X    }
X
X#ifdef	MATCH_TAR_PATTERN
X    if (*text == '/')
X	return TRUE;
X#endif	/* MATCH_TAR_ATTERN */
X    return *text == '\0';
X}
X
X
X/*
X**  User-level routine.  Returns TRUE or FALSE.
X*/
Xint
Xwildmat(text, p)
X    char	*text;
X    char	*p;
X{
X#ifdef	OPTIMIZE_JUST_STAR
X    if (p[0] == '*' && p[1] == '\0')
X	return TRUE;
X#endif	/* OPTIMIZE_JUST_STAR */
X    return DoMatch(text, p) == TRUE;
X}
X
X
X
X#if	defined(TEST)
X#include <stdio.h>
X
X/* Yes, we use gets not fgets.  Sue me. */
Xextern char	*gets();
X
X
Xint
Xmain()
X{
X    char	 p[80];
X    char	 text[80];
X
X    printf("Wildmat tester.  Enter pattern, then strings to test.\n");
X    printf("A blank line gets prompts for a new pattern; a blank pattern\n");
X    printf("exits the program.\n");
X
X    for ( ; ; ) {
X	printf("\nEnter pattern:  ");
X	(void)fflush(stdout);
X	if (gets(p) == NULL || p[0] == '\0')
X	    break;
X	for ( ; ; ) {
X	    printf("Enter text:  ");
X	    (void)fflush(stdout);
X	    if (gets(text) == NULL)
X		exit(0);
X	    if (text[0] == '\0')
X		/* Blank line; go back and get a new pattern. */
X		break;
X	    printf("      %s\n", wildmat(text, p) ? "YES" : "NO");
X	}
X    }
X
X    exit(0);
X    /* NOTREACHED */
X}
X#endif	/* defined(TEST) */
END_OF_FILE
  if test 4768 -ne `wc -c <'wildmat.c'`; then
    echo shar: \"'wildmat.c'\" unpacked with wrong size!
  fi
  # end of 'wildmat.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
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

