BASIS  r3148
shflags.sh
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file   shflags.sh
00003 # @author Kate Ward <kate.ward at forestent.com>, Andreas Schuh
00004 # @brief  Advanced command-line flag library for Unix shell scripts.
00005 #
00006 # @sa http://code.google.com/p/shflags/
00007 #
00008 # @note The shFlags implementation by Kate Ward (revision 147) has been
00009 #       considerably modified by Andreas Schuh as part of the BASIS project
00010 #       to fit the needs of the SBIA Group at The University of Pennsylvania.
00011 #
00012 # This module implements something like the google-gflags library available
00013 # from http://code.google.com/p/google-gflags/.
00014 #
00015 # FLAG TYPES: This is a list of the DEFINE_*'s that you can do.  All flags take
00016 # a name, default value, help-string, and optional 'short' name (one-letter
00017 # name).  Some flags have other arguments, which are described with the flag.
00018 #
00019 # - DEFINE_string: takes any input, and intreprets it as a string.
00020 #
00021 # - DEFINE_boolean: typically does not take any argument: say --myflag to set
00022 #   FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false.
00023 #   Alternatively, you can say
00024 #     --myflag=true  or --myflag=t or --myflag=0  or
00025 #     --myflag=false or --myflag=f or --myflag=1
00026 #   Passing an option has the same affect as passing the option once.
00027 #
00028 # - DEFINE_float: takes an input and intreprets it as a floating point number. As
00029 #   shell does not support floats per-se, the input is merely validated as
00030 #   being a valid floating point value.
00031 #
00032 # - DEFINE_integer: takes an input and intreprets it as an integer.
00033 #
00034 # - SPECIAL FLAGS: There are a few flags that have special meaning:
00035 #   --help (or -?)  prints a list of all the flags in a human-readable fashion
00036 #   --flagfile=foo  read flags from foo.  (not implemented yet)
00037 #   --              as in getopt(), terminates flag-processing
00038 #
00039 # EXAMPLE USAGE:
00040 #
00041 # Example script hello.sh(.in):
00042 # @code
00043 # #! /bin/sh
00044 # . ${BASIS_SOURCE} || exit 1
00045 #
00046 # DEFINE_string name 'world' "somebody's name" n
00047 #
00048 # FLAGS "$@" || exit $?
00049 # eval set -- "${FLAGS_ARGV}"
00050 #
00051 # echo "Hello, ${FLAGS_name}."
00052 # @endcode
00053 #
00054 # Usage of example script hello.sh:
00055 # @code
00056 # $ ./hello.sh -n Kate
00057 # Hello, Kate.
00058 # @endcode
00059 #
00060 # CUSTOMIZABLE BEHAVIOR:
00061 #
00062 # A script can override the default 'getopt' command by providing the path to
00063 # an alternate implementation by defining the FLAGS_GETOPT_CMD variable.
00064 #
00065 # ATTRIBUTES:
00066 #
00067 # Shared attributes:
00068 #   flags_error: last error message
00069 #   flags_return: last return value
00070 #
00071 #   __flags_longNames: list of long names for all flags
00072 #   __flags_shortNames: list of short names for all flags
00073 #   __flags_boolNames: list of boolean flag names
00074 #
00075 #   __flags_opts: options parsed by getopt
00076 #
00077 # Per-flag attributes:
00078 #   FLAGS_<flag_name>: contains value of flag named 'flag_name'
00079 #   __flags_<flag_name>_default: the default flag value
00080 #   __flags_<flag_name>_help: the flag help string
00081 #   __flags_<flag_name>_short: the flag short name
00082 #   __flags_<flag_name>_type: the flag type
00083 #   __flags_<flag_name>_category: category of flag, use special category
00084 #                                 'required' to denote flags that need to be
00085 #                                 given on the command line
00086 #
00087 # NOTES:
00088 #
00089 # - Not all systems include a getopt version that supports long flags. On these
00090 #   systems, only short flags are recognized.
00091 #
00092 # - Lists of strings are space separated, and a null value is the '~' char.
00093 #
00094 # Copyright (c) 2008, Kate Ward.<br />
00095 # Copyright (c) 2011, University of Pennsylvania.<br />
00096 # All Rights Reserved.
00097 #
00098 # Released under the LGPL (GNU Lesser General Public License)
00099 
00100 # return if FLAGS already loaded
00101 [ -n "${FLAGS_VERSION:-}" ] && return 0
00102 
00103 FLAGS_VERSION='1.0.4pre-basis'
00104 
00105 # ============================================================================
00106 # variables
00107 # ============================================================================
00108 
00109 # a user can set the path to a different getopt command by overriding this
00110 # variable in their script
00111 FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt}
00112 
00113 # return values that scripts can use
00114 FLAGS_TRUE=0
00115 FLAGS_FALSE=1
00116 FLAGS_ERROR=2
00117 
00118 # logging functions
00119 _flags_debug() { echo "flags:DEBUG $@" >&2; }
00120 _flags_warn() { echo "flags:WARN $@" >&2; }
00121 _flags_error() { echo "flags:ERROR $@" >&2; }
00122 _flags_fatal() { echo "flags:FATAL $@" >&2; exit ${FLAGS_ERROR}; }
00123 
00124 # specific shell checks
00125 if [ -n "${ZSH_VERSION:-}" ]; then
00126   setopt |grep "^shwordsplit$" >/dev/null
00127   if [ $? -ne ${FLAGS_TRUE} ]; then
00128     _flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
00129   fi
00130   if [ -z "${FLAGS_PARENT:-}" ]; then
00131     _flags_fatal "zsh does not pass \$0 through properly. please declare' \
00132 \"FLAGS_PARENT=\$0\" before calling shFlags"
00133   fi
00134 fi
00135 
00136 # ----------------------------------------------------------------------------
00137 # constants
00138 # ----------------------------------------------------------------------------
00139 
00140 # reserved flag names
00141 __FLAGS_RESERVED_LIST=' ARGC ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE '
00142 __FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION "
00143 
00144 # getopt version
00145 __FLAGS_GETOPT_VERS_STD=0
00146 __FLAGS_GETOPT_VERS_ENH=1
00147 __FLAGS_GETOPT_VERS_BSD=2
00148 
00149 ${FLAGS_GETOPT_CMD} >/dev/null 2>&1
00150 case $? in
00151   0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;;  # bsd getopt
00152   2)
00153     # TODO(kward): look into '-T' option to test the internal getopt() version
00154     if [ "`${FLAGS_GETOPT_CMD} --version`" = '-- ' ]; then
00155       __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD}
00156     else
00157       __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
00158     fi
00159     ;;
00160   *) _flags_fatal 'unable to determine getopt version' ;;
00161 esac
00162 
00163 # getopt optstring lengths
00164 __FLAGS_OPTSTR_SHORT=0
00165 __FLAGS_OPTSTR_LONG=1
00166 
00167 __FLAGS_NULL='~'
00168 
00169 # flag info strings
00170 __FLAGS_INFO_DEFAULT='default'
00171 __FLAGS_INFO_HELP='help'
00172 __FLAGS_INFO_SHORT='short'
00173 __FLAGS_INFO_TYPE='type'
00174 __FLAGS_INFO_CATEGORY='category'
00175 
00176 # flag lengths
00177 __FLAGS_LEN_SHORT=0
00178 __FLAGS_LEN_LONG=1
00179 
00180 # flag types
00181 __FLAGS_TYPE_NONE=0
00182 __FLAGS_TYPE_BOOLEAN=1
00183 __FLAGS_TYPE_FLOAT=2
00184 __FLAGS_TYPE_INTEGER=3
00185 __FLAGS_TYPE_STRING=4
00186 
00187 # flag multi-types, offset MUST be 128
00188 __FLAGS_TYPE_MULTI_BOOLEAN=`expr "${__FLAGS_TYPE_BOOLEAN}" + 128`
00189 __FLAGS_TYPE_MULTI_FLOAT=`expr   "${__FLAGS_TYPE_FLOAT}"   + 128`
00190 __FLAGS_TYPE_MULTI_INTEGER=`expr "${__FLAGS_TYPE_INTEGER}" + 128`
00191 __FLAGS_TYPE_MULTI_STRING=`expr  "${__FLAGS_TYPE_STRING}"  + 128`
00192 
00193 # set the constants readonly
00194 __flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'`
00195 for __flags_const in ${__flags_constants}; do
00196   # skip certain flags
00197   case ${__flags_const} in
00198     FLAGS_PARENT) continue ;;
00199   esac
00200   # set flag readonly
00201   if [ -z "${ZSH_VERSION:-}" ]; then
00202     readonly ${__flags_const}
00203   else  # handle zsh
00204     case ${ZSH_VERSION} in
00205       [123].*) readonly ${__flags_const} ;;
00206       *) readonly -g ${__flags_const} ;;  # declare readonly constants globally
00207     esac
00208   fi
00209 done
00210 unset __flags_const __flags_constants
00211 
00212 # ----------------------------------------------------------------------------
00213 # internal variables
00214 # ----------------------------------------------------------------------------
00215 
00216 # space separated lists
00217 __flags_boolNames=' '    # boolean flag names
00218 __flags_longNames=' '    # long flag names
00219 __flags_shortNames=' '   # short flag names
00220 __flags_definedNames=' ' # defined flag names (used for validation)
00221 
00222 # arrays
00223 __flags_categoryNames=() # flag category names
00224 
00225 # others
00226 __flags_columns='' # determined screen width in columns
00227 __flags_opts=''    # temporary storage for parsed getopt flags
00228 
00229 # ============================================================================
00230 # private functions
00231 # ============================================================================
00232 
00233 ##############################################################################
00234 # Define a flag.
00235 #
00236 # Calling this function will define the following info variables for the
00237 # specified flag:
00238 #   FLAGS_flagname - the name for this flag (based upon the long flag name)
00239 #   __flags_<flag_name>_default - the default value
00240 #   __flags_<flag_name>_help - the help string
00241 #   __flags_<flag_name>_short - the single letter alias
00242 #   __flags_<flag_name>_type - the type of flag (one of __FLAGS_TYPE_*)
00243 #   __flags_<flag_name>_category - the category of the flag
00244 #
00245 # Args:
00246 #   _flags_type: integer: internal type of flag (__FLAGS_TYPE_*)
00247 #   _flags_name: string: long flag name
00248 #   _flags_default: default flag value
00249 #   _flags_help: string: help string
00250 #   _flags_short: string: (optional) short flag name
00251 #   _flags_category: string: (optional) category name this flags belongs to
00252 # Returns:
00253 #   integer: success of operation, or error
00254 _flags_define()
00255 {
00256   if [ $# -lt 4 ]; then
00257     flags_error='DEFINE error: too few arguments'
00258     flags_return=${FLAGS_ERROR}
00259     _flags_error "${flags_error}"
00260     return ${flags_return}
00261   fi
00262 
00263   _flags_type_="$1"
00264   _flags_name_="$2"
00265   _flags_default_="$3"
00266   _flags_help_="$4"
00267   _flags_short_="${5:-${__FLAGS_NULL}}"
00268   _flags_category_="${6:-${__FLAGS_NULL}}"
00269 
00270   _flags_return_=${FLAGS_TRUE}
00271   _flags_usName_=`_flags_underscoreName ${_flags_name_}`
00272 
00273   # check whether the flag name is reserved
00274   _flags_itemInList ${_flags_usName_} "${__FLAGS_RESERVED_LIST}"
00275   if [ $? -eq ${FLAGS_TRUE} ]; then
00276     flags_error="flag name (${_flags_name_}) is reserved"
00277     _flags_return_=${FLAGS_ERROR}
00278   fi
00279 
00280   # require short option for getopt that don't support long options
00281   if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
00282       -a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \
00283       -a "${_flags_short_}" = "${__FLAGS_NULL}" ]
00284   then
00285     flags_error="short flag required for (${_flags_name_}) on this platform"
00286     _flags_return_=${FLAGS_ERROR}
00287   fi
00288 
00289   # check for existing long name definition
00290   if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
00291     if _flags_itemInList ${_flags_usName_} ${__flags_definedNames}; then
00292       flags_error="definition for ([no]${_flags_name_}) already exists"
00293       _flags_warn "${flags_error}"
00294       _flags_return_=${FLAGS_FALSE}
00295     fi
00296   fi
00297 
00298   # check for existing short name definition
00299   if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
00300       -a "${_flags_short_}" != "${__FLAGS_NULL}" ]
00301   then
00302     if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then
00303       flags_error="flag short name (${_flags_short_}) already defined"
00304       _flags_warn "${flags_error}"
00305       _flags_return_=${FLAGS_FALSE}
00306     fi
00307   fi
00308 
00309   # convert array given as string such as "'a 1' 'b 2' 'c' 'd 4'" to array
00310   # ('a 1' 'b 2' 'c' 'd 4') and get type of values for multi-flags
00311   if [ ${_flags_type_} -gt 128 -a ${_flags_type_} -ne ${__FLAGS_TYPE_MULTI_BOOLEAN} ]; then
00312     _flags_valueType_=`expr "${_flags_type_}" - 128`
00313     eval "_flags_default_=(${_flags_default_})"
00314   else
00315     if [ ${#_flags_default_[@]} -ne 1 ]; then
00316       flags_error="${_flags_name_}: invalid default flag value '${_flags_default_}'"
00317       _flags_return_=${FLAGS_ERROR}
00318     fi
00319     _flags_valueType_=${_flags_type_}
00320   fi
00321 
00322   # handle default value. note, on several occasions the 'if' portion of an
00323   # if/then/else contains just a ':' which does nothing. a binary reversal via
00324   # '!' is not done because it does not work on all shells.
00325   if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
00326     case ${_flags_type_} in
00327       ${__FLAGS_TYPE_BOOLEAN})
00328         if _flags_validateBoolean "${_flags_default_}"; then
00329           case ${_flags_default_} in
00330             true|t|0) _flags_default_=${FLAGS_TRUE} ;;
00331             false|f|1) _flags_default_=${FLAGS_FALSE} ;;
00332           esac
00333         else
00334           flags_error="${_flags_name_}: invalid default flag value '${_flags_default_}'"
00335           _flags_return_=${FLAGS_ERROR}
00336         fi
00337         ;;
00338 
00339       ${__FLAGS_TYPE_MULTI_BOOLEAN})
00340         if _flags_validateInteger "${_flags_default_}"; then
00341           :
00342         else
00343           flags_error="${_flags_name_}: invalid default flag value '${_flags_default_}'"
00344           _flags_return_=${FLAGS_ERROR}
00345         fi
00346         ;;
00347 
00348       *)
00349         for _flags_defaultValue_ in "${_flags_default_[@]}"; do
00350           case ${_flags_valueType_} in
00351             ${__FLAGS_TYPE_FLOAT})
00352               if _flags_validateFloat "${_flags_defaultValue_}"; then
00353                 :
00354               else
00355                 flags_error="${_flags_name_}: invalid default flag value '${_flags_defaultValue_}'"
00356                 _flags_return_=${FLAGS_ERROR}
00357               fi
00358               ;;
00359 
00360             ${__FLAGS_TYPE_INTEGER})
00361               if _flags_validateInteger "${_flags_defaultValue_}"; then
00362                 :
00363               else
00364                 flags_error="${_flags_name_}: invalid default flag value '${_flags_defaultValue_}'"
00365                 _flags_return_=${FLAGS_ERROR}
00366               fi
00367               ;;
00368 
00369             ${__FLAGS_TYPE_STRING}) ;;  # everything in shell is a valid string
00370 
00371             *)
00372               flags_error="${_flags_name_}: unrecognized flag type '${_flags_type_}'"
00373               _flags_return_=${FLAGS_ERROR}
00374               ;;
00375           esac
00376         done
00377         ;;
00378     esac
00379   fi
00380 
00381   if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
00382     # store flag information
00383     if [ ${_flags_type_} -gt 128 ]; then
00384       eval "FLAGS_${_flags_usName_}=(\"\${_flags_default_[@]}\")"
00385       eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=(\"\${_flags_default_[@]}\")"
00386     else
00387       eval "FLAGS_${_flags_usName_}='${_flags_default_}'"
00388       eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}='${_flags_default_}'"
00389     fi
00390     eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}"
00391     eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\""
00392     eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'"
00393     eval "__flags_${_flags_usName_}_${__FLAGS_INFO_CATEGORY}='${_flags_category_}'"
00394 
00395     # append flag names to name lists
00396     __flags_shortNames="${__flags_shortNames}${_flags_short_} "
00397     __flags_longNames="${__flags_longNames}${_flags_name_} "
00398     [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} -o \
00399       ${_flags_type_} -eq ${__FLAGS_TYPE_MULTI_BOOLEAN} ] && \
00400         __flags_boolNames="${__flags_boolNames}no${_flags_name_} "
00401 
00402     # append flag names to defined names for later validation checks
00403     __flags_definedNames="${__flags_definedNames}${_flags_usName_} "
00404     [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
00405         __flags_definedNames="${__flags_definedNames}no${_flags_usName_} "
00406 
00407     # append category name to category names list
00408     if [ "${_flags_category_}" != "${__FLAGS_NULL}" ]; then
00409       _flags_found_=${FLAGS_FALSE}
00410       for _flags_categoryName_ in "${__flags_categoryNames[@]}"; do
00411         if [ "${_flags_categoryName_}" = "${_flags_category_}" ]; then
00412           _flags_found_=${FLAGS_TRUE}
00413           break
00414         fi
00415       done
00416       if [ ${_flags_found_} -eq ${FLAGS_FALSE} ]; then
00417         __flags_categoryNames[${#__flags_categoryNames[@]}]="${_flags_category_}"
00418       fi
00419     fi
00420   fi
00421 
00422   flags_return=${_flags_return_}
00423   unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \
00424       _flags_short_ _flags_type_ _flags_usName_ \
00425       _flags_category_ _flags_found_
00426   [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
00427   return ${flags_return}
00428 }
00429 
00430 ##############################################################################
00431 # Return valid getopt options using currently defined list of long options.
00432 #
00433 # This function builds a proper getopt option string for short (and long)
00434 # options, using the current list of long options for reference.
00435 #
00436 # Args:
00437 #   _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*)
00438 # Output:
00439 #   string: generated option string for getopt
00440 # Returns:
00441 #   boolean: success of operation (always returns True)
00442 _flags_genOptStr()
00443 {
00444   _flags_optStrType_=$1
00445 
00446   _flags_opts_=''
00447 
00448   for _flags_name_ in ${__flags_longNames}; do
00449     _flags_usName_=`_flags_underscoreName ${_flags_name_}`
00450     _flags_type_=`_flags_getFlagInfo ${_flags_usName_} ${__FLAGS_INFO_TYPE}`
00451     [ $? -eq ${FLAGS_TRUE} ] || _flags_fatal 'call to _flags_type_ failed'
00452     case ${_flags_optStrType_} in
00453       ${__FLAGS_OPTSTR_SHORT})
00454         _flags_shortName_=`_flags_getFlagInfo \
00455             ${_flags_usName_} ${__FLAGS_INFO_SHORT}`
00456         if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then
00457           _flags_opts_="${_flags_opts_}${_flags_shortName_}"
00458           # getopt needs a trailing ':' to indicate a required argument
00459           [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} -a \
00460             ${_flags_type_} -ne ${__FLAGS_TYPE_MULTI_BOOLEAN} ] && \
00461               _flags_opts_="${_flags_opts_}:"
00462         fi
00463         ;;
00464 
00465       ${__FLAGS_OPTSTR_LONG})
00466         _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_name_}"
00467         # getopt needs a trailing ':' to indicate a required argument
00468         [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} -a \
00469           ${_flags_type_} -ne ${__FLAGS_TYPE_MULTI_BOOLEAN} ] && \
00470             _flags_opts_="${_flags_opts_}:"
00471         ;;
00472     esac
00473   done
00474 
00475   echo "${_flags_opts_}"
00476   unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \
00477       _flags_type_ _flags_usName_
00478   return ${FLAGS_TRUE}
00479 }
00480 
00481 ##############################################################################
00482 # Returns flag details based on a flag name and flag info.
00483 #
00484 # Args:
00485 #   string: underscored flag name
00486 #   string: flag info (see the _flags_define function for valid info types)
00487 # Output:
00488 #   string: value of dereferenced flag variable
00489 # Returns:
00490 #   integer: one of FLAGS_{TRUE|FALSE|ERROR}
00491 _flags_getFlagInfo()
00492 {
00493   # note: adding gFI to variable names to prevent naming conflicts with calling
00494   # functions
00495   _flags_gFI_usName_=$1
00496   _flags_gFI_info_=$2
00497 
00498   _flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}"
00499   _flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\""
00500   eval "${_flags_strToEval_}"
00501   if [ -n "${_flags_infoValue_}" ]; then
00502     flags_return=${FLAGS_TRUE}
00503   else
00504     # see if the _flags_gFI_usName_ variable is a string as strings can be
00505     # empty...
00506     # note: the DRY principle would say to have this function call itself for
00507     # the next three lines, but doing so results in an infinite loop as an
00508     # invalid _flags_name_ will also not have the associated _type variable.
00509     # Because it doesn't (it will evaluate to an empty string) the logic will
00510     # try to find the _type variable of the _type variable, and so on. Not so
00511     # good ;-)
00512     _flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}"
00513     _flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\""
00514     eval "${_flags_strToEval_}"
00515     if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" -o "${_flags_typeValue_}" -gt 128 ]; then
00516       flags_return=${FLAGS_TRUE}
00517     else
00518       flags_return=${FLAGS_ERROR}
00519       flags_error="missing flag info variable (${_flags_infoVar_})"
00520     fi
00521   fi
00522 
00523   echo "${_flags_infoValue_}"
00524   unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \
00525       _flags_strToEval_ _flags_typeValue_ _flags_typeVar_
00526   [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
00527   return ${flags_return}
00528 }
00529 
00530 ##############################################################################
00531 # Returns flag value based on a flag name.
00532 #
00533 # Args:
00534 #   unnamed: string: underscored flag name
00535 #   unnamed: string: name of the output variable
00536 # Output:
00537 #   sets the variable named by the second argument to the current value,
00538 #   which is an array in case of a multi-flag.
00539 # Returns:
00540 #   integer: one of FLAGS_{TRUE|FALSE|ERROR}
00541 _flags_getFlagValue()
00542 {
00543   _flags_gFV_usName_=$1
00544   _flags_gFV_type_=`_flags_getFlagInfo ${_flags_gFV_usName_} ${__FLAGS_INFO_TYPE}`
00545 
00546   if [ ${_flags_gFV_type_} -gt 128 ]; then
00547     eval "$2=(\"\${FLAGS_${_flags_gFV_usName_}[@]}\")"
00548   else
00549     eval "$2=\"\${FLAGS_${_flags_gFV_usName_}:-}\""
00550   fi
00551 
00552   unset _flags_gFV_usName_ _flags_gFV_type_
00553 
00554   return ${FLAGS_TRUE}
00555 }
00556 
00557 ##############################################################################
00558 # Returns flag default value based on a flag name.
00559 #
00560 # Args:
00561 #   unnamed: string: underscored flag name
00562 #   unnamed: string: name of the output variable
00563 # Output:
00564 #   sets the variable named by the second argument to the default value,
00565 #   which is an array in case of a multi-flag.
00566 # Returns:
00567 #   integer: one of FLAGS_{TRUE|FALSE|ERROR}
00568 _flags_getFlagDefault()
00569 {
00570   _flags_gFD_usName_=$1
00571   _flags_gFD_type_=`_flags_getFlagInfo ${_flags_gFD_usName_} ${__FLAGS_INFO_TYPE}`
00572 
00573   if [ ${_flags_gFD_type_} -gt 128 ]; then
00574     eval "$2=(\"\${__flags_${_flags_gFD_usName_}_${__FLAGS_INFO_DEFAULT}[@]}\")"
00575   else
00576     eval "$2=\"\${__flags_${_flags_gFD_usName_}_${__FLAGS_INFO_DEFAULT}:-}\""
00577   fi
00578 
00579   unset _flags_gFD_usName_ _flags_gFD_type_
00580 
00581   return ${FLAGS_TRUE}
00582 }
00583 
00584 # ----------------------------------------------------------------------------
00585 # helpers
00586 # ----------------------------------------------------------------------------
00587 
00588 ##############################################################################
00589 # Underscore a flag or category name by replacing dashes and whitespaces with underscores.
00590 #
00591 # Args:
00592 #   unnamed: string: long flag or category name
00593 # Output:
00594 #   string: underscored name
00595 _flags_underscoreName()
00596 {
00597   echo $1 | sed 's/[ -]/_/g'
00598 }
00599 
00600 ##############################################################################
00601 # Returns the width of the current screen.
00602 #
00603 # Output:
00604 #   integer: width in columns of the current screen.
00605 _flags_columns()
00606 {
00607   if [ -z "${__flags_columns}" ]; then
00608     # determine the value and store it
00609     if eval stty size >/dev/null 2>&1; then
00610       # stty size worked :-)
00611       set -- `stty size`
00612       __flags_columns=$2
00613     elif eval tput cols >/dev/null 2>&1; then
00614       set -- `tput cols`
00615       __flags_columns=$1
00616     else
00617       __flags_columns=80  # default terminal width
00618     fi
00619   fi
00620   echo ${__flags_columns}
00621 }
00622 
00623 ##############################################################################
00624 # Check for presense of item in a list.
00625 #
00626 # Passed a string (e.g. 'abc'), this function will determine if the string is
00627 # present in the list of strings (e.g.  ' foo bar abc ').
00628 #
00629 # Args:
00630 #   _flags_str_: string: string to search for in a list of strings
00631 #   unnamed: list: list of strings
00632 # Returns:
00633 #   boolean: true if item is in the list
00634 _flags_itemInList()
00635 {
00636   _flags_str_=$1
00637   shift
00638 
00639   echo " ${*:-} " |grep " ${_flags_str_} " >/dev/null
00640   if [ $? -eq 0 ]; then
00641     flags_return=${FLAGS_TRUE}
00642   else
00643     flags_return=${FLAGS_FALSE}
00644   fi
00645 
00646   unset _flags_str_
00647   return ${flags_return}
00648 }
00649 
00650 ##############################################################################
00651 # Sort space separated list.
00652 #
00653 # Args:
00654 #   @: list: space separated list of strings
00655 # Output:
00656 #   list: sorted space separated list of strings
00657 _flags_sortList()
00658 {
00659   echo "$@" | tr ' ' '\n' | sort | tr '\n' ' '
00660 }
00661 
00662 # ----------------------------------------------------------------------------
00663 # validators
00664 # ----------------------------------------------------------------------------
00665 
00666 ##############################################################################
00667 # Validate a boolean.
00668 #
00669 # Args:
00670 #   _flags__bool: boolean: value to validate
00671 # Returns:
00672 #   bool: true if the value is a valid boolean
00673 _flags_validateBoolean()
00674 {
00675   _flags_bool_=$1
00676 
00677   flags_return=${FLAGS_TRUE}
00678   case "${_flags_bool_}" in
00679     true|t|0) ;;
00680     false|f|1) ;;
00681     *) flags_return=${FLAGS_FALSE} ;;
00682   esac
00683 
00684   unset _flags_bool_
00685   return ${flags_return}
00686 }
00687 
00688 ##############################################################################
00689 # Validate a float.
00690 #
00691 # Args:
00692 #   _flags__float: float: value to validate
00693 # Returns:
00694 #   bool: true if the value is a valid float
00695 _flags_validateFloat()
00696 {
00697   _flags_float_=$1
00698 
00699   if _flags_validateInteger ${_flags_float_}; then
00700     flags_return=${FLAGS_TRUE}
00701   else
00702     flags_return=${FLAGS_TRUE}
00703     case ${_flags_float_} in
00704       -*)  # negative floats
00705         _flags_test_=`expr -- "${_flags_float_}" :\
00706             '\(-[0-9][0-9]*\.[0-9][0-9]*\)'`
00707         ;;
00708       *)  # positive floats
00709         _flags_test_=`expr -- "${_flags_float_}" :\
00710             '\([0-9][0-9]*\.[0-9][0-9]*\)'`
00711         ;;
00712     esac
00713     [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE}
00714   fi
00715 
00716   unset _flags_float_ _flags_test_
00717   return ${flags_return}
00718 }
00719 
00720 ##############################################################################
00721 # Validate an integer.
00722 #
00723 # Args:
00724 #   _flags__int_: interger: value to validate
00725 # Returns:
00726 #   bool: true if the value is a valid integer
00727 _flags_validateInteger()
00728 {
00729   _flags_int_=$1
00730 
00731   flags_return=${FLAGS_TRUE}
00732   case ${_flags_int_} in
00733     -*)  # negative ints
00734       _flags_test_=`expr -- "${_flags_int_}" : '\(-[0-9][0-9]*\)'`
00735       ;;
00736     *)  # positive ints
00737       _flags_test_=`expr -- "${_flags_int_}" : '\([0-9][0-9]*\)'`
00738       ;;
00739   esac
00740   [ "${_flags_test_}" != "${_flags_int_}" ] && flags_return=${FLAGS_FALSE}
00741 
00742   unset _flags_int_ _flags_test_
00743   return ${flags_return}
00744 }
00745 
00746 ##############################################################################
00747 # Validate an unsigned integer.
00748 #
00749 # Args:
00750 #   _flags__uint_: interger: value to validate
00751 # Returns:
00752 #   bool: true if the value is a valid unsigned integer
00753 _flags_validateUnsignedInteger()
00754 {
00755   _flags_uint_=$1
00756 
00757   flags_return=${FLAGS_TRUE}
00758   _flags_test_=`expr -- "${_flags_uint_}" : '\([0-9][0-9]*\)'`
00759   [ "${_flags_test_}" != "${_flags_uint_}" ] && flags_return=${FLAGS_FALSE}
00760 
00761   unset _flags_uint_ _flags_test_
00762   return ${flags_return}
00763 }
00764 
00765 # ----------------------------------------------------------------------------
00766 # helpers for command-line parsing
00767 # ----------------------------------------------------------------------------
00768 
00769 ##############################################################################
00770 # Parse command-line options using the standard getopt.
00771 #
00772 # Note: the flag options are passed around in the global __flags_opts so that
00773 # the formatting is not lost due to shell parsing and such.
00774 #
00775 # Args:
00776 #   @: varies: command-line options to parse
00777 # Returns:
00778 #   integer: a FLAGS success condition
00779 _flags_getoptStandard()
00780 {
00781   flags_return=${FLAGS_TRUE}
00782   _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
00783 
00784   # check for spaces in passed options
00785   for _flags_opt_ in "$@"; do
00786     # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
00787     _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'`
00788     if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then
00789       flags_error='the available getopt does not support spaces in options'
00790       flags_return=${FLAGS_ERROR}
00791       break
00792     fi
00793   done
00794 
00795   if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
00796     __flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1`
00797     _flags_rtrn_=$?
00798     if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
00799       _flags_warn "${__flags_opts}"
00800       flags_error='unable to parse provided options with getopt.'
00801       flags_return=${FLAGS_ERROR}
00802     fi
00803   fi
00804 
00805   unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_
00806   return ${flags_return}
00807 }
00808 
00809 ##############################################################################
00810 # Parse command-line options using the enhanced getopt.
00811 #
00812 # Note: the flag options are passed around in the global __flags_opts so that
00813 # the formatting is not lost due to shell parsing and such.
00814 #
00815 # Args:
00816 #   @: varies: command-line options to parse
00817 # Returns:
00818 #   integer: a FLAGS success condition
00819 _flags_getoptEnhanced()
00820 {
00821   flags_return=${FLAGS_TRUE}
00822   _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
00823   _flags_boolOpts_=`echo "${__flags_boolNames}" \
00824       |sed 's/^ *//;s/ *$//;s/ /,/g'`
00825   _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}`
00826 
00827   __flags_opts=`${FLAGS_GETOPT_CMD} \
00828       -o ${_flags_shortOpts_} \
00829       -l "${_flags_longOpts_},${_flags_boolOpts_}" \
00830       -- "$@" 2>&1`
00831   _flags_rtrn_=$?
00832   if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
00833     _flags_warn "${__flags_opts}"
00834     flags_error='unable to parse provided options with getopt.'
00835     flags_return=${FLAGS_ERROR}
00836   fi
00837 
00838   unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_
00839   return ${flags_return}
00840 }
00841 
00842 ##############################################################################
00843 # Dynamically parse a getopt result and set appropriate variables.
00844 #
00845 # This function does the actual conversion of getopt output and runs it through
00846 # the standard case structure for parsing. The case structure is actually quite
00847 # dynamic to support any number of flags.
00848 #
00849 # Args:
00850 #   argc: int: original command-line argument count
00851 #   @: varies: output from getopt parsing
00852 # Returns:
00853 #   integer: a FLAGS success condition
00854 _flags_parseGetopt()
00855 {
00856   _flags_argc_=$1
00857   shift
00858 
00859   flags_return=${FLAGS_TRUE}
00860 
00861   if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
00862     set -- $@
00863   else
00864     # note the quotes around the `$@' -- they are essential!
00865     eval set -- "$@"
00866   fi
00867 
00868   # provide user with number of arguments to shift by later
00869   # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not
00870   # properly give user access to non-flag arguments mixed in between flag
00871   # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only
00872   # for backwards compatibility reasons.
00873   FLAGS_ARGC=`expr $# - 1 - ${_flags_argc_}`
00874 
00875   # handle options. note options with values must do an additional shift
00876   while true; do
00877     _flags_opt_=$1
00878     _flags_arg_=${2:-}
00879     _flags_name_=''
00880 
00881     # determine long flag name
00882     case "${_flags_opt_}" in
00883       --) shift; break ;;  # discontinue option parsing
00884 
00885       --*)  # long option
00886         _flags_opt_=`expr -- "${_flags_opt_}" : '--\(.*\)'`
00887         _flags_len_=${__FLAGS_LEN_LONG}
00888         if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then
00889           _flags_name_=${_flags_opt_}
00890         else
00891           # check for negated long boolean version
00892           if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then
00893             _flags_name_=`expr -- "${_flags_opt_}" : 'no\(.*\)'`
00894             _flags_arg_=${__FLAGS_NULL}
00895           fi
00896         fi
00897         ;;
00898 
00899       -*)  # short option
00900         _flags_opt_=`expr -- "${_flags_opt_}" : '-\(.*\)'`
00901         _flags_len_=${__FLAGS_LEN_SHORT}
00902         if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then
00903           # yes. match short name to long name. note purposeful off-by-one
00904           # (too high) with awk calculations.
00905           _flags_pos_=`echo "${__flags_shortNames}" \
00906               |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
00907                   e=${_flags_opt_}`
00908           _flags_name_=`echo "${__flags_longNames}" \
00909               |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
00910         fi
00911         ;;
00912     esac
00913 
00914     # die if the flag was unrecognized
00915     if [ -z "${_flags_name_}" ]; then
00916       flags_error="unrecognized option (${_flags_opt_})"
00917       flags_return=${FLAGS_ERROR}
00918       break
00919     fi
00920 
00921     # set new flag value
00922     _flags_usName_=`_flags_underscoreName ${_flags_name_}`
00923     _flags_type_=`_flags_getFlagInfo "${_flags_usName_}" ${__FLAGS_INFO_TYPE}`
00924 
00925     case ${_flags_type_} in
00926       ${__FLAGS_TYPE_MULTI_BOOLEAN})
00927         eval "_flags_val_=\${FLAGS_${_flags_usName_}}"
00928         if [ ${_flags_len_} -eq ${__FLAGS_LEN_SHORT} -o \
00929              "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
00930           _flags_val_=`expr "${_flags_val_}" + 1`
00931         else
00932           _flags_val_=`expr "${_flags_val_}" - 1`
00933         fi
00934         eval "FLAGS_${_flags_usName_}=${_flags_val_}"
00935         ;;
00936 
00937       *)
00938         if [ ${_flags_type_} -ge 128 ]; then
00939           eval "_flags_idx_=\${#FLAGS_${_flags_usName_}[@]}"
00940           _flags_type_=`expr "${_flags_type_}" - 128`
00941         else
00942           _flags_idx_=0
00943         fi
00944         case ${_flags_type_} in
00945           ${__FLAGS_TYPE_BOOLEAN})
00946             if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
00947               if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
00948                 eval "FLAGS_${_flags_usName_}[${_flags_idx_}]=${FLAGS_TRUE}"
00949               else
00950                 eval "FLAGS_${_flags_usName_}[${_flags_idx_}]=${FLAGS_FALSE}"
00951               fi
00952             else
00953               _flags_strToEval_="_flags_val_=\${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}"
00954               eval "${_flags_strToEval_}"
00955               if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then
00956                 eval "FLAGS_${_flags_usName_}[${_flags_idx_}]=${FLAGS_TRUE}"
00957               else
00958                 eval "FLAGS_${_flags_usName_}[${_flags_idx_}]=${FLAGS_FALSE}"
00959               fi
00960             fi
00961             ;;
00962 
00963           ${__FLAGS_TYPE_FLOAT})
00964             if _flags_validateFloat "${_flags_arg_}"; then
00965               eval "FLAGS_${_flags_usName_}[${_flags_idx_}]='${_flags_arg_}'"
00966             else
00967               flags_error="${_flags_name_}: invalid float value (${_flags_arg_})"
00968               flags_return=${FLAGS_ERROR}
00969               break
00970             fi
00971             ;;
00972 
00973           ${__FLAGS_TYPE_INTEGER})
00974             if _flags_validateInteger "${_flags_arg_}"; then
00975               eval "FLAGS_${_flags_usName_}[${_flags_idx_}]='${_flags_arg_}'"
00976             else
00977               flags_error="${_flags_name_}: invalid integer value (${_flags_arg_})"
00978               flags_return=${FLAGS_ERROR}
00979               break
00980             fi
00981             ;;
00982 
00983           ${__FLAGS_TYPE_STRING})
00984             eval "FLAGS_${_flags_usName_}[${_flags_idx_}]='${_flags_arg_}'"
00985             ;;
00986         esac
00987         ;;
00988     esac
00989 
00990     # handle special case help flag
00991     if [ "${_flags_usName_}" = 'help' ]; then
00992       if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
00993         flags_help
00994         flags_error='help requested'
00995         flags_return=${FLAGS_TRUE}
00996         break
00997       fi
00998     fi
00999 
01000     # handle special case helpman flag
01001     if [ "${_flags_usName_}" = 'helpman' ]; then
01002       if [ ${FLAGS_helpman} -eq ${FLAGS_TRUE} ]; then
01003         flags_error='help requested'
01004         flags_return=${FLAGS_TRUE}
01005         # if man should not be executed dirtly,
01006         # print generated man page to STDOUT instead
01007         if [ -n "${FLAGS_execman}" ] && [ ${FLAGS_execman} -eq ${FLAGS_FALSE} ]; then
01008           flags_helpman
01009           break
01010         fi
01011         # save generated man page to temporary file
01012         flags_manFile_="`mktemp -t \"${0##*/}.1\"`"
01013         if [ $? -ne 0 ]; then
01014           flags_error='failed to create temporary man page file name'
01015           flags_return=${FLAGS_ERROR}
01016           break
01017         fi
01018         flags_man_="`flags_helpman`"
01019         if [ $? -ne ${FLAGS_TRUE} ]; then
01020           flags_error='failed to generate temporary man page file'
01021           flags_return=${FLAGS_ERROR}
01022           break
01023         fi
01024         echo "${flags_man_}" > "${flags_manFile_}"
01025         if [ $? -ne ${FLAGS_TRUE} ]; then
01026           flags_error='failed to write temporary man page file'
01027           flags_return=${FLAGS_ERROR}
01028           break
01029         fi
01030         # execute man to view the man page
01031         man "${flags_manFile_}"
01032         if [ $? -ne ${FLAGS_TRUE} ]; then
01033           flags_error='failed to execute man to view generated man page'
01034           flags_return=${FLAGS_ERROR}
01035         fi
01036         # remove temporary man page file
01037         rm -f "${flags_manFile_}"
01038         if [ ${flags_return} -ne ${FLAGS_ERROR} -a $? -ne ${FLAGS_TRUE} ]; then
01039           flags_error='failed to execute man to view generated man page'
01040           flags_return=${FLAGS_ERROR}
01041         fi
01042         break
01043       fi
01044     fi
01045 
01046     # handle special case helpxml flag
01047     if [ "${_flags_usName_}" = 'helpxml' ]; then
01048       if [ ${FLAGS_helpxml} -eq ${FLAGS_TRUE} ]; then
01049         flags_helpxml
01050         flags_error='help requested'
01051         flags_return=${FLAGS_TRUE}
01052         break
01053       fi
01054     fi
01055 
01056     # handle special case usage flag
01057     if [ "${_flags_usName_}" = 'helpshort' ]; then
01058       if [ ${FLAGS_helpshort} -eq ${FLAGS_TRUE} ]; then
01059         flags_helpshort
01060         flags_error='help requested'
01061         flags_return=${FLAGS_TRUE}
01062         break
01063       fi
01064     fi
01065 
01066     # handle special case version flag
01067     if [ "${_flags_usName_}" = 'version' ]; then
01068       if [ ${FLAGS_version} -eq ${FLAGS_TRUE} ]; then
01069         flags_version
01070         flags_error='version requested'
01071         flags_return=${FLAGS_TRUE}
01072         break
01073       fi
01074     fi
01075 
01076     # shift the option and non-boolean arguments out.
01077     shift
01078     [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} -a \
01079       ${_flags_type_} != ${__FLAGS_TYPE_MULTI_BOOLEAN} ] && shift
01080   done
01081 
01082   # give user back non-flag arguments
01083   FLAGS_ARGV=''
01084   while [ $# -gt 0 ]; do
01085     FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
01086     shift
01087   done
01088 
01089   unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \
01090       _flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_
01091   return ${flags_return}
01092 }
01093 
01094 # ----------------------------------------------------------------------------
01095 # helpers for help output
01096 # ----------------------------------------------------------------------------
01097 
01098 ##############################################################################
01099 # Convert type ID to type string.
01100 #
01101 # Args:
01102 #   _flags_type_: integer: type ID
01103 # Outputs:
01104 #   string: type string
01105 _flags_typeStr()
01106 {
01107   _flags_tS_type_=$1
01108 
01109   # type ID's of multi-flags have an offset of 128 (8th bit set)
01110   if [ ${_flags_tS_type_} -gt 128 ]; then
01111     _flags_tS_type_=`expr "${_flags_type__}" - 128`
01112     echo -n 'multi '
01113   fi
01114 
01115   # type string of value type
01116   case "${_flags_tS_type_}" in
01117     ${__FLAGS_TYPE_BOOLEAN}) echo -n 'bool'; ;;
01118     ${__FLAGS_TYPE_FLOAT})   echo -n 'float'; ;;
01119     ${__FLAGS_TYPE_INTEGER}) echo -n 'int'; ;;
01120     ${__FLAGS_TYPE_STRING})  echo -n 'string'; ;;
01121     *)                       echo -n 'unknown'; ;;
01122   esac
01123 
01124   unset _flags_tS_type_
01125 }
01126 
01127 ##############################################################################
01128 # Convert current value to string for help output.
01129 _flags_currentStr()
01130 {
01131   _flags_name__=$1
01132 
01133   # get flag info
01134   _flags_usName__=`_flags_underscoreName ${_flags_name__}`
01135   _flags_type__=`_flags_getFlagInfo "${_flags_usName__}" ${__FLAGS_INFO_TYPE}`
01136   _flags_getFlagValue "${_flags_usName__}" '_flags_current__'
01137 
01138   _flags_multi__=${FLAGS_FALSE}
01139   if [ ${_flags_type__} -eq ${__FLAGS_TYPE_MULTI_BOOLEAN} ]; then
01140     _flags_valueType__=${__FLAGS_TYPE_INTEGER}
01141   elif [ ${_flags_type__} -gt 128 ]; then
01142     _flags_valueType__=`expr "${_flags_type__}" - 128`
01143     _flags_multi__=${FLAGS_TRUE}
01144     echo -n '['
01145   else
01146     _flags_valueType__=${_flags_type__}
01147   fi
01148 
01149   _flags_separator__='' # set at end of first iteration
01150   for _flags_value__ in "${_flags_current__[@]}"; do
01151     echo -n "${_flags_separator__}"
01152     case ${_flags_valueType__} in
01153       ${__FLAGS_TYPE_BOOLEAN})
01154         if [ ${_flags_value__} -eq ${FLAGS_TRUE} ]; then
01155           echo -n 'true'
01156         else
01157           echo -n 'false'
01158         fi
01159         ;;
01160 
01161       ${__FLAGS_TYPE_STRING})
01162         echo -n "'${_flags_value__}'"
01163         ;;
01164 
01165       *)
01166         echo -n ${_flags_value__}
01167         ;;
01168     esac
01169     _flags_separator__=' '
01170   done
01171 
01172   if [ ${_flags_multi__} -eq ${FLAGS_TRUE} ]; then
01173     echo -n ']'
01174   fi
01175 
01176   unset _flags_name__ _flags_usName__ _flags_current__ _flags_type__ \
01177       _flags_valueType__ _flags_value__ _flags_multi__ _flags_separator__
01178 }
01179 
01180 ##############################################################################
01181 # Convert default value to string for help output.
01182 _flags_defaultStr()
01183 {
01184   _flags_dS_name_=$1
01185 
01186   # get flag info
01187   _flags_dS_usName_=`_flags_underscoreName ${_flags_dS_name_}`
01188   _flags_dS_type_=`_flags_getFlagInfo "${_flags_dS_usName_}" ${__FLAGS_INFO_TYPE}`
01189   _flags_getFlagDefault "${_flags_dS_usName_}" '_flags_dS_default_'
01190 
01191   _flags_dS_multi_=${FLAGS_FALSE}
01192   if [ ${_flags_dS_type_} -eq ${__FLAGS_TYPE_MULTI_BOOLEAN} ]; then
01193     _flags_dS_valueType_=${__FLAGS_TYPE_INTEGER}
01194   elif [ ${_flags_dS_type_} -gt 128 ]; then
01195     _flags_dS_valueType_=`expr "${_flags_dS_type_}" - 128`
01196     _flags_dS_multi_=${FLAGS_TRUE}
01197     echo -n '['
01198   else
01199     _flags_dS_valueType_=${_flags_dS_type_}
01200   fi
01201 
01202   _flags_dS_separator_='' # set at end of first iteration
01203   for _flags_dS_value_ in "${_flags_dS_default_[@]}"; do
01204     echo -n "${_flags_dS_separator_}"
01205     case ${_flags_dS_valueType_} in
01206       ${__FLAGS_TYPE_BOOLEAN})
01207         if [ ${_flags_dS_value_} -eq ${FLAGS_TRUE} ]; then
01208           echo -n 'true'
01209         else
01210           echo -n 'false'
01211         fi
01212         ;;
01213 
01214       ${__FLAGS_TYPE_STRING})
01215         echo -n "'${_flags_dS_value_}'"
01216         ;;
01217 
01218       *)
01219         echo -n ${_flags_dS_value_}
01220         ;;
01221     esac
01222     _flags_dS_separator_=' '
01223   done
01224 
01225   if [ ${_flags_dS_multi_} -eq ${FLAGS_TRUE} ]; then
01226     echo -n ']'
01227   fi
01228 
01229   unset _flags_dS_name_ _flags_dS_usName_ _flags_dS_default_ _flags_dS_type_ \
01230       _flags_dS_valueType_ _flags_dS_value_ _flags_dS_multi_ _flags_dS_separator_
01231 }
01232 
01233 ##############################################################################
01234 # Escape string for use in XML output.
01235 #
01236 # Args:
01237 #   unnamed: string: some string
01238 # Output:
01239 #   string: xml-escaped string
01240 _flags_xmlText()
01241 {
01242   echo -e "$1" | sed 's/\&/\&amp;/g;s/</\&lt;/g'
01243 }
01244 
01245 ##############################################################################
01246 # Escape string for use in man page output.
01247 #
01248 # Args:
01249 #   unnamed: string: some string
01250 # Output:
01251 #   string: man page-escaped string
01252 _flags_manText()
01253 {
01254   echo -e "$1" | sed 's/\\/\\\\/g;s/-/\\-/g'
01255 }
01256 
01257 ##############################################################################
01258 # Output short usage of named flag.
01259 #
01260 # Args:
01261 #   _flags_name_: string: long flag name
01262 # Outputs:
01263 #  string: usage of flag, e.g., "--someflag=<int>"
01264 _flags_flagusage()
01265 {
01266   _flags_name_=$1
01267 
01268   # get type of flag
01269   _flags_usName_=`_flags_underscoreName ${_flags_name_}`
01270   _flags_type_=`_flags_getFlagInfo "${_flags_usName_}" ${__FLAGS_INFO_TYPE}`
01271 
01272   # type ID's of multi-flags have an offset of 128 (8th bit set)
01273   if [ ${_flags_type_} -ge 128 ]; then
01274     _flags_multi_=${FLAGS_TRUE}
01275     _flags_type_=`expr "${_flags_type_}" - 128`
01276   else
01277     _flags_multi_=${FLAGS_FALSE}
01278   fi
01279 
01280   # value type
01281   case ${_flags_type_} in
01282     ${__FLAGS_TYPE_BOOLEAN})
01283       echo -n "--[no]${_flags_name_}"
01284       ;;
01285 
01286     *)
01287       echo -n "--${_flags_name_}=<`_flags_typeStr ${_flags_type_}`>"
01288       ;;
01289   esac
01290 
01291   # append '...' if it's a multi-flag
01292   if [ ${_flags_multi_} -eq ${FLAGS_TRUE} ]; then
01293     echo -n '...'
01294   fi
01295 
01296   unset _flags_name_ _flags_usName_ _flags_type_ _flags_multi_
01297 }
01298 
01299 ##############################################################################
01300 # Output short usage of named flag in man page format.
01301 #
01302 # Args:
01303 #   _flags_name_: string: long flag name
01304 # Outputs:
01305 #  string: usage of flag, e.g., "--someflag=<int>"
01306 _flags_helpman_flagusage()
01307 {
01308   _flags_name_=$1
01309 
01310   # get type of flag
01311   _flags_usName_=`_flags_underscoreName ${_flags_name_}`
01312   _flags_type_=`_flags_getFlagInfo "${_flags_usName_}" ${__FLAGS_INFO_TYPE}`
01313 
01314   # type ID's of multi-flags have an offset of 128 (8th bit set)
01315   if [ ${_flags_type_} -ge 128 ]; then
01316     _flags_multi_=${FLAGS_TRUE}
01317     _flags_type_=`expr "${_flags_type_}" - 128`
01318   else
01319     _flags_multi_=${FLAGS_FALSE}
01320   fi
01321 
01322   # value type
01323   case ${_flags_type_} in
01324     ${__FLAGS_TYPE_BOOLEAN})
01325       echo -n "\fB--[no]${_flags_name_}\fR"
01326       ;;
01327 
01328     *)
01329       echo -n "\fB--${_flags_name_}\fR=<\fI`_flags_typeStr ${_flags_type_}`\fR>"
01330       ;;
01331   esac
01332 
01333   # append '...' if it's a multi-flag
01334   if [ ${_flags_multi_} -eq ${FLAGS_TRUE} ]; then
01335     echo -n '...'
01336   fi
01337 
01338   unset _flags_name_ _flags_usName_ _flags_type_ _flags_multi_
01339 }
01340 
01341 # ============================================================================
01342 # public functions
01343 # ============================================================================
01344 
01345 # ----------------------------------------------------------------------------
01346 # flag definition
01347 # ----------------------------------------------------------------------------
01348 
01349 # A basic boolean flag. Boolean flags do not take any arguments, and their
01350 # value is either 1 (false) or 0 (true). For long flags, the false value is
01351 # specified on the command line by prepending the word 'no'. With short flags,
01352 # the presense of the flag toggles the current value between true and false.
01353 # Specifying a short boolean flag twice on the command results in returning the
01354 # value back to the default value.
01355 #
01356 # A default value is required for boolean flags.
01357 #
01358 # For example, lets say a Boolean flag was created whose long name was 'update'
01359 # and whose short name was 'x', and the default value was 'false'. This flag
01360 # could be explicitly set to 'true' with '--update' or by '-x', and it could be
01361 # explicitly set to 'false' with '--noupdate'.
01362 DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }
01363 DEFINE_bool()    { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }
01364 
01365 # Other basic flags.
01366 DEFINE_float()   { _flags_define ${__FLAGS_TYPE_FLOAT}   "$@"; }
01367 DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
01368 DEFINE_int()     { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
01369 DEFINE_string()  { _flags_define ${__FLAGS_TYPE_STRING}  "$@"; }
01370 
01371 # A multi boolean flag. Such flag can be given multiple times and instead of
01372 # representing a list of boolean values, this flag's value is a counter which
01373 # is incremented for every boolean flag value that is 'true' and decremented
01374 # otherwise. Note that the value of the counter may hence also be negative.
01375 #
01376 # An example use case of this flag is the --verbose flag. The more often this
01377 # flag was given, the more verbose the output messages should be.
01378 DEFINE_multi_boolean() { _flags_define ${__FLAGS_TYPE_MULTI_BOOLEAN} "$@"; }
01379 DEFINE_multi_bool()    { _flags_define ${__FLAGS_TYPE_MULTI_BOOLEAN} "$@"; }
01380 
01381 # Other multi-flags, i.e., flags that may be given multiple times
01382 DEFINE_multi_float()   { _flags_define ${__FLAGS_TYPE_MULTI_FLOAT}   "$@"; }
01383 DEFINE_multi_integer() { _flags_define ${__FLAGS_TYPE_MULTI_INTEGER} "$@"; }
01384 DEFINE_multi_int()     { _flags_define ${__FLAGS_TYPE_MULTI_INTEGER} "$@"; }
01385 DEFINE_multi_string()  { _flags_define ${__FLAGS_TYPE_MULTI_STRING}  "$@"; }
01386 
01387 # ----------------------------------------------------------------------------
01388 # command-line parsing
01389 # ----------------------------------------------------------------------------
01390 
01391 ##############################################################################
01392 # Parse the flags.
01393 #
01394 # Args:
01395 #   unnamed: list: command-line flags to parse
01396 # Returns:
01397 #   integer: success of operation, or error
01398 FLAGS()
01399 {
01400   # define standard flags if not already defined
01401   [ -z "${__flags_help_type:-}" ] && \
01402       DEFINE_boolean 'help' false 'Show help and exit.' 'h' 'help'
01403   [ -z "${__flags_helpman_type:-}" -a ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ] && \
01404       DEFINE_boolean 'helpman' false 'Show help as man page and exit. If --execman is true (the default),
01405                                       a temporary man page file is written and displayed using man.
01406                                       Otherwise, if --noexecman was given before, the generated man
01407                                       page is printed to stdout instead.' \
01408           "${__FLAGS_NULL}" 'help'
01409   [ -z "${__flags_execman_type:-}" -a ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ] && \
01410       DEFINE_boolean 'execman' true 'Execute man to view generated man page. See --helpman.' \
01411           "${__FLAGS_NULL}" 'help'
01412   [ -z "${__flags_helpxml_type:-}" -a ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ] && \
01413       DEFINE_boolean 'helpxml' false 'Output help in XML format and exit.' "${__FLAGS_NULL}" 'help'
01414   [ -z "${__flags_helpshort_type:-}" -a ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ] && \
01415       DEFINE_boolean 'helpshort' false 'Show usage information and exit.' "${__FLAGS_NULL}" 'help'
01416   [ -z "${__flags_version_type:-}" ] && \
01417       DEFINE_boolean 'version' false 'Show version and exit.' "${__FLAGS_NULL}" 'help'
01418   [ -z "${__flags_verbose_type:-}" ] && \
01419       DEFINE_multi_boolean 'verbose' 0 'Increase verbosity of output messages.
01420                                         Can be given multiple times.' 'v' 'help'
01421 
01422   # parse options
01423   if [ $# -gt 0 ]; then
01424     if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
01425       _flags_getoptStandard "$@"
01426     else
01427       _flags_getoptEnhanced "$@"
01428     fi
01429     flags_return=$?
01430   else
01431     # nothing passed; won't bother running getopt
01432     __flags_opts='--'
01433     flags_return=${FLAGS_TRUE}
01434   fi
01435 
01436   if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
01437     _flags_parseGetopt $# "${__flags_opts}"
01438     flags_return=$?
01439   fi
01440 
01441   [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}"
01442   [[ ${flags_error} = 'help requested'    ]] && exit 0
01443   [[ ${flags_error} = 'version requested' ]] && exit 0
01444   return ${flags_return}
01445 }
01446 
01447 # ----------------------------------------------------------------------------
01448 # getopt information
01449 # ----------------------------------------------------------------------------
01450 
01451 ##############################################################################
01452 # This is a helper function for determining the 'getopt' version for platforms
01453 # where the detection isn't working. It simply outputs debug information that
01454 # can be included in a bug report.
01455 #
01456 # Args:
01457 #   none
01458 # Output:
01459 #   debug info that can be included in a bug report
01460 # Returns:
01461 #   nothing
01462 flags_getoptInfo()
01463 {
01464   # platform info
01465   _flags_debug "uname -a: `uname -a`"
01466   _flags_debug "PATH: ${PATH}"
01467 
01468   # shell info
01469   if [ -n "${BASH_VERSION:-}" ]; then
01470     _flags_debug 'shell: bash'
01471     _flags_debug "BASH_VERSION: ${BASH_VERSION}"
01472   elif [ -n "${ZSH_VERSION:-}" ]; then
01473     _flags_debug 'shell: zsh'
01474     _flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
01475   fi
01476 
01477   # getopt info
01478   ${FLAGS_GETOPT_CMD} >/dev/null
01479   _flags_getoptReturn=$?
01480   _flags_debug "getopt return: ${_flags_getoptReturn}"
01481   _flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`"
01482 
01483   unset _flags_getoptReturn
01484 }
01485 
01486 ##############################################################################
01487 # Returns whether the detected getopt version is the enhanced version.
01488 #
01489 # Args:
01490 #   none
01491 # Output:
01492 #   none
01493 # Returns:
01494 #   bool: true if getopt is the enhanced version
01495 flags_getoptIsEnh()
01496 {
01497   test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH}
01498 }
01499 
01500 ##############################################################################
01501 # Returns whether the detected getopt version is the standard version.
01502 #
01503 # Args:
01504 #   none
01505 # Returns:
01506 #   bool: true if getopt is the standard version
01507 flags_getoptIsStd()
01508 {
01509   test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD}
01510 }
01511 
01512 # ----------------------------------------------------------------------------
01513 # help and usage information
01514 # ----------------------------------------------------------------------------
01515 
01516 ##############################################################################
01517 # Prints usage as in synopsis section of man pages.
01518 flags_usage()
01519 {
01520   flags_requiredFlags_=' '
01521   flags_optionalFlags_=' '
01522   for flags_name_ in ${__flags_longNames}; do
01523     flags_usName_=`_flags_underscoreName ${flags_name_}`
01524     flags_category_=`_flags_getFlagInfo "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
01525     if [ "${flags_category_}" = 'required' ]; then
01526       flags_requiredFlags_="${flags_requiredFlags_}${flags_name_} "
01527     elif [ "${flags_category_}" != 'help' ]; then
01528       flags_optionalFlags_="${flags_optionalFlags_}${flags_name_} "
01529     fi
01530   done
01531 
01532   flags_command_=${HELP_COMMAND:-${0##*/}}       # actual command name (constant)
01533   flags_executable_="${FLAGS_PARENT:-${0##*/}}"  # name of executable (may differ)
01534 
01535   flags_usage_=''
01536   if [ -n "${flags_optionalFlags_}" ]; then
01537     for flags_name_ in ${flags_optionalFlags_}; do
01538       flags_usage_="${flags_usage_} [`_flags_flagusage ${flags_name_}`]"
01539     done
01540   fi
01541   if [ -n "${flags_requiredFlags_}" ]; then
01542     for flags_name_ in ${flags_requiredFlags_}; do
01543       flags_usage_="${flags_usage_} `_flags_flagusage ${flags_name_}`"
01544     done
01545   fi
01546   flags_usage_="${flags_usage_} [args]"
01547 
01548   echo "NAME"
01549   # use first sentence of description as brief description similar to Doxygen
01550   if [ -n "${HELP_DESCRIPTION}" ]; then
01551     flags_brief_=${HELP_DESCRIPTION%%.*}
01552     flags_brief_="$(echo "${flags_brief_}"|sed 's/^\ *//g;s/\ *$//g'|tr '\n' ' ')"
01553     flags_brief_="     ${flags_command_} -- ${flags_brief_}"
01554     flags_columns_=`_flags_columns`
01555     flags_columns_=`expr -- "${flags_columns_}" - 3`
01556     if [ `expr -- "${flags_brief_}" : '.*'` -gt ${flags_columns_} ]; then
01557       flags_brief_="${flags_brief_:0:${flags_columns_}}"
01558       flags_brief_="${flags_brief_% *}..."
01559     fi
01560     echo "${flags_brief_}"
01561   else
01562     echo "     ${flags_command_}"
01563   fi
01564   echo
01565   echo "SYNOPSIS"
01566   # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
01567   # because it doesn't like empty strings when used in this manner.
01568   flags_emptyStr_="`echo \"x${flags_executable_}x\" \
01569       |awk '{printf "%"length($0)+3"s", ""}'`"
01570   flags_emptyStrLen_=`expr -- "${flags_emptyStr_}" : '.*'`
01571   flags_usage_="$(echo "${flags_emptyStr_}${flags_usage_}" | fmt -l 0 -$(_flags_columns))"
01572   flags_usage_="     ${flags_executable_}${flags_usage_:${flags_emptyStrLen_}}"
01573   echo "${flags_usage_}"
01574 
01575   unset flags_name_ flags_command_ flags_usage_ flags_brief_ flags_usName_ \
01576       flags_executable_ flags_type_ flags_optionalFlags_ flags_requiredFlags_ \
01577       flags_standardFlags_ flags_emptyStr_ flags_emptyStrLen_ flags_columns_
01578 
01579   return ${FLAGS_TRUE}
01580 }
01581 
01582 ##############################################################################
01583 # Print help for named flag.
01584 #
01585 # Args:
01586 #   flags_name_: string: long name of flag
01587 #   flags_maxNameLen: integer: (optional) maximum length of long flag names
01588 #                              used to align help texts (default: 0)
01589 #   flags_showDefault: boolean: (optional) whether to display default value (default: true)
01590 # Returns:
01591 #   integer: success of operation (always returns true)
01592 flags_helpflag()
01593 {
01594   flags_name_=$1
01595   flags_maxNameLen=${2:-0}
01596   flags_showDefault_=${3:-${FLAGS_TRUE}}
01597   flags_flagStr_=''
01598   flags_boolStr_=''
01599   flags_usName_=`_flags_underscoreName ${flags_name_}`
01600 
01601   flags_help_=`_flags_getFlagInfo \
01602       "${flags_usName_}" ${__FLAGS_INFO_HELP}`
01603   flags_short_=`_flags_getFlagInfo \
01604       "${flags_usName_}" ${__FLAGS_INFO_SHORT}`
01605   flags_type_=`_flags_getFlagInfo \
01606       "${flags_usName_}" ${__FLAGS_INFO_TYPE}`
01607   flags_category_=`_flags_getFlagInfo \
01608       "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
01609 
01610   flags_help_=$(echo "${flags_help_}"|sed 's/^\ *//g'|tr '\n' ' ')
01611 
01612   if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
01613     # add [no] to long boolean flag names, except the 'help' flags
01614     [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
01615         flags_boolStr_='[no]'
01616     # long flag name
01617     flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}"
01618   fi
01619   # short flag name
01620   [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
01621       flags_flagStr_="${flags_flagStr_}, -${flags_short_}"
01622   # fill with spaces for alignment of help texts
01623   flags_flagStrLen_=`expr -- "${flags_flagStr_}" : '.*'`
01624   flags_numSpaces_=`expr -- 12 + "${flags_maxNameLen_}" - "${flags_flagStrLen_}"`
01625   [ ${flags_numSpaces_} -ge 0 ] || flags_numSpaces_=0
01626   flags_spaces_=`printf %${flags_numSpaces_}s`
01627   flags_flagStr_="${flags_flagStr_}${flags_spaces_}"
01628   # default value
01629   flags_defaultStr_="(default: `_flags_defaultStr ${flags_name_}`)"
01630   # help text
01631   flags_helpStr_="  ${flags_flagStr_}   ${flags_help_}"
01632   if [ ${flags_showDefault_} -eq ${FLAGS_TRUE} ]; then
01633     flags_helpStr_="${flags_helpStr_} ${flags_defaultStr_}"
01634   fi
01635   if [ ${flags_showDefault_} -eq ${FLAGS_TRUE} ]; then
01636     flags_helpStr_="${flags_help_} ${flags_defaultStr_}"
01637   else
01638     flags_helpStr_="${flags_help_}"
01639   fi
01640   flags_helpStrLen_=`expr -- "${flags_helpStr_}" : '.*'`
01641   flags_columns_=`_flags_columns`
01642   # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
01643   # because it doesn't like empty strings when used in this manner.
01644   flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
01645       |awk '{printf "%"length($0)+6"s", ""}'`"
01646   flags_emptyStrLen_=`expr -- "${flags_emptyStr_}" : '.*'`
01647   # split long help text on multiple lines
01648   flags_helpStr_="$(echo "${flags_emptyStr_}${flags_helpStr_}" | fmt -l 0 -${flags_columns_})"
01649   flags_helpStr_="     ${flags_flagStr_}   ${flags_helpStr_:${flags_emptyStrLen_}}"
01650   echo "${flags_helpStr_}"
01651 
01652   unset flags_boolStr_ flags_defaultStr_ flags_emptyStr_ flags_emptyStrLen_ \
01653       flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \
01654       flags_columns_ flags_short_ flags_type_ flags_usName_ flags_flagStrLen_
01655 
01656   return ${FLAGS_TRUE}
01657 }
01658 
01659 ##############################################################################
01660 # Print help of all flags.
01661 #
01662 # This function is used by flags_help() and flags_helpshort().
01663 #
01664 # Args:
01665 #   flags_helpshort_: bool: display only short help of options, leaving out
01666 #                           less important options
01667 # Returns:
01668 #   integer: success of operation (always returns true)
01669 flags_helpflags()
01670 {
01671   flags_helpshort_=${1:-${FLAGS_FALSE}}
01672 
01673   echo "OPTIONS"
01674 
01675   # reset (all) categories
01676   flags_maxNameLen_=0
01677   flags_otherFlags_=''
01678   for flags_category_ in "${__flags_categoryNames[@]}"; do
01679     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
01680     eval "flags_${flags_usCategory_}Flags_=''"
01681   done
01682 
01683   # get lists of flags belonging to each category and
01684   # maximum length of long names required for alignment of help
01685   for flags_name_ in ${__flags_longNames}; do
01686     flags_usName_=`_flags_underscoreName ${flags_name_}`
01687 
01688     # update maximum length of flag name
01689     flags_nameStrLen_=`expr -- "${flags_name_}" : '.*'`
01690     # length + 4 for boolean flags because of the '[no]' prefix
01691     flags_type_=`_flags_getFlagInfo "${flags_usName_}" ${__FLAGS_INFO_TYPE}`
01692     if [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ]; then
01693       flags_nameStrLen_=`expr -- "${flags_nameStrLen}" + 4`
01694     fi
01695     if [ ${flags_nameStrLen_} -gt ${flags_maxNameLen_} ]; then
01696       flags_maxNameLen_=${flags_nameStrLen_}
01697     fi
01698 
01699     # append flag to list for its category
01700     flags_category_=`_flags_getFlagInfo "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
01701     if [ "${flags_category_}" = "${__FLAGS_NULL}" ]; then
01702       flags_otherFlags_="${flags_otherFlags_} ${flags_name_}"
01703     else
01704       flags_usCategory_=`_flags_underscoreName ${flags_category_}`
01705       eval "flags_${flags_usCategory_}Flags_=\"\${flags_${flags_usCategory_}Flags_} ${flags_name_}\""
01706     fi
01707   done
01708 
01709   # select subset of categories to display
01710   if [ ${flags_helpshort_} -eq ${FLAGS_TRUE} ]; then
01711     flags_categories_=()
01712     for flags_category_ in "${__flags_categoryNames[@]}"; do
01713       if [ "${flags_category_}" = 'help' ]; then
01714         flags_usCategory_=`_flags_underscoreName ${flags_category_}`
01715         eval "unset flags_${flags_usCategory_}Flags_"
01716         continue
01717       fi
01718       flags_categories_[${#flags_categories_[@]}]="${flags_category_}"
01719     done
01720   else
01721     flags_categories_=("${__flags_categoryNames[@]}")
01722   fi
01723 
01724   # output help of required flags
01725   if [ -n "${flags_requiredFlags_}" ]; then
01726     echo "     The required options are as follows:"
01727     echo
01728     flags_requiredFlags_=`_flags_sortList "${flags_requiredFlags_}"`
01729     for flags_name_ in ${flags_requiredFlags_}; do
01730       flags_helpflag ${flags_name_} ${flags_maxNameLen_} ${FLAGS_FALSE}
01731     done
01732     echo
01733   fi
01734 
01735   # output help of non-required and non-help flags
01736   for flags_category_ in "${flags_categories_[@]}"; do
01737     if [ "${flags_category_}" = 'required' -o \
01738          "${flags_category_}" = 'help' ]; then
01739       continue
01740     fi
01741     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
01742     eval "flags_${flags_usCategory_}Flags_=\`_flags_sortList \"\${flags_${flags_usCategory_}Flags_}\"\`"
01743     eval "flags_names_=\"\${flags_${flags_usCategory_}Flags_}\""
01744     if [ -n "${flags_names_}" ]; then
01745       echo "     The ${flags_category_} options are as follows:"
01746       echo
01747       for flags_name_ in ${flags_names_}; do
01748         flags_helpflag ${flags_name_} ${flags_maxNameLen_} ${FLAGS_TRUE}
01749       done
01750       echo
01751     fi
01752   done
01753 
01754   # output help of remaining non-help flags
01755   if [ -n "${flags_otherFlags_}" ]; then
01756     echo "     The available options are as follows:"
01757     echo
01758     flags_otherFlags_=`_flags_sortList "${flags_otherFlags_}"`
01759     for flags_name_ in ${flags_otherFlags_}; do
01760       flags_helpflag ${flags_name_} ${flags_maxNameLen_} ${FLAGS_TRUE}
01761     done
01762     echo
01763   fi
01764 
01765   # output help of help flags
01766   if [ -n "${flags_helpFlags_}" ]; then
01767     echo "     The help options are as follows:"
01768     echo
01769     for flags_name_ in ${flags_helpFlags_}; do
01770       flags_helpflag ${flags_name_} ${flags_maxNameLen_} ${FLAGS_FALSE}
01771     done
01772     echo
01773   fi
01774 
01775   # clean up
01776   for flags_category_ in "${flags_categories_[@]}"; do
01777     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
01778     eval "unset flags_${flags_usCategory_}Flags_"
01779   done
01780   unset flags_maxNameLen_ flags_name_ flags_nameStrLen_ flags_type_ \
01781       flags_otherFlags flags_categories_ flags_category_ flags_usCategory_
01782  
01783   return ${FLAGS_TRUE}
01784 }
01785 
01786 ##############################################################################
01787 # This is effectively a 'usage()' function. It prints a usage information on
01788 # how to use the program and the available flags. Note this function can be
01789 # overridden so other apps can define their own short help output,
01790 # replacing this one, if they want.
01791 #
01792 # Args:
01793 #   none
01794 # Returns:
01795 #   integer: success of operation (always returns true)
01796 flags_helpshort()
01797 {
01798   # head / usage
01799   echo
01800   flags_usage
01801   echo
01802   # flags
01803   flags_helpflags ${FLAGS_TRUE}
01804  
01805   return ${FLAGS_TRUE}
01806 }
01807 
01808 ##############################################################################
01809 # This is effectively a 'help()' function. It prints a program description together
01810 # with usage information and example command-lines on how to use the program.
01811 # Note this function can be overridden so other apps can define their own help
01812 # output, replacing this one, if they want.
01813 #
01814 # Args:
01815 #  none
01816 # Returns:
01817 #   integer: success of operation (always returns true)
01818 flags_help()
01819 {
01820   # head / usage
01821   echo
01822   flags_usage
01823   # description
01824   if [ -n "${HELP_DESCRIPTION:-}" ]; then
01825     echo
01826     echo "DESCRIPTION"
01827     flags_fmtStr_=$(echo "${HELP_DESCRIPTION}"\
01828         |awk '{printf "%s:NEWLINE:",$0}'\
01829         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:\ *$//g;s/:NEWLINE:/:NEWLINE:     /g;s/:NEWLINE:/\\n/g')
01830     flags_fmtStr_="$(echo -e "     ${flags_fmtStr_}" | fmt -l 0 -$(_flags_columns))"
01831     echo "${flags_fmtStr_}"
01832   fi
01833   # flags
01834   echo
01835   flags_helpflags ${FLAGS_FALSE} # attention: unsets flags_columns_
01836   # contact
01837   if [ -n "${HELP_CONTACT:-}" ]; then
01838     echo "CONTACT"
01839     flags_fmtStr_=$(echo "${HELP_CONTACT}"\
01840         |awk '{printf "%s:NEWLINE:",$0}'\
01841         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:$//g;s/:NEWLINE:/:NEWLINE:     /g;s/:NEWLINE:/\\n/g')
01842     flags_fmtStr_="$(echo "     ${flags_fmtStr_}" | fmt -l 0 -$(_flags_columns))"
01843     echo "${flags_fmtStr_}"
01844     echo
01845   fi
01846  
01847   unset flags_fmtStr_
01848 
01849   return ${FLAGS_TRUE}
01850 }
01851 
01852 # ----------------------------------------------------------------------------
01853 # XML help
01854 # ----------------------------------------------------------------------------
01855 
01856 ##############################################################################
01857 # This function outputs the help of named flag in XML format
01858 #
01859 # Args:
01860 #   flags_name_: string: long name of flag
01861 #   indentation: integer: (optional) indentation
01862 # Returns:
01863 #   integer: success of operation (always returns true)
01864 flags_helpflagxml()
01865 {
01866   # get flag attributes
01867   flags_name_=$1
01868   flags_indentation_=${2:-0}
01869   flags_usName_=`_flags_underscoreName ${flags_name_}`
01870 
01871   flags_help_=`_flags_getFlagInfo \
01872       "${flags_usName_}" ${__FLAGS_INFO_HELP}`
01873   flags_short_=`_flags_getFlagInfo \
01874       "${flags_usName_}" ${__FLAGS_INFO_SHORT}`
01875   flags_type_=`_flags_getFlagInfo \
01876       "${flags_usName_}" ${__FLAGS_INFO_TYPE}`
01877   flags_category_=`_flags_getFlagInfo \
01878       "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
01879 
01880   # re-format strings
01881   flags_help_=$(echo "${flags_help_}"|sed 's/^\ *//g'|tr '\n' ' '|sed 's/^\ *//g;s/\ *$//g')
01882 
01883   [ "${flags_short_}"    = "${__FLAGS_NULL}" ] && flags_short_=''
01884   [ "${flags_category_}" = "${__FLAGS_NULL}" ] && flags_category_=''
01885 
01886   # current and default value
01887   flags_current_=`_flags_currentStr ${flags_usName_}`
01888   flags_default_=`_flags_defaultStr ${flags_usName_}`
01889 
01890   # convert type
01891   flags_type_=`_flags_typeStr ${flags_type_}`
01892 
01893   # xml-escape values
01894   flags_short_=`_flags_xmlText "${flags_short_}"`
01895   flags_category_=`_flags_xmlText "${flags_category_}"`
01896   flags_help_=`_flags_xmlText "${flags_help_}"`
01897   flags_current_=`_flags_xmlText "${flags_current_}"`
01898   flags_default_=`_flags_xmlText "${flags_default_}"`
01899   flags_type_=`_flags_xmlText "${flags_type_}"`
01900 
01901   # indentation
01902   flags_emptyStr_=`printf %${flags_indentation_}s`
01903 
01904   # output XML tags
01905   echo "${flags_emptyStr_}<flag>"
01906   echo "${flags_emptyStr_}    <category>${flags_category_}</category>"
01907   echo "${flags_emptyStr_}    <name>${flags_name_}</name>"
01908   echo "${flags_emptyStr_}    <short_name>${flags_short_}</short_name>"
01909   echo "${flags_emptyStr_}    <meaning>${flags_help_}</meaning>"
01910   echo "${flags_emptyStr_}    <default>${flags_default_}</default>"
01911   echo "${flags_emptyStr_}    <current>${flags_current_}</current>"
01912   echo "${flags_emptyStr_}    <type>${flags_type_}</type>"
01913   echo "${flags_emptyStr_}</flag>"
01914 
01915   unset flags_current_ flags_default_ flags_name_ flags_usName_ \
01916       flags_short_ flags_type_ flags_help_ flags_indentation_ \
01917       flags_emptyStr_
01918 }
01919 
01920 ##############################################################################
01921 # This function outputs the help in XML format.
01922 #
01923 # Args:
01924 #   none
01925 # Returns:
01926 #   integer: success of operation (always returns true)
01927 flags_helpxml()
01928 {
01929   # get (re-formated) help strings
01930   flags_executable_=${FLAGS_PARENT:-${0##*/}}
01931   flags_command_=${HELP_COMMAND:-${flags_executable_}}
01932   flags_version_=${HELP_VERSION:-'unknown'}
01933   flags_copyright_=$(echo "${HELP_COPYRIGHT}"\
01934         |awk '{printf "%s:NEWLINE:",$0}'\
01935         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:\ *$//g;s/:NEWLINE:/\\n/g')
01936   flags_contact_=$(echo "${HELP_CONTACT}"\
01937         |awk '{printf "%s:NEWLINE:",$0}'\
01938         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:$//g;s/:NEWLINE:/\\n/g')
01939   flags_description_=$(echo "${HELP_DESCRIPTION}"\
01940         |awk '{printf "%s:NEWLINE:",$0}'\
01941         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:\ *$//g;s/:NEWLINE:/\\n/g')
01942 
01943   # xml-escape values
01944   flags_executable_=`_flags_xmlText "${flags_executable_}"`
01945   flags_command_=`_flags_xmlText "${flags_command_}"`
01946   flags_version_=`_flags_xmlText "${flags_version_}"`
01947   flags_copyright_=`_flags_xmlText "${flags_copyright_}"`
01948   flags_contact_=`_flags_xmlText "${flags_contact_}"`
01949   flags_description_=`_flags_xmlText "${flags_description_}"`
01950 
01951   # output XML tags
01952   echo "<?xml version=\"1.0\"?>"
01953   echo "<AllFlags>"
01954   echo "  <name>${flags_command_}</name>"
01955   echo "  <program>${flags_executable_}</program>"
01956   echo "  <version>${flags_version_}</version>"
01957   echo "  <copyright>${flags_copyright_}</copyright>"
01958   echo "  <contact>${flags_contact_}</contact>"
01959   echo "  <usage>${flags_description_}</usage>"
01960   for flags_name_ in ${__flags_longNames}; do
01961     flags_helpflagxml ${flags_name_} 2
01962   done
01963   echo "</AllFlags>"
01964 
01965   # clean up
01966   unset flags_executable_ flags_command_ flags_version_ \
01967       flags_name_ flags_description_ flags_copyright_ flags_contact_
01968 
01969   return ${FLAGS_TRUE}
01970 }
01971 
01972 # ----------------------------------------------------------------------------
01973 # man page
01974 # ----------------------------------------------------------------------------
01975 
01976 ##############################################################################
01977 # Prints NAME section of man page.
01978 flags_helpman_name()
01979 {
01980   flags_command_=${HELP_COMMAND:-${0##*/}}
01981   flags_command_=`_flags_manText "${flags_command_}"`
01982 
01983   echo ".SH NAME"
01984   # use first sentence of description as brief description similar to Doxygen
01985   if [ -n "${HELP_DESCRIPTION}" ]; then
01986     flags_brief_=${HELP_DESCRIPTION%%.*}
01987     flags_brief_="$(echo "${flags_brief_}"|sed 's/^\ *//g;s/\ *$//g'|tr '\n' ' ')"
01988     flags_brief_="${flags_command_} -- ${flags_brief_}"
01989     flags_columns_=`_flags_columns`
01990     flags_columns_=`expr -- "${flags_columns_}" - 24`
01991     [ ${flags_columns_} -lt 80 ] && flags_columns_=80
01992     if [ `expr -- "${flags_brief_}" : '.*'` -gt ${flags_columns_} ]; then
01993       flags_brief_="${flags_brief_:0:${flags_columns_}}"
01994       flags_brief_="${flags_brief_% *}..."
01995     fi
01996     flags_brief_=`_flags_manText "${flags_brief_}"`
01997     echo "${flags_brief_}"
01998   else
01999     echo "${flags_command_}"
02000   fi
02001 
02002   unset flags_command_ flags_brief_ flags_columns_
02003 
02004   return ${FLAGS_TRUE}
02005 }
02006 
02007 ##############################################################################
02008 # Prints SYNOPSIS section of man page.
02009 flags_helpman_synopsis()
02010 {
02011   flags_executable_="${FLAGS_PARENT:-${0##*/}}"
02012 
02013   echo ".SH SYNOPSIS"
02014   echo "\fB${flags_executable_}\fR"
02015 
02016   flags_requiredFlags_=' '
02017   flags_optionalFlags_=' '
02018   for flags_name_ in ${__flags_longNames}; do
02019     flags_usName_=`_flags_underscoreName ${flags_name_}`
02020     flags_category_=`_flags_getFlagInfo "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
02021     if [ "${flags_category_}" = 'required' ]; then
02022       flags_requiredFlags_="${flags_requiredFlags_}${flags_name_} "
02023     elif [ "${flags_category_}" != 'help' ]; then
02024       flags_optionalFlags_="${flags_optionalFlags_}${flags_name_} "
02025     fi
02026   done
02027 
02028   flags_requiredFlags_=`_flags_sortList "${flags_requiredFlags_}"`
02029   flags_optionalFlags_=`_flags_sortList "${flags_optionalFlags_}"`
02030 
02031   if [ -n "${flags_optionalFlags_}" ]; then
02032     for flags_name_ in ${flags_optionalFlags_}; do
02033       echo "[\fB`_flags_helpman_flagusage ${flags_name_}`\fR]"
02034     done
02035   fi
02036   if [ -n "${flags_requiredFlags_}" ]; then
02037     for flags_name_ in ${flags_requiredFlags_}; do
02038       echo "\fB`_flags_helpman_flagusage ${flags_name_}`\fR"
02039     done
02040   fi
02041   echo "[args]"
02042 
02043   unset flags_executable_ flags_name_ flags_usName_ flags_type_ \
02044       flags_optionalFlags_ flags_requiredFlags_
02045 
02046   return ${FLAGS_TRUE}
02047 }
02048 
02049 ##############################################################################
02050 # Prints DESCRIPTION section of man page.
02051 flags_helpman_description()
02052 {
02053   if [ -n "${HELP_DESCRIPTION}" ]; then
02054     echo ".SH DESCRIPTION"
02055     flags_description_="${HELP_DESCRIPTION:-'No description available.'}"
02056     flags_description_=`_flags_manText "${flags_description_}"`
02057     echo "${flags_description_}"
02058 
02059     unset flags_description_
02060   fi
02061 }
02062 
02063 ##############################################################################
02064 # Prints OPTIONS section entry of man page of named flag.
02065 flags_helpman_flag()
02066 {
02067   flags_name_=$1
02068   flags_showDefault_=${2:-${FLAGS_TRUE}}
02069   flags_flagStr_=''
02070   flags_boolStr_=''
02071   flags_usName_=`_flags_underscoreName ${flags_name_}`
02072 
02073   _flags_getFlagDefault "${flags_usName_}" 'flags_default_'
02074   flags_help_=`_flags_getFlagInfo \
02075       "${flags_usName_}" ${__FLAGS_INFO_HELP}`
02076   flags_short_=`_flags_getFlagInfo \
02077       "${flags_usName_}" ${__FLAGS_INFO_SHORT}`
02078   flags_type_=`_flags_getFlagInfo \
02079       "${flags_usName_}" ${__FLAGS_INFO_TYPE}`
02080   flags_category_=`_flags_getFlagInfo \
02081       "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
02082 
02083   flags_help_=$(echo "${flags_help_}"|sed 's/^\ *//g'|tr '\n' ' ')
02084 
02085   # adjust type ID for multi-flags
02086   if [ ${flags_type_} -gt 128 ]; then
02087     flags_type_=`expr "${flags_type_}" - 128`
02088   fi
02089   # flag name
02090   if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
02091     # add [no] to long boolean flag names, except the 'help' flags
02092     [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
02093         flags_boolStr_='[no]'
02094     # long flag name
02095     flags_flagStr_="\fB${flags_flagStr_}--${flags_boolStr_}${flags_name_}"
02096   fi
02097   [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
02098       # short flag name
02099       flags_flagStr_="${flags_flagStr_}, -${flags_short_}"
02100   flags_flagStr_="${flags_flagStr_}\fR"
02101   # argument
02102   if [ ${flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ]; then
02103     flags_flagStr_="${flags_flagStr_} \fI`_flags_typeStr ${flags_type_}`\fR"
02104   fi
02105   # default value
02106   if [ ${flags_showDefault_} -eq ${FLAGS_TRUE} ]; then
02107     flags_defaultStr_=`_flags_defaultStr "${flags_usName_}"`
02108     flags_defaultStr_=" (default:\ ${flags_defaultStr_//\ /\\ })"
02109   else
02110     flags_defaultStr_=''
02111   fi
02112 
02113   echo ".TP 8"
02114   echo "${flags_flagStr_}"
02115   echo "${flags_help_}${flags_defaultStr_}"
02116 
02117   unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ flags_emptyStrLen_ \
02118       flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \
02119       flags_columns_ flags_short_ flags_type_ flags_usName_ flags_flagStrLen_
02120 
02121   return ${FLAGS_TRUE}
02122 }
02123 
02124 ##############################################################################
02125 # Prints OPTIONS section of man page.
02126 flags_helpman_flags()
02127 {
02128   echo ".SH OPTIONS"
02129   # get lists of flags belonging to same category
02130   flags_otherFlags_=''
02131   for flags_category_ in "${__flags_categoryNames[@]}"; do
02132     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
02133     eval "flags_${flags_usCategory_}Flags_=''"
02134   done
02135   for flags_name_ in ${__flags_longNames}; do
02136     flags_nameStrLen_=`expr -- "${flags_name_}" : '.*'`
02137     flags_usName_=`_flags_underscoreName ${flags_name_}`
02138     flags_category_=`_flags_getFlagInfo "${flags_usName_}" ${__FLAGS_INFO_CATEGORY}`
02139     if [ "${flags_category_}" = "${__FLAGS_NULL}" ]; then
02140       flags_otherFlags_="${flags_otherFlags_} ${flags_name_}"
02141     else
02142       flags_usCategory_=`_flags_underscoreName ${flags_category_}`
02143       eval "flags_${flags_usCategory_}Flags_=\"\${flags_${flags_usCategory_}Flags_} ${flags_name_}\""
02144     fi
02145   done
02146   # output help of required flags
02147   if [ -n "${flags_requiredFlags_}" ]; then
02148     echo ".P"
02149     echo "\fBThe required options are as follows:\fR"
02150     flags_requiredFlags_=`_flags_sortList "${flags_requiredFlags_}"`
02151     for flags_name_ in ${flags_requiredFlags_}; do
02152       flags_helpman_flag ${flags_name_} ${FLAGS_FALSE}
02153     done
02154   fi
02155   # output help of non-required and non-help flags
02156   for flags_category_ in "${__flags_categoryNames[@]}"; do
02157     if [ "${flags_category_}" = 'required' -o \
02158          "${flags_category_}" = 'help' ]; then
02159       continue
02160     fi
02161     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
02162     eval "flags_${flags_usCategory_}Flags_=\`_flags_sortList \"\${flags_${flags_usCategory_}Flags_}\"\`"
02163     eval "flags_names_=\"\${flags_${flags_usCategory_}Flags_}\""
02164     if [ -n "${flags_names_}" ]; then
02165       echo ".P"
02166       echo "\fBThe ${flags_category_} options are as follows:\fR"
02167       for flags_name_ in ${flags_names_}; do
02168         flags_helpman_flag ${flags_name_}
02169       done
02170     fi
02171   done
02172   # output help of remaining non-help flags
02173   if [ -n "${flags_otherFlags_}" ]; then
02174     echo ".P"
02175     echo "\fBThe available options are as follows:\fR"
02176     flags_otherFlags_=`_flags_sortList "${flags_otherFlags_}"`
02177     for flags_name_ in ${flags_otherFlags_}; do
02178       flags_helpman_flag ${flags_name_}
02179     done
02180   fi
02181   # output help of help flags
02182   if [ -n "${flags_helpFlags_}" ]; then
02183     echo ".P"
02184     echo "\fBThe help options are as follows:\fR"
02185     for flags_name_ in ${flags_helpFlags_}; do
02186       flags_helpman_flag ${flags_name_} ${FLAGS_FALSE}
02187     done
02188   fi
02189 
02190   # clean up
02191   for flags_category_ in "${__flags_categoryNames[@]}"; do
02192     flags_usCategory_=`_flags_underscoreName ${flags_category_}`
02193     eval "unset flags_${flags_usCategory_}Flags_"
02194   done
02195   unset flags_maxNameLen_ flags_name_ flags_nameStrLen_ flags_type_ \
02196       flags_otherFlags flags_category_ flags_usCategory_
02197 }
02198 
02199 ##############################################################################
02200 # Prints COPYRIGHT section of man page.
02201 flags_helpman_copyright()
02202 {
02203   if [ -n "${HELP_COPYRIGHT}" ]; then
02204     echo ".SH COPYRIGHT"
02205     flags_copyright_="${HELP_COPYRIGHT}"
02206     flags_copyright_=`echo "${flags_copyright_}"|awk '{printf "%s\n.br\n",$0}'`
02207     flags_copyright_=`_flags_manText "${flags_copyright_}"`
02208     echo "${flags_copyright_}"
02209 
02210     unset flags_copyright_
02211   fi
02212 }
02213 
02214 ##############################################################################
02215 # Prints CONTACT section of man page.
02216 flags_helpman_contact()
02217 {
02218   if [ -n "${HELP_CONTACT}" ]; then
02219     echo ".SH CONTACT"
02220     flags_contact_="${HELP_CONTACT}"
02221     flags_contact_=`_flags_manText "${flags_contact_}"`
02222     echo "${flags_contact_}"
02223 
02224     unset flags_contact_
02225   fi
02226 }
02227 
02228 ##############################################################################
02229 # This function outputs the help in man page format.
02230 #
02231 # Args:
02232 #   none
02233 # Returns:
02234 #   integer: success of operation (always returns true)
02235 flags_helpman()
02236 {
02237   flags_command_=${FLAGS_PARENT:-${0##*/}}
02238   flags_command_=`_flags_manText "${flags_command_}"`
02239 
02240   echo ".TH \"${flags_command_}\" 1 `date '+%e\ %B\ %G'`"
02241   flags_helpman_name
02242   flags_helpman_synopsis
02243   flags_helpman_description
02244   flags_helpman_flags
02245   flags_helpman_copyright
02246   flags_helpman_contact
02247 
02248   unset flags_command_
02249 
02250   return ${FLAGS_TRUE}
02251 }
02252 
02253 # ----------------------------------------------------------------------------
02254 # version information
02255 # ----------------------------------------------------------------------------
02256 
02257 ##############################################################################
02258 # This function outputs the version and copyright.
02259 #
02260 # Args:
02261 #   none
02262 # Returns:
02263 #   integer: success of operation (always returns true)
02264 flags_version()
02265 {
02266   flags_command_=${HELP_COMMAND:-$0##*/}
02267   flags_version_=${HELP_VERSION:-'unknown'}
02268   echo "${flags_command_} version ${flags_version_}"
02269   if [ -n "${HELP_COPYRIGHT}" ]; then
02270     flags_copyright_=$(echo "${HELP_COPYRIGHT}"\
02271         |awk '{printf "%s:NEWLINE:",$0}'\
02272         |sed 's/^\ *:NEWLINE://g;s/:NEWLINE:\ *$//g;s/:NEWLINE:/\\n/g')
02273     echo -e "${flags_copyright_}"
02274   fi
02275   unset flags_command_ flags_version_ flags_copyright_
02276 }
02277 
02278 # ----------------------------------------------------------------------------
02279 # reset
02280 # ----------------------------------------------------------------------------
02281 
02282 ##############################################################################
02283 # Reset shflags back to an uninitialized state.
02284 #
02285 # Args:
02286 #   none
02287 # Returns:
02288 #   nothing
02289 flags_reset()
02290 {
02291   for flags_name_ in ${__flags_longNames}; do
02292     flags_usName_=`_flags_underscoreName ${flags_name_}`
02293     flags_strToEval_="unset FLAGS_${flags_usName_}"
02294     for flags_type_ in \
02295         ${__FLAGS_INFO_DEFAULT} \
02296         ${__FLAGS_INFO_HELP} \
02297         ${__FLAGS_INFO_SHORT} \
02298         ${__FLAGS_INFO_TYPE} \
02299         ${__FLAGS_INFO_CATEGORY}
02300     do
02301       flags_strToEval_=\
02302 "${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}"
02303     done
02304     eval ${flags_strToEval_}
02305   done
02306 
02307   # reset internal variables
02308   __flags_boolNames=' '
02309   __flags_longNames=' '
02310   __flags_shortNames=' '
02311   __flags_definedNames=' '
02312   __flags_categoryNames=' '
02313 
02314   unset flags_name_ flags_type_ flags_strToEval_ flags_usName_
02315 }