mirror of
https://github.com/eth-p/bat-extras.git
synced 2024-12-12 17:20:40 +01:00
193 lines
4.7 KiB
Bash
193 lines
4.7 KiB
Bash
#!/usr/bin/env bash
|
|
# -----------------------------------------------------------------------------
|
|
# bat-extras | Copyright (C) 2019-2020 eth-p | MIT License
|
|
#
|
|
# Repository: https://github.com/eth-p/bat-extras
|
|
# Issues: https://github.com/eth-p/bat-extras/issues
|
|
# -----------------------------------------------------------------------------
|
|
source "${LIB}/constants.sh"
|
|
|
|
# An array of functions to call before returning from `shiftopt`.
|
|
#
|
|
# If one of these functions returns a successful exit code, the
|
|
# option will be transparently skipped instead of handled.
|
|
SHIFTOPT_HOOKS=()
|
|
|
|
# A setting to change how `shiftopt` will interpret short options that consist
|
|
# of more than one character.
|
|
#
|
|
# Values:
|
|
#
|
|
# SPLIT -- Splits the option into multiple single-character short options.
|
|
# "-abc" -> ("-a" "-b" "-c")
|
|
#
|
|
# VALUE -- Uses the remaining characters as the value for the short option.
|
|
# "-abc" -> ("-a=bc")
|
|
#
|
|
# CONV -- Converts the argument to a long option.
|
|
# "-abc" -> ("--abc")
|
|
#
|
|
# PASS -- Pass the argument along as-is.
|
|
# "-abc" -> ("-abc")
|
|
#
|
|
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
|
|
|
# Sets the internal _ARGV, _ARGV_INDEX, and _ARGV_LAST variables used when
|
|
# parsing options with the shiftopt and shiftval functions.
|
|
#
|
|
# Arguments:
|
|
# ... -- The program arguments.
|
|
#
|
|
# Example:
|
|
# setargs "--long=3" "file.txt"
|
|
setargs() {
|
|
_ARGV=("$@")
|
|
_ARGV_LAST="$((${#_ARGV[@]} - 1))"
|
|
_ARGV_INDEX=0
|
|
_ARGV_SUBINDEX=1
|
|
}
|
|
|
|
# Gets all the remaining unparsed arguments and saves them to a variable.
|
|
#
|
|
# Arguments:
|
|
# "-a" -- Append the arguments to the variable instead of replacing it.
|
|
# $1 -- The variable to save the args to.
|
|
#
|
|
# Example:
|
|
# getargs remaining_args
|
|
getargs() {
|
|
if [[ "$1" = "-a" || "$1" = "--append" ]]; then
|
|
if [[ "${_ARGV_INDEX}" -ne "$((_ARGV_LAST+1))" ]]; then
|
|
eval "$2=(\"\${$2[@]}\" $(printf '%q ' "${_ARGV[@]:$_ARGV_INDEX}"))"
|
|
fi
|
|
else
|
|
if [[ "${_ARGV_INDEX}" -ne "$((_ARGV_LAST+1))" ]]; then
|
|
eval "$1=($(printf '%q ' "${_ARGV[@]:$_ARGV_INDEX}"))"
|
|
else
|
|
eval "$1=()"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Resets the internal _ARGV* variables to the original script arguments.
|
|
# This is the equivalent of storing the top-level $@ and using setargs with it.
|
|
resetargs() {
|
|
setargs "${_ARGV_ORIGINAL[@]}"
|
|
}
|
|
|
|
# INTERNAL.
|
|
#
|
|
# Increments the argv index pointer used by `shiftopt`.
|
|
_shiftopt_next() {
|
|
_ARGV_SUBINDEX=1
|
|
((_ARGV_INDEX++)) || true
|
|
}
|
|
|
|
# Gets the next option passed to the script.
|
|
#
|
|
# Variables:
|
|
# OPT -- The option name.
|
|
#
|
|
# Returns:
|
|
# 0 -- An option was read.
|
|
# 1 -- No more options were read.
|
|
#
|
|
# Example:
|
|
# while shiftopt; do
|
|
# shiftval
|
|
# echo "$OPT = $OPT_VAL"
|
|
# done
|
|
shiftopt() {
|
|
# Read the top of _ARGV.
|
|
[[ "$_ARGV_INDEX" -gt "$_ARGV_LAST" ]] && return 1
|
|
OPT="${_ARGV[$_ARGV_INDEX]}"
|
|
unset OPT_VAL
|
|
|
|
if [[ "$OPT" =~ ^-[a-zA-Z0-9_-]+=.* ]]; then
|
|
OPT_VAL="${OPT#*=}"
|
|
OPT="${OPT%%=*}"
|
|
fi
|
|
|
|
# Handle short options.
|
|
if [[ "$OPT" =~ ^-[^-]{2,} ]]; then
|
|
case "$SHIFTOPT_SHORT_OPTIONS" in
|
|
# PASS mode: "-abc=0" -> ("-abc=0")
|
|
PASS) _shiftopt_next ;;
|
|
|
|
# CONV mode: "-abc=0" -> ("--abc=0")
|
|
CONV) OPT="-${OPT}"; _shiftopt_next ;;
|
|
|
|
# VALUE mode: "-abc=0" -> ("-a=bc=0")
|
|
VALUE) {
|
|
OPT="${_ARGV[$_ARGV_INDEX]}"
|
|
OPT_VAL="${OPT:2}"
|
|
OPT="${OPT:0:2}"
|
|
_shiftopt_next
|
|
} ;;
|
|
|
|
# SPLIT mode: "-abc=0" -> ("-a=0" "-b=0" "-c=0")
|
|
SPLIT) {
|
|
OPT="-${OPT:$_ARGV_SUBINDEX:1}"
|
|
((_ARGV_SUBINDEX++)) || true
|
|
if [[ "$_ARGV_SUBINDEX" -gt "${#OPT}" ]]; then
|
|
_shiftopt_next
|
|
fi
|
|
} ;;
|
|
|
|
# ????? mode: Treat it as pass.
|
|
*)
|
|
printf "shiftopt: unknown SHIFTOPT_SHORT_OPTIONS mode '%s'" \
|
|
"$SHIFTOPT_SHORT_OPTIONS" 1>&2
|
|
_shiftopt_next
|
|
;;
|
|
esac
|
|
else
|
|
_shiftopt_next
|
|
fi
|
|
|
|
# Handle hooks.
|
|
local hook
|
|
for hook in "${SHIFTOPT_HOOKS[@]}"; do
|
|
if "$hook"; then
|
|
shiftopt
|
|
return $?
|
|
fi
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
# Gets the value for the current option.
|
|
#
|
|
# Variables:
|
|
# OPT_VAL -- The option value.
|
|
#
|
|
# Returns:
|
|
# 0 -- An option value was read.
|
|
# EXIT 1 -- No option value was available.
|
|
shiftval() {
|
|
# Skip if a value was already provided.
|
|
if [[ -n "${OPT_VAL+x}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ "$_ARGV_SUBINDEX" -gt 1 && "$SHIFTOPT_SHORT_OPTIONS" = "SPLIT" ]]; then
|
|
# If it's a short group argument in SPLIT mode, we grab the next argument.
|
|
OPT_VAL="${_ARGV[$((_ARGV_INDEX+1))]}"
|
|
else
|
|
# Otherwise, we can handle it normally.
|
|
OPT_VAL="${_ARGV[$_ARGV_INDEX]}"
|
|
_shiftopt_next
|
|
fi
|
|
|
|
# Error if no value is provided.
|
|
if [[ "$OPT_VAL" =~ -.* ]]; then
|
|
printc "%{RED}%s: '%s' requires a value%{CLEAR}\n" "$PROGRAM" "$ARG"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
setargs "$@"
|
|
_ARGV_ORIGINAL=("$@")
|