From 5d62de59adfa8e6b7c19c418effc8757637c702e Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Tue, 17 Apr 2012 19:22:24 -0400 Subject: functions: add parseopts for longopt fun Signed-off-by: Dave Reisner --- functions | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/functions b/functions index 5485578..eebf3a4 100644 --- a/functions +++ b/functions @@ -1,5 +1,143 @@ #!/bin/bash +parseopts() { + local opt= optarg= i= shortopts=$1 + local -a longopts=() unused_argv=() + + shift + while [[ $1 && $1 != '--' ]]; do + longopts+=("$1") + shift + done + shift + + longoptmatch() { + local o longmatch=() + for o in "${longopts[@]}"; do + if [[ ${o%:} = "$1" ]]; then + longmatch=("$o") + break + fi + [[ ${o%:} = "$1"* ]] && longmatch+=("$o") + done + + case ${#longmatch[*]} in + 1) + # success, override with opt and return arg req (0 == none, 1 == required) + opt=${longmatch%:} + if [[ $longmatch = *: ]]; then + return 1 + else + return 0 + fi ;; + 0) + # fail, no match found + return 255 ;; + *) + # fail, ambiguous match + error "option '%s' is ambiguous; possibilities:%s" \ + "--$1" "$(printf " '%s'" "${longmatch[@]%:}")" + return 254 ;; + esac + } + + while (( $# )); do + case $1 in + --) # explicit end of options + shift + break + ;; + -[!-]*) # short option + for (( i = 1; i < ${#1}; i++ )); do + opt=${1:i:1} + + # option doesn't exist + if [[ $shortopts != *$opt* ]]; then + error "invalid option '%s'" "$opt" + OPTRET=(--) + return 1 + fi + + OPTRET+=("-$opt") + # option requires optarg + if [[ $shortopts = *$opt:* ]]; then + # if we're not at the end of the option chunk, the rest is the optarg + if (( i < ${#1} - 1 )); then + OPTRET+=("${1:i+1}") + break + # if we're at the end, grab the the next positional, if it exists + elif (( i == ${#1} - 1 )) && [[ $2 ]]; then + OPTRET+=("$2") + shift + break + # parse failure + else + error "option '%s' requires an argument" "-$opt" + OPTRET=(--) + return 1 + fi + fi + done + ;; + --?*=*|--?*) # long option + IFS='=' read -r opt optarg <<< "${1#--}" + longoptmatch "$opt" + case $? in + 0) + if [[ $optarg ]]; then + error "option '%s' does not allow an argument" "--$opt" + OPTRET=(--) + return 1 + else + OPTRET+=("--$opt") + shift + continue 2 + fi + ;; + 1) + # --longopt=optarg + if [[ $optarg ]]; then + OPTRET+=("--$opt" "$optarg") + shift + # --longopt optarg + elif [[ $2 ]]; then + OPTRET+=("--$opt" "$2" ) + shift 2 + else + error "option '%s' requires an argument" "--$opt" + OPTRET=(--) + return 1 + fi + continue 2 + ;; + 254) + # ambiguous option -- error was reported for us by longoptmatch() + OPTRET=(--) + return 1 + ;; + 255) + error "invalid option '%s'" "--$opt" + OPTRET=(--) + return 1 + ;; + *) + error "internal error: invalid option in longopt array '%s'" "--$opt" + esac + ;; + *) # non-option arg encountered, add it as a parameter + unused_argv+=("$1") + ;; + esac + shift + done + + # add end-of-opt terminator and any leftover positional parameters + OPTRET+=('--' "${unused_argv[@]}" "$@") + unset longoptmatch + + return 0 +} + plain() { local mesg=$1; shift printf "$BOLD $mesg$NC\n" "$@" >&1 -- cgit v1.2.3-24-g4f1b