blob: 5cfab3beba086c08a92f73c418f6e1ec5f9efe6f [file] [log] [blame]
kate.ward60c25982008-11-12 20:12:44 +00001# vim:et:ft=sh:sts=2:sw=2
2#
Kate Wardcbc669d2020-03-29 15:44:19 +02003# Copyright 2008-2020 Kate Ward. All Rights Reserved.
Kate Wardc5dbc0c2017-08-04 16:48:11 +02004# Released under the Apache License 2.0 license.
5# http://www.apache.org/licenses/LICENSE-2.0
kate.wardf51c6162008-06-17 16:38:35 +00006#
Kate Warde563d4c2018-01-15 11:28:57 +01007# shFlags is an advanced command-line flag library for Unix shell scripts.
kate.wardf51c6162008-06-17 16:38:35 +00008#
kate.ward29ddd4e2008-06-18 19:05:43 +00009# Author: kate.ward@forestent.com (Kate Ward)
Kate Warde563d4c2018-01-15 11:28:57 +010010# https://github.com/kward/shflags
kate.ward29ddd4e2008-06-18 19:05:43 +000011#
Kate Wardc5dbc0c2017-08-04 16:48:11 +020012# This module implements something like the gflags library available
13# from https://github.com/gflags/gflags.
kate.wardf51c6162008-06-17 16:38:35 +000014#
15# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take
16# a name, default value, help-string, and optional 'short' name (one-letter
Kate Warddc385d52017-08-04 20:47:11 +020017# name). Some flags have other arguments, which are described with the flag.
kate.wardf51c6162008-06-17 16:38:35 +000018#
Peter van der Does4f2f26e2016-03-05 20:29:42 -050019# DEFINE_string: takes any input, and interprets it as a string.
kate.wardf51c6162008-06-17 16:38:35 +000020#
kate.ward0a4f16f2013-01-07 22:10:49 +000021# DEFINE_boolean: does not take any arguments. Say --myflag to set
22# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. For short
23# flags, passing the flag on the command-line negates the default value, i.e.
24# if the default is true, passing the flag sets the value to false.
kate.wardf51c6162008-06-17 16:38:35 +000025#
Peter van der Does4f2f26e2016-03-05 20:29:42 -050026# DEFINE_float: takes an input and interprets it as a floating point number. As
kate.wardf51c6162008-06-17 16:38:35 +000027# shell does not support floats per-se, the input is merely validated as
28# being a valid floating point value.
29#
Peter van der Does4f2f26e2016-03-05 20:29:42 -050030# DEFINE_integer: takes an input and interprets it as an integer.
kate.wardf51c6162008-06-17 16:38:35 +000031#
32# SPECIAL FLAGS: There are a few flags that have special meaning:
33# --help (or -?) prints a list of all the flags in a human-readable fashion
kate.ward39913d12009-04-01 14:09:23 +000034# --flagfile=foo read flags from foo. (not implemented yet)
kate.wardf51c6162008-06-17 16:38:35 +000035# -- as in getopt(), terminates flag-processing
36#
37# EXAMPLE USAGE:
38#
kate.wardc5210682009-03-30 18:54:36 +000039# -- begin hello.sh --
kate.wardf51c6162008-06-17 16:38:35 +000040# #! /bin/sh
41# . ./shflags
kate.wardc5210682009-03-30 18:54:36 +000042# DEFINE_string name 'world' "somebody's name" n
43# FLAGS "$@" || exit $?
44# eval set -- "${FLAGS_ARGV}"
kate.wardf51c6162008-06-17 16:38:35 +000045# echo "Hello, ${FLAGS_name}."
kate.wardc5210682009-03-30 18:54:36 +000046# -- end hello.sh --
47#
48# $ ./hello.sh -n Kate
49# Hello, Kate.
kate.ward29ddd4e2008-06-18 19:05:43 +000050#
kate.ward1cb79602011-06-10 11:15:49 +000051# CUSTOMIZABLE BEHAVIOR:
52#
53# A script can override the default 'getopt' command by providing the path to
54# an alternate implementation by defining the FLAGS_GETOPT_CMD variable.
55#
56# NOTES:
57#
58# * Not all systems include a getopt version that supports long flags. On these
59# systems, only short flags are recognized.
kate.wardf51c6162008-06-17 16:38:35 +000060
61#==============================================================================
kate.warda8953952008-06-17 16:48:34 +000062# shFlags
kate.wardf51c6162008-06-17 16:38:35 +000063#
64# Shared attributes:
kate.wardc85fa862013-01-14 21:33:11 +000065# flags_error: last error message
66# flags_output: last function output (rarely valid)
kate.wardf51c6162008-06-17 16:38:35 +000067# flags_return: last return value
68#
69# __flags_longNames: list of long names for all flags
70# __flags_shortNames: list of short names for all flags
71# __flags_boolNames: list of boolean flag names
72#
kate.ward60c25982008-11-12 20:12:44 +000073# __flags_opts: options parsed by getopt
74#
kate.wardf51c6162008-06-17 16:38:35 +000075# Per-flag attributes:
76# FLAGS_<flag_name>: contains value of flag named 'flag_name'
77# __flags_<flag_name>_default: the default flag value
78# __flags_<flag_name>_help: the flag help string
79# __flags_<flag_name>_short: the flag short name
80# __flags_<flag_name>_type: the flag type
81#
82# Notes:
83# - lists of strings are space separated, and a null value is the '~' char.
Kate Ward83807eb2017-10-06 23:22:27 +020084#
Kate Ward638ed782017-10-21 21:29:59 +020085### ShellCheck (http://www.shellcheck.net/)
Kate Ward3908d0f2018-01-18 01:05:45 +010086# expr may be antiquated, but it is the only solution in some cases.
87# shellcheck disable=SC2003
Kate Ward83807eb2017-10-06 23:22:27 +020088# $() are not fully portable (POSIX != portable).
89# shellcheck disable=SC2006
90# [ p -a q ] are well defined enough (vs [ p ] && [ q ]).
91# shellcheck disable=SC2166
kate.wardf51c6162008-06-17 16:38:35 +000092
Kate Ward61ed6592017-08-17 15:20:11 +020093# Return if FLAGS already loaded.
Kate Ward7cafbef2020-04-09 17:52:50 +020094if [ -n "${FLAGS_VERSION:-}" ]; then return 0; fi
Kate Ward191e13b2020-04-13 22:56:45 +020095FLAGS_VERSION='1.4.0pre'
kate.wardf51c6162008-06-17 16:38:35 +000096
Kate Ward61ed6592017-08-17 15:20:11 +020097# Return values that scripts can use.
kate.warde10dd532013-01-04 21:52:23 +000098FLAGS_TRUE=0
99FLAGS_FALSE=1
100FLAGS_ERROR=2
101
Kate Ward7cafbef2020-04-09 17:52:50 +0200102# shlib_expr_cmd determines a reasonable default `expr` command.
103# https://github.com/kward/shlib
104#
105# Use like:
106# EXPR_CMD=$(shlib_expr_cmd)
107# ${EXPR_CMD} 1 + 1
108#
109# Args:
110# none
111# Output:
112# string: expr command
113# Return
114# int: 0 upon success
115shlib_expr_cmd() {
Kate Wardd368f832020-04-09 10:53:53 +0200116 if [ "$(uname -s)" = 'BSD' ]; then
117 echo 'gexpr --'
118 return 0
Kate Ward61ed6592017-08-17 15:20:11 +0200119 fi
Kate Wardd368f832020-04-09 10:53:53 +0200120
Kate Ward7cafbef2020-04-09 17:52:50 +0200121 _shlib_expr_cmd_='expr --'
Kate Wardd368f832020-04-09 10:53:53 +0200122 # shellcheck disable=SC2003
Kate Ward7cafbef2020-04-09 17:52:50 +0200123 if _shlib_output_=$(${_shlib_expr_cmd_} 2>&1); then
124 if [ "${_shlib_output_}" = '--' ]; then
Kate Wardd368f832020-04-09 10:53:53 +0200125 # We are likely running inside BusyBox.
Kate Ward7cafbef2020-04-09 17:52:50 +0200126 _shlib_expr_cmd_='expr'
Kate Wardd368f832020-04-09 10:53:53 +0200127 fi
128 fi
129
Kate Ward7cafbef2020-04-09 17:52:50 +0200130 echo "${_shlib_expr_cmd_}"
131 unset _shlib_expr_cmd_ _shlib_output_
Kate Wardd368f832020-04-09 10:53:53 +0200132}
Kate Ward7cafbef2020-04-09 17:52:50 +0200133__FLAGS_EXPR_CMD=`shlib_expr_cmd`
kate.warda589b9f2012-12-17 23:27:51 +0000134
Kate Ward61c6d0e2017-10-21 21:08:52 +0200135# Commands a user can override if desired.
kate.ward4ae73d82012-12-17 23:34:29 +0000136FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}}
kate.ward1cb79602011-06-10 11:15:49 +0000137FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt}
138
Kate Ward9123f582018-01-25 12:54:08 +0100139#
140# Logging functions.
141#
142
Kate Ward7cafbef2020-04-09 17:52:50 +0200143# Logging levels.
144FLAGS_LEVEL_DEBUG=0
145FLAGS_LEVEL_INFO=1
146FLAGS_LEVEL_WARN=2
147FLAGS_LEVEL_ERROR=3
148FLAGS_LEVEL_FATAL=4
149__FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN}
150__flags_level=${__FLAGS_LEVEL_DEFAULT} # Current logging level.
Kate Ward9123f582018-01-25 12:54:08 +0100151
152_flags_debug() {
Kate Ward7cafbef2020-04-09 17:52:50 +0200153 if [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ]; then echo "flags:DEBUG $*" >&2; fi
Kate Ward9123f582018-01-25 12:54:08 +0100154}
155_flags_info() {
Kate Ward7cafbef2020-04-09 17:52:50 +0200156 if [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ]; then echo "flags:INFO $*" >&2; fi
Kate Ward9123f582018-01-25 12:54:08 +0100157}
158_flags_warn() {
Kate Ward7cafbef2020-04-09 17:52:50 +0200159 if [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ]; then echo "flags:WARN $*" >&2; fi
Kate Ward9123f582018-01-25 12:54:08 +0100160}
161_flags_error() {
Kate Ward7cafbef2020-04-09 17:52:50 +0200162 if [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ]; then echo "flags:ERROR $*" >&2; fi
Kate Ward9123f582018-01-25 12:54:08 +0100163}
164_flags_fatal() {
Kate Ward9123f582018-01-25 12:54:08 +0100165 echo "flags:FATAL $*" >&2
166 exit ${FLAGS_ERROR}
167}
168
169# Get the logging level.
170flags_loggingLevel() { echo ${__flags_level}; }
171
Kate Ward7cafbef2020-04-09 17:52:50 +0200172# Set the logging level by overriding the `__flags_level` variable.
Kate Ward9123f582018-01-25 12:54:08 +0100173#
174# Args:
175# _flags_level_: integer: new logging level
176# Returns:
177# nothing
178flags_setLoggingLevel() {
179 [ $# -ne 1 ] && _flags_fatal "flags_setLevel(): logging level missing"
180 _flags_level_=$1
Kate Ward7cafbef2020-04-09 17:52:50 +0200181 if ! [ "${_flags_level_}" -ge "${FLAGS_LEVEL_DEBUG}" -a "${_flags_level_}" -le "${FLAGS_LEVEL_FATAL}" ]; then
182 _flags_fatal "Invalid logging level '${_flags_level_}' specified."
183 fi
Kate Ward9123f582018-01-25 12:54:08 +0100184 __flags_level=$1
185 unset _flags_level_
186}
187
188#
189# Shell checks.
190#
191
kate.wardf51c6162008-06-17 16:38:35 +0000192if [ -n "${ZSH_VERSION:-}" ]; then
kate.ward1d0ecc42008-07-11 15:33:23 +0000193 setopt |grep "^shwordsplit$" >/dev/null
194 if [ $? -ne ${FLAGS_TRUE} ]; then
195 _flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
kate.wardf51c6162008-06-17 16:38:35 +0000196 fi
197 if [ -z "${FLAGS_PARENT:-}" ]; then
198 _flags_fatal "zsh does not pass \$0 through properly. please declare' \
kate.warda8953952008-06-17 16:48:34 +0000199\"FLAGS_PARENT=\$0\" before calling shFlags"
kate.wardf51c6162008-06-17 16:38:35 +0000200 fi
201fi
202
Kate Ward61ed6592017-08-17 15:20:11 +0200203# Can we use built-ins?
kate.warde10dd532013-01-04 21:52:23 +0000204( echo "${FLAGS_TRUE#0}"; ) >/dev/null 2>&1
205if [ $? -eq ${FLAGS_TRUE} ]; then
kate.wardc66a5fc2013-01-12 23:10:15 +0000206 __FLAGS_USE_BUILTIN=${FLAGS_TRUE}
kate.warde10dd532013-01-04 21:52:23 +0000207else
kate.wardc66a5fc2013-01-12 23:10:15 +0000208 __FLAGS_USE_BUILTIN=${FLAGS_FALSE}
kate.warde10dd532013-01-04 21:52:23 +0000209fi
210
kate.wardf51c6162008-06-17 16:38:35 +0000211#
Kate Ward61ed6592017-08-17 15:20:11 +0200212# Constants.
kate.wardf51c6162008-06-17 16:38:35 +0000213#
214
Kate Ward61ed6592017-08-17 15:20:11 +0200215# Reserved flag names.
Kate Ward46e081e2020-04-13 23:51:43 +0200216__FLAGS_RESERVED_LIST=' ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE '
kate.ward1cb79602011-06-10 11:15:49 +0000217__FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION "
218
Kate Ward61c6d0e2017-10-21 21:08:52 +0200219# Determined getopt version (standard or enhanced).
kate.wardf51c6162008-06-17 16:38:35 +0000220__FLAGS_GETOPT_VERS_STD=0
221__FLAGS_GETOPT_VERS_ENH=1
kate.wardf51c6162008-06-17 16:38:35 +0000222
Kate Ward61c6d0e2017-10-21 21:08:52 +0200223# shellcheck disable=SC2120
224_flags_getopt_vers() {
225 _flags_getopt_cmd_=${1:-${FLAGS_GETOPT_CMD}}
226 case "`${_flags_getopt_cmd_} -lfoo '' --foo 2>&1`" in
227 ' -- --foo') echo ${__FLAGS_GETOPT_VERS_STD} ;;
228 ' --foo --') echo ${__FLAGS_GETOPT_VERS_ENH} ;;
229 # Unrecognized output. Assuming standard getopt version.
230 *) echo ${__FLAGS_GETOPT_VERS_STD} ;;
231 esac
232 unset _flags_getopt_cmd_
233}
234# shellcheck disable=SC2119
235__FLAGS_GETOPT_VERS=`_flags_getopt_vers`
kate.wardf51c6162008-06-17 16:38:35 +0000236
237# getopt optstring lengths
238__FLAGS_OPTSTR_SHORT=0
239__FLAGS_OPTSTR_LONG=1
240
241__FLAGS_NULL='~'
242
Kate Ward61ed6592017-08-17 15:20:11 +0200243# Flag info strings.
kate.wardfb0e7182009-05-10 16:59:13 +0000244__FLAGS_INFO_DEFAULT='default'
245__FLAGS_INFO_HELP='help'
246__FLAGS_INFO_SHORT='short'
247__FLAGS_INFO_TYPE='type'
kate.wardf51c6162008-06-17 16:38:35 +0000248
Kate Ward61ed6592017-08-17 15:20:11 +0200249# Flag lengths.
kate.wardf51c6162008-06-17 16:38:35 +0000250__FLAGS_LEN_SHORT=0
251__FLAGS_LEN_LONG=1
252
Kate Ward61ed6592017-08-17 15:20:11 +0200253# Flag types.
kate.wardf51c6162008-06-17 16:38:35 +0000254__FLAGS_TYPE_NONE=0
255__FLAGS_TYPE_BOOLEAN=1
256__FLAGS_TYPE_FLOAT=2
257__FLAGS_TYPE_INTEGER=3
258__FLAGS_TYPE_STRING=4
259
Kate Ward61ed6592017-08-17 15:20:11 +0200260# Set the constants readonly.
kate.wardd9672402008-11-15 16:55:51 +0000261__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'`
262for __flags_const in ${__flags_constants}; do
Kate Ward61ed6592017-08-17 15:20:11 +0200263 # Skip certain flags.
kate.wardd9672402008-11-15 16:55:51 +0000264 case ${__flags_const} in
kate.ward39913d12009-04-01 14:09:23 +0000265 FLAGS_HELP) continue ;;
kate.wardd9672402008-11-15 16:55:51 +0000266 FLAGS_PARENT) continue ;;
267 esac
Kate Ward61ed6592017-08-17 15:20:11 +0200268 # Set flag readonly.
kate.wardd9672402008-11-15 16:55:51 +0000269 if [ -z "${ZSH_VERSION:-}" ]; then
Kate Ward83807eb2017-10-06 23:22:27 +0200270 readonly "${__flags_const}"
Kate Ward61ed6592017-08-17 15:20:11 +0200271 continue
kate.wardf51c6162008-06-17 16:38:35 +0000272 fi
Kate Ward61ed6592017-08-17 15:20:11 +0200273 case ${ZSH_VERSION} in
Kate Ward83807eb2017-10-06 23:22:27 +0200274 [123].*) readonly "${__flags_const}" ;;
Kate Ward8c168e52020-02-11 04:18:45 +0100275 *)
276 # Declare readonly constants globally.
277 # shellcheck disable=SC2039
278 readonly -g "${__flags_const}" ;;
Kate Ward61ed6592017-08-17 15:20:11 +0200279 esac
kate.wardf51c6162008-06-17 16:38:35 +0000280done
kate.wardd9672402008-11-15 16:55:51 +0000281unset __flags_const __flags_constants
kate.wardf51c6162008-06-17 16:38:35 +0000282
283#
Kate Warddc385d52017-08-04 20:47:11 +0200284# Internal variables.
kate.wardf51c6162008-06-17 16:38:35 +0000285#
286
Kate Warddc385d52017-08-04 20:47:11 +0200287# Space separated lists.
288__flags_boolNames=' ' # Boolean flag names.
289__flags_longNames=' ' # Long flag names.
290__flags_shortNames=' ' # Short flag names.
291__flags_definedNames=' ' # Defined flag names (used for validation).
kate.wardf51c6162008-06-17 16:38:35 +0000292
Kate Warddc385d52017-08-04 20:47:11 +0200293__flags_columns='' # Screen width in columns.
Kate Warddc385d52017-08-04 20:47:11 +0200294__flags_opts='' # Temporary storage for parsed getopt flags.
kate.ward60c25982008-11-12 20:12:44 +0000295
kate.wardcc145682008-11-14 00:32:42 +0000296# Define a flag.
297#
298# Calling this function will define the following info variables for the
299# specified flag:
kate.wardf51c6162008-06-17 16:38:35 +0000300# FLAGS_flagname - the name for this flag (based upon the long flag name)
301# __flags_<flag_name>_default - the default value
302# __flags_flagname_help - the help string
303# __flags_flagname_short - the single letter alias
304# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*)
305#
306# Args:
Kate Warddc385d52017-08-04 20:47:11 +0200307# _flags_type_: integer: internal type of flag (__FLAGS_TYPE_*)
308# _flags_name_: string: long flag name
309# _flags_default_: default flag value
310# _flags_help_: string: help string
311# _flags_short_: string: (optional) short flag name
kate.wardf51c6162008-06-17 16:38:35 +0000312# Returns:
313# integer: success of operation, or error
Kate Ward271a12c2017-10-18 00:52:40 +0200314_flags_define() {
kate.wardf51c6162008-06-17 16:38:35 +0000315 if [ $# -lt 4 ]; then
316 flags_error='DEFINE error: too few arguments'
317 flags_return=${FLAGS_ERROR}
318 _flags_error "${flags_error}"
319 return ${flags_return}
320 fi
321
kate.ward60c25982008-11-12 20:12:44 +0000322 _flags_type_=$1
323 _flags_name_=$2
324 _flags_default_=$3
Kate Ward3355cde2017-10-16 23:30:29 +0200325 _flags_help_=${4:-§} # Special value '§' indicates no help string provided.
kate.ward60c25982008-11-12 20:12:44 +0000326 _flags_short_=${5:-${__FLAGS_NULL}}
kate.wardf51c6162008-06-17 16:38:35 +0000327
Kate Warddc385d52017-08-04 20:47:11 +0200328 _flags_debug "type:${_flags_type_} name:${_flags_name_}" \
329 "default:'${_flags_default_}' help:'${_flags_help_}'" \
330 "short:${_flags_short_}"
331
kate.ward60c25982008-11-12 20:12:44 +0000332 _flags_return_=${FLAGS_TRUE}
Kate Ward83807eb2017-10-06 23:22:27 +0200333 _flags_usName_="`_flags_underscoreName "${_flags_name_}"`"
kate.wardf51c6162008-06-17 16:38:35 +0000334
Kate Ward638ed782017-10-21 21:29:59 +0200335 # Check whether the flag name is reserved.
Kate Ward7cafbef2020-04-09 17:52:50 +0200336 if _flags_itemInList "${_flags_usName_}" "${__FLAGS_RESERVED_LIST}"; then
kate.ward39913d12009-04-01 14:09:23 +0000337 flags_error="flag name (${_flags_name_}) is reserved"
338 _flags_return_=${FLAGS_ERROR}
339 fi
340
Kate Ward638ed782017-10-21 21:29:59 +0200341 # Require short option for getopt that don't support long options.
kate.ward60c25982008-11-12 20:12:44 +0000342 if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
Kate Ward638ed782017-10-21 21:29:59 +0200343 -a "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" \
kate.ward60c25982008-11-12 20:12:44 +0000344 -a "${_flags_short_}" = "${__FLAGS_NULL}" ]
kate.wardf51c6162008-06-17 16:38:35 +0000345 then
kate.ward5b48fc12008-11-13 00:42:43 +0000346 flags_error="short flag required for (${_flags_name_}) on this platform"
kate.ward60c25982008-11-12 20:12:44 +0000347 _flags_return_=${FLAGS_ERROR}
kate.wardf51c6162008-06-17 16:38:35 +0000348 fi
349
Kate Ward638ed782017-10-21 21:29:59 +0200350 # Check for existing long name definition.
kate.ward60c25982008-11-12 20:12:44 +0000351 if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
Kate Ward83807eb2017-10-06 23:22:27 +0200352 if _flags_itemInList "${_flags_usName_}" "${__flags_definedNames}"; then
kate.wardda8d2c02011-06-28 13:26:02 +0000353 flags_error="definition for ([no]${_flags_name_}) already exists"
kate.ward20d06782008-10-21 19:57:19 +0000354 _flags_warn "${flags_error}"
kate.ward60c25982008-11-12 20:12:44 +0000355 _flags_return_=${FLAGS_FALSE}
kate.wardf51c6162008-06-17 16:38:35 +0000356 fi
357 fi
358
Kate Ward638ed782017-10-21 21:29:59 +0200359 # Check for existing short name definition.
Kate Ward77a6d9e2020-04-10 14:30:13 +0200360 if [ ${_flags_return_} -eq ${FLAGS_TRUE} -a "${_flags_short_}" != "${__FLAGS_NULL}" ]; then
Kate Ward83807eb2017-10-06 23:22:27 +0200361 if _flags_itemInList "${_flags_short_}" "${__flags_shortNames}"; then
kate.ward60c25982008-11-12 20:12:44 +0000362 flags_error="flag short name (${_flags_short_}) already defined"
kate.ward20d06782008-10-21 19:57:19 +0000363 _flags_warn "${flags_error}"
kate.ward60c25982008-11-12 20:12:44 +0000364 _flags_return_=${FLAGS_FALSE}
kate.wardf51c6162008-06-17 16:38:35 +0000365 fi
366 fi
367
Kate Ward638ed782017-10-21 21:29:59 +0200368 # Handle default value. Note, on several occasions the 'if' portion of an
369 # if/then/else contains just a ':' which does nothing. A binary reversal via
kate.wardf51c6162008-06-17 16:38:35 +0000370 # '!' is not done because it does not work on all shells.
kate.ward60c25982008-11-12 20:12:44 +0000371 if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
372 case ${_flags_type_} in
kate.wardf51c6162008-06-17 16:38:35 +0000373 ${__FLAGS_TYPE_BOOLEAN})
kate.warde10dd532013-01-04 21:52:23 +0000374 if _flags_validBool "${_flags_default_}"; then
kate.ward60c25982008-11-12 20:12:44 +0000375 case ${_flags_default_} in
376 true|t|0) _flags_default_=${FLAGS_TRUE} ;;
377 false|f|1) _flags_default_=${FLAGS_FALSE} ;;
kate.wardf51c6162008-06-17 16:38:35 +0000378 esac
379 else
kate.ward60c25982008-11-12 20:12:44 +0000380 flags_error="invalid default flag value '${_flags_default_}'"
381 _flags_return_=${FLAGS_ERROR}
kate.wardf51c6162008-06-17 16:38:35 +0000382 fi
383 ;;
384
385 ${__FLAGS_TYPE_FLOAT})
kate.ward74178272013-01-14 22:17:05 +0000386 if _flags_validFloat "${_flags_default_}"; then
kate.wardf51c6162008-06-17 16:38:35 +0000387 :
388 else
kate.ward60c25982008-11-12 20:12:44 +0000389 flags_error="invalid default flag value '${_flags_default_}'"
390 _flags_return_=${FLAGS_ERROR}
kate.wardf51c6162008-06-17 16:38:35 +0000391 fi
392 ;;
393
394 ${__FLAGS_TYPE_INTEGER})
kate.wardc66a5fc2013-01-12 23:10:15 +0000395 if _flags_validInt "${_flags_default_}"; then
kate.wardf51c6162008-06-17 16:38:35 +0000396 :
397 else
kate.ward60c25982008-11-12 20:12:44 +0000398 flags_error="invalid default flag value '${_flags_default_}'"
399 _flags_return_=${FLAGS_ERROR}
kate.wardf51c6162008-06-17 16:38:35 +0000400 fi
401 ;;
402
Kate Ward638ed782017-10-21 21:29:59 +0200403 ${__FLAGS_TYPE_STRING}) ;; # Everything in shell is a valid string.
kate.wardf51c6162008-06-17 16:38:35 +0000404
405 *)
kate.ward60c25982008-11-12 20:12:44 +0000406 flags_error="unrecognized flag type '${_flags_type_}'"
407 _flags_return_=${FLAGS_ERROR}
kate.wardf51c6162008-06-17 16:38:35 +0000408 ;;
409 esac
410 fi
411
kate.ward60c25982008-11-12 20:12:44 +0000412 if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
Kate Warddc385d52017-08-04 20:47:11 +0200413 # Store flag information.
kate.wardda8d2c02011-06-28 13:26:02 +0000414 eval "FLAGS_${_flags_usName_}='${_flags_default_}'"
415 eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}"
416 eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=\
kate.ward60c25982008-11-12 20:12:44 +0000417\"${_flags_default_}\""
kate.wardda8d2c02011-06-28 13:26:02 +0000418 eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\""
419 eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'"
kate.wardf51c6162008-06-17 16:38:35 +0000420
kate.wardda8d2c02011-06-28 13:26:02 +0000421 # append flag names to name lists
kate.ward60c25982008-11-12 20:12:44 +0000422 __flags_shortNames="${__flags_shortNames}${_flags_short_} "
kate.wardda8d2c02011-06-28 13:26:02 +0000423 __flags_longNames="${__flags_longNames}${_flags_name_} "
Kate Ward83807eb2017-10-06 23:22:27 +0200424 [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \
kate.ward60c25982008-11-12 20:12:44 +0000425 __flags_boolNames="${__flags_boolNames}no${_flags_name_} "
kate.wardda8d2c02011-06-28 13:26:02 +0000426
Kate Ward638ed782017-10-21 21:29:59 +0200427 # Append flag names to defined names for later validation checks.
kate.wardda8d2c02011-06-28 13:26:02 +0000428 __flags_definedNames="${__flags_definedNames}${_flags_usName_} "
Kate Ward83807eb2017-10-06 23:22:27 +0200429 [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \
kate.wardda8d2c02011-06-28 13:26:02 +0000430 __flags_definedNames="${__flags_definedNames}no${_flags_usName_} "
kate.wardf51c6162008-06-17 16:38:35 +0000431 fi
432
kate.ward60c25982008-11-12 20:12:44 +0000433 flags_return=${_flags_return_}
kate.wardda8d2c02011-06-28 13:26:02 +0000434 unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \
435 _flags_short_ _flags_type_ _flags_usName_
kate.wardf51c6162008-06-17 16:38:35 +0000436 [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
437 return ${flags_return}
438}
439
kate.wardda8d2c02011-06-28 13:26:02 +0000440# Underscore a flag name by replacing dashes with underscores.
441#
442# Args:
443# unnamed: string: log flag name
444# Output:
445# string: underscored name
Kate Ward271a12c2017-10-18 00:52:40 +0200446_flags_underscoreName() {
Kate Warda8e81fd2018-01-15 11:31:02 +0100447 echo "$1" |tr z- z_
kate.wardda8d2c02011-06-28 13:26:02 +0000448}
449
kate.wardcc145682008-11-14 00:32:42 +0000450# Return valid getopt options using currently defined list of long options.
451#
452# This function builds a proper getopt option string for short (and long)
453# options, using the current list of long options for reference.
kate.wardf51c6162008-06-17 16:38:35 +0000454#
455# Args:
kate.wardcc145682008-11-14 00:32:42 +0000456# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*)
kate.wardf51c6162008-06-17 16:38:35 +0000457# Output:
458# string: generated option string for getopt
459# Returns:
460# boolean: success of operation (always returns True)
Kate Ward271a12c2017-10-18 00:52:40 +0200461_flags_genOptStr() {
kate.wardcc145682008-11-14 00:32:42 +0000462 _flags_optStrType_=$1
kate.wardf51c6162008-06-17 16:38:35 +0000463
kate.wardcc145682008-11-14 00:32:42 +0000464 _flags_opts_=''
kate.wardf51c6162008-06-17 16:38:35 +0000465
kate.wardda8d2c02011-06-28 13:26:02 +0000466 for _flags_name_ in ${__flags_longNames}; do
Kate Ward83807eb2017-10-06 23:22:27 +0200467 _flags_usName_="`_flags_underscoreName "${_flags_name_}"`"
468 _flags_type_="`_flags_getFlagInfo "${_flags_usName_}" "${__FLAGS_INFO_TYPE}"`"
Kate Ward74f30402020-04-13 23:00:19 +0200469 if [ $? -ne ${FLAGS_TRUE} ]; then
470 _flags_fatal 'call to _flags_type_ failed'
471 fi
kate.wardcc145682008-11-14 00:32:42 +0000472 case ${_flags_optStrType_} in
kate.wardf51c6162008-06-17 16:38:35 +0000473 ${__FLAGS_OPTSTR_SHORT})
Kate Ward83807eb2017-10-06 23:22:27 +0200474 _flags_shortName_="`_flags_getFlagInfo \
475 "${_flags_usName_}" "${__FLAGS_INFO_SHORT}"`"
kate.wardcc145682008-11-14 00:32:42 +0000476 if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then
477 _flags_opts_="${_flags_opts_}${_flags_shortName_}"
Kate Ward638ed782017-10-21 21:29:59 +0200478 # getopt needs a trailing ':' to indicate a required argument.
Kate Ward83807eb2017-10-06 23:22:27 +0200479 [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \
kate.wardcc145682008-11-14 00:32:42 +0000480 _flags_opts_="${_flags_opts_}:"
kate.wardf51c6162008-06-17 16:38:35 +0000481 fi
482 ;;
483
484 ${__FLAGS_OPTSTR_LONG})
kate.wardda8d2c02011-06-28 13:26:02 +0000485 _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_name_}"
kate.wardc5210682009-03-30 18:54:36 +0000486 # getopt needs a trailing ':' to indicate a required argument
Kate Ward83807eb2017-10-06 23:22:27 +0200487 [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \
kate.wardcc145682008-11-14 00:32:42 +0000488 _flags_opts_="${_flags_opts_}:"
kate.wardf51c6162008-06-17 16:38:35 +0000489 ;;
490 esac
491 done
492
kate.wardcc145682008-11-14 00:32:42 +0000493 echo "${_flags_opts_}"
kate.wardda8d2c02011-06-28 13:26:02 +0000494 unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \
495 _flags_type_ _flags_usName_
kate.wardf51c6162008-06-17 16:38:35 +0000496 return ${FLAGS_TRUE}
497}
498
499# Returns flag details based on a flag name and flag info.
500#
501# Args:
kate.wardda8d2c02011-06-28 13:26:02 +0000502# string: underscored flag name
kate.wardf51c6162008-06-17 16:38:35 +0000503# string: flag info (see the _flags_define function for valid info types)
504# Output:
505# string: value of dereferenced flag variable
506# Returns:
507# integer: one of FLAGS_{TRUE|FALSE|ERROR}
Kate Wardf9a3d772017-10-16 23:31:48 +0200508_flags_getFlagInfo() {
509 # Note: adding gFI to variable names to prevent naming conflicts with calling
kate.wardda8d2c02011-06-28 13:26:02 +0000510 # functions
511 _flags_gFI_usName_=$1
512 _flags_gFI_info_=$2
kate.wardf51c6162008-06-17 16:38:35 +0000513
Kate Ward3355cde2017-10-16 23:30:29 +0200514 # Example: given argument usName (underscored flag name) of 'my_flag', and
515 # argument info of 'help', set the _flags_infoValue_ variable to the value of
516 # ${__flags_my_flag_help}, and see if it is non-empty.
kate.wardda8d2c02011-06-28 13:26:02 +0000517 _flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}"
518 _flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\""
kate.ward1b600c52008-11-12 21:26:05 +0000519 eval "${_flags_strToEval_}"
Kate Ward3355cde2017-10-16 23:30:29 +0200520 if [ -n "${_flags_infoValue_}" ]; then
521 # Special value '§' indicates no help string provided.
522 [ "${_flags_gFI_info_}" = ${__FLAGS_INFO_HELP} \
523 -a "${_flags_infoValue_}" = '§' ] && _flags_infoValue_=''
kate.wardf51c6162008-06-17 16:38:35 +0000524 flags_return=${FLAGS_TRUE}
525 else
Kate Wardf9a3d772017-10-16 23:31:48 +0200526 # See if the _flags_gFI_usName_ variable is a string as strings can be
kate.wardda8d2c02011-06-28 13:26:02 +0000527 # empty...
Kate Wardf9a3d772017-10-16 23:31:48 +0200528 # Note: the DRY principle would say to have this function call itself for
kate.ward1b600c52008-11-12 21:26:05 +0000529 # the next three lines, but doing so results in an infinite loop as an
530 # invalid _flags_name_ will also not have the associated _type variable.
531 # Because it doesn't (it will evaluate to an empty string) the logic will
532 # try to find the _type variable of the _type variable, and so on. Not so
533 # good ;-)
Kate Ward3355cde2017-10-16 23:30:29 +0200534 #
535 # Example cont.: set the _flags_typeValue_ variable to the value of
536 # ${__flags_my_flag_type}, and see if it equals '4'.
kate.wardda8d2c02011-06-28 13:26:02 +0000537 _flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}"
kate.ward929261f2010-03-28 23:12:17 +0000538 _flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\""
kate.ward1b600c52008-11-12 21:26:05 +0000539 eval "${_flags_strToEval_}"
Kate Ward271a12c2017-10-18 00:52:40 +0200540 # shellcheck disable=SC2154
kate.ward929261f2010-03-28 23:12:17 +0000541 if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" ]; then
kate.ward437639d2008-10-19 17:21:41 +0000542 flags_return=${FLAGS_TRUE}
543 else
544 flags_return=${FLAGS_ERROR}
kate.wardda8d2c02011-06-28 13:26:02 +0000545 flags_error="missing flag info variable (${_flags_infoVar_})"
kate.ward437639d2008-10-19 17:21:41 +0000546 fi
kate.wardf51c6162008-06-17 16:38:35 +0000547 fi
548
kate.wardda8d2c02011-06-28 13:26:02 +0000549 echo "${_flags_infoValue_}"
550 unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \
kate.ward929261f2010-03-28 23:12:17 +0000551 _flags_strToEval_ _flags_typeValue_ _flags_typeVar_
kate.wardf51c6162008-06-17 16:38:35 +0000552 [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
553 return ${flags_return}
554}
555
Kate Wardc7ed8182017-08-07 17:51:50 +0200556# Check for presence of item in a list.
kate.wardda8d2c02011-06-28 13:26:02 +0000557#
558# Passed a string (e.g. 'abc'), this function will determine if the string is
559# present in the list of strings (e.g. ' foo bar abc ').
kate.wardf51c6162008-06-17 16:38:35 +0000560#
561# Args:
kate.wardda8d2c02011-06-28 13:26:02 +0000562# _flags_str_: string: string to search for in a list of strings
kate.wardf51c6162008-06-17 16:38:35 +0000563# unnamed: list: list of strings
564# Returns:
565# boolean: true if item is in the list
kate.wardda8d2c02011-06-28 13:26:02 +0000566_flags_itemInList() {
Kate Warde64fc762018-01-16 23:49:41 +0100567 _flags_str_=$1
kate.wardf51c6162008-06-17 16:38:35 +0000568 shift
569
Kate Ward23802b92017-08-17 08:45:16 +0200570 case " ${*:-} " in
571 *\ ${_flags_str_}\ *) flags_return=${FLAGS_TRUE} ;;
572 *) flags_return=${FLAGS_FALSE} ;;
Peter van der Does6d0ccc82016-03-05 19:55:29 -0500573 esac
kate.wardf51c6162008-06-17 16:38:35 +0000574
kate.wardcc145682008-11-14 00:32:42 +0000575 unset _flags_str_
kate.wardf51c6162008-06-17 16:38:35 +0000576 return ${flags_return}
577}
578
kate.warddadc1642008-11-14 02:00:29 +0000579# Returns the width of the current screen.
kate.ward437639d2008-10-19 17:21:41 +0000580#
kate.ward18d456e2008-11-14 00:46:44 +0000581# Output:
kate.warddadc1642008-11-14 02:00:29 +0000582# integer: width in columns of the current screen.
Kate Ward78740ed2017-10-19 12:57:09 +0200583_flags_columns() {
kate.ward14b33bf2008-11-15 20:03:18 +0000584 if [ -z "${__flags_columns}" ]; then
kate.ward14b33bf2008-11-15 20:03:18 +0000585 if eval stty size >/dev/null 2>&1; then
586 # stty size worked :-)
Kate Ward271a12c2017-10-18 00:52:40 +0200587 # shellcheck disable=SC2046
kate.ward14b33bf2008-11-15 20:03:18 +0000588 set -- `stty size`
Kate Ward78740ed2017-10-19 12:57:09 +0200589 __flags_columns="${2:-}"
kate.ward14b33bf2008-11-15 20:03:18 +0000590 fi
kate.warddadc1642008-11-14 02:00:29 +0000591 fi
Kate Ward78740ed2017-10-19 12:57:09 +0200592 if [ -z "${__flags_columns}" ]; then
593 if eval tput cols >/dev/null 2>&1; then
594 # shellcheck disable=SC2046
595 set -- `tput cols`
596 __flags_columns="${1:-}"
597 fi
598 fi
599 echo "${__flags_columns:-80}"
kate.ward437639d2008-10-19 17:21:41 +0000600}
601
602# Validate a boolean.
kate.wardf51c6162008-06-17 16:38:35 +0000603#
604# Args:
605# _flags__bool: boolean: value to validate
606# Returns:
607# bool: true if the value is a valid boolean
Kate Ward271a12c2017-10-18 00:52:40 +0200608_flags_validBool() {
kate.ward60c25982008-11-12 20:12:44 +0000609 _flags_bool_=$1
kate.wardf51c6162008-06-17 16:38:35 +0000610
611 flags_return=${FLAGS_TRUE}
kate.ward60c25982008-11-12 20:12:44 +0000612 case "${_flags_bool_}" in
kate.wardf51c6162008-06-17 16:38:35 +0000613 true|t|0) ;;
614 false|f|1) ;;
615 *) flags_return=${FLAGS_FALSE} ;;
616 esac
617
kate.ward60c25982008-11-12 20:12:44 +0000618 unset _flags_bool_
kate.wardf51c6162008-06-17 16:38:35 +0000619 return ${flags_return}
620}
621
kate.ward74178272013-01-14 22:17:05 +0000622# Validate a float.
kate.warde10dd532013-01-04 21:52:23 +0000623#
624# Args:
625# _flags_float_: float: value to validate
kate.warde10dd532013-01-04 21:52:23 +0000626# Returns:
627# bool: true if the value is a valid integer
Kate Ward61ed6592017-08-17 15:20:11 +0200628_flags_validFloat() {
kate.warde10dd532013-01-04 21:52:23 +0000629 flags_return=${FLAGS_FALSE}
Kate Ward74f30402020-04-13 23:00:19 +0200630 if [ -z "$1" ]; then
631 return ${flags_return}
632 fi
kate.warde10dd532013-01-04 21:52:23 +0000633 _flags_float_=$1
634
Kate Ward271a12c2017-10-18 00:52:40 +0200635 if _flags_validInt "${_flags_float_}"; then
kate.warde10dd532013-01-04 21:52:23 +0000636 flags_return=${FLAGS_TRUE}
kate.ward74178272013-01-14 22:17:05 +0000637 elif _flags_useBuiltin; then
kate.wardc66a5fc2013-01-12 23:10:15 +0000638 _flags_float_whole_=${_flags_float_%.*}
639 _flags_float_fraction_=${_flags_float_#*.}
Kate Ward4a9ecde2018-01-17 00:08:36 +0100640 [ "${_flags_float_whole_}" = '-' ] && _flags_float_whole_='-0'
Kate Ward271a12c2017-10-18 00:52:40 +0200641 if _flags_validInt "${_flags_float_whole_:-0}" -a \
642 _flags_validInt "${_flags_float_fraction_}"; then
kate.wardc66a5fc2013-01-12 23:10:15 +0000643 flags_return=${FLAGS_TRUE}
644 fi
kate.ward74178272013-01-14 22:17:05 +0000645 unset _flags_float_whole_ _flags_float_fraction_
kate.wardf51c6162008-06-17 16:38:35 +0000646 else
647 flags_return=${FLAGS_TRUE}
kate.wardcc145682008-11-14 00:32:42 +0000648 case ${_flags_float_} in
Kate Ward638ed782017-10-21 21:29:59 +0200649 -*) # Negative floats.
Kate Ward61ed6592017-08-17 15:20:11 +0200650 _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\
kate.warde10dd532013-01-04 21:52:23 +0000651 '\(-[0-9]*\.[0-9]*\)'`
kate.wardf51c6162008-06-17 16:38:35 +0000652 ;;
Kate Ward638ed782017-10-21 21:29:59 +0200653 *) # Positive floats.
Kate Ward61ed6592017-08-17 15:20:11 +0200654 _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\
kate.warde10dd532013-01-04 21:52:23 +0000655 '\([0-9]*\.[0-9]*\)'`
kate.wardf51c6162008-06-17 16:38:35 +0000656 ;;
657 esac
kate.wardcc145682008-11-14 00:32:42 +0000658 [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE}
kate.ward74178272013-01-14 22:17:05 +0000659 unset _flags_test_
kate.wardf51c6162008-06-17 16:38:35 +0000660 fi
661
kate.ward74178272013-01-14 22:17:05 +0000662 unset _flags_float_ _flags_float_whole_ _flags_float_fraction_
kate.wardf51c6162008-06-17 16:38:35 +0000663 return ${flags_return}
664}
665
kate.wardc66a5fc2013-01-12 23:10:15 +0000666# Validate an integer.
kate.wardf51c6162008-06-17 16:38:35 +0000667#
668# Args:
kate.warde10dd532013-01-04 21:52:23 +0000669# _flags_int_: integer: value to validate
kate.wardf51c6162008-06-17 16:38:35 +0000670# Returns:
671# bool: true if the value is a valid integer
Kate Ward271a12c2017-10-18 00:52:40 +0200672_flags_validInt() {
Kate Ward4a9ecde2018-01-17 00:08:36 +0100673 expr \( "$1" + '0' \) '=' "$1" >/dev/null 2>&1
kate.wardf51c6162008-06-17 16:38:35 +0000674}
675
kate.ward18d456e2008-11-14 00:46:44 +0000676# Parse command-line options using the standard getopt.
677#
678# Note: the flag options are passed around in the global __flags_opts so that
679# the formatting is not lost due to shell parsing and such.
680#
681# Args:
682# @: varies: command-line options to parse
683# Returns:
684# integer: a FLAGS success condition
Kate Ward271a12c2017-10-18 00:52:40 +0200685_flags_getoptStandard() {
kate.ward60c25982008-11-12 20:12:44 +0000686 flags_return=${FLAGS_TRUE}
687 _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
688
Kate Ward638ed782017-10-21 21:29:59 +0200689 # Check for spaces in passed options.
kate.ward60c25982008-11-12 20:12:44 +0000690 for _flags_opt_ in "$@"; do
Kate Ward638ed782017-10-21 21:29:59 +0200691 # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06.
kate.ward14b33bf2008-11-15 20:03:18 +0000692 _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'`
693 if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then
kate.ward60c25982008-11-12 20:12:44 +0000694 flags_error='the available getopt does not support spaces in options'
695 flags_return=${FLAGS_ERROR}
696 break
697 fi
698 done
699
700 if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
Kate Ward271a12c2017-10-18 00:52:40 +0200701 __flags_opts=`getopt "${_flags_shortOpts_}" "$@" 2>&1`
kate.ward7a3c9c42009-04-24 00:12:35 +0000702 _flags_rtrn_=$?
703 if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
704 _flags_warn "${__flags_opts}"
kate.ward60c25982008-11-12 20:12:44 +0000705 flags_error='unable to parse provided options with getopt.'
706 flags_return=${FLAGS_ERROR}
707 fi
708 fi
709
kate.ward7a3c9c42009-04-24 00:12:35 +0000710 unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_
kate.ward60c25982008-11-12 20:12:44 +0000711 return ${flags_return}
712}
713
kate.ward18d456e2008-11-14 00:46:44 +0000714# Parse command-line options using the enhanced getopt.
715#
716# Note: the flag options are passed around in the global __flags_opts so that
717# the formatting is not lost due to shell parsing and such.
718#
719# Args:
720# @: varies: command-line options to parse
721# Returns:
722# integer: a FLAGS success condition
Kate Ward271a12c2017-10-18 00:52:40 +0200723_flags_getoptEnhanced() {
kate.ward60c25982008-11-12 20:12:44 +0000724 flags_return=${FLAGS_TRUE}
725 _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
726 _flags_boolOpts_=`echo "${__flags_boolNames}" \
kate.wardd9672402008-11-15 16:55:51 +0000727 |sed 's/^ *//;s/ *$//;s/ /,/g'`
kate.ward60c25982008-11-12 20:12:44 +0000728 _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}`
729
kate.ward1cb79602011-06-10 11:15:49 +0000730 __flags_opts=`${FLAGS_GETOPT_CMD} \
Kate Ward271a12c2017-10-18 00:52:40 +0200731 -o "${_flags_shortOpts_}" \
kate.ward60c25982008-11-12 20:12:44 +0000732 -l "${_flags_longOpts_},${_flags_boolOpts_}" \
733 -- "$@" 2>&1`
kate.ward7a3c9c42009-04-24 00:12:35 +0000734 _flags_rtrn_=$?
735 if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
736 _flags_warn "${__flags_opts}"
kate.ward60c25982008-11-12 20:12:44 +0000737 flags_error='unable to parse provided options with getopt.'
738 flags_return=${FLAGS_ERROR}
739 fi
740
kate.ward7a3c9c42009-04-24 00:12:35 +0000741 unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_
kate.ward60c25982008-11-12 20:12:44 +0000742 return ${flags_return}
743}
744
kate.ward18d456e2008-11-14 00:46:44 +0000745# Dynamically parse a getopt result and set appropriate variables.
746#
747# This function does the actual conversion of getopt output and runs it through
748# the standard case structure for parsing. The case structure is actually quite
749# dynamic to support any number of flags.
750#
751# Args:
752# @: varies: output from getopt parsing
753# Returns:
754# integer: a FLAGS success condition
Kate Ward271a12c2017-10-18 00:52:40 +0200755_flags_parseGetopt() {
kate.ward60c25982008-11-12 20:12:44 +0000756 flags_return=${FLAGS_TRUE}
757
Kate Ward638ed782017-10-21 21:29:59 +0200758 if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then
Kate Ward271a12c2017-10-18 00:52:40 +0200759 # The @$ must be unquoted as it needs to be re-split.
760 # shellcheck disable=SC2068
kate.ward60c25982008-11-12 20:12:44 +0000761 set -- $@
762 else
Kate Ward46e081e2020-04-13 23:51:43 +0200763 # Note the quotes around the `$@` -- they are essential!
kate.ward60c25982008-11-12 20:12:44 +0000764 eval set -- "$@"
765 fi
766
Kate Ward47237bc2017-10-21 21:37:34 +0200767 # Handle options. note options with values must do an additional shift.
kate.ward60c25982008-11-12 20:12:44 +0000768 while true; do
769 _flags_opt_=$1
770 _flags_arg_=${2:-}
771 _flags_type_=${__FLAGS_TYPE_NONE}
kate.ward7a3c9c42009-04-24 00:12:35 +0000772 _flags_name_=''
kate.ward60c25982008-11-12 20:12:44 +0000773
Kate Ward638ed782017-10-21 21:29:59 +0200774 # Determine long flag name.
kate.ward60c25982008-11-12 20:12:44 +0000775 case "${_flags_opt_}" in
Kate Ward638ed782017-10-21 21:29:59 +0200776 --) shift; break ;; # Discontinue option parsing.
kate.ward60c25982008-11-12 20:12:44 +0000777
Kate Ward638ed782017-10-21 21:29:59 +0200778 --*) # Long option.
kate.wardc85fa862013-01-14 21:33:11 +0000779 if _flags_useBuiltin; then
780 _flags_opt_=${_flags_opt_#*--}
781 else
Kate Ward61ed6592017-08-17 15:20:11 +0200782 _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '--\(.*\)'`
kate.wardc85fa862013-01-14 21:33:11 +0000783 fi
kate.ward60c25982008-11-12 20:12:44 +0000784 _flags_len_=${__FLAGS_LEN_LONG}
Kate Ward271a12c2017-10-18 00:52:40 +0200785 if _flags_itemInList "${_flags_opt_}" "${__flags_longNames}"; then
kate.ward60c25982008-11-12 20:12:44 +0000786 _flags_name_=${_flags_opt_}
787 else
Kate Ward271a12c2017-10-18 00:52:40 +0200788 # Check for negated long boolean version.
789 if _flags_itemInList "${_flags_opt_}" "${__flags_boolNames}"; then
kate.wardc85fa862013-01-14 21:33:11 +0000790 if _flags_useBuiltin; then
791 _flags_name_=${_flags_opt_#*no}
792 else
Kate Ward61ed6592017-08-17 15:20:11 +0200793 _flags_name_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : 'no\(.*\)'`
kate.wardc85fa862013-01-14 21:33:11 +0000794 fi
kate.ward60c25982008-11-12 20:12:44 +0000795 _flags_type_=${__FLAGS_TYPE_BOOLEAN}
796 _flags_arg_=${__FLAGS_NULL}
797 fi
798 fi
799 ;;
800
Kate Ward271a12c2017-10-18 00:52:40 +0200801 -*) # Short option.
kate.wardc85fa862013-01-14 21:33:11 +0000802 if _flags_useBuiltin; then
803 _flags_opt_=${_flags_opt_#*-}
804 else
Kate Ward61ed6592017-08-17 15:20:11 +0200805 _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '-\(.*\)'`
kate.wardc85fa862013-01-14 21:33:11 +0000806 fi
kate.ward60c25982008-11-12 20:12:44 +0000807 _flags_len_=${__FLAGS_LEN_SHORT}
Kate Ward271a12c2017-10-18 00:52:40 +0200808 if _flags_itemInList "${_flags_opt_}" "${__flags_shortNames}"; then
809 # Yes. Match short name to long name. Note purposeful off-by-one
kate.ward60c25982008-11-12 20:12:44 +0000810 # (too high) with awk calculations.
811 _flags_pos_=`echo "${__flags_shortNames}" \
812 |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
Kate Ward271a12c2017-10-18 00:52:40 +0200813 e="${_flags_opt_}"`
kate.ward60c25982008-11-12 20:12:44 +0000814 _flags_name_=`echo "${__flags_longNames}" \
815 |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
816 fi
817 ;;
818 esac
819
Kate Ward271a12c2017-10-18 00:52:40 +0200820 # Die if the flag was unrecognized.
kate.ward60c25982008-11-12 20:12:44 +0000821 if [ -z "${_flags_name_}" ]; then
822 flags_error="unrecognized option (${_flags_opt_})"
823 flags_return=${FLAGS_ERROR}
824 break
825 fi
826
Kate Ward271a12c2017-10-18 00:52:40 +0200827 # Set new flag value.
828 _flags_usName_=`_flags_underscoreName "${_flags_name_}"`
kate.ward60c25982008-11-12 20:12:44 +0000829 [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \
kate.wardd9672402008-11-15 16:55:51 +0000830 _flags_type_=`_flags_getFlagInfo \
kate.wardda8d2c02011-06-28 13:26:02 +0000831 "${_flags_usName_}" ${__FLAGS_INFO_TYPE}`
kate.ward60c25982008-11-12 20:12:44 +0000832 case ${_flags_type_} in
833 ${__FLAGS_TYPE_BOOLEAN})
834 if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
835 if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
kate.wardda8d2c02011-06-28 13:26:02 +0000836 eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}"
kate.ward60c25982008-11-12 20:12:44 +0000837 else
kate.wardda8d2c02011-06-28 13:26:02 +0000838 eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}"
kate.ward60c25982008-11-12 20:12:44 +0000839 fi
840 else
841 _flags_strToEval_="_flags_val_=\
kate.wardda8d2c02011-06-28 13:26:02 +0000842\${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}"
kate.ward60c25982008-11-12 20:12:44 +0000843 eval "${_flags_strToEval_}"
Kate Ward271a12c2017-10-18 00:52:40 +0200844 # shellcheck disable=SC2154
845 if [ "${_flags_val_}" -eq ${FLAGS_FALSE} ]; then
kate.wardda8d2c02011-06-28 13:26:02 +0000846 eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}"
kate.ward60c25982008-11-12 20:12:44 +0000847 else
kate.wardda8d2c02011-06-28 13:26:02 +0000848 eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}"
kate.ward60c25982008-11-12 20:12:44 +0000849 fi
850 fi
851 ;;
852
853 ${__FLAGS_TYPE_FLOAT})
kate.ward74178272013-01-14 22:17:05 +0000854 if _flags_validFloat "${_flags_arg_}"; then
kate.wardda8d2c02011-06-28 13:26:02 +0000855 eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
kate.ward60c25982008-11-12 20:12:44 +0000856 else
857 flags_error="invalid float value (${_flags_arg_})"
858 flags_return=${FLAGS_ERROR}
859 break
860 fi
861 ;;
862
863 ${__FLAGS_TYPE_INTEGER})
kate.wardc66a5fc2013-01-12 23:10:15 +0000864 if _flags_validInt "${_flags_arg_}"; then
kate.wardda8d2c02011-06-28 13:26:02 +0000865 eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
kate.ward60c25982008-11-12 20:12:44 +0000866 else
867 flags_error="invalid integer value (${_flags_arg_})"
868 flags_return=${FLAGS_ERROR}
869 break
870 fi
871 ;;
872
873 ${__FLAGS_TYPE_STRING})
kate.wardda8d2c02011-06-28 13:26:02 +0000874 eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
kate.ward60c25982008-11-12 20:12:44 +0000875 ;;
876 esac
877
Kate Ward271a12c2017-10-18 00:52:40 +0200878 # Handle special case help flag.
kate.wardda8d2c02011-06-28 13:26:02 +0000879 if [ "${_flags_usName_}" = 'help' ]; then
Kate Ward271a12c2017-10-18 00:52:40 +0200880 # shellcheck disable=SC2154
881 if [ "${FLAGS_help}" -eq ${FLAGS_TRUE} ]; then
kate.ward5b48fc12008-11-13 00:42:43 +0000882 flags_help
883 flags_error='help requested'
Kate Ward16e8d0d2017-10-21 19:45:29 +0200884 flags_return=${FLAGS_FALSE}
kate.ward5b48fc12008-11-13 00:42:43 +0000885 break
886 fi
887 fi
888
Kate Ward271a12c2017-10-18 00:52:40 +0200889 # Shift the option and non-boolean arguments out.
kate.ward60c25982008-11-12 20:12:44 +0000890 shift
Kate Ward271a12c2017-10-18 00:52:40 +0200891 [ "${_flags_type_}" != ${__FLAGS_TYPE_BOOLEAN} ] && shift
kate.wardc5210682009-03-30 18:54:36 +0000892 done
kate.ward60c25982008-11-12 20:12:44 +0000893
Kate Ward271a12c2017-10-18 00:52:40 +0200894 # Give user back non-flag arguments.
kate.wardc5210682009-03-30 18:54:36 +0000895 FLAGS_ARGV=''
896 while [ $# -gt 0 ]; do
897 FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
898 shift
kate.ward60c25982008-11-12 20:12:44 +0000899 done
900
901 unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \
kate.wardda8d2c02011-06-28 13:26:02 +0000902 _flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_
kate.ward60c25982008-11-12 20:12:44 +0000903 return ${flags_return}
904}
905
kate.wardb0759202013-01-05 13:57:46 +0000906# Perform some path using built-ins.
907#
908# Args:
909# $@: string: math expression to evaluate
kate.wardc85fa862013-01-14 21:33:11 +0000910# Output:
911# integer: the result
kate.wardb0759202013-01-05 13:57:46 +0000912# Returns:
kate.wardc85fa862013-01-14 21:33:11 +0000913# bool: success of math evaluation
Kate Ward61ed6592017-08-17 15:20:11 +0200914_flags_math() {
kate.ward74178272013-01-14 22:17:05 +0000915 if [ $# -eq 0 ]; then
916 flags_return=${FLAGS_FALSE}
917 elif _flags_useBuiltin; then
kate.wardc85fa862013-01-14 21:33:11 +0000918 # Variable assignment is needed as workaround for Solaris Bourne shell,
919 # which cannot parse a bare $((expression)).
Kate Ward271a12c2017-10-18 00:52:40 +0200920 # shellcheck disable=SC2016
kate.wardc85fa862013-01-14 21:33:11 +0000921 _flags_expr_='$(($@))'
922 eval echo ${_flags_expr_}
kate.ward74178272013-01-14 22:17:05 +0000923 flags_return=$?
924 unset _flags_expr_
925 else
Kate Ward271a12c2017-10-18 00:52:40 +0200926 eval expr "$@"
kate.ward74178272013-01-14 22:17:05 +0000927 flags_return=$?
kate.wardc85fa862013-01-14 21:33:11 +0000928 fi
kate.wardc85fa862013-01-14 21:33:11 +0000929
kate.wardc85fa862013-01-14 21:33:11 +0000930 return ${flags_return}
931}
932
933# Cross-platform strlen() implementation.
934#
935# Args:
936# _flags_str: string: to determine length of
937# Output:
938# integer: length of string
939# Returns:
940# bool: success of strlen evaluation
Kate Ward271a12c2017-10-18 00:52:40 +0200941_flags_strlen() {
kate.wardc85fa862013-01-14 21:33:11 +0000942 _flags_str_=${1:-}
943
944 if [ -z "${_flags_str_}" ]; then
945 flags_output=0
kate.wardc85fa862013-01-14 21:33:11 +0000946 elif _flags_useBuiltin; then
947 flags_output=${#_flags_str_}
kate.wardc85fa862013-01-14 21:33:11 +0000948 else
Kate Ward61ed6592017-08-17 15:20:11 +0200949 flags_output=`${FLAGS_EXPR_CMD} "${_flags_str_}" : '.*'`
kate.wardc85fa862013-01-14 21:33:11 +0000950 fi
kate.ward74178272013-01-14 22:17:05 +0000951 flags_return=$?
kate.wardc85fa862013-01-14 21:33:11 +0000952
953 unset _flags_str_
Kate Ward271a12c2017-10-18 00:52:40 +0200954 echo "${flags_output}"
kate.wardc85fa862013-01-14 21:33:11 +0000955 return ${flags_return}
kate.wardb0759202013-01-05 13:57:46 +0000956}
957
kate.wardc66a5fc2013-01-12 23:10:15 +0000958# Use built-in helper function to enable unit testing.
kate.wardb0759202013-01-05 13:57:46 +0000959#
960# Args:
kate.wardc66a5fc2013-01-12 23:10:15 +0000961# None
kate.wardb0759202013-01-05 13:57:46 +0000962# Returns:
kate.wardc66a5fc2013-01-12 23:10:15 +0000963# bool: true if built-ins should be used
Kate Ward1c2ca7f2017-08-09 09:19:08 +0200964_flags_useBuiltin() { return ${__FLAGS_USE_BUILTIN}; }
kate.wardb0759202013-01-05 13:57:46 +0000965
kate.wardf51c6162008-06-17 16:38:35 +0000966#------------------------------------------------------------------------------
967# public functions
Peter van der Does4f2f26e2016-03-05 20:29:42 -0500968#
kate.wardf51c6162008-06-17 16:38:35 +0000969# A basic boolean flag. Boolean flags do not take any arguments, and their
970# value is either 1 (false) or 0 (true). For long flags, the false value is
971# specified on the command line by prepending the word 'no'. With short flags,
Kate Wardc7ed8182017-08-07 17:51:50 +0200972# the presence of the flag toggles the current value between true and false.
kate.wardf51c6162008-06-17 16:38:35 +0000973# Specifying a short boolean flag twice on the command results in returning the
974# value back to the default value.
975#
976# A default value is required for boolean flags.
977#
978# For example, lets say a Boolean flag was created whose long name was 'update'
979# and whose short name was 'x', and the default value was 'false'. This flag
980# could be explicitly set to 'true' with '--update' or by '-x', and it could be
981# explicitly set to 'false' with '--noupdate'.
982DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }
983
984# Other basic flags.
985DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; }
986DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
987DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; }
988
989# Parse the flags.
990#
991# Args:
992# unnamed: list: command-line flags to parse
993# Returns:
994# integer: success of operation, or error
Kate Wardf9a3d772017-10-16 23:31:48 +0200995FLAGS() {
996 # Define a standard 'help' flag if one isn't already defined.
Kate Wardc8259732020-04-11 20:22:47 +0200997 if [ -z "${__flags_help_type:-}" ]; then
998 DEFINE_boolean 'help' false 'show this help' 'h'
999 fi
kate.wardf08c5b62008-07-11 20:32:11 +00001000
Kate Wardf9a3d772017-10-16 23:31:48 +02001001 # Parse options.
kate.ward7a3c9c42009-04-24 00:12:35 +00001002 if [ $# -gt 0 ]; then
Kate Ward638ed782017-10-21 21:29:59 +02001003 if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then
kate.ward7a3c9c42009-04-24 00:12:35 +00001004 _flags_getoptStandard "$@"
1005 else
1006 _flags_getoptEnhanced "$@"
1007 fi
1008 flags_return=$?
kate.wardf51c6162008-06-17 16:38:35 +00001009 else
Kate Wardf9a3d772017-10-16 23:31:48 +02001010 # Nothing passed; won't bother running getopt.
kate.ward7a3c9c42009-04-24 00:12:35 +00001011 __flags_opts='--'
1012 flags_return=${FLAGS_TRUE}
kate.wardf51c6162008-06-17 16:38:35 +00001013 fi
kate.ward60c25982008-11-12 20:12:44 +00001014
1015 if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
Kate Ward46e081e2020-04-13 23:51:43 +02001016 _flags_parseGetopt "${__flags_opts}"
kate.ward60c25982008-11-12 20:12:44 +00001017 flags_return=$?
kate.wardf51c6162008-06-17 16:38:35 +00001018 fi
1019
Kate Wardc8259732020-04-11 20:22:47 +02001020 if [ ${flags_return} -eq ${FLAGS_ERROR} ]; then
1021 _flags_fatal "${flags_error}"
1022 fi
kate.wardf51c6162008-06-17 16:38:35 +00001023 return ${flags_return}
1024}
1025
kate.ward1cb79602011-06-10 11:15:49 +00001026# This is a helper function for determining the 'getopt' version for platforms
kate.wardf51c6162008-06-17 16:38:35 +00001027# where the detection isn't working. It simply outputs debug information that
1028# can be included in a bug report.
1029#
1030# Args:
1031# none
kate.ward60c25982008-11-12 20:12:44 +00001032# Output:
1033# debug info that can be included in a bug report
kate.wardf51c6162008-06-17 16:38:35 +00001034# Returns:
1035# nothing
Kate Ward271a12c2017-10-18 00:52:40 +02001036flags_getoptInfo() {
Kate Ward47237bc2017-10-21 21:37:34 +02001037 # Platform info.
kate.wardf51c6162008-06-17 16:38:35 +00001038 _flags_debug "uname -a: `uname -a`"
1039 _flags_debug "PATH: ${PATH}"
1040
Kate Ward47237bc2017-10-21 21:37:34 +02001041 # Shell info.
kate.wardf51c6162008-06-17 16:38:35 +00001042 if [ -n "${BASH_VERSION:-}" ]; then
1043 _flags_debug 'shell: bash'
1044 _flags_debug "BASH_VERSION: ${BASH_VERSION}"
1045 elif [ -n "${ZSH_VERSION:-}" ]; then
1046 _flags_debug 'shell: zsh'
1047 _flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
1048 fi
1049
Kate Ward47237bc2017-10-21 21:37:34 +02001050 # getopt info.
kate.ward1cb79602011-06-10 11:15:49 +00001051 ${FLAGS_GETOPT_CMD} >/dev/null
kate.ward60c25982008-11-12 20:12:44 +00001052 _flags_getoptReturn=$?
1053 _flags_debug "getopt return: ${_flags_getoptReturn}"
kate.ward1cb79602011-06-10 11:15:49 +00001054 _flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`"
kate.wardf51c6162008-06-17 16:38:35 +00001055
kate.ward60c25982008-11-12 20:12:44 +00001056 unset _flags_getoptReturn
kate.wardf51c6162008-06-17 16:38:35 +00001057}
1058
kate.ward437639d2008-10-19 17:21:41 +00001059# Returns whether the detected getopt version is the enhanced version.
kate.wardf51c6162008-06-17 16:38:35 +00001060#
1061# Args:
1062# none
kate.ward60c25982008-11-12 20:12:44 +00001063# Output:
1064# none
kate.wardf51c6162008-06-17 16:38:35 +00001065# Returns:
1066# bool: true if getopt is the enhanced version
Kate Ward271a12c2017-10-18 00:52:40 +02001067flags_getoptIsEnh() {
Kate Ward16a3af22020-03-30 00:09:16 +02001068 test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}"
kate.wardf51c6162008-06-17 16:38:35 +00001069}
1070
kate.ward437639d2008-10-19 17:21:41 +00001071# Returns whether the detected getopt version is the standard version.
kate.wardf51c6162008-06-17 16:38:35 +00001072#
1073# Args:
1074# none
1075# Returns:
1076# bool: true if getopt is the standard version
Kate Ward271a12c2017-10-18 00:52:40 +02001077flags_getoptIsStd() {
Kate Ward16a3af22020-03-30 00:09:16 +02001078 test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}"
kate.wardf51c6162008-06-17 16:38:35 +00001079}
1080
1081# This is effectively a 'usage()' function. It prints usage information and
1082# exits the program with ${FLAGS_FALSE} if it is ever found in the command line
1083# arguments. Note this function can be overridden so other apps can define
1084# their own --help flag, replacing this one, if they want.
1085#
1086# Args:
1087# none
1088# Returns:
1089# integer: success of operation (always returns true)
Kate Ward271a12c2017-10-18 00:52:40 +02001090flags_help() {
kate.wardf51c6162008-06-17 16:38:35 +00001091 if [ -n "${FLAGS_HELP:-}" ]; then
1092 echo "${FLAGS_HELP}" >&2
1093 else
kate.ward4d8e0472008-07-18 11:52:56 +00001094 echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2
kate.wardf51c6162008-06-17 16:38:35 +00001095 fi
1096 if [ -n "${__flags_longNames}" ]; then
1097 echo 'flags:' >&2
kate.wardd9672402008-11-15 16:55:51 +00001098 for flags_name_ in ${__flags_longNames}; do
1099 flags_flagStr_=''
kate.wardbda39172009-04-01 03:30:22 +00001100 flags_boolStr_=''
Kate Ward271a12c2017-10-18 00:52:40 +02001101 flags_usName_=`_flags_underscoreName "${flags_name_}"`
kate.wardf51c6162008-06-17 16:38:35 +00001102
kate.wardd9672402008-11-15 16:55:51 +00001103 flags_default_=`_flags_getFlagInfo \
kate.wardda8d2c02011-06-28 13:26:02 +00001104 "${flags_usName_}" ${__FLAGS_INFO_DEFAULT}`
kate.wardd9672402008-11-15 16:55:51 +00001105 flags_help_=`_flags_getFlagInfo \
kate.wardda8d2c02011-06-28 13:26:02 +00001106 "${flags_usName_}" ${__FLAGS_INFO_HELP}`
kate.wardd9672402008-11-15 16:55:51 +00001107 flags_short_=`_flags_getFlagInfo \
kate.wardda8d2c02011-06-28 13:26:02 +00001108 "${flags_usName_}" ${__FLAGS_INFO_SHORT}`
kate.wardd9672402008-11-15 16:55:51 +00001109 flags_type_=`_flags_getFlagInfo \
kate.wardda8d2c02011-06-28 13:26:02 +00001110 "${flags_usName_}" ${__FLAGS_INFO_TYPE}`
kate.wardf51c6162008-06-17 16:38:35 +00001111
kate.ward1cb79602011-06-10 11:15:49 +00001112 [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
1113 flags_flagStr_="-${flags_short_}"
kate.ward437639d2008-10-19 17:21:41 +00001114
Kate Ward638ed782017-10-21 21:29:59 +02001115 if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}" ]; then
kate.ward1cb79602011-06-10 11:15:49 +00001116 [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
1117 flags_flagStr_="${flags_flagStr_},"
Kate Ward47237bc2017-10-21 21:37:34 +02001118 # Add [no] to long boolean flag names, except the 'help' flag.
Kate Ward271a12c2017-10-18 00:52:40 +02001119 [ "${flags_type_}" -eq ${__FLAGS_TYPE_BOOLEAN} \
kate.wardda8d2c02011-06-28 13:26:02 +00001120 -a "${flags_usName_}" != 'help' ] && \
kate.ward1cb79602011-06-10 11:15:49 +00001121 flags_boolStr_='[no]'
kate.wardd9672402008-11-15 16:55:51 +00001122 flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:"
kate.ward437639d2008-10-19 17:21:41 +00001123 fi
1124
kate.wardd9672402008-11-15 16:55:51 +00001125 case ${flags_type_} in
kate.ward437639d2008-10-19 17:21:41 +00001126 ${__FLAGS_TYPE_BOOLEAN})
Kate Ward271a12c2017-10-18 00:52:40 +02001127 if [ "${flags_default_}" -eq ${FLAGS_TRUE} ]; then
kate.wardd9672402008-11-15 16:55:51 +00001128 flags_defaultStr_='true'
kate.ward437639d2008-10-19 17:21:41 +00001129 else
kate.wardd9672402008-11-15 16:55:51 +00001130 flags_defaultStr_='false'
kate.ward437639d2008-10-19 17:21:41 +00001131 fi
1132 ;;
1133 ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER})
kate.wardd9672402008-11-15 16:55:51 +00001134 flags_defaultStr_=${flags_default_} ;;
1135 ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;;
kate.ward437639d2008-10-19 17:21:41 +00001136 esac
kate.wardd9672402008-11-15 16:55:51 +00001137 flags_defaultStr_="(default: ${flags_defaultStr_})"
kate.ward437639d2008-10-19 17:21:41 +00001138
Kate Ward3355cde2017-10-16 23:30:29 +02001139 flags_helpStr_=" ${flags_flagStr_} ${flags_help_:+${flags_help_} }${flags_defaultStr_}"
kate.wardc85fa862013-01-14 21:33:11 +00001140 _flags_strlen "${flags_helpStr_}" >/dev/null
1141 flags_helpStrLen_=${flags_output}
kate.ward14b33bf2008-11-15 20:03:18 +00001142 flags_columns_=`_flags_columns`
kate.wardc85fa862013-01-14 21:33:11 +00001143
Kate Ward271a12c2017-10-18 00:52:40 +02001144 if [ "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then
kate.wardd9672402008-11-15 16:55:51 +00001145 echo "${flags_helpStr_}" >&2
kate.ward437639d2008-10-19 17:21:41 +00001146 else
kate.ward64099612008-11-17 17:36:14 +00001147 echo " ${flags_flagStr_} ${flags_help_}" >&2
Kate Ward47237bc2017-10-21 21:37:34 +02001148 # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
kate.ward87b0c2e2009-04-01 03:48:16 +00001149 # because it doesn't like empty strings when used in this manner.
kate.wardbda39172009-04-01 03:30:22 +00001150 flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
1151 |awk '{printf "%"length($0)-2"s", ""}'`"
kate.ward64099612008-11-17 17:36:14 +00001152 flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}"
kate.wardc85fa862013-01-14 21:33:11 +00001153 _flags_strlen "${flags_helpStr_}" >/dev/null
1154 flags_helpStrLen_=${flags_output}
1155
Kate Ward638ed782017-10-21 21:29:59 +02001156 if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}" \
Kate Ward271a12c2017-10-18 00:52:40 +02001157 -o "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then
Kate Ward47237bc2017-10-21 21:37:34 +02001158 # Indented to match help string.
kate.ward64099612008-11-17 17:36:14 +00001159 echo "${flags_helpStr_}" >&2
1160 else
Kate Ward47237bc2017-10-21 21:37:34 +02001161 # Indented four from left to allow for longer defaults as long flag
1162 # names might be used too, making things too long.
kate.ward64099612008-11-17 17:36:14 +00001163 echo " ${flags_defaultStr_}" >&2
1164 fi
kate.ward437639d2008-10-19 17:21:41 +00001165 fi
kate.wardf51c6162008-06-17 16:38:35 +00001166 done
1167 fi
1168
kate.wardd9672402008-11-15 16:55:51 +00001169 unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \
1170 flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \
kate.wardda8d2c02011-06-28 13:26:02 +00001171 flags_columns_ flags_short_ flags_type_ flags_usName_
kate.wardf51c6162008-06-17 16:38:35 +00001172 return ${FLAGS_TRUE}
1173}
1174
kate.wardcecd7bd2009-05-10 17:56:13 +00001175# Reset shflags back to an uninitialized state.
kate.wardf51c6162008-06-17 16:38:35 +00001176#
1177# Args:
1178# none
1179# Returns:
1180# nothing
Kate Ward271a12c2017-10-18 00:52:40 +02001181flags_reset() {
kate.wardd9672402008-11-15 16:55:51 +00001182 for flags_name_ in ${__flags_longNames}; do
Kate Ward271a12c2017-10-18 00:52:40 +02001183 flags_usName_=`_flags_underscoreName "${flags_name_}"`
kate.ward869a71b2011-06-28 13:29:40 +00001184 flags_strToEval_="unset FLAGS_${flags_usName_}"
kate.wardd9672402008-11-15 16:55:51 +00001185 for flags_type_ in \
kate.wardcecd7bd2009-05-10 17:56:13 +00001186 ${__FLAGS_INFO_DEFAULT} \
kate.wardfb0e7182009-05-10 16:59:13 +00001187 ${__FLAGS_INFO_HELP} \
1188 ${__FLAGS_INFO_SHORT} \
1189 ${__FLAGS_INFO_TYPE}
kate.wardf51c6162008-06-17 16:38:35 +00001190 do
kate.wardd9672402008-11-15 16:55:51 +00001191 flags_strToEval_=\
kate.ward869a71b2011-06-28 13:29:40 +00001192"${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}"
kate.wardf51c6162008-06-17 16:38:35 +00001193 done
Kate Ward271a12c2017-10-18 00:52:40 +02001194 eval "${flags_strToEval_}"
kate.wardf51c6162008-06-17 16:38:35 +00001195 done
1196
Kate Warddc385d52017-08-04 20:47:11 +02001197 # Reset internal variables.
kate.wardf51c6162008-06-17 16:38:35 +00001198 __flags_boolNames=' '
1199 __flags_longNames=' '
1200 __flags_shortNames=' '
kate.wardda8d2c02011-06-28 13:26:02 +00001201 __flags_definedNames=' '
kate.wardf51c6162008-06-17 16:38:35 +00001202
Kate Warddc385d52017-08-04 20:47:11 +02001203 # Reset logging level back to default.
1204 flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT}
1205
kate.ward869a71b2011-06-28 13:29:40 +00001206 unset flags_name_ flags_type_ flags_strToEval_ flags_usName_
kate.wardf51c6162008-06-17 16:38:35 +00001207}
Kate Warddc385d52017-08-04 20:47:11 +02001208
Kate Wardd368f832020-04-09 10:53:53 +02001209#-----------------------------------------------------------------------------
Kate Warddc385d52017-08-04 20:47:11 +02001210# Initialization
1211#
1212
1213# Set the default logging level.
1214flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT}