]> git.tuebingen.mpg.de Git - gsu.git/blobdiff - misc/gsu/subcommand
Split gsu.
[gsu.git] / misc / gsu / subcommand
diff --git a/misc/gsu/subcommand b/misc/gsu/subcommand
new file mode 100644 (file)
index 0000000..332e5a0
--- /dev/null
@@ -0,0 +1,380 @@
+#!/bin/bash
+# (C) 2006-2011 Andre Noll
+
+if [[ $(type -t gsu_is_a_number) != "function" ]]; then
+       GSU_DIR=${GSU_DIR:=$HOME/.gsu}
+       . $GSU_DIR/common || exit 1
+fi
+
+_gsu_usage()
+{
+       gsu_short_msg "# Usage: $_gsu_self command [options]"
+}
+export -f _gsu_usage
+
+# Each line matching this is recognized as a subcommand. The name
+# of the subcommand is the first subexpression.
+export gsu_command_regex='^com_\([-a-zA-Z_0-9]\+\)()'
+
+_gsu_available_commands()
+{
+       result="$({
+               printf "help\nman\nprefs\n"
+               sed -ne "s/$gsu_command_regex/\1/g;T;p" $0
+               } | sort | tr '\n' ' ')"
+}
+export -f _gsu_available_commands
+
+_gsu_print_available_commands()
+{(
+       local i count
+       gsu_short_msg "Available commands:"
+       for i in $gsu_cmds; do
+               printf "$i"
+               count=$(($count + 1))
+               if test $(($count % 4)) -eq 0; then
+                       echo
+               else
+                       printf "\t"
+                       if test ${#i} -lt 8; then
+                               printf "\t"
+                       fi
+               fi
+       done
+       echo
+) 2>&1
+}
+export -f _gsu_print_available_commands
+
+export gsu_prefs_txt="
+Print the current preferences.
+
+Usage: prefs [-e]
+
+If -e is given, the config file is opened with the default editor.  Without
+options, the command prints out a list of all cmt config variables, together
+with their current value and the default value."
+_com_prefs()
+{
+       local i conf="${gsu_config_file:=$HOME/.$gsu_name.rc}"
+
+       if [[ "$1" = "-e" ]]; then
+               ret=-$E_GSU_MKDIR
+               result="${conf%/*}"
+               mkdir -p "$result"
+               [[ $? -ne 0 ]] && return
+               ret=-$E_GSU_EDITOR
+               result="${EDITOR:-vi}"
+               "$result" "$conf"
+               [[ $? -ne 0 ]] && return
+               ret=$GSU_SUCCESS
+               return
+       fi
+
+       for ((i=0; i < ${#gsu_options[@]}; i++)); do
+               local name= option_type= default_value= required=
+               local description= help_text=
+               eval "${gsu_options[$i]}"
+               eval val='"$'${gsu_config_var_prefix}_$name'"'
+               case "$required" in
+               true|yes)
+                       printf "# required"
+                       ;;
+               *)
+                       printf "# optional"
+                       ;;
+               esac
+               printf " $option_type: $description"
+               if [[ "$required" != "yes" && "$required" != "true" ]]; then
+                       printf " [$default_value]"
+               fi
+               echo
+               [[ -n "$help_text" ]] && sed -e '/^[    ]*$/d; s/^[     ]*/#    /g' <<< "$help_text"
+               printf "$name=$val"
+               [[ "$val" == "$default_value" ]] && printf " # default"
+               echo
+       done
+}
+export -f _com_prefs
+
+export gsu_man_txt="
+Print the manual.
+
+Usage: man"
+
+_com_man()
+{
+       local equal_signs="=================================================="
+       local minus_signs="--------------------------------------------------"
+        local com num
+
+       echo "$_gsu_self (_${gsu_banner_txt}_) manual"
+       echo "${equal_signs:0:${#_gsu_self} + ${#gsu_banner_txt} + 16}"
+       echo
+
+        sed -e '1,/^#\{70,\}/d' -e '/^#\{70,\}/,$d' $0 -e 's/^# *//'
+       echo "----"
+        echo
+       echo "$_gsu_self usage"
+       echo "${minus_signs:0:${#_gsu_self} + 6}"
+       printf "\t"
+       _gsu_usage 2>&1
+       echo "Each command has its own set of options as described below."
+       echo
+       echo "----"
+       echo
+       echo "Available commands:"
+
+       _gsu_available_commands
+        for com in $result; do
+               num=${#com}
+               if test $num -lt 4; then
+                       num=4
+               fi
+                echo "${minus_signs:0:$num}"
+                echo "$com"
+                echo "${minus_signs:0:$num}"
+                $0 help $com
+               echo
+        done
+        ret=$GSU_SUCCESS
+}
+export -f _com_man
+
+_gsu_banner_msg()
+{
+       local txt="### $_gsu_self --"
+       if test -z "$gsu_banner_txt"; then
+               txt="$txt set \$gsu_banner_txt to customize this message"
+       else
+               txt="$txt $gsu_banner_txt"
+       fi
+       gsu_short_msg "$txt ###"
+}
+export -f _gsu_banner_msg
+
+export gsu_help_txt="
+Print online help.
+
+Usage: help [command]
+
+Without arguments, print the list of available commands. Otherwise,
+print the help text for the given command."
+
+_com_help()
+{
+       local a b
+       if test -z "$1"; then
+               _gsu_banner_msg 2>&1
+               _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 "--"
+                       grep -A 2 "$gsu_command_regex" $0
+               } | grep -v -- '--' \
+                       | sed -e "/$gsu_command_regex/bs" \
+                               -e 'H;$!d;x;s/\n//g;b' \
+                               -e :s \
+                               -e 'x;s/\n//g;${p;x;}' \
+                       | sed -e "s/${gsu_command_regex}#*/\1\t/" \
+                       | sort \
+                       | while read a b; do
+                               printf "$a\t"
+                               if test ${#a} -lt 8; then
+                                       printf "\t"
+                               fi
+                               echo "$b"
+                        done
+               echo
+               echo "# Try $_gsu_self help <command> for info on <command>."
+               ret=$GSU_SUCCESS
+               return
+       fi
+       if test "$1" = "help"; then
+               echo "$gsu_help_txt"
+               ret=$GSU_SUCCESS
+               return
+       fi
+       if test "$1" = "man"; then
+               echo "$gsu_man_txt"
+               ret=$GSU_SUCCESS
+               return
+       fi
+       if test "$1" = "prefs"; then
+               echo "$gsu_prefs_txt"
+               ret=$GSU_SUCCESS
+               return
+       fi
+       ret=$GSU_SUCCESS
+       if grep -q "^com_$1()" $0; then
+               sed -e "1,/^com_$1()$/d" -e '/^{/,$d' -e 's/^## *//' $0
+               return
+       fi
+       _gsu_print_available_commands
+       result="$1"
+       ret=-$E_GSU_BAD_COMMAND
+}
+export -f _com_help
+
+# Wrapper for bash's getopts.
+#
+# 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 an argument or the emtpy string/the
+# given argument, depending on whether this option was contained in the "$@"
+# array.
+#
+# Example:
+#      gsu_getopts abc:x:y
+#      eval "$result"
+#      [[ $ret -lt 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 -lt 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 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 opt \"\$@\"; do
+               case \"\$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
+}
+export -f gsu_getopts
+
+gsu()
+{
+       local i
+       _gsu_setup
+       _gsu_available_commands
+       gsu_cmds="$result"
+       if test $# -eq 0; then
+               _gsu_usage
+               _gsu_print_available_commands
+               exit 1
+       fi
+       arg="$1"
+       shift
+       # check internal commands
+       if [[ "$arg" = "help" || "$arg" = "man" || "$arg" = "prefs" ]]; then
+               _com_$arg "$@"
+               if [[ "$ret" -lt 0 ]]; then
+                       gsu_err_msg
+                       exit 1
+               fi
+               exit 0
+       fi
+
+       # external commands
+       for i in $gsu_cmds; do
+               if test "$arg" = "$i"; then
+                       com_$arg "$@"
+                       if [[ "$ret" -lt 0 ]]; then
+                               gsu_err_msg
+                               exit 1
+                       fi
+                       exit 0
+               fi
+       done
+
+       ret=-$E_GSU_BAD_COMMAND
+       result="$arg"
+       gsu_err_msg
+       _gsu_print_available_commands
+       exit 1
+}
+export -f gsu
+
+# Check number of arguments.
+#
+# Usage: gsu_check_arg_count <num_given> <num1> [<num2>]
+#
+# Check that <num_given> is between <num1> and <num2> inclusively.
+# If only <num1> ist given, num2 is assumed to be infinity.
+#
+# Examples:
+#      0 0 no argument allowed
+#      1 1 exactly one argument required
+#      0 2 at most two arguments admissible
+#      2   at least two arguments reqired
+#
+gsu_check_arg_count()
+{
+       ret=-$E_GSU_BAD_ARG_COUNT
+       if [[ $# -eq 2 ]]; then # only num1 is given
+               result="at least $2 args required, $1 given"
+               [[ $1 -lt $2 ]] && return
+               ret=$GSU_SUCCESS
+               return
+       fi
+       # num1 and num2 given
+       result="need at least $2 args, $1 given"
+       [[ $1 -lt $2 ]] && return
+       result="need at most $3 args, $1 given"
+       [[ $1 -gt $3 ]] && return
+       ret=$GSU_SUCCESS
+}
+export -f gsu_check_arg_count
+