2012-04-08 12:32:17 -04:00
|
|
|
# getopt-like parser
|
|
|
|
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
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "option '%s' is ambiguous; possibilities:")" "--$1"
|
|
|
|
printf " '%s'" "${longmatch[@]%:}"
|
|
|
|
printf '\n'
|
|
|
|
return 254 ;;
|
|
|
|
esac >&2
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "invalid option") -- '%s'\n" "$opt" >&2
|
|
|
|
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
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "option requires an argument") -- '%s'\n" "$opt" >&2
|
|
|
|
OPTRET=(--)
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
--?*=*|--?*) # long option
|
|
|
|
IFS='=' read -r opt optarg <<< "${1#--}"
|
|
|
|
longoptmatch "$opt"
|
|
|
|
case $? in
|
|
|
|
0)
|
|
|
|
# parse failure
|
|
|
|
if [[ $optarg ]]; then
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "option '%s' does not allow an argument")\n" "--$opt" >&2
|
|
|
|
OPTRET=(--)
|
|
|
|
return 1
|
|
|
|
# --longopt
|
|
|
|
else
|
|
|
|
OPTRET+=("--$opt")
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
1)
|
|
|
|
# --longopt=optarg
|
|
|
|
if [[ $optarg ]]; then
|
|
|
|
OPTRET+=("--$opt" "$optarg")
|
|
|
|
# --longopt optarg
|
|
|
|
elif [[ $2 ]]; then
|
|
|
|
OPTRET+=("--$opt" "$2" )
|
2013-01-01 22:43:20 -05:00
|
|
|
shift
|
2012-04-08 12:32:17 -04:00
|
|
|
# parse failure
|
|
|
|
else
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "option '%s' requires an argument")\n" "--$opt" >&2
|
|
|
|
OPTRET=(--)
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
254)
|
|
|
|
# ambiguous option -- error was reported for us by longoptmatch()
|
|
|
|
OPTRET=(--)
|
|
|
|
return 1
|
|
|
|
;;
|
|
|
|
255)
|
|
|
|
# parse failure
|
|
|
|
printf "@SCRIPTNAME@: $(gettext "invalid option") '--%s'\n" "$opt" >&2
|
|
|
|
OPTRET=(--)
|
|
|
|
return 1
|
|
|
|
;;
|
|
|
|
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
|
|
|
|
}
|