]> git.corax.cc Git - toolbox/commitdiff
include/opt: Add parser for command line parameters
authorMatthias Kruk <m@m10k.eu>
Sun, 28 Mar 2021 02:11:59 +0000 (11:11 +0900)
committerMatthias Kruk <m@m10k.eu>
Sun, 28 Mar 2021 02:32:44 +0000 (11:32 +0900)
Parsing of command line parameters and printing the help text adds
a significant amount of boilerplate code to any shell script (when
done thoroughly). This commit adds the opt module, which will parse
short and long parameters, execute callbacks, and print the help
text if either "-h" or "--help" were passed.

include/opt.sh [new file with mode: 0644]

diff --git a/include/opt.sh b/include/opt.sh
new file mode 100644 (file)
index 0000000..3c3c9a3
--- /dev/null
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+__init() {
+       if ! include "log" "array"; then
+               return 1
+       fi
+
+       declare -Axg __opt_short=()
+       declare -Axg __opt_long=()
+       declare -Axg __opt_desc=()
+       declare -Axg __opt_flags=()
+       declare -Axg __opt_value=()
+       declare -Axg __opt_action=()
+       declare -Axg __opt_map=()
+       declare -xgi __opt_num=0
+       declare -xgi __opt_longest=0
+
+       opt_add_arg "h" "help" "no" 0 \
+                   "Print this text" \
+                   opt_print_help
+
+       return 0
+}
+
+opt_add_arg() {
+       local short
+       local long
+       local flags
+       local default
+       local desc
+       local action
+
+       local optlen
+
+       short="$1"
+       long="$2"
+       flags="$3"
+       default="$4"
+       desc="$5"
+       action="$6"
+
+       if array_contains "$short" "${__opt_short[@]}" ||
+          array_contains "$long" "${__opt_long[@]}"; then
+               return 1
+       fi
+
+       optlen="${#long}"
+
+       __opt_short["$long"]="$short"
+       __opt_long["$short"]="$long"
+       __opt_flags["$long"]="$flags"
+       __opt_desc["$long"]="$desc"
+       __opt_value["$long"]="$default"
+       __opt_action["$long"]="$action"
+
+       __opt_map["-$short"]="$long"
+       __opt_map["--$long"]="$long"
+
+       if (( __opt_longest < optlen )); then
+               __opt_longest=optlen;
+       fi
+
+       ((__opt_num++))
+
+       return 0
+}
+
+opt_print_help() {
+       local short
+       local shortopts
+
+       shortopts=""
+
+       for short in $(array_sort "${__opt_short[@]}"); do
+               shortopts+="$short"
+       done
+
+       echo "Usage: $BASH_ARGV0 [-$shortopts]"
+       echo ""
+       echo "Options"
+
+       for short in $(array_sort "${__opt_short[@]}"); do
+               local long
+               local desc
+               local optlen
+               local padding
+
+               long="${__opt_long[$short]}"
+               desc="${__opt_desc[$long]}"
+               optlen="${#long}"
+               padding=$((__opt_longest - optlen))
+
+               printf " -%s  --%s %*s %s\n" \
+                      "$short" "$long" "$padding" "" "$desc"
+       done
+
+       return 2
+}
+
+opt_parse() {
+       local opt
+       local i
+
+       for (( i = 1; i <= $#; i++ )); do
+               local param
+               local long
+               local flags
+               local value
+               local action
+
+               param="${!i}"
+               long="${__opt_map[$param]}"
+
+               if [[ -z "$long" ]]; then
+                       log_error "Unrecognized parameter: $param"
+                       return 1
+               fi
+
+               flags="${__opt_flags[$long]}"
+               action="${__opt_action[$long]}"
+
+               if [[ "$flags" == "yes" ]]; then
+                       ((i++))
+
+                       if (( i > $# )); then
+                               log_error "Missing argument after $param"
+                               return 1
+                       fi
+
+                       value="${!i}"
+               else
+                       value="${__opt_value[$long]}"
+                       ((value++))
+               fi
+
+               __opt_value["$long"]="$value"
+
+               if ! [[ -z "$action" ]]; then
+                       local err
+
+                       "$action" "$long" "$value"
+                       err="$?"
+
+                       if (( err != 0 )); then
+                               return "$err"
+                       fi
+               fi
+       done
+
+       return 0
+}
+
+opt_get() {
+       local long
+
+       long="$1"
+
+       if ! array_contains "$long" "${!__opt_value[@]}"; then
+               return 1
+       fi
+
+       echo "${__opt_value[$long]}"
+       return 0
+}