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