aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkate.ward <kate.ward@forestent.com>2009-03-30 18:54:36 +0000
committerkate.ward <kate.ward@forestent.com>2009-03-30 18:54:36 +0000
commitc521068ebb95298c61d714d1961d577ff86c58a7 (patch)
treeb3c58f63d6cd0da21e8fbc95d38f0a9d821958c3
parentc4b0ef7a998796dee6095d61120e6249488cb908 (diff)
downloadshflags-c521068ebb95298c61d714d1961d577ff86c58a7.tar.gz
- fixed issue# 7 where long flags declared with '=' didn't work
- flag and non-flag arguments can now be mixed on the command-line - removed setting and unsetting of '-u' to check for unset variables - obsoleted FLAGS_ARGC and replaced with FLAGS_ARGV
-rw-r--r--source/1.0/doc/CHANGES-1.0.txt25
-rw-r--r--source/1.0/doc/RELEASE_NOTES-1.0.3.txt94
-rw-r--r--source/1.0/doc/contributors.txt5
-rwxr-xr-xsource/1.0/examples/debug_output.sh47
-rwxr-xr-xsource/1.0/examples/hello_world.sh3
-rwxr-xr-xsource/1.0/examples/write_date.sh48
-rw-r--r--source/1.0/src/shflags75
-rwxr-xr-xsource/1.0/src/shflags_test_parsing.sh52
8 files changed, 272 insertions, 77 deletions
diff --git a/source/1.0/doc/CHANGES-1.0.txt b/source/1.0/doc/CHANGES-1.0.txt
index 1eac214..f1375ac 100644
--- a/source/1.0/doc/CHANGES-1.0.txt
+++ b/source/1.0/doc/CHANGES-1.0.txt
@@ -1,6 +1,31 @@
Changes in shFlags 1.0.x
========================
+Changes with 1.0.3
+------------------
+
+MAJOR CHANGE! FLAGS_ARGC is now obsolete, and is replaced by FLAGS_ARGV.
+
+Fixed issue# 7 where long flags defined with '=' (e.g. --abc=123) made it
+impossible for the user to know how many non-flag command-line arguments were
+available because the value returned by FLAGS_ARGC was wrong. The FLAGS_ARGC
+value is now obsolete, but will be maintained for backwards compatibility. The
+new method of getting the non-flag arguments is by executing 'eval set --
+"${FLAGS_ARGV}"' after the FLAGS command. The arguments will then be available
+using the standard shell $#, $@, $*, $1, etc. variables.
+
+Due to above fix for issue# 7, there is now proper support for mixing flags
+with non-flag arguments on the command-line. Previously, all non-flag arguments
+had to be at the end of the command-line.
+
+Renamed _flags_standardGetopt() and _flags_enhancedGetopt() functions to
+_flags_getoptStandard() and _flags_getoptEnhanced().
+
+Took out the setting and restoration of the '-u' shell flag to treat unset
+variables as an error. No point in having it in this library as it is verified
+in the unit tests, and provides basically no benefit.
+
+
Changes with 1.0.2
------------------
diff --git a/source/1.0/doc/RELEASE_NOTES-1.0.3.txt b/source/1.0/doc/RELEASE_NOTES-1.0.3.txt
new file mode 100644
index 0000000..637a18d
--- /dev/null
+++ b/source/1.0/doc/RELEASE_NOTES-1.0.3.txt
@@ -0,0 +1,94 @@
+------------------------------
+shFlags.sh 1.0.3 Release Notes
+------------------------------
+
+Preface
+=======
+Copyright 2009 Kate Ward. All Rights Reserved.
+Released under the LGPL (GNU Lesser General Public License)
+Author: Kate Ward (kate.ward@forestent.com)
+
+This document covers any known issues and workarounds for the stated release of
+shFlags.
+
+Release info
+============
+
+This is a major bugfix release of shFlags. The biggest fix is in how non-flag
+arguments are made available to the script.
+
+Major changes
+-------------
+
+The use of the ``FLAGS_ARGC`` variable is now obsolete. It will be maintained
+for backwards compatibility with old scripts, but its value is known to be
+wrong when flag and non-flag arguments are mixed together on the command-line.
+
+To gain access to the non-flag arguments, replace the following snippet of code
+in your scripts with the updated version.
+
+:old: shift ${FLAGS_ARGC}
+:new: eval set -- "${FLAGS_ARGV}"
+
+Please see the CHANGES-1.0.txt file for a complete list of changes.
+
+Obsolete items
+--------------
+
+Bug fixes
+---------
+
+Issue# 7 Flags set with '=' result in off-by-one shifting error
+
+General info
+============
+
+The unit tests
+--------------
+
+shFlags is designed to work on as many environments as possible, but not all
+environments are created equal. As such, not all of the unit tests will succeed
+on every platform. The unit tests are therefore designed to fail, indicating to
+the tester that the supported functionality is not present, but an additional
+test is present to verify that shFlags properly caught the limitation and
+presented the user with an appropriate error message.
+
+shFlags tries to support both the standard and enhanced versions of ``getopt``.
+As each responds differently, and not everything is supported on the standard
+version, some unit tests will be skipped (i.e. ASSERTS will not be thrown) when
+the standard version of ``getopt`` is detected. The reason being that there is
+no point testing for functionality that is positively known not to exist. A
+tally of skipped tests will be kept for later reference.
+
+Standard vs Enhanced getopt
+---------------------------
+
+Here is a matrix of the supported features of the various **getopt** variants.
+
++-------------------------+---+---+
+|Feature |std|enh|
++=========================+===+===+
+|short option names | Y | Y |
+|long option names | N | Y |
+|spaces in string options | N | Y |
++-------------------------+---+---+
+
+Known Issues
+------------
+
+The **getopt** version provided by default with all versions of Mac OS X (up to
+and including 10.5.6) is the standard version. As such, only short flags are
+supported.
+
+The **getopt** version provided by default with all versions of Solaris (up to
+and including Solaris 10 and OpenSolaris) is the standard version. As such,
+only short flags are supported.
+
+Workarounds
+-----------
+
+The Zsh shell requires the ``shwordsplit`` option to be set, and the special
+``FLAGS_PARENT`` variable must be defined.
+
+
+.. vim:fileencoding=latin1:ft=rst:spell:tw=80
diff --git a/source/1.0/doc/contributors.txt b/source/1.0/doc/contributors.txt
index a097f78..146c0c0 100644
--- a/source/1.0/doc/contributors.txt
+++ b/source/1.0/doc/contributors.txt
@@ -1 +1,4 @@
-- Maciej Bliziński <blizinski@google.com> -- many code reviews
+I'd like to thank these people for their contributisons to shFlags.
+
+Maciej Bliziński <blizinski@google.com> -- _many_ code reviews
+Bjarni Einarsson <bre@google.com> -- bug reports
diff --git a/source/1.0/examples/debug_output.sh b/source/1.0/examples/debug_output.sh
index ed552ef..d54635f 100755
--- a/source/1.0/examples/debug_output.sh
+++ b/source/1.0/examples/debug_output.sh
@@ -10,17 +10,54 @@
#
# This script demonstrates the use of a boolean flag to enable custom
# functionality in a script.
+#
+# Try running these:
+# $ ./debug_output.sh speak
+# $ ./debug_output.sh sing
+# $ ./debug_output.sh --debug sing
# source shflags
. ../src/shflags
-debug() { [ ${FLAGS_debug} -eq ${FLAGS_TRUE} ] && echo "DEBUG: $@" >&2; }
-
# define flags
DEFINE_boolean 'debug' false 'enable debug mode' 'd'
+FLAGS_HELP=`cat <<EOF
+commands:
+ speak: say something
+ sing: sing something
+EOF`
+
+
+debug()
+{
+ [ ${FLAGS_debug} -eq ${FLAGS_TRUE} ] || return
+ echo "DEBUG: $@" >&2
+}
+
+die() {
+ [ $# -gt 0 ] && echo "error: $@" >&2
+ flags_help
+ exit 1
+}
+
# parse the command-line
-FLAGS "$@" || exit 1; shift ${FLAGS_ARGC}
+FLAGS "$@" || exit 1
+eval set -- "${FLAGS_ARGV}"
+
+command=$1
+case ${command} in
+ '') die ;;
+
+ speak)
+ debug "I'm getting ready to say something..."
+ echo 'The answer to the question "What is the meaning of life?" is "42".'
+ ;;
+
+ sing)
+ debug "I'm getting ready to sing something..."
+ echo 'I love to sing! La diddy da dum!'
+ ;;
-debug 'debug mode enabled'
-echo 'something interesting'
+ *) die "unrecognized command (${command})" ;;
+esac
diff --git a/source/1.0/examples/hello_world.sh b/source/1.0/examples/hello_world.sh
index d04a797..6fb2cb0 100755
--- a/source/1.0/examples/hello_world.sh
+++ b/source/1.0/examples/hello_world.sh
@@ -19,6 +19,7 @@
DEFINE_string 'name' 'world' 'name to say hello to' 'n'
# parse the command-line
-FLAGS "$@" || exit 1; shift ${FLAGS_ARGC}
+FLAGS "$@" || exit 1
+eval set -- "${FLAGS_ARGV}"
echo "Hello, ${FLAGS_name}!"
diff --git a/source/1.0/examples/write_date.sh b/source/1.0/examples/write_date.sh
index 0d9ccd0..85695cf 100755
--- a/source/1.0/examples/write_date.sh
+++ b/source/1.0/examples/write_date.sh
@@ -14,34 +14,46 @@
# - direct calling of the flags_help() function for script controlled usage
# output
# - handling of non-flag type command-line arguments that follow the flags
+#
+# Try the following:
+# $ ./write_date.sh now.out
+# $ cat now.out
+#
+# $ ./write_date.sh now.out
+# $ cat now.out
+#
+# $ ./write_date.sh -f now.out
+# $ cat now.out
# source shflags
. ../src/shflags
-write_date() { date >"$1"; }
-
# configure shflags
DEFINE_boolean 'force' false 'force overwriting' 'f'
FLAGS_HELP="USAGE: $0 [flags] filename"
-# parse the command-line
-FLAGS "$@" || exit 1; shift ${FLAGS_ARGC}
-# check for filename
-if [ $# -eq 0 ]; then
- echo 'error: filename missing' >&2
+write_date()
+{
+ date >"$1"
+}
+
+die()
+{
+ [ $# -gt 0 ] && echo "error: $@" >&2
flags_help
exit 1
-fi
+}
+
+
+# parse the command-line
+FLAGS "$@" || exit 1
+eval set -- "${FLAGS_ARGV}"
+
+# check for filename
+[ $# -gt 0 ] || die 'filename missing'
filename=$1
-if [ ! -f "${filename}" ]; then
- write_date "${filename}"
-else
- if [ ${FLAGS_force} -eq ${FLAGS_TRUE} ]; then
- write_date "${filename}"
- else
- echo 'warning: filename exists; not overwriting' >&2
- exit 2
- fi
-fi
+[ -f "${filename}" -a ${FLAGS_force} -eq ${FLAGS_FALSE} ] \
+ && die 'filename exists; not overwriting'
+write_date "${filename}"
diff --git a/source/1.0/src/shflags b/source/1.0/src/shflags
index 304e6db..805b07a 100644
--- a/source/1.0/src/shflags
+++ b/source/1.0/src/shflags
@@ -4,7 +4,8 @@
# 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
+# shFlags -- Advanced command-line flag library for Unix shell scripts.
+# http://code.google.com/p/shflags/
#
# Author: kate.ward@forestent.com (Kate Ward)
#
@@ -37,12 +38,17 @@
#
# EXAMPLE USAGE:
#
+# -- begin hello.sh --
# #! /bin/sh
# . ./shflags
-#
-# DEFINE_string name 'world' "somebody's name"
-# FLAGS "$@" || exit $?; shift ${FLAGS_ARGC}
+# 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.
@@ -72,7 +78,7 @@
# return if FLAGS already loaded
[ -n "${FLAGS_VERSION:-}" ] && return 0
-FLAGS_VERSION='1.0.2'
+FLAGS_VERSION='1.0.3pre'
FLAGS_TRUE=0
FLAGS_FALSE=1
@@ -97,17 +103,6 @@ if [ -n "${ZSH_VERSION:-}" ]; then
fi
fi
-# shell flags
-# u: treat unset variables as an error when performing parameter expansion
-__FLAGS_SHELL_FLAGS='u'
-
-# save the current set of shell flags, and then set some for ourself
-__flags_oldShellFlags=$-
-for __flags_shellFlag in `echo "${__FLAGS_SHELL_FLAGS}" |sed 's/\(.\)/\1 /g'`
-do
- set "-${__flags_shellFlag}"
-done
-
#
# constants
#
@@ -121,6 +116,7 @@ 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
@@ -183,16 +179,10 @@ __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_argc=0 # count of non-flag arguments
__flags_columns='' # screen width in columns
__flags_opts='' # temporary storage for parsed getopt flags
-# restore the previous set of shell flags
-for __flags_shellFlag in ${__FLAGS_SHELL_FLAGS}; do
- echo ${__flags_oldShellFlags} \
- |grep ${__flags_shellFlag} >/dev/null || set +${__flags_shellFlag}
-done
-unset __flags_oldShellFlags __flags_shellFlag
-
#------------------------------------------------------------------------------
# private functions
#
@@ -357,7 +347,7 @@ _flags_genOptStr()
${_flags_flag_} ${__FLAGS_INFO_SHORT_STR}`
if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then
_flags_opts_="${_flags_opts_}${_flags_shortName_}"
- # getopt needs a trailing ':' to indicate a needed option
+ # getopt needs a trailing ':' to indicate a required argument
[ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
_flags_opts_="${_flags_opts_}:"
fi
@@ -365,7 +355,7 @@ _flags_genOptStr()
${__FLAGS_OPTSTR_LONG})
_flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}"
- # getopt needs a trailing ':' to indicate a needed option
+ # getopt needs a trailing ':' to indicate a required argument
[ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
_flags_opts_="${_flags_opts_}:"
;;
@@ -554,7 +544,7 @@ _flags_validateInteger()
# @: varies: command-line options to parse
# Returns:
# integer: a FLAGS success condition
-_flags_standardGetopt()
+_flags_getoptStandard()
{
flags_return=${FLAGS_TRUE}
_flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
@@ -593,7 +583,7 @@ _flags_standardGetopt()
# @: varies: command-line options to parse
# Returns:
# integer: a FLAGS success condition
-_flags_enhancedGetopt()
+_flags_getoptEnhanced()
{
flags_return=${FLAGS_TRUE}
_flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
@@ -627,7 +617,6 @@ _flags_enhancedGetopt()
# integer: a FLAGS success condition
_flags_parseGetopt()
{
- FLAGS_ARGC=0
flags_return=${FLAGS_TRUE}
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
@@ -637,6 +626,13 @@ _flags_parseGetopt()
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
@@ -743,15 +739,16 @@ _flags_parseGetopt()
fi
fi
- # shift the option out
+ # shift the option and non-boolean arguements out.
shift
- FLAGS_ARGC=`expr ${FLAGS_ARGC} + 1`
+ [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift
+ done
- # additional shift for the argument
- if [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ]; then
- shift
- FLAGS_ARGC=`expr ${FLAGS_ARGC} + 1`
- fi
+ # 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_ \
@@ -795,12 +792,14 @@ FLAGS()
[ -z "${__flags_help_type:-}" ] && \
DEFINE_boolean 'help' false 'show this help' 'h'
+ # record original number of args for use elsewhere
+ __flags_argc=$#
+
# parse options
- # TODO(kward): look into '-T' option to test the internal getopt() version
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
- _flags_standardGetopt "$@"
+ _flags_getoptStandard "$@"
else
- _flags_enhancedGetopt "$@"
+ _flags_getoptEnhanced "$@"
fi
flags_return=$?
diff --git a/source/1.0/src/shflags_test_parsing.sh b/source/1.0/src/shflags_test_parsing.sh
index c027522..bc5e534 100755
--- a/source/1.0/src/shflags_test_parsing.sh
+++ b/source/1.0/src/shflags_test_parsing.sh
@@ -10,6 +10,7 @@
# shFlags unit test for the flag definition methods
#
# TODO(kward): assert on FLAGS errors
+# TODO(kward): testNonStandardIFS()
# load test helpers
. ./shflags_test_helpers
@@ -20,12 +21,12 @@
testStandardGetopt()
{
- _flags_standardGetopt '-b' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptStandard '-b' >"${stdoutF}" 2>"${stderrF}"
rslt=$?
assertTrue "didn't parse valid flag 'b'" ${rslt}
th_showOutput ${rslt} "${stdoutF}" "${stderrF}"
- _flags_standardGetopt '-x' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptStandard '-x' >"${stdoutF}" 2>"${stderrF}"
assertFalse "parsed invalid flag 'x'" $?
}
@@ -33,14 +34,14 @@ testEnhancedGetopt()
{
flags_getoptIsEnh || startSkipping
- _flags_enhancedGetopt '-b' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptEnhanced '-b' >"${stdoutF}" 2>"${stderrF}"
assertTrue "didn't parse valid flag 'b'" $?
- _flags_enhancedGetopt '--bool' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptEnhanced '--bool' >"${stdoutF}" 2>"${stderrF}"
assertTrue "didn't parse valid flag 'bool'" $?
- _flags_enhancedGetopt '-x' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptEnhanced '-x' >"${stdoutF}" 2>"${stderrF}"
assertFalse "parsed invalid flag 'x'" $?
- _flags_enhancedGetopt '--xyz' >"${stdoutF}" 2>"${stderrF}"
+ _flags_getoptEnhanced '--xyz' >"${stdoutF}" 2>"${stderrF}"
assertFalse "parsed invalid flag 'xyz'" $?
}
@@ -231,15 +232,15 @@ _testMultipleFlags()
_testNonFlagArgs()
{
- argc=$1
+ argv=$1
shift
- FLAGS $@
- assertTrue 'parse returned value.' $?
+ FLAGS "$@"
+ assertTrue 'parse returned non-zero value.' $?
- # shift out the parsed arguments to reach those that weren't parsed
- shift ${FLAGS_ARGC}
- assertSame 'wrong argc value.' ${argc} $#
+ eval set -- "${FLAGS_ARGV}"
+ assertEquals 'wrong count of argv arguments returned.' ${argv} $#
+ assertEquals 'wrong count of argc arguments returned.' 0 ${FLAGS_ARGC}
}
testSingleNonFlagArg()
@@ -254,10 +255,33 @@ testMultipleNonFlagArgs()
testMultipleNonFlagStringArgsWithSpaces()
{
- _testNonFlagArgs 3 argOne 'arg #2' arg3
+ _testNonFlagArgs 3 argOne 'arg two' arg3
}
-# TODO(kward): testNonStandardIFS()
+testFlagsWithEquals()
+{
+ FLAGS --str='str_flag' 'non_flag' >"${stdoutF}" 2>"${stderrF}"
+ assertTrue 'FLAGS returned a non-zero result' $?
+ assertEquals 'string flag not set properly' 'str_flag' "${FLAGS_str}"
+ th_showOutput ${rtrn} "${stdoutF}" "${stderrF}"
+
+ eval set -- "${FLAGS_ARGV}"
+ assertEquals 'wrong count of argv arguments returned.' 1 $#
+ assertEquals 'wrong count of argc arguments returned.' 1 ${FLAGS_ARGC}
+}
+
+testComplicatedCommandLine()
+{
+ FLAGS -i 1 --str='two' non_flag_1 --float 3 non_flag_two 'non flag 3' \
+ >"${stdoutF}" 2>"${stderrF}"
+ assertTrue 'FLAGS returned a non-zero result' $?
+ assertEquals 1 ${FLAGS_int}
+ assertEquals 'two' "${FLAGS_str}"
+ assertEquals 3 ${FLAGS_float}
+
+ eval set -- "${FLAGS_ARGV}"
+ assertEquals $# 3
+}
#------------------------------------------------------------------------------
# suite functions