diff --git a/AUTHORS b/AUTHORS index 77332636..a44db18b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,8 @@ R. Bernstein (rocky@gnu.org) + +Kate Ward is the author of shunit2 used in unit testing + +Stéphane Chazelas is the author of getopts_long.sh for GNU long options + processing + +Nikolaj Schumacher is the author of elk-test.el used in GNU Emacs testing diff --git a/Makefile.am b/Makefile.am index d46a36bf..3e515805 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,7 +30,7 @@ pkgdata_DATA = \ # Set up the install target bin_SCRIPTS = zshdb -EXTRA_DIST = $(pkgdata_DATA) THANKS getopt-test.sh +EXTRA_DIST = $(pkgdata_DATA) THANKS getopts_long.sh # cvs2cl MAINTAINERCLEANFILES = ChangeLog diff --git a/THANKS b/THANKS index 1b7f511a..f4c0db4b 100644 --- a/THANKS +++ b/THANKS @@ -1,2 +1,6 @@ Thanks to Peter Stephenson for the adding necessary support to zsh needed to get this off the ground and make debugging possible. + +Thanks to Kate Ward, Stéphane Chazelas and Nikolaj Schumacher for +programs used in conjunction with zshdb. + diff --git a/configure.ac b/configure.ac index d680372a..10d7736e 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,8 @@ AC_CONFIG_FILES([test/example/hanoi.sh], AC_CONFIG_FILES([test/unit/test-alias.sh], [chmod +x test/unit/test-alias.sh]) AC_CONFIG_FILES([test/unit/test-columns.sh], [chmod +x test/unit/test-columns.sh]) +AC_CONFIG_FILES([test/unit/test-dbg-opts.sh], + [chmod +x test/unit/test-dbg-opts.sh]) AC_CONFIG_FILES([test/unit/test-file.sh], [chmod +x test/unit/test-file.sh]) AC_CONFIG_FILES([test/unit/test-filecache.sh], diff --git a/dbg-main.sh b/dbg-main.sh index 6be2a166..e73b4544 100755 --- a/dbg-main.sh +++ b/dbg-main.sh @@ -6,7 +6,7 @@ # Software Foundation; either version 2, or (at your option) any later # version. # -# kshd is distributed in the hope that it will be useful, but WITHOUT ANY +# zshdb is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. diff --git a/dbg-opts.sh b/dbg-opts.sh index bd13ed35..2d3ef69e 100644 --- a/dbg-opts.sh +++ b/dbg-opts.sh @@ -31,69 +31,124 @@ options: (Needed in regression tests) -L libdir | --library libdir Set the directory location of library helper file: $_Dbg_main - -n | --nx |--no-init Don't run initialization files. + -n | --nx | --no-init Don't run initialization files. -V | --version Print the debugger version number. -x command | --command CMDFILE Execute debugger commands from CMDFILE. -" +" >&2 exit 100 } _Dbg_show_version() { printf 'There is absolutely no warranty for zshdb. Type "show warranty" for details. -' +' >&2 exit 101 + } +# Script arguments before adulteration by _Dbg_parse_otps +typeset -a _Dbg_orig_script_args +_Dbg_orig_script_args=($@) + + +# The following globals are set by _Dbg_parse_opts. Any values set are +# the default values. +typeset -a _Dbg_script_args + typeset -i _Dbg_annotate=0 typeset -i _Dbg_linetrace=0 +typeset -i _Dbg_basename_only=0 +typeset -i _Dbg_o_nx=0 + + +_Dbg_parse_options() { + + . ${_Dbg_libdir}/getopts_long.sh + + typeset -i _Dbg_o_quiet=0 + typeset -i _Dbg_o_version=0 -# Debugger command file -typeset _Dbg_o_cmdfile='' _Dbg_o_nx='' _Dbg_o_basename='' _Dbg_o_quiet='' - -local temp -zparseopts -D -- \ - A:=_Dbg_o_annotate -annotate:=_Dbg_o_annotate \ - B=_Dbg_o_basename -basename=_Dbg_o_basename \ - L:=temp -library:=temp \ - V=_Dbg_o_version -version=_Dbg_o_version \ - h=_Dbg_o_help -help=_Dbg_o_help \ - n=_Dbg_o_nx -nx=_Dbg_o_nx -no-init=_Dbg_o_nx \ - q=_Dbg_o_quiet -quiet=_Dbg_o_quiet \ - x:=_Dbg_o_cmdfile -command:=_Dbg_o_cmdfile - -[[ $? != 0 || "$_Dbg_o_help" != '' ]] && _Dbg_usage - -if [[ -z $_Dbg_o_quiet || -n $_Dbg_o_version ]]; then - print "Zsh Shell Debugger, release $_Dbg_release" - printf ' + while getopts_long A:Bx:hL:nqV opt \ + annotate required_argument \ + basename 0 \ + cmdfile required_argument \ + help 0 \ + '?' 0 \ + library required_argument \ + no-init 0 \ + nx 0 \ + quiet 0 \ + version 0 \ + '' "$@" + do + case "$opt" in + A | annotate ) + _Dbg_o_annotate=$OPTLARG + ;; + B | basename ) + _Dbg_basename_only=1 + ;; + x | command ) + DBG_INPUT=$OPTLARG + ;; + h | '?' | help ) + _Dbg_usage + ;; + L | library ) + ;; + V | version ) + _Dbg_o_version=1 + ;; + n | nx | no-init ) + _Dbg_o_nx=1 + ;; + q | quiet ) + _Dbg_o_quiet=1 + ;; + * ) + print "Unknown option $opt. Use -h or --help to see options" >&2 + exit 2 + ;; + esac + done + shift "$(($OPTLIND - 1))" + + if (( ! _Dbg_o_quiet && ! _Dbg_o_version )); then + print "Zsh Shell Debugger, release $_Dbg_release" + printf ' Copyright 2008 Rocky Bernstein This is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. ' -fi -[[ -n "$_Dbg_o_version" ]] && _Dbg_show_version -[[ -n "$_Dbg_o_basename" ]] && _Dbg_basename_only=1 -[[ -n "$_Dbg_o_cmdfile" ]] && { - typeset -a _Dbg_input - _Dbg_input=($_Dbg_o_cmdfile) - DBG_INPUT=${_Dbg_input[-1]} - unset _Dbg_input -} - + fi + (( _Dbg_o_version )) && _Dbg_show_version -# FIXME: check that _Dbg_o_annotate is an integer -if [[ -n $_Dbg_o_annotate ]] ; then - typeset -a level; eval "level=($_Dbg_o_annotate)" - if [[ ${level[-1]} == [0-9]* ]] ; then - if (( ${level[-1]} > 3 || ${level[-1]} < 0)); then - print "Annotation level must be less between 0 and 3. Got: ${level[-1]}." + if [[ -n $_Dbg_o_annotate ]] ; then + if [[ ${_Dbg_o_annotate} == [0-9]* ]] ; then + _Dbg_annotate=$_Dbg_o_annotate + if (( _Dbg_annotate > 3 || _Dbg_annotate < 0)); then + print "Annotation level must be less between 0 and 3. Got: $_Dbg_annotate." >&2 + print "Setting Annotation level to 0." >&2 + _Dbg_annotate=0 + fi else - _Dbg_annotate=${level[-1]} + print "Annotate option should be an integer, got ${_Dbg_o_annotate}." >&2 + print "Setting annotation level to 0." >&2 fi - else - print "Annotate option should be an integer, got ${level[-1]}." fi + unset _Dbg_o_annotate _Dbg_o_version _Dbg_o_quiet + _Dbg_script_args=($@) +} + +[[ -n $DBG_INPUT ]] && typeset -p DBG_INPUT + + +# Stand-alone Testing. +if [[ -n "$_Dbg_dbg_opts_test" ]] ; then + _Dbg_libdir='.' + _Dbg_parse_options "$@" + typeset -p _Dbg_annotate + typeset -p _Dbg_linetrace + typeset -p _Dbg_basename_only fi -unset _Dbg_o_annotate _Dbg_o_version _Dbg_o_basename _Dbg_o_cmdfile diff --git a/dbg-pre.sh b/dbg-pre.sh index 5a5af52a..9948b192 100644 --- a/dbg-pre.sh +++ b/dbg-pre.sh @@ -44,8 +44,6 @@ typeset -r _Dbg_release='0.01git' # Will be set to 1 if the top-level call is a debugger. typeset -i _Dbg_script=0 -typeset -i _Dbg_basename_only=0 - # Expand filename given as $1. # we echo the expanded name or return $1 unchanged if a bad filename. # Return is 0 if good or 1 if bad. @@ -97,6 +95,8 @@ _Dbg_tempname() { # Process command-line options . ${_Dbg_libdir}/dbg-opts.sh +OPTLIND=1 +_Dbg_parse_options "$@" if [[ ! -d $_Dbg_tmpdir ]] && [[ ! -w $_Dbg_tmpdir ]] ; then echo "${_Dbg_pname}: cannot write to temp directory $_Dbg_tmpdir." >&2 @@ -114,9 +114,6 @@ typeset _Dbg_init_cwd=$PWD # fi # fi -typeset -a _Dbg_script_args -_Dbg_script_args=($@) - typeset -i _Dbg_running=1 # True we are not finished running the program typeset -i _Dbg_currentbp=0 # If nonzero, the breakpoint number that we diff --git a/getopt-test.sh b/getopt-test.sh deleted file mode 100755 index 43e87484..00000000 --- a/getopt-test.sh +++ /dev/null @@ -1,7 +0,0 @@ -# Test for a getopt that handles long options properly. -TEMP=$(getopt -o :h --long help,library: -n 'foo' -- "--help") -if [[ " --help --" == $TEMP ]] ; then - exit 0 -else - exit 1 -fi diff --git a/getopts_long.sh b/getopts_long.sh new file mode 100644 index 00000000..29a9504c --- /dev/null +++ b/getopts_long.sh @@ -0,0 +1,675 @@ +#! /bin/echo Usage:. +# +# getopts_long -- POSIX shell getopts with GNU-style long option support +# +# Copyright 2005-2008 Stephane Chazelas +# +# Permission to use, copy, modify, distribute, and sell this software and +# its documentation for any purpose is hereby granted without fee, provided +# that the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. No representations are made about the suitability of this +# software for any purpose. It is provided "as is" without express or +# implied warranty. + + +getopts_long() { + # args: shortopts, var, [name, type]*, "", "$@" + # + # getopts_long parses command line arguments. It works like the + # getopts shell built-in command except that it also recognises long + # options a la GNU. + # + # You must provide getopts_long with the list of supported single + # letter options in the same format as getopts', followed by the + # variable name you want getopts_long to return the current processed + # option in, followed by the list of long option names (without the + # leading "--") and types (0 or no_argument, 1 or required_argument, + # 2 or optional_argument). The end of the long option specification + # is indicated by an empty argument. Then follows the list of + # arguments to be parsed. + # + # The $OPTLIND variable must be set to 1 before the first call of the + # getopts_long function to process a given list of arguments. + # + # getopts_long returns the value of the current option in the variable + # whose name is provided as its second argument (be careful to avoid + # variables that have a special signification to getopts_long or the + # shell or any other tool you may call from your script). If the + # current option is a single letter option, then it is returned + # without the leading "-". If it's a long option (possibly + # abbreviated), then the full name of the option (without the leading + # "--") is returned. If the option has an argument, then it is stored + # in the $OPTLARG variable. If the current option is not recognised, + # or if it is provided with an argument while it is not expecting one + # (as in --opt=value) or if it is not provided with an argument while + # it is expecting one, or if the option is so abbreviated that it is + # impossible to identify the option uniquely, then: + # - if the short option specifications begin with ":", getopts_long + # returns ":" in the output variable and $OPTLARG contains the + # faulty option name (in full except in the case of the ambiguous + # or bad option) and $OPTLERR contains the error message. + # - if not, then getopts_long behaves the same as above except that + # it returns "?" instead of ":", leaves $OPTLARG unset and + # displays the error message on stderr. + # + # The exit status of getopts_long is 0 unless the end of options is + # reached or an error is encountered in the syntax of the getopts_long + # call. + # + # After getopts_long has finished processing the options, $OPTLIND + # contains the index of the first non-option argument or $# + 1 if + # there's no non-option argument. + # + # The "=" character is not allowed in a long option name. Any other + # character is. "-" and ":" are not allowed as short option names. Any + # other character is. If a short option appears more than once in the + # specification, the one with the greatest number of ":"s following it + # is retained. If a long option name is provided more than once, only + # the first one is taken into account. Note that if you have both a -a + # and --a option, there's no way to differentiate them. Beside the + # $OPTLIND, $OPTLARG, and $OPTLERR, getopts_long uses the $OPTLPENDING + # variable to hold the remaining options to be processed for arguments + # with several one-letter options. That variable shouldn't be used + # anywhere else in your script. Those 4 variables are the only ones + # getopts_long may modify. + # + # Dependency: only POSIX utilities are called by that function. They + # are "set", "unset", "shift", "break", "return", "eval", "command", + # ":", "printf" and "[". Those are generally built in the POSIX + # shells. Only "printf" has been known not to be in some old versions + # of bash, zsh or ash based shells. + # + # Differences with the POSIX getopts: + # - if an error is detected during the parsing of command line + # arguments, the error message is stored in the $OPTLERR variable + # - in the single-letter option specification, if a letter is + # followed by 2 colons ("::"), then the option can have an optional + # argument as in GNU getopt(3). In that case, the argument must + # directly follow the option as in -oarg (not -o arg). + # - there must be an empty argument to mark the end of the option + # specification. + # - long options starting with "--" are supported. + # + # Differences with GNU getopt_long(3): + # - getopts_long doesn't allow options to be interspersed with other + # arguments (as if POSIXLY_CORRECT was set for GNU getopt_long(3)) + # - there's no linkage of any sort between the short and long + # options. The caller is responsible of that (see example below). + # + # Compatibility: + # getopts_long code is (hopefully) POSIX.2/SUSv3 compliant. It won't + # work with the Bourne/SystemV shell. Use /usr/xpg4/bin/sh or ksh or + # bash on Solaris. + # It has been tested successfully with: + # - bash 3.0 (patch level 16) on Cygwin + # - zsh 4.2.4 on Solaris 2.7 + # - /usr/xpg4/bin/sh (same as /usr/bin/ksh) (ksh88i) on Solaris 2.7 + # - /usr/dt/bin/dtksh (ksh93d) on Solaris 2.7 + # - /usr/bin/ksh (pdksh 5.2.14) on Linux + # - zsh 3.0.6 on Solaris 2.8 + # - bash 2.0.3 on Solaris 2.8 + # - dash 0.5.2 on Linux + # - bash 2.05b (patch level 0) on Linux + # - ksh93p and ksh93q on Linux + # + # It is known to fail with those non-POSIX compliant shells: + # - /bin/sh on Solaris + # - /usr/bin/sh on Cygwin + # - bash 1.x + # + # Bugs: + # please report them to + # + # Example: + # + # verbose=false opt_bar=false bar=default_bar foo=default_foo + # opt_s=false opt_long=false + # OPTLIND=1 + # while getopts_long :sf:b::vh opt \ + # long 0 \ + # foo required_argument \ + # bar 2 \ + # verbose no_argument \ + # help 0 "" "$@" + # do + # case "$opt" in + # s) opt_s=true;; + # long) opt_long=true;; + # v|verbose) verbose=true;; + # h|help) usage; exit 0;; + # f|foo) foo=$OPTLARG;; + # b|bar) bar=${OPTLARG-$bar};; + # :) printf >&2 '%s: %s\n' "${0##*/}" "$OPTLERR" + # usage + # exit 1;; + # esac + # done + # shift "$(($OPTLIND - 1))" + # # process the remaining arguments + + [ -n "${ZSH_VERSION+z}" ] && emulate -L sh + + unset OPTLERR OPTLARG || : + + case "$OPTLIND" in + "" | 0 | 1 | *[!0-9]*) + # First time in the loop. Initialise the parameters. + OPTLIND=1 + OPTLPENDING= + ;; + esac + + if [ "$#" -lt 2 ]; then + printf >&2 'getopts_long: not enough arguments\n' + return 1 + fi + + # validate variable name. Need to fix locale for character ranges. + LC_ALL=C command eval ' + case "$2" in + *[!a-zA-Z_0-9]*|""|[0-9]*) + printf >&2 "getopts_long: invalid variable name: \`%s'\''\n" "$2" + return 1 + ;; + esac' + + # validate short option specification + case "$1" in + ::*|*:::*|*-*) + printf >&2 "getopts_long: invalid option specification: \`%s'\n" "$1" + return 1 + ;; + esac + + # validate long option specifications + + # POSIX shells only have $1, $2... as local variables, hence the + # extensive use of "set" in that function. + + set 4 "$@" + while :; do + if + [ "$1" -gt "$#" ] || { + eval 'set -- "${'"$1"'}" "$@"' + [ -n "$1" ] || break + [ "$(($2 + 2))" -gt "$#" ] + } + then + printf >&2 "getopts_long: long option specifications must end in an empty argument\n" + return 1 + fi + eval 'set -- "${'"$(($2 + 2))"'}" "$@"' + # $1 = type, $2 = name, $3 = $@ + case "$2" in + *=*) + printf >&2 "getopts_long: invalid long option name: \`%s'\n" "$2" + return 1 + ;; + esac + case "$1" in + 0 | no_argument) ;; + 1 | required_argument) ;; + 2 | optional_argument) ;; + *) + printf >&2 "getopts_long: invalid long option type: \`%s'\n" "$1" + return 1 + ;; + esac + eval "shift 3; set $(($3 + 2))"' "$@"' + done + shift + + eval "shift; set $(($1 + $OPTLIND))"' "$@"' + + # unless there are pending short options to be processed (in + # $OPTLPENDING), the current option is now in ${$1} + + if [ -z "$OPTLPENDING" ]; then + [ "$1" -le "$#" ] || return 1 + eval 'set -- "${'"$1"'}" "$@"' + + case "$1" in + --) + OPTLIND=$(($OPTLIND + 1)) + return 1 + ;; + --*) + ;; + -?*) + OPTLPENDING="${1#-}" + shift + ;; + *) + return 1 + ;; + esac + OPTLIND=$(($OPTLIND + 1)) + fi + + if [ -n "$OPTLPENDING" ]; then + # WA for zsh and bash 2.03 bugs: + OPTLARG=${OPTLPENDING%"${OPTLPENDING#?}"} + set -- "$OPTLARG" "$@" + OPTLPENDING="${OPTLPENDING#?}" + unset OPTLARG + + # $1 = current option = ${$2+1}, $3 = $@ + + case "$1" in + [-:]) + OPTLERR="bad option: \`-$1'" + case "$3" in + :*) + eval "$4=:" + OPTLARG="$1" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$4='?'" + ;; + esac + ;; + + *) + case "$3" in + *"$1"::*) # optional argument + eval "$4=\"\$1\"" + if [ -n "$OPTLPENDING" ]; then + # take the argument from $OPTLPENDING if any + OPTLARG="$OPTLPENDING" + OPTLPENDING= + fi + ;; + + *"$1":*) # required argument + if [ -n "$OPTLPENDING" ]; then + # take the argument from $OPTLPENDING if any + OPTLARG="$OPTLPENDING" + eval "$4=\"\$1\"" + OPTLPENDING= + else + # take the argument from the next argument + if [ "$(($2 + 2))" -gt "$#" ]; then + OPTLERR="option \`-$1' requires an argument" + case "$3" in + :*) + eval "$4=:" + OPTLARG="$1" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$4='?'" + ;; + esac + else + OPTLIND=$(($OPTLIND + 1)) + eval "OPTLARG=\"\${$(($2 + 2))}\"" + eval "$4=\"\$1\"" + fi + fi + ;; + + *"$1"*) # no argument + eval "$4=\"\$1\"" + ;; + *) + OPTLERR="bad option: \`-$1'" + case "$3" in + :*) + eval "$4=:" + OPTLARG="$1" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$4='?'" + ;; + esac + ;; + esac + ;; + esac + else # long option + + # remove the leading "--" + OPTLPENDING="$1" + shift + set 6 "${OPTLPENDING#--}" "$@" + OPTLPENDING= + + while + eval 'set -- "${'"$1"'}" "$@"' + [ -n "$1" ] + do + # $1 = option name = ${$2+1}, $3 => given option = ${$4+3}, $5 = $@ + + case "${3%%=*}" in + "$1") + OPTLPENDING=EXACT + break;; + esac + + # try to see if the current option can be seen as an abbreviation. + case "$1" in + "${3%%=*}"*) + if [ -n "$OPTLPENDING" ]; then + [ "$OPTLPENDING" = AMBIGUOUS ] || eval '[ "${'"$(($OPTLPENDING + 2))"'}" = "$1" ]' || + OPTLPENDING=AMBIGUOUS + # there was another different option matching the current + # option. The eval thing is in case one option is provided + # twice in the specifications which is OK as per the + # documentation above + else + OPTLPENDING="$2" + fi + ;; + esac + eval "shift 2; set $(($2 + 2)) "'"$@"' + done + + case "$OPTLPENDING" in + AMBIGUOUS) + OPTLERR="option \`--${3%%=*}' is ambiguous" + case "$5" in + :*) + eval "$6=:" + OPTLARG="${3%%=*}" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$6='?'" + ;; + esac + OPTLPENDING= + return 0 + ;; + EXACT) + eval 'set "${'"$(($2 + 2))"'}" "$@"' + ;; + "") + OPTLERR="bad option: \`--${3%%=*}'" + case "$5" in + :*) + eval "$6=:" + OPTLARG="${3%%=*}" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$6='?'" + ;; + esac + OPTLPENDING= + return 0 + ;; + *) + # we've got an abbreviated long option. + shift + eval 'set "${'"$(($OPTLPENDING + 1))"'}" "${'"$OPTLPENDING"'}" "$@"' + ;; + esac + + OPTLPENDING= + + # $1 = option type, $2 = option name, $3 unused, + # $4 = given option = ${$5+4}, $6 = $@ + + case "$4" in + *=*) + case "$1" in + 1 | required_argument | 2 | optional_argument) + eval "$7=\"\$2\"" + OPTLARG="${4#*=}" + ;; + *) + OPTLERR="option \`--$2' doesn't allow an argument" + case "$6" in + :*) + eval "$7=:" + OPTLARG="$2" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$7='?'" + ;; + esac + ;; + esac + ;; + + *) + case "$1" in + 1 | required_argument) + if [ "$(($5 + 5))" -gt "$#" ]; then + OPTLERR="option \`--$2' requires an argument" + case "$6" in + :*) + eval "$7=:" + OPTLARG="$2" + ;; + *) + printf >&2 '%s\n' "$OPTLERR" + eval "$7='?'" + ;; + esac + else + OPTLIND=$(($OPTLIND + 1)) + eval "OPTLARG=\"\${$(($5 + 5))}\"" + eval "$7=\"\$2\"" + fi + ;; + *) + # optional argument (but obviously not provided) or no + # argument + eval "$7=\"\$2\"" + ;; + esac + ;; + esac + fi + return 0 +} + +# testing code +if [ -n "$_Dbg_getopts_long_test" ]; then +test_getopts_long() { + expected="$1" had= + shift + OPTLIND=1 + + while err="$(set +x;getopts_long "$@" 2>&1 > /dev/null)" + getopts_long "$@" 2> /dev/null; do + eval "opt=\"\$$2\"" + had="$had|$opt@${OPTLARG-unset}@${OPTLERR-unset}@$err" + done + had="$had|$OPTLIND|$err" + + if [ "$had" = "$expected" ]; then + echo PASS + else + echo FAIL + printf 'Expected: %s\n Got: %s\n' "$expected" "$had" + fi +} +while IFS= read -r c && IFS= read -r e; do + printf '+ %-72s ' "$c" + #set -x + eval "test_getopts_long \"\$e\" $c" +done << \EOF +: a +|1|getopts_long: long option specifications must end in an empty argument +:a opt "" -a +|a@unset@unset@|2| +:a opt "" -a b +|a@unset@unset@|2| +:a opt "" -a -a +|a@unset@unset@|a@unset@unset@|3| +:a opt "" -ab +|a@unset@unset@|:@b@bad option: `-b'@|2| +:a: opt "" -ab +|a@b@unset@|2| +:a: opt "" -a b +|a@b@unset@|3| +:a: opt "" -a -a +|a@-a@unset@|3| +:a: opt "" -a +|:@a@option `-a' requires an argument@|2| +:a:: opt "" -a +|a@unset@unset@|2| +:a:: opt "" -ab +|a@b@unset@|2| +:a:: opt "" -a b +|a@unset@unset@|2| +:a:: opt "" -a -a +|a@unset@unset@|a@unset@unset@|3| +:a:: opt "" -:a: +|:@:@bad option: `-:'@|a@:@unset@|2| +:= opt "" +|1| +:: opt "" +|1|getopts_long: invalid option specification: `::' +: opt "" +|1| +:a:a opt "" -a +|:@a@option `-a' requires an argument@|2| +:a::a opt "" -a +|a@unset@unset@|2| +:ab:c:: opt "" -abc -cba -bac +|a@unset@unset@|b@c@unset@|c@ba@unset@|b@ac@unset@|4| +: opt abc 0 "" --abc +|abc@unset@unset@|2| +: opt abc no_argument "" --abc +|abc@unset@unset@|2| +: opt abc no_argument "" --abc=foo +|:@abc@option `--abc' doesn't allow an argument@|2| +: opt abc no_argument "" --abc foo +|abc@unset@unset@|2| +: opt abc 1 "" --abc=foo +|abc@foo@unset@|2| +: opt abc required_argument "" --abc foo +|abc@foo@unset@|3| +: opt abc required_argument "" --abc= +|abc@@unset@|2| +: opt abc required_argument "" --abc +|:@abc@option `--abc' requires an argument@|2| +: opt abc 2 "" --abc +|abc@unset@unset@|2| +: opt abc optional_argument "" --abc= +|abc@@unset@|2| +: opt abc optional_argument "" --abc=foo +|abc@foo@unset@|2| +: opt abc optional_argument "" --abc --abc +|abc@unset@unset@|abc@unset@unset@|3| +: opt abc 0 abcd 0 "" --abc +|abc@unset@unset@|2| +: opt abc 0 abd 0 "" --ab +|:@ab@option `--ab' is ambiguous@|2| +: opt abc 0 abcd 0 "" --ab +|:@ab@option `--ab' is ambiguous@|2| +: opt abc 0 abc 1 "" --abc +|abc@unset@unset@|2| +: opt abc 0 acd 0 "" --ab +|abc@unset@unset@|2| +:abc:d:e::f:: opt ab 0 ac 1 bc 2 cd 1 cde 2 "" -abcdef -a -f -c --a --a= --b=foo -fg +|a@unset@unset@|b@unset@unset@|c@def@unset@|a@unset@unset@|f@unset@unset@|c@--a@unset@|:@a@option `--a' is ambiguous@|bc@foo@unset@|f@g@unset@|9| +a opt "" -a +|a@unset@unset@|2| +a opt "" -a b +|a@unset@unset@|2| +a opt "" -a -a +|a@unset@unset@|a@unset@unset@|3| +a opt "" -ab +|a@unset@unset@|?@unset@bad option: `-b'@bad option: `-b'|2| +a: opt "" -ab +|a@b@unset@|2| +a: opt "" -a b +|a@b@unset@|3| +a: opt "" -a -a +|a@-a@unset@|3| +a: opt "" -a +|?@unset@option `-a' requires an argument@option `-a' requires an argument|2| +a:: opt "" -a +|a@unset@unset@|2| +a:: opt "" -ab +|a@b@unset@|2| +a:: opt "" -a b +|a@unset@unset@|2| +a:: opt "" -a -a +|a@unset@unset@|a@unset@unset@|3| +a:: opt "" -:a: +|?@unset@bad option: `-:'@bad option: `-:'|a@:@unset@|2| += opt "" +|1| +: opt "" +|1| +'' opt "" +|1| +a:a opt "" -a +|?@unset@option `-a' requires an argument@option `-a' requires an argument|2| +a::a opt "" -a +|a@unset@unset@|2| +ab:c:: opt "" -abc -cba -bac +|a@unset@unset@|b@c@unset@|c@ba@unset@|b@ac@unset@|4| +'' opt abc 0 "" --abc +|abc@unset@unset@|2| +'' opt abc no_argument "" --abc +|abc@unset@unset@|2| +'' opt abc no_argument "" --abc=foo +|?@unset@option `--abc' doesn't allow an argument@option `--abc' doesn't allow an argument|2| +'' opt abc no_argument "" --abc foo +|abc@unset@unset@|2| +'' opt abc 1 "" --abc=foo +|abc@foo@unset@|2| +'' opt abc required_argument "" --abc foo +|abc@foo@unset@|3| +'' opt abc required_argument "" --abc= +|abc@@unset@|2| +'' opt abc required_argument "" --abc +|?@unset@option `--abc' requires an argument@option `--abc' requires an argument|2| +'' opt abc 2 "" --abc +|abc@unset@unset@|2| +'' opt abc optional_argument "" --abc= +|abc@@unset@|2| +'' opt abc optional_argument "" --abc=foo +|abc@foo@unset@|2| +'' opt abc optional_argument "" --abc --abc +|abc@unset@unset@|abc@unset@unset@|3| +'' opt abc 0 abcd 0 "" --abc +|abc@unset@unset@|2| +'' opt abc 0 abd 0 "" --ab +|?@unset@option `--ab' is ambiguous@option `--ab' is ambiguous|2| +'' opt abc 0 abcd 0 "" --ab +|?@unset@option `--ab' is ambiguous@option `--ab' is ambiguous|2| +'' opt abc 0 abc 1 "" --abc +|abc@unset@unset@|2| +'' opt abc 0 acd 0 "" --ab +|abc@unset@unset@|2| +abc:d:e::f:: opt ab 0 ac 1 bc 2 cd 1 cde 2 "" -abcdef -a -f -c --a --a= --b=foo -fg +|a@unset@unset@|b@unset@unset@|c@def@unset@|a@unset@unset@|f@unset@unset@|c@--a@unset@|?@unset@option `--a' is ambiguous@option `--a' is ambiguous|bc@foo@unset@|f@g@unset@|9| +: '' '' a +|1|getopts_long: invalid variable name: `' +: 1a '' +|1|getopts_long: invalid variable name: `1a' +- a +|1|getopts_long: invalid option specification: `-' +:a::a:abcd o ab 1 abc 1 abd 1 abe 1 abc 2 '' -aa --ab 1 --abc +|a@a@unset@|ab@1@unset@|:@abc@option `--abc' requires an argument@|5| +: +|1|getopts_long: not enough arguments +'\[$' o -- 0 ' ' 1 '#' required_argument '' '-\\\[$' --\ =a --\#=\$\$ +|\@unset@unset@|\@unset@unset@|\@unset@unset@|[@unset@unset@|$@unset@unset@| @a@unset@|#@$$@unset@|4| +: o a 1 b 2 c +|1|getopts_long: long option specifications must end in an empty argument +: o a 1 b 2 +|1|getopts_long: long option specifications must end in an empty argument +: o a 1 b 2 c 3 '' --c +|1|getopts_long: invalid long option type: `3' +": " o " " 1 '' "- " "-- =1" +| @unset@unset@| @unset@unset@| @1@unset@|3| +: o a 1 '' --c +|:@c@bad option: `--c'@|2| +: o a 1 '' --c=foo +|:@c@bad option: `--c'@|2| +: o ab 1 ac 1 ad 1 a 1 '' --a=1 +|a@1@unset@|2| +EOF +fi diff --git a/test/unit/.gitignore b/test/unit/.gitignore index a75db35f..3cb82ef1 100644 --- a/test/unit/.gitignore +++ b/test/unit/.gitignore @@ -4,6 +4,7 @@ /Makefile.in /test-alias.sh /test-columns.sh +/test-dbg-opts.sh /test-file.sh /test-filecache.sh /test-fns.sh diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index 24d5f614..da78b3cf 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -1,5 +1,6 @@ TESTS = test-alias.sh \ test-columns.sh \ + test-dbg-opts.sh \ test-file.sh \ test-filecache.sh \ test-fns.sh \ @@ -19,7 +20,8 @@ TESTS_ENVIRONMENT = \ EXTRA_DIST = $(TESTS) $(check_DATA) \ test-alias.sh.in \ - test-columns.sh \ + test-columns.sh.in \ + test-dbg-opts.sh.in \ test-file.sh.in \ test-filecache.sh.in \ test-fns.sh.in \ diff --git a/test/unit/shunit2 b/test/unit/shunit2 index 9fdacca2..4115ddcb 100644 --- a/test/unit/shunit2 +++ b/test/unit/shunit2 @@ -64,7 +64,7 @@ for shunit_const_ in ${shunit_constants_}; do *) shunit_ro_opts_='-g' ;; # declare readonly constants globally esac fi - readonly ${shunit_ro_opts_} ${shunit_const_} + # readonly ${shunit_ro_opts_} ${shunit_const_} done unset shunit_const_ shunit_constants_ shunit_ro_opts_ @@ -380,7 +380,7 @@ assertTrue() [ -z "${shunit_message_:-}" ] && shunit_message_='' if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" + shunit_message_="$1" shift fi shunit_condition_=$1 @@ -450,7 +450,7 @@ assertFalse() [ -z "${shunit_message_:-}" ] && shunit_message_='' if [ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" + shunit_message_="$1" shift fi shunit_condition_=$1 @@ -513,7 +513,7 @@ fail() [ -z "${shunit_message_:-}" ] && shunit_message_='' if [ $# -eq 1 ]; then - shunit_message_="${shunit_message_}$1" + shunit_message_="$1" shift fi diff --git a/test/unit/test-columns.sh.in b/test/unit/test-columns.sh.in index 7c703f31..630ecaf4 100644 --- a/test/unit/test-columns.sh.in +++ b/test/unit/test-columns.sh.in @@ -1,6 +1,5 @@ #!@SH_PROG@ # -*- shell-script -*- - PS4='(%x:%I): [%?] zsh+ ' setopt ksharrays @@ -42,12 +41,12 @@ test_columnized() } -# Make sure @top_builddir@ has a trailing slash if [ '@abs_top_srcdir@' = '' ] ; then echo "Something is wrong abs_top_srcdir is not set." exit 1 fi abs_top_srcdir=@abs_top_srcdir@ +# Make sure @top_srcdir@ has a trailing slash abs_top_srcdir=${abs_top_srcdir%%/}/ . $abs_top_srcdir/lib/columns.sh diff --git a/test/unit/test-dbg-opts.sh.in b/test/unit/test-dbg-opts.sh.in new file mode 100755 index 00000000..bae45967 --- /dev/null +++ b/test/unit/test-dbg-opts.sh.in @@ -0,0 +1,74 @@ +#!@SH_PROG@ +# -*- shell-script -*- +PS4='(%x:%I): [%?] zsh+ +' + +traceAssertEquals() { + first="$1" + second="$2" + third="$3" + typeset -p first + typeset -p second + typeset -p third +} + +do_opts_test() { + if (( $# < 3 )); then + assertTrue "Too few parameters: $# should be at least 3" $(($# < 3)) + return 1 + fi + typeset assert_msg="$1"; shift + typeset expected_eval="$1"; shift + typeset expected_value="$1" ; shift + # typeset -p assert_msg + # typeset -p expected_eval + # typeset -p expected_value + + . ${abs_top_srcdir}/dbg-opts.sh + OPTLIND=1 + _Dbg_parse_options "$@" + assertEquals "$assert_msg" "$expected_value" "$(eval $expected_eval)" +} + +test_opts() +{ + # Eval expression value options + msg='Short annotate' + do_opts_test "$msg" 'print $_Dbg_annotate' 1 -q -A 1 + msg='Long annotate' + do_opts_test "$msg" 'print $_Dbg_annotate' 3 --quiet --annotate 3 + msg='Annotate default' + do_opts_test "$msg" 'print $_Dbg_annotate' 0 --quiet + msg='Short basename' + do_opts_test "$msg" 'print $_Dbg_basename_only' 1 -B --quiet + msg='basename default' + do_opts_test "$msg" 'print $_Dbg_basename_only' 0 --quiet + msg='Long basename' + do_opts_test "$msg" 'print $_Dbg_basename_only' 1 --quiet --basename + msg='Long --no-init' + do_opts_test "$msg" 'print $_Dbg_o_nx' 1 --no-init --quiet + msg='--no-init default' + do_opts_test "$msg" 'print $_Dbg_o_nx' 0 -q + msg='Short --no-init (-n)' + do_opts_test "$msg" 'print $_Dbg_o_nx' 1 -n --quiet + msg='Alternate no-init' + do_opts_test "$msg" 'print $_Dbg_o_nx' 1 -B -q -L . --nx +} + +if [ '@abs_top_srcdir@' = '' ] ; then + echo "Something is wrong abs_top_srcdir is not set." + exit 1 +fi +abs_top_srcdir=@abs_top_srcdir@ +# Make sure @top_srcdir@ has a trailing slash +abs_top_srcdir=${abs_top_srcdir%%/}/ +_Dbg_libdir=$abs_top_srcdir + +set -o shwordsplit +SHUNIT_PARENT=$0 + +# load shunit2 +shunit_file=${abs_top_srcdir}test/unit/shunit2 +. ${shunit_file} + +