[net.sources] New Version of Shar

perlman@wanginst.UUCP (Gary Perlman) (03/11/86)

Here is a new version of my C language shell archiver, shar.
It supercedes all previous versions.

Some notable changes:
	The -u option uuencodes the files and inserts the uudecode
	commands to unpack them.  I am not too sure how this should
	work, because the files (on my system), then are owned by uucp.
	Please tell me about you success/failures with this option.
	In any case, it should only be used as a last resort.

	The -m option makes sure that all file/directory protection
	modes are restored on extraction.  This option was added so
	that people could send files with read-protection without
	having to chnage the modes manually.

Other changes were requested by assorted users who found the
shell archive format incompatible with their old shells.

I will post an updated version of shar to mod.sources once the
few, the brave, in net.sources have exercised it a few months.
	Gary Perlman

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	makefile
#	shar.c
#	traverse.c
#	getopt.c
#	shar.1
#	traverse.3
#	getopt.3
# This archive created: Tue Mar 11 14:51:42 1986
# By:	Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'makefile'" '(415 characters)'
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'makefile'
	XCFLAGS=-O
	X
	XOBJS=shar.o traverse.o getopt.o
	XSRCS=shar.c traverse.c getopt.c
	XDOCS=shar.1 traverse.3 getopt.3
	X
	XPR=/usr/ucb/print
	XLINT=lint -h
	X
	Xshar: $(OBJS) makefile
	X	@cc $(CFLAGS) -o shar $(OBJS)
	X
	Xtraverse:
	X	@cc -o traverse -DSTANDALONE traverse.c
	X
	Xarchive: makefile $(SRCS) $(DOCS)
	X	@shar -a makefile $(SRCS) $(DOCS) > archive
	X
	Xprint:
	X	@$(PR) makefile shar.c
	X
	Xlint:
	X	@$(LINT) $(SRCS)
	X
	Xclean:
	X	@-rm -f core a.out *.o
SHAR_EOF
if test 415 -ne "`wc -c < 'makefile'`"
then
	echo shar: "error transmitting 'makefile'" '(should have been 415 characters)'
fi
fi
echo shar: "extracting 'shar.c'" '(11109 characters)'
if test -f 'shar.c'
then
	echo shar: "will not over-write existing file 'shar.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'shar.c'
	X/*
	X	Shar puts readable text files together in a package
	X	from which they are extracted with /bin/sh and friends.
	X*/
	X
	X#include <stdio.h>
	X#include <sys/types.h>
	X#include <sys/stat.h>
	X#include <ctype.h>
	X
	X#ifndef lint
	Xstatic	char	sccsid[] = "@(#)shar.c 2.0 (Usenet) 3/11/86";
	X#endif
	X
	Xtypedef	int 	Boole;
	X#define	TRUE	((Boole) 1)
	X#define	FALSE	((Boole) 0)
	Xtypedef	int 	Status;
	X#define	SUCCESS	0
	X#define	FAILURE	1
	X
	X/* GLOBALS */
	Xint 	Lastchar;   /* the last character printed */
	Xint 	Ctrlcount;  /* how many bad control characters are in file */
	X
	X/* COMMANDS */
	X#define	EXTRACT "#! /bin/sh"          /* magic exec string at shar file start */
	X#define	PATH    "/bin:/usr/bin:$PATH" /* search path for programs */
	X#define	CAT     "cat";                /* /bin/cat */
	X#define	SED     "sed 's/^%s//'"       /* /bin/sed removes Prefix from lines */
	X#define	MKDIR   "mkdir"               /* make a new dirctory */
	X#define	CHMOD   "chmod"               /* change file mode */
	X#define	CHDIR   "cd"                  /* change current directory */
	X#define	TEST    "test"                /* /bin/test files */
	X#define	WC_C    "wc -c <"             /* counts chars in file */
	X#define	ECHO    "echo shar:"          /* echo a message to extractor */
	X#define	DECODE  "uudecode"            /* used to decode uuencoded files */
	X
	X/*FUNCTION main: traverse files to make archive to standard output */
	Xmain (argc, argv) char **argv;	
	X	{
	X	int 	shar ();
	X	int 	optind;
	X
	X	if ((optind = initial (argc, argv)) < 0)
	X		exit (FAILURE);
	X
	X	if (header (argc, argv, optind))
	X		exit (FAILURE);
	X
	X	while (optind < argc)
	X		traverse (argv[optind++], shar);
	X
	X	footer ();
	X
	X	exit (SUCCESS);
	X	}
	X
	X/* OPTIONS */
	XBoole	Verbose = FALSE;       /* provide append/extract feedback */
	XBoole	Basename = FALSE;      /* extract into basenames */
	XBoole	Count = FALSE;         /* count characters to check transfer */
	XBoole	Overcheck = TRUE;      /* check overwriting */
	XBoole	Uucode = FALSE;        /* uuencode the file */
	Xchar	*Delim = "SHAR_EOF";   /* put after each file */
	Xchar	Filter[100] = CAT;     /* used to extract archived files */
	Xchar	*Prefix = NULL;        /* line prefix to avoid funny chars */
	XBoole	Modeset = FALSE;       /* set exact modes on extraction */
	X
	X/*FUNCTION: initial: do option parsing and any setup */
	Xint /* returns the index of the first operand file */
	Xinitial (argc, argv) char **argv;
	X	{
	X	int 	errflg = 0;
	X	extern	int 	optind;
	X	extern	char	*optarg;
	X	int 	C;
	X	char	*optstring = "abcmsuvp:d:";
	X	char	*usage = "[-abcmsuv] [-p prefix] [-d delim] files > archive";
	X
	X	while ((C = getopt (argc, argv, optstring)) != EOF)
	X		switch (C)
	X			{
	X			case 'u': Uucode = TRUE; break;
	X			case 'b': Basename = TRUE; break;
	X			case 'c': Count = TRUE; break;
	X			case 'd': Delim = optarg; break;
	X			case 'm': Modeset = TRUE; break;
	X			case 's': /* silent running */
	X				Overcheck = FALSE;
	X				Verbose = FALSE;
	X				Count = FALSE;
	X				Prefix = NULL;
	X				break;
	X			case 'a': /* all the options */
	X				Verbose = TRUE;
	X				Count = TRUE;
	X				Basename = TRUE;
	X				/* fall through to set prefix */
	X				optarg = "	X";
	X				/* FALLTHROUGH */
	X			case 'p': (void) sprintf (Filter, SED, Prefix = optarg); break;
	X			case 'v': Verbose = TRUE; break;
	X			default: errflg++;
	X			}
	X
	X	if (errflg || optind == argc)
	X		{
	X		if (optind == argc)
	X			fprintf (stderr, "shar: No input files\n");
	X		fprintf (stderr, "Usage: shar %s\n", usage);
	X		return (-1);
	X		}
	X
	X	return (optind);
	X	}
	X
	X/*FUNCTION header: print header for archive */
	Xheader (argc, argv, optind)
	Xchar	**argv;
	X	{
	X	int 	i;
	X	Boole	problems = FALSE;
	X	long	clock;
	X	char	*ctime ();
	X	char	*getenv ();
	X	char	*NAME = getenv ("NAME");
	X	char	*ORG = getenv ("ORGANIZATION");
	X
	X	for (i = optind; i < argc; i++)
	X		if (access (argv[i], 4)) /* check read permission */
	X			{
	X			fprintf (stderr, "shar: Can't read '%s'\n", argv[i]);
	X			problems++;
	X			}
	X
	X	if (problems)
	X		return (FAILURE);
	X
	X	printf ("%s\n", EXTRACT);
	X	printf ("# This is a shell archive, meaning:\n");
	X	printf ("# 1. Remove everything above the %s line.\n", EXTRACT);
	X	printf ("# 2. Save the resulting text in a file.\n");
	X	printf ("# 3. Execute the file with /bin/sh (not csh) to create:\n");
	X	for (i = optind; i < argc; i++)
	X		printf ("#\t%s\n", argv[i]);
	X	(void) time (&clock);
	X	printf ("# This archive created: %s", ctime (&clock));
	X	if (NAME)
	X		printf ("# By:\t%s (%s)\n", NAME, ORG ? ORG : "");
	X	printf ("export PATH; PATH=%s\n", PATH);
	X	return (SUCCESS);
	X	}
	X
	X/*FUNCTION footer: print end of shell archive */
	Xfooter ()
	X	{
	X	printf ("exit 0\n");
	X	printf ("#\tEnd of shell archive\n");
	X	}
	X
	X/* uuencode options available to send cntrl and non-ascii chars */
	X/* really, this is getting to be too much like cpio or tar */
	X
	X/* ENC is the basic 1 character encoding function to make a char printing */
	X#define ENC(c) (((c) & 077) + ' ')
	X
	X/*FUNCTION uuarchive: simulate uuencode to send files */
	XStatus
	Xuuarchive (input, protection, output)
	Xchar	*input;
	Xint 	protection;
	Xchar	*output;
	X	{
	X	FILE	*in;
	X	if (in = fopen (input, "r"))
	X		{
	X		printf ("%s << \\%s\n", DECODE, Delim);
	X		printf ("begin %o %s\n", protection, output);
	X		uuencode (in, stdout);
	X		printf ("end\n");
	X		fclose (in);
	X		return (SUCCESS);
	X		}
	X	return (FAILURE);
	X	}
	X
	Xuuencode (in, out)
	XFILE *in, *out;
	X	{
	X	char	buf[80];
	X	int 	i, n;
	X	for (;;)
	X		{
	X		n = fread (buf, 1, 45, in);
	X		putc (ENC(n), out);
	X		for (i = 0; i < n; i += 3)
	X			outdec (&buf[i], out);
	X		putc ('\n', out);
	X		if (n <= 0)
	X			break;
	X		}
	X	}
	X
	X/* output one group of 3 bytes, pointed at by p, on file ioptr */
	Xoutdec (p, ioptr)
	Xchar	*p;
	XFILE	*ioptr;
	X	{
	X	int c1, c2, c3, c4;
	X	c1 = *p >> 2;
	X	c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
	X	c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
	X	c4 = p[2] & 077;
	X	putc (ENC(c1), ioptr);
	X	putc (ENC(c2), ioptr);
	X	putc (ENC(c3), ioptr);
	X	putc (ENC(c4), ioptr);
	X	}
	X
	X/*FUNCTION archive: make archive of input file to be extracted to output */
	Xarchive (input, output)
	Xchar	*input, *output;
	X	{
	X	char	buf[BUFSIZ];
	X	FILE	*ioptr;
	X
	X	if (ioptr = fopen (input, "r"))
	X		{
	X		Ctrlcount = 0;    /* no bad control characters so far */
	X		Lastchar = '\n';  /* simulate line start */
	X
	X		printf ("%s << \\%s > '%s'\n", Filter, Delim, output);
	X
	X		if (Prefix)
	X			{
	X			while (fgets (buf, BUFSIZ, ioptr))
	X				{
	X				if (Prefix) outline (Prefix);
	X				outline (buf);
	X				}
	X			}
	X		else copyout (ioptr);
	X
	X		if (Lastchar != '\n') /* incomplete last line */
	X			putchar ('\n');   /* Delim MUST begin new line! */
	X
	X		if (Count == TRUE && Lastchar != '\n')
	X			printf ("%s \"a missing newline was added to '%s'\"\n", ECHO, input);
	X		if (Count == TRUE && Ctrlcount)
	X			printf ("%s \"%d control character%s may be missing from '%s'\"\n",
	X				ECHO, Ctrlcount, Ctrlcount > 1 ? "s" : "", input);
	X
	X		(void) fclose (ioptr);
	X		return (SUCCESS);
	X		}
	X	else
	X		{
	X		fprintf (stderr, "shar: Can't open '%s'\n", input);
	X		return (FAILURE);
	X		}
	X	}
	X
	X/*FUNCTION copyout: copy ioptr to stdout */
	X/*
	X	Copyout copies its ioptr almost as fast as possible
	X	except that it has to keep track of the last character
	X	printed.  If the last character is not a newline, then
	X	shar has to add one so that the end of file delimiter
	X	is recognized by the shell.  This checking costs about
	X	a 10% difference in user time.  Otherwise, it is about
	X	as fast as cat.  It also might count control characters.
	X*/
	X#define	badctrl(c) (iscntrl (c) && !isspace (c))
	Xcopyout (ioptr)
	Xregister	FILE	*ioptr;
	X	{
	X	register	int 	C;
	X	register	int 	L;
	X	register	count;
	X
	X	count = Count;
	X
	X	while ((C = getc (ioptr)) != EOF)
	X		{
	X		if (count == TRUE && badctrl (C))
	X			Ctrlcount++;
	X		L = putchar (C);
	X		}
	X
	X	Lastchar = L;
	X	}
	X
	X/*FUNCTION outline: output a line, recoring last character */
	Xoutline (s)
	Xregister	char	*s;
	X	{
	X	if (*s)
	X		{
	X		while (*s)
	X			{
	X			if (Count == TRUE && badctrl (*s)) Ctrlcount++;
	X			putchar (*s++);
	X			}
	X		Lastchar = *(s-1);
	X		}
	X	}
	X
	X/*FUNCTION shar: main archiving routine passed to directory traverser */
	Xshar (file, type, pos)
	Xchar	*file;     /* file or directory to be processed */
	Xint 	type;      /* either 'f' for file or 'd' for directory */
	Xint 	pos;       /* 0 going in to a file or dir, 1 going out */
	X	{
	X	struct	stat	statbuf;
	X	char	*basefile = file;
	X	int 	protection;
	X
	X	if (!strcmp (file, "."))
	X		return;
	X
	X	if (stat (file, &statbuf))
	X		statbuf.st_size = 0;
	X	else
	X		protection = statbuf.st_mode & 07777;
	X
	X	if (Basename == TRUE)
	X		{
	X		while (*basefile) basefile++; /* go to end of name */
	X		while (basefile > file && *(basefile-1) != '/')
	X			basefile--;
	X		}
	X
	X	if (pos == 0) /* before the file starts */
	X		{
	X		beginfile (basefile, type, statbuf.st_size, protection);
	X		if (type == 'f')
	X			{
	X			if (Uucode)
	X				{
	X				if (uuarchive (file, protection, basefile) != SUCCESS)
	X					exit (FAILURE);
	X				}
	X			else
	X				if (archive (file, basefile) != SUCCESS)
	X					exit (FAILURE);
	X			}
	X		}
	X	else /* pos == 1, after the file is archived */
	X		endfile (basefile, type, statbuf.st_size, protection);
	X	}
	X
	X/*FUNCTION beginfile: do activities before packing up a file */
	Xbeginfile (basefile, type, size, protection)
	Xchar	*basefile;  /* name of the target file */
	Xint 	type;       /* either 'd' for directory, or 'f' for file */
	Xint 	size;       /* size of the file */
	Xint 	protection; /* chmod protection bits */
	X	{
	X	if (type == 'd')
	X		{
	X		printf ("if %s ! -d '%s'\n", TEST, basefile);
	X		printf ("then\n");
	X		if (Verbose == TRUE)
	X			printf ("	%s \"creating directory '%s'\"\n", ECHO, basefile);
	X		printf ("	%s '%s'\n", MKDIR, basefile);
	X		printf ("fi\n");
	X		if (Verbose == TRUE)
	X			printf ("%s \"entering directory '%s'\"\n", ECHO, basefile);
	X		printf ("%s '%s'\n", CHDIR, basefile);
	X		}
	X	else /* type == 'f' */
	X		{
	X		if (Verbose == TRUE)
	X			printf ("%s \"extracting '%s'\" '(%d character%s)'\n",
	X				ECHO, basefile, size, size > 1 ? "s" : "");
	X
	X		if (Overcheck == TRUE)
	X			{
	X			printf ("if %s -f '%s'\n", TEST, basefile);
	X			printf ("then\n");
	X			printf ("	%s \"will not over-write existing file '%s'\"\n",
	X				ECHO, basefile);
	X			printf ("else\n");
	X			}
	X
	X		}
	X	}
	X
	X/*FUNCTION endfile: do activities after packing up a file */
	Xendfile (basefile, type, size, protection)
	Xchar	*basefile;  /* name of the target file */
	Xint 	type;       /* either 'd' for directory, or 'f' for file */
	Xint 	size;       /* size of the file */
	Xint 	protection; /* chmod protection bits */
	X	{
	X	if (type == 'd')
	X		{
	X		if (Modeset == TRUE)
	X			printf ("%s %o .\n", CHMOD, protection);
	X		if (Verbose == TRUE)
	X			printf ("%s \"done with directory '%s'\"\n", ECHO, basefile);
	X		printf ("%s ..\n", CHDIR);
	X		}
	X	else /* type == 'f' (plain file) */
	X		{
	X		printf ("%s\n", Delim);
	X		if (Count == TRUE)
	X			{
	X			printf ("if %s %d -ne \"`%s '%s'`\"\n", TEST, size, WC_C, basefile);
	X			printf ("then\n");
	X			printf ("	%s \"error transmitting '%s'\" ", ECHO, basefile);
	X			printf ("'(should have been %d character%s)'\n",
	X				size, size == 1 ? "" : "s");
	X			printf ("fi\n");
	X			}
	X		if (Uucode == FALSE) /* might have to chmod by hand */
	X			{
	X			if (Modeset == TRUE) /* set all protection bits (W McKeeman) */
	X				printf ("%s %o '%s'\n",
	X						CHMOD, protection, basefile);
	X			else if (protection & 0111) /* executable -> chmod +x */
	X				printf ("%s +x '%s'\n", CHMOD, basefile);
	X			}
	X		if (Overcheck == TRUE)
	X			printf ("fi\n");
	X		}
	X	}
SHAR_EOF
if test 11109 -ne "`wc -c < 'shar.c'`"
then
	echo shar: "error transmitting 'shar.c'" '(should have been 11109 characters)'
fi
fi
echo shar: "extracting 'traverse.c'" '(1855 characters)'
if test -f 'traverse.c'
then
	echo shar: "will not over-write existing file 'traverse.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'traverse.c'
	X/*LINTLIBRARY*/
	X#ifndef lint
	Xstatic	char	sccsid[] = "@(#)traverse.c 1.0 (WangInst) 12/23/84";
	X#endif
	X
	X#include <stdio.h>
	X#include <sys/types.h>
	X#include <sys/dir.h>
	X
	X#ifdef MAXNAMLEN
	X
	X#define	namedir(entry) (entry->d_name)
	X#define	MAXNAME 256
	X
	X#else
	X
	X#define	DIR	FILE
	X#define	MAXNAME (DIRSIZ+2)
	X#define	opendir(path) fopen (path, "r")
	X#define closedir(dirp) fclose (dirp)
	Xstruct direct *
	Xreaddir (dirp)
	XDIR 	*dirp;
	X	{
	X	static	struct	direct	entry;
	X	if (dirp == NULL) return (NULL);
	X	for (;;)
	X		{
	X		if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
	X		if (entry.d_ino) return (&entry);
	X		}
	X	}
	Xchar	*strncpy ();
	Xchar *
	Xnamedir (entry)
	Xstruct	direct	*entry;
	X	{
	X	static	char	name[MAXNAME];
	X	return (strncpy (name, entry->d_name, DIRSIZ));
	X	}
	X
	X#endif
	X
	X#include <sys/stat.h>
	X#define	isdir(path) (stat(path, &buf) ? 0 : (buf.st_mode&S_IFMT)==S_IFDIR)
	X
	Xtraverse (path, func)
	Xchar	*path;
	Xint 	(*func) ();
	X	{
	X	DIR 	*dirp;
	X	struct	direct	*entry;
	X	struct	stat	buf;
	X	int 	filetype = isdir (path) ? 'd' : 'f';
	X	(*func) (path, filetype, 0);
	X	if (filetype == 'd')
	X		{
	X		if (chdir (path) == 0)
	X			{
	X			if (dirp = opendir ("."))
	X				{
	X				while (entry = readdir (dirp))
	X					{
	X					char	name[MAXNAME];
	X					(void) strcpy (name, namedir (entry));
	X					if (strcmp(name, ".") && strcmp(name, ".."))
	X						traverse (name, func);
	X					}
	X				(void) closedir(dirp);
	X				}
	X			(void) chdir ("..");
	X			}
	X		}
	X	(*func) (path, filetype, 1);
	X	}
	X
	X#ifdef STANDALONE
	X
	Xstatic	Indent = 0;
	Xtryverse (file, type, pos)
	Xchar	*file;
	X	{
	X	int 	in;
	X	if (pos == 0)
	X		{
	X		for (in = 0; in < Indent; in++) putchar ('\t');
	X		if (type == 'd')
	X			{
	X			printf ("%s/\n", file);
	X			Indent++;
	X			}
	X		else puts (file);
	X		}
	X	else if (type == 'd') Indent--;
	X	}
	X
	Xmain (argc, argv) char **argv;
	X	{
	X	int 	tryverse ();
	X	char	*root = argc > 1 ? argv[1] : ".";
	X	traverse (root, tryverse);
	X	}
	X#endif
SHAR_EOF
if test 1855 -ne "`wc -c < 'traverse.c'`"
then
	echo shar: "error transmitting 'traverse.c'" '(should have been 1855 characters)'
fi
fi
echo shar: "extracting 'getopt.c'" '(2996 characters)'
if test -f 'getopt.c'
then
	echo shar: "will not over-write existing file 'getopt.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'getopt.c'
	X/*
	X	I got this off net.sources from Henry Spencer.
	X	It is a public domain getopt(3) like in System V.
	X	I have made the following modifications:
	X
	X	index(s,c) was added because too many people could
	X	not compile getopt without it.
	X
	X	A test main program was added, ifdeffed by GETOPT.
	X	This main program is a public domain implementation
	X	of the getopt(1) program like in System V.  The getopt
	X	program can be used to standardize shell option handling.
	X		e.g.  cc -DGETOPT getopt.c -o getopt
	X*/
	X#include <stdio.h>
	X
	X#ifndef lint
	Xstatic	char	sccsfid[] = "@(#) getopt.c 5.0 (UTZoo) 1985";
	X#endif
	X
	X#define	ARGCH    (int)':'
	X#define BADCH	 (int)'?'
	X#define EMSG	 ""
	X#define	ENDARGS  "--"
	X
	X/* this is included because index is not on some UNIX systems */
	Xstatic
	Xchar *
	Xindex (s, c)
	Xregister	char	*s;
	Xregister	int 	c;
	X	{
	X	while (*s)
	X		if (c == *s) return (s);
	X		else s++;
	X	return (NULL);
	X	}
	X
	X/*
	X * get option letter from argument vector
	X */
	Xint	opterr = 1,		/* useless, never set or used */
	X	optind = 1,		/* index into parent argv vector */
	X	optopt;			/* character checked for validity */
	Xchar	*optarg;		/* argument associated with option */
	X
	X#define tell(s)	fputs(*nargv,stderr);fputs(s,stderr); \
	X		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
	X
	X
	Xgetopt(nargc,nargv,ostr)
	Xint	nargc;
	Xchar	**nargv,
	X	*ostr;
	X{
	X	static char	*place = EMSG;	/* option letter processing */
	X	register char	*oli;		/* option letter list index */
	X	char	*index();
	X
	X	if(!*place) {			/* update scanning pointer */
	X		if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
	X		if (*place == '-') {	/* found "--" */
	X			++optind;
	X			return(EOF);
	X		}
	X	}				/* option letter okay? */
	X	if ((optopt = (int)*place++) == ARGCH || !(oli = index(ostr,optopt))) {
	X		if(!*place) ++optind;
	X		tell(": illegal option -- ");
	X	}
	X	if (*++oli != ARGCH) {		/* don't need argument */
	X		optarg = NULL;
	X		if (!*place) ++optind;
	X	}
	X	else {				/* need an argument */
	X		if (*place) optarg = place;	/* no white space */
	X		else if (nargc <= ++optind) {	/* no arg */
	X			place = EMSG;
	X			tell(": option requires an argument -- ");
	X		}
	X	 	else optarg = nargv[optind];	/* white space */
	X		place = EMSG;
	X		++optind;
	X	}
	X	return(optopt);			/* dump back option letter */
	X}
	X
	X
	X#ifdef GETOPT
	X
	X#ifndef lint
	Xstatic	char	sccspid[] = "@(#) getopt.c 5.1 (WangInst) 6/15/85";
	X#endif
	X
	Xmain (argc, argv) char **argv;
	X	{
	X	char	*optstring = argv[1];
	X	char	*argv0 = argv[0];
	X	extern	int 	optind;
	X	extern	char	*optarg;
	X	int 	opterr = 0;
	X	int 	C;
	X	char	*opi;
	X	if (argc == 1)
	X		{
	X		fprintf (stderr, "Usage: %s optstring args\n", argv0);
	X		exit (1);
	X		}
	X	argv++;
	X	argc--;
	X	argv[0] = argv0;
	X	while ((C = getopt (argc, argv, optstring)) != EOF)
	X		{
	X		if (C == BADCH) opterr++;
	X		printf ("-%c ", C);
	X		opi = index (optstring, C);
	X		if (opi && opi[1] == ARGCH)
	X			if (optarg)
	X				printf ("\"%s\" ", optarg);
	X			else opterr++;
	X		}
	X	printf ("%s", ENDARGS);
	X	while (optind < argc)
	X		printf (" \"%s\"", argv[optind++]);
	X	putchar ('\n');
	X	exit (opterr);
	X	}
	X
	X#endif
SHAR_EOF
if test 2996 -ne "`wc -c < 'getopt.c'`"
then
	echo shar: "error transmitting 'getopt.c'" '(should have been 2996 characters)'
fi
fi
echo shar: "extracting 'shar.1'" '(3280 characters)'
if test -f 'shar.1'
then
	echo shar: "will not over-write existing file 'shar.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'shar.1'
	X.TH SHAR 1net "March 4, 1986" "UNIX User's Manual" "Wang Institute"
	X.SH NAME
	Xshar \- create file storage archive for extraction by /bin/sh
	X.SH SYNOPSIS
	X.B shar
	X[-abcmsuv] [-p prefix] [-d delim] files > archive
	X.SH DESCRIPTION
	X.I shar
	Xprints its input files with special command lines around them
	Xto be used by the shell,
	X.I /bin/sh ,
	Xto extract the files later.
	XThe output can be filtered through the shell to
	Xrecreate copies of the original files.
	X.PP
	X.I shar
	Xallows directories to be named, and
	X.I shar
	Xprints the necessary commands
	X.ul
	X(mkdir & cd)
	Xto create new directories and fill them.
	X.I shar
	Xwill not allow existing files to be over-written;
	Xsuch files must be removed by the user extracting the files.
	X.SH OPTIONS
	X.de OP
	X.TP
	X.B -\\$1
	X..
	X.OP a
	XAll the options.
	XThe options:
	X.B "-v -c -b -p <tab>X"
	Xare implied.
	X.OP b
	XExtract files into basenames so that files with absolute path names
	Xare put into the current directory.
	XThis option has strange effects when directories are archived.
	X.OP c
	XCheck file size on extraction by counting characters.
	XAn error message is reported to the person doing the
	Xextraction if the sizes don't match.
	XOne reason why the sizes may not match is that
	X.I shar
	Xwill append a newline to complete incomplete last lines;
	X.I shar
	Xprints a message that mentions added newlines.
	XAnother reason why the sizes may not match is that some
	Xnetwork mail programs remove non-whitespace control characters.
	X.I shar
	Xprints a message that mentions control characters to the extractor.
	X.OP d delim
	XUse this as the ``end of file'' delimiter instead of the default.
	XThe only reason to change it is if you suspect a file
	Xcontains the default delimiter:
	X.B SHAR_EOF.
	X.OP m
	XReset the exact protection modes of files when they are extracted
	X(using the
	X.I chmod
	Xprogram).
	XBy default, the extractor's default file modes are used,
	Xand executable files (e.g., shell scripts)
	Xare made executable.
	X.OP p prefix
	XUse this as the prefix to each line of the archived files.
	XThis is to make sure that special characters at the start of lines are not
	Xeaten up by programs like mailers.
	XIf this option is used,
	Xthe files will be extracted with the stream editor
	X.B sed
	Xrather than
	X.B cat
	Xso it is more efficient and portable to avoid setting the prefix,
	Xthough perhaps less safe if you don't know what is in the files.
	X.OP s
	XSilent running.
	XAll checking and extra output is inhibited.
	X.OP u
	XArchive the input files with the
	X.I uuencode
	Xformat for later extraction with
	X.I uudecode.
	XThis will allow you to send files with control characters in them,
	Xbut will slow down the extracting.
	XYou must be sure that the receiving party has access to uudecode.
	X.OP v
	XPrint verbose feedback messages about what
	X.I shar
	Xis doing to be printed during extraction.
	XSizes of plain files are echoed to allow a simple validity check.
	X.SH "SEE ALSO
	Xsh(1), tar(1), cpio(1), tp(1), uuencode(1), uudecode(1)
	X.br
	Xfpack(1) is a plain-file packer useful for UNIX and MSDOS
	X.SH AUTHOR
	XGary Perlman
	X(based on a shell version by James Gosling,
	Xwith additions motivated by many people on the UNIX network:
	XDerek Zahn,
	XMichael Thompson,
	XH. Morrow Long,
	XFred Avolio,
	XGran Uddeborg,
	XChuck Wegrzyn,
	Xnucleus!randy@TORONTO,
	X&
	XBill McKeeman)
	X.SH LIMITATIONS
	X.I shar
	Xdoes not know anything about links between files.
SHAR_EOF
if test 3280 -ne "`wc -c < 'shar.1'`"
then
	echo shar: "error transmitting 'shar.1'" '(should have been 3280 characters)'
fi
fi
echo shar: "extracting 'traverse.3'" '(1169 characters)'
if test -f 'traverse.3'
then
	echo shar: "will not over-write existing file 'traverse.3'"
else
sed 's/^	X//' << \SHAR_EOF > 'traverse.3'
	X.TH TRAVERSE 3WI "December 16, 1984"
	X.SH NAME
	Xtraverse \- recursively traverse a directory
	X.SH SYNOPSIS
	X.nf
	Xtraverse (path, func)
	Xchar	*path;
	Xint 	(*func) ();
	X
	Xfunc (path, filetype, position)
	Xchar	*path;
	X.fi
	X.SH DESCRIPTION
	Xtraverse
	Xapplies its argument function func to its argument file pathname path.
	XIf path is a directory,
	Xthen traverse applies func to all its entries.
	XThis traversal is in depth first order
	Xso that files are processed in the order
	Xthat they are stored in the directory.
	X.PP
	XThe argument func should take three parameters:
	Xa file name,
	Xa file type,
	Xand a position.
	XThe call looks like this for directories:
	X.ce
	X(*func) (path, 'd', position);
	Xand like this for other files:
	X.ce
	X(*func) (path, 'f', position);
	XThe position
	Xis 0 when path is first encountered
	Xand 1 when traverse is done.
	XThis is used to allow processing before and after
	Xa directory is processed.
	X.SH EXAMPLE
	X.nf
	Xlist (name, type, pos)
	Xchar	*name;
	X	{
	X	if (type == 'd')
	X		printf ("%s %s\en", pos ? "Leaving" : "Entering", name);
	X	else /* type == 'f' */
	X		printf ("	%s\en", name);
	X	}
	X.fi
	X.SH AUTHOR
	XGary Perlman
	X.SH BUGS
	XThere are no diagnostics when directories cannot be searched.
SHAR_EOF
if test 1169 -ne "`wc -c < 'traverse.3'`"
then
	echo shar: "error transmitting 'traverse.3'" '(should have been 1169 characters)'
fi
fi
echo shar: "extracting 'getopt.3'" '(2686 characters)'
if test -f 'getopt.3'
then
	echo shar: "will not over-write existing file 'getopt.3'"
else
sed 's/^	X//' << \SHAR_EOF > 'getopt.3'
	X.TH GETOPT 3 local
	X.DA 25 March 1982
	X.SH NAME
	Xgetopt \- get option letter from argv
	X.SH SYNOPSIS
	X.ft B
	Xint getopt(argc, argv, optstring)
	X.br
	Xint argc;
	X.br
	Xchar **argv;
	X.br
	Xchar *optstring;
	X.sp
	Xextern char *optarg;
	X.br
	Xextern int optind;
	X.ft
	X.SH DESCRIPTION
	X.I Getopt
	Xreturns the next option letter in
	X.I argv
	Xthat matches a letter in
	X.IR optstring .
	X.I Optstring
	Xis a string of recognized option letters;
	Xif a letter is followed by a colon, the option is expected to have
	Xan argument that may or may not be separated from it by white space.
	X.I Optarg
	Xis set to point to the start of the option argument on return from
	X.IR getopt .
	X.PP
	X.I Getopt
	Xplaces in
	X.I optind
	Xthe
	X.I argv
	Xindex of the next argument to be processed.
	XBecause
	X.I optind
	Xis external, it is normally initialized to zero automatically
	Xbefore the first call to 
	X.IR getopt .
	X.PP
	XWhen all options have been processed (i.e., up to the first
	Xnon-option argument),
	X.I getopt
	Xreturns
	X.BR EOF .
	XThe special option
	X.B \-\-
	Xmay be used to delimit the end of the options;
	X.B EOF
	Xwill be returned, and
	X.B \-\-
	Xwill be skipped.
	X.SH SEE ALSO
	Xgetopt(1)
	X.SH DIAGNOSTICS
	X.I Getopt
	Xprints an error message on
	X.I stderr
	Xand returns a question mark
	X.RB ( ? )
	Xwhen it encounters an option letter not included in
	X.IR optstring .
	X.SH EXAMPLE
	XThe following code fragment shows how one might process the arguments
	Xfor a command that can take the mutually exclusive options
	X.B a
	Xand
	X.BR b ,
	Xand the options
	X.B f
	Xand
	X.BR o ,
	Xboth of which require arguments:
	X.PP
	X.RS
	X.nf
	Xmain(argc, argv)
	Xint argc;
	Xchar **argv;
	X{
	X	int c;
	X	extern int optind;
	X	extern char *optarg;
	X	\&.
	X	\&.
	X	\&.
	X	while ((c = getopt(argc, argv, "abf:o:")) != EOF)
	X		switch (c) {
	X		case 'a':
	X			if (bflg)
	X				errflg++;
	X			else
	X				aflg++;
	X			break;
	X		case 'b':
	X			if (aflg)
	X				errflg++;
	X			else
	X				bproc();
	X			break;
	X		case 'f':
	X			ifile = optarg;
	X			break;
	X		case 'o':
	X			ofile = optarg;
	X			break;
	X		case '?':
	X		default:
	X			errflg++;
	X			break;
	X		}
	X	if (errflg) {
	X		fprintf(stderr, "Usage: ...");
	X		exit(2);
	X	}
	X	for (; optind < argc; optind++) {
	X		\&.
	X		\&.
	X		\&.
	X	}
	X	\&.
	X	\&.
	X	\&.
	X}
	X.RE
	X.PP
	X.SH HISTORY
	XWritten by Henry Spencer, working from a Bell Labs manual page.
	XBehavior believed identical to the Bell version.
	X.SH BUGS
	XIt is not obvious how
	X`\-'
	Xstanding alone should be treated;  this version treats it as
	Xa non-option argument, which is not always right.
	X.PP
	XOption arguments are allowed to begin with `\-';
	Xthis is reasonable but reduces the amount of error checking possible.
	X.PP
	X.I Getopt
	Xis quite flexible but the obvious price must be paid:  there is much
	Xit could do that it doesn't, like
	Xchecking mutually exclusive options, checking type of
	Xoption arguments, etc.
SHAR_EOF
if test 2686 -ne "`wc -c < 'getopt.3'`"
then
	echo shar: "error transmitting 'getopt.3'" '(should have been 2686 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Gary Perlman  Wang Institute  Tyngsboro, MA 01879  (617) 649-9731
UUCP: decvax!wanginst!perlman             CSNET: perlman@wanginst