Home | History | Annotate | Line # | Download | only in build
      1 #!/bin/sh
      2 ##
      3 ##  GNU shtool -- The GNU Portable Shell Tool
      4 ##  Copyright (c) 1994-2008 Ralf S. Engelschall <rse (at] 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.8 (18-Jul-2008)
     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 (at] 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.8 (18-Jul-2008)"
     96     echo 'Copyright (c) 1994-2008 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.8 (18-Jul-2008)"
    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 #   iterate 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 occurrences override)
    387             eval "opt_${opt_OPT}=\"\$opt_ARG\""
    388             ;;
    389         '+' )
    390             #   option with argument (multiple occurrences 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-2008 Ralf S. Engelschall <rse (at] 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=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \
    605                                     sed -e 'q' | sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'`
    606                             if [ ".$userid" = . ]; then
    607                                 userid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \
    608                                         sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'`
    609                                 if [ ".$userid" = . ]; then
    610                                     userid='?'
    611                                 fi
    612                             fi
    613                         fi
    614                     fi
    615                 fi
    616             fi
    617         fi
    618     fi
    619 
    620     #   determine (primary) group id
    621     groupid=''
    622     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then
    623         groupid="`(id -g ${username}) 2>/dev/null`"
    624         if [ ".$groupid" = . ]; then
    625             str="`(id) 2>/dev/null`"
    626             if [ ".`echo $str | grep 'gid[ 	]*=[ 	]*[0-9]*('`" != . ]; then
    627                 groupid=`echo $str | sed -e 's/^.*gid[ 	]*=[ 	]*//' -e 's/(.*$//'`
    628             fi
    629             if [ ".$groupid" = . ]; then
    630                 groupid=`(getent passwd ${username}) 2>/dev/null | \
    631                          sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
    632                 if [ ".$groupid" = . ]; then
    633                     groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \
    634                              sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
    635                     if [ ".$groupid" = . ]; then
    636                         groupid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \
    637                                  sed -e 'q' | sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
    638                         if [ ".$groupid" = . ]; then
    639                             groupid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \
    640                                      sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'`
    641                             if [ ".$groupid" = . ]; then
    642                                 groupid='?'
    643                             fi
    644                         fi
    645                     fi
    646                 fi
    647             fi
    648         fi
    649     fi
    650 
    651     #   determine (primary) group name
    652     groupname=''
    653     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then
    654         groupname="`(id -gn ${username}) 2>/dev/null`"
    655         if [ ".$groupname" = . ]; then
    656             str="`(id) 2>/dev/null`"
    657             if [ ".`echo $str | grep 'gid[ 	]*=[ 	]*[0-9]*('`" != . ]; then
    658                 groupname=`echo $str | sed -e 's/^.*gid[ 	]*=[ 	]*[0-9]*(//' -e 's/).*$//'`
    659             fi
    660             if [ ".$groupname" = . ]; then
    661                 groupname=`(getent group) 2>/dev/null | \
    662                            grep "^[^:]*:[^:]*:${groupid}:" | \
    663                            sed -e 's/:.*$//'`
    664                 if [ ".$groupname" = . ]; then
    665                     groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \
    666                                sed -e 's/:.*$//'`
    667                     if [ ".$groupname" = . ]; then
    668                         groupname=`(ypcat group; niscat group) 2>/dev/null | \
    669                                    sed -e 'q' | grep "^[^:]*:[^:]*:${groupid}:" | \
    670                                    sed -e 's/:.*$//'`
    671                         if [ ".$groupname" = . ]; then
    672                             groupname=`(nidump group .) 2>/dev/null | \
    673                                        grep "^[^:]*:[^:]*:${groupid}:" | \
    674                                        sed -e 's/:.*$//'`
    675                             if [ ".$groupname" = . ]; then
    676                                 groupname='?'
    677                             fi
    678                         fi
    679                     fi
    680                 fi
    681             fi
    682         fi
    683     fi
    684 
    685     #   determine host and domain name
    686     hostname=''
    687     domainname=''
    688     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then
    689         hostname="`(uname -n) 2>/dev/null |\
    690                    awk '{ printf("%s", $1); }'`"
    691         if [ ".$hostname" = . ]; then
    692             hostname="`(hostname) 2>/dev/null |\
    693                        awk '{ printf("%s", $1); }'`"
    694             if [ ".$hostname" = . ]; then
    695                 hostname='unknown'
    696             fi
    697         fi
    698         case $hostname in
    699             *.* )
    700                 domainname=".`echo $hostname | cut -d. -f2-`"
    701                 hostname="`echo $hostname | cut -d. -f1`"
    702                 ;;
    703         esac
    704     fi
    705     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then
    706         if [ ".$domainname" = . ]; then
    707             if [ -f /etc/resolv.conf ]; then
    708                 domainname="`grep '^[ 	]*domain' /etc/resolv.conf | sed -e 'q' |\
    709                              sed -e 's/.*domain//' \
    710                                  -e 's/^[ 	]*//' -e 's/^ *//' -e 's/^	*//' \
    711                                  -e 's/^\.//' -e 's/^/./' |\
    712                              awk '{ printf("%s", $1); }'`"
    713                 if [ ".$domainname" = . ]; then
    714                     domainname="`grep '^[ 	]*search' /etc/resolv.conf | sed -e 'q' |\
    715                                  sed -e 's/.*search//' \
    716                                      -e 's/^[ 	]*//' -e 's/^ *//' -e 's/^	*//' \
    717                                      -e 's/ .*//' -e 's/	.*//' \
    718                                      -e 's/^\.//' -e 's/^/./' |\
    719                                  awk '{ printf("%s", $1); }'`"
    720                 fi
    721             fi
    722         fi
    723     fi
    724 
    725     #   determine current time
    726     time_day=''
    727     time_month=''
    728     time_year=''
    729     time_monthname=''
    730     if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then
    731         time_day=`date '+%d'`
    732         time_month=`date '+%m'`
    733         time_year=`date '+%Y' 2>/dev/null`
    734         if [ ".$time_year" = . ]; then
    735             time_year=`date '+%y'`
    736             case $time_year in
    737                 [5-9][0-9]) time_year="19$time_year" ;;
    738                 [0-4][0-9]) time_year="20$time_year" ;;
    739             esac
    740         fi
    741         case $time_month in
    742             1|01) time_monthname='Jan' ;;
    743             2|02) time_monthname='Feb' ;;
    744             3|03) time_monthname='Mar' ;;
    745             4|04) time_monthname='Apr' ;;
    746             5|05) time_monthname='May' ;;
    747             6|06) time_monthname='Jun' ;;
    748             7|07) time_monthname='Jul' ;;
    749             8|08) time_monthname='Aug' ;;
    750             9|09) time_monthname='Sep' ;;
    751               10) time_monthname='Oct' ;;
    752               11) time_monthname='Nov' ;;
    753               12) time_monthname='Dec' ;;
    754         esac
    755     fi
    756 
    757     #   expand special ``%x'' constructs
    758     if [ ".$opt_e" = .yes ]; then
    759         text=`echo $seo "$text" |\
    760               sed -e "s/%B/${term_bold}/g" \
    761                   -e "s/%b/${term_norm}/g" \
    762                   -e "s/%u/${username}/g" \
    763                   -e "s/%U/${userid}/g" \
    764                   -e "s/%g/${groupname}/g" \
    765                   -e "s/%G/${groupid}/g" \
    766                   -e "s/%h/${hostname}/g" \
    767                   -e "s/%d/${domainname}/g" \
    768                   -e "s/%D/${time_day}/g" \
    769                   -e "s/%M/${time_month}/g" \
    770                   -e "s/%Y/${time_year}/g" \
    771                   -e "s/%m/${time_monthname}/g" 2>/dev/null`
    772     fi
    773 
    774     #   create output
    775     if [ .$opt_n = .no ]; then
    776         echo $seo "$text"
    777     else
    778         #   the harder part: echo -n is best, because
    779         #   awk may complain about some \xx sequences.
    780         if [ ".$minusn" != . ]; then
    781             echo $seo $minusn "$text"
    782         else
    783             echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text"
    784         fi
    785     fi
    786 
    787     shtool_exit 0
    788     ;;
    789 
    790 move )
    791     ##
    792     ##  move -- Move files with simultaneous substitution
    793     ##  Copyright (c) 1999-2008 Ralf S. Engelschall <rse (at] engelschall.com>
    794     ##
    795 
    796     src="$1"
    797     dst="$2"
    798 
    799     #   consistency checks
    800     if [ ".$src" = . ] || [ ".$dst" = . ]; then
    801         echo "$msgprefix:Error: Invalid arguments" 1>&2
    802         shtool_exit 1
    803     fi
    804     if [ ".$src" = ".$dst" ]; then
    805         echo "$msgprefix:Error: Source and destination files are the same" 1>&2
    806         shtool_exit 1
    807     fi
    808     expsrc="$src"
    809     if [ ".$opt_e" = .yes ]; then
    810         expsrc="`echo $expsrc`"
    811     fi
    812     if [ ".$opt_e" = .yes ]; then
    813         if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then
    814             echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2
    815             shtool_exit 1
    816         fi
    817         if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then
    818             echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2
    819             shtool_exit 1
    820         fi
    821         if [ ".$expsrc" = ".$src" ]; then
    822             echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2
    823             shtool_exit 1
    824         fi
    825     else
    826         if [ ! -r "$src" ]; then
    827             echo "$msgprefix:Error: Source not found: $src" 1>&2
    828             shtool_exit 1
    829         fi
    830     fi
    831 
    832     #   determine substitution patterns
    833     if [ ".$opt_e" = .yes ]; then
    834         srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'`
    835         dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'`
    836     fi
    837 
    838     #   iterate over source(s)
    839     for onesrc in $expsrc; do
    840         if [ .$opt_e = .yes ]; then
    841             onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"`
    842         else
    843             onedst="$dst"
    844         fi
    845         errorstatus=0
    846         if [ ".$opt_v" = .yes ]; then
    847             echo "$onesrc -> $onedst"
    848         fi
    849         if [ ".$opt_p" = .yes ]; then
    850             if [ -r $onedst ]; then
    851                 if cmp -s $onesrc $onedst; then
    852                     if [ ".$opt_t" = .yes ]; then
    853                         echo "rm -f $onesrc" 1>&2
    854                     fi
    855                     rm -f $onesrc || errorstatus=$?
    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             else
    863                 if [ ".$opt_t" = .yes ]; then
    864                     echo "mv -f $onesrc $onedst" 1>&2
    865                 fi
    866                 mv -f $onesrc $onedst || errorstatus=$?
    867             fi
    868         else
    869             if [ ".$opt_t" = .yes ]; then
    870                 echo "mv -f $onesrc $onedst" 1>&2
    871             fi
    872             mv -f $onesrc $onedst || errorstatus=$?
    873         fi
    874         if [ $errorstatus -ne 0 ]; then
    875             break;
    876         fi
    877     done
    878 
    879     shtool_exit $errorstatus
    880     ;;
    881 
    882 install )
    883     ##
    884     ##  install -- Install a program, script or datafile
    885     ##  Copyright (c) 1997-2008 Ralf S. Engelschall <rse (at] engelschall.com>
    886     ##
    887 
    888     #   special case: "shtool install -d <dir> [...]" internally
    889     #   maps to "shtool mkdir -f -p -m 755 <dir> [...]"
    890     if [ "$opt_d" = yes ]; then
    891         cmd="$0 mkdir -f -p -m 755"
    892         if [ ".$opt_o" != . ]; then
    893             cmd="$cmd -o '$opt_o'"
    894         fi
    895         if [ ".$opt_g" != . ]; then
    896             cmd="$cmd -g '$opt_g'"
    897         fi
    898         if [ ".$opt_v" = .yes ]; then
    899             cmd="$cmd -v"
    900         fi
    901         if [ ".$opt_t" = .yes ]; then
    902             cmd="$cmd -t"
    903         fi
    904         for dir in "$@"; do
    905             eval "$cmd $dir" || shtool_exit $?
    906         done
    907         shtool_exit 0
    908     fi
    909 
    910     #   determine source(s) and destination
    911     argc=$#
    912     srcs=""
    913     while [ $# -gt 1 ]; do
    914         srcs="$srcs $1"
    915         shift
    916     done
    917     dstpath="$1"
    918 
    919     #   type check for destination
    920     dstisdir=0
    921     if [ -d $dstpath ]; then
    922         dstpath=`echo "$dstpath" | sed -e 's:/$::'`
    923         dstisdir=1
    924     fi
    925 
    926     #   consistency check for destination
    927     if [ $argc -gt 2 ] && [ $dstisdir = 0 ]; then
    928         echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2
    929         shtool_exit 1
    930     fi
    931 
    932     #   iterate over all source(s)
    933     for src in $srcs; do
    934         dst=$dstpath
    935 
    936         #   if destination is a directory, append the input filename
    937         if [ $dstisdir = 1 ]; then
    938             dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'`
    939             dst="$dst/$dstfile"
    940         fi
    941 
    942         #   check for correct arguments
    943         if [ ".$src" = ".$dst" ]; then
    944             echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2
    945             continue
    946         fi
    947         if [ -d "$src" ]; then
    948             echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2
    949             continue
    950         fi
    951 
    952         #   make a temp file name in the destination directory
    953         dsttmp=`echo $dst |\
    954                 sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \
    955                     -e "s;\$;/#INST@$$#;"`
    956 
    957         #   verbosity
    958         if [ ".$opt_v" = .yes ]; then
    959             echo "$src -> $dst" 1>&2
    960         fi
    961 
    962         #   copy or move the file name to the temp name
    963         #   (because we might be not allowed to change the source)
    964         if [ ".$opt_C" = .yes ]; then
    965             opt_c=yes
    966         fi
    967         if [ ".$opt_c" = .yes ]; then
    968             if [ ".$opt_t" = .yes ]; then
    969                 echo "cp $src $dsttmp" 1>&2
    970             fi
    971             cp "$src" "$dsttmp" || shtool_exit $?
    972         else
    973             if [ ".$opt_t" = .yes ]; then
    974                 echo "mv $src $dsttmp" 1>&2
    975             fi
    976             mv "$src" "$dsttmp" || shtool_exit $?
    977         fi
    978 
    979         #   adjust the target file
    980         if [ ".$opt_e" != . ]; then
    981             sed='sed'
    982             OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS"
    983             for e
    984             do
    985                 sed="$sed -e '$e'"
    986             done
    987             cp "$dsttmp" "$dsttmp.old"
    988             chmod u+w $dsttmp
    989             eval "$sed <$dsttmp.old >$dsttmp" || shtool_exit $?
    990             rm -f $dsttmp.old
    991         fi
    992         if [ ".$opt_s" = .yes ]; then
    993             if [ ".$opt_t" = .yes ]; then
    994                 echo "strip $dsttmp" 1>&2
    995             fi
    996             ${STRIP:-strip} $dsttmp || shtool_exit $?
    997         fi
    998         if [ ".$opt_o" != . ]; then
    999             if [ ".$opt_t" = .yes ]; then
   1000                 echo "chown $opt_o $dsttmp" 1>&2
   1001             fi
   1002             chown $opt_o $dsttmp || shtool_exit $?
   1003         fi
   1004         if [ ".$opt_g" != . ]; then
   1005             if [ ".$opt_t" = .yes ]; then
   1006                 echo "chgrp $opt_g $dsttmp" 1>&2
   1007             fi
   1008             chgrp $opt_g $dsttmp || shtool_exit $?
   1009         fi
   1010         if [ ".$opt_m" != ".-" ]; then
   1011             if [ ".$opt_t" = .yes ]; then
   1012                 echo "chmod $opt_m $dsttmp" 1>&2
   1013             fi
   1014             chmod $opt_m $dsttmp || shtool_exit $?
   1015         fi
   1016 
   1017         #   determine whether to do a quick install
   1018         #   (has to be done _after_ the strip was already done)
   1019         quick=no
   1020         if [ ".$opt_C" = .yes ]; then
   1021             if [ -r $dst ]; then
   1022                 if cmp -s "$src" "$dst"; then
   1023                     quick=yes
   1024                 fi
   1025             fi
   1026         fi
   1027 
   1028         #   finally, install the file to the real destination
   1029         if [ $quick = yes ]; then
   1030             if [ ".$opt_t" = .yes ]; then
   1031                 echo "rm -f $dsttmp" 1>&2
   1032             fi
   1033             rm -f $dsttmp
   1034         else
   1035             if [ ".$opt_t" = .yes ]; then
   1036                 echo "rm -f $dst && mv $dsttmp $dst" 1>&2
   1037             fi
   1038             rm -f $dst && mv $dsttmp $dst
   1039         fi
   1040     done
   1041 
   1042     shtool_exit 0
   1043     ;;
   1044 
   1045 mkdir )
   1046     ##
   1047     ##  mkdir -- Make one or more directories
   1048     ##  Copyright (c) 1996-2008 Ralf S. Engelschall <rse (at] engelschall.com>
   1049     ##
   1050 
   1051     errstatus=0
   1052     for p in ${1+"$@"}; do
   1053         #   if the directory already exists...
   1054         if [ -d "$p" ]; then
   1055             if [ ".$opt_f" = .no ] && [ ".$opt_p" = .no ]; then
   1056                 echo "$msgprefix:Error: directory already exists: $p" 1>&2
   1057                 errstatus=1
   1058                 break
   1059             else
   1060                 continue
   1061             fi
   1062         fi
   1063         #   if the directory has to be created...
   1064         if [ ".$opt_p" = .no ]; then
   1065             if [ ".$opt_t" = .yes ]; then
   1066                 echo "mkdir $p" 1>&2
   1067             fi
   1068             mkdir $p || errstatus=$?
   1069             if [ ".$opt_o" != . ]; then
   1070                 if [ ".$opt_t" = .yes ]; then
   1071                     echo "chown $opt_o $p" 1>&2
   1072                 fi
   1073                 chown $opt_o $p || errstatus=$?
   1074             fi
   1075             if [ ".$opt_g" != . ]; then
   1076                 if [ ".$opt_t" = .yes ]; then
   1077                     echo "chgrp $opt_g $p" 1>&2
   1078                 fi
   1079                 chgrp $opt_g $p || errstatus=$?
   1080             fi
   1081             if [ ".$opt_m" != . ]; then
   1082                 if [ ".$opt_t" = .yes ]; then
   1083                     echo "chmod $opt_m $p" 1>&2
   1084                 fi
   1085                 chmod $opt_m $p || errstatus=$?
   1086             fi
   1087         else
   1088             #   the smart situation
   1089             set fnord `echo ":$p" |\
   1090                        sed -e 's/^:\//%/' \
   1091                            -e 's/^://' \
   1092                            -e 's/\// /g' \
   1093                            -e 's/^%/\//'`
   1094             shift
   1095             pathcomp=''
   1096             for d in ${1+"$@"}; do
   1097                 pathcomp="$pathcomp$d"
   1098                 case "$pathcomp" in
   1099                     -* ) pathcomp="./$pathcomp" ;;
   1100                 esac
   1101                 if [ ! -d "$pathcomp" ]; then
   1102                     if [ ".$opt_t" = .yes ]; then
   1103                         echo "mkdir $pathcomp" 1>&2
   1104                     fi
   1105                     mkdir $pathcomp || errstatus=$?
   1106                     if [ ".$opt_o" != . ]; then
   1107                         if [ ".$opt_t" = .yes ]; then
   1108                             echo "chown $opt_o $pathcomp" 1>&2
   1109                         fi
   1110                         chown $opt_o $pathcomp || errstatus=$?
   1111                     fi
   1112                     if [ ".$opt_g" != . ]; then
   1113                         if [ ".$opt_t" = .yes ]; then
   1114                             echo "chgrp $opt_g $pathcomp" 1>&2
   1115                         fi
   1116                         chgrp $opt_g $pathcomp || errstatus=$?
   1117                     fi
   1118                     if [ ".$opt_m" != . ]; then
   1119                         if [ ".$opt_t" = .yes ]; then
   1120                             echo "chmod $opt_m $pathcomp" 1>&2
   1121                         fi
   1122                         chmod $opt_m $pathcomp || errstatus=$?
   1123                     fi
   1124                 fi
   1125                 pathcomp="$pathcomp/"
   1126             done
   1127         fi
   1128     done
   1129 
   1130     shtool_exit $errstatus
   1131     ;;
   1132 
   1133 mkln )
   1134     ##
   1135     ##  mkln -- Make link with calculation of relative paths
   1136     ##  Copyright (c) 1998-2008 Ralf S. Engelschall <rse (at] engelschall.com>
   1137     ##
   1138 
   1139     #   determine source(s) and destination
   1140     args=$#
   1141     srcs=""
   1142     while [ $# -gt 1 ]; do
   1143         srcs="$srcs $1"
   1144         shift
   1145     done
   1146     dst="$1"
   1147     if [ ! -d $dst ]; then
   1148         if [ $args -gt 2 ]; then
   1149             echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2
   1150             shtool_exit 1
   1151         fi
   1152     fi
   1153 
   1154     #   determine link options
   1155     lnopt=""
   1156     if [ ".$opt_f" = .yes ]; then
   1157         lnopt="$lnopt -f"
   1158     fi
   1159     if [ ".$opt_s" = .yes ]; then
   1160         lnopt="$lnopt -s"
   1161     fi
   1162 
   1163     #   iterate over sources
   1164     for src in $srcs; do
   1165         #   determine if one of the paths is an absolute path,
   1166         #   because then we _have_ to use an absolute symlink
   1167         oneisabs=0
   1168         srcisabs=0
   1169         dstisabs=0
   1170         case $src in
   1171             /* ) oneisabs=1; srcisabs=1 ;;
   1172         esac
   1173         case $dst in
   1174             /* ) oneisabs=1; dstisabs=1 ;;
   1175         esac
   1176 
   1177         #   split source and destination into dir and base name
   1178         if [ -d $src ]; then
   1179             srcdir=`echo $src | sed -e 's;/*$;;'`
   1180             srcbase=""
   1181         else
   1182             srcdir=`echo  $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'`
   1183             srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'`
   1184         fi
   1185         if [ -d $dst ]; then
   1186             dstdir=`echo $dst | sed -e 's;/*$;;'`
   1187             dstbase=""
   1188         else
   1189             dstdir=`echo  $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'`
   1190             dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'`
   1191         fi
   1192 
   1193         #   consistency check
   1194         if [ ".$dstdir" != . ]; then
   1195             if [ ! -d $dstdir ]; then
   1196                 echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2
   1197                 shtool_exit 1
   1198             fi
   1199         fi
   1200 
   1201         #   make sure the source is reachable from the destination
   1202         if [ $dstisabs = 1 ]; then
   1203             if [ $srcisabs = 0 ]; then
   1204                 if [ ".$srcdir" = . ]; then
   1205                     srcdir="`pwd | sed -e 's;/*$;;'`"
   1206                     srcisabs=1
   1207                     oneisabs=1
   1208                 elif [ -d $srcdir ]; then
   1209                     srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`"
   1210                     srcisabs=1
   1211                     oneisabs=1
   1212                 fi
   1213             fi
   1214         fi
   1215 
   1216         #   split away a common prefix
   1217         prefix=""
   1218         if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then
   1219             prefix="$srcdir/"
   1220             srcdir=""
   1221             dstdir=""
   1222         else
   1223             while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do
   1224                 presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'`
   1225                 predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'`
   1226                 if [ ".$presrc" != ".$predst" ]; then
   1227                     break
   1228                 fi
   1229                 prefix="$prefix$presrc/"
   1230                 srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'`
   1231                 dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'`
   1232             done
   1233         fi
   1234 
   1235         #   destination prefix is just the common prefix
   1236         dstpre="$prefix"
   1237 
   1238         #   determine source prefix which is the reverse directory
   1239         #   step-up corresponding to the destination directory
   1240         srcpre=""
   1241         allow_relative_srcpre=no
   1242         if [ ".$prefix" != . ] && [ ".$prefix" != ./ ]; then
   1243             allow_relative_srcpre=yes
   1244         fi
   1245         if [ $oneisabs = 0 ]; then
   1246             allow_relative_srcpre=yes
   1247         fi
   1248         if [ ".$opt_s" != .yes ]; then
   1249             allow_relative_srcpre=no
   1250         fi
   1251         if [ ".$allow_relative_srcpre" = .yes ]; then
   1252             pl="$dstdir/"
   1253             OIFS="$IFS"; IFS='/'
   1254             for pe in $pl; do
   1255                 [ ".$pe" = .  ] && continue
   1256                 [ ".$pe" = .. ] && continue
   1257                 srcpre="../$srcpre"
   1258             done
   1259             IFS="$OIFS"
   1260         else
   1261             if [ $srcisabs = 1 ]; then
   1262                 srcpre="$prefix"
   1263             fi
   1264         fi
   1265 
   1266         #   determine destination symlink name
   1267         if [ ".$dstbase" = . ]; then
   1268             if [ ".$srcbase" != . ]; then
   1269                 dstbase="$srcbase"
   1270             else
   1271                 dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'`
   1272             fi
   1273         fi
   1274 
   1275         #   now finalize source and destination directory paths
   1276         srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'`
   1277         dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'`
   1278 
   1279         #   run the final link command
   1280         if [ ".$opt_t" = .yes ]; then
   1281             echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase"
   1282         fi
   1283         eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase
   1284     done
   1285 
   1286     shtool_exit 0
   1287     ;;
   1288 
   1289 subst )
   1290     ##
   1291     ##  subst -- Apply sed(1) substitution operations
   1292     ##  Copyright (c) 2001-2008 Ralf S. Engelschall <rse (at] engelschall.com>
   1293     ##
   1294 
   1295     #   remember optional list of file(s)
   1296     files="$*"
   1297     files_num="$#"
   1298 
   1299     #   parameter consistency check
   1300     if [ $# -eq 0 ] && [ ".$opt_b" != . ]; then
   1301         echo "$msgprefix:Error: option -b cannot be applied to stdin" 1>&2
   1302         shtool_exit 1
   1303     fi
   1304     if [ $# -eq 0 ] && [ ".$opt_s" = .yes ]; then
   1305         echo "$msgprefix:Error: option -s cannot be applied to stdin" 1>&2
   1306         shtool_exit 1
   1307     fi
   1308 
   1309     #   build underlying sed(1) command
   1310     sedcmd='sed'
   1311     if [ ".$opt_e" != . ]; then
   1312         OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS"
   1313         for e
   1314         do
   1315             sedcmd="$sedcmd -e '$e'"
   1316         done
   1317     elif [ ".$opt_f" != . ]; then
   1318         if [ ! -f $opt_f ]; then
   1319             echo "$msgprefix:Error: command file \`$opt_f' not found or not a regular file" 1>&2
   1320             shtool_exit 1
   1321         fi
   1322         sedcmd="$sedcmd -f '$opt_f'"
   1323     else
   1324         echo "$msgprefix:Error: either -e option(s) or -f option required" 1>&2
   1325         shtool_exit 1
   1326     fi
   1327 
   1328     #   determine extension for original file
   1329     orig=".orig"
   1330     if [ ".$opt_b" != . ]; then
   1331         orig="$opt_b"
   1332     fi
   1333 
   1334     #   apply sed(1) operation(s)
   1335     if [ ".$files" != . ]; then
   1336         #   apply operation(s) to files
   1337         substdone=no
   1338         for file in $files; do
   1339             test ".$file" = . && continue
   1340             if [ ! -f $file ]; then
   1341                 echo "$msgprefix:Warning: file \`$file' not found or not a regular file" 1>&2
   1342                 continue
   1343             fi
   1344 
   1345             #   handle interactive mode
   1346             if [ ".$opt_i" = .yes ]; then
   1347                 eval "$sedcmd <$file >$file.new"
   1348                 skip=no
   1349                 if cmp $file $file.new >/dev/null 2>&1; then
   1350                     rm -f $file.new
   1351                     skip=yes
   1352                 else
   1353                     (diff -U1 $file $file.new >$tmpfile) 2>/dev/null
   1354                     if [ ".`cat $tmpfile`" = . ]; then
   1355                         (diff -C1 $file $file.new >$tmpfile) 2>/dev/null
   1356                         if [ ".`cat $tmpfile`" = . ]; then
   1357                             echo "$msgprefix:Warning: unable to show difference for file \`$file'" 1>&2
   1358                             cp /dev/null $tmpfile
   1359                         fi
   1360                     fi
   1361                     rm -f $file.new
   1362                     cat $tmpfile
   1363                     echo dummy | awk '{ printf("%s", TEXT); }' TEXT=">>> Apply [Y/n]: "
   1364                     read input
   1365                     if [ ".$input" != .Y ] &&\
   1366                        [ ".$input" != .y ] &&\
   1367                        [ ".$input" != . ]; then
   1368                        skip=yes
   1369                     fi
   1370                 fi
   1371                 if [ ".$skip" = .yes ]; then
   1372                     if [ ".$opt_v" = .yes ]; then
   1373                         echo "file \`$file' -- skipped" 1>&2
   1374                     fi
   1375                     continue
   1376                 fi
   1377             fi
   1378 
   1379             #   apply sed(1) operation(s)
   1380             if [ ".$opt_v" = .yes ]; then
   1381                 echo "patching \`$file'" 1>&2
   1382             fi
   1383             if [ ".$opt_t" = .yes ]; then
   1384                 echo "\$ cp -p $file $file$orig"
   1385                 echo "\$ chmod u+w $file"
   1386                 echo "\$ $sedcmd <$file$orig >$file"
   1387             fi
   1388             if [ ".$opt_n" = .no ]; then
   1389                 cp -p $file $file$orig
   1390                 chmod u+w $file >/dev/null 2>&1 || true
   1391                 eval "$sedcmd <$file$orig >$file"
   1392             fi
   1393 
   1394             #   optionally fix timestamp
   1395             if [ ".$opt_s" = .yes ]; then
   1396                 if [ ".$opt_t" = .yes ]; then
   1397                     echo "\$ touch -r $file$orig $file"
   1398                 fi
   1399                 if [ ".$opt_n" = .no ]; then
   1400                     touch -r $file$orig $file
   1401                 fi
   1402             fi
   1403 
   1404             #   optionally check whether any content change actually occurred
   1405             if [ ".$opt_q" = .no ]; then
   1406                 if cmp $file$orig $file >/dev/null 2>&1; then
   1407                     if [ ".$opt_w" = .yes ]; then
   1408                         echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2
   1409                     fi
   1410                 else
   1411                     substdone=yes
   1412                 fi
   1413             fi
   1414 
   1415             #   optionally remove preserved original file
   1416             if [ ".$opt_b" = . ]; then
   1417                 if [ ".$opt_t" = .yes ]; then
   1418                     echo "\$ rm -f $file$orig"
   1419                 fi
   1420                 if [ ".$opt_n" = .no ]; then
   1421                     rm -f $file$orig
   1422                 fi
   1423             fi
   1424         done
   1425         if [ ".$opt_q" = .no ] && [ ".$opt_w" = .no ]; then
   1426             if [ ".$substdone" = .no ]; then
   1427                 if [ ".$files_num" = .1 ]; then
   1428                     echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2
   1429                 else
   1430                     echo "$msgprefix:Warning: substitution resulted in no content change on any file" 1>&2
   1431                 fi
   1432             fi
   1433         fi
   1434     else
   1435         #   apply operation(s) to stdin/stdout
   1436         if [ ".$opt_v" = .yes ]; then
   1437             echo "patching <stdin>" 1>&2
   1438         fi
   1439         if [ ".$opt_t" = .yes ]; then
   1440             echo "\$ $sedcmd"
   1441         fi
   1442         if [ ".$opt_n" = .no ]; then
   1443             eval "$sedcmd"
   1444         fi
   1445     fi
   1446 
   1447     shtool_exit 0
   1448     ;;
   1449 
   1450 esac
   1451 
   1452 shtool_exit 0
   1453 
   1454