[comp.sources.unix] v15i018: Tools to create and unpack shell archives, Part01/03

rsalz@uunet.uu.net (Rich Salz) (05/28/88)

Submitted-by: Rich Salz <rsalz@uunet.uu.net>
Posting-number: Volume 15, Issue 18
Archive-name: cshar/part01

[  I will soon be posting a variant of this package that handles the
   missing features, for those who want or need them.  --r$  ]

This set of tools is designed to make it easier to ship sources around.  I
wrote them because I do a lot of that as moderator of comp.sources.unix,
and nothing else did the job for me.  This set isn't perfect, but's very
close.  Included are a program to find source files, a program to
partition them into reasonable sizes, a program to make shell archives out
of them, a program to strip mail, news, and notes headers from archives
before feeding them to a shell, and a program that simulates enough
/bin/sh syntax so that non-Unix systems can unpack them.

I believe this works under MSDOS.  If you have diffs, send them to me.
Owen at Oxford Trading Partners, oxtrap!osm, ported an earlier version to
MSDOS; I hope I didn't break anything when I merged his changes into what
I've got now.  Same for Amiga and other PC's.  I might do a VMS port.  The
dir.msdos shar (which I haven't touched) seems to be solid; I don't know
about the dir.amiga code.

I freely stole ideas from a number of people who have been good enough to
put their stuff out on Usenet.  Particular thanks to Gary Perlman and
Larry Wall for giving me something nice to reverse-engineer, and Michael
Mauldin for unshar.  People who sent significant comments and fixes from
earlier versions include Bob Desinger, Darryl Ohahato, Jamie Watson, Joel
Shprentz, Ken Yap, Matt Landau, Paul Vixie, Shane McCarron, Tim Pointing,
Tom Beattie, Vital Dobroey, and Don Libes.  Thanks to all of them,
particularly Paul for an amazing number of comments on earlier versions.

On a philosophical note, I've tried to make this all as general as
possible for shipping sources around.  I'm not interested in binaries, so
things like automatically running uuencode don't interest me a great
deal.  I haven't come up with a good portable way to split files into
pieces if they're too large, and doubt I ever will.  There are too many
installation parameters, but I'm not particularly worried about that:  Once
you get things working, consider it incentive to avoid future changes.
It would be nice if I could use Larry's meta-Config, but that only works
on Unix-type systems.
	/rich $alz

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 3)."
# Contents:  MANIFEST Makefile README config.h dir.msdos findsrc.man
#   glue.c lcwd.c lexec.c lfiles.c lhost.c llib.c lmem.c luser.c
#   makekit.man patchlevel.h shar.h shar.man shell.c shell.man
#   unshar.man
# Wrapped by rsalz@fig.bbn.com on Fri May 27 14:15:05 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1725 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   1	Control file for Unix make program
X README                     1	Acknowledgements, installation notes
X config.h                   1	Default configuration file
X dir.amiga                  2	A partial Amiga readdir package
X dir.msdos                  1	An MS-DOS readdir package
X findsrc.c                  2	Find source files, based on filename
X findsrc.man                1	Manual page for findsrc
X glue.c                     1	Glue that so unshar uses my /bin/sh parser
X lcwd.c                     1	Routines to find current directory
X lexec.c                    1	Fork, exec, system, signal, etc., routines
X lfiles.c                   1	File size and type routines
X lhost.c                    1	Find our machine name
X llib.c                     1	Stuff that should be in your C library
X lmem.c                     1	Memory allocator, uses calloc
X luser.c                    1	Get user's name
X makekit.c                  2	Partition files into reasonable-sized kits
X makekit.man                1	Manual page for makekit
X parser.c                   3	Interpreter for shell archives
X patchlevel.h               1	Mistake recorder
X shar.c                     2	Create script to create files
X shar.h                     1	Header file, used by everyone
X shar.man                   1	Manual page for makekit
X shell.c                    1	Main routine for my shell interpreter
X shell.man                  1	Manual page for shell
X unshar.c                   2	Strip news, notes, mail headers from shar's
X unshar.man                 1	Manual page for unshar
END_OF_FILE
if test 1725 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(3261 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X##
X##  SOURCE-SHIPPING TOOLS MAKEFILE
X##  $Header: Makefile,v 2.0 88/05/27 13:29:42 rsalz Exp $
X##  $Log:	Makefile,v $
X# Revision 2.0  88/05/27  13:29:42  rsalz
X# First comp.sources.unix release
X# 
X##
X
X## Grrrr...
SHELL	= /bin/sh
X
X##  Edit appropriately, such as -g if you don't trust me...
CFLAGS	= -O
X
X##  Where the readdir() and friends are, if not in your C library.
X#DIRLIB	= -lndir
X
X##  Use these two lines if you use ranlib...
AR_OBJ	= $(LIB_OBJ)
RANLIB	= ranlib lib.a
X##  ...or use these two if you need tsort instead...
X#AR_OBJ	= `lorder $(LIB_OBJ) | tsort`
X#RANLIB	= @echo
X##  ...or these two if you need neither.
X#AR_OBJ	= $(LIB_OBJ)
X#RANLIB	= @echo
X
X##  Where executables should be put.
DESTDIR	= /usr/local/bin
X
X##  The "foo" manpage will get put in $(MANDIR)/foo.$1
MANDIR	= /usr/man/man1
X1	= 1
X#MANDIR	= /usr/man/u_man/manl
X#1	= 1L
X
X##
X##  END OF CONFIGURATION SECTION
X##
X
X##  Header files.
HDRS	= shar.h config.h
LIB	= lib.a $(DIRLIB)
X
X##  Programs and documentation.
PROGRAMS= findsrc    makekit    shar    unshar    shell
MANPAGES= findsrc.$1 makekit.$1 shar.$1 unshar.$1 shell.$1
X
X##  Our library of utility functions.
LIB_SRC	= glue.c parser.c lcwd.c lexec.c lfiles.c lhost.c llib.c lmem.c luser.c
LIB_OBJ	= glue.o parser.o lcwd.o lexec.o lfiles.o lhost.o llib.o lmem.o luser.o
X
X
all:		$(PROGRAMS) $(MANPAGES)
X	touch all
X
X##  You might want to change these actions...
install:	all
X	cd $(DESTDIR) ; rm -f $(PROGRAMS)
X	cp $(PROGRAMS) $(DESTDIR)
X	cd $(DESTDIR) ; strip $(PROGRAMS) ; chmod 755 $(PROGRAMS)
X#	cd $(DESTDIR) ; /etc/chown root $(PROGRAMS)
X	cd $(MANDIR) ; rm -f $(MANPAGES)
X	cp $(MANPAGES) $(MANDIR)
X	touch install
X
clean:
X	rm -f *.[oa] *.$1 *.BAK $(PROGRAMS) unshar.safe
X	rm -f lint lib.ln tags core foo a.out Part?? all install
X
X
X##  Creating manpages.
X.SUFFIXES:	.$1 .man
X.man.$1:
X	@rm -f $@
X	cp $< $@
X	chmod 444 $@
X
X
X##  Programs.
findsrc:	findsrc.o $(HDRS) $(LIB)
X	@rm -f $@
X	$(CC) $(CFLAGS) -o findsrc findsrc.o $(LIB)
X
makekit:	makekit.o $(HDRS) $(LIB)
X	@rm -f $@
X	$(CC) $(CFLAGS) -o makekit makekit.o $(LIB)
X
shar:		shar.o $(HDRS) $(LIB)
X	@rm -f $@
X	$(CC) $(CFLAGS) -o shar shar.o $(LIB)
X
shell:		shell.o $(HDRS) $(LIB)
X	@rm -f $@
X	$(CC) $(CFLAGS) -o shell shell.o $(LIB)
X
unshar:		unshar.o $(HDRS) $(LIB)
X	@rm -f $@
X	$(CC) $(CFLAGS) -o unshar unshar.c $(LIB)
X
X
X##  Special case, a version of unshar that uses the /bin/sh interpreter.
unshar.safe:	unshar.c $(HDRS) $(LIB)
X	@rm -f $@
X	@rm -f unshar.o
X	$(CC) $(CFLAGS) -DUSE_MY_SHELL -o unshar unshar.c $(LIB)
X	@rm -f unshar.o
X
X
X##  Support your local library.
lib.a:		$(LIB_OBJ)
X	@rm -f $@
X	ar r lib.a $(AR_OBJ)
X	$(RANLIB)
X$(LIB_OBJ):	$(HDRS)
X
X
X##  Lint; this is probably only good for BSD-derived lints.
X##  Ultrix 1.2 lint really hates the !var construct, for some reason.
X#LINTF	= -p -ahb
LINTF	= -ahb
X##  A slight speed hack...
XX	= exec
lint:		$(PROGRAMS) lib.ln
X	@rm -f $@
X	$X lint $(LINTF) -u  >lint $(LIB_SRC)
X	$X lint $(LINTF)    >>lint findsrc.c lib.ln
X	$X lint $(LINTF)    >>lint makekit.c lib.ln
X	$X lint $(LINTF)    >>lint shar.c    lib.ln
X	$X lint $(LINTF)    >>lint shell.c   lib.ln
X	$X lint $(LINTF)    >>lint unshar.c  lib.ln
X#	$X lint $(LINTF) -DUSE_MY_SHELL >>lint unshar.c  lib.ln
X
lib.ln:		$(LIB_SRC)
X	@rm -f $@
X	lint -CX $(LIB_SRC)
X	mv llib-lX.ln lib.ln
END_OF_FILE
if test 3261 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3392 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
This set of tools is designed to make it easier to ship sources around.  I
wrote them because I do a lot of that as moderator of comp.sources.unix,
and nothing else did the job for me.  This set isn't perfect, but's very
close.  Included are a program to find source files, a program to
partition them into reasonable sizes, a program to make shell archives out
of them, a program to strip mail, news, and notes headers from archives
before feeding them to a shell, and a program that simulates enough
X/bin/sh syntax so that non-Unix systems can unpack them.
X
The sources in this distribution are being released into the public
domain; do what you want, but let your conscience be your guide.  If you
somehow enhance this package, please send it on to me so that others can
benefit.
X
I'll try to answer any questions or problems that come up -- send me
electronic mail.
X
To install, edit the Makefile and config.h as necessary then run make;
doing make install will put the manpages and executables where you told
it to.  I don't think "make lint" will be totally reasonable except on
a BSD-derived system, but you can try.  If you write config.h files for
other systems, send them to me.
X
If you aren't running on Unix, then you will have to write replacements
for the functions in the lxxxx.c files; everything else should be OK.  If
you find something in another file that you had to change, please let me
know.  If you don't have a Unix-like make available, you will have to
write a command script or otherwise work out something with your compiler,
linker, etc.
X
I believe this works under MSDOS.  If you have diffs, send them to me.
Owen at Oxford Trading Partners, oxtrap!osm, ported an earlier version to
MSDOS; I hope I didn't break anything when I merged his changes into what
I've got now.  Same for Amiga and other PC's.  I might do a VMS port.  The
dir.msdos shar (which I haven't touched) seems to be solid; I don't know
about the dir.amiga code.
X
I freely stole ideas from a number of people who have been good enough to
put their stuff out on Usenet.  Particular thanks to Gary Perlman and
Larry Wall for giving me something nice to reverse-engineer, and Michael
Mauldin for unshar.  People who sent significant comments and fixes from
earlier versions include Bob Desinger, Darryl Ohahato, Jamie Watson, Joel
Shprentz, Ken Yap, Matt Landau, Paul Vixie, Shane McCarron, Tim Pointing,
Tom Beattie, Vital Dobroey, and Don Libes.  Thanks to all of them,
particularly Paul for an amazing number of comments on earlier versions.
X
On a philosophical note, I've tried to make this all as general as
possible for shipping sources around.  I'm not interested in binaries, so
things like automatically running uuencode don't interest me a great
deal.  I haven't come up with a good portable way to split files into
pieces if they're too large, and doubt I ever will.  There are too many
installation parameters, but I'm not particularly worried about that:  Once
you get things working, consider it incentive to avoid future changes.
It would be nice if I could use Larry's meta-Config, but that only works
on Unix (and Eunice).  Send me your config.h file so that others can benefit.
X
XEnjoy!
X	Rich $alz
X	BBN Laboratories, Inc.
X	10 Moulton Street
X	Cambridge, MA  02238
X	rsalz@bbn.com
X	rsalz@uunet.uu.net
X
My, my, my, aren't we anal:
X	$Header: README,v 2.0 88/05/27 13:29:50 rsalz Exp $
END_OF_FILE
if test 3392 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'config.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(4142 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/*
X**  Configuration file for shar and friends.
X**
X**  This is known to work on Ultrix1.2 and Sun3.4 machines; it may work
X**  on other BSD variants, too.
X**
X**  $Header: config.h,v 2.0 88/05/27 13:15:39 rsalz Exp $
X*/
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		index		/* Maybe strchr?		*/
X#define RDX		rindex		/* Maybe strrchr?		*/
X/*efine NEED_MKDIR			/* Don't have mkdir(2)?		*/
X/*efine NEED_QSORT			/* Don't have qsort(3)?		*/
X#define NEED_GETOPT			/* Need local getopt object?	*/
X#define CAN_POPEN			/* Can invoke file(1) command?	*/
X/*efine USE_MY_SHELL			/* Don't popen("/bin/sh")?	*/
typedef int		 sigret_t;	/* What a signal handler returns */
typedef int		*align_t;	/* Worst-case alignment, for lint */
X/* typedef long		time_t		/* Needed for non-BSD sites?	*/
X/* typedef long		off_t		/* Needed for non-BSD sites?	*/
X/*efine void		int		/* If you don't have void	*/
X#define SYS_WAIT			/* Have <sys/wait.h> and vfork?	*/
X/*efine USE_SYSTEM			/* Use system(3), not exec(2)?	*/
X#define USE_SYSERRLIST			/* Have sys_errlist[], sys_nerr? */
X#define USE_GETPWUID			/* Use getpwuid(3)?		*/
X#define DEF_SAVEIT	1		/* Save headers by default?	*/
X/*efine FMT02d				/* Need "%02.2d", not "%2.2d"?	*/
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	"USER"		/* Your name, if not in environ	*/
X#define PTR_SPRINTF			/* Need extern char *sprinf()?	*/
X/*efine ANSI_HDRS			/* Use <stdlib.h>, etc.?	*/
X#define REGISTER	register	/* Do you trust your compiler?	*/
X
X
X/*
X**  There are several ways to get current machine name.  Enable just one
X**  of one of the following lines.
X*/
X#define GETHOSTNAME			/* Use gethostname(2) call	*/
X/*efine UNAME				/* Use uname(2) call		*/
X/*efine UUNAME				/* Invoke "uuname -l"		*/
X/*efine	WHOAMI				/* Try /etc/whoami & <whoami.h>	*/
X/*efine 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#define GETWD				/* Use getwd(3) routine		*/
X/*efine 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 tweaks 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#define IN_SYS_DIR			/* <sys/dir.h>			*/
X/*efine 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**  Congratulations, you're done!
X*/
END_OF_FILE
if test 4142 -ne `wc -c <'config.h'`; then
    echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'dir.msdos' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dir.msdos'\"
else
echo shar: Extracting \"'dir.msdos'\" \(6547 characters\)
sed "s/^X//" >'dir.msdos' <<'END_OF_FILE'
X#! /bin/sh
X# This is a shell archive.  Remove anything before this line, then unpack
X# it by saving it into a file and typing "sh file".  To overwrite existing
X# files, type "sh file -c".  You can also feed this as standard input via
X# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
X# will see the following message at the end:
X#		"End of shell archive."
X# Contents:  msd_dir.c msd_dir.h
X# Wrapped by rsalz@fig.bbn.com on Thu May 26 16:06:31 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'msd_dir.c' -a "${1}" != "-c" ; then 
X  echo shar: Will not clobber existing file \"'msd_dir.c'\"
else
echo shar: Extracting \"'msd_dir.c'\" \(4114 characters\)
sed "s/^X//" >'msd_dir.c' <<'END_OF_FILE'
XX/*
XX * @(#)msd_dir.c 1.4 87/11/06	Public Domain.
XX *
XX *  A public domain implementation of BSD directory routines for
XX *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
XX *  August 1897
XX */
XX
XX#include	<sys/types.h>
XX#include	<sys/stat.h>
XX#include	<sys/dir.h>
XX#include	<malloc.h>
XX#include	<string.h>
XX#include	<dos.h>
XX
XX#ifndef	NULL
XX# define	NULL	0
XX#endif	/* NULL */
XX
XX#ifndef	MAXPATHLEN
XX# define	MAXPATHLEN	255
XX#endif	/* MAXPATHLEN */
XX
XX/* attribute stuff */
XX#define	A_RONLY		0x01
XX#define	A_HIDDEN	0x02
XX#define	A_SYSTEM	0x04
XX#define	A_LABEL		0x08
XX#define	A_DIR		0x10
XX#define	A_ARCHIVE	0x20
XX
XX/* dos call values */
XX#define	DOSI_FINDF	0x4e
XX#define	DOSI_FINDN	0x4f
XX#define	DOSI_SDTA	0x1a
XX
XX#define	Newisnull(a, t)		((a = (t *) malloc(sizeof(t))) == (t *) NULL)
XX#define	ATTRIBUTES		(A_DIR | A_HIDDEN | A_SYSTEM)
XX
XX/* what find first/next calls look use */
typedef struct {
XX	char		d_buf[21];
XX	char		d_attribute;
XX	unsigned short	d_time;
XX	unsigned short	d_date;
XX	long		d_size;
XX	char		d_name[13];
XX} Dta_buf;
XX
static	char	*getdirent();
static	void	setdta();
static	void	free_dircontents();
XX
static	Dta_buf		dtabuf;
static	Dta_buf		*dtapnt = &dtabuf;
static	union REGS	reg, nreg;
XX
XX#if	defined(M_I86LM)
static	struct SREGS	sreg;
XX#endif
XX
DIR	*
opendir(name)
XX	char	*name;
XX{
XX	struct	stat		statb;
XX	DIR			*dirp;
XX	char			c;
XX	char			*s;
XX	struct _dircontents	*dp;
XX	char			nbuf[MAXPATHLEN + 1];
XX	
XX	if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
XX		return (DIR *) NULL;
XX	if (Newisnull(dirp, DIR))
XX		return (DIR *) NULL;
XX	if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
XX		(void) strcat(strcpy(nbuf, name), "\\*.*");
XX	else
XX		(void) strcat(strcpy(nbuf, name), "*.*");
XX	dirp->dd_loc = 0;
XX	setdta();
XX	dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
XX	if ((s = getdirent(nbuf)) == (char *) NULL)
XX		return dirp;
XX	do {
XX		if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
XX			malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
XX		{
XX			if (dp)
XX				free((char *) dp);
XX			free_dircontents(dirp->dd_contents);
XX			return (DIR *) NULL;
XX		}
XX		if (dirp->dd_contents)
XX			dirp->dd_cp = dirp->dd_cp->_d_next = dp;
XX		else
XX			dirp->dd_contents = dirp->dd_cp = dp;
XX		(void) strcpy(dp->_d_entry, s);
XX		dp->_d_next = (struct _dircontents *) NULL;
XX	} while ((s = getdirent((char *) NULL)) != (char *) NULL);
XX	dirp->dd_cp = dirp->dd_contents;
XX
XX	return dirp;
XX}
XX
void
closedir(dirp)
XX	DIR	*dirp;
XX{
XX	free_dircontents(dirp->dd_contents);
XX	free((char *) dirp);
XX}
XX
struct direct	*
readdir(dirp)
XX	DIR	*dirp;
XX{
XX	static	struct direct	dp;
XX	
XX	if (dirp->dd_cp == (struct _dircontents *) NULL)
XX		return (struct direct *) NULL;
XX	dp.d_namlen = dp.d_reclen =
XX		strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
XX	dp.d_ino = 0;
XX	dirp->dd_cp = dirp->dd_cp->_d_next;
XX	dirp->dd_loc++;
XX
XX	return &dp;
XX}
XX
void
seekdir(dirp, off)
XX	DIR	*dirp;
XX	long	off;
XX{
XX	long			i = off;
XX	struct _dircontents	*dp;
XX
XX	if (off < 0)
XX		return;
XX	for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
XX		;
XX	dirp->dd_loc = off - (i + 1);
XX	dirp->dd_cp = dp;
XX}
XX
long
telldir(dirp)
XX	DIR	*dirp;
XX{
XX	return dirp->dd_loc;
XX}
XX
static	void
free_dircontents(dp)
XX	struct	_dircontents	*dp;
XX{
XX	struct _dircontents	*odp;
XX
XX	while (dp) {
XX		if (dp->_d_entry)
XX			free(dp->_d_entry);
XX		dp = (odp = dp)->_d_next;
XX		free((char *) odp);
XX	}
XX}
XX
static	char	*
getdirent(dir)
XX	char	*dir;
XX{
XX	if (dir != (char *) NULL) {		/* get first entry */
XX		reg.h.ah = DOSI_FINDF;
XX		reg.h.cl = ATTRIBUTES;
XX#if	defined(M_I86LM)
XX		reg.x.dx = FP_OFF(dir);
XX		sreg.ds = FP_SEG(dir);
XX#else
XX		reg.x.dx = (unsigned) dir;
XX#endif
XX	} else {				/* get next entry */
XX		reg.h.ah = DOSI_FINDN;
XX#if	defined(M_I86LM)
XX		reg.x.dx = FP_OFF(dtapnt);
XX		sreg.ds = FP_SEG(dtapnt);
XX#else
XX		reg.x.dx = (unsigned) dtapnt;
XX#endif
XX	}
XX#if	defined(M_I86LM)
XX	intdosx(&reg, &nreg, &sreg);
XX#else
XX	intdos(&reg, &nreg);
XX#endif
XX	if (nreg.x.cflag)
XX		return (char *) NULL;
XX
XX	return dtabuf.d_name;
XX}
XX
static	void
setdta()
XX{
XX	reg.h.ah = DOSI_SDTA;
XX#if	defined(M_I86LM)
XX	reg.x.dx = FP_OFF(dtapnt);
XX	sreg.ds = FP_SEG(dtapnt);
XX	intdosx(&reg, &nreg, &sreg);
XX#else
XX	reg.x.dx = (int) dtapnt;
XX	intdos(&reg, &nreg);
XX#endif
XX}
XEND_OF_FILE
if test 4114 -ne `wc -c <'msd_dir.c'`; then
X    echo shar: \"'msd_dir.c'\" unpacked with wrong size!
fi
X# end of 'msd_dir.c'
fi
if test -f 'msd_dir.h' -a "${1}" != "-c" ; then 
X  echo shar: Will not clobber existing file \"'msd_dir.h'\"
else
echo shar: Extracting \"'msd_dir.h'\" \(954 characters\)
sed "s/^X//" >'msd_dir.h' <<'END_OF_FILE'
XX/*
XX * @(#)msd_dir.h 1.4 87/11/06	Public Domain.
XX *
XX *  A public domain implementation of BSD directory routines for
XX *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
XX *  August 1897
XX */
XX
XX#define	rewinddir(dirp)	seekdir(dirp, 0L)
XX
XX#define	MAXNAMLEN	12
XX
struct direct {
XX	ino_t	d_ino;			/* a bit of a farce */
XX	int	d_reclen;		/* more farce */
XX	int	d_namlen;		/* length of d_name */
XX	char	d_name[MAXNAMLEN + 1];		/* garentee null termination */
XX};
XX
struct _dircontents {
XX	char	*_d_entry;
XX	struct _dircontents	*_d_next;
XX};
XX
typedef struct _dirdesc {
XX	int		dd_id;	/* uniquely identify each open directory */
XX	long		dd_loc;	/* where we are in directory entry is this */
XX	struct _dircontents	*dd_contents;	/* pointer to contents of dir */
XX	struct _dircontents	*dd_cp;	/* pointer to current position */
XX} DIR;
XX
extern	DIR		*opendir();
extern	struct direct	*readdir();
extern	void		seekdir();
extern	long		telldir();
extern	void		closedir();
XEND_OF_FILE
if test 954 -ne `wc -c <'msd_dir.h'`; then
X    echo shar: \"'msd_dir.h'\" unpacked with wrong size!
fi
X# end of 'msd_dir.h'
fi
echo shar: End of shell archive.
exit 0
END_OF_FILE
if test 6547 -ne `wc -c <'dir.msdos'`; then
    echo shar: \"'dir.msdos'\" unpacked with wrong size!
fi
# end of 'dir.msdos'
fi
if test -f 'findsrc.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'findsrc.man'\"
else
echo shar: Extracting \"'findsrc.man'\" \(1859 characters\)
sed "s/^X//" >'findsrc.man' <<'END_OF_FILE'
X.TH FINDSRC 1l
X.\" $Header: findsrc.man,v 2.0 88/05/27 13:28:20 rsalz Exp $
X.SH NAME
findsrc \- walk directories, trying to find source files
X.SH SYNOPSIS
X.B findsrc
X[
X.B \-.
X] [
X.BI \-d\| y_or_n
X] [
X.BI \-o\| output_file
X] [
X.B \-R
X] [
X.B \-S
X] [
X.B \-v
X] [ file... ]
X.SH DESCRIPTION
X.I Findsrc
recursively examines all directories and files specified on the command
line, and determines, based on the file name, whether the file contains
source code or not.
All directories are listed first, followed by all regular files,
with one item per line.
X.PP
If
X.I findsrc
is unable to make a decision, it invokes the
X.IR file (1)
command, and prompts the user for a decision.
In reply to the prompt, type the letter ``y'' or ``n'' (either case);
RETURN means yes.
If the reply starts with an exclamation point, the rest of the line
is passed off to a sub-shell and the question is repeated.
The ``\-d'' option may be used with an argument of ``y'' or ``n''
to by-pass the interaction, and provide a default answer.
X.PP
The ``\-o'' option may be used to specify an output filename.
This is designed to prevent confusion if a command like the following
is executed:
X.RS
findsrc . * >LIST
X.RE
X.PP
By default,
X.I findsrc
ignores files whose names begin with a period, like ``.newsrc'' or
X``.tags''; such files may be included by using the ``\-.'' option.
X.I Findsrc
also normally ignores
RCS and SCCS files and directories; using either the ``\-R'' or ``\-S''
option causes both to be included.
X.PP
X.I Findsrc
normally lists only the names of those files that have been selected.
If the ``\-v'' option is used, rejected files are also listed preceeded
by the word ``PUNTED.''
X.PP
If no files are specified on the command line, the program operates as
a filter, reading a list of files and directories from the standard
input, one per line.
X.SH "SEE ALSO"
makekit(1l).
END_OF_FILE
if test 1859 -ne `wc -c <'findsrc.man'`; then
    echo shar: \"'findsrc.man'\" unpacked with wrong size!
fi
# end of 'findsrc.man'
fi
if test -f 'glue.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'glue.c'\"
else
echo shar: Extracting \"'glue.c'\" \(1239 characters\)
sed "s/^X//" >'glue.c' <<'END_OF_FILE'
X/*
X**  Subroutine to call the shell archive parser.  This is "glue"
X**  between unshar and the parser proper.
X*/
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: glue.c,v 2.0 88/05/27 13:26:14 rsalz Exp $";
X#endif	/* RCSID */
X
X
X#ifdef	USE_MY_SHELL
X/*
X**  Cleanup routine after BinSh is done
X*/
void
BSclean()
X{
X    (void)fclose(Input);
X    (void)unlink(File);
X}
X
X
X/*
X**  Copy the input to a temporary file, then call the shell parser.
X*/
BinSh(Name, Stream, Pushback)
X    char		*Name;
X    REGISTER FILE	*Stream;
X    char		*Pushback;
X{
X    REGISTER FILE	*F;
X    char		 buff[BUFSIZ];
X    char		*vec[MAX_WORDS];
X
X    Interactive = Name == NULL;
X#ifdef	MSDOS
X    File = "shell.XXX";
X    onexit(BSclean);
X#else
X    File = mktemp("/tmp/shellXXXXXX");
X#endif	/* MSDOS */
X
X    F = fopen(File, "w");
X    (void)fputs(Pushback, F);
X    while (fgets(buff, sizeof buff, Stream))
X	(void)fputs(buff, F);
X    (void)fclose(Stream);
X
X    if ((Input = fopen(TEMP, "r")) == NULL)
X	Fprintf(stderr, "Can't open %s, %s!?\n", TEMP, Ermsg(errno));
X    else
X	while (GetLine(TRUE)) {
X#ifdef	MSDOS
X	    if (setjmp(jEnv))
X		break;
X#endif	/* MSDOS */
X	    if (Argify(vec) && Exec(vec) == -FALSE)
X		    break;
X	}
X
X    BSclean();
X}
X#endif	/* USE_MY_SHELL */
END_OF_FILE
if test 1239 -ne `wc -c <'glue.c'`; then
    echo shar: \"'glue.c'\" unpacked with wrong size!
fi
# end of 'glue.c'
fi
if test -f 'lcwd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lcwd.c'\"
else
echo shar: Extracting \"'lcwd.c'\" \(1110 characters\)
sed "s/^X//" >'lcwd.c' <<'END_OF_FILE'
X/*
X**  Return current working directory.  Something for everyone.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: lcwd.c,v 2.0 88/05/27 13:26:24 rsalz Exp $";
X#endif	/* RCSID */
X
X
X#ifdef	PWDGETENV
X/* ARGSUSED */
char *
Cwd(p, i)
X    char	*p;
X    int		 i;
X{
X    char	*q;
X
X    return((q = getenv(PWDGETENV)) ? strcpy(p, q) : NULL);
X}
X#endif	/* PWDGETENV */
X
X
X#ifdef	GETWD
X/* ARGSUSED1 */
char *
Cwd(p, size)
X    char	*p;
X    int		 size;
X{
X    extern char	*getwd();
X
X    return(getwd(p) ? p : NULL);
X}
X#endif	/* GETWD */
X
X
X#ifdef	GETCWD
char *
Cwd(p, size)
X    char	*p;
X    int		 size;
X{
X    extern char	*getcwd();
X
X    return(getcwd(p, size) ? p : NULL);
X}
X#endif	/* GETCWD */
X
X
X#ifdef	PWDPOPEN
char *
Cwd(p, size)
X    char	*p;
X    int		 size;
X{
X    extern FILE	*popen();
X    FILE	*F;
X    int		 i;
X
X    /* This string could be "exec /bin/pwd" if you want... */
X    if (F = popen("pwd", "r")) {
X	if (fgets(p, size, F) && p[i = strlen(p) - 1] == '\n') {
X	    p[i] = '\0';
X	    (void)fclose(F);
X	    return(p);
X	}
X	(void)fclose(F);
X    }
X    return(NULL);
X}
X#endif	/* PWDPOPEN */
END_OF_FILE
if test 1110 -ne `wc -c <'lcwd.c'`; then
    echo shar: \"'lcwd.c'\" unpacked with wrong size!
fi
# end of 'lcwd.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'\" \(2062 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
static 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#include <sys/wait.h>
X#define FORK()		 vfork()
X#define W_VAL(w)	 ((w).w_retcode)
typedef union wait	 WAITER;
X#else
X#define FORK()		 fork()
X#define W_VAL(w)	 ((w) >> 8)
typedef int		 WAITER;
X#endif	/* SYS_WAIT */
X
X
X
X/*
X**  Set up a signal handler.
X*/
SetSigs(What, Func)
X    int		  What;
X    sigret_t	(*Func)();
X{
X    if (What == S_IGNORE)
X	Func = SIG_IGN;
X    else if (What == S_RESET)
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}
X
X
X/*
X**  Return the process ID.
X*/
int
Pid()
X{
X#ifdef	MSDOS
X    return(1);
X#else
X    static int	 X;
X
X    if (X == 0)
X	X = getpid();
X    return(X);
X#endif	/* MSDOS */
X}
X
X
X#ifndef	USE_SYSTEM
X/*
X**  Fork off a command.
X*/
int
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(S_RESET, (sigret_t (*)())NULL);
X	(void)execvp(av[0], av);
X	perror(av[0]);
X	_exit(1);
X    }
X
X    SetSigs(S_IGNORE, (sigret_t (*)())NULL);
X    while ((j = wait(&W)) < 0 && j != i)
X	;
X    SetSigs(S_RESET, (sigret_t (*)())NULL);
X    return(W_VAL(W));
X}
X
X#else
X
X/*
X**  Cons all the arguments together into a single command line and hand
X**  it off to the shell to execute.
X*/
int
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 = 0, v = av; *v; v++)
X	i += strlen(*v) + 1;
X
X    /* Create command line and execute it. */
X    p = NEW(char, i);
X    for (q = p, v = av; *v; v++) {
X	*q++ = ' ';
X	q += strlen(strcpy(q, *v));
X    }
X
X    return(system(p));
X}
X#endif	/* USE_SYSTEM */
END_OF_FILE
if test 2062 -ne `wc -c <'lexec.c'`; then
    echo shar: \"'lexec.c'\" unpacked with wrong size!
fi
# end of 'lexec.c'
fi
if test -f 'lfiles.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lfiles.c'\"
else
echo shar: Extracting \"'lfiles.c'\" \(1007 characters\)
sed "s/^X//" >'lfiles.c' <<'END_OF_FILE'
X/*
X**  File related routines.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#include <sys/stat.h>
X#ifdef	RCSID
static char RCS[] =
X	"$Header: lfiles.c,v 2.0 88/05/27 13:26:47 rsalz Exp $";
X#endif	/* RCSID */
X
X
X/* Mask of executable bits. */
X#define	EXE_MASK	(S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6))
X
X/* Stat buffer for last file. */
static struct stat	 Sb;
X
X
X/*
X**  Stat the file if it's not the one we did last time.
X*/
int
GetStat(p)
X    char		*p;
X{
X    static char		 Name[BUFSIZ];
X
X    if (*p == Name[0] && EQ(p, Name))
X	return(TRUE);
X    return(stat(strcpy(Name, p), &Sb) < 0 ? FALSE : TRUE);
X}
X
X
X/*
X**  Return the file type -- directory or regular file.
X*/
int
XFtype(p)
X    char	*p;
X{
X    return(GetStat(p) && ((Sb.st_mode & S_IFMT) == S_IFDIR) ? F_DIR : F_FILE);
X}
X
X
X/*
X**  Return the file size.
X*/
off_t
XFsize(p)
X    char	*p;
X{
X    return(GetStat(p) ? Sb.st_size : 0);
X}
X
X
X/*
X**  Is a file executable?
X*/
int
XFexecute(p)
X    char	*p;
X{
X    return(GetStat(p) && (Sb.st_mode & EXE_MASK) ? TRUE : FALSE);
X}
END_OF_FILE
if test 1007 -ne `wc -c <'lfiles.c'`; then
    echo shar: \"'lfiles.c'\" unpacked with wrong size!
fi
# end of 'lfiles.c'
fi
if test -f 'lhost.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lhost.c'\"
else
echo shar: Extracting \"'lhost.c'\" \(1714 characters\)
sed "s/^X//" >'lhost.c' <<'END_OF_FILE'
X/*
X**  Return name of this host.  Something for everyone.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: lhost.c,v 2.0 88/05/27 13:27:01 rsalz Exp $";
X#endif	/* RCSID */
X
X
X#ifdef	HOST
char *
Host()
X{
X    return(HOST);
X}
X#endif	/* HOST */
X
X
X#ifdef	GETHOSTNAME
char *
Host()
X{
X    static char		 buff[64];
X
X    return(gethostname(buff, sizeof buff) < 0 ? "SITE" : buff);
X}
X#endif	/* GETHOSTNAME */
X
X
X#ifdef	UNAME
X#include <sys/utsname.h>
char *
Host()
X{
X    static struct utsname	 U;
X
X    return(uname(&U) < 0 ? "SITE" : U.nodename);
X}
X#endif	/* UNAME */
X
X
X#ifdef	UUNAME
extern FILE	*popen();
char *
Host()
X{
X    static char		 buff[50];
X    FILE		*F;
X    char		*p;
X
X    if (F = popen("exec uuname -l", "r")) {
X	if (fgets(buff, sizeof buff, F) == buff && (p = IDX(buff, '\n'))) {
X	    (void)pclose(F);
X	    *p = '\0';
X	    return(buff);
X	}
X	(void)pclose(F);
X    }
X    return("SITE");
X}
X#endif	/* UUNAME */
X
X
X#ifdef	WHOAMI
char *
Host()
X{
X    static char		 name[64];
X    REGISTER FILE	*F;
X    REGISTER char	*p;
X    char		 buff[100];
X
X    /* Try /etc/whoami; look for a single well-formed line. */
X    if (F = fopen("/etc/whoami", "r")) {
X	if (fgets(name, sizeof name, F) && (p = IDX(name, '\n'))) {
X	    (void)fclose(F);
X	    *p = '\0';
X	    return(name);
X	}
X	(void)fclose(F);
X    }
X
X    /* Try /usr/include/whoami.h; look for #define sysname "foo" somewhere. */
X    if (F = fopen("/usr/include/whoami.h", "r")) {
X	while (fgets(buff, sizeof buff, F))
X	    /* I don't like sscanf, nor do I trust it.  Sigh. */
X	    if (sscanf(buff, "#define sysname \"%[^\"]\"", name) == 1) {
X		(void)fclose(F);
X		return(name);
X	    }
X	(void)fclose(F);
X    }
X    return("SITE");
X}
X#endif /* WHOAMI */
END_OF_FILE
if test 1714 -ne `wc -c <'lhost.c'`; then
    echo shar: \"'lhost.c'\" unpacked with wrong size!
fi
# end of 'lhost.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'\" \(3393 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.  I put Ermsg() here so that everyone will need
X**  something from this file...
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: llib.c,v 2.0 88/05/27 13:27:09 rsalz Exp $";
X#endif	/* RCSID */
X
X
X/*
X**  Return the text string that corresponds to errno.
X*/
char *
XErmsg(e)
X    int			 e;
X{
X#ifdef	USE_SYSERRLIST
X    extern int		 sys_nerr;
X    extern char		*sys_errlist[];
X#endif	/* USE_SYSERRLIST */
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    (void)sprintf(buff, "Error code %d", e);
X    return(buff);
X}
X
X
X
X#ifdef	NEED_MKDIR
X/*
X**  Quick and dirty mkdir routine for them that's need it.
X*/
int
mkdir(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	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, hence the name.  If I were to put this into my C library,
X**  I'd do two things:
X**	-Make it be a quicksort;
X**	-Have a front routine which called specialized routines for
X**	 cases where Width equals sizeof(int), sizeof(char *), etc.
X*/
qsort(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)	if(opterr){\
X	char errbuf[2];\
X	errbuf[0] = c; errbuf[1] = '\n';\
X	(void) write(2, argv[0], (TYPE)strlen(argv[0]));\
X	(void) write(2, s, (TYPE)strlen(s));\
X	(void) write(2, errbuf, 2);}
X
extern int strcmp();
X
int	opterr = 1;
int	optind = 1;
int	optopt;
char	*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*/
int
getopt(argc, argv, opts)
int	argc;
char	**argv, *opts;
X{
X	static int sp = 1;
X	REGISTER int c;
X	REGISTER char *cp;
X
X	if(sp == 1)
X		if(optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		else if(strcmp(argv[optind], "--") == NULL) {
X			optind++;
X
X		}
X	optopt = c = argv[optind][sp];
X	if(c == ':' || (cp=IDX(opts, c)) == NULL) {
X		ERR(": illegal option -- ", c);
X		if(argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return('?');
X	}
X	if(*++cp == ':') {
X		if(argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if(++optind >= argc) {
X			ERR(": option requires an argument -- ", c);
X			sp = 1;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if(argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
X
X#endif	/* NEED_GETOPT */
END_OF_FILE
if test 3393 -ne `wc -c <'llib.c'`; then
    echo shar: \"'llib.c'\" unpacked with wrong size!
fi
# end of 'llib.c'
fi
if test -f 'lmem.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lmem.c'\"
else
echo shar: Extracting \"'lmem.c'\" \(579 characters\)
sed "s/^X//" >'lmem.c' <<'END_OF_FILE'
X/*
X**  Get some memory or die trying.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: lmem.c,v 2.0 88/05/27 13:27:16 rsalz Exp $";
X#endif	/* RCSID */
X
X
align_t
getmem(i, j)
X    unsigned int	 i;
X    unsigned int	 j;
X{
X    extern char		*calloc();
X    align_t		 p;
X
X    /* Lint fluff:  "possible pointer alignment problem." */
X    if ((p = (align_t)calloc(i, j)) == NULL) {
X	/* Print the unsigned values as int's so ridiculous values show up. */
X	Fprintf(stderr, "Can't Calloc(%d,%d), %s.\n", i, j, Ermsg(errno));
X	exit(1);
X    }
X    return(p);
X}
END_OF_FILE
if test 579 -ne `wc -c <'lmem.c'`; then
    echo shar: \"'lmem.c'\" unpacked with wrong size!
fi
# end of 'lmem.c'
fi
if test -f 'luser.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'luser.c'\"
else
echo shar: Extracting \"'luser.c'\" \(727 characters\)
sed "s/^X//" >'luser.c' <<'END_OF_FILE'
X/*
X**  Get user name.  Something for everyone.
X*/
X/* LINTLIBRARY */
X#include "shar.h"
X#ifdef	USE_GETPWUID
X#include <pwd.h>
X#endif	/* USE_GETPWUID */
X#ifdef	RCSID
static char RCS[] =
X	"$Header: luser.c,v 2.0 88/05/27 13:27:23 rsalz Exp $";
X#endif	/* RCSID */
X
X
X/*
X**  Get user name.  Not secure, but who sends nastygrams as shell archives?
X*/
char *
User()
X{
X#ifdef	USE_GETPWUID
X    extern struct passwd	*getpwuid();
X    struct passwd		*p;
X#endif	/* USE_GETPWUID */
X    char			*g;
X
X    if (g = getenv("USER"))
X	return(g);
X    if (g = getenv("LOGNAME"))
X	return(g);
X    if (g = getenv("NAME"))
X	return(g);
X#ifdef	USE_GETPWUID
X    if (p = getpwuid(getuid()))
X	return(p->pw_name);
X#endif	/* USE_GETPWUID */
X    return(USERNAME);
X}
END_OF_FILE
if test 727 -ne `wc -c <'luser.c'`; then
    echo shar: \"'luser.c'\" unpacked with wrong size!
fi
# end of 'luser.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'\" \(4320 characters\)
sed "s/^X//" >'makekit.man' <<'END_OF_FILE'
X.TH MAKEKIT 1l
X.\" $Header: makekit.man,v 2.0 88/05/27 13:28:41 rsalz Exp $
X.SH NAME
makekit \- split files up into shell archive packages
X.SH SYNOPSIS
X.B makekit
X[
X.B -1
X] [
X[
X.B -e
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] [ file... ]
X.SH DESCRIPTION
X.I Makekit
reads a list of files and directories, determines their sizes,
and parcels them up into a series of shell archives such that all the
archives are of reasonable size.
It then invokes
X.IR shar (1l)
to actually create the archives.
X.PP
By default, no archive will be larger than about 50,000 bytes; this may be
changed by using the ``\-s'' option.
If the number given with the ``\-s'' option ends with the letter ``k''
then the size is multiplied by 1024, otherwise it is taken to be the
desired maximum size, in bytes.
XEach archive will have a name that looks like
X.IR Part nn,
where ``nn'' represents the two-digit sequence number (with leading zero
if needed).
The leader part of the archive name may be changed with the ``\-n'' option.
The ``\-n'' is also useful when write permission to the directory being
archive is denied; e.g., ``\-n/tmp/KERNEL.''
X.PP
X.I Makekit
reads its list of files on the command line, or standard input
if none are given.
It is also possible to specify an input filename with the ``\-i'' option.
The input should contain a list of files, one to a line, to separate.
In addition, if each input line looks like this:
X.RS
filename\ \ \ whitespace\ \ \ optional-digits\ \ \ whitespace\ \ \ text
X.RE
then
X.I makekit
will ignore the spaces and digits, but remember the text associated with
each file, and output it with the filename when generating the ``shipping
manifest.''
XFurther, the ``\-h'' option may be given to have the program skip the
indicated number of lines in the input; this option is provided so that
X.I makekit
can more easily re-parse the manifests it has generated.
X.PP
The generated manifest will be sent to the standard output.
An alternate output file may be given by using the ``\-o'' option; if
the output file exists,
X.I makekit
will try to rename it with an extension of
X.IR \&.BAK \&.
If the ``\-o'' option is used,
X.I makekit
will add that name to the list of files to be archived; the ``\-e''
option may be given to exclude the manifest from the list.
X.PP
The ``\-m'' option is the same as giving the options,
X\&``-iMANIFEST -oMANIFEST -h2.''
This is a common way to regenerate a set of archives after the first
use of
X.I makekit
in a directory.
X.PP
If a large number of kits has to be generated, you may need to give
the ``\-k'' option to increase the maximum number of kits to be
generated.
X.PP
After partitioning the files and directories,
X.I makekit
calls
X.I shar
with the proper options to generate archives in a series.
XEach resultant archive will, when executed, check to see if all the parts
are present.
If the ``\-1'' option is used, then
X.I makekit
will not instruct
X.I shar
to generate the checks (by not passing on the ``\-n'' and ``\-e'' options).
By using the ``\-t'' option, you can specify a line of starting instructions
to display to the recipient when all pieces have been unpacked.
This is useful when resending part of a series that has probably already
been unpacked by the recipient.
See
X.I shar
for more information on multi-part archives.
If the ``\-x'' option is used,
X.I shar
is not called, but the manifest is still created.
X.PP
X.I Makekit
normally reorders its input so that the archives are as ``dense'' as
possible, with the exception that directories are given priority over
files, and a file named
X.I README
is the first of all.
The manifest is also sorted in alphabetical order; this makes it easy
to locate ``missing'' files when the distribution is a large one.
The ``\-p'' option may be used to override both sortings, however,
and preserve the original order of the input list in generating
both the manifest, and the shell archives.
X.SH NOTES
X.I Makekit
tries to partition the files so that all directories are in the first archive.
This usually means the first archive must be the first one to be unpacked.
X.PP
Saying ``the `\-k' option is to help prevent runaway packaging'' is probably
X.I "post hoc propter hoc"
reasoning.
X.SH "SEE ALSO"
findsrc(1l), shar(1l)
END_OF_FILE
if test 4320 -ne `wc -c <'makekit.man'`; then
    echo shar: \"'makekit.man'\" unpacked with wrong size!
fi
# end of 'makekit.man'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(214 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X/*
X**  This file records official patches.  RCS records the edit log.
X**
X**  $Log:	patchlevel.h,v $
X**  Revision 2.0  88/05/27  13:32:13  rsalz
X**  First comp.sources.unix release
X**  
X**  
X*/
X#define PATCHLEVEL 0
END_OF_FILE
if test 214 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
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'\" \(3038 characters\)
sed "s/^X//" >'shar.h' <<'END_OF_FILE'
X/*
X**  Header file for shar and friends.
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.0 88/05/27 13:28:00 rsalz Exp $
X*/
X
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#else
X#include <stdio.h>
X#ifdef	VMS
X#include <types.h>
X#else
X#include <sys/types.h>
X#endif	/* VMS */
X#include <ctype.h>
X#include <setjmp.h>
X#endif	/* ANSI_HDRS */
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
X#define FALSE		0
X#define WIDTH		72
X#define F_DIR		36		/* Something is a directory	*/
X#define F_FILE		65		/* Something is a regular file	*/
X#define S_IGNORE	76		/* Ignore this signal		*/
X#define S_RESET		90		/* Reset signal to default	*/
X
X/* These are used by the archive parser. */
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
X
X/*
X**  Lint placation.
X*/
X#ifdef	lint
X#undef RCSID
X#undef putchar
X#endif	/* lint */
X#define Fprintf		(void)fprintf
X#define Printf		(void)printf
X
X
X/*
X**  Memory hacking.
X*/
X#define NEW(T, count)	((T *)getmem(sizeof (T), (unsigned int)(count)))
X#define ALLOC(n)	getmem(1, (unsigned int)(n))
X#define COPY(s)		strcpy(NEW(char, strlen((s)) + 1), (s))
X
X
X/*
X**  Macros.
X*/
X#define BADCHAR(c)	(iscntrl((c)) && !isspace((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*/
extern int	 errno;
extern int	 optind;
extern char	*optarg;
X
X/* From your C run-time library. */
extern FILE	*popen();
extern time_t	 time();
extern long	 atol();
extern char	*IDX();
extern char	*RDX();
extern char	*ctime();
extern char	*gets();
extern char	*mktemp();
extern char	*strcat();
extern char	*strcpy();
extern char	*strncpy();
extern char   	*getenv();
X#ifdef	PTR_SPRINTF
extern char	*sprintf();
X#endif	/* PTR_SPRINTF */
X
X/* From our local library. */
extern align_t	 getmem();
extern off_t	 Fsize();
extern char	*Copy();
extern char	*Cwd();
extern char	*Ermsg();
extern char	*Host();
extern char	*User();
X
X/* Exported by the archive parser. */
extern jmp_buf	 jEnv;
extern FILE	*Input;			/* Current input stream		*/
extern char	*File;			/* Input filename		*/
extern int	 Interactive;		/* isatty(fileno(stdin))?	*/
extern void	 SetVar();		/* Shell variable assignment	*/
extern void	 SynErr();		/* Fatal syntax error		*/
END_OF_FILE
if test 3038 -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'\" \(2967 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
shar \- create shell archive file for extraction by /bin/sh
X.SH SYNOPSIS
X.B shar
X[
X.B \-b
X] [
X.BI \-i\| input_file
X] [
X.BI \-n\| seq_number
X] [
X.BI \-e\| seq_end
X] [
X.BI \-o\| output_file
X] [
X.BI \-t\| final_text
X] [file...]
X.SH DESCRIPTION
X.I Shar
takes a list of files, and generates a
X.IR /bin/sh
script that, when executed, will re-create those files in a different
directory or on a different machine.
The resultant script will use
X.IR wc (1)
to do a mild error-check, and will warn about possibly-omitted
control characters.
X.PP
X.I Shar
generates scripts that will make directories and plain files.
It will not try to generate intermediate filenames, however, so
X.RS
shar foo/bar/file
X.RE
will not work.  Do
X.RS
shar foo foo/bar foo/bar/file
X.RE
instead.
X.PP
The script is normally sent to standard output; the ``\-o'' option may be
used to specify an output filename.
This is designed to prevent filling up the disk if
X.RS
shar * >SHAR
X.RE
command is done; do
X.RS
shar -o SHAR *
X.RE
instead.
X.PP
The list of files is normally specified on the command line; the ''\-i''
option may be used instead, to specify a file that contains the list
of files to pack up, one per line.
If the file name is ``-'' the standard input is read.
X.PP
The ``\-b'' option says that all leading directory names should be stripped
from the file when they are packed into the archive.
XFor example,
X.RS
shar -b /etc/termcap
X.RE
creates an archive that, when executed, creates a file named
X``termcap'' in the current directory, rather than overwrite the
host system file.
Note, however, that the scripts generated by
X.I shar
normally refuse to overwrite pre-existing files.
X.SS "Multi\-part Archives"
Most larger software packages are usually sent out in two or more shell
archives.
The ``\-n,'' ``\-e,'' and ``\-t'' options are used to make an archive
that is part of a series.
The individual archives are often called ``kits'' when this is done.
The ``\-n'' option specifies the archive number; the ``\-e'' option species
the highest number in the series.
When executed, the generated archives will then echo messages like
X.RS
shar: End of archive 3 of 9.
X.RE
at their end.
X.PP
In addition, each shar will generate a file named
X.IR ark X isdone .
XEach script will contain a loop to check for the presence of these
files, and indicate to the recipient which archives still need to be
executed.
The ``\-t'' option may be used to give starting instructions to the recipient.
When the scripts determine that all the archives have been unpacked,
the text specified with this flag is displayed.
XFor example,
X.RS
shar -n1 -k9 -t "Now do 'sh ./Configure'" *.c >SHAR
X.RE
Adds commands to output the following when all the archives have been unpacked:
X.RS
X.nf
You have run all 9 archives.
Now do 'sh ./Configure'
X.fi
X.RE
X.SH "SEE ALSO"
echo(1), findsrc(1l), makekit(1l), mkdir(1), sh(1), test(1), unshar(1l),
wc(1).
END_OF_FILE
if test 2967 -ne `wc -c <'shar.man'`; then
    echo shar: \"'shar.man'\" unpacked with wrong size!
fi
# end of 'shar.man'
fi
if test -f 'shell.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shell.c'\"
else
echo shar: Extracting \"'shell.c'\" \(808 characters\)
sed "s/^X//" >'shell.c' <<'END_OF_FILE'
X/*
X**  Stand-alone driver for shell.
X*/
X#include "shar.h"
X#ifdef	RCSID
static char RCS[] =
X	"$Header: shell.c,v 2.0 88/05/27 13:28:06 rsalz Exp $";
X#endif	/* RCSID */
X
X
main(ac, av)
X    REGISTER int	 ac;
X    REGISTER char	*av[];
X{
X    char		*vec[MAX_WORDS];
X    char		 buff[VAR_VALUE_SIZE];
X
X    if (Interactive = ac == 1) {
X	Fprintf(stderr, "Testing shell interpreter...\n");
X	Input = stdin;
X	File = "stdin";
X    }
X    else {
X	if ((Input = fopen(File = av[1], "r")) == NULL)
X	    SynErr("UNREADABLE INPUT");
X	/* Build the positional parameters. */
X	for (ac = 1; av[ac]; ac++) {
X	    (void)sprintf(buff, "%d", ac - 1);
X	    SetVar(buff, av[ac]);
X	}
X    }
X
X    /* Read, parse, and execute. */
X    while (GetLine(TRUE))
X	if (Argify(vec) && Exec(vec) == -FALSE)
X	    break;
X
X    /* That's it. */
X    exit(0);
X}
END_OF_FILE
if test 808 -ne `wc -c <'shell.c'`; then
    echo shar: \"'shell.c'\" unpacked with wrong size!
fi
# end of 'shell.c'
fi
if test -f 'shell.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shell.man'\"
else
echo shar: Extracting \"'shell.man'\" \(1090 characters\)
sed "s/^X//" >'shell.man' <<'END_OF_FILE'
X.TH SHELL 1l
X.\" $Header: shell.man,v 2.0 88/05/27 13:28:55 rsalz Exp $
X.SH NAME
shell \- Interpreter for shell archives
X.SH SYNOPSIS
X.B shell
X[ file...  ]
X.SH DESCRIPTION
This program interprets enough UNIX shell syntax, and command usage,
to enable it to unpack many different types of UNIX shell archives,
or ``shar's.''
It is primarily intended to be used on non-UNIX systems that need to
unpack such archives.
X.PP
X.I Shell
does
X.B not
check for security holes, and will blithely execute commands like
X.RS
cp /dev/null /etc/passwd
X.RE
which, if executed by the super-user, can be disastrous.
X.PP
The
X.I shell
parser is line-based, where lines are then split into tokens; it is not a
true token-based parser.
In general, it is best if all
X.I sh
keywords that can appear alone on a line do so, and that compound
commands (i.e., using a semi-colon) be avoided.
XFor more details on the syntax, see the source (sorry...).
X.SH BUGS
It is probably easier to write a true portable replacement for /bin/sh
than it is to write something which understands all shar formats.
X.SH SEE ALSO
shar(1l).
END_OF_FILE
if test 1090 -ne `wc -c <'shell.man'`; then
    echo shar: \"'shell.man'\" unpacked with wrong size!
fi
# end of 'shell.man'
fi
if test -f 'unshar.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'unshar.man'\"
else
echo shar: Extracting \"'unshar.man'\" \(2326 characters\)
sed "s/^X//" >'unshar.man' <<'END_OF_FILE'
X.TH UNSHAR 1l
X.\" $Header: unshar.man,v 2.0 88/05/27 13:29:02 rsalz Exp $
X.SH NAME
unshar \- unpack shell archives from news, mail, notes, etc.
X.SH SYNOPSIS
X.B unshar
X[
X.BI \-c\| directory
X] [
X.BI \-d\| directory
X] [
X.BI \-h\| file
X] [
X.B \-f
X] [
X.B \-n
X] [
X.B \-s
X] [ file... ]
X.SH DESCRIPTION
X.I Unshar
removes mail and news header lines from its input, and feeds the remainder
to
X.IR /bin/sh (1)
so that a shell archive can be properly unpacked.
If no files are specified,
X.I unshar
reads from standard input.
The program is designed to be useful when unpacking archives directly
from the news or mail systems (e.g., s | unshar).
X.PP
X.I Unshar
normally unpacks its files in the current directory.
Use the ``\-c'' option to have the program change to a new directory
before invoking the shell.
If the directory does not exist, it will try to create it.
If the directory name starts with a question mark, then
X.I unshar
will ask for the directory name before doing anything; this is most useful
with the environment variable UNSHAREDIR.
If the directory name starts with a tilde, then the value of the HOME
environment variable is inserted in place of that character.
XFor convenience, the ``\-d'' option is a synonym for the ``\-c'' option.
X.PP
X.I Unshar
normally complains if the input looks like something other than a shar file.
X(Among other things, it checks for files that resemble C, and Pascal code).
It can be fooled, however, by nonstandard versions of news, notes, etc.
The ``\-f'' option forces
X.I unshar
to try unpacking files, even if they look like something else.
X.PP
Depending on how the program is installed,
X.I unshar
may or may not try to preserve the header part of file ``foo''
into the name ``foo.hdr'' (if the file is standard input, the name
will be ``UNSHAR.HDR'').
Using the ``\-s'' option forces the program to save the headers, while
using the ``\-n'' option forces it to discard the headers.
The file is appended to, if it already exists, so all headers can be easily
saved in one file.
The name of the file may be given by using the ``\-h'' option; this is
particularly useful when processing more than one file at a time.
X.SH ENVIRONMENT
X.ta \w'UNSHAREDIR  'u
HOME	Value used if a leading tilde is given in directory name.
X.br
UNSHAREDIR	Default value for ``\-c'' option.
X.SH SEE ALSO
shar(1).
END_OF_FILE
if test 2326 -ne `wc -c <'unshar.man'`; then
    echo shar: \"'unshar.man'\" unpacked with wrong size!
fi
# end of 'unshar.man'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    echo "See the README"
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.