]> git.sur5r.net Git - openldap/blob - build/shtool
Merge remote-tracking branch 'origin/mdb.RE/0.9' into OPENLDAP_REL_ENG_2_5
[openldap] / build / shtool
1 #!/bin/sh
2 ##
3 ##  GNU shtool -- The GNU Portable Shell Tool
4 ##  Copyright (c) 1994-2006 Ralf S. Engelschall <rse@engelschall.com>
5 ##
6 ##  See http://www.gnu.org/software/shtool/ for more information.
7 ##  See ftp://ftp.gnu.org/gnu/shtool/ for latest version.
8 ##
9 ##  Version:  2.0.5 (07-Feb-2006)
10 ##  Contents: 6/19 available modules
11 ##
12
13 ##
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.
18 ##
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.
23 ##
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>.
28 ##
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.
35 ##
36
37 ##
38 ##  Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]
39 ##
40 ##  Available commands:
41 ##    echo       Print string with optional construct expansion
42 ##    move       Move files with simultaneous substitution
43 ##    install    Install a program, script or datafile
44 ##    mkdir      Make one or more directories
45 ##    mkln       Make link with calculation of relative paths
46 ##    subst      Apply sed(1) substitution operations
47 ##
48 ##  Not available commands (because module was not built-in):
49 ##    mdate      Pretty-print modification time of a file or dir
50 ##    table      Pretty-print a field-separated list as a table
51 ##    prop       Display progress with a running propeller
52 ##    mkshadow   Make a shadow tree through symbolic links
53 ##    fixperm    Fix file permissions inside a source tree
54 ##    rotate     Logfile rotation
55 ##    tarball    Roll distribution tarballs
56 ##    platform   Platform Identification Utility
57 ##    arx        Extended archive command
58 ##    slo        Separate linker options by library class
59 ##    scpp       Sharing C Pre-Processor
60 ##    version    Maintain a version information file
61 ##    path       Deal with program paths
62 ##
63
64 #   maximum Bourne-Shell compatibility
65 if [ ".$ZSH_VERSION" != . ] && (emulate sh) >/dev/null 2>&1; then
66     #   reconfigure zsh(1)
67     emulate sh
68     NULLCMD=:
69     alias -g '${1+"$@"}'='"$@"'
70 elif [ ".$BASH_VERSION" != . ] && (set -o posix) >/dev/null 2>&1; then
71     #   reconfigure bash(1)
72     set -o posix
73 fi
74
75 #   maximum independence of NLS nuisances
76 for var in \
77     LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
78     LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
79     LC_TELEPHONE LC_TIME
80 do
81     if (set +x; test -z "`(eval $var=C; export $var) 2>&1`"); then
82         eval $var=C; export $var
83     else
84         unset $var
85     fi
86 done
87
88 #   initial command line handling
89 if [ $# -eq 0 ]; then
90     echo "$0:Error: invalid command line" 1>&2
91     echo "$0:Hint:  run \`$0 -h' for usage" 1>&2
92     exit 1
93 fi
94 if [ ".$1" = ".-h" ] || [ ".$1" = ".--help" ]; then
95     echo "This is GNU shtool, version 2.0.5 (07-Feb-2006)"
96     echo 'Copyright (c) 1994-2006 Ralf S. Engelschall <rse@engelschall.com>'
97     echo 'Report bugs to <bug-shtool@gnu.org>'
98     echo ''
99     echo 'Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]'
100     echo ''
101     echo 'Available global <options>:'
102     echo '  -v, --version   display shtool version information'
103     echo '  -h, --help      display shtool usage help page (this one)'
104     echo '  -d, --debug     display shell trace information'
105     echo '  -r, --recreate  recreate this shtool script via shtoolize'
106     echo ''
107     echo 'Available <cmd-name> [<cmd-options>] [<cmd-args>]:'
108     echo '  echo     [-n|--newline] [-e|--expand] [<string> ...]'
109     echo '  move     [-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve]'
110     echo '           <src-file> <dst-file>'
111     echo '  install  [-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy]'
112     echo '           [-C|--compare-copy] [-s|--strip] [-m|--mode <mode>]'
113     echo '           [-o|--owner <owner>] [-g|--group <group>] [-e|--exec'
114     echo '           <sed-cmd>] <file> [<file> ...] <path>'
115     echo '  mkdir    [-t|--trace] [-f|--force] [-p|--parents] [-m|--mode'
116     echo '           <mode>] [-o|--owner <owner>] [-g|--group <group>] <dir>'
117     echo '           [<dir> ...]'
118     echo '  mkln     [-t|--trace] [-f|--force] [-s|--symbolic] <src-path>'
119     echo '           [<src-path> ...] <dst-path>'
120     echo '  subst    [-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning]'
121     echo '           [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup'
122     echo '           <ext>] [-e|--exec <cmd>] [-f|--file <cmd-file>] [<file>]'
123     echo '           [...]'
124     echo ''
125     echo 'Not available <cmd-name> (because module was not built-in):'
126     echo '  mdate    [-n|--newline] [-z|--zero] [-s|--shorten] [-d|--digits]'
127     echo '           [-f|--field-sep <str>] [-o|--order <spec>] <path>'
128     echo '  table    [-F|--field-sep <sep>] [-w|--width <width>] [-c|--columns'
129     echo '           <cols>] [-s|--strip <strip>] <str><sep><str>...'
130     echo '  prop     [-p|--prefix <str>]'
131     echo '  mkshadow [-v|--verbose] [-t|--trace] [-a|--all] <src-dir> <dst-dir>'
132     echo '  fixperm  [-v|--verbose] [-t|--trace] <path> [<path> ...]'
133     echo '  rotate   [-v|--verbose] [-t|--trace] [-f|--force] [-n|--num-files'
134     echo '           <count>] [-s|--size <size>] [-c|--copy] [-r|--remove]'
135     echo '           [-a|--archive-dir <dir>] [-z|--compress [<tool>:]<level>]'
136     echo '           [-b|--background] [-d|--delay] [-p|--pad <len>] [-m|--mode'
137     echo '           <mode>] [-o|--owner <owner>] [-g|--group <group>] [-M|--migrate'
138     echo '           <cmd>] [-P|--prolog <cmd>] [-E|--epilog <cmd>] <file> [...]'
139     echo '  tarball  [-t|--trace] [-v|--verbose] [-o|--output <tarball>]'
140     echo '           [-c|--compress <prog>] [-d|--directory <dir>] [-u|--user'
141     echo '           <user>] [-g|--group <group>] [-e|--exclude <pattern>]'
142     echo '           <path> [<path> ...]'
143     echo '  platform [-F|--format <format>] [-S|--sep <string>] [-C|--conc'
144     echo '           <string>] [-L|--lower] [-U|--upper] [-v|--verbose]'
145     echo '           [-c|--concise] [-n|--no-newline] [-t|--type <type>]'
146     echo '           [-V|--version] [-h|--help]'
147     echo '  arx      [-t|--trace] [-C|--command <cmd>] <op> <archive> [<file>'
148     echo '           ...]'
149     echo '  slo      [-p|--prefix <str>] -- -L<dir> -l<lib> [-L<dir> -l<lib>'
150     echo '           ...]'
151     echo '  scpp     [-v|--verbose] [-p|--preserve] [-f|--filter <filter>]'
152     echo '           [-o|--output <ofile>] [-t|--template <tfile>] [-M|--mark'
153     echo '           <mark>] [-D|--define <dname>] [-C|--class <cname>]'
154     echo '           <file> [<file> ...]'
155     echo '  version  [-l|--language <lang>] [-n|--name <name>] [-p|--prefix'
156     echo '           <prefix>] [-s|--set <version>] [-e|--edit] [-i|--increase'
157     echo '           <knob>] [-d|--display <type>] <file>'
158     echo '  path     [-s|--suppress] [-r|--reverse] [-d|--dirname] [-b|--basename]'
159     echo '           [-m|--magic] [-p|--path <path>] <str> [<str> ...]'
160     echo ''
161     exit 0
162 fi
163 if [ ".$1" = ".-v" ] || [ ".$1" = ".--version" ]; then
164     echo "GNU shtool 2.0.5 (07-Feb-2006)"
165     exit 0
166 fi
167 if [ ".$1" = ".-r" ] || [ ".$1" = ".--recreate" ]; then
168     shtoolize -oshtool echo move install mkdir mkln subst
169     exit 0
170 fi
171 if [ ".$1" = ".-d" ] || [ ".$1" = ".--debug" ]; then
172     shift
173     set -x
174 fi
175 name=`echo "$0" | sed -e 's;.*/\([^/]*\)$;\1;' -e 's;-sh$;;' -e 's;\.sh$;;'`
176 case "$name" in
177     echo|move|install|mkdir|mkln|subst )
178         #   implicit tool command selection
179         tool="$name"
180         ;;
181     * )
182         #   explicit tool command selection
183         tool="$1"
184         shift
185         ;;
186 esac
187 arg_spec=""
188 opt_spec=""
189 gen_tmpfile=no
190
191 ##
192 ##  DISPATCH INTO SCRIPT PROLOG
193 ##
194
195 case $tool in
196     echo )
197         str_tool="echo"
198         str_usage="[-n|--newline] [-e|--expand] [<string> ...]"
199         arg_spec="0+"
200         opt_spec="n.e."
201         opt_alias="n:newline,e:expand"
202         opt_n=no
203         opt_e=no
204         ;;
205     move )
206         str_tool="move"
207         str_usage="[-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve] <src-file> <dst-file>"
208         arg_spec="2="
209         opt_spec="v.t.e.p."
210         opt_alias="v:verbose,t:trace,e:expand,p:preserve"
211         opt_v=no
212         opt_t=no
213         opt_e=no
214         opt_p=no
215         ;;
216     install )
217         str_tool="install"
218         str_usage="[-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy] [-C|--compare-copy] [-s|--strip] [-m|--mode <mode>] [-o|--owner <owner>] [-g|--group <group>] [-e|--exec <sed-cmd>] <file> [<file> ...] <path>"
219         arg_spec="1+"
220         opt_spec="v.t.d.c.C.s.m:o:g:e+"
221         opt_alias="v:verbose,t:trace,d:mkdir,c:copy,C:compare-copy,s:strip,m:mode,o:owner,g:group,e:exec"
222         opt_v=no
223         opt_t=no
224         opt_d=no
225         opt_c=no
226         opt_C=no
227         opt_s=no
228         opt_m="0755"
229         opt_o=""
230         opt_g=""
231         opt_e=""
232         ;;
233     mkdir )
234         str_tool="mkdir"
235         str_usage="[-t|--trace] [-f|--force] [-p|--parents] [-m|--mode <mode>] [-o|--owner <owner>] [-g|--group <group>] <dir> [<dir> ...]"
236         arg_spec="1+"
237         opt_spec="t.f.p.m:o:g:"
238         opt_alias="t:trace,f:force,p:parents,m:mode,o:owner,g:group"
239         opt_t=no
240         opt_f=no
241         opt_p=no
242         opt_m=""
243         opt_o=""
244         opt_g=""
245         ;;
246     mkln )
247         str_tool="mkln"
248         str_usage="[-t|--trace] [-f|--force] [-s|--symbolic] <src-path> [<src-path> ...] <dst-path>"
249         arg_spec="2+"
250         opt_spec="t.f.s."
251         opt_alias="t:trace,f:force,s:symbolic"
252         opt_t=no
253         opt_f=no
254         opt_s=no
255         ;;
256     subst )
257         str_tool="subst"
258         str_usage="[-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning] [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup <ext>] [-e|--exec <cmd>] [-f|--file <cmd-file>] [<file>] [...]"
259         gen_tmpfile=yes
260         arg_spec="0+"
261         opt_spec="v.t.n.w.q.s.i.b:e+f:"
262         opt_alias="v:verbose,t:trace,n:nop,w:warning,q:quiet,s:stealth,i:interactive,b:backup,e:exec,f:file"
263         opt_v=no
264         opt_t=no
265         opt_n=no
266         opt_w=no
267         opt_q=no
268         opt_s=no
269         opt_i=no
270         opt_b=""
271         opt_e=""
272         opt_f=""
273         ;;
274     -* )
275         echo "$0:Error: unknown option \`$tool'" 2>&1
276         echo "$0:Hint:  run \`$0 -h' for usage" 2>&1
277         exit 1
278         ;;
279     * )
280         echo "$0:Error: unknown command \`$tool'" 2>&1
281         echo "$0:Hint:  run \`$0 -h' for usage" 2>&1
282         exit 1
283         ;;
284 esac
285
286 ##
287 ##  COMMON UTILITY CODE
288 ##
289
290 #   commonly used ASCII values
291 ASC_TAB="       "
292 ASC_NL="
293 "
294
295 #   determine name of tool
296 if [ ".$tool" != . ]; then
297     #   used inside shtool script
298     toolcmd="$0 $tool"
299     toolcmdhelp="shtool $tool"
300     msgprefix="shtool:$tool"
301 else
302     #   used as standalone script
303     toolcmd="$0"
304     toolcmdhelp="sh $0"
305     msgprefix="$str_tool"
306 fi
307
308 #   parse argument specification string
309 eval `echo $arg_spec |\
310       sed -e 's/^\([0-9]*\)\([+=]\)/arg_NUMS=\1; arg_MODE=\2/'`
311
312 #   parse option specification string
313 eval `echo h.$opt_spec |\
314       sed -e 's/\([a-zA-Z0-9]\)\([.:+]\)/opt_MODE_\1=\2;/g'`
315
316 #   parse option alias string
317 eval `echo h:help,$opt_alias |\
318       sed -e 's/-/_/g' -e 's/\([a-zA-Z0-9]\):\([^,]*\),*/opt_ALIAS_\2=\1;/g'`
319
320 #   interate over argument line
321 opt_PREV=''
322 while [ $# -gt 0 ]; do
323     #   special option stops processing
324     if [ ".$1" = ".--" ]; then
325         shift
326         break
327     fi
328
329     #   determine option and argument
330     opt_ARG_OK=no
331     if [ ".$opt_PREV" != . ]; then
332         #   merge previous seen option with argument
333         opt_OPT="$opt_PREV"
334         opt_ARG="$1"
335         opt_ARG_OK=yes
336         opt_PREV=''
337     else
338         #   split argument into option and argument
339         case "$1" in
340             --[a-zA-Z0-9]*=*)
341                 eval `echo "x$1" |\
342                       sed -e 's/^x--\([a-zA-Z0-9-]*\)=\(.*\)$/opt_OPT="\1";opt_ARG="\2"/'`
343                 opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'`
344                 eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}"
345                 ;;
346             --[a-zA-Z0-9]*)
347                 opt_OPT=`echo "x$1" | cut -c4-`
348                 opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'`
349                 eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}"
350                 opt_ARG=''
351                 ;;
352             -[a-zA-Z0-9]*)
353                 eval `echo "x$1" |\
354                       sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \
355                           -e 's/";\(.*\)$/"; opt_ARG="\1"/'`
356                 ;;
357             -[a-zA-Z0-9])
358                 opt_OPT=`echo "x$1" | cut -c3-`
359                 opt_ARG=''
360                 ;;
361             *)
362                 break
363                 ;;
364         esac
365     fi
366
367     #   eat up option
368     shift
369
370     #   determine whether option needs an argument
371     eval "opt_MODE=\$opt_MODE_${opt_OPT}"
372     if [ ".$opt_ARG" = . ] && [ ".$opt_ARG_OK" != .yes ]; then
373         if [ ".$opt_MODE" = ".:" ] || [ ".$opt_MODE" = ".+" ]; then
374             opt_PREV="$opt_OPT"
375             continue
376         fi
377     fi
378
379     #   process option
380     case $opt_MODE in
381         '.' )
382             #   boolean option
383             eval "opt_${opt_OPT}=yes"
384             ;;
385         ':' )
386             #   option with argument (multiple occurances override)
387             eval "opt_${opt_OPT}=\"\$opt_ARG\""
388             ;;
389         '+' )
390             #   option with argument (multiple occurances append)
391             eval "opt_${opt_OPT}=\"\$opt_${opt_OPT}\${ASC_NL}\$opt_ARG\""
392             ;;
393         * )
394             echo "$msgprefix:Error: unknown option: \`$opt_OPT'" 1>&2
395             echo "$msgprefix:Hint:  run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2
396             exit 1
397             ;;
398     esac
399 done
400 if [ ".$opt_PREV" != . ]; then
401     echo "$msgprefix:Error: missing argument to option \`$opt_PREV'" 1>&2
402     echo "$msgprefix:Hint:  run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2
403     exit 1
404 fi
405
406 #   process help option
407 if [ ".$opt_h" = .yes ]; then
408     echo "Usage: $toolcmdhelp $str_usage"
409     exit 0
410 fi
411
412 #   complain about incorrect number of arguments
413 case $arg_MODE in
414     '=' )
415         if [ $# -ne $arg_NUMS ]; then
416             echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2
417             echo "$msgprefix:Hint:  run \`$toolcmd -h' or \`man shtool' for details" 1>&2
418             exit 1
419         fi
420         ;;
421     '+' )
422         if [ $# -lt $arg_NUMS ]; then
423             echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2
424             echo "$msgprefix:Hint:  run \`$toolcmd -h' or \`man shtool' for details" 1>&2
425             exit 1
426         fi
427         ;;
428 esac
429
430 #   establish a temporary file on request
431 if [ ".$gen_tmpfile" = .yes ]; then
432     #   create (explicitly) secure temporary directory
433     if [ ".$TMPDIR" != . ]; then
434         tmpdir="$TMPDIR"
435     elif [ ".$TEMPDIR" != . ]; then
436         tmpdir="$TEMPDIR"
437     else
438         tmpdir="/tmp"
439     fi
440     tmpdir="$tmpdir/.shtool.$$"
441     ( umask 077
442       rm -rf "$tmpdir" >/dev/null 2>&1 || true
443       mkdir  "$tmpdir" >/dev/null 2>&1
444       if [ $? -ne 0 ]; then
445           echo "$msgprefix:Error: failed to create temporary directory \`$tmpdir'" 1>&2
446           exit 1
447       fi
448     )
449
450     #   create (implicitly) secure temporary file
451     tmpfile="$tmpdir/shtool.tmp"
452     touch "$tmpfile"
453 fi
454
455 #   utility function: map string to lower case
456 util_lower () {
457     echo "$1" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'
458 }
459
460 #   utility function: map string to upper case
461 util_upper () {
462     echo "$1" | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
463 }
464
465 #   cleanup procedure
466 shtool_exit () {
467     rc="$1"
468     if [ ".$gen_tmpfile" = .yes ]; then
469         rm -rf "$tmpdir" >/dev/null 2>&1 || true
470     fi
471     exit $rc
472 }
473
474 ##
475 ##  DISPATCH INTO SCRIPT BODY
476 ##
477
478 case $tool in
479
480 echo )
481     ##
482     ##  echo -- Print string with optional construct expansion
483     ##  Copyright (c) 1998-2006 Ralf S. Engelschall <rse@engelschall.com>
484     ##
485
486     text="$*"
487
488     #   check for broken escape sequence expansion
489     seo=''
490     bytes=`echo '\1' | wc -c | awk '{ printf("%s", $1); }'`
491     if [ ".$bytes" != .3 ]; then
492         bytes=`echo -E '\1' | wc -c | awk '{ printf("%s", $1); }'`
493         if [ ".$bytes" = .3 ]; then
494             seo='-E'
495         fi
496     fi
497
498     #   check for existing -n option (to suppress newline)
499     minusn=''
500     bytes=`echo -n 123 2>/dev/null | wc -c | awk '{ printf("%s", $1); }'`
501     if [ ".$bytes" = .3 ]; then
502         minusn='-n'
503     fi
504
505     #   determine terminal bold sequence
506     term_bold=''
507     term_norm=''
508     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[Bb]'`" != . ]; then
509         case $TERM in
510             #   for the most important terminal types we directly know the sequences
511             xterm|xterm*|vt220|vt220*)
512                 term_bold=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' </dev/null 2>/dev/null`
513                 term_norm=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' </dev/null 2>/dev/null`
514                 ;;
515             vt100|vt100*|cygwin)
516                 term_bold=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' </dev/null 2>/dev/null`
517                 term_norm=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' </dev/null 2>/dev/null`
518                 ;;
519             #   for all others, we try to use a possibly existing `tput' or `tcout' utility
520             * )
521                 paths=`echo $PATH | sed -e 's/:/ /g'`
522                 for tool in tput tcout; do
523                     for dir in $paths; do
524                         if [ -r "$dir/$tool" ]; then
525                             for seq in bold md smso; do # 'smso' is last
526                                 bold="`$dir/$tool $seq 2>/dev/null`"
527                                 if [ ".$bold" != . ]; then
528                                     term_bold="$bold"
529                                     break
530                                 fi
531                             done
532                             if [ ".$term_bold" != . ]; then
533                                 for seq in sgr0 me rmso init reset; do # 'reset' is last
534                                     norm="`$dir/$tool $seq 2>/dev/null`"
535                                     if [ ".$norm" != . ]; then
536                                         term_norm="$norm"
537                                         break
538                                     fi
539                                 done
540                             fi
541                             break
542                         fi
543                     done
544                     if [ ".$term_bold" != . ] && [ ".$term_norm" != . ]; then
545                         break;
546                     fi
547                 done
548                 ;;
549         esac
550         if [ ".$term_bold" = . ] || [ ".$term_norm" = . ]; then
551             echo "$msgprefix:Warning: unable to determine terminal sequence for bold mode" 1>&2
552             term_bold=''
553             term_norm=''
554         fi
555     fi
556
557     #   determine user name
558     username=''
559     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[uUgG]'`" != . ]; then
560         username="`(id -un) 2>/dev/null`"
561         if [ ".$username" = . ]; then
562             str="`(id) 2>/dev/null`"
563             if [ ".`echo $str | grep '^uid[     ]*=[    ]*[0-9]*('`" != . ]; then
564                 username=`echo $str | sed -e 's/^uid[   ]*=[    ]*[0-9]*(//' -e 's/).*$//'`
565             fi
566             if [ ".$username" = . ]; then
567                 username="$LOGNAME"
568                 if [ ".$username" = . ]; then
569                     username="$USER"
570                     if [ ".$username" = . ]; then
571                         username="`(whoami) 2>/dev/null |\
572                                    awk '{ printf("%s", $1); }'`"
573                         if [ ".$username" = . ]; then
574                             username="`(who am i) 2>/dev/null |\
575                                        awk '{ printf("%s", $1); }'`"
576                             if [ ".$username" = . ]; then
577                                 username='unknown'
578                             fi
579                         fi
580                     fi
581                 fi
582             fi
583         fi
584     fi
585
586     #   determine user id
587     userid=''
588     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%U'`" != . ]; then
589         userid="`(id -u) 2>/dev/null`"
590         if [ ".$userid" = . ]; then
591             userid="`(id -u ${username}) 2>/dev/null`"
592             if [ ".$userid" = . ]; then
593                 str="`(id) 2>/dev/null`"
594                 if [ ".`echo $str | grep '^uid[         ]*=[    ]*[0-9]*('`" != . ]; then
595                     userid=`echo $str | sed -e 's/^uid[         ]*=[    ]*//' -e 's/(.*$//'`
596                 fi
597                 if [ ".$userid" = . ]; then
598                     userid=`(getent passwd ${username}) 2>/dev/null | \
599                             sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'`
600                     if [ ".$userid" = . ]; then
601                         userid=`grep "^${username}:" /etc/passwd 2>/dev/null | \
602                                 sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'`
603                         if [ ".$userid" = . ]; then
604                             userid=`(ypcat passwd) 2>/dev/null |
605                                     grep "^${username}:" | \
606                                     sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'`
607                             if [ ".$userid" = . ]; then
608                                 userid='?'
609                             fi
610                         fi
611                     fi
612                 fi
613             fi
614         fi
615     fi
616
617     #   determine (primary) group id
618     groupid=''
619     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then
620         groupid="`(id -g ${username}) 2>/dev/null`"
621         if [ ".$groupid" = . ]; then
622             str="`(id) 2>/dev/null`"
623             if [ ".`echo $str | grep 'gid[      ]*=[    ]*[0-9]*('`" != . ]; then
624                 groupid=`echo $str | sed -e 's/^.*gid[  ]*=[    ]*//' -e 's/(.*$//'`
625             fi
626             if [ ".$groupid" = . ]; then
627                 groupid=`(getent passwd ${username}) 2>/dev/null | \
628                          sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
629                 if [ ".$groupid" = . ]; then
630                     groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \
631                              sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
632                     if [ ".$groupid" = . ]; then
633                         groupid=`(ypcat passwd) 2>/dev/null | grep "^${username}:" | \
634                                  sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
635                         if [ ".$groupid" = . ]; then
636                             groupid='?'
637                         fi
638                     fi
639                 fi
640             fi
641         fi
642     fi
643
644     #   determine (primary) group name
645     groupname=''
646     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then
647         groupname="`(id -gn ${username}) 2>/dev/null`"
648         if [ ".$groupname" = . ]; then
649             str="`(id) 2>/dev/null`"
650             if [ ".`echo $str | grep 'gid[      ]*=[    ]*[0-9]*('`" != . ]; then
651                 groupname=`echo $str | sed -e 's/^.*gid[        ]*=[    ]*[0-9]*(//' -e 's/).*$//'`
652             fi
653             if [ ".$groupname" = . ]; then
654                 groupname=`(getent group) 2>/dev/null | \
655                            grep "^[^:]*:[^:]*:${groupid}:" | \
656                            sed -e 's/:.*$//'`
657                 if [ ".$groupname" = . ]; then
658                     groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \
659                                sed -e 's/:.*$//'`
660                     if [ ".$groupname" = . ]; then
661                         groupname=`(ypcat group) 2>/dev/null | \
662                                    grep "^[^:]*:[^:]*:${groupid}:" | \
663                                    sed -e 's/:.*$//'`
664                         if [ ".$groupname" = . ]; then
665                             groupname='?'
666                         fi
667                     fi
668                 fi
669             fi
670         fi
671     fi
672
673     #   determine host and domain name
674     hostname=''
675     domainname=''
676     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then
677         hostname="`(uname -n) 2>/dev/null |\
678                    awk '{ printf("%s", $1); }'`"
679         if [ ".$hostname" = . ]; then
680             hostname="`(hostname) 2>/dev/null |\
681                        awk '{ printf("%s", $1); }'`"
682             if [ ".$hostname" = . ]; then
683                 hostname='unknown'
684             fi
685         fi
686         case $hostname in
687             *.* )
688                 domainname=".`echo $hostname | cut -d. -f2-`"
689                 hostname="`echo $hostname | cut -d. -f1`"
690                 ;;
691         esac
692     fi
693     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then
694         if [ ".$domainname" = . ]; then
695             if [ -f /etc/resolv.conf ]; then
696                 domainname="`grep '^[   ]*domain' /etc/resolv.conf | sed -e 'q' |\
697                              sed -e 's/.*domain//' \
698                                  -e 's/^[       ]*//' -e 's/^ *//' -e 's/^      *//' \
699                                  -e 's/^\.//' -e 's/^/./' |\
700                              awk '{ printf("%s", $1); }'`"
701                 if [ ".$domainname" = . ]; then
702                     domainname="`grep '^[       ]*search' /etc/resolv.conf | sed -e 'q' |\
703                                  sed -e 's/.*search//' \
704                                      -e 's/^[   ]*//' -e 's/^ *//' -e 's/^      *//' \
705                                      -e 's/ .*//' -e 's/        .*//' \
706                                      -e 's/^\.//' -e 's/^/./' |\
707                                  awk '{ printf("%s", $1); }'`"
708                 fi
709             fi
710         fi
711     fi
712
713     #   determine current time
714     time_day=''
715     time_month=''
716     time_year=''
717     time_monthname=''
718     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then
719         time_day=`date '+%d'`
720         time_month=`date '+%m'`
721         time_year=`date '+%Y' 2>/dev/null`
722         if [ ".$time_year" = . ]; then
723             time_year=`date '+%y'`
724             case $time_year in
725                 [5-9][0-9]) time_year="19$time_year" ;;
726                 [0-4][0-9]) time_year="20$time_year" ;;
727             esac
728         fi
729         case $time_month in
730             1|01) time_monthname='Jan' ;;
731             2|02) time_monthname='Feb' ;;
732             3|03) time_monthname='Mar' ;;
733             4|04) time_monthname='Apr' ;;
734             5|05) time_monthname='May' ;;
735             6|06) time_monthname='Jun' ;;
736             7|07) time_monthname='Jul' ;;
737             8|08) time_monthname='Aug' ;;
738             9|09) time_monthname='Sep' ;;
739               10) time_monthname='Oct' ;;
740               11) time_monthname='Nov' ;;
741               12) time_monthname='Dec' ;;
742         esac
743     fi
744
745     #   expand special ``%x'' constructs
746     if [ ".$opt_e" = .yes ]; then
747         text=`echo $seo "$text" |\
748               sed -e "s/%B/${term_bold}/g" \
749                   -e "s/%b/${term_norm}/g" \
750                   -e "s/%u/${username}/g" \
751                   -e "s/%U/${userid}/g" \
752                   -e "s/%g/${groupname}/g" \
753                   -e "s/%G/${groupid}/g" \
754                   -e "s/%h/${hostname}/g" \
755                   -e "s/%d/${domainname}/g" \
756                   -e "s/%D/${time_day}/g" \
757                   -e "s/%M/${time_month}/g" \
758                   -e "s/%Y/${time_year}/g" \
759                   -e "s/%m/${time_monthname}/g" 2>/dev/null`
760     fi
761
762     #   create output
763     if [ .$opt_n = .no ]; then
764         echo $seo "$text"
765     else
766         #   the harder part: echo -n is best, because
767         #   awk may complain about some \xx sequences.
768         if [ ".$minusn" != . ]; then
769             echo $seo $minusn "$text"
770         else
771             echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text"
772         fi
773     fi
774
775     shtool_exit 0
776     ;;
777
778 move )
779     ##
780     ##  move -- Move files with simultaneous substitution
781     ##  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com>
782     ##
783
784     src="$1"
785     dst="$2"
786
787     #   consistency checks
788     if [ ".$src" = . ] || [ ".$dst" = . ]; then
789         echo "$msgprefix:Error: Invalid arguments" 1>&2
790         shtool_exit 1
791     fi
792     if [ ".$src" = ".$dst" ]; then
793         echo "$msgprefix:Error: Source and destination files are the same" 1>&2
794         shtool_exit 1
795     fi
796     expsrc="$src"
797     if [ ".$opt_e" = .yes ]; then
798         expsrc="`echo $expsrc`"
799     fi
800     if [ ".$opt_e" = .yes ]; then
801         if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then
802             echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2
803             shtool_exit 1
804         fi
805         if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then
806             echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2
807             shtool_exit 1
808         fi
809         if [ ".$expsrc" = ".$src" ]; then
810             echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2
811             shtool_exit 1
812         fi
813     else
814         if [ ! -r "$src" ]; then
815             echo "$msgprefix:Error: Source not found: $src" 1>&2
816             shtool_exit 1
817         fi
818     fi
819
820     #   determine substitution patterns
821     if [ ".$opt_e" = .yes ]; then
822         srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'`
823         dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'`
824     fi
825
826     #   iterate over source(s)
827     for onesrc in $expsrc; do
828         if [ .$opt_e = .yes ]; then
829             onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"`
830         else
831             onedst="$dst"
832         fi
833         errorstatus=0
834         if [ ".$opt_v" = .yes ]; then
835             echo "$onesrc -> $onedst"
836         fi
837         if [ ".$opt_p" = .yes ]; then
838             if [ -r $onedst ]; then
839                 if cmp -s $onesrc $onedst; then
840                     if [ ".$opt_t" = .yes ]; then
841                         echo "rm -f $onesrc" 1>&2
842                     fi
843                     rm -f $onesrc || errorstatus=$?
844                 else
845                     if [ ".$opt_t" = .yes ]; then
846                         echo "mv -f $onesrc $onedst" 1>&2
847                     fi
848                     mv -f $onesrc $onedst || errorstatus=$?
849                 fi
850             else
851                 if [ ".$opt_t" = .yes ]; then
852                     echo "mv -f $onesrc $onedst" 1>&2
853                 fi
854                 mv -f $onesrc $onedst || errorstatus=$?
855             fi
856         else
857             if [ ".$opt_t" = .yes ]; then
858                 echo "mv -f $onesrc $onedst" 1>&2
859             fi
860             mv -f $onesrc $onedst || errorstatus=$?
861         fi
862         if [ $errorstatus -ne 0 ]; then
863             break;
864         fi
865     done
866
867     shtool_exit $errorstatus
868     ;;
869
870 install )
871     ##
872     ##  install -- Install a program, script or datafile
873     ##  Copyright (c) 1997-2006 Ralf S. Engelschall <rse@engelschall.com>
874     ##
875
876     #   special case: "shtool install -d <dir> [...]" internally
877     #   maps to "shtool mkdir -f -p -m 755 <dir> [...]"
878     if [ "$opt_d" = yes ]; then
879         cmd="$0 mkdir -f -p -m 755"
880         if [ ".$opt_o" != . ]; then
881             cmd="$cmd -o '$opt_o'"
882         fi
883         if [ ".$opt_g" != . ]; then
884             cmd="$cmd -g '$opt_g'"
885         fi
886         if [ ".$opt_v" = .yes ]; then
887             cmd="$cmd -v"
888         fi
889         if [ ".$opt_t" = .yes ]; then
890             cmd="$cmd -t"
891         fi
892         for dir in "$@"; do
893             eval "$cmd $dir" || shtool_exit $?
894         done
895         shtool_exit 0
896     fi
897
898     #   determine source(s) and destination
899     argc=$#
900     srcs=""
901     while [ $# -gt 1 ]; do
902         srcs="$srcs $1"
903         shift
904     done
905     dstpath="$1"
906
907     #   type check for destination
908     dstisdir=0
909     if [ -d $dstpath ]; then
910         dstpath=`echo "$dstpath" | sed -e 's:/$::'`
911         dstisdir=1
912     fi
913
914     #   consistency check for destination
915     if [ $argc -gt 2 ] && [ $dstisdir = 0 ]; then
916         echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2
917         shtool_exit 1
918     fi
919
920     #   iterate over all source(s)
921     for src in $srcs; do
922         dst=$dstpath
923
924         #   if destination is a directory, append the input filename
925         if [ $dstisdir = 1 ]; then
926             dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'`
927             dst="$dst/$dstfile"
928         fi
929
930         #   check for correct arguments
931         if [ ".$src" = ".$dst" ]; then
932             echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2
933             continue
934         fi
935         if [ -d "$src" ]; then
936             echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2
937             continue
938         fi
939
940         #   make a temp file name in the destination directory
941         dsttmp=`echo $dst |\
942                 sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \
943                     -e "s;\$;/#INST@$$#;"`
944
945         #   verbosity
946         if [ ".$opt_v" = .yes ]; then
947             echo "$src -> $dst" 1>&2
948         fi
949
950         #   copy or move the file name to the temp name
951         #   (because we might be not allowed to change the source)
952         if [ ".$opt_C" = .yes ]; then
953             opt_c=yes
954         fi
955         if [ ".$opt_c" = .yes ]; then
956             if [ ".$opt_t" = .yes ]; then
957                 echo "cp $src $dsttmp" 1>&2
958             fi
959             cp $src $dsttmp || shtool_exit $?
960         else
961             if [ ".$opt_t" = .yes ]; then
962                 echo "mv $src $dsttmp" 1>&2
963             fi
964             mv $src $dsttmp || shtool_exit $?
965         fi
966
967         #   adjust the target file
968         if [ ".$opt_e" != . ]; then
969             sed='sed'
970             OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS"
971             for e
972             do
973                 sed="$sed -e '$e'"
974             done
975             cp $dsttmp $dsttmp.old
976             chmod u+w $dsttmp
977             eval "$sed <$dsttmp.old >$dsttmp" || shtool_exit $?
978             rm -f $dsttmp.old
979         fi
980         if [ ".$opt_s" = .yes ]; then
981             if [ ".$opt_t" = .yes ]; then
982                 echo "strip $dsttmp" 1>&2
983             fi
984             strip $dsttmp || shtool_exit $?
985         fi
986         if [ ".$opt_o" != . ]; then
987             if [ ".$opt_t" = .yes ]; then
988                 echo "chown $opt_o $dsttmp" 1>&2
989             fi
990             chown $opt_o $dsttmp || shtool_exit $?
991         fi
992         if [ ".$opt_g" != . ]; then
993             if [ ".$opt_t" = .yes ]; then
994                 echo "chgrp $opt_g $dsttmp" 1>&2
995             fi
996             chgrp $opt_g $dsttmp || shtool_exit $?
997         fi
998         if [ ".$opt_m" != ".-" ]; then
999             if [ ".$opt_t" = .yes ]; then
1000                 echo "chmod $opt_m $dsttmp" 1>&2
1001             fi
1002             chmod $opt_m $dsttmp || shtool_exit $?
1003         fi
1004
1005         #   determine whether to do a quick install
1006         #   (has to be done _after_ the strip was already done)
1007         quick=no
1008         if [ ".$opt_C" = .yes ]; then
1009             if [ -r $dst ]; then
1010                 if cmp -s $src $dst; then
1011                     quick=yes
1012                 fi
1013             fi
1014         fi
1015
1016         #   finally, install the file to the real destination
1017         if [ $quick = yes ]; then
1018             if [ ".$opt_t" = .yes ]; then
1019                 echo "rm -f $dsttmp" 1>&2
1020             fi
1021             rm -f $dsttmp
1022         else
1023             if [ ".$opt_t" = .yes ]; then
1024                 echo "rm -f $dst && mv $dsttmp $dst" 1>&2
1025             fi
1026             rm -f $dst && mv $dsttmp $dst
1027         fi
1028     done
1029
1030     shtool_exit 0
1031     ;;
1032
1033 mkdir )
1034     ##
1035     ##  mkdir -- Make one or more directories
1036     ##  Copyright (c) 1996-2006 Ralf S. Engelschall <rse@engelschall.com>
1037     ##
1038
1039     errstatus=0
1040     for p in ${1+"$@"}; do
1041         #   if the directory already exists...
1042         if [ -d "$p" ]; then
1043             if [ ".$opt_f" = .no ] && [ ".$opt_p" = .no ]; then
1044                 echo "$msgprefix:Error: directory already exists: $p" 1>&2
1045                 errstatus=1
1046                 break
1047             else
1048                 continue
1049             fi
1050         fi
1051         #   if the directory has to be created...
1052         if [ ".$opt_p" = .no ]; then
1053             if [ ".$opt_t" = .yes ]; then
1054                 echo "mkdir $p" 1>&2
1055             fi
1056             mkdir $p || errstatus=$?
1057             if [ ".$opt_o" != . ]; then
1058                 if [ ".$opt_t" = .yes ]; then
1059                     echo "chown $opt_o $p" 1>&2
1060                 fi
1061                 chown $opt_o $p || errstatus=$?
1062             fi
1063             if [ ".$opt_g" != . ]; then
1064                 if [ ".$opt_t" = .yes ]; then
1065                     echo "chgrp $opt_g $p" 1>&2
1066                 fi
1067                 chgrp $opt_g $p || errstatus=$?
1068             fi
1069             if [ ".$opt_m" != . ]; then
1070                 if [ ".$opt_t" = .yes ]; then
1071                     echo "chmod $opt_m $p" 1>&2
1072                 fi
1073                 chmod $opt_m $p || errstatus=$?
1074             fi
1075         else
1076             #   the smart situation
1077             set fnord `echo ":$p" |\
1078                        sed -e 's/^:\//%/' \
1079                            -e 's/^://' \
1080                            -e 's/\// /g' \
1081                            -e 's/^%/\//'`
1082             shift
1083             pathcomp=''
1084             for d in ${1+"$@"}; do
1085                 pathcomp="$pathcomp$d"
1086                 case "$pathcomp" in
1087                     -* ) pathcomp="./$pathcomp" ;;
1088                 esac
1089                 if [ ! -d "$pathcomp" ]; then
1090                     if [ ".$opt_t" = .yes ]; then
1091                         echo "mkdir $pathcomp" 1>&2
1092                     fi
1093                     mkdir $pathcomp || errstatus=$?
1094                     if [ ".$opt_o" != . ]; then
1095                         if [ ".$opt_t" = .yes ]; then
1096                             echo "chown $opt_o $pathcomp" 1>&2
1097                         fi
1098                         chown $opt_o $pathcomp || errstatus=$?
1099                     fi
1100                     if [ ".$opt_g" != . ]; then
1101                         if [ ".$opt_t" = .yes ]; then
1102                             echo "chgrp $opt_g $pathcomp" 1>&2
1103                         fi
1104                         chgrp $opt_g $pathcomp || errstatus=$?
1105                     fi
1106                     if [ ".$opt_m" != . ]; then
1107                         if [ ".$opt_t" = .yes ]; then
1108                             echo "chmod $opt_m $pathcomp" 1>&2
1109                         fi
1110                         chmod $opt_m $pathcomp || errstatus=$?
1111                     fi
1112                 fi
1113                 pathcomp="$pathcomp/"
1114             done
1115         fi
1116     done
1117
1118     shtool_exit $errstatus
1119     ;;
1120
1121 mkln )
1122     ##
1123     ##  mkln -- Make link with calculation of relative paths
1124     ##  Copyright (c) 1998-2006 Ralf S. Engelschall <rse@engelschall.com>
1125     ##
1126
1127     #   determine source(s) and destination
1128     args=$?
1129     srcs=""
1130     while [ $# -gt 1 ]; do
1131         srcs="$srcs $1"
1132         shift
1133     done
1134     dst="$1"
1135     if [ ! -d $dst ]; then
1136         if [ $args -gt 2 ]; then
1137             echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2
1138             shtool_exit 1
1139         fi
1140     fi
1141
1142     #   determine link options
1143     lnopt=""
1144     if [ ".$opt_f" = .yes ]; then
1145         lnopt="$lnopt -f"
1146     fi
1147     if [ ".$opt_s" = .yes ]; then
1148         lnopt="$lnopt -s"
1149     fi
1150
1151     #   iterate over sources
1152     for src in $srcs; do
1153         #   determine if one of the paths is an absolute path,
1154         #   because then we _have_ to use an absolute symlink
1155         oneisabs=0
1156         srcisabs=0
1157         dstisabs=0
1158         case $src in
1159             /* ) oneisabs=1; srcisabs=1 ;;
1160         esac
1161         case $dst in
1162             /* ) oneisabs=1; dstisabs=1 ;;
1163         esac
1164
1165         #   split source and destination into dir and base name
1166         if [ -d $src ]; then
1167             srcdir=`echo $src | sed -e 's;/*$;;'`
1168             srcbase=""
1169         else
1170             srcdir=`echo  $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'`
1171             srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'`
1172         fi
1173         if [ -d $dst ]; then
1174             dstdir=`echo $dst | sed -e 's;/*$;;'`
1175             dstbase=""
1176         else
1177             dstdir=`echo  $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'`
1178             dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'`
1179         fi
1180
1181         #   consistency check
1182         if [ ".$dstdir" != . ]; then
1183             if [ ! -d $dstdir ]; then
1184                 echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2
1185                 shtool_exit 1
1186             fi
1187         fi
1188
1189         #   make sure the source is reachable from the destination
1190         if [ $dstisabs = 1 ]; then
1191             if [ $srcisabs = 0 ]; then
1192                 if [ ".$srcdir" = . ]; then
1193                     srcdir="`pwd | sed -e 's;/*$;;'`"
1194                     srcisabs=1
1195                     oneisabs=1
1196                 elif [ -d $srcdir ]; then
1197                     srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`"
1198                     srcisabs=1
1199                     oneisabs=1
1200                 fi
1201             fi
1202         fi
1203
1204         #   split away a common prefix
1205         prefix=""
1206         if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then
1207             prefix="$srcdir/"
1208             srcdir=""
1209             dstdir=""
1210         else
1211             while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do
1212                 presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'`
1213                 predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'`
1214                 if [ ".$presrc" != ".$predst" ]; then
1215                     break
1216                 fi
1217                 prefix="$prefix$presrc/"
1218                 srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'`
1219                 dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'`
1220             done
1221         fi
1222
1223         #   destination prefix is just the common prefix
1224         dstpre="$prefix"
1225
1226         #   determine source prefix which is the reverse directory
1227         #   step-up corresponding to the destination directory
1228         srcpre=""
1229
1230         isroot=0
1231         if [ ".$prefix" = . ] || [ ".$prefix" = ./ ]; then
1232             isroot=1
1233         fi
1234         if [ $oneisabs = 0 ] || [ $isroot = 0 ]; then
1235             pl="$dstdir/"
1236             OIFS="$IFS"; IFS='/'
1237             for pe in $pl; do
1238                 [ ".$pe" = .  ] && continue
1239                 [ ".$pe" = .. ] && continue
1240                 srcpre="../$srcpre"
1241             done
1242             IFS="$OIFS"
1243         else
1244             if [ $srcisabs = 1 ]; then
1245                 srcpre="$prefix"
1246             fi
1247         fi
1248
1249         #   determine destination symlink name
1250         if [ ".$dstbase" = . ]; then
1251             if [ ".$srcbase" != . ]; then
1252                 dstbase="$srcbase"
1253             else
1254                 dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'`
1255             fi
1256         fi
1257
1258         #   now finalize source and destination directory paths
1259         srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'`
1260         dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'`
1261
1262         #   run the final link command
1263         if [ ".$opt_t" = .yes ]; then
1264             echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase"
1265         fi
1266         eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase
1267     done
1268
1269     shtool_exit 0
1270     ;;
1271
1272 subst )
1273     ##
1274     ##  subst -- Apply sed(1) substitution operations
1275     ##  Copyright (c) 2001-2006 Ralf S. Engelschall <rse@engelschall.com>
1276     ##
1277
1278     #   remember optional list of file(s)
1279     files="$*"
1280     files_num="$#"
1281
1282     #   parameter consistency check
1283     if [ $# -eq 0 ] && [ ".$opt_b" != . ]; then
1284         echo "$msgprefix:Error: option -b cannot be applied to stdin" 1>&2
1285         shtool_exit 1
1286     fi
1287     if [ $# -eq 0 ] && [ ".$opt_s" = .yes ]; then
1288         echo "$msgprefix:Error: option -s cannot be applied to stdin" 1>&2
1289         shtool_exit 1
1290     fi
1291
1292     #   build underlying sed(1) command
1293     sedcmd='sed'
1294     if [ ".$opt_e" != . ]; then
1295         OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS"
1296         for e
1297         do
1298             sedcmd="$sedcmd -e '$e'"
1299         done
1300     elif [ ".$opt_f" != . ]; then
1301         if [ ! -f $opt_f ]; then
1302             echo "$msgprefix:Error: command file \`$opt_f' not found or not a regular file" 1>&2
1303             shtool_exit 1
1304         fi
1305         sedcmd="$sedcmd -f '$opt_f'"
1306     else
1307         echo "$msgprefix:Error: either -e option(s) or -f option required" 1>&2
1308         shtool_exit 1
1309     fi
1310
1311     #   determine extension for original file
1312     orig=".orig"
1313     if [ ".$opt_b" != . ]; then
1314         orig="$opt_b"
1315     fi
1316
1317     #   apply sed(1) operation(s)
1318     if [ ".$files" != . ]; then
1319         #   apply operation(s) to files
1320         substdone=no
1321         for file in $files; do
1322             test ".$file" = . && continue
1323             if [ ! -f $file ]; then
1324                 echo "$msgprefix:Warning: file \`$file' not found or not a regular file" 1>&2
1325                 continue
1326             fi
1327
1328             #   handle interactive mode
1329             if [ ".$opt_i" = .yes ]; then
1330                 eval "$sedcmd <$file >$file.new"
1331                 skip=no
1332                 if cmp $file $file.new >/dev/null 2>&1; then
1333                     rm -f $file.new
1334                     skip=yes
1335                 else
1336                     (diff -U1 $file $file.new >$tmpfile) 2>/dev/null
1337                     if [ ".`cat $tmpfile`" = . ]; then
1338                         (diff -C1 $file $file.new >$tmpfile) 2>/dev/null
1339                         if [ ".`cat $tmpfile`" = . ]; then
1340                             echo "$msgprefix:Warning: unable to show difference for file \`$file'" 1>&2
1341                             cp /dev/null $tmpfile
1342                         fi
1343                     fi
1344                     rm -f $file.new
1345                     cat $tmpfile
1346                     echo dummy | awk '{ printf("%s", TEXT); }' TEXT=">>> Apply [Y/n]: "
1347                     read input
1348                     if [ ".$input" != .Y ] &&\
1349                        [ ".$input" != .y ] &&\
1350                        [ ".$input" != . ]; then
1351                        skip=yes
1352                     fi
1353                 fi
1354                 if [ ".$skip" = .yes ]; then
1355                     if [ ".$opt_v" = .yes ]; then
1356                         echo "file \`$file' -- skipped" 1>&2
1357                     fi
1358                     continue
1359                 fi
1360             fi
1361
1362             #   apply sed(1) operation(s)
1363             if [ ".$opt_v" = .yes ]; then
1364                 echo "patching \`$file'" 1>&2
1365             fi
1366             if [ ".$opt_t" = .yes ]; then
1367                 echo "\$ cp -p $file $file$orig"
1368                 echo "\$ chmod u+w $file"
1369                 echo "\$ $sedcmd <$file$orig >$file"
1370             fi
1371             if [ ".$opt_n" = .no ]; then
1372                 cp -p $file $file$orig
1373                 chmod u+w $file >/dev/null 2>&1 || true
1374                 eval "$sedcmd <$file$orig >$file"
1375             fi
1376
1377             #   optionally fix timestamp
1378             if [ ".$opt_s" = .yes ]; then
1379                 if [ ".$opt_t" = .yes ]; then
1380                     echo "\$ touch -r $file$orig $file"
1381                 fi
1382                 if [ ".$opt_n" = .no ]; then
1383                     touch -r $file$orig $file
1384                 fi
1385             fi
1386
1387             #   optionally check whether any content change actually occurred 
1388             if [ ".$opt_q" = .no ]; then
1389                 if cmp $file$orig $file >/dev/null 2>&1; then
1390                     if [ ".$opt_w" = .yes ]; then
1391                         echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2
1392                     fi
1393                 else
1394                     substdone=yes
1395                 fi
1396             fi
1397
1398             #   optionally remove preserved original file
1399             if [ ".$opt_b" = . ]; then
1400                 if [ ".$opt_t" = .yes ]; then
1401                     echo "\$ rm -f $file$orig"
1402                 fi
1403                 if [ ".$opt_n" = .no ]; then
1404                     rm -f $file$orig
1405                 fi
1406             fi
1407         done
1408         if [ ".$opt_q" = .no ] && [ ".$opt_w" = .no ]; then
1409             if [ ".$substdone" = .no ]; then
1410                 if [ ".$files_num" = .1 ]; then
1411                     echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2
1412                 else
1413                     echo "$msgprefix:Warning: substitution resulted in no content change on any file" 1>&2
1414                 fi
1415             fi
1416         fi
1417     else
1418         #   apply operation(s) to stdin/stdout
1419         if [ ".$opt_v" = .yes ]; then
1420             echo "patching <stdin>" 1>&2
1421         fi
1422         if [ ".$opt_t" = .yes ]; then
1423             echo "\$ $sedcmd"
1424         fi
1425         if [ ".$opt_n" = .no ]; then
1426             eval "$sedcmd"
1427         fi
1428     fi
1429
1430     shtool_exit 0
1431     ;;
1432
1433 esac
1434
1435 shtool_exit 0
1436