
###############################################################################
## Utilities

PATH=/usr/bin:/bin

if test "x`echo -n`" = "x-n"; then
  echon() { /bin/echo "$*\c"; }
else
  echon() { echo -n "$*"; }
fi

rm_on_abort=""
failwith() {
  err="Error: "
  if test "x$1" = "x-noerror"; then err=""; shift; fi
  echo "$err$*" 1>&2
  if test ! "x$rm_on_abort" = "x" && test -e "$rm_on_abort"; then
    echon "  (Removing installation files in $rm_on_abort)"
    "$rm" -rf "$rm_on_abort"
    echo ""
  fi
  exit 1
}
# intentional aborts
abort() { failwith -noerror "Aborting installation."; }
# unexpected exits
exithandler() { echo ""; failwith "Aborting..."; }

trap exithandler 2 3 9 15

lookfor() {
  saved_IFS="${IFS}"
  IFS=":"
  for dir in $PATH; do
    if test -x "$dir/$1"; then
      eval "$1=$dir/$1"
      IFS="$saved_IFS"
      return
    fi
  done
  IFS="$saved_IFS"
  failwith "could not find \"$1\"."
}

lookfor rm
lookfor ls
lookfor ln
lookfor tail
lookfor cksum
lookfor tar
lookfor gunzip
lookfor mkdir
lookfor basename
lookfor dirname

# substitute env vars and tildes
expand_path_var() {
  eval "expanded_val=\"\$$1\""
  first_part="${expanded_val%%/*}"
  if [ "x$first_part" = "x$expanded_val" ]; then
    rest_parts=""
  else
    rest_parts="/${expanded_val#*/}"
  fi
  case "x$first_part" in
    x*" "* ) ;;
    x~* ) expanded_val="`eval \"echo $first_part\"`$rest_parts" ;;
  esac
  eval "$1=\"$expanded_val\""
}

# Need this to make new `tail' respect old-style command-line arguments.  Can't
# use `tail -n #' because some old tails won't know what to do with that.
_POSIX2_VERSION=199209
export _POSIX2_VERSION

origwd="`pwd`"
installer_file="$0"
cat_installer() {
  oldwd="`pwd`"; cd "$origwd"
  "$tail" +"$BINSTARTLINE" "$installer_file"
  cd "$oldwd"
}

echo "This program will extract and install $DISTNAME."
echo ""
echo "Note: the required diskspace for this installation is $ORIGSIZE."
echo ""

###############################################################################
## What kind of installation?

echo "Do you want a Unix-style distribution?"
echo "  In this distribution mode files go into different directories according"
echo "  to Unix conventions.  A \"racket-uninstall\" script will be generated"
echo "  to be used when you want to remove the installation.  If you say 'no',"
echo "  the whole Racket directory is kept in a single installation directory"
echo "  (movable and erasable), possibly with external links into it -- this is"
echo "  often more convenient, especially if you want to install multiple"
echo "  versions or keep it in your home directory."
if test ! "x$RELEASED" = "xyes"; then
  echo "*** This is a nightly build: such a unix-style distribution is *not*"
  echo "*** recommended because it cannot be used to install multiple versions."
fi
unixstyle="x"
while test "$unixstyle" = "x"; do
  echon "Enter yes/no (default: no) > "
  read unixstyle
  case "$unixstyle" in
    [yY]* ) unixstyle="Y" ;;
    [nN]* ) unixstyle="N" ;;
    "" )    unixstyle="N" ;;
    * )     unixstyle="x" ;;
  esac
done
echo ""

###############################################################################
## Where do you want it?
## sets $where to the location: target path for wholedir, prefix for unixstyle

if test "$unixstyle" = "Y"; then
  echo "Where do you want to base your installation of $DISTNAME?"
  echo "  (If you've done such an installation in the past, either"
  echo "   enter the same directory, or run 'racket-uninstall' manually.)"
  TARGET1="..."
else
  echo "Where do you want to install the \"$TARGET\" directory tree?"
  TARGET1="$TARGET"
fi
echo "  1 - /usr/$TARGET1 [default]"
echo "  2 - /usr/local/$TARGET1"
echo "  3 - ~/$TARGET1 ($HOME/$TARGET1)"
echo "  4 - ./$TARGET1 (here)"
if test "$unixstyle" = "Y"; then
  echo "  Or enter a different directory prefix to install in."
else
  echo "  Or enter a different \"racket\" directory to install in."
fi
echon "> "
read where

# numeric choice (make "." and "./" synonym for 4)
if test "$unixstyle" = "Y"; then TARGET1=""
else TARGET1="/$TARGET"; fi
case "x$where" in
  x | x1 ) where="/usr$TARGET1" ;;
  x2     ) where="/usr/local${TARGET1}" ;;
  x3     ) where="${HOME}${TARGET1}" ;;
  x4 | x. | x./ ) where="`pwd`${TARGET1}" ;;
  * ) expand_path_var where ;;
esac

###############################################################################
## Default system directories prefixed by $1, mimic configure behavior
## used for unixstyle targets and for wholedir links

set_dirs() {
  # unixstyle: uses all of these
  # wholedir: uses only bindir & mandir, no need for the others
  bindir="$1/bin"
  libdir="$1/lib"
  incrktdir="$1/include/$TARGET"
  librktdir="$1/lib/$TARGET"
  collectsdir="$1/lib/$TARGET/collects"
  has_share="N"
  if test -d "$1/share"; then has_share="Y"; fi
  if test "$has_share" = "N" && test -d "$1/doc"; then docdir="$1/doc/$TARGET"
  else docdir="$1/share/$TARGET/doc"
  fi
  if test "$has_share" = "N" && test -d "$1/man"; then mandir="$1/man"
  else mandir="$1/share/man"
  fi
  # The source tree is always removed -- no point keeping it if it won't work
  # if test "$has_share" = "N" && test -d "$1/src"; then srcdir="$1/src/$TARGET"
  # else srcdir="$1/share/$TARGET/src"
  # fi
}

###############################################################################
## Integrity check and unpack into $1
## also sets $INSTDIR to the directory in its canonical form

unpack_installation() {
  T="$1"
  # integrity check
  echo ""
  echon "Checking the integrity of the binary archive... "
  SUM="`cat_installer | \"$cksum\"`" || failwith "problems running cksum."
  SUM="`set $SUM; echo $1`"
  test "$BINSUM" = "$SUM" || failwith "bad CRC checksum."
  echo "ok."
  # test that the target does not exists
  here="N"
  if test -d "$T" || test -f "$T"; then
    if test -d "$T" && test -x "$T"; then
      # use the real name, so "/foo/.." shows as an explicit "/"
      oldwd="`pwd`"; cd "$T"; T="`pwd`"; cd "$oldwd"
    fi
    if test -f "$T"; then echon "\"$T\" exists (as a file)"
    elif test ! "`pwd`" = "$T"; then echon "\"$T\" exists"
    else here="Y"; echon "\"$T\" is where you ran the installer from"
    fi
    echon ", delete? "
    read R
    case "$R" in
      [yY]* )
        echon "Deleting old \"$T\"... "
        "$rm" -rf "$T" || failwith "could not delete \"$T\"."
        echo "done."
        ;;
      * ) abort ;;
    esac
  fi
  # unpack
  rm_on_abort="$T"
  "$mkdir" -p "$T" || failwith "could not create directory: $T"
  if test "$here" = "Y"; then
    cd "$T"; INSTDIR="$T"
    echo "*** Note: your original directory was deleted, so you will need"
    echo "*** to 'cd' back into it when the installer is done, otherwise"
    echo "*** it will look like you have an empty directory."
    sleep 1
  else oldwd="`pwd`"; cd "$T"; INSTDIR="`pwd`"; cd "$oldwd"
  fi
  rm_on_abort="$INSTDIR"
  echo "Unpacking into \"$INSTDIR\" (Ctrl+C to abort)..."
  cat_installer | "$gunzip" -c \
    | { cd "$INSTDIR"
        "$tar" xf - || failwith "problems during unpacking of binary archive."
      }
  test -d "$INSTDIR/collects" \
    || failwith "unpack failed (could not find \"$T/collects\")."
  echo "Done."
}

###############################################################################
## Whole-directory installations

wholedir_install() {

  unpack_installation "$where"
  rm_on_abort=""

  echo ""
  echo "If you want to install new system links within the \"bin\" and"
  echo "  \"man\" subdirectories of a common directory prefix (for example,"
  echo "  \"/usr/local\") then enter the prefix of an existing directory"
  echo "  that you want to use.  This might overwrite existing symlinks,"
  echo "  but not files."
  echon "(default: skip links) > "
  read SYSDIR
  if test "x$SYSDIR" = "x"; then :
  elif test ! -d "$SYSDIR"; then
    echo "\"$SYSDIR\" does not exist, skipping links."
  elif test ! -x "$SYSDIR" || test ! -w "$SYSDIR"; then
    echo "\"$SYSDIR\" is not writable, skipping links."
  else
    oldwd="`pwd`"; cd "$SYSDIR"; SYSDIR="`pwd`"; cd "$oldwd"
    set_dirs "$SYSDIR"
    install_links() { # tgtdir(absolute) srcdir(relative to INSTDIR)
      if ! test -d "$1"; then
        echo "\"$1\" does not exist, skipping."
      elif ! test -x "$1" || ! test -w "$1"; then
        echo "\"$1\" is not writable, skipping"
      else
        echo "Installing links in \"$1\"..."
        printsep="  "
        cd "$1"
        for x in `cd "$INSTDIR/$2"; ls`; do
          echon "${printsep}$x"; printsep=", "
          if test -h "$x"; then rm -f "$x"; fi
          if test -d "$x" || test -f "$x"; then
            echon " skipped (non-link exists)"
          elif ! "$ln" -s "$INSTDIR/$2/$x" "$x"; then
            echon " skipped (symlink failed)"
          fi
        done
        echo ""; echo "  done."
      fi
    }
    install_links "$bindir" "bin"
    install_links "$mandir/man1" "man/man1"
  fi

}

###############################################################################
## Unix-style installations

dir_createable() {
  tdir="`\"$dirname\" \"$1\"`"
  if test -d "$tdir" && test -x "$tdir" && test -w "$tdir"; then return 0
  elif test "$tdir" = "/"; then return 1
  else dir_createable "$tdir"; fi
}
show_dir_var() {
  if   test -f   "$2"; then status="error: not a directory!"; err="Y"
  elif test ! -d "$2"; then
    if dir_createable "$2"; then status="will be created"
    else                    status="error: not writable!"; err="Y"; fi
  elif test ! -w "$2"; then status="error: not writable!"; err="Y"
  else                      status="exists"
  fi
  echo "  $1 $2 ($status)"
}

unixstyle_install() {

  if test -f "$where"; then
    failwith "The entered base directory exists as a file: $where"
  elif test ! -d "$where"; then
    echo "Base directory does not exist: $where"
    echon "  should I create it? (default: yes) "
    read R; case "$R" in [nN]* ) abort ;; esac
    "$mkdir" -p "$where" || failwith "could not create directory: $where"
  elif test ! -w "$where"; then
    failwith "The entered base directory is not writable: $where"
  fi
  cd "$where" || failwith "Base directory does not exist: $where"
  where="`pwd`"; cd "$origwd"

  set_dirs "$where"
  # loop for possible changes
  done="N"; retry="N"
  while test ! "$done" = "Y" || test "x$err" = "xY" ; do
    err="N"
    if test "$retry" = "N"; then
      echo ""
      echo "Target Directories:"
      show_dir_var "[e] Executables  " "$bindir"
      show_dir_var "[r] Racket Code  " "$collectsdir"
      show_dir_var "[d] Core Docs    " "$docdir"
      show_dir_var "[l] C Libraries  " "$libdir"
      show_dir_var "[h] C headers    " "$incrktdir"
      show_dir_var "[o] Extra C Objs " "$librktdir"
      show_dir_var "[m] Man Pages    " "$mandir"
      if test "$PNAME" = "full"; then
        echo "  (C sources are not kept)"
        # show_dir_var "[s] Source Tree  " "$srcdir"
      fi
      echo "Enter a letter to change an entry, or enter to continue."
    fi
    retry="N"
    echon "> "; read change_what
    read_dir() {
      echon "New directory (absolute or relative to $where): "; read new_dir
      expand_path_var new_dir
      case "$new_dir" in
        "/"* ) eval "$1=\"$new_dir\"" ;;
        *    ) eval "$1=\"$where/$new_dir\"" ;;
      esac
    }
    case "$change_what" in
      [eE]* ) read_dir bindir ;;
      [rR]* ) read_dir collectsdir ;;
      [dD]* ) read_dir docdir ;;
      [lL]* ) read_dir libdir ;;
      [hH]* ) read_dir incrktdir ;;
      [oO]* ) read_dir librktdir ;;
      [mM]* ) read_dir mandir ;;
      # [sS]* ) if test "$PNAME" = "full"; then read_dir srcdir
      #         else echo "Invalid response"; fi ;;
      ""    ) if test "$err" = "N"; then done="Y"
              else echo "*** Please fix erroneous paths to proceed"; fi ;;
      *     ) retry="Y" ;;
    esac
  done

  if test -x "$bindir/racket-uninstall"; then
    echo ""
    echo "A previous Racket uninstaller is found at"
    echo "  \"$bindir/racket-uninstall\","
    echon "  should I run it? (default: yes) "
    read R
    case "$R" in
      [nN]* ) abort ;;
      * ) echon "  running uninstaller..."
          "$bindir/racket-uninstall" || failwith "problems during uninstall"
          echo " done." ;;
    esac
  fi

  tmp="$where/$TARGET-tmp-install"
  if test -f "$tmp" || test -d "$tmp"; then
    echo "\"$tmp\" already exists (needed for the installation),"
    echon "  ok to remove it? "
    read R; case "$R" in [yY]* ) "$rm" -rf "$tmp" ;; * ) abort ;; esac
  fi
  unpack_installation "$tmp"

  cd "$where"
  "$tmp/bin/racket" "$tmp/collects/setup/unixstyle-install.rkt" \
    "move" "$tmp" "$bindir" "$collectsdir" "$docdir" "$libdir" \
    "$incrktdir" "$librktdir" "$mandir" \
    || failwith "installation failed"

}

###############################################################################
## Run the right installer now

if test "$unixstyle" = "Y"; then unixstyle_install; else wholedir_install; fi

echo ""
echo "Installation complete."

exit

========== tar.gz file follows ==========
