Fix gsu_cword_is_option_parameter().
[gsu.git] / subcommand
index b12783b1692bff8aba74beed03c19adbc773e096..c04f23feeb5ae018ce0e0ae1fea46efe20318b40 100644 (file)
@@ -4,7 +4,7 @@
 
 if [[ "$(type -t _gsu_setup)" != "function" ]]; then
        gsu_dir=${gsu_dir:-${BASH_SOURCE[0]%/*}}
-       . $gsu_dir/common || exit 1
+       . "$gsu_dir/common" || exit 1
        _gsu_setup
 fi
 
@@ -46,7 +46,7 @@ _gsu_available_commands()
 
                        # otherwise delete it
                        d
-               ' $0
+               ' "$0"
        } | sort | tr '\n' ' ')"
 }
 
@@ -79,6 +79,91 @@ gsu_check_arg_count()
        ret=$GSU_SUCCESS
 }
 
+# Wrapper for the bash getopts builtin.
+#
+# Aborts on programming errors such as missing or invalid option string.  On
+# success $result contains shell code that can be eval'ed. For each defined
+# option x, the local variable o_x will be created when calling eval "$result".
+# o_x contains true/false for options without argument and either the empty
+# string or the given argument for options that take an argument.
+#
+# Example:
+#      gsu_getopts abc:x:y
+#      eval "$result"
+#      (($ret < 0)) && return
+#
+#      [[ "$o_a" = 'true' ]] && echo 'The -a flag was given'
+#      [[ -n "$o_c" ]] && echo "The -c option was given with arg $o_c"
+gsu_getopts()
+{
+       local i c tab=' ' cr='
+'
+
+       gsu_check_arg_count $# 1 1
+       if (($ret < 0)); then
+               gsu_err_msg
+               exit 1
+       fi
+
+       ret=-$E_GSU_GETOPTS
+       result="invalid optstring $1"
+       if [[ -z "$1" ]] || grep -q '::' <<< "$1" ; then
+               gsu_err_msg
+               exit 1
+       fi
+
+       for ((i=0; i < ${#1}; i++)); do
+               c=${1:$i:1}
+               case "$c" in
+               [a-zA-Z:]);;
+               *)
+                       ret=-$E_GSU_GETOPTS
+                       result="invalid character $c in optstring"
+                       gsu_err_msg
+                       exit 1
+               esac
+       done
+       result="local _gsu_getopts_opt"
+       for ((i=0; i < ${#1}; i++)); do
+               c1=${1:$i:1}
+               c2=${1:$(($i + 1)):1}
+               result+=" o_$c1="
+               if [[ "$c2" = ":" ]]; then
+                       let i++
+               else
+                       result+="false"
+               fi
+       done
+       result+="
+       OPTIND=1
+       while getopts $1 _gsu_getopts_opt \"\$@\"; do
+               case \"\$_gsu_getopts_opt\" in
+"
+       for ((i=0; i < ${#1}; i++)); do
+               c1=${1:$i:1}
+               c2=${1:$(($i + 1)):1}
+               result+="$tab$tab$c1) o_$c1="
+               if [[ "$c2" = ":" ]]; then
+                       result+="\"\$OPTARG\""
+                       let i++
+               else
+                       result+="true"
+               fi
+               result+=";;$cr"
+       done
+       result+="
+               *)
+                       ret=-\$E_GSU_GETOPTS
+                       result=\"invalid option given\"
+                       return
+                       ;;
+               esac
+       done
+       shift \$((\$OPTIND - 1))
+"
+       ret=$GSU_SUCCESS
+}
+
 _gsu_print_available_commands()
 {
        local cmd cmds
@@ -124,7 +209,7 @@ gsu_complete_options()
 
 com_prefs_options='e'
 
-export gsu_prefs_txt="
+_gsu_prefs_txt="
 Print the current preferences.
 
 Usage: prefs [-e]
@@ -170,40 +255,52 @@ com_prefs()
                        printf "# optional"
                        ;;
                esac
-               printf " $option_type: $description"
+               printf "%s: %s" "$option_type" "$description"
                if [[ "$required" != "yes" && "$required" != "true" ]]; then
-                       printf " [$default_value]"
+                       printf " [%s]" "$default_value"
                fi
                echo
                [[ -n "$help_text" ]] && sed -e '/^[    ]*$/d; s/^[     ]*/#    /g' <<< "$help_text"
-               printf "$name=$val"
+               printf "%s=%s" "$name" "$val"
                [[ "$val" == "$default_value" ]] && printf " # default"
                echo
        done
 }
 
+_gsu_isatty()
+{(
+       exec 3<&1
+       stty 0<&3 &> /dev/null
+)}
+
 complete_prefs()
 {
        gsu_complete_options "$com_prefs_options" "$@"
 }
 
-export gsu_man_txt="
+_gsu_man_txt='
 Print the manual.
 
-Usage: man"
+Usage: man
 
+If stdout associated with a terminal device, output is piped to
+$PAGER. If $PAGER is unset, less(1) is assumed.
+'
 
 com_man()
 {
        local equal_signs="=================================================="
        local minus_signs="--------------------------------------------------"
-       local com num
+       local com num pager='cat'
 
+       _gsu_isatty && pager="${PAGER:-less}"
+       [[ "$pager" == 'less' ]] && export LESS=${LESS-RI}
+       {
        echo "$gsu_name (_${gsu_banner_txt}_) manual"
        echo "${equal_signs:0:${#gsu_name} + ${#gsu_banner_txt} + 16}"
        echo
 
-       sed -e '1,/^#\{70,\}/d' -e '/^#\{70,\}/,$d' $0 -e 's/^# *//'
+       sed -e '1,/^#\{70,\}/d' -e '/^#\{70,\}/,$d' "$0" -e 's/^# *//'
        echo "----"
        echo
        echo "$gsu_name usage"
@@ -223,13 +320,14 @@ com_man()
                echo "${minus_signs:0:$num}"
                echo "$com"
                echo "${minus_signs:0:$num}"
-               $0 help $com
+               "$0" help "$com"
                echo
        done
+       } | $pager
        ret=$GSU_SUCCESS
 }
 
-export gsu_help_txt="
+_gsu_help_txt="
 Print online help.
 
 Usage: help [command]
@@ -237,7 +335,7 @@ Usage: help [command]
 Without arguments, print the list of available commands. Otherwise,
 print the help text for the given command."
 
-export gsu_complete_txt="
+_gsu_complete_txt="
 Command line completion.
 
 Usage: complete [<cword> <word>...]
@@ -253,7 +351,7 @@ the subcommand.
 
 com_help()
 {
-       local a b ere tab='     '
+       local ere tab=' '
 
        _gsu_get_command_regex
        ere="$result"
@@ -262,11 +360,11 @@ com_help()
                gsu_short_msg "### $gsu_name -- $gsu_banner_txt ###"
                _gsu_usage 2>&1
                {
-                       printf "com_help()\n$gsu_help_txt" | head -n 4; echo "--"
-                       printf "com_man()\n$gsu_man_txt" | head -n 4; echo "--"
-                       printf "com_prefs()\n$gsu_prefs_txt" | head -n 4; echo "--"
-                       printf "com_complete()\n$gsu_complete_txt" | head -n 4; echo "--"
-                       grep -EA 2 "$ere" $0
+                       printf "com_help()\n%s" "$_gsu_help_txt" | head -n 4; echo "--"
+                       printf "com_man()\n%s" "$_gsu_man_txt" | head -n 4; echo "--"
+                       printf "com_prefs()\n%s" "$_gsu_prefs_txt" | head -n 4; echo "--"
+                       printf "com_complete()\n%s" "$_gsu_complete_txt" | head -n 4; echo "--"
+                       grep -EA 2 "$ere" "$0"
                } | grep -v -- '--' \
                        | sed -En "/$ere/"'!d
                                # remove everything but the command name
@@ -294,29 +392,29 @@ com_help()
                return
        fi
        if test "$1" = "help"; then
-               echo "$gsu_help_txt"
+               echo "$_gsu_help_txt"
                ret=$GSU_SUCCESS
                return
        fi
        if test "$1" = "man"; then
-               echo "$gsu_man_txt"
+               echo "$_gsu_man_txt"
                ret=$GSU_SUCCESS
                return
        fi
        if test "$1" = "prefs"; then
-               echo "$gsu_prefs_txt"
+               echo "$_gsu_prefs_txt"
                ret=$GSU_SUCCESS
                return
        fi
        if test "$1" = "complete"; then
-               echo "$gsu_complete_txt"
+               echo "$_gsu_complete_txt"
                ret=$GSU_SUCCESS
                return
        fi
        ret=$GSU_SUCCESS
        _gsu_get_command_regex "$1"
        ere="$result"
-       if ! grep -Eq "$ere" $0; then
+       if ! grep -Eq "$ere" "$0"; then
                _gsu_print_available_commands
                result="$1"
                ret=-$E_GSU_BAD_COMMAND
@@ -339,7 +437,7 @@ com_help()
                        :p
                        p
                }
-       ' $0
+       ' "$0"
 }
 
 complete_help()
@@ -348,91 +446,6 @@ complete_help()
        echo "$result"
 }
 
-# Wrapper for the bash getopts builtin.
-#
-# Aborts on programming errors such as missing or invalid option string.  On
-# success $result contains shell code that can be eval'ed. For each defined
-# option x, the local variable o_x will be created when calling eval "$result".
-# o_x contains true/false for options without argument and either the empty
-# string or the given argument for options that take an argument.
-#
-# Example:
-#      gsu_getopts abc:x:y
-#      eval "$result"
-#      (($ret < 0)) && return
-#
-#      [[ "$o_a" = 'true' ]] && echo 'The -a flag was given'
-#      [[ -n "$o_c" ]] && echo "The -c option was given with arg $o_c"
-gsu_getopts()
-{
-       local i c tab=' ' cr='
-'
-
-       gsu_check_arg_count $# 1 1
-       if (($ret < 0)); then
-               gsu_err_msg
-               exit 1
-       fi
-
-       ret=-$E_GSU_GETOPTS
-       result="invalid optstring $1"
-       if [[ -z "$1" ]] || grep -q '::' <<< "$1" ; then
-               gsu_err_msg
-               exit 1
-       fi
-
-       for ((i=0; i < ${#1}; i++)); do
-               c=${1:$i:1}
-               case "$c" in
-               [a-zA-Z:]);;
-               *)
-                       ret=-$E_GSU_GETOPTS
-                       result="invalid character $c in optstring"
-                       gsu_err_msg
-                       exit 1
-               esac
-       done
-       result="local _gsu_getopts_opt"
-       for ((i=0; i < ${#1}; i++)); do
-               c1=${1:$i:1}
-               c2=${1:$(($i + 1)):1}
-               result+=" o_$c1="
-               if [[ "$c2" = ":" ]]; then
-                       let i++
-               else
-                       result+="false"
-               fi
-       done
-       result+="
-       OPTIND=1
-       while getopts $1 _gsu_getopts_opt \"\$@\"; do
-               case \"\$_gsu_getopts_opt\" in
-"
-       for ((i=0; i < ${#1}; i++)); do
-               c1=${1:$i:1}
-               c2=${1:$(($i + 1)):1}
-               result+="$tab$tab$c1) o_$c1="
-               if [[ "$c2" = ":" ]]; then
-                       result+="\"\$OPTARG\""
-                       let i++
-               else
-                       result+="true"
-               fi
-               result+=";;$cr"
-       done
-       result+="
-               *)
-                       ret=-\$E_GSU_GETOPTS
-                       result=\"invalid option given\"
-                       return
-                       ;;
-               esac
-       done
-       shift \$((\$OPTIND - 1))
-"
-       ret=$GSU_SUCCESS
-}
-
 com_complete()
 {
        local cmd n cword
@@ -463,8 +476,8 @@ EOF
        words=("$@")
        cmd="${words[1]}"
        ret=$GSU_SUCCESS # It's not an error if no completer was defined
-       [[ "$(type -t complete_$cmd)" != "function" ]] && return
-       complete_$cmd "$cword" "${words[@]}"
+       [[ "$(type -t "complete_$cmd")" != "function" ]] && return
+       "complete_$cmd" "$cword" "${words[@]}"
        # ignore errors, they would only clutter the completion output
        ret=$GSU_SUCCESS
 }
@@ -497,7 +510,7 @@ gsu_cword_is_option_parameter()
                opt="${opts:$i:1}"
                [[ "${opts:$(($i + 1)):1}" != ":" ]] && continue
                let i++
-               [[ "$prev" != "-$opt" ]] && continue
+               [[ ! "$prev" =~ ^-.*$opt$ ]] && continue
                result="$opt"
                return
        done
@@ -571,8 +584,8 @@ gsu()
        fi
        arg="$1"
        shift
-       if [[ "$(type -t com_$arg)" == 'function' ]]; then
-               com_$arg "$@"
+       if [[ "$(type -t "com_$arg")" == 'function' ]]; then
+               "com_$arg" "$@"
                if (("$ret" < 0)); then
                        gsu_err_msg
                        exit 1