function perr-badflag { perr "unrecognised flag ${BOLD}${MAGENTA}'$1'${RESET}";}
function perr-noflagval { perr "flag ${BOLD}${MAGENTA}'$1'${RESET} requires ${BOLD}${MAGENTA}${2}${RESET} argument(s), but only ${BOLD}${MAGENTA}${3}${RESET} were given";}
function perr-badarg { perr "unrecognised arg ${BOLD}${MAGENTA}'$1'${RESET}";}
function perr-noarg { perr "required argument ${BOLD}${MAGENTA}'$1'${RESET} is missing";}
# Failures
function throw {echo -e "${@:2}" >&2;if[["$1" -ge 0]];thenexit"$1";fi;}
function throw-usage { throw "$1""$(perr-usage 2>&1)";}
function throw-badflag { throw "$1""$(perr-badflag "${@:2}" 2>&1)";}
function throw-noflagval { throw "$1""$(perr-noflagval "${@:2}" 2>&1)";}
function throw-badarg { throw "$1""$(perr-badarg "${@:2}" 2>&1)";}
function throw-noarg { throw "$1""$(perr-noarg "${@:2}" 2>&1)";}
# Parsing/Validation
function required {[[ -n "$1"]]|| throw-noarg 1"${@:2}";}
# Other
function confirm-action {
local CHAR
while :;do
echo -e "$1"
read -n1 CHAR
case$CHAR in
[yY])
return0;;
[nN])
return1;;
esac
done
}
function confirm { confirm-action ":: Proceed? [Y/n] ";}