File gitflow-shFlags in this repository appears corrupted #295

Open
DougHockin opened this Issue Jan 31, 2013 · 7 comments

Comments

Projects
None yet
3 participants
@DougHockin

The file gitflow-shFlags located here (this repostitory) which used to be some 30K in size is now only 19 chars long (contents: shFlags/src/shflags). When I run any of the gitflow scripts I get this error:

$ git flow help
C:/cygwin/usr/local/bin/gitflow-shFlags: line 1: shFlags/src/shflags: No such file or directory
C:\cygwin\usr\local\bin\git-flow: line 85: DEFINE_boolean: command not found
C:\cygwin\usr\local\bin\git-flow: line 88: FLAGS: command not found
fatal: 'flow' appears to be a git command, but we were not
able to execute it. Maybe git-flow is broken?

@petervanderdoes

This comment has been minimized.

Show comment Hide comment
@petervanderdoes

petervanderdoes Feb 1, 2013

What's the content of gitflow-shFlags?

What's the content of gitflow-shFlags?

@DougHockin

This comment has been minimized.

Show comment Hide comment
@DougHockin

DougHockin Feb 1, 2013

I don't see a way to attach a file so...

$Id$

vim:et:ft=sh:sts=2:sw=2

Copyright 2008 Kate Ward. All Rights Reserved.

Released under the LGPL (GNU Lesser General Public License)

shFlags -- Advanced command-line flag library for Unix shell scripts.

http://code.google.com/p/shflags/

Author: kate.ward@forestent.com (Kate Ward)

This module implements something like the google-gflags library available

from http://code.google.com/p/google-gflags/.

FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take

a name, default value, help-string, and optional 'short' name (one-letter

name). Some flags have other arguments, which are described with the flag.

DEFINE_string: takes any input, and intreprets it as a string.

DEFINE_boolean: typically does not take any argument: say --myflag to set

FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false.

Alternately, you can say

--myflag=true or --myflag=t or --myflag=0 or

--myflag=false or --myflag=f or --myflag=1

Passing an option has the same affect as passing the option once.

DEFINE_float: takes an input and intreprets it as a floating point number. As

shell does not support floats per-se, the input is merely validated as

being a valid floating point value.

DEFINE_integer: takes an input and intreprets it as an integer.

SPECIAL FLAGS: There are a few flags that have special meaning:

--help (or -?) prints a list of all the flags in a human-readable fashion

--flagfile=foo read flags from foo. (not implemented yet)

-- as in getopt(), terminates flag-processing

EXAMPLE USAGE:

-- begin hello.sh --

#! /bin/sh

. ./shflags

DEFINE_string name 'world' "somebody's name" n

FLAGS "$@" || exit $?

eval set -- "${FLAGS_ARGV}"

echo "Hello, ${FLAGS_name}."

-- end hello.sh --

$ ./hello.sh -n Kate

Hello, Kate.

NOTE: Not all systems include a getopt version that supports long flags. On

these systems, only short flags are recognized.

#==============================================================================

shFlags

Shared attributes:

flags_error: last error message

flags_return: last return value

__flags_longNames: list of long names for all flags

__flags_shortNames: list of short names for all flags

__flags_boolNames: list of boolean flag names

__flags_opts: options parsed by getopt

Per-flag attributes:

FLAGS_<flag_name>: contains value of flag named 'flag_name'

_flags<flag_name>_default: the default flag value

_flags<flag_name>_help: the flag help string

_flags<flag_name>_short: the flag short name

_flags<flag_name>_type: the flag type

Notes:

- lists of strings are space separated, and a null value is the '~' char.

return if FLAGS already loaded

[ -n "${FLAGS_VERSION:-}" ] && return 0
FLAGS_VERSION='1.0.3'

return values

FLAGS_TRUE=0
FLAGS_FALSE=1
FLAGS_ERROR=2

reserved flag names

FLAGS_RESERVED='ARGC ARGV ERROR FALSE HELP PARENT RESERVED TRUE VERSION'

_flags_debug() { echo "flags:DEBUG $@" >&2; }
_flags_warn() { echo "flags:WARN $@" >&2; }
_flags_error() { echo "flags:ERROR $@" >&2; }
_flags_fatal() { echo "flags:FATAL $@" >&2; }

specific shell checks

if [ -n "${ZSH_VERSION:-}" ]; then
setopt |grep "^shwordsplit$" >/dev/null
if [ $? -ne ${FLAGS_TRUE} ]; then
_flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
exit ${FLAGS_ERROR}
fi
if [ -z "${FLAGS_PARENT:-}" ]; then
_flags_fatal "zsh does not pass $0 through properly. please declare'
"FLAGS_PARENT=$0" before calling shFlags"
exit ${FLAGS_ERROR}
fi
fi

constants

getopt version

__FLAGS_GETOPT_VERS_STD=0
__FLAGS_GETOPT_VERS_ENH=1
__FLAGS_GETOPT_VERS_BSD=2

getopt >/dev/null 2>&1
case $? in
0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt
2)
# TODO(kward): look into '-T' option to test the internal getopt() version
if [ "getopt --version" = '-- ' ]; then
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD}
else
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
fi
;;
*)
_flags_fatal 'unable to determine getopt version'
exit ${FLAGS_ERROR}
;;
esac

getopt optstring lengths

__FLAGS_OPTSTR_SHORT=0
__FLAGS_OPTSTR_LONG=1

__FLAGS_NULL='~'

flag info strings

__FLAGS_INFO_DEFAULT='default'
__FLAGS_INFO_HELP='help'
__FLAGS_INFO_SHORT='short'
__FLAGS_INFO_TYPE='type'

flag lengths

__FLAGS_LEN_SHORT=0
__FLAGS_LEN_LONG=1

flag types

__FLAGS_TYPE_NONE=0
__FLAGS_TYPE_BOOLEAN=1
__FLAGS_TYPE_FLOAT=2
__FLAGS_TYPE_INTEGER=3
__FLAGS_TYPE_STRING=4

set the constants readonly

__flags_constants=set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'
for __flags_const in ${__flags_constants}; do

skip certain flags

case ${__flags_const} in
FLAGS_HELP) continue ;;
FLAGS_PARENT) continue ;;
esac

set flag readonly

if [ -z "${ZSH_VERSION:-}" ]; then
readonly ${__flags_const}
else # handle zsh
case ${ZSH_VERSION} in
[123].*) readonly ${__flags_const} ;;
*) readonly -g ${__flags_const} ;; # declare readonly constants globally
esac
fi
done
unset __flags_const __flags_constants

internal variables

__flags_boolNames=' ' # space separated list of boolean flag names
__flags_longNames=' ' # space separated list of long flag names
__flags_shortNames=' ' # space separated list of short flag names

__flags_columns='' # screen width in columns
__flags_opts='' # temporary storage for parsed getopt flags

#------------------------------------------------------------------------------

private functions

Define a flag.

Calling this function will define the following info variables for the

specified flag:

FLAGS_flagname - the name for this flag (based upon the long flag name)

_flags<flag_name>_default - the default value

__flags_flagname_help - the help string

__flags_flagname_short - the single letter alias

__flags_flagname_type - the type of flag (one of _FLAGS_TYPE*)

Args:

_flags__type: integer: internal type of flag (_FLAGS_TYPE*)

_flags__name: string: long flag name

_flags__default: default flag value

_flags__help: string: help string

_flags__short: string: (optional) short flag name

Returns:

integer: success of operation, or error

_flags_define()
{
if [ $# -lt 4 ]; then
flags_error='DEFINE error: too few arguments'
flags_return=${FLAGS_ERROR}
_flags_error "${flags_error}"
return ${flags_return}
fi

flags_type=$1
flags_name=$2
flags_default=$3
flags_help=$4
flags_short=${5:-${__FLAGS_NULL}}

flags_return=${FLAGS_TRUE}

TODO(kward): check for validity of the flag name (e.g. dashes)

check whether the flag name is reserved

echo " ${FLAGS_RESERVED} " |grep " ${flags_name} " >/dev/null
if [ $? -eq 0 ]; then
flags_error="flag name (${flags_name}) is reserved"
flags_return=${FLAGS_ERROR}
fi

require short option for getopt that don't support long options

if [ ${flags_return} -eq ${FLAGS_TRUE}
-a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH}
-a "${flags_short}" = "${__FLAGS_NULL}" ]
then
flags_error="short flag required for (${flags_name}) on this platform"
flags_return=${FLAGS_ERROR}
fi

check for existing long name definition

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
if _flags_itemInList "${flags_name}"
${__flags_longNames} ${__flags_boolNames}
then
flags_error="flag name ([no]${flags_name}) already defined"
_flags_warn "${flags_error}"
flags_return=${FLAGS_FALSE}
fi
fi

check for existing short name definition

if [ ${flags_return} -eq ${FLAGS_TRUE}
-a "${flags_short}" != "${__FLAGS_NULL}" ]
then
if _flags_itemInList "${flags_short}" ${__flags_shortNames}; then
flags_error="flag short name (${flags_short}) already defined"
_flags_warn "${flags_error}"
flags_return=${FLAGS_FALSE}
fi
fi

handle default value. note, on several occasions the 'if' portion of an

if/then/else contains just a ':' which does nothing. a binary reversal via

'!' is not done because it does not work on all shells.

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
case ${flags_type} in
${__FLAGS_TYPE_BOOLEAN})
if _flags_validateBoolean "${flags_default}"; then
case ${flags_default} in
true|t|0) flags_default=${FLAGS_TRUE} ;;
false|f|1) flags_default=${FLAGS_FALSE} ;;
esac
else
flags_error="invalid default flag value '${flags_default}'"
flags_return=${FLAGS_ERROR}
fi
;;

  ${__FLAGS_TYPE_FLOAT})
    if _flags_validateFloat "${_flags_default_}"; then
      :
    else
      flags_error="invalid default flag value '${_flags_default_}'"
      _flags_return_=${FLAGS_ERROR}
    fi
    ;;

  ${__FLAGS_TYPE_INTEGER})
    if _flags_validateInteger "${_flags_default_}"; then
      :
    else
      flags_error="invalid default flag value '${_flags_default_}'"
      _flags_return_=${FLAGS_ERROR}
    fi
    ;;

  ${__FLAGS_TYPE_STRING}) ;;  # everything in shell is a valid string

  *)
    flags_error="unrecognized flag type '${_flags_type_}'"
    _flags_return_=${FLAGS_ERROR}
    ;;
esac

fi

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
# store flag information
eval "FLAGS_${flags_name}='${flags_default}'"
eval "_flags${flags_name}${__FLAGS_INFO_TYPE}=${flags_type}"
eval "_flags${flags_name}
${__FLAGS_INFO_DEFAULT}=
"${flags_default}""
eval "_flags${flags_name}${__FLAGS_INFO_HELP}="${flags_help}""
eval "_flags${flags_name}
${__FLAGS_INFO_SHORT}='${flags_short}'"

# append flag name(s) to list of names
__flags_longNames="${__flags_longNames}${_flags_name_} "
__flags_shortNames="${__flags_shortNames}${_flags_short_} "
[ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
    __flags_boolNames="${__flags_boolNames}no${_flags_name_} "

fi

flags_return=${flags_return}
unset flags_default flags_help flags_name flags_return flags_short
flags_type
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}

Return valid getopt options using currently defined list of long options.

This function builds a proper getopt option string for short (and long)

options, using the current list of long options for reference.

Args:

_flags_optStr: integer: option string type (_FLAGS_OPTSTR*)

Output:

string: generated option string for getopt

Returns:

boolean: success of operation (always returns True)

_flags_genOptStr()
{
flags_optStrType=$1

flags_opts=''

for flags_flag in ${__flags_longNames}; do
flags_type=_flags_getFlagInfo ${_flags_flag_} ${__FLAGS_INFO_TYPE}
case ${flags_optStrType} in
${__FLAGS_OPTSTR_SHORT})
flags_shortName=_flags_getFlagInfo \ ${_flags_flag_} ${__FLAGS_INFO_SHORT}
if [ "${flags_shortName}" != "${__FLAGS_NULL}" ]; then
flags_opts="${flags_opts}${flags_shortName}"
# getopt needs a trailing ':' to indicate a required argument
[ ${flags_type} -ne ${__FLAGS_TYPE_BOOLEAN} ] &&
flags_opts="${flags_opts}:"
fi
;;

  ${__FLAGS_OPTSTR_LONG})
    _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}"
    # getopt needs a trailing ':' to indicate a required argument
    [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
        _flags_opts_="${_flags_opts_}:"
    ;;
esac

done

echo "${flags_opts}"
unset flags_flag flags_opts flags_optStrType flags_shortName
flags_type
return ${FLAGS_TRUE}
}

Returns flag details based on a flag name and flag info.

Args:

string: long flag name

string: flag info (see the _flags_define function for valid info types)

Output:

string: value of dereferenced flag variable

Returns:

integer: one of FLAGS_{TRUE|FALSE|ERROR}

_flags_getFlagInfo()
{
flags_name=$1
flags_info=$2

flags_nameVar="_flags${flags_name}_${flags_info}"
flags_strToEval="flags_value="${${flags_nameVar}:-}""
eval "${flags_strToEval}"
if [ -n "${flags_value}" ]; then
flags_return=${FLAGS_TRUE}
else
# see if the flags_name variable is a string as strings can be empty...
# note: the DRY principle would say to have this function call itself for
# the next three lines, but doing so results in an infinite loop as an
# invalid flags_name will also not have the associated _type variable.
# Because it doesn't (it will evaluate to an empty string) the logic will
# try to find the _type variable of the type variable, and so on. Not so
# good ;-)
flags_typeVar="_flags${flags_name}
${__FLAGS_INFO_TYPE}"
flags_strToEval="flags_type="${${flags_typeVar}:-}""
eval "${flags_strToEval}"
if [ "${flags_type}" = "${__FLAGS_TYPE_STRING}" ]; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_ERROR}
flags_error="invalid flag name (${flags_nameVar})"
fi
fi

echo "${flags_value}"
unset flags_info flags_name flags_strToEval flags_type flags_value
flags_nameVar flags_typeVar
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}

check for presense of item in a list. passed a string (e.g. 'abc'), this

function will determine if the string is present in the list of strings (e.g.

' foo bar abc ').

Args:

_flags__str: string: string to search for in a list of strings

unnamed: list: list of strings

Returns:

boolean: true if item is in the list

_flags_itemInList()
{
flags_str=$1
shift

echo " ${*:-} " |grep " ${flags_str} " >/dev/null
if [ $? -eq 0 ]; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_FALSE}
fi

unset flags_str
return ${flags_return}
}

Returns the width of the current screen.

Output:

integer: width in columns of the current screen.

_flags_columns()
{
if [ -z "${__flags_columns}" ]; then
# determine the value and store it
if eval stty size >/dev/null 2>&1; then
# stty size worked :-)
set -- stty size
__flags_columns=$2
elif eval tput cols >/dev/null 2>&1; then
set -- tput cols
__flags_columns=$1
else
__flags_columns=80 # default terminal width
fi
fi
echo ${__flags_columns}
}

Validate a boolean.

Args:

_flags__bool: boolean: value to validate

Returns:

bool: true if the value is a valid boolean

_flags_validateBoolean()
{
flags_bool=$1

flags_return=${FLAGS_TRUE}
case "${flags_bool}" in
true|t|0) ;;
false|f|1) ;;
*) flags_return=${FLAGS_FALSE} ;;
esac

unset flags_bool
return ${flags_return}
}

Validate a float.

Args:

_flags__float: float: value to validate

Returns:

bool: true if the value is a valid float

_flags_validateFloat()
{
flags_float=$1

if flags_validateInteger ${flags_float}; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_TRUE}
case ${flags_float} in
-
) # negative floats
flags_test=expr "${_flags_float_}" : '(-[0-9][0-9]_.[0-9][0-9]_)'
;;
*) # positive floats
flags_test=expr "${_flags_float_}" : '([0-9][0-9]_.[0-9][0-9]*)'
;;
esac
[ "${flags_test}" != "${flags_float}" ] && flags_return=${FLAGS_FALSE}
fi

unset flags_float flags_test
return ${flags_return}
}

Validate an integer.

Args:

_flags__integer: interger: value to validate

Returns:

bool: true if the value is a valid integer

_flags_validateInteger()
{
flags_int=$1

flags_return=${FLAGS_TRUE}
case ${flags_int} in
-_) # negative ints
flags_test=expr "${_flags_int_}" : '(-[0-9][0-9]_)'
;;
*) # positive ints
flags_test=expr "${_flags_int_}" : '([0-9][0-9]*)'
;;
esac
[ "${flags_test}" != "${flags_int}" ] && flags_return=${FLAGS_FALSE}

unset flags_int flags_test
return ${flags_return}
}

Parse command-line options using the standard getopt.

Note: the flag options are passed around in the global __flags_opts so that

the formatting is not lost due to shell parsing and such.

Args:

@: varies: command-line options to parse

Returns:

integer: a FLAGS success condition

_flags_getoptStandard()
{
flags_return=${FLAGS_TRUE}
flags_shortOpts=_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}

check for spaces in passed options

for flags_opt in "$@"; do
# note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
flags_match=echo "x${_flags_opt_}x" |sed 's/ //g'
if [ "${flags_match}" != "x${flags_opt}x" ]; then
flags_error='the available getopt does not support spaces in options'
flags_return=${FLAGS_ERROR}
break
fi
done

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
__flags_opts=getopt ${_flags_shortOpts_} $@ 2>&1
flags_rtrn=$?
if [ ${flags_rtrn} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi
fi

unset flags_match flags_opt flags_rtrn flags_shortOpts
return ${flags_return}
}

Parse command-line options using the enhanced getopt.

Note: the flag options are passed around in the global __flags_opts so that

the formatting is not lost due to shell parsing and such.

Args:

@: varies: command-line options to parse

Returns:

integer: a FLAGS success condition

_flags_getoptEnhanced()
{
flags_return=${FLAGS_TRUE}
flags_shortOpts=_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}
flags_boolOpts=echo "${__flags_boolNames}" \ |sed 's/^ *//;s/ *$//;s/ /,/g'
flags_longOpts=_flags_genOptStr ${__FLAGS_OPTSTR_LONG}

__flags_opts=getopt \ -o ${_flags_shortOpts_} \ -l "${_flags_longOpts_},${_flags_boolOpts_}" \ -- "$@" 2>&1
flags_rtrn=$?
if [ ${flags_rtrn} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi

unset flags_boolOpts flags_longOpts flags_rtrn flags_shortOpts
return ${flags_return}
}

Dynamically parse a getopt result and set appropriate variables.

This function does the actual conversion of getopt output and runs it through

the standard case structure for parsing. The case structure is actually quite

dynamic to support any number of flags.

Args:

argc: int: original command-line argument count

@: varies: output from getopt parsing

Returns:

integer: a FLAGS success condition

_flags_parseGetopt()
{
flags_argc=$1
shift

flags_return=${FLAGS_TRUE}

if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
set -- $@
else
# note the quotes around the `$@' -- they are essential!
eval set -- "$@"
fi

provide user with number of arguments to shift by later

NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not

properly give user access to non-flag arguments mixed in between flag

arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only

for backwards compatibility reasons.

FLAGS_ARGC=expr $# - 1 - ${_flags_argc_}

handle options. note options with values must do an additional shift

while true; do
flags_opt=$1
flags_arg=${2:-}
flags_type=${__FLAGS_TYPE_NONE}
flags_name=''

# determine long flag name
case "${_flags_opt_}" in
  --) shift; break ;;  # discontinue option parsing

  --*)  # long option
    _flags_opt_=`expr "${_flags_opt_}" : '--\(.*\)'`
    _flags_len_=${__FLAGS_LEN_LONG}
    if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then
      _flags_name_=${_flags_opt_}
    else
      # check for negated long boolean version
      if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then
        _flags_name_=`expr "${_flags_opt_}" : 'no\(.*\)'`
        _flags_type_=${__FLAGS_TYPE_BOOLEAN}
        _flags_arg_=${__FLAGS_NULL}
      fi
    fi
    ;;

  -*)  # short option
    _flags_opt_=`expr "${_flags_opt_}" : '-\(.*\)'`
    _flags_len_=${__FLAGS_LEN_SHORT}
    if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then
      # yes. match short name to long name. note purposeful off-by-one
      # (too high) with awk calculations.
      _flags_pos_=`echo "${__flags_shortNames}" \
          |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
              e=${_flags_opt_}`
      _flags_name_=`echo "${__flags_longNames}" \
          |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
    fi
    ;;
esac

# die if the flag was unrecognized
if [ -z "${_flags_name_}" ]; then
  flags_error="unrecognized option (${_flags_opt_})"
  flags_return=${FLAGS_ERROR}
  break
fi

# set new flag value
[ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \
    _flags_type_=`_flags_getFlagInfo \
        "${_flags_name_}" ${__FLAGS_INFO_TYPE}`
case ${_flags_type_} in
  ${__FLAGS_TYPE_BOOLEAN})
    if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
      if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
        eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}"
      else
        eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}"
      fi
    else
      _flags_strToEval_="_flags_val_=\

${_flags${flags_name}_${FLAGS_INFO_DEFAULT}}"
eval "${flags_strToEval}"
if [ ${flags_val} -eq ${FLAGS_FALSE} ]; then
eval "FLAGS
${flags_name}=${FLAGS_TRUE}"
else
eval "FLAGS
${flags_name}=${FLAGS_FALSE}"
fi
fi
;;

  ${__FLAGS_TYPE_FLOAT})
    if _flags_validateFloat "${_flags_arg_}"; then
      eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    else
      flags_error="invalid float value (${_flags_arg_})"
      flags_return=${FLAGS_ERROR}
      break
    fi
    ;;

  ${__FLAGS_TYPE_INTEGER})
    if _flags_validateInteger "${_flags_arg_}"; then
      eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    else
      flags_error="invalid integer value (${_flags_arg_})"
      flags_return=${FLAGS_ERROR}
      break
    fi
    ;;

  ${__FLAGS_TYPE_STRING})
    eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    ;;
esac

# handle special case help flag
if [ "${_flags_name_}" = 'help' ]; then
  if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
    flags_help
    flags_error='help requested'
    flags_return=${FLAGS_FALSE}
    break
  fi
fi

# shift the option and non-boolean arguements out.
shift
[ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift

done

give user back non-flag arguments

FLAGS_ARGV=''
while [ $# -gt 0 ]; do
FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
shift
done

unset flags_arg flags_len flags_name flags_opt flags_pos
flags_strToEval flags_type flags_val
return ${flags_return}
}

#------------------------------------------------------------------------------

public functions

A basic boolean flag. Boolean flags do not take any arguments, and their

value is either 1 (false) or 0 (true). For long flags, the false value is

specified on the command line by prepending the word 'no'. With short flags,

the presense of the flag toggles the current value between true and false.

Specifying a short boolean flag twice on the command results in returning the

value back to the default value.

A default value is required for boolean flags.

For example, lets say a Boolean flag was created whose long name was 'update'

and whose short name was 'x', and the default value was 'false'. This flag

could be explicitly set to 'true' with '--update' or by '-x', and it could be

explicitly set to 'false' with '--noupdate'.

DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }

Other basic flags.

DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; }
DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; }

Parse the flags.

Args:

unnamed: list: command-line flags to parse

Returns:

integer: success of operation, or error

FLAGS()
{

define a standard 'help' flag if one isn't already defined

[ -z "${__flags_help_type:-}" ] &&
DEFINE_boolean 'help' false 'show this help' 'h'

parse options

if [ $# -gt 0 ]; then
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
_flags_getoptStandard "$@"
else
_flags_getoptEnhanced "$@"
fi
flags_return=$?
else
# nothing passed; won't bother running getopt
__flags_opts='--'
flags_return=${FLAGS_TRUE}
fi

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
_flags_parseGetopt $# "${__flags_opts}"
flags_return=$?
fi

[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}"
return ${flags_return}
}

This is a helper function for determining the getopt version for platforms

where the detection isn't working. It simply outputs debug information that

can be included in a bug report.

Args:

none

Output:

debug info that can be included in a bug report

Returns:

nothing

flags_getoptInfo()
{

platform info

_flags_debug "uname -a: uname -a"
_flags_debug "PATH: ${PATH}"

shell info

if [ -n "${BASH_VERSION:-}" ]; then
_flags_debug 'shell: bash'
_flags_debug "BASH_VERSION: ${BASH_VERSION}"
elif [ -n "${ZSH_VERSION:-}" ]; then
_flags_debug 'shell: zsh'
_flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
fi

getopt info

getopt >/dev/null
_flags_getoptReturn=$?
_flags_debug "getopt return: ${_flags_getoptReturn}"
_flags_debug "getopt --version: getopt --version 2>&1"

unset _flags_getoptReturn
}

Returns whether the detected getopt version is the enhanced version.

Args:

none

Output:

none

Returns:

bool: true if getopt is the enhanced version

flags_getoptIsEnh()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH}
}

Returns whether the detected getopt version is the standard version.

Args:

none

Returns:

bool: true if getopt is the standard version

flags_getoptIsStd()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD}
}

This is effectively a 'usage()' function. It prints usage information and

exits the program with ${FLAGS_FALSE} if it is ever found in the command line

arguments. Note this function can be overridden so other apps can define

their own --help flag, replacing this one, if they want.

Args:

none

Returns:

integer: success of operation (always returns true)

flags_help()
{
if [ -n "${FLAGS_HELP:-}" ]; then
echo "${FLAGS_HELP}" >&2
else
echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2
fi
if [ -n "${_flags_longNames}" ]; then
echo 'flags:' >&2
for flags_name
in ${flags_longNames}; do
flags_flagStr
=''
flags_boolStr
=''

  flags_default_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_DEFAULT}`
  flags_help_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_HELP}`
  flags_short_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_SHORT}`
  flags_type_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_TYPE}`

  [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
      && flags_flagStr_="-${flags_short_}"

  if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
    [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
        && flags_flagStr_="${flags_flagStr_},"
    [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] \
        && flags_boolStr_='[no]'
    flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:"
  fi

  case ${flags_type_} in
    ${__FLAGS_TYPE_BOOLEAN})
      if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then
        flags_defaultStr_='true'
      else
        flags_defaultStr_='false'
      fi
      ;;
    ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER})
      flags_defaultStr_=${flags_default_} ;;
    ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;;
  esac
  flags_defaultStr_="(default: ${flags_defaultStr_})"

  flags_helpStr_="  ${flags_flagStr_}  ${flags_help_} ${flags_defaultStr_}"
  flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
  flags_columns_=`_flags_columns`
  if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
    echo "${flags_helpStr_}" >&2
  else
    echo "  ${flags_flagStr_}  ${flags_help_}" >&2
    # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
    # because it doesn't like empty strings when used in this manner.
    flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
        |awk '{printf "%"length($0)-2"s", ""}'`"
    flags_helpStr_="  ${flags_emptyStr_}  ${flags_defaultStr_}"
    flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
    if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \
        -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
      # indented to match help string
      echo "${flags_helpStr_}" >&2
    else
      # indented four from left to allow for longer defaults as long flag
      # names might be used too, making things too long
      echo "    ${flags_defaultStr_}" >&2
    fi
  fi
done

fi

unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_
flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_
flags_columns_ flags_short_ flags_type_
return ${FLAGS_TRUE}
}

Reset shflags back to an uninitialized state.

Args:

none

Returns:

nothing

flags_reset()
{
for flags_name_ in ${flags_longNames}; do
flags_strToEval
="unset FLAGS
${flags_name_}"
for flags_type_ in
${__FLAGS_INFO_DEFAULT}
${__FLAGS_INFO_HELP}
${__FLAGS_INFO_SHORT}
${FLAGS_INFO_TYPE}
do
flags_strToEval
=
"${flags_strToEval
} flags${flags_name}${flags_type}"
done
eval ${flags_strToEval_}
done

reset internal variables

__flags_boolNames=' '
__flags_longNames=' '
__flags_shortNames=' '

unset flags_name_ flags_type_ flags_strToEval_
}

I don't see a way to attach a file so...

$Id$

vim:et:ft=sh:sts=2:sw=2

Copyright 2008 Kate Ward. All Rights Reserved.

Released under the LGPL (GNU Lesser General Public License)

shFlags -- Advanced command-line flag library for Unix shell scripts.

http://code.google.com/p/shflags/

Author: kate.ward@forestent.com (Kate Ward)

This module implements something like the google-gflags library available

from http://code.google.com/p/google-gflags/.

FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take

a name, default value, help-string, and optional 'short' name (one-letter

name). Some flags have other arguments, which are described with the flag.

DEFINE_string: takes any input, and intreprets it as a string.

DEFINE_boolean: typically does not take any argument: say --myflag to set

FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false.

Alternately, you can say

--myflag=true or --myflag=t or --myflag=0 or

--myflag=false or --myflag=f or --myflag=1

Passing an option has the same affect as passing the option once.

DEFINE_float: takes an input and intreprets it as a floating point number. As

shell does not support floats per-se, the input is merely validated as

being a valid floating point value.

DEFINE_integer: takes an input and intreprets it as an integer.

SPECIAL FLAGS: There are a few flags that have special meaning:

--help (or -?) prints a list of all the flags in a human-readable fashion

--flagfile=foo read flags from foo. (not implemented yet)

-- as in getopt(), terminates flag-processing

EXAMPLE USAGE:

-- begin hello.sh --

#! /bin/sh

. ./shflags

DEFINE_string name 'world' "somebody's name" n

FLAGS "$@" || exit $?

eval set -- "${FLAGS_ARGV}"

echo "Hello, ${FLAGS_name}."

-- end hello.sh --

$ ./hello.sh -n Kate

Hello, Kate.

NOTE: Not all systems include a getopt version that supports long flags. On

these systems, only short flags are recognized.

#==============================================================================

shFlags

Shared attributes:

flags_error: last error message

flags_return: last return value

__flags_longNames: list of long names for all flags

__flags_shortNames: list of short names for all flags

__flags_boolNames: list of boolean flag names

__flags_opts: options parsed by getopt

Per-flag attributes:

FLAGS_<flag_name>: contains value of flag named 'flag_name'

_flags<flag_name>_default: the default flag value

_flags<flag_name>_help: the flag help string

_flags<flag_name>_short: the flag short name

_flags<flag_name>_type: the flag type

Notes:

- lists of strings are space separated, and a null value is the '~' char.

return if FLAGS already loaded

[ -n "${FLAGS_VERSION:-}" ] && return 0
FLAGS_VERSION='1.0.3'

return values

FLAGS_TRUE=0
FLAGS_FALSE=1
FLAGS_ERROR=2

reserved flag names

FLAGS_RESERVED='ARGC ARGV ERROR FALSE HELP PARENT RESERVED TRUE VERSION'

_flags_debug() { echo "flags:DEBUG $@" >&2; }
_flags_warn() { echo "flags:WARN $@" >&2; }
_flags_error() { echo "flags:ERROR $@" >&2; }
_flags_fatal() { echo "flags:FATAL $@" >&2; }

specific shell checks

if [ -n "${ZSH_VERSION:-}" ]; then
setopt |grep "^shwordsplit$" >/dev/null
if [ $? -ne ${FLAGS_TRUE} ]; then
_flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
exit ${FLAGS_ERROR}
fi
if [ -z "${FLAGS_PARENT:-}" ]; then
_flags_fatal "zsh does not pass $0 through properly. please declare'
"FLAGS_PARENT=$0" before calling shFlags"
exit ${FLAGS_ERROR}
fi
fi

constants

getopt version

__FLAGS_GETOPT_VERS_STD=0
__FLAGS_GETOPT_VERS_ENH=1
__FLAGS_GETOPT_VERS_BSD=2

getopt >/dev/null 2>&1
case $? in
0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt
2)
# TODO(kward): look into '-T' option to test the internal getopt() version
if [ "getopt --version" = '-- ' ]; then
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD}
else
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
fi
;;
*)
_flags_fatal 'unable to determine getopt version'
exit ${FLAGS_ERROR}
;;
esac

getopt optstring lengths

__FLAGS_OPTSTR_SHORT=0
__FLAGS_OPTSTR_LONG=1

__FLAGS_NULL='~'

flag info strings

__FLAGS_INFO_DEFAULT='default'
__FLAGS_INFO_HELP='help'
__FLAGS_INFO_SHORT='short'
__FLAGS_INFO_TYPE='type'

flag lengths

__FLAGS_LEN_SHORT=0
__FLAGS_LEN_LONG=1

flag types

__FLAGS_TYPE_NONE=0
__FLAGS_TYPE_BOOLEAN=1
__FLAGS_TYPE_FLOAT=2
__FLAGS_TYPE_INTEGER=3
__FLAGS_TYPE_STRING=4

set the constants readonly

__flags_constants=set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'
for __flags_const in ${__flags_constants}; do

skip certain flags

case ${__flags_const} in
FLAGS_HELP) continue ;;
FLAGS_PARENT) continue ;;
esac

set flag readonly

if [ -z "${ZSH_VERSION:-}" ]; then
readonly ${__flags_const}
else # handle zsh
case ${ZSH_VERSION} in
[123].*) readonly ${__flags_const} ;;
*) readonly -g ${__flags_const} ;; # declare readonly constants globally
esac
fi
done
unset __flags_const __flags_constants

internal variables

__flags_boolNames=' ' # space separated list of boolean flag names
__flags_longNames=' ' # space separated list of long flag names
__flags_shortNames=' ' # space separated list of short flag names

__flags_columns='' # screen width in columns
__flags_opts='' # temporary storage for parsed getopt flags

#------------------------------------------------------------------------------

private functions

Define a flag.

Calling this function will define the following info variables for the

specified flag:

FLAGS_flagname - the name for this flag (based upon the long flag name)

_flags<flag_name>_default - the default value

__flags_flagname_help - the help string

__flags_flagname_short - the single letter alias

__flags_flagname_type - the type of flag (one of _FLAGS_TYPE*)

Args:

_flags__type: integer: internal type of flag (_FLAGS_TYPE*)

_flags__name: string: long flag name

_flags__default: default flag value

_flags__help: string: help string

_flags__short: string: (optional) short flag name

Returns:

integer: success of operation, or error

_flags_define()
{
if [ $# -lt 4 ]; then
flags_error='DEFINE error: too few arguments'
flags_return=${FLAGS_ERROR}
_flags_error "${flags_error}"
return ${flags_return}
fi

flags_type=$1
flags_name=$2
flags_default=$3
flags_help=$4
flags_short=${5:-${__FLAGS_NULL}}

flags_return=${FLAGS_TRUE}

TODO(kward): check for validity of the flag name (e.g. dashes)

check whether the flag name is reserved

echo " ${FLAGS_RESERVED} " |grep " ${flags_name} " >/dev/null
if [ $? -eq 0 ]; then
flags_error="flag name (${flags_name}) is reserved"
flags_return=${FLAGS_ERROR}
fi

require short option for getopt that don't support long options

if [ ${flags_return} -eq ${FLAGS_TRUE}
-a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH}
-a "${flags_short}" = "${__FLAGS_NULL}" ]
then
flags_error="short flag required for (${flags_name}) on this platform"
flags_return=${FLAGS_ERROR}
fi

check for existing long name definition

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
if _flags_itemInList "${flags_name}"
${__flags_longNames} ${__flags_boolNames}
then
flags_error="flag name ([no]${flags_name}) already defined"
_flags_warn "${flags_error}"
flags_return=${FLAGS_FALSE}
fi
fi

check for existing short name definition

if [ ${flags_return} -eq ${FLAGS_TRUE}
-a "${flags_short}" != "${__FLAGS_NULL}" ]
then
if _flags_itemInList "${flags_short}" ${__flags_shortNames}; then
flags_error="flag short name (${flags_short}) already defined"
_flags_warn "${flags_error}"
flags_return=${FLAGS_FALSE}
fi
fi

handle default value. note, on several occasions the 'if' portion of an

if/then/else contains just a ':' which does nothing. a binary reversal via

'!' is not done because it does not work on all shells.

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
case ${flags_type} in
${__FLAGS_TYPE_BOOLEAN})
if _flags_validateBoolean "${flags_default}"; then
case ${flags_default} in
true|t|0) flags_default=${FLAGS_TRUE} ;;
false|f|1) flags_default=${FLAGS_FALSE} ;;
esac
else
flags_error="invalid default flag value '${flags_default}'"
flags_return=${FLAGS_ERROR}
fi
;;

  ${__FLAGS_TYPE_FLOAT})
    if _flags_validateFloat "${_flags_default_}"; then
      :
    else
      flags_error="invalid default flag value '${_flags_default_}'"
      _flags_return_=${FLAGS_ERROR}
    fi
    ;;

  ${__FLAGS_TYPE_INTEGER})
    if _flags_validateInteger "${_flags_default_}"; then
      :
    else
      flags_error="invalid default flag value '${_flags_default_}'"
      _flags_return_=${FLAGS_ERROR}
    fi
    ;;

  ${__FLAGS_TYPE_STRING}) ;;  # everything in shell is a valid string

  *)
    flags_error="unrecognized flag type '${_flags_type_}'"
    _flags_return_=${FLAGS_ERROR}
    ;;
esac

fi

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
# store flag information
eval "FLAGS_${flags_name}='${flags_default}'"
eval "_flags${flags_name}${__FLAGS_INFO_TYPE}=${flags_type}"
eval "_flags${flags_name}
${__FLAGS_INFO_DEFAULT}=
"${flags_default}""
eval "_flags${flags_name}${__FLAGS_INFO_HELP}="${flags_help}""
eval "_flags${flags_name}
${__FLAGS_INFO_SHORT}='${flags_short}'"

# append flag name(s) to list of names
__flags_longNames="${__flags_longNames}${_flags_name_} "
__flags_shortNames="${__flags_shortNames}${_flags_short_} "
[ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
    __flags_boolNames="${__flags_boolNames}no${_flags_name_} "

fi

flags_return=${flags_return}
unset flags_default flags_help flags_name flags_return flags_short
flags_type
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}

Return valid getopt options using currently defined list of long options.

This function builds a proper getopt option string for short (and long)

options, using the current list of long options for reference.

Args:

_flags_optStr: integer: option string type (_FLAGS_OPTSTR*)

Output:

string: generated option string for getopt

Returns:

boolean: success of operation (always returns True)

_flags_genOptStr()
{
flags_optStrType=$1

flags_opts=''

for flags_flag in ${__flags_longNames}; do
flags_type=_flags_getFlagInfo ${_flags_flag_} ${__FLAGS_INFO_TYPE}
case ${flags_optStrType} in
${__FLAGS_OPTSTR_SHORT})
flags_shortName=_flags_getFlagInfo \ ${_flags_flag_} ${__FLAGS_INFO_SHORT}
if [ "${flags_shortName}" != "${__FLAGS_NULL}" ]; then
flags_opts="${flags_opts}${flags_shortName}"
# getopt needs a trailing ':' to indicate a required argument
[ ${flags_type} -ne ${__FLAGS_TYPE_BOOLEAN} ] &&
flags_opts="${flags_opts}:"
fi
;;

  ${__FLAGS_OPTSTR_LONG})
    _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}"
    # getopt needs a trailing ':' to indicate a required argument
    [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
        _flags_opts_="${_flags_opts_}:"
    ;;
esac

done

echo "${flags_opts}"
unset flags_flag flags_opts flags_optStrType flags_shortName
flags_type
return ${FLAGS_TRUE}
}

Returns flag details based on a flag name and flag info.

Args:

string: long flag name

string: flag info (see the _flags_define function for valid info types)

Output:

string: value of dereferenced flag variable

Returns:

integer: one of FLAGS_{TRUE|FALSE|ERROR}

_flags_getFlagInfo()
{
flags_name=$1
flags_info=$2

flags_nameVar="_flags${flags_name}_${flags_info}"
flags_strToEval="flags_value="${${flags_nameVar}:-}""
eval "${flags_strToEval}"
if [ -n "${flags_value}" ]; then
flags_return=${FLAGS_TRUE}
else
# see if the flags_name variable is a string as strings can be empty...
# note: the DRY principle would say to have this function call itself for
# the next three lines, but doing so results in an infinite loop as an
# invalid flags_name will also not have the associated _type variable.
# Because it doesn't (it will evaluate to an empty string) the logic will
# try to find the _type variable of the type variable, and so on. Not so
# good ;-)
flags_typeVar="_flags${flags_name}
${__FLAGS_INFO_TYPE}"
flags_strToEval="flags_type="${${flags_typeVar}:-}""
eval "${flags_strToEval}"
if [ "${flags_type}" = "${__FLAGS_TYPE_STRING}" ]; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_ERROR}
flags_error="invalid flag name (${flags_nameVar})"
fi
fi

echo "${flags_value}"
unset flags_info flags_name flags_strToEval flags_type flags_value
flags_nameVar flags_typeVar
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}

check for presense of item in a list. passed a string (e.g. 'abc'), this

function will determine if the string is present in the list of strings (e.g.

' foo bar abc ').

Args:

_flags__str: string: string to search for in a list of strings

unnamed: list: list of strings

Returns:

boolean: true if item is in the list

_flags_itemInList()
{
flags_str=$1
shift

echo " ${*:-} " |grep " ${flags_str} " >/dev/null
if [ $? -eq 0 ]; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_FALSE}
fi

unset flags_str
return ${flags_return}
}

Returns the width of the current screen.

Output:

integer: width in columns of the current screen.

_flags_columns()
{
if [ -z "${__flags_columns}" ]; then
# determine the value and store it
if eval stty size >/dev/null 2>&1; then
# stty size worked :-)
set -- stty size
__flags_columns=$2
elif eval tput cols >/dev/null 2>&1; then
set -- tput cols
__flags_columns=$1
else
__flags_columns=80 # default terminal width
fi
fi
echo ${__flags_columns}
}

Validate a boolean.

Args:

_flags__bool: boolean: value to validate

Returns:

bool: true if the value is a valid boolean

_flags_validateBoolean()
{
flags_bool=$1

flags_return=${FLAGS_TRUE}
case "${flags_bool}" in
true|t|0) ;;
false|f|1) ;;
*) flags_return=${FLAGS_FALSE} ;;
esac

unset flags_bool
return ${flags_return}
}

Validate a float.

Args:

_flags__float: float: value to validate

Returns:

bool: true if the value is a valid float

_flags_validateFloat()
{
flags_float=$1

if flags_validateInteger ${flags_float}; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_TRUE}
case ${flags_float} in
-
) # negative floats
flags_test=expr "${_flags_float_}" : '(-[0-9][0-9]_.[0-9][0-9]_)'
;;
*) # positive floats
flags_test=expr "${_flags_float_}" : '([0-9][0-9]_.[0-9][0-9]*)'
;;
esac
[ "${flags_test}" != "${flags_float}" ] && flags_return=${FLAGS_FALSE}
fi

unset flags_float flags_test
return ${flags_return}
}

Validate an integer.

Args:

_flags__integer: interger: value to validate

Returns:

bool: true if the value is a valid integer

_flags_validateInteger()
{
flags_int=$1

flags_return=${FLAGS_TRUE}
case ${flags_int} in
-_) # negative ints
flags_test=expr "${_flags_int_}" : '(-[0-9][0-9]_)'
;;
*) # positive ints
flags_test=expr "${_flags_int_}" : '([0-9][0-9]*)'
;;
esac
[ "${flags_test}" != "${flags_int}" ] && flags_return=${FLAGS_FALSE}

unset flags_int flags_test
return ${flags_return}
}

Parse command-line options using the standard getopt.

Note: the flag options are passed around in the global __flags_opts so that

the formatting is not lost due to shell parsing and such.

Args:

@: varies: command-line options to parse

Returns:

integer: a FLAGS success condition

_flags_getoptStandard()
{
flags_return=${FLAGS_TRUE}
flags_shortOpts=_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}

check for spaces in passed options

for flags_opt in "$@"; do
# note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
flags_match=echo "x${_flags_opt_}x" |sed 's/ //g'
if [ "${flags_match}" != "x${flags_opt}x" ]; then
flags_error='the available getopt does not support spaces in options'
flags_return=${FLAGS_ERROR}
break
fi
done

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
__flags_opts=getopt ${_flags_shortOpts_} $@ 2>&1
flags_rtrn=$?
if [ ${flags_rtrn} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi
fi

unset flags_match flags_opt flags_rtrn flags_shortOpts
return ${flags_return}
}

Parse command-line options using the enhanced getopt.

Note: the flag options are passed around in the global __flags_opts so that

the formatting is not lost due to shell parsing and such.

Args:

@: varies: command-line options to parse

Returns:

integer: a FLAGS success condition

_flags_getoptEnhanced()
{
flags_return=${FLAGS_TRUE}
flags_shortOpts=_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}
flags_boolOpts=echo "${__flags_boolNames}" \ |sed 's/^ *//;s/ *$//;s/ /,/g'
flags_longOpts=_flags_genOptStr ${__FLAGS_OPTSTR_LONG}

__flags_opts=getopt \ -o ${_flags_shortOpts_} \ -l "${_flags_longOpts_},${_flags_boolOpts_}" \ -- "$@" 2>&1
flags_rtrn=$?
if [ ${flags_rtrn} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi

unset flags_boolOpts flags_longOpts flags_rtrn flags_shortOpts
return ${flags_return}
}

Dynamically parse a getopt result and set appropriate variables.

This function does the actual conversion of getopt output and runs it through

the standard case structure for parsing. The case structure is actually quite

dynamic to support any number of flags.

Args:

argc: int: original command-line argument count

@: varies: output from getopt parsing

Returns:

integer: a FLAGS success condition

_flags_parseGetopt()
{
flags_argc=$1
shift

flags_return=${FLAGS_TRUE}

if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
set -- $@
else
# note the quotes around the `$@' -- they are essential!
eval set -- "$@"
fi

provide user with number of arguments to shift by later

NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not

properly give user access to non-flag arguments mixed in between flag

arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only

for backwards compatibility reasons.

FLAGS_ARGC=expr $# - 1 - ${_flags_argc_}

handle options. note options with values must do an additional shift

while true; do
flags_opt=$1
flags_arg=${2:-}
flags_type=${__FLAGS_TYPE_NONE}
flags_name=''

# determine long flag name
case "${_flags_opt_}" in
  --) shift; break ;;  # discontinue option parsing

  --*)  # long option
    _flags_opt_=`expr "${_flags_opt_}" : '--\(.*\)'`
    _flags_len_=${__FLAGS_LEN_LONG}
    if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then
      _flags_name_=${_flags_opt_}
    else
      # check for negated long boolean version
      if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then
        _flags_name_=`expr "${_flags_opt_}" : 'no\(.*\)'`
        _flags_type_=${__FLAGS_TYPE_BOOLEAN}
        _flags_arg_=${__FLAGS_NULL}
      fi
    fi
    ;;

  -*)  # short option
    _flags_opt_=`expr "${_flags_opt_}" : '-\(.*\)'`
    _flags_len_=${__FLAGS_LEN_SHORT}
    if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then
      # yes. match short name to long name. note purposeful off-by-one
      # (too high) with awk calculations.
      _flags_pos_=`echo "${__flags_shortNames}" \
          |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
              e=${_flags_opt_}`
      _flags_name_=`echo "${__flags_longNames}" \
          |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
    fi
    ;;
esac

# die if the flag was unrecognized
if [ -z "${_flags_name_}" ]; then
  flags_error="unrecognized option (${_flags_opt_})"
  flags_return=${FLAGS_ERROR}
  break
fi

# set new flag value
[ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \
    _flags_type_=`_flags_getFlagInfo \
        "${_flags_name_}" ${__FLAGS_INFO_TYPE}`
case ${_flags_type_} in
  ${__FLAGS_TYPE_BOOLEAN})
    if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
      if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
        eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}"
      else
        eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}"
      fi
    else
      _flags_strToEval_="_flags_val_=\

${_flags${flags_name}_${FLAGS_INFO_DEFAULT}}"
eval "${flags_strToEval}"
if [ ${flags_val} -eq ${FLAGS_FALSE} ]; then
eval "FLAGS
${flags_name}=${FLAGS_TRUE}"
else
eval "FLAGS
${flags_name}=${FLAGS_FALSE}"
fi
fi
;;

  ${__FLAGS_TYPE_FLOAT})
    if _flags_validateFloat "${_flags_arg_}"; then
      eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    else
      flags_error="invalid float value (${_flags_arg_})"
      flags_return=${FLAGS_ERROR}
      break
    fi
    ;;

  ${__FLAGS_TYPE_INTEGER})
    if _flags_validateInteger "${_flags_arg_}"; then
      eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    else
      flags_error="invalid integer value (${_flags_arg_})"
      flags_return=${FLAGS_ERROR}
      break
    fi
    ;;

  ${__FLAGS_TYPE_STRING})
    eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
    ;;
esac

# handle special case help flag
if [ "${_flags_name_}" = 'help' ]; then
  if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
    flags_help
    flags_error='help requested'
    flags_return=${FLAGS_FALSE}
    break
  fi
fi

# shift the option and non-boolean arguements out.
shift
[ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift

done

give user back non-flag arguments

FLAGS_ARGV=''
while [ $# -gt 0 ]; do
FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
shift
done

unset flags_arg flags_len flags_name flags_opt flags_pos
flags_strToEval flags_type flags_val
return ${flags_return}
}

#------------------------------------------------------------------------------

public functions

A basic boolean flag. Boolean flags do not take any arguments, and their

value is either 1 (false) or 0 (true). For long flags, the false value is

specified on the command line by prepending the word 'no'. With short flags,

the presense of the flag toggles the current value between true and false.

Specifying a short boolean flag twice on the command results in returning the

value back to the default value.

A default value is required for boolean flags.

For example, lets say a Boolean flag was created whose long name was 'update'

and whose short name was 'x', and the default value was 'false'. This flag

could be explicitly set to 'true' with '--update' or by '-x', and it could be

explicitly set to 'false' with '--noupdate'.

DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }

Other basic flags.

DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; }
DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; }

Parse the flags.

Args:

unnamed: list: command-line flags to parse

Returns:

integer: success of operation, or error

FLAGS()
{

define a standard 'help' flag if one isn't already defined

[ -z "${__flags_help_type:-}" ] &&
DEFINE_boolean 'help' false 'show this help' 'h'

parse options

if [ $# -gt 0 ]; then
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
_flags_getoptStandard "$@"
else
_flags_getoptEnhanced "$@"
fi
flags_return=$?
else
# nothing passed; won't bother running getopt
__flags_opts='--'
flags_return=${FLAGS_TRUE}
fi

if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
_flags_parseGetopt $# "${__flags_opts}"
flags_return=$?
fi

[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}"
return ${flags_return}
}

This is a helper function for determining the getopt version for platforms

where the detection isn't working. It simply outputs debug information that

can be included in a bug report.

Args:

none

Output:

debug info that can be included in a bug report

Returns:

nothing

flags_getoptInfo()
{

platform info

_flags_debug "uname -a: uname -a"
_flags_debug "PATH: ${PATH}"

shell info

if [ -n "${BASH_VERSION:-}" ]; then
_flags_debug 'shell: bash'
_flags_debug "BASH_VERSION: ${BASH_VERSION}"
elif [ -n "${ZSH_VERSION:-}" ]; then
_flags_debug 'shell: zsh'
_flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
fi

getopt info

getopt >/dev/null
_flags_getoptReturn=$?
_flags_debug "getopt return: ${_flags_getoptReturn}"
_flags_debug "getopt --version: getopt --version 2>&1"

unset _flags_getoptReturn
}

Returns whether the detected getopt version is the enhanced version.

Args:

none

Output:

none

Returns:

bool: true if getopt is the enhanced version

flags_getoptIsEnh()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH}
}

Returns whether the detected getopt version is the standard version.

Args:

none

Returns:

bool: true if getopt is the standard version

flags_getoptIsStd()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD}
}

This is effectively a 'usage()' function. It prints usage information and

exits the program with ${FLAGS_FALSE} if it is ever found in the command line

arguments. Note this function can be overridden so other apps can define

their own --help flag, replacing this one, if they want.

Args:

none

Returns:

integer: success of operation (always returns true)

flags_help()
{
if [ -n "${FLAGS_HELP:-}" ]; then
echo "${FLAGS_HELP}" >&2
else
echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2
fi
if [ -n "${_flags_longNames}" ]; then
echo 'flags:' >&2
for flags_name
in ${flags_longNames}; do
flags_flagStr
=''
flags_boolStr
=''

  flags_default_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_DEFAULT}`
  flags_help_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_HELP}`
  flags_short_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_SHORT}`
  flags_type_=`_flags_getFlagInfo \
      "${flags_name_}" ${__FLAGS_INFO_TYPE}`

  [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
      && flags_flagStr_="-${flags_short_}"

  if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
    [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
        && flags_flagStr_="${flags_flagStr_},"
    [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] \
        && flags_boolStr_='[no]'
    flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:"
  fi

  case ${flags_type_} in
    ${__FLAGS_TYPE_BOOLEAN})
      if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then
        flags_defaultStr_='true'
      else
        flags_defaultStr_='false'
      fi
      ;;
    ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER})
      flags_defaultStr_=${flags_default_} ;;
    ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;;
  esac
  flags_defaultStr_="(default: ${flags_defaultStr_})"

  flags_helpStr_="  ${flags_flagStr_}  ${flags_help_} ${flags_defaultStr_}"
  flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
  flags_columns_=`_flags_columns`
  if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
    echo "${flags_helpStr_}" >&2
  else
    echo "  ${flags_flagStr_}  ${flags_help_}" >&2
    # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
    # because it doesn't like empty strings when used in this manner.
    flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
        |awk '{printf "%"length($0)-2"s", ""}'`"
    flags_helpStr_="  ${flags_emptyStr_}  ${flags_defaultStr_}"
    flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
    if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \
        -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
      # indented to match help string
      echo "${flags_helpStr_}" >&2
    else
      # indented four from left to allow for longer defaults as long flag
      # names might be used too, making things too long
      echo "    ${flags_defaultStr_}" >&2
    fi
  fi
done

fi

unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_
flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_
flags_columns_ flags_short_ flags_type_
return ${FLAGS_TRUE}
}

Reset shflags back to an uninitialized state.

Args:

none

Returns:

nothing

flags_reset()
{
for flags_name_ in ${flags_longNames}; do
flags_strToEval
="unset FLAGS
${flags_name_}"
for flags_type_ in
${__FLAGS_INFO_DEFAULT}
${__FLAGS_INFO_HELP}
${__FLAGS_INFO_SHORT}
${FLAGS_INFO_TYPE}
do
flags_strToEval
=
"${flags_strToEval
} flags${flags_name}${flags_type}"
done
eval ${flags_strToEval_}
done

reset internal variables

__flags_boolNames=' '
__flags_longNames=' '
__flags_shortNames=' '

unset flags_name_ flags_type_ flags_strToEval_
}

@petervanderdoes

This comment has been minimized.

Show comment Hide comment
@petervanderdoes

petervanderdoes Feb 1, 2013

Hehe, OK, got it. Maybe just edit your post now, so it's not so big :)
It seems the link from gitflow-shFlags to shFlags/src/shflags is not working under cygwin. You can just copy shFlags/src/shflags to gitflow-shFlags

Hehe, OK, got it. Maybe just edit your post now, so it's not so big :)
It seems the link from gitflow-shFlags to shFlags/src/shflags is not working under cygwin. You can just copy shFlags/src/shflags to gitflow-shFlags

@DougHockin

This comment has been minimized.

Show comment Hide comment
@DougHockin

DougHockin Feb 1, 2013

I'm pretty new to Git. That looks like a reference from one git repo to another? Perhaps there's some option in git to say "follow references" when cloning?

I'm pretty new to Git. That looks like a reference from one git repo to another? Perhaps there's some option in git to say "follow references" when cloning?

@petervanderdoes

This comment has been minimized.

Show comment Hide comment
@petervanderdoes

petervanderdoes Feb 1, 2013

It's more Cygwin, the gitflow-shFlags is supposed to be a soft link to shFlags/src/shflags and your system just makes it a file containing where it supposed to link to.

It's more Cygwin, the gitflow-shFlags is supposed to be a soft link to shFlags/src/shflags and your system just makes it a file containing where it supposed to link to.

@evannieuwburg

This comment has been minimized.

Show comment Hide comment
@evannieuwburg

evannieuwburg Aug 14, 2013

I got the exact same error, but I don't understand your explanation. When I open "gitflow-shFlags" , it only contains the string "shFlags/src/shflags". Should I change that to something else?

I got the exact same error, but I don't understand your explanation. When I open "gitflow-shFlags" , it only contains the string "shFlags/src/shflags". Should I change that to something else?

@petervanderdoes

This comment has been minimized.

Show comment Hide comment
@petervanderdoes

petervanderdoes Aug 14, 2013

See #295 (comment) or better yet:
Use my fork git-flow (AVH Edition)

Checkout the changelog for more information about bugfixes and new features implemented in my fork.

When on Windows you need to read the new Windows installation instruction to install git-flow (AVH Edition)

See #295 (comment) or better yet:
Use my fork git-flow (AVH Edition)

Checkout the changelog for more information about bugfixes and new features implemented in my fork.

When on Windows you need to read the new Windows installation instruction to install git-flow (AVH Edition)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment