1#!/bin/sh
2# UNISRC_ID: @(#)shar.sh	27.1	84/12/17  
3: Make a shell archive package
4
5# Usage: $0 [-b] [-c] [-t] [-v] files... > package
6# See the manual entry for details.
7
8
9# Initialize:
10
11diagnostic='eval echo >&2'	# diagnostics to stderr by default.
12trap '$diagnostic "$0: quitting early"; exit 1' 1 2 3 15
13base_option=FALSE		# use pathnames, not basenames.
14check_option=FALSE		# don't generate integrity check.
15USAGE='Usage: $0 \[-b] \[-c] \[-t] \[-v] files... \> package'
16
17
18# Extract and digest options, if any:
19#
20# Un-comment the "-)" line below to treat single dashes as a no-op.
21# Commented means single dashes elicit a usage diagnostic.
22
23while [ -n "$1" ]	# while there are more arguments,
24do			# digest them; stop when you find a non-option.
25	case "$1" in
26	-b)	base_option=TRUE;	shift;;
27	-c)	check_option=TRUE;	shift;;
28	-v)	verbose=TRUE;		shift;;
29	-t)	verbose=TRUE; diagnostic='eval echo >/dev/tty'; shift;;
30###	-)	shift;;		# if uncommented, eat single dashes.
31	-*)	$diagnostic $USAGE; exit 1;;	 # die at illegal options.
32	*)	break;;		# non-option found.
33	esac
34done
35
36
37# Check remaining arguments, which should be just a list of files:
38
39if [ $# = 0 ]
40then	# no arguments left!
41	$diagnostic $USAGE
42	exit 1
43fi
44
45
46# Check the cupboard to see if the ingredients are all there:
47
48contents=''	# no files so far.
49contdirs=''	# no directories so far.
50
51for arg		# for all files specified,
52do		# establish the archive name.
53	if [ -f "$arg" ]
54	then	# file exists and is not a directory.
55		case $base_option in
56		TRUE)	unpack_name=`basename "$arg"` ;;
57		FALSE)	unpack_name="$arg" ;;
58		esac
59
60		contents="$contents $unpack_name"
61
62	elif [ -d "$arg" ]
63	then	# file exists and is a directory.
64		case $base_option in
65		TRUE)   $diagnostic '$0: cannot archive directory "$arg" with -b option.'
66			exit 1 ;;
67		FALSE)  contdirs="$contdirs $arg/ " ;;
68		esac
69
70	else	# not a plain file and not a directory.
71		$diagnostic '$0: cannot archive "$arg"'
72		exit 1
73	fi
74done
75
76
77# Emit the prologue:
78# (The leading newline is for those who type csh instead of sh.)
79
80cat <<!!!
81
82# This is a shell archive.  Remove anything before this line,
83# then unpack it by saving it in a file and typing "sh file".
84#
85# Wrapped by `who am i | sed 's/[ 	].*//'` on `date`
86!!!
87
88
89# Emit the list of ingredients:
90
91# Simple version (breaks if you shar lots of files at once):
92#	echo "# Contents: $contdirs$contents"
93#
94# Complex and cosmetic version to pack contents list onto lines that fit on
95# one terminal line ("expr string : .*" prints the length of the string):
96
97MAX=80
98line='# Contents: '
99for item in $contdirs $contents
100do
101	if [ `expr "$line" : '.*' + 1 + "$item" : '.*'` -lt $MAX ]
102	then	# length of old line + new item is short enough,
103		line="$line $item"	# so just append it.
104
105	else	# new element makes line too long,
106		echo "$line"		# so put it on a new line.
107		line="#	$item"		# start a new line.
108		MAX=74			# compensate for tab width.
109	fi
110done
111
112echo "$line"
113echo " "
114
115
116# Emit the files and their separators:
117
118for arg
119do
120	# Decide which name to archive under.
121	case $base_option in
122	TRUE)   unpack_name=`basename "$arg"`
123		test $verbose && $diagnostic "a - $unpack_name [from $arg]" ;;
124	FALSE)  unpack_name="$arg"
125		test $verbose && $diagnostic "a - $arg" ;;
126	esac
127
128	# Emit either a mkdir or a cat/sed to extract the file.
129	if [ -d "$arg" ]
130	then
131		echo "echo mkdir - $arg"
132		echo "mkdir $arg"
133	else
134		echo "echo x - $unpack_name"
135		separator="@//E*O*F $unpack_name//"
136		echo "sed 's/^@//' > \"$unpack_name\" <<'$separator'"
137		sed  -e 's/^[.~@]/@&/'  -e 's/^From/@&/'  "$arg"
138		echo $separator
139	fi
140
141	# Emit chmod to set permissions on the extracted file;
142	# this keels over if the filename contains "?".
143	ls -ld $arg | sed \
144		-e 's/^.\(...\)\(...\)\(...\).*/u=\1,g=\2,o=\3/' \
145		-e 's/-//g' \
146		-e 's?.*?chmod & '"$unpack_name?"
147	echo " "
148done
149
150
151# If the -c option was given, emit the checking epilogue:
152# (The sed script converts files to basenames so it works regardless of -b.)
153
154if [ $check_option = TRUE ]
155then
156	echo 'echo Inspecting for damage in transit...'
157	echo 'temp=/tmp/shar$$; dtemp=/tmp/.shar$$'
158	echo 'trap "rm -f $temp $dtemp; exit" 0 1 2 3 15'
159	echo 'cat > $temp <<\!!!'
160	case $base_option in
161	TRUE)   wc $@ | sed 's=[^ ]*/=='	;;
162	FALSE)  wc $contents | sed 's=[^ ]*/=='	;;
163	esac
164	echo '!!!'
165	echo "wc $contents | sed 's=[^ ]*/==' | "'diff -b $temp - >$dtemp'
166	echo 'if [ -s $dtemp ]'
167	echo 'then echo "Ouch [diff of wc output]:" ; cat $dtemp'
168	echo 'else echo "No problems found."'
169	echo 'fi'
170fi
171
172
173# Finish up:
174
175echo 'exit 0'	# sharchives unpack even if junk follows.
176exit 0
177