diff options
author | Kate Ward <kate.ward@forestent.com> | 2018-01-15 10:31:32 +0100 |
---|---|---|
committer | Kate Ward <kate.ward@forestent.com> | 2018-01-15 10:31:32 +0100 |
commit | bf9a2471431387588ada3b4a250f1d616bd9988c (patch) | |
tree | 2977c501f55a0a8dabb83b59e849471ef416d59e | |
parent | 5df39c91d3d8804a254bcf2ed3f8432dcc982e1c (diff) | |
download | shflags-bf9a2471431387588ada3b4a250f1d616bd9988c.tar.gz |
Made a sym-link to ../shflags.
l---------[-rw-r--r--] | lib/shflags | 1218 |
1 files changed, 1 insertions, 1217 deletions
diff --git a/lib/shflags b/lib/shflags index 470bd1f..c9b48b6 100644..120000 --- a/lib/shflags +++ b/lib/shflags @@ -1,1217 +1 @@ -# vim:et:ft=sh:sts=2:sw=2 -# -# Copyright 2008-2017 Kate Ward. All Rights Reserved. -# Released under the Apache License 2.0 license. -# http://www.apache.org/licenses/LICENSE-2.0 -# -# shFlags -- Advanced command-line flag library for Unix shell scripts. -# https://github.com/kward/shflags -# -# Author: kate.ward@forestent.com (Kate Ward) -# -# This module implements something like the gflags library available -# from https://github.com/gflags/gflags. -# -# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take -# a name, default value, help-string, and optional 'short' name (one-letter -# name). Some flags have other arguments, which are described with the flag. -# -# DEFINE_string: takes any input, and interprets it as a string. -# -# DEFINE_boolean: does not take any arguments. Say --myflag to set -# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. For short -# flags, passing the flag on the command-line negates the default value, i.e. -# if the default is true, passing the flag sets the value to false. -# -# DEFINE_float: takes an input and interprets it as a floating point number. As -# shell does not support floats per-se, the input is merely validated as -# being a valid floating point value. -# -# DEFINE_integer: takes an input and interprets it as an integer. -# -# SPECIAL FLAGS: There are a few flags that have special meaning: -# --help (or -?) prints a list of all the flags in a human-readable fashion -# --flagfile=foo read flags from foo. (not implemented yet) -# -- as in getopt(), terminates flag-processing -# -# EXAMPLE USAGE: -# -# -- begin hello.sh -- -# #! /bin/sh -# . ./shflags -# DEFINE_string name 'world' "somebody's name" n -# FLAGS "$@" || exit $? -# eval set -- "${FLAGS_ARGV}" -# echo "Hello, ${FLAGS_name}." -# -- end hello.sh -- -# -# $ ./hello.sh -n Kate -# Hello, Kate. -# -# CUSTOMIZABLE BEHAVIOR: -# -# A script can override the default 'getopt' command by providing the path to -# an alternate implementation by defining the FLAGS_GETOPT_CMD variable. -# -# NOTES: -# -# * Not all systems include a getopt version that supports long flags. On these -# systems, only short flags are recognized. - -#============================================================================== -# shFlags -# -# Shared attributes: -# flags_error: last error message -# flags_output: last function output (rarely valid) -# flags_return: last return value -# -# __flags_longNames: list of long names for all flags -# __flags_shortNames: list of short names for all flags -# __flags_boolNames: list of boolean flag names -# -# __flags_opts: options parsed by getopt -# -# Per-flag attributes: -# FLAGS_<flag_name>: contains value of flag named 'flag_name' -# __flags_<flag_name>_default: the default flag value -# __flags_<flag_name>_help: the flag help string -# __flags_<flag_name>_short: the flag short name -# __flags_<flag_name>_type: the flag type -# -# Notes: -# - lists of strings are space separated, and a null value is the '~' char. - -# Return if FLAGS already loaded. -[ -n "${FLAGS_VERSION:-}" ] && return 0 -FLAGS_VERSION='1.2.1' - -# Return values that scripts can use. -FLAGS_TRUE=0 -FLAGS_FALSE=1 -FLAGS_ERROR=2 - -# Logging levels. -FLAGS_LEVEL_DEBUG=0 -FLAGS_LEVEL_INFO=1 -FLAGS_LEVEL_WARN=2 -FLAGS_LEVEL_ERROR=3 -FLAGS_LEVEL_FATAL=4 -__FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN} - -# Determine some reasonable command defaults. -__FLAGS_EXPR_CMD='expr --' -__FLAGS_UNAME_S=`uname -s` -if [ "${__FLAGS_UNAME_S}" = 'BSD' ]; then - __FLAGS_EXPR_CMD='gexpr --' -else - _flags_output_=`${__FLAGS_EXPR_CMD} 2>&1` - if [ $? -eq ${FLAGS_TRUE} -a "${_flags_output_}" = '--' ]; then - # We are likely running inside BusyBox. - __FLAGS_EXPR_CMD='expr' - fi - unset _flags_output_ -fi - -# Commands a user can override if needed. -FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}} -FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt} - -# Specific shell checks. -if [ -n "${ZSH_VERSION:-}" ]; then - setopt |grep "^shwordsplit$" >/dev/null - if [ $? -ne ${FLAGS_TRUE} ]; then - _flags_fatal 'zsh shwordsplit option is required for proper zsh operation' - fi - if [ -z "${FLAGS_PARENT:-}" ]; then - _flags_fatal "zsh does not pass \$0 through properly. please declare' \ -\"FLAGS_PARENT=\$0\" before calling shFlags" - fi -fi - -# Can we use built-ins? -( echo "${FLAGS_TRUE#0}"; ) >/dev/null 2>&1 -if [ $? -eq ${FLAGS_TRUE} ]; then - __FLAGS_USE_BUILTIN=${FLAGS_TRUE} -else - __FLAGS_USE_BUILTIN=${FLAGS_FALSE} -fi - - -# -# Constants. -# - -# Reserved flag names. -__FLAGS_RESERVED_LIST=' ARGC ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE ' -__FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION " - -# getopt version. -__FLAGS_GETOPT_VERS_STD=0 -__FLAGS_GETOPT_VERS_ENH=1 -__FLAGS_GETOPT_VERS_BSD=2 - -${FLAGS_GETOPT_CMD} >/dev/null 2>&1 -case $? in - 0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt - 1) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH} ;; # BusyBox getopt. - 2) - # TODO(kward): look into '-T' option to test the internal getopt() version - if [ "`${FLAGS_GETOPT_CMD} --version`" = '-- ' ]; then - __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} - else - __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH} - fi - ;; - *) _flags_fatal 'unable to determine getopt version' ;; -esac - -# getopt optstring lengths -__FLAGS_OPTSTR_SHORT=0 -__FLAGS_OPTSTR_LONG=1 - -__FLAGS_NULL='~' - -# Flag info strings. -__FLAGS_INFO_DEFAULT='default' -__FLAGS_INFO_HELP='help' -__FLAGS_INFO_SHORT='short' -__FLAGS_INFO_TYPE='type' - -# Flag lengths. -__FLAGS_LEN_SHORT=0 -__FLAGS_LEN_LONG=1 - -# Flag types. -__FLAGS_TYPE_NONE=0 -__FLAGS_TYPE_BOOLEAN=1 -__FLAGS_TYPE_FLOAT=2 -__FLAGS_TYPE_INTEGER=3 -__FLAGS_TYPE_STRING=4 - -# Set the constants readonly. -__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'` -for __flags_const in ${__flags_constants}; do - # Skip certain flags. - case ${__flags_const} in - FLAGS_HELP) continue ;; - FLAGS_PARENT) continue ;; - esac - # Set flag readonly. - if [ -z "${ZSH_VERSION:-}" ]; then - readonly ${__flags_const} - continue - fi - case ${ZSH_VERSION} in - [123].*) readonly ${__flags_const} ;; - *) readonly -g ${__flags_const} ;; # Declare readonly constants globally. - esac -done -unset __flags_const __flags_constants - -# -# Internal variables. -# - -# Space separated lists. -__flags_boolNames=' ' # Boolean flag names. -__flags_longNames=' ' # Long flag names. -__flags_shortNames=' ' # Short flag names. -__flags_definedNames=' ' # Defined flag names (used for validation). - -__flags_columns='' # Screen width in columns. -__flags_level=0 # Default logging level. -__flags_opts='' # Temporary storage for parsed getopt flags. - -#------------------------------------------------------------------------------ -# Private functions. -# - -# Logging functions. -_flags_debug() { - [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ] || return - echo "flags:DEBUG $@" >&2 -} -_flags_info() { - [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ] || return - echo "flags:INFO $@" >&2 -} -_flags_warn() { - [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ] || return - echo "flags:WARN $@" >&2 -} -_flags_error() { - [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ] || return - echo "flags:ERROR $@" >&2 -} -_flags_fatal() { - [ ${__flags_level} -le ${FLAGS_LEVEL_FATAL} ] || return - echo "flags:FATAL $@" >&2 - exit ${FLAGS_ERROR} -} - -# Get the logging level. -flags_loggingLevel() { echo ${__flags_level}; } - -# Set the logging level. -# -# Args: -# _flags_level_: integer: new logging level -# Returns: -# nothing -flags_setLoggingLevel() { - [ $# -ne 1 ] && _flags_fatal "flags_setLevel(): logging level missing" - _flags_level_=$1 - [ ${_flags_level_} -ge ${FLAGS_LEVEL_DEBUG} \ - -a ${_flags_level_} -le ${FLAGS_LEVEL_FATAL} ] \ - || _flags_fatal "Invalid logging level '${_flags_level_}' specified." - __flags_level=$1 - unset _flags_level_ -} - -# Define a flag. -# -# Calling this function will define the following info variables for the -# specified flag: -# FLAGS_flagname - the name for this flag (based upon the long flag name) -# __flags_<flag_name>_default - the default value -# __flags_flagname_help - the help string -# __flags_flagname_short - the single letter alias -# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*) -# -# Args: -# _flags_type_: integer: internal type of flag (__FLAGS_TYPE_*) -# _flags_name_: string: long flag name -# _flags_default_: default flag value -# _flags_help_: string: help string -# _flags_short_: string: (optional) short flag name -# Returns: -# integer: success of operation, or error -_flags_define() -{ - if [ $# -lt 4 ]; then - flags_error='DEFINE error: too few arguments' - flags_return=${FLAGS_ERROR} - _flags_error "${flags_error}" - return ${flags_return} - fi - - _flags_type_=$1 - _flags_name_=$2 - _flags_default_=$3 - _flags_help_=$4 - _flags_short_=${5:-${__FLAGS_NULL}} - - _flags_debug "type:${_flags_type_} name:${_flags_name_}" \ - "default:'${_flags_default_}' help:'${_flags_help_}'" \ - "short:${_flags_short_}" - - _flags_return_=${FLAGS_TRUE} - _flags_usName_=`_flags_underscoreName ${_flags_name_}` - - # check whether the flag name is reserved - _flags_itemInList ${_flags_usName_} "${__FLAGS_RESERVED_LIST}" - if [ $? -eq ${FLAGS_TRUE} ]; then - flags_error="flag name (${_flags_name_}) is reserved" - _flags_return_=${FLAGS_ERROR} - fi - - # require short option for getopt that don't support long options - if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ - -a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \ - -a "${_flags_short_}" = "${__FLAGS_NULL}" ] - then - flags_error="short flag required for (${_flags_name_}) on this platform" - _flags_return_=${FLAGS_ERROR} - fi - - # check for existing long name definition - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - if _flags_itemInList ${_flags_usName_} ${__flags_definedNames}; then - flags_error="definition for ([no]${_flags_name_}) already exists" - _flags_warn "${flags_error}" - _flags_return_=${FLAGS_FALSE} - fi - fi - - # check for existing short name definition - if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ - -a "${_flags_short_}" != "${__FLAGS_NULL}" ] - then - if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then - flags_error="flag short name (${_flags_short_}) already defined" - _flags_warn "${flags_error}" - _flags_return_=${FLAGS_FALSE} - fi - fi - - # handle default value. note, on several occasions the 'if' portion of an - # if/then/else contains just a ':' which does nothing. a binary reversal via - # '!' is not done because it does not work on all shells. - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - case ${_flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if _flags_validBool "${_flags_default_}"; then - case ${_flags_default_} in - true|t|0) _flags_default_=${FLAGS_TRUE} ;; - false|f|1) _flags_default_=${FLAGS_FALSE} ;; - esac - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_FLOAT}) - if _flags_validFloat "${_flags_default_}"; then - : - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_INTEGER}) - if _flags_validInt "${_flags_default_}"; then - : - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_STRING}) ;; # everything in shell is a valid string - - *) - flags_error="unrecognized flag type '${_flags_type_}'" - _flags_return_=${FLAGS_ERROR} - ;; - esac - fi - - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - # Store flag information. - eval "FLAGS_${_flags_usName_}='${_flags_default_}'" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=\ -\"${_flags_default_}\"" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\"" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'" - - # append flag names to name lists - __flags_shortNames="${__flags_shortNames}${_flags_short_} " - __flags_longNames="${__flags_longNames}${_flags_name_} " - [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \ - __flags_boolNames="${__flags_boolNames}no${_flags_name_} " - - # append flag names to defined names for later validation checks - __flags_definedNames="${__flags_definedNames}${_flags_usName_} " - [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \ - __flags_definedNames="${__flags_definedNames}no${_flags_usName_} " - fi - - flags_return=${_flags_return_} - unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \ - _flags_short_ _flags_type_ _flags_usName_ - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" - return ${flags_return} -} - -# Underscore a flag name by replacing dashes with underscores. -# -# Args: -# unnamed: string: log flag name -# Output: -# string: underscored name -_flags_underscoreName() -{ - echo $1 |tr '-' '_' -} - -# Return valid getopt options using currently defined list of long options. -# -# This function builds a proper getopt option string for short (and long) -# options, using the current list of long options for reference. -# -# Args: -# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*) -# Output: -# string: generated option string for getopt -# Returns: -# boolean: success of operation (always returns True) -_flags_genOptStr() -{ - _flags_optStrType_=$1 - - _flags_opts_='' - - for _flags_name_ in ${__flags_longNames}; do - _flags_usName_=`_flags_underscoreName ${_flags_name_}` - _flags_type_=`_flags_getFlagInfo ${_flags_usName_} ${__FLAGS_INFO_TYPE}` - [ $? -eq ${FLAGS_TRUE} ] || _flags_fatal 'call to _flags_type_ failed' - case ${_flags_optStrType_} in - ${__FLAGS_OPTSTR_SHORT}) - _flags_shortName_=`_flags_getFlagInfo \ - ${_flags_usName_} ${__FLAGS_INFO_SHORT}` - if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then - _flags_opts_="${_flags_opts_}${_flags_shortName_}" - # getopt needs a trailing ':' to indicate a required argument - [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ - _flags_opts_="${_flags_opts_}:" - fi - ;; - - ${__FLAGS_OPTSTR_LONG}) - _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_name_}" - # getopt needs a trailing ':' to indicate a required argument - [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ - _flags_opts_="${_flags_opts_}:" - ;; - esac - done - - echo "${_flags_opts_}" - unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \ - _flags_type_ _flags_usName_ - return ${FLAGS_TRUE} -} - -# Returns flag details based on a flag name and flag info. -# -# Args: -# string: underscored flag name -# string: flag info (see the _flags_define function for valid info types) -# Output: -# string: value of dereferenced flag variable -# Returns: -# integer: one of FLAGS_{TRUE|FALSE|ERROR} -_flags_getFlagInfo() -{ - # note: adding gFI to variable names to prevent naming conflicts with calling - # functions - _flags_gFI_usName_=$1 - _flags_gFI_info_=$2 - - _flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}" - _flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\"" - eval "${_flags_strToEval_}" - if [ -n "${_flags_infoValue_+x}" ]; then - flags_return=${FLAGS_TRUE} - else - # see if the _flags_gFI_usName_ variable is a string as strings can be - # empty... - # note: the DRY principle would say to have this function call itself for - # the next three lines, but doing so results in an infinite loop as an - # invalid _flags_name_ will also not have the associated _type variable. - # Because it doesn't (it will evaluate to an empty string) the logic will - # try to find the _type variable of the _type variable, and so on. Not so - # good ;-) - _flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}" - _flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\"" - eval "${_flags_strToEval_}" - if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" ]; then - flags_return=${FLAGS_TRUE} - else - flags_return=${FLAGS_ERROR} - flags_error="missing flag info variable (${_flags_infoVar_})" - fi - fi - - echo "${_flags_infoValue_}" - unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \ - _flags_strToEval_ _flags_typeValue_ _flags_typeVar_ - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" - return ${flags_return} -} - -# Check for presence of item in a list. -# -# Passed a string (e.g. 'abc'), this function will determine if the string is -# present in the list of strings (e.g. ' foo bar abc '). -# -# Args: -# _flags_str_: string: string to search for in a list of strings -# unnamed: list: list of strings -# Returns: -# boolean: true if item is in the list -_flags_itemInList() { - _flags_str_=$1 - shift - - case " ${*:-} " in - *\ ${_flags_str_}\ *) flags_return=${FLAGS_TRUE} ;; - *) flags_return=${FLAGS_FALSE} ;; - esac - - unset _flags_str_ - return ${flags_return} -} - -# Returns the width of the current screen. -# -# Output: -# integer: width in columns of the current screen. -_flags_columns() -{ - if [ -z "${__flags_columns}" ]; then - # determine the value and store it - if eval stty size >/dev/null 2>&1; then - # stty size worked :-) - set -- `stty size` - __flags_columns=$2 - elif eval tput cols >/dev/null 2>&1; then - set -- `tput cols` - __flags_columns=$1 - else - __flags_columns=80 # default terminal width - fi - fi - echo ${__flags_columns} -} - -# Validate a boolean. -# -# Args: -# _flags__bool: boolean: value to validate -# Returns: -# bool: true if the value is a valid boolean -_flags_validBool() -{ - _flags_bool_=$1 - - flags_return=${FLAGS_TRUE} - case "${_flags_bool_}" in - true|t|0) ;; - false|f|1) ;; - *) flags_return=${FLAGS_FALSE} ;; - esac - - unset _flags_bool_ - return ${flags_return} -} - -# Validate a float. -# -# Args: -# _flags_float_: float: value to validate -# Returns: -# bool: true if the value is a valid integer -_flags_validFloat() { - flags_return=${FLAGS_FALSE} - [ -n "$1" ] || return ${flags_return} - _flags_float_=$1 - - if _flags_validInt ${_flags_float_}; then - flags_return=${FLAGS_TRUE} - elif _flags_useBuiltin; then - _flags_float_whole_=${_flags_float_%.*} - _flags_float_fraction_=${_flags_float_#*.} - if _flags_validInt ${_flags_float_whole_:-0} -a \ - _flags_validInt ${_flags_float_fraction_}; then - flags_return=${FLAGS_TRUE} - fi - unset _flags_float_whole_ _flags_float_fraction_ - else - flags_return=${FLAGS_TRUE} - case ${_flags_float_} in - -*) # negative floats - _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ - '\(-[0-9]*\.[0-9]*\)'` - ;; - *) # positive floats - _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ - '\([0-9]*\.[0-9]*\)'` - ;; - esac - [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE} - unset _flags_test_ - fi - - unset _flags_float_ _flags_float_whole_ _flags_float_fraction_ - return ${flags_return} -} - -# Validate an integer. -# -# Args: -# _flags_int_: integer: value to validate -# Returns: -# bool: true if the value is a valid integer -_flags_validInt() -{ - flags_return=${FLAGS_FALSE} - [ -n "$1" ] || return ${flags_return} - _flags_int_=$1 - - case ${_flags_int_} in - -*.*) ;; # ignore negative floats (we'll invalidate them later) - -*) # strip possible leading negative sign - if _flags_useBuiltin; then - _flags_int_=${_flags_int_#-} - else - _flags_int_=`${FLAGS_EXPR_CMD} "${_flags_int_}" : '-\([0-9][0-9]*\)'` - fi - ;; - esac - - case ${_flags_int_} in - *[!0-9]*) flags_return=${FLAGS_FALSE} ;; - *) flags_return=${FLAGS_TRUE} ;; - esac - - unset _flags_int_ - return ${flags_return} -} - -# Parse command-line options using the standard getopt. -# -# Note: the flag options are passed around in the global __flags_opts so that -# the formatting is not lost due to shell parsing and such. -# -# Args: -# @: varies: command-line options to parse -# Returns: -# integer: a FLAGS success condition -_flags_getoptStandard() -{ - flags_return=${FLAGS_TRUE} - _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` - - # check for spaces in passed options - for _flags_opt_ in "$@"; do - # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 - _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'` - if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then - flags_error='the available getopt does not support spaces in options' - flags_return=${FLAGS_ERROR} - break - fi - done - - if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then - __flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1` - _flags_rtrn_=$? - if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then - _flags_warn "${__flags_opts}" - flags_error='unable to parse provided options with getopt.' - flags_return=${FLAGS_ERROR} - fi - fi - - unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_ - return ${flags_return} -} - -# Parse command-line options using the enhanced getopt. -# -# Note: the flag options are passed around in the global __flags_opts so that -# the formatting is not lost due to shell parsing and such. -# -# Args: -# @: varies: command-line options to parse -# Returns: -# integer: a FLAGS success condition -_flags_getoptEnhanced() -{ - flags_return=${FLAGS_TRUE} - _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` - _flags_boolOpts_=`echo "${__flags_boolNames}" \ - |sed 's/^ *//;s/ *$//;s/ /,/g'` - _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}` - - __flags_opts=`${FLAGS_GETOPT_CMD} \ - -o ${_flags_shortOpts_} \ - -l "${_flags_longOpts_},${_flags_boolOpts_}" \ - -- "$@" 2>&1` - _flags_rtrn_=$? - if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then - _flags_warn "${__flags_opts}" - flags_error='unable to parse provided options with getopt.' - flags_return=${FLAGS_ERROR} - fi - - unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_ - return ${flags_return} -} - -# Dynamically parse a getopt result and set appropriate variables. -# -# This function does the actual conversion of getopt output and runs it through -# the standard case structure for parsing. The case structure is actually quite -# dynamic to support any number of flags. -# -# Args: -# argc: int: original command-line argument count -# @: varies: output from getopt parsing -# Returns: -# integer: a FLAGS success condition -_flags_parseGetopt() -{ - _flags_argc_=$1 - shift - - flags_return=${FLAGS_TRUE} - - if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then - set -- $@ - else - # note the quotes around the `$@' -- they are essential! - eval set -- "$@" - fi - - # Provide user with the number of arguments to shift by later. - # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not - # properly give user access to non-flag arguments mixed in between flag - # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only - # for backwards compatibility reasons. - FLAGS_ARGC=`_flags_math "$# - 1 - ${_flags_argc_}"` - - # handle options. note options with values must do an additional shift - while true; do - _flags_opt_=$1 - _flags_arg_=${2:-} - _flags_type_=${__FLAGS_TYPE_NONE} - _flags_name_='' - - # determine long flag name - case "${_flags_opt_}" in - --) shift; break ;; # discontinue option parsing - - --*) # long option - if _flags_useBuiltin; then - _flags_opt_=${_flags_opt_#*--} - else - _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '--\(.*\)'` - fi - _flags_len_=${__FLAGS_LEN_LONG} - if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then - _flags_name_=${_flags_opt_} - else - # check for negated long boolean version - if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then - if _flags_useBuiltin; then - _flags_name_=${_flags_opt_#*no} - else - _flags_name_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : 'no\(.*\)'` - fi - _flags_type_=${__FLAGS_TYPE_BOOLEAN} - _flags_arg_=${__FLAGS_NULL} - fi - fi - ;; - - -*) # short option - if _flags_useBuiltin; then - _flags_opt_=${_flags_opt_#*-} - else - _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '-\(.*\)'` - fi - _flags_len_=${__FLAGS_LEN_SHORT} - if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then - # yes. match short name to long name. note purposeful off-by-one - # (too high) with awk calculations. - _flags_pos_=`echo "${__flags_shortNames}" \ - |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \ - e=${_flags_opt_}` - _flags_name_=`echo "${__flags_longNames}" \ - |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"` - fi - ;; - esac - - # die if the flag was unrecognized - if [ -z "${_flags_name_}" ]; then - flags_error="unrecognized option (${_flags_opt_})" - flags_return=${FLAGS_ERROR} - break - fi - - # set new flag value - _flags_usName_=`_flags_underscoreName ${_flags_name_}` - [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \ - _flags_type_=`_flags_getFlagInfo \ - "${_flags_usName_}" ${__FLAGS_INFO_TYPE}` - case ${_flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then - if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then - eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" - else - eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" - fi - else - _flags_strToEval_="_flags_val_=\ -\${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}" - eval "${_flags_strToEval_}" - if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then - eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" - else - eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" - fi - fi - ;; - - ${__FLAGS_TYPE_FLOAT}) - if _flags_validFloat "${_flags_arg_}"; then - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - else - flags_error="invalid float value (${_flags_arg_})" - flags_return=${FLAGS_ERROR} - break - fi - ;; - - ${__FLAGS_TYPE_INTEGER}) - if _flags_validInt "${_flags_arg_}"; then - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - else - flags_error="invalid integer value (${_flags_arg_})" - flags_return=${FLAGS_ERROR} - break - fi - ;; - - ${__FLAGS_TYPE_STRING}) - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - ;; - esac - - # handle special case help flag - if [ "${_flags_usName_}" = 'help' ]; then - if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then - flags_help - flags_error='help requested' - flags_return=${FLAGS_FALSE} - break - fi - fi - - # shift the option and non-boolean arguments out. - shift - [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift - done - - # give user back non-flag arguments - FLAGS_ARGV='' - while [ $# -gt 0 ]; do - FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'" - shift - done - - unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \ - _flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_ - return ${flags_return} -} - -# Perform some path using built-ins. -# -# Args: -# $@: string: math expression to evaluate -# Output: -# integer: the result -# Returns: -# bool: success of math evaluation -_flags_math() { - if [ $# -eq 0 ]; then - flags_return=${FLAGS_FALSE} - elif _flags_useBuiltin; then - # Variable assignment is needed as workaround for Solaris Bourne shell, - # which cannot parse a bare $((expression)). - _flags_expr_='$(($@))' - eval echo ${_flags_expr_} - flags_return=$? - unset _flags_expr_ - else - eval expr $@ - flags_return=$? - fi - - return ${flags_return} -} - -# Cross-platform strlen() implementation. -# -# Args: -# _flags_str: string: to determine length of -# Output: -# integer: length of string -# Returns: -# bool: success of strlen evaluation -_flags_strlen() -{ - _flags_str_=${1:-} - - if [ -z "${_flags_str_}" ]; then - flags_output=0 - elif _flags_useBuiltin; then - flags_output=${#_flags_str_} - else - flags_output=`${FLAGS_EXPR_CMD} "${_flags_str_}" : '.*'` - fi - flags_return=$? - - unset _flags_str_ - echo ${flags_output} - return ${flags_return} -} - -# Use built-in helper function to enable unit testing. -# -# Args: -# None -# Returns: -# bool: true if built-ins should be used -_flags_useBuiltin() { return ${__FLAGS_USE_BUILTIN}; } - -#------------------------------------------------------------------------------ -# public functions -# -# A basic boolean flag. Boolean flags do not take any arguments, and their -# value is either 1 (false) or 0 (true). For long flags, the false value is -# specified on the command line by prepending the word 'no'. With short flags, -# the presence of the flag toggles the current value between true and false. -# Specifying a short boolean flag twice on the command results in returning the -# value back to the default value. -# -# A default value is required for boolean flags. -# -# For example, lets say a Boolean flag was created whose long name was 'update' -# and whose short name was 'x', and the default value was 'false'. This flag -# could be explicitly set to 'true' with '--update' or by '-x', and it could be -# explicitly set to 'false' with '--noupdate'. -DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; } - -# Other basic flags. -DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; } -DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; } -DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; } - -# Parse the flags. -# -# Args: -# unnamed: list: command-line flags to parse -# Returns: -# integer: success of operation, or error -FLAGS() -{ - # define a standard 'help' flag if one isn't already defined - [ -z "${__flags_help_type:-}" ] && \ - DEFINE_boolean 'help' false 'show this help' 'h' - - # parse options - if [ $# -gt 0 ]; then - if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then - _flags_getoptStandard "$@" - else - _flags_getoptEnhanced "$@" - fi - flags_return=$? - else - # nothing passed; won't bother running getopt - __flags_opts='--' - flags_return=${FLAGS_TRUE} - fi - - if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then - _flags_parseGetopt $# "${__flags_opts}" - flags_return=$? - fi - - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}" - return ${flags_return} -} - -# This is a helper function for determining the 'getopt' version for platforms -# where the detection isn't working. It simply outputs debug information that -# can be included in a bug report. -# -# Args: -# none -# Output: -# debug info that can be included in a bug report -# Returns: -# nothing -flags_getoptInfo() -{ - # platform info - _flags_debug "uname -a: `uname -a`" - _flags_debug "PATH: ${PATH}" - - # shell info - if [ -n "${BASH_VERSION:-}" ]; then - _flags_debug 'shell: bash' - _flags_debug "BASH_VERSION: ${BASH_VERSION}" - elif [ -n "${ZSH_VERSION:-}" ]; then - _flags_debug 'shell: zsh' - _flags_debug "ZSH_VERSION: ${ZSH_VERSION}" - fi - - # getopt info - ${FLAGS_GETOPT_CMD} >/dev/null - _flags_getoptReturn=$? - _flags_debug "getopt return: ${_flags_getoptReturn}" - _flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`" - - unset _flags_getoptReturn -} - -# Returns whether the detected getopt version is the enhanced version. -# -# Args: -# none -# Output: -# none -# Returns: -# bool: true if getopt is the enhanced version -flags_getoptIsEnh() -{ - test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} -} - -# Returns whether the detected getopt version is the standard version. -# -# Args: -# none -# Returns: -# bool: true if getopt is the standard version -flags_getoptIsStd() -{ - test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} -} - -# This is effectively a 'usage()' function. It prints usage information and -# exits the program with ${FLAGS_FALSE} if it is ever found in the command line -# arguments. Note this function can be overridden so other apps can define -# their own --help flag, replacing this one, if they want. -# -# Args: -# none -# Returns: -# integer: success of operation (always returns true) -flags_help() -{ - if [ -n "${FLAGS_HELP:-}" ]; then - echo "${FLAGS_HELP}" >&2 - else - echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2 - fi - if [ -n "${__flags_longNames}" ]; then - echo 'flags:' >&2 - for flags_name_ in ${__flags_longNames}; do - flags_flagStr_='' - flags_boolStr_='' - flags_usName_=`_flags_underscoreName ${flags_name_}` - - flags_default_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_DEFAULT}` - flags_help_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_HELP}` - flags_short_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_SHORT}` - flags_type_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_TYPE}` - - [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ - flags_flagStr_="-${flags_short_}" - - if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then - [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ - flags_flagStr_="${flags_flagStr_}," - # add [no] to long boolean flag names, except the 'help' flag - [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} \ - -a "${flags_usName_}" != 'help' ] && \ - flags_boolStr_='[no]' - flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:" - fi - - case ${flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then - flags_defaultStr_='true' - else - flags_defaultStr_='false' - fi - ;; - ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER}) - flags_defaultStr_=${flags_default_} ;; - ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;; - esac - flags_defaultStr_="(default: ${flags_defaultStr_})" - - flags_helpStr_=" ${flags_flagStr_} ${flags_help_} ${flags_defaultStr_}" - _flags_strlen "${flags_helpStr_}" >/dev/null - flags_helpStrLen_=${flags_output} - flags_columns_=`_flags_columns` - - if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then - echo "${flags_helpStr_}" >&2 - else - echo " ${flags_flagStr_} ${flags_help_}" >&2 - # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 - # because it doesn't like empty strings when used in this manner. - flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \ - |awk '{printf "%"length($0)-2"s", ""}'`" - flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}" - _flags_strlen "${flags_helpStr_}" >/dev/null - flags_helpStrLen_=${flags_output} - - if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \ - -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then - # indented to match help string - echo "${flags_helpStr_}" >&2 - else - # indented four from left to allow for longer defaults as long flag - # names might be used too, making things too long - echo " ${flags_defaultStr_}" >&2 - fi - fi - done - fi - - unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \ - flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \ - flags_columns_ flags_short_ flags_type_ flags_usName_ - return ${FLAGS_TRUE} -} - -# Reset shflags back to an uninitialized state. -# -# Args: -# none -# Returns: -# nothing -flags_reset() -{ - for flags_name_ in ${__flags_longNames}; do - flags_usName_=`_flags_underscoreName ${flags_name_}` - flags_strToEval_="unset FLAGS_${flags_usName_}" - for flags_type_ in \ - ${__FLAGS_INFO_DEFAULT} \ - ${__FLAGS_INFO_HELP} \ - ${__FLAGS_INFO_SHORT} \ - ${__FLAGS_INFO_TYPE} - do - flags_strToEval_=\ -"${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}" - done - eval ${flags_strToEval_} - done - - # Reset internal variables. - __flags_boolNames=' ' - __flags_longNames=' ' - __flags_shortNames=' ' - __flags_definedNames=' ' - - # Reset logging level back to default. - flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} - - unset flags_name_ flags_type_ flags_strToEval_ flags_usName_ -} - -# -# Initialization -# - -# Set the default logging level. -flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} +../shflags
\ No newline at end of file |