3 ## GNU shtool -- The GNU Portable Shell Tool
4 ## Copyright (c) 1994-2001 Ralf S. Engelschall <rse@engelschall.com>
6 ## See http://www.gnu.org/software/shtool/ for more information.
7 ## See ftp://ftp.gnu.org/gnu/shtool/ for latest version.
9 ## Version: 1.5.2 (27-Feb-2001)
10 ## Contents: 3/17 available modules
14 ## This program is free software; you can redistribute it and/or modify
15 ## it under the terms of the GNU General Public License as published by
16 ## the Free Software Foundation; either version 2 of the License, or
17 ## (at your option) any later version.
19 ## This program is distributed in the hope that it will be useful,
20 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ## General Public License for more details.
24 ## You should have received a copy of the GNU General Public License
25 ## along with this program; if not, write to the Free Software
26 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 ## USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
29 ## Notice: Given that you include this file verbatim into your own
30 ## source tree, you are justified in saying that it remains separate
31 ## from your package, and that this way you are simply just using GNU
32 ## shtool. So, in this situation, there is no requirement that your
33 ## package itself is licensed under the GNU General Public License in
34 ## order to take advantage of GNU shtool.
38 ## Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]
40 ## Available commands:
41 ## install Install a program, script or datafile
42 ## mkdir Make one or more directories
43 ## mkshadow Make a shadow tree through symbolic links
45 ## Not available commands (because module was not built-in):
46 ## echo Print string with optional construct expansion
47 ## mdate Pretty-print modification time of a file or dir
48 ## table Pretty-print a field-separated list as a table
49 ## prop Display progress with a running propeller
50 ## move Move files with simultaneous substitution
51 ## mkln Make link with calculation of relative paths
52 ## fixperm Fix file permissions inside a source tree
53 ## tarball Roll distribution tarballs
54 ## guessos Simple operating system guesser
55 ## arx Extended archive command
56 ## slo Separate linker options by library class
57 ## scpp Sharing C Pre-Processor
58 ## version Maintain a version information file
59 ## path Deal with program paths
63 echo "$0:Error: invalid command line" 1>&2
64 echo "$0:Hint: run \`$0 -h' for usage" 1>&2
67 if [ ".$1" = ".-h" -o ".$1" = ".--help" ]; then
68 echo "This is GNU shtool, version 1.5.2 (27-Feb-2001)"
69 echo "Copyright (c) 1994-2001 Ralf S. Engelschall <rse@engelschall.com>"
70 echo "Report bugs to <bug-shtool@gnu.org>"
72 echo "Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]"
74 echo 'Available global <options>:'
75 echo ' -v, --version display shtool version information'
76 echo ' -h, --help display shtool usage help page (this one)'
77 echo ' -d, --debug display shell trace information'
78 echo ' -r, --recreate recreate this shtool script via shtoolize'
80 echo 'Available <cmd-name> [<cmd-options>] [<cmd-args>]:'
81 echo ' install [-v] [-t] [-c] [-C] [-s] [-m<mode>] [-o<owner>] [-g<group>]'
82 echo ' [-e<sed-cmd>] <file> [<file> ...] <path>'
83 echo ' mkdir [-t] [-f] [-p] [-m<mode>] <dir> [<dir> ...]'
84 echo ' mkshadow [-v] [-t] [-a] <src-dir> <dst-dir>'
86 echo 'Not available <cmd-name> (because module was not built-in):'
87 echo ' echo [-n] [-e] [<str> ...]'
88 echo ' mdate [-n] [-z] [-s] [-d] [-f<str>] [-o<spec>] <path>'
89 echo ' table [-F<sep>] [-w<width>] [-c<cols>] [-s<strip>] <str><sep><str>...'
90 echo ' prop [-p<str>]'
91 echo ' move [-v] [-t] [-e] [-p] <src-file> <dst-file>'
92 echo ' mkln [-t] [-f] [-s] <src-path> [<src-path> ...] <dst-path>'
93 echo ' fixperm [-v] [-t] <path> [<path> ...]'
94 echo ' tarball [-t] [-v] [-o <tarball>] [-c <prog>] [-d <dir>] [-u'
95 echo ' <user>] [-g <group>] [-e <pattern>] <path> [<path> ...]'
97 echo ' arx [-t] [-C<cmd>] <op> <archive> [<file> ...]'
98 echo ' slo [-p<str>] -- -L<dir> -l<lib> [-L<dir> -l<lib> ...]'
99 echo ' scpp [-v] [-p] [-f<filter>] [-o<ofile>] [-t<tfile>] [-M<mark>]'
100 echo ' [-D<dname>] [-C<cname>] <file> [<file> ...]'
101 echo ' version [-l<lang>] [-n<name>] [-p<prefix>] [-s<version>] [-e]'
102 echo ' [-i<knob>] [-d<type>] <file>'
103 echo ' path [-s] [-r] [-d] [-b] [-m] [-p<path>] <str> [<str> ...]'
107 if [ ".$1" = ".-v" -o ".$1" = .
"--version" ]; then
108 echo "GNU shtool 1.5.2 (27-Feb-2001)"
111 if [ ".$1" = ".-r" -o ".$1" = .
"--recreate" ]; then
112 shtoolize
-oshtool install mkdir mkshadow
115 if [ ".$1" = ".-d" -o ".$1" = .
"--debug" ]; then
119 name
=`echo "$0" | sed -e 's;.*/\([^/]*\)$;\1;' -e 's;-sh$;;' -e 's;\.sh$;;'`
121 install|mkdir|mkshadow
)
122 # implicit tool command selection
126 # explicit tool command selection
136 ## DISPATCH INTO SCRIPT PROLOG
142 str_usage
="[-v] [-t] [-c] [-C] [-s] [-m<mode>] [-o<owner>] [-g<group>] [-e<sed-cmd>] <file> [<file> ...] <path>"
144 opt_spec
="v.t.c.C.s.m:o:g:e+"
157 str_usage
="[-t] [-f] [-p] [-m<mode>] <dir> [<dir> ...]"
167 str_usage
="[-v] [-t] [-a] <src-dir> <dst-dir>"
175 echo "$0:Error: unknown option \`$tool'" 2>&1
176 echo "$0:Hint: run \`$0 -h' for usage" 2>&1
180 echo "$0:Error: unknown command \`$tool'" 2>&1
181 echo "$0:Hint: run \`$0 -h' for usage" 2>&1
187 ## COMMON UTILITY CODE
190 # determine name of tool
191 if [ ".$tool" != .
]; then
192 # used inside shtool script
194 toolcmdhelp
="shtool $tool"
195 msgprefix
="shtool:$tool"
197 # used as standalone script
200 msgprefix
="$str_tool"
203 # parse argument specification string
204 eval `echo $arg_spec |\
205 sed -e 's/^\([0-9]*\)\([+=]\)/arg_NUMS=\1; arg_MODE=\2/'`
207 # parse option specification string
208 eval `echo h.$opt_spec |\
209 sed -e 's/\([a-zA-Z0-9]\)\([.:+]\)/opt_MODE_\1=\2;/g'`
211 # interate over argument line
213 while [ $# -gt 0 ]; do
214 # special option stops processing
215 if [ ".$1" = ".--" ]; then
220 # determine option and argument
222 if [ ".$opt_PREV" != .
]; then
223 # merge previous seen option with argument
229 # split argument into option and argument
233 sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \
234 -e 's/";\(.*\)$/"; opt_ARG="\1"/'`
237 opt_OPT
=`echo "x$1" | cut -c3-`
249 # determine whether option needs an argument
250 eval "opt_MODE=\$opt_MODE_${opt_OPT}"
251 if [ ".$opt_ARG" = .
-a ".$opt_ARG_OK" != .
yes ]; then
252 if [ ".$opt_MODE" = ".:" -o ".$opt_MODE" = ".+" ]; then
262 eval "opt_${opt_OPT}=yes"
265 # option with argument (multiple occurances override)
266 eval "opt_${opt_OPT}=\"\$opt_ARG\""
269 # option with argument (multiple occurances append)
270 eval "opt_${opt_OPT}=\"\$opt_${opt_OPT} \$opt_ARG\""
273 echo "$msgprefix:Error: unknown option: \`-$opt_OPT'" 1>&2
274 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2
279 if [ ".$opt_PREV" != .
]; then
280 echo "$msgprefix:Error: missing argument to option \`-$opt_PREV'" 1>&2
281 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2
285 # process help option
286 if [ ".$opt_h" = .
yes ]; then
287 echo "Usage: $toolcmdhelp $str_usage"
291 # complain about incorrect number of arguments
294 if [ $# -ne $arg_NUMS ]; then
295 echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2
296 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2
301 if [ $# -lt $arg_NUMS ]; then
302 echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2
303 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2
309 # establish a temporary file on request
310 if [ ".$gen_tmpfile" = .
yes ]; then
311 if [ ".$TMPDIR" != .
]; then
313 elif [ ".$TEMPDIR" != .
]; then
318 tmpfile
="$tmpdir/.shtool.$$"
319 rm -f $tmpfile >/dev
/null
2>&1
325 ## DISPATCH INTO SCRIPT BODY
332 ## install -- Install a program, script or datafile
333 ## Copyright (c) 1997-2001 Ralf S. Engelschall <rse@engelschall.com>
334 ## Originally written for shtool
337 # determine source(s) and destination
340 while [ $# -gt 1 ]; do
346 # type check for destination
348 if [ -d $dstpath ]; then
349 dstpath
=`echo "$dstpath" | sed -e 's:/$::'`
353 # consistency check for destination
354 if [ $argc -gt 2 -a $dstisdir = 0 ]; then
355 echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2
359 # iterate over all source(s)
363 # if destination is a directory, append the input filename
364 if [ $dstisdir = 1 ]; then
365 dstfile
=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'`
369 # check for correct arguments
370 if [ ".$src" = ".$dst" ]; then
371 echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2
374 if [ -d "$src" ]; then
375 echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2
379 # make a temp file name in the destination directory
381 sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \
382 -e "s;\$;/#INST@$$#;"`
385 if [ ".$opt_v" = .
yes ]; then
386 echo "$src -> $dst" 1>&2
389 # copy or move the file name to the temp name
390 # (because we might be not allowed to change the source)
391 if [ ".$opt_C" = .
yes ]; then
394 if [ ".$opt_c" = .
yes ]; then
395 if [ ".$opt_t" = .
yes ]; then
396 echo "cp $src $dsttmp" 1>&2
398 cp $src $dsttmp ||
exit $?
400 if [ ".$opt_t" = .
yes ]; then
401 echo "mv $src $dsttmp" 1>&2
403 mv $src $dsttmp ||
exit $?
406 # adjust the target file
407 if [ ".$opt_e" != .
]; then
412 cp $dsttmp $dsttmp.old
413 eval "$sed <$dsttmp.old >$dsttmp" ||
exit $?
416 if [ ".$opt_s" = .
yes ]; then
417 if [ ".$opt_t" = .
yes ]; then
418 echo "strip $dsttmp" 1>&2
420 strip
$dsttmp ||
exit $?
422 if [ ".$opt_o" != .
]; then
423 if [ ".$opt_t" = .
yes ]; then
424 echo "chown $opt_o $dsttmp" 1>&2
426 chown
$opt_o $dsttmp ||
exit $?
428 if [ ".$opt_g" != .
]; then
429 if [ ".$opt_t" = .
yes ]; then
430 echo "chgrp $opt_g $dsttmp" 1>&2
432 chgrp
$opt_g $dsttmp ||
exit $?
434 if [ ".$opt_m" != ".-" ]; then
435 if [ ".$opt_t" = .
yes ]; then
436 echo "chmod $opt_m $dsttmp" 1>&2
438 chmod $opt_m $dsttmp ||
exit $?
441 # determine whether to do a quick install
442 # (has to be done _after_ the strip was already done)
444 if [ ".$opt_C" = .
yes ]; then
446 if cmp -s $src $dst; then
452 # finally, install the file to the real destination
453 if [ $quick = yes ]; then
454 if [ ".$opt_t" = .
yes ]; then
455 echo "rm -f $dsttmp" 1>&2
459 if [ ".$opt_t" = .
yes ]; then
460 echo "rm -f $dst && mv $dsttmp $dst" 1>&2
462 rm -f $dst && mv $dsttmp $dst
469 ## mkdir -- Make one or more directories
470 ## Copyright (c) 1996-2001 Ralf S. Engelschall <rse@engelschall.com>
471 ## Originally written for public domain by Noah Friedman <friedman@prep.ai.mit.edu>
472 ## Cleaned up and enhanced for shtool
476 for p
in ${1+"$@"}; do
477 # if the directory already exists...
479 if [ ".$opt_f" = .no
-a ".$opt_p" = .no
]; then
480 echo "$msgprefix:Error: directory already exists: $p" 1>&2
487 # if the directory has to be created...
488 if [ ".$opt_p" = .no
]; then
489 if [ ".$opt_t" = .
yes ]; then
492 mkdir
$p || errstatus
=$?
494 # the smart situation
495 set fnord
`echo ":$p" |\
502 for d
in ${1+"$@"}; do
503 pathcomp
="$pathcomp$d"
505 -* ) pathcomp
="./$pathcomp" ;;
507 if [ ! -d "$pathcomp" ]; then
508 if [ ".$opt_t" = .
yes ]; then
509 echo "mkdir $pathcomp" 1>&2
511 mkdir
$pathcomp || errstatus
=$?
512 if [ ".$opt_m" != .
]; then
513 if [ ".$opt_t" = .
yes ]; then
514 echo "chmod $opt_m $pathcomp" 1>&2
516 chmod $opt_m $pathcomp || errstatus
=$?
519 pathcomp
="$pathcomp/"
528 ## mkshadow -- Make a shadow tree through symbolic links
529 ## Copyright (c) 1998-2001 Ralf S. Engelschall <rse@engelschall.com>
530 ## Originally written for Apache
533 # source and destination directory
534 src
=`echo "$1" | sed -e 's:/$::' -e 's:^\./\(.\):\1:'`
535 dst
=`echo "$2" | sed -e 's:/$::' -e 's:^\./\(.\):\1:'`
537 # check whether source exists
538 if [ ! -d $src ]; then
539 echo "$msgprefix:Error: source directory not found: \`$src'" 1>&2
543 # determine if one of the paths is an absolute path,
544 # because then we have to use an absolute symlink
553 # determine reverse directory for destination directory
555 if [ $oneisabs = 0 ]; then
556 # derive reverse path from forward path
560 if [ "x$pe" = "x.." ]; then
561 OIFS2
="$IFS"; IFS
="$DIFS"
563 sed -e 's:\([^/]*\)$:; dir="\1":' \
564 -e 's:^\(.*\)/[^/]*;:pwd="\1";:'\
566 dstrevdir
="$dir/$dstrevdir"
569 dstrevdir
="../$dstrevdir"
574 src
="`cd $src; pwd`";
577 # create directory tree at destination
578 if [ ! -d $dst ]; then
579 if [ ".$opt_t" = .
yes ]; then
580 echo "mkdir $dst" 1>&2
584 if [ ".$opt_a" = .
yes ]; then
585 DIRS
=`cd $src; find . -type d -print |\
586 sed -e '/^\.$/d' -e 's:^\./::'`
588 DIRS
=`cd $src; find . -type d -print |\
589 sed -e '/\/CVS/d' -e '/^\.$/d' -e 's:^\./::'`
592 if [ ".$opt_t" = .
yes ]; then
593 echo "mkdir $dst/$dir" 1>&2
598 # fill directory tree with symlinks to files
599 if [ ".$opt_a" = .
yes ]; then
600 FILES
="`cd $src; find . -depth -print |\
603 FILES
="`cd $src; find . -depth -print |\
604 sed -e '/\.o$/d' -e '/\.a$/d' -e '/\.so$/d' \
605 -e '/\.cvsignore$/d' -e '/\/CVS/d' \
606 -e '/\/\.#/d' -e '/\.orig$/d' \
609 for file in $FILES; do
610 # don't use `-type f' above for find because of symlinks
611 if [ -d "$src/$file" ]; then
614 basename=`echo $file | sed -e 's:^.*/::'`
615 dir
=`echo $file | sed -e 's:[^/]*$::' -e 's:/$::' -e 's:$:/:' -e 's:^/$::'`
616 from
=`echo "$src/$file" | sed -e 's/^\.\///'`
617 to
="$dst/$dir$basename"
618 if [ $oneisabs = 0 ]; then
619 if [ ".$dir" != .
]; then
620 subdir
=`echo $dir | sed -e 's:/$::'`
621 # derive reverse path from forward path
624 for pe
in $subdir; do
631 from
="$dstrevdir$from"
633 if [ ".$opt_v" = .
yes ]; then
636 if [ ".$opt_t" = .
yes ]; then
637 echo "ln -s $from $to" 1>&2