#!/bin/sh
#
# INSTALL (C) 2002 Emile van Bergen. Distribution of this file is allowed under
# the conditions detailed in the GNU General Public License (GPL). See the file
# COPYING for more information.
#
# This script installs zero or more files into a specified directory. If one or
# more components of the destination path do not exist, they are created.  The
# permissions of the destination file and the destination directory(s), if any
# need to be created, can be specified separately. The user can also specify
# that the operation must be skipped if the destination file or the destination
# directory already exists. Source files are stripped of their directory
# components before determining the destination name.
#
# It is intended to replace the /usr/bin/install command, which has no portable
# subset of features that offers anything above /bin/cp. Each version is broken
# in its own ways, the most annoying examples being that some can only install
# a single file at a time and that some do not create destination directories
# recursively. Hence this shell script, that is intended to be portable across
# all POSIX-compliant /bin/sh shells. It does not assume a working 'mkdir -p'
# command.
#
# Invocation:
#
# install arguments...
#
# Each argument is either an option, as specified below, either a source file,
# or a destination directory, with -d prepended. Each time a destination
# directory is encountered, the source files leading up to it are installed,
# and then all options are reset, allowing you to perform multiple install
# operations with one command. Source directories are copied recursively,
# including the source directory name itself.
#
# Options:
#
#	-h	Show a brief usage message
# 	-v	Show what's being done
#	-m	specify mode of destination files
#	-md	specify mode of destination directories, if any are created
#	-n	skip operation if destination file exists
#	-nd	skip operation if destination directory exists
#
# Return values:
#
# 	0	Successful completion
#	>0	Error occurred
#
# Limitations:
#
# * Source files cannot start with a '-' or contain spaces
# * You cannot specify source directories for recursive copying. POSIX cp
#   does not support recursive copies.
# * Destination directories cannot start with a '-' or contain spaces
# * If multiple different modes are desired for files in a single destination 
#   directory, you must specify multiple installation sets (-d options), one 
#   for each mode (eg. install -m 644 file1 file2 -d dir file3 -m 600 -d dir).
# * The /bin/sh shell used to run this script must support user-defined 
#   functions.
# * The system must have mkdir, chmod, basename, tr, sed and cp available.
#   If needed, basename and tr could be provided by sed, but I don't think
#   that should be done by default as they are very common.
#
# Notes (not bugs, features. Really!):
#
# * If the destination directory already exists, its mode is not changed
#   even if -md is specified; that mode is only used when creating new ones.
# * If the destination file already exists but is overwritten because no -n
#   was specified, the new mode, if specified, is applied as well.
# * QNX-style paths starting with // are honored, as are .. path components.
#   An initial .. works as expected, and a destination path a/b/../c creates
#   a, a/b, a/c and installs the files in a/c.
#
# History
#
# 2002/09/13 - EvB - Created


make_dir() {

  dir="$1"
  [ -n "$verbose" ] && echo "Creating directory $dir"

  mkdir "$dir" || exit 1

  if [ -n "$mode_dir" ] 
  then
    chmod "$mode_dir" "$dir" || exit 2
  fi

  return
}


make_dir_tree() {

  root=`echo $1 | sed -e 's/[^/].*$//g'`
  components=`echo $1 | tr / " "`

  cumul=
  for comp in $components
  do
    if [ -n "$cumul" ] 
    then
      cumul="$cumul/$comp"
    else
      cumul="$comp"
    fi
    [ "$comp" = "." ] || [ "$comp" = ".." ] || 
      [ -d "$root$cumul" ] || make_dir "$root$cumul"
  done

  dest=$root$cumul
}


do_install() {

  dest="$1"

  if [ ! -d "$dest" ] 
  then
    make_dir_tree "$dest"
  else
    if [ -n "$new_dir" ]
    then
      echo "$me: Directory $dest already exists -- skipping"
      return
    fi
  fi

  for src_file in $src
  do
    file=`basename $src_file`
    dest_file="$dest/$file"

    if [ -n "$new" ] && [ -f $dest_file ]
    then
      echo "$me: File $dest_file already exists -- skipping"
      continue
    fi

    [ -n "$verbose" ] && echo "Copying $src_file to $dest_file"
    cp "$src_file" "$dest_file" || exit 3

    if [ -n "$mode" ] 
    then
      chmod "$mode" "$dest_file" || exit 4
    fi
  done

  return
}


init_opts() {
# verbose=
  mode=
  mode_dir=
  new=
  new_dir=
  src=
}


### Main entry point

me=`basename $0`
init_opts
while [ -n "$1" ]
do
  case "$1" in

    -v) verbose=1 ;;
    
    -m) mode="$2" ; shift ;;
    -md) mode_dir="$2" ; shift ;;

    -n) new=1 ;;
    -nd) new_dir=1 ;;

    -d) do_install "$2" ; init_opts ; shift ;;

    -*)
      echo Usage: $me [options] [file...] -d directory
      exit 5
      ;;

    *) src="$src $1" ;;

  esac
  shift
done

exit 0


syntax highlighted by Code2HTML, v. 0.9.1