#!/bin/sh # gsu -- the global subcommand utility # (C) 2006-2009 Andre Noll _gsu_init_errors() { gsu_errors=" GSU_SUCCESS success E_GSU_BAD_COMMAND invalid command E_GSU_NOT_A_NUMBER not a number E_GSU_SOURCE error in config file E_GSU_CONFIG bad/missing config file option $gsu_errors " local a b i=0 while read a b; do if test -z "$a"; then continue fi #echo "a:$a, b: $b" gsu_error_txt[i]="$b" eval $a=$i i=$(($i + 1)) done << EOF $gsu_errors EOF } export -f _gsu_init_errors # check if $1 is a number gsu_is_a_number() { result="$1" if test "$1" -eq "$1" &> /dev/null; then ret=$GSU_SUCCESS else ret=-$E_GSU_NOT_A_NUMBER fi } export -f gsu_is_a_number gsu_short_msg() { echo "$1" 1>&2 } export -f gsu_short_msg gsu_msg() { gsu_short_msg "$_gsu_self: $1" } export -f gsu_msg gsu_date_msg() { gsu_short_msg "$_gsu_self $(date): $1" } export -f gsu_date_msg _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 gsu_err_msg() { local txt="$result" err gsu_is_a_number "$ret" if test $ret -lt 0; then gsu_msg "unknown error ($ret:$txt)" exit 1 fi if test $result -ge 0; then gsu_msg "unknown error ($result:$txt)" exit 1 fi err=$((0 - $result)) if test -n "$txt"; then txt="$txt: ${gsu_error_txt[$err]}" else txt="${gsu_error_txt[$err]}" fi gsu_msg "$txt" } export -f gsu_err_msg _gsu_usage() { gsu_short_msg "Usage: $_gsu_self command [options]" } export -f _gsu_usage _gsu_available_commands() { result="$( (printf "help\nman\n"; grep "^com_[a-z_]\+()" $0) \ | sed -e 's/^com_//' -e 's/()//' \ | sort \ | tr '\n' ' ')" ret=$GSU_SUCCESS } 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_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 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 # sed is magic, baby (printf "com_help()\n$gsu_help_txt" | head -n 4; echo "--" printf "com_man()\n$gsu_man_txt" | head -n 4; echo "--" grep -A 2 "^com_\([a-zA-Z_0-9]\+\)()" $0) \ | grep -v -- '--' \ | sed -e '/^com_\([a-zA-Z_0-9]\+\)()/bs' \ -e 'H;$!d;x;s/\n//g;b' \ -e :s \ -e 'x;s/\n//g;${p;x;}' \ | sed -e 's/^com_\([a-zA-Z_0-9]\+\)()#*/\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 for info on ." 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 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 _gsu_init_config() { local name val default_val required ty comment # set default values while read name default_val required ty comment; do if test -z "$name"; then continue fi eval ${gsu_self}_$name="$default_val" done << EOF $gsu_config_vars EOF result="$HOME/.${gsu_self}rc" # overwrite by custom configuration if [ -r "$result" ]; then ret=-$E_GSU_SOURCE if ! . "$result"; then gsu_err_msg exit 1 fi fi while read name default_val required ty comment; do [ -z "$name" ] && continue eval val="\$$name" # abort if any required config var remains unset ret=-$_E_GSU_CONFIG if [ "$val" = "-" -a "$required" = "required" ]; then result="$name" gsu_err_msg exit 1 fi if [ $ty == "number" ]; then gsu_is_a_number "$val" if [ $ret -lt 0]; then gsu_err_msg exit 1 fi fi eval export ${gsu_self}_$name done << EOF $config_vars EOF } export -f _gsu_init_config gsu() { local i _gsu_self="$(basename $0)" _gsu_init_errors _gsu_init_config _gsu_available_commands gsu_cmds="$result" if test $# -eq 0; then _gsu_usage _gsu_print_available_commands exit 1 fi arg="$1" shift for i in $gsu_cmds; do if test "$arg" = "$i"; then com_$arg "$@" if test $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