<commit_before>#!/bin/bash - 
#===============================================================================
#
#          FILE: default.txt
# 
#         USAGE: curl https://getcroc.schollz.com | bash
#                 OR
#                wget -qO- https://getcroc.schollz.com | bash
# 
#   DESCRIPTION: croc Installer Script.
#
#                This script installs croc into a specified prefix.
#                Default prefix = /usr/local/bin
#
#       OPTIONS: -p, --prefix "${INSTALL_PREFIX}"
#                      Prefix to install croc into.  Defaults to /usr/local/bin
#  REQUIREMENTS: bash, uname, tar/unzip, curl/wget, sudo (if not run
#                as root), install, mktemp, sha256sum/shasum/sha256
#
#          BUGS: ...hopefully not.  Please report.
#
#         NOTES: Homepage: https://schollz.com/software/croc
#                  Issues: https://github.com/schollz/croc/issues
#
#       CREATED: 08/10/2019 16:41
#      REVISION: 0.5.0
#===============================================================================
set -o nounset                              # Treat unset variables as an error

#-------------------------------------------------------------------------------
# DEFAULTS
#-------------------------------------------------------------------------------
PREFIX="${PREFIX:-}"
ANDROID_ROOT="${ANDROID_ROOT:-}"

# Termux on Android has ${PREFIX} set which already ends with '/usr'
if [[ -n "${ANDROID_ROOT}" && -n "${PREFIX}" ]]; then
  INSTALL_PREFIX="${PREFIX}/bin"
else
  INSTALL_PREFIX="/usr/local/bin"
fi

#-------------------------------------------------------------------------------
# FUNCTIONS
#-------------------------------------------------------------------------------

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  print_help
#   DESCRIPTION:  Prints out a help message
#    PARAMETERS:  none
#       RETURNS:  0
#-------------------------------------------------------------------------------
print_help() {
  local help_header
  local help_message

  help_header="croc Installer Script"
  help_message="Usage:
  -p INSTALL_PREFIX
      Prefix to install croc into.  Directory must already exist.
      Default = /usr/local/bin ('\${PREFIX}/bin' on Termux for Android)
  
  -h
      Prints this helpfull message and exit."

  echo "${help_header}"
  echo ""
  echo "${help_message}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  print_message
#   DESCRIPTION:  Prints a message all fancy like
#    PARAMETERS:  $1 = Message to print
#                 $2 = Severity. info, ok, error, warn
#       RETURNS:  Formatted Message to stdout
#-------------------------------------------------------------------------------
print_message() {
  local message
  local severity
  local red
  local green
  local yellow
  local nc

  message="${1}"
  severity="${2}"
  red='\e[0;31m'
  green='\e[0;32m'
  yellow='\e[1;33m'
  nc='\e[0m'

  case "${severity}" in
    "info" ) echo -e "${nc}${message}${nc}";;
      "ok" ) echo -e "${green}${message}${nc}";;
   "error" ) echo -e "${red}${message}${nc}";;
    "warn" ) echo -e "${yellow}${message}${nc}";;
  esac


}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  make_tempdir
#   DESCRIPTION:  Makes a temp dir using mktemp if available
#    PARAMETERS:  $1 = Directory template
#       RETURNS:  0 = Created temp dir. Also prints temp file path to stdout
#                 1 = Failed to create temp dir
#-------------------------------------------------------------------------------
make_tempdir() {
  local template
  local tempdir
  local tempdir_rcode

  template="${1}.XXXXXX"

  if command -v mktemp >/dev/null 2>&1; then
    tempdir="$(mktemp -d -t "${template}")"
    tempdir_rcode="${?}"
    if [[ "${tempdir_rcode}" == "0" ]]; then
      echo "${tempdir}"
      return 0
    else
      return 1
    fi
  fi
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  determine_os
#   DESCRIPTION:  Attempts to determin host os using uname
#    PARAMETERS:  none
#       RETURNS:  0 = OS Detected. Also prints detected os to stdout
#                 1 = Unkown OS
#                 2 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_os() {
  local uname_cmd
  local uname_out

  uname_cmd="$(command -v uname)"
  if [[ "${uname_cmd}" == "" ]]; then
    return 2
  else
    uname_out="$(uname)"
  fi

  if [[ "${uname_out}" == "" ]]; then
    return 1
  else
    echo "${uname_out}"
    return 0
  fi
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  determine_arch
#   DESCRIPTION:  Attempt to determin architecture of host
#    PARAMETERS:  none
#       RETURNS:  0 = Arch Detected. Also prints detected arch to stdout
#                 1 = Unkown arch
#                 2 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_arch() {
  local uname_cmd
  local uname_out

  uname_cmd="$(command -v uname)"

  if [[ "${uname_cmd}" == "" ]]; then
    return 2
  else
    uname_out="$(uname -m)"
  fi

  if [[ "${uname_out}" == "" ]]; then
    return 1
  else
    echo "${uname_out}"
    return 0
  fi
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  download_file
#   DESCRIPTION:  Downloads a file into the specified directory.  Attempts to
#                 use curl, then wget.  If neither is found, fail.
#    PARAMETERS:  $1 = url of file to download
#                 $2 = location to download file into on host system
#       RETURNS:  If curl or wget found, returns the return code of curl or wget
#                 2 = Could not find curl and wget
#-------------------------------------------------------------------------------
download_file() {
  local url
  local dir
  local filename
  local rcode

  url="${1}"
  dir="${2}"
  filename="${3}"

  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "${url}" -o "${dir}/${filename}"
    rcode="${?}"
  elif command -v wget >/dev/null 2>&1; then
    wget --quiet  "${url}" -O "${dir}/${filename}"
    rcode="${?}"
  else
    rcode="2"
  fi
  
  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  checksum_check
#   DESCRIPTION:  Attempt to verify checksum of downloaded file to ensure
#                 integrity.  Tries multiple tools before faling.
#    PARAMETERS:  $1 = path to checksum file
#                 $2 = location of file to check
#                 $3 = working directory
#       RETURNS:  0 = checkusm verified
#                 1 = checksum verification failed
#                 20 = failed to determine tool to use to check checksum
#                 30 = failed to change into or go back from working dir
#-------------------------------------------------------------------------------
checksum_check() {
  local checksum_file
  local file
  local dir
  local rcode
  local shasum_1
  local shasum_2

  checksum_file="${1}"
  file="${2}"
  dir="${3}"

  cd "${dir}" || return 3
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum -c "${checksum_file}" --ignore-missing >/dev/null 2>&1
    rcode="${?}"
  elif command -v shasum >/dev/null 2>&1; then
    ## With shasum on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
    ## to only include the file we downloaded.
    grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
    shasum -s -a 256 -c "filtered_checksum.txt"
    rcode="${?}"
  elif command -v sha256 >/dev/null 2>&1; then
    ## With sha256 on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
    ## to only include the file we downloaded.
    ## Also sha256 -c option seems to fail, so fall back to an if statement
    grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
    shasum_1="$(sha256 -q "${file}")"
    shasum_2="$(awk '{print $1}' filtered_checksum.txt)"
    if [[ "${shasum_1}" == "${shasum_2}" ]]; then
      rcode="0"
    else
      rcode="1"
    fi
  else
    return 20
  fi
  cd - >/dev/null 2>&1 || return 30
  
  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  extract_file
#   DESCRIPTION:  Extracts a file into a location.  Attempts to determine which
#                 tool to use by checking file extention.
#    PARAMETERS:  $1 = file to extract
#                 $2 = location to extract file into
#                 $3 = extention
#       RETURNS:  Return code of the tool used to extract the file
#                 2 = Failed to determine which tool to use
#                 3 = Failed to find tool in path
#-------------------------------------------------------------------------------
extract_file() {
  local file
  local dir
  local ext
  local rcode

  file="${1}"
  dir="${2}"
  ext="${3}"

  case "${ext}" in
       "zip" ) if command -v unzip >/dev/null 2>&1; then
                 unzip "${file}" -d "${dir}"
                 rcode="${?}"
               else
                 rcode="3"
               fi
               ;;
    "tar.gz" ) if command -v tar >/dev/null 2>&1; then
                 tar -xf "${file}" -C "${dir}"
                 rcode="${?}"
               else
                 rcode="3"
               fi
               ;;
           * ) rcode="2";;
  esac

  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  install_file_freebsd
#   DESCRIPTION:  Installs a file into a location using 'install'.  If EUID not
#                 0, then attempt to use sudo.
#    PARAMETERS:  $1 = file to install
#                 $2 = location to install file into
#       RETURNS:  0 = File Installed
#                 1 = File not installed
#                 2 = Could not find install command
#                 3 = Could not find sudo command
#-------------------------------------------------------------------------------
install_file_freebsd() {
  local file
  local prefix
  local rcode

  file="${1}"
  prefix="${2}"

  if command -v install >/dev/null 2>&1; then
    if [[ "${EUID}" == "0" ]]; then
      install -C -b -B '_old' -m 755 "${file}" "${prefix}"
      rcode="${?}"
    else
      if command -v sudo >/dev/null 2>&1; then
        sudo install -C -b -B '_old' -m 755 "${file}" "${prefix}"
        rcode="${?}"
      else
        rcode="3"
      fi
    fi
  else
    rcode="2"
  fi

  return "${rcode}"
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  install_file_linux
#   DESCRIPTION:  Installs a file into a location using 'install'.  If EUID not
#                 0, then attempt to use sudo (unless on android).
#    PARAMETERS:  $1 = file to install
#                 $2 = location to install file into
#       RETURNS:  0 = File Installed
#                 1 = File not installed
#                 2 = Could not find install command
#-------------------------------------------------------------------------------
install_file_linux() {
  local file
  local prefix
  local rcode

  file="${1}"
  prefix="${2}"

  if command -v install >/dev/null 2>&1; then
    if [[ "${EUID}" == "0" ]]; then
      install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
      rcode="${?}"
    else
      if command -v sudo >/dev/null 2>&1; then
        sudo install -C -b -S '_old' -m 755 "${file}" "${prefix}"
        rcode="${?}"
      elif [[ "${ANDROID_ROOT}" != "" ]]; then
        install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
        rcode="${?}"
      else
        rcode="3"
      fi
    fi
  else
    rcode="2"
  fi

  return "${rcode}"
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  cleanup
#   DESCRIPTION:  Cleanup our temp files
#    PARAMETERS:  $1 = Path to temp dir to remove
#       RETURNS:  nothing
#-------------------------------------------------------------------------------
cleanup() {
  local dir

  dir="$1"

  rm -rf "${dir}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  main
#   DESCRIPTION:  Put it all together in a logical way
#                 ...at least that is the hope...
#    PARAMETERS:  1 = prefix
#       RETURNS:  0 = All good
#                 1 = Something done broke
#-------------------------------------------------------------------------------
main() {
  local prefix
  local tmpdir
  local tmpdir_rcode
  local croc_arch
  local croc_arch_rcode
  local croc_os
  local croc_os_rcode
  local croc_base_url
  local croc_url
  local croc_file
  local croc_checksum_file
  local croc_bin_name
  local croc_version
  local croc_dl_ext
  local download_file_rcode
  local download_checksum_file_rcode
  local checksum_check_rcode
  local extract_file_rcode
  local install_file_rcode

  croc_bin_name="croc"
  croc_version="6.1.1"
  croc_dl_ext="tar.gz"
  croc_base_url="https://github.com/schollz/croc/releases/download"
  prefix="${1}"

  print_message "== Install prefix set to ${prefix}" "info"
  
  tmpdir="$(make_tempdir "${croc_bin_name}")"
  tmpdir_rcode="${?}"
  if [[ "${tmpdir_rcode}" == "0" ]]; then
    print_message "== Created temp dir at ${tmpdir}" "info"
  else
    print_message "== Failed to create temp dir at ${tmpdir}" "error"
    exit 1
  fi

  croc_arch="$(determine_arch)"
  croc_arch_rcode="${?}"
  if [[ "${croc_arch_rcode}" == "0" ]]; then
    print_message "== Architecture detected as ${croc_arch}" "info"
  elif [[ "${croc_arch_rcode}" == "1" ]]; then
    print_message "== Architecture not detected" "error"
    exit 1
  else
    print_message "== 'uname' not found in path. Is it installed?" "error"
  fi

  croc_os="$(determine_os)"
  croc_os_rcode="${?}"
  if [[ "${croc_os_rcode}" == "0" ]]; then
    print_message "== OS detected as ${croc_os}" "info"
  elif [[ "${croc_os_rcode}" == "1" ]]; then
    print_message "== OS not detected" "error"
    exit 1
  else
    print_message "== 'uname' not found in path. Is it installed?" "error"
  fi

  case "${croc_os}" in
    "Darwin" ) croc_os="macOS";;
  esac

  case "${croc_arch}" in
     "x86_64" ) croc_arch="64bit";;
      "amd64" ) croc_arch="64bit";;
    "aarch64" ) croc_arch="ARM64";;
     "armv7l" ) croc_arch="ARM";;
       "i686" ) croc_arch="32bit";;
            * ) croc_arch="unknown";;
  esac

  croc_file="${croc_bin_name}_${croc_version}_${croc_os}-${croc_arch}.${croc_dl_ext}"
  croc_checksum_file="${croc_bin_name}_${croc_version}_checksums.txt"
  croc_url="${croc_base_url}/v${croc_version}/${croc_file}"
  croc_checksum_url="${croc_base_url}/v${croc_version}/${croc_checksum_file}"

  download_file "${croc_url}" "${tmpdir}" "${croc_file}"
  download_file_rcode="${?}"
  if [[ "${download_file_rcode}" == "0" ]]; then
    print_message "== Downloaded croc archive into ${tmpdir}" "info"
  elif [[ "${download_file_rcode}" == "1" ]]; then
    print_message "== Failed to download croc archive" "error"
    exit 1
  elif [[ "${download_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate curl or wget" "error"
    exit 1
  else
    print_message "== Return code of download tool returned an unexpected value of ${download_file_rcode}" "error"
    exit 1
  fi
  download_file "${croc_checksum_url}" "${tmpdir}" "${croc_checksum_file}"
  download_checksum_file_rcode="${?}"
  if [[ "${download_checksum_file_rcode}" == "0" ]]; then
    print_message "== Downloaded croc checksums file into ${tmpdir}" "info"
  elif [[ "${download_checksum_file_rcode}" == "1" ]]; then
    print_message "== Failed to download croc checksums" "error"
    exit 1
  elif [[ "${download_checksum_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate curl or wget" "error"
    exit 1
  else
    print_message "== Return code of download tool returned an unexpected value of ${download_checksum_file_rcode}" "error"
    exit 1
  fi

  checksum_check "${tmpdir}/${croc_checksum_file}" "${tmpdir}/${croc_file}" "${tmpdir}"
  checksum_check_rcode="${?}"
  if [[ "${checksum_check_rcode}" == "0" ]]; then
    print_message "== Checksum of ${tmpdir}/${croc_file} verified" "ok"
  elif [[ "${checksum_check_rcode}" == "1" ]]; then
    print_message "== Failed to verify checksum of ${tmpdir}/${croc_file}" "error"
    exit 1
  elif [[ "${checksum_check_rcode}" == "20" ]]; then
    print_message "== Failed to find tool to verify sha256 sums" "error"
    exit 1
  elif [[ "${checksum_check_rcode}" == "30" ]]; then
    print_message "== Failed to change into working directory ${tmpdir}" "error"
    exit 1
  else
    print_message "== Unknown return code returned while checking checksum of ${tmpdir}/${croc_file}. Returned ${checksum_check_rcode}" "error"
    exit 1
  fi

  extract_file "${tmpdir}/${croc_file}" "${tmpdir}/" "${croc_dl_ext}"
  extract_file_rcode="${?}"
  if [[ "${extract_file_rcode}" == "0" ]]; then
    print_message "== Extracted ${croc_file} to ${tmpdir}/" "info"
  elif [[ "${extract_file_rcode}" == "1" ]]; then
    print_message "== Failed to extract ${croc_file}" "error"
    exit 1
  elif [[ "${extract_file_rcode}" == "2" ]]; then
    print_message "== Failed to determine which extraction tool to use" "error"
    exit 1
  elif [[ "${extract_file_rcode}" == "3" ]]; then
    print_message "== Failed to find extraction tool in path" "error"
    exit 1
  else
    print_message "== Unknown error returned from extraction attempt" "error"
    exit 1
  fi

  case "${croc_os}" in
    "Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
              install_file_rcode="${?}";;
  "FreeBSD" ) install_file_freebsd "${tmpdir}/${croc_bin_name}" "${prefix}/";
              install_file_rcode="${?}";;
  esac
  if [[ "${install_file_rcode}" == "0" ]]; then
    print_message "== Installed ${croc_bin_name} to ${prefix}/" "ok"
  elif [[ "${install_file_rcode}" == "1" ]]; then
    print_message "== Failed to install ${croc_bin_name}" "error"
    exit 1
  elif [[ "${install_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate 'install' command" "error"
    exit 1
  elif [[ "${install_file_rcode}" == "3" ]]; then
    print_message "== Failed to locate 'sudo' command" "error"
    exit 1
  else
    print_message "== Install attempt returned an unexpected value of ${install_file_rcode}" "error"
    exit 1
  fi

  print_message "== Cleaning up ${tmpdir}" "info"
  cleanup "${tmpdir}"
  print_message "== Installation complete" "ok"
}

#-------------------------------------------------------------------------------
#  ARGUMENT PARSING
#-------------------------------------------------------------------------------
OPTS="hp:"
while getopts "${OPTS}" optchar; do
  case "${optchar}" in
    'h' ) print_help
          exit 0
          ;;
    'p' ) INSTALL_PREFIX="${OPTARG}"
          ;;
     /? ) print_message "Unknown option ${OPTARG}" "warn"
          ;;
  esac
done

#-------------------------------------------------------------------------------
# CALL MAIN
#-------------------------------------------------------------------------------
main "${INSTALL_PREFIX}"
<commit_msg>Adding in fix for macOS (Darwin) not having an install case.  Uses the same logic from install_file_freebsd<commit_after>#!/bin/bash - 
#===============================================================================
#
#          FILE: default.txt
# 
#         USAGE: curl https://getcroc.schollz.com | bash
#                 OR
#                wget -qO- https://getcroc.schollz.com | bash
# 
#   DESCRIPTION: croc Installer Script.
#
#                This script installs croc into a specified prefix.
#                Default prefix = /usr/local/bin
#
#       OPTIONS: -p, --prefix "${INSTALL_PREFIX}"
#                      Prefix to install croc into.  Defaults to /usr/local/bin
#  REQUIREMENTS: bash, uname, tar/unzip, curl/wget, sudo (if not run
#                as root), install, mktemp, sha256sum/shasum/sha256
#
#          BUGS: ...hopefully not.  Please report.
#
#         NOTES: Homepage: https://schollz.com/software/croc
#                  Issues: https://github.com/schollz/croc/issues
#
#       CREATED: 08/10/2019 16:41
#      REVISION: 0.5.0
#===============================================================================
set -o nounset                              # Treat unset variables as an error

#-------------------------------------------------------------------------------
# DEFAULTS
#-------------------------------------------------------------------------------
PREFIX="${PREFIX:-}"
ANDROID_ROOT="${ANDROID_ROOT:-}"

# Termux on Android has ${PREFIX} set which already ends with '/usr'
if [[ -n "${ANDROID_ROOT}" && -n "${PREFIX}" ]]; then
  INSTALL_PREFIX="${PREFIX}/bin"
else
  INSTALL_PREFIX="/usr/local/bin"
fi

#-------------------------------------------------------------------------------
# FUNCTIONS
#-------------------------------------------------------------------------------

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  print_help
#   DESCRIPTION:  Prints out a help message
#    PARAMETERS:  none
#       RETURNS:  0
#-------------------------------------------------------------------------------
print_help() {
  local help_header
  local help_message

  help_header="croc Installer Script"
  help_message="Usage:
  -p INSTALL_PREFIX
      Prefix to install croc into.  Directory must already exist.
      Default = /usr/local/bin ('\${PREFIX}/bin' on Termux for Android)
  
  -h
      Prints this helpfull message and exit."

  echo "${help_header}"
  echo ""
  echo "${help_message}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  print_message
#   DESCRIPTION:  Prints a message all fancy like
#    PARAMETERS:  $1 = Message to print
#                 $2 = Severity. info, ok, error, warn
#       RETURNS:  Formatted Message to stdout
#-------------------------------------------------------------------------------
print_message() {
  local message
  local severity
  local red
  local green
  local yellow
  local nc

  message="${1}"
  severity="${2}"
  red='\e[0;31m'
  green='\e[0;32m'
  yellow='\e[1;33m'
  nc='\e[0m'

  case "${severity}" in
    "info" ) echo -e "${nc}${message}${nc}";;
      "ok" ) echo -e "${green}${message}${nc}";;
   "error" ) echo -e "${red}${message}${nc}";;
    "warn" ) echo -e "${yellow}${message}${nc}";;
  esac


}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  make_tempdir
#   DESCRIPTION:  Makes a temp dir using mktemp if available
#    PARAMETERS:  $1 = Directory template
#       RETURNS:  0 = Created temp dir. Also prints temp file path to stdout
#                 1 = Failed to create temp dir
#-------------------------------------------------------------------------------
make_tempdir() {
  local template
  local tempdir
  local tempdir_rcode

  template="${1}.XXXXXX"

  if command -v mktemp >/dev/null 2>&1; then
    tempdir="$(mktemp -d -t "${template}")"
    tempdir_rcode="${?}"
    if [[ "${tempdir_rcode}" == "0" ]]; then
      echo "${tempdir}"
      return 0
    else
      return 1
    fi
  fi
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  determine_os
#   DESCRIPTION:  Attempts to determin host os using uname
#    PARAMETERS:  none
#       RETURNS:  0 = OS Detected. Also prints detected os to stdout
#                 1 = Unkown OS
#                 2 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_os() {
  local uname_cmd
  local uname_out

  uname_cmd="$(command -v uname)"
  if [[ "${uname_cmd}" == "" ]]; then
    return 2
  else
    uname_out="$(uname)"
  fi

  if [[ "${uname_out}" == "" ]]; then
    return 1
  else
    echo "${uname_out}"
    return 0
  fi
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  determine_arch
#   DESCRIPTION:  Attempt to determin architecture of host
#    PARAMETERS:  none
#       RETURNS:  0 = Arch Detected. Also prints detected arch to stdout
#                 1 = Unkown arch
#                 2 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_arch() {
  local uname_cmd
  local uname_out

  uname_cmd="$(command -v uname)"

  if [[ "${uname_cmd}" == "" ]]; then
    return 2
  else
    uname_out="$(uname -m)"
  fi

  if [[ "${uname_out}" == "" ]]; then
    return 1
  else
    echo "${uname_out}"
    return 0
  fi
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  download_file
#   DESCRIPTION:  Downloads a file into the specified directory.  Attempts to
#                 use curl, then wget.  If neither is found, fail.
#    PARAMETERS:  $1 = url of file to download
#                 $2 = location to download file into on host system
#       RETURNS:  If curl or wget found, returns the return code of curl or wget
#                 2 = Could not find curl and wget
#-------------------------------------------------------------------------------
download_file() {
  local url
  local dir
  local filename
  local rcode

  url="${1}"
  dir="${2}"
  filename="${3}"

  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "${url}" -o "${dir}/${filename}"
    rcode="${?}"
  elif command -v wget >/dev/null 2>&1; then
    wget --quiet  "${url}" -O "${dir}/${filename}"
    rcode="${?}"
  else
    rcode="2"
  fi
  
  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  checksum_check
#   DESCRIPTION:  Attempt to verify checksum of downloaded file to ensure
#                 integrity.  Tries multiple tools before faling.
#    PARAMETERS:  $1 = path to checksum file
#                 $2 = location of file to check
#                 $3 = working directory
#       RETURNS:  0 = checkusm verified
#                 1 = checksum verification failed
#                 20 = failed to determine tool to use to check checksum
#                 30 = failed to change into or go back from working dir
#-------------------------------------------------------------------------------
checksum_check() {
  local checksum_file
  local file
  local dir
  local rcode
  local shasum_1
  local shasum_2

  checksum_file="${1}"
  file="${2}"
  dir="${3}"

  cd "${dir}" || return 3
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum -c "${checksum_file}" --ignore-missing >/dev/null 2>&1
    rcode="${?}"
  elif command -v shasum >/dev/null 2>&1; then
    ## With shasum on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
    ## to only include the file we downloaded.
    grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
    shasum -s -a 256 -c "filtered_checksum.txt"
    rcode="${?}"
  elif command -v sha256 >/dev/null 2>&1; then
    ## With sha256 on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
    ## to only include the file we downloaded.
    ## Also sha256 -c option seems to fail, so fall back to an if statement
    grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
    shasum_1="$(sha256 -q "${file}")"
    shasum_2="$(awk '{print $1}' filtered_checksum.txt)"
    if [[ "${shasum_1}" == "${shasum_2}" ]]; then
      rcode="0"
    else
      rcode="1"
    fi
  else
    return 20
  fi
  cd - >/dev/null 2>&1 || return 30
  
  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  extract_file
#   DESCRIPTION:  Extracts a file into a location.  Attempts to determine which
#                 tool to use by checking file extention.
#    PARAMETERS:  $1 = file to extract
#                 $2 = location to extract file into
#                 $3 = extention
#       RETURNS:  Return code of the tool used to extract the file
#                 2 = Failed to determine which tool to use
#                 3 = Failed to find tool in path
#-------------------------------------------------------------------------------
extract_file() {
  local file
  local dir
  local ext
  local rcode

  file="${1}"
  dir="${2}"
  ext="${3}"

  case "${ext}" in
       "zip" ) if command -v unzip >/dev/null 2>&1; then
                 unzip "${file}" -d "${dir}"
                 rcode="${?}"
               else
                 rcode="3"
               fi
               ;;
    "tar.gz" ) if command -v tar >/dev/null 2>&1; then
                 tar -xf "${file}" -C "${dir}"
                 rcode="${?}"
               else
                 rcode="3"
               fi
               ;;
           * ) rcode="2";;
  esac

  return "${rcode}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  install_file_freebsd
#   DESCRIPTION:  Installs a file into a location using 'install'.  If EUID not
#                 0, then attempt to use sudo.
#    PARAMETERS:  $1 = file to install
#                 $2 = location to install file into
#       RETURNS:  0 = File Installed
#                 1 = File not installed
#                 2 = Could not find install command
#                 3 = Could not find sudo command
#-------------------------------------------------------------------------------
install_file_freebsd() {
  local file
  local prefix
  local rcode

  file="${1}"
  prefix="${2}"

  if command -v install >/dev/null 2>&1; then
    if [[ "${EUID}" == "0" ]]; then
      install -C -b -B '_old' -m 755 "${file}" "${prefix}"
      rcode="${?}"
    else
      if command -v sudo >/dev/null 2>&1; then
        sudo install -C -b -B '_old' -m 755 "${file}" "${prefix}"
        rcode="${?}"
      else
        rcode="3"
      fi
    fi
  else
    rcode="2"
  fi

  return "${rcode}"
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  install_file_linux
#   DESCRIPTION:  Installs a file into a location using 'install'.  If EUID not
#                 0, then attempt to use sudo (unless on android).
#    PARAMETERS:  $1 = file to install
#                 $2 = location to install file into
#       RETURNS:  0 = File Installed
#                 1 = File not installed
#                 2 = Could not find install command
#-------------------------------------------------------------------------------
install_file_linux() {
  local file
  local prefix
  local rcode

  file="${1}"
  prefix="${2}"

  if command -v install >/dev/null 2>&1; then
    if [[ "${EUID}" == "0" ]]; then
      install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
      rcode="${?}"
    else
      if command -v sudo >/dev/null 2>&1; then
        sudo install -C -b -S '_old' -m 755 "${file}" "${prefix}"
        rcode="${?}"
      elif [[ "${ANDROID_ROOT}" != "" ]]; then
        install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
        rcode="${?}"
      else
        rcode="3"
      fi
    fi
  else
    rcode="2"
  fi

  return "${rcode}"
}


#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  cleanup
#   DESCRIPTION:  Cleanup our temp files
#    PARAMETERS:  $1 = Path to temp dir to remove
#       RETURNS:  nothing
#-------------------------------------------------------------------------------
cleanup() {
  local dir

  dir="$1"

  rm -rf "${dir}"
}

#---  FUNCTION  ----------------------------------------------------------------
#          NAME:  main
#   DESCRIPTION:  Put it all together in a logical way
#                 ...at least that is the hope...
#    PARAMETERS:  1 = prefix
#       RETURNS:  0 = All good
#                 1 = Something done broke
#-------------------------------------------------------------------------------
main() {
  local prefix
  local tmpdir
  local tmpdir_rcode
  local croc_arch
  local croc_arch_rcode
  local croc_os
  local croc_os_rcode
  local croc_base_url
  local croc_url
  local croc_file
  local croc_checksum_file
  local croc_bin_name
  local croc_version
  local croc_dl_ext
  local download_file_rcode
  local download_checksum_file_rcode
  local checksum_check_rcode
  local extract_file_rcode
  local install_file_rcode

  croc_bin_name="croc"
  croc_version="6.1.1"
  croc_dl_ext="tar.gz"
  croc_base_url="https://github.com/schollz/croc/releases/download"
  prefix="${1}"

  print_message "== Install prefix set to ${prefix}" "info"
  
  tmpdir="$(make_tempdir "${croc_bin_name}")"
  tmpdir_rcode="${?}"
  if [[ "${tmpdir_rcode}" == "0" ]]; then
    print_message "== Created temp dir at ${tmpdir}" "info"
  else
    print_message "== Failed to create temp dir at ${tmpdir}" "error"
    exit 1
  fi

  croc_arch="$(determine_arch)"
  croc_arch_rcode="${?}"
  if [[ "${croc_arch_rcode}" == "0" ]]; then
    print_message "== Architecture detected as ${croc_arch}" "info"
  elif [[ "${croc_arch_rcode}" == "1" ]]; then
    print_message "== Architecture not detected" "error"
    exit 1
  else
    print_message "== 'uname' not found in path. Is it installed?" "error"
  fi

  croc_os="$(determine_os)"
  croc_os_rcode="${?}"
  if [[ "${croc_os_rcode}" == "0" ]]; then
    print_message "== OS detected as ${croc_os}" "info"
  elif [[ "${croc_os_rcode}" == "1" ]]; then
    print_message "== OS not detected" "error"
    exit 1
  else
    print_message "== 'uname' not found in path. Is it installed?" "error"
  fi

  case "${croc_os}" in
    "Darwin" ) croc_os="macOS";;
  esac

  case "${croc_arch}" in
     "x86_64" ) croc_arch="64bit";;
      "amd64" ) croc_arch="64bit";;
    "aarch64" ) croc_arch="ARM64";;
     "armv7l" ) croc_arch="ARM";;
       "i686" ) croc_arch="32bit";;
            * ) croc_arch="unknown";;
  esac

  croc_file="${croc_bin_name}_${croc_version}_${croc_os}-${croc_arch}.${croc_dl_ext}"
  croc_checksum_file="${croc_bin_name}_${croc_version}_checksums.txt"
  croc_url="${croc_base_url}/v${croc_version}/${croc_file}"
  croc_checksum_url="${croc_base_url}/v${croc_version}/${croc_checksum_file}"

  download_file "${croc_url}" "${tmpdir}" "${croc_file}"
  download_file_rcode="${?}"
  if [[ "${download_file_rcode}" == "0" ]]; then
    print_message "== Downloaded croc archive into ${tmpdir}" "info"
  elif [[ "${download_file_rcode}" == "1" ]]; then
    print_message "== Failed to download croc archive" "error"
    exit 1
  elif [[ "${download_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate curl or wget" "error"
    exit 1
  else
    print_message "== Return code of download tool returned an unexpected value of ${download_file_rcode}" "error"
    exit 1
  fi
  download_file "${croc_checksum_url}" "${tmpdir}" "${croc_checksum_file}"
  download_checksum_file_rcode="${?}"
  if [[ "${download_checksum_file_rcode}" == "0" ]]; then
    print_message "== Downloaded croc checksums file into ${tmpdir}" "info"
  elif [[ "${download_checksum_file_rcode}" == "1" ]]; then
    print_message "== Failed to download croc checksums" "error"
    exit 1
  elif [[ "${download_checksum_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate curl or wget" "error"
    exit 1
  else
    print_message "== Return code of download tool returned an unexpected value of ${download_checksum_file_rcode}" "error"
    exit 1
  fi

  checksum_check "${tmpdir}/${croc_checksum_file}" "${tmpdir}/${croc_file}" "${tmpdir}"
  checksum_check_rcode="${?}"
  if [[ "${checksum_check_rcode}" == "0" ]]; then
    print_message "== Checksum of ${tmpdir}/${croc_file} verified" "ok"
  elif [[ "${checksum_check_rcode}" == "1" ]]; then
    print_message "== Failed to verify checksum of ${tmpdir}/${croc_file}" "error"
    exit 1
  elif [[ "${checksum_check_rcode}" == "20" ]]; then
    print_message "== Failed to find tool to verify sha256 sums" "error"
    exit 1
  elif [[ "${checksum_check_rcode}" == "30" ]]; then
    print_message "== Failed to change into working directory ${tmpdir}" "error"
    exit 1
  else
    print_message "== Unknown return code returned while checking checksum of ${tmpdir}/${croc_file}. Returned ${checksum_check_rcode}" "error"
    exit 1
  fi

  extract_file "${tmpdir}/${croc_file}" "${tmpdir}/" "${croc_dl_ext}"
  extract_file_rcode="${?}"
  if [[ "${extract_file_rcode}" == "0" ]]; then
    print_message "== Extracted ${croc_file} to ${tmpdir}/" "info"
  elif [[ "${extract_file_rcode}" == "1" ]]; then
    print_message "== Failed to extract ${croc_file}" "error"
    exit 1
  elif [[ "${extract_file_rcode}" == "2" ]]; then
    print_message "== Failed to determine which extraction tool to use" "error"
    exit 1
  elif [[ "${extract_file_rcode}" == "3" ]]; then
    print_message "== Failed to find extraction tool in path" "error"
    exit 1
  else
    print_message "== Unknown error returned from extraction attempt" "error"
    exit 1
  fi

  case "${croc_os}" in
    "Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
              install_file_rcode="${?}";;
  "FreeBSD" ) install_file_freebsd "${tmpdir}/${croc_bin_name}" "${prefix}/";
              install_file_rcode="${?}";;
    "macOS" ) install_file_freebsd "${tmpdir}/${croc_bin_name}" "${prefix}/";
              install_file_rcode="${?}";;
  esac
  if [[ "${install_file_rcode}" == "0" ]]; then
    print_message "== Installed ${croc_bin_name} to ${prefix}/" "ok"
  elif [[ "${install_file_rcode}" == "1" ]]; then
    print_message "== Failed to install ${croc_bin_name}" "error"
    exit 1
  elif [[ "${install_file_rcode}" == "2" ]]; then
    print_message "== Failed to locate 'install' command" "error"
    exit 1
  elif [[ "${install_file_rcode}" == "3" ]]; then
    print_message "== Failed to locate 'sudo' command" "error"
    exit 1
  else
    print_message "== Install attempt returned an unexpected value of ${install_file_rcode}" "error"
    exit 1
  fi

  print_message "== Cleaning up ${tmpdir}" "info"
  cleanup "${tmpdir}"
  print_message "== Installation complete" "ok"
}

#-------------------------------------------------------------------------------
#  ARGUMENT PARSING
#-------------------------------------------------------------------------------
OPTS="hp:"
while getopts "${OPTS}" optchar; do
  case "${optchar}" in
    'h' ) print_help
          exit 0
          ;;
    'p' ) INSTALL_PREFIX="${OPTARG}"
          ;;
     /? ) print_message "Unknown option ${OPTARG}" "warn"
          ;;
  esac
done

#-------------------------------------------------------------------------------
# CALL MAIN
#-------------------------------------------------------------------------------
main "${INSTALL_PREFIX}"

{'fraction_non_alphanumeric': 0.2564095976981966, 'fraction_numerical': 0.013615578276730206, 'mean_word_length': 1.7280818557712523, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 63, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 58, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3272460', 'n_tokens_mistral': 12143, 'n_tokens_neox': 11468, 'n_words': 3361}