Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP
Path: utzoo!decvax!genrad!bd@hpdsb.UUCP
From: bd@hpdsb.UUCP
Newsgroups: mod.sources
Subject: Re: The Connoisseur's Shar, version 2
Message-ID: <542@genrad.UUCP>
Date: Thu, 20-Dec-84 10:07:34 EST
Article-I.D.: genrad.542
Posted: Thu Dec 20 10:07:34 1984
Date-Received: Fri, 21-Dec-84 06:38:26 EST
Sender: john@genrad.UUCP
Lines: 314
Approved: john@genrad.UUCP

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by john on Thu Dec 20 10:04:09 EST 1984
# Contents:  shar shar.l
 
echo x - shar
sed 's/^@//' > "shar" <<'@//E*O*F shar//'

# UNISRC_ID: @(#)shar.sh	27.1	84/12/17  
: Make a shell archive package

# Usage: $0 [-b] [-c] [-t] [-v] files... > package
# See the manual entry for details.


# Initialize:

diagnostic='eval echo >&2'	# diagnostics to stderr by default.
trap '$diagnostic "$0: quitting early"; exit 1' 1 2 3 15
base_option=FALSE		# use pathnames, not basenames.
check_option=FALSE		# don't generate integrity check.
USAGE='Usage: $0 \[-b] \[-c] \[-t] \[-v] files... \> package'


# Extract and digest options, if any:
#
# Un-comment the "-)" line below to treat single dashes as a no-op.
# Commented means single dashes elicit a usage diagnostic.

while [ -n "$1" ]	# while there are more arguments,
do			# digest them; stop when you find a non-option.
	case "$1" in
	-b)	base_option=TRUE;	shift;;
	-c)	check_option=TRUE;	shift;;
	-v)	verbose=TRUE;		shift;;
	-t)	verbose=TRUE; diagnostic='eval echo >/dev/tty'; shift;;
###	-)	shift;;		# if uncommented, eat single dashes.
	-*)	$diagnostic $USAGE; exit 1;;	 # die at illegal options.
	*)	break;;		# non-option found.
	esac
done


# Check remaining arguments, which should be just a list of files:

if [ $# = 0 ]
then	# no arguments left!
	$diagnostic $USAGE
	exit 1
fi


# Check the cupboard to see if the ingredients are all there:

contents=''	# no files so far.
contdirs=''	# no directories so far.

for arg		# for all files specified,
do		# establish the archive name.
	if [ -f "$arg" ]
	then	# file exists and is not a directory.
		case $base_option in
		TRUE)	unpack_name=`basename "$arg"` ;;
		FALSE)	unpack_name="$arg" ;;
		esac

		contents="$contents $unpack_name"

	elif [ -d "$arg" ]
	then	# file exists and is a directory.
		case $base_option in
		TRUE)   $diagnostic '$0: cannot archive directory "$arg" with -b option.'
			exit 1 ;;
		FALSE)  contdirs="$contdirs $arg/ " ;;
		esac

	else	# not a plain file and not a directory.
		$diagnostic '$0: cannot archive "$arg"'
		exit 1
	fi
done


# Emit the prologue:
# (The leading newline is for those who type csh instead of sh.)

cat < \"$unpack_name\" <<'$separator'"
		sed  -e 's/^[.~@]/@&/'  -e 's/^From/@&/'  "$arg"
		echo $separator
	fi

	# Emit chmod to set permissions on the extracted file;
	# this keels over if the filename contains "?".
	ls -ld $arg | sed \
		-e 's/^.\(...\)\(...\)\(...\).*/u=\1,g=\2,o=\3/' \
		-e 's/-//g' \
		-e 's?.*?chmod & '"$unpack_name?"
	echo " "
done


# If the -c option was given, emit the checking epilogue:
# (The sed script converts files to basenames so it works regardless of -b.)

if [ $check_option = TRUE ]
then
	echo 'echo Inspecting for damage in transit...'
	echo 'temp=/tmp/shar$$; dtemp=/tmp/.shar$$'
	echo 'trap "rm -f $temp $dtemp; exit" 0 1 2 3 15'
	echo 'cat > $temp <<\!!!'
	case $base_option in
	TRUE)   wc $@ | sed 's=[^ ]*/=='	;;
	FALSE)  wc $contents | sed 's=[^ ]*/=='	;;
	esac
	echo '!!!'
	echo "wc $contents | sed 's=[^ ]*/==' | "'diff -b $temp - >$dtemp'
	echo 'if [ -s $dtemp ]'
	echo 'then echo "Ouch [diff of wc output]:" ; cat $dtemp'
	echo 'else echo "No problems found."'
	echo 'fi'
fi


# Finish up:

echo 'exit 0'	# sharchives unpack even if junk follows.
exit 0
@//E*O*F shar//
chmod u=rwx,g=rx,o=rx shar
 
echo x - shar.l
sed 's/^@//' > "shar.l" <<'@//E*O*F shar.l//'
@.TH SHAR LOCAL HEWLETT-PACKARD
@.ad b
@.SH NAME
shar \- make a shell archive package
@.SH SYNOPSIS
\fBshar\fR [\fB-b\fR] [\fB-c\fR] [\fB-t\fR] [\fB-v\fR] file ...
@.SH DESCRIPTION
@.I Shar
bundles the named
@.IR file ( s )
into a single distribution package suitable for mailing or carrying around.
The files should be mailable (not object code, for instance).
@.IR Shar 's
resulting package, written to standard output, is an editable file.
It is actually a shell script using
@.IR sh (1)
"here" documents to extract its contents into the appropriate places.
@.PP
The package is unwrapped by running
@.IR sh
with the package name as an argument.
Its files are written to the pathnames recorded in the archive,
then permissions are set via
@.IR chmod (1)
to match the original files.
@.PP
Except with the
@.B \-b
option, a directory tree
@.I dir
can be archived using the command "shar `find
@.I dir
-print`".
@.PP
Available options are:
@.TP
@.B \-b
Archive files under their basenames, regardless of the original pathnames
specified.
The contents are thus unpacked into the current directory instead of to the
originally-specified pathnames.
This allows you to archive files from many directories but unpack them into a
single directory.
It also allows you to unpack, say,
@.I /etc/termcap
into
@.I ./termcap
instead of overwriting the original one in
@.IR /etc .
@.TP
@.B \-c
Append to the package a simple data-integrity check using
@.IR wc (1)
to insure that the contents were not damaged in transit.
This check will be performed automatically after unpacking.
@.TP
@.B \-t
Write diagnostics and messages directly to your terminal,
instead of to the standard error.  This is useful when invoking
@.I shar
from programs such as
@.IR vi (1)
which normally combine standard error with standard output.
Specifying
@.B \-t
also turns on the
@.B \-v
(verbose) option.
@.TP
@.B \-v
Announce archived file names as they are packed.
The
@.B \-t
option determines the destination for these announcements.
@.br
@.ne 5
@.SH FILES
/dev/tty               	if specified with \fB-t\fR
@.br
/tmp/shar*, /tmp/.shar*	when inspecting for damage
@.br
cat, echo, sed, chmod  	as subprocesses
@.br
basename, wc, mkdir    	as optional subprocesses
@.SH DIAGNOSTICS
@.I Shar
refuses to archive nonexistent files.
When the
@.B \-b
option is used, it refuses to archive directories.
@.I Shar
terminates and does no archiving if it encounters either problem.
@.PP
Exit status 1 is returned upon interrupt or trouble with arguments.
@.SH "SEE ALSO"
ar(1),
cpio(1),
find(1),
tar(1).
@.SH BUGS
Archived directories must appear before the files in them.  Failure to adhere
to this ordering is not detected, but the result will fail to unpack.
@.PP
Ownerships for archived files are not retained.
@.PP
The integrity check is very simple-minded.
In particular, it notices only if the number of characters, words, or lines
is altered; it fails to catch bits flipped during transmission.
@.PP
@.I Shar
should complain about binary files.
It should also complain about filenames with embedded spaces and
question marks, which
@.IR shar 's
subprocesses don't handle.
@.PP
There should be a standard way
to record the system on which the archive was created.
Berkeley hosts return this information via
@.IR "who am i" ,
but Bell-derived hosts often use wildly differing methods.
@//E*O*F shar.l//
chmod u=rw,g=rw,o=r shar.l
 
exit 0