introduce gsu: The global subcommand utility, and make bbf_adm use it.
[gsu.git] / funcs / gsu
1 #!/bin/bash
2 # gsu -- the global subcommand utility
3 # (C) 2006-2007 Andre Noll
4
5 gsu_init_errors()
6 {
7         gsu_errors="
8 GSU_SUCCESS                     success
9 E_GSU_BAD_COMMAND               invalid command
10 E_GSU_NOT_A_NUMBER              not a number
11 $gsu_errors
12 "
13         local a b i
14         local i=0
15         while read a b; do
16                 if test -z "$a"; then
17                         continue
18                 fi
19                 #echo "a:$a,  b: $b"
20                 gsu_error_txt[i]="$b"
21                 eval $a=$i
22                 i=$((i + 1))
23         done << EOF
24         $gsu_errors
25 EOF
26 }
27 export -f gsu_init_errors
28
29 # check if $1 is a number
30 gsu_is_a_number()
31 {
32         result="$1"
33         if test "$1" -eq "$1" &> /dev/null; then
34                 ret=$GSU_SUCCESS
35         else
36                 ret=-$E_GSU_NOT_A_NUMBER
37         fi
38 }
39 export -f gsu_is_a_number
40
41 gsu_short_msg()
42 {
43         echo "$1" 1>&2
44 }
45 export -f gsu_short_msg
46
47 gsu_msg()
48 {
49         gsu_short_msg "$gsu_self: $1"
50 }
51 export -f gsu_msg
52
53 gsu_date_msg()
54 {
55         gsu_short_msg "$gsu_self $(date): $1"
56 }
57 export -f gsu_date_msg
58
59 gsu_banner_msg()
60 {
61         local txt="*** $gsu_self --"
62         if test -z "$gsu_banner_txt"; then
63                 txt="$txt set \$gsu_banner_txt to customize this message"
64         else
65                 txt="$txt $gsu_banner_txt"
66         fi
67         gsu_short_msg "$txt ***"
68 }
69 export -f gsu_banner_msg
70
71 gsu_err_msg()
72 {
73         local txt="$result" err
74
75         gsu_is_a_number "$ret"
76         if test $ret -lt 0; then
77                 gsu_msg "unknown error ($ret:$txt)"
78                 exit 1
79         fi
80         if test $result -ge 0; then
81                 gsu_msg "unknown error ($result:$txt)"
82                 exit 1
83         fi
84         err=$((0 - $result))
85         if test -n "$txt"; then
86                 txt="$txt: ${gsu_error_txt[$err]}"
87         else
88                 txt="${gsu_error_txt[$err]}"
89         fi
90         echo "$gsu_self: $txt" 1>&2
91 }
92 export -f gsu_err_msg
93
94 gsu_usage()
95 {
96         gsu_short_msg "Usage: $gsu_self command [options]"
97 }
98 export -f gsu_usage
99
100 export gsu_help_txt="
101 Print online help.
102
103 Usage: help [command]
104
105 Without arguments, print the list of available commands. Otherwise,
106 print the help text for the given command."
107 com_help()
108 {
109         local a b
110         if test -z "$1"; then
111                 gsu_banner_msg
112                 gsu_usage
113                 # sed is magic, baby
114                 grep -A 2 "^com_\([a-zA-Z_0-9]\+\)()" $0 \
115                         | grep -v -- '--' \
116                         | sed -e '/^com_\([a-zA-Z_0-9]\+\)()/bs' \
117                                 -e 'H;$!d;x;s/\n//g;b' \
118                                 -e :s \
119                                 -e 'x;s/\n//g;${p;x;}' \
120                         | sed -e 's/^com_\([a-zA-Z_0-9]\+\)()#*/\1\t/' \
121                         | sort \
122                         | while read a b; do
123                                 echo -en "$a\t"
124                                 if test ${#a} -lt 8; then
125                                         echo -en "\t"
126                                 fi
127                                 echo "$b"
128                         done
129                 echo
130                 gsu_msg "Try $0 help <command> for info on <command>."
131                 ret=$GSU_SUCCESS
132                 return
133         fi
134         if test "$1" = "help"; then
135                 gsu_short_msg "$gsu_help_txt"
136                 ret=$GSU_SUCCESS
137                 return
138         fi
139         ret=$GSU_SUCCESS
140         if grep -q "^com_$1()" $0; then
141                 sed -e "1,/com_$1()/d" -e '/^{/,$d' -e 's/^## *//' $0
142                 return
143         fi
144         gsu_print_available_commands
145         result="$1"
146         ret=-$E_GSU_BAD_COMMAND
147 }
148 export -f com_help
149
150 gsu_available_commands()
151 {
152         result="$( (echo help; grep "^com_[a-z_]\+()" $0) \
153                 | sed -e 's/^com_//' -e 's/()//' \
154                 | sort \
155                 | tr '\n' ' ')"
156         ret=$SUCCESS
157 }
158 export -f gsu_available_commands
159
160 gsu_print_available_commands()
161 {(
162         local i count
163         gsu_short_msg "Available commands:"
164         for i in $gsu_cmds; do
165                 printf "$i"
166                 count=$((count + 1))
167                 if test $((count % 4)) -eq 0; then
168                         echo
169                 else
170                         printf "\t"
171                         if test ${#i} -lt 8; then
172                                 printf "\t"
173                         fi
174                 fi
175         done
176         echo
177 ) 2>&1
178 }
179 export -f gsu_print_available_commands
180
181 gsu()
182 {
183         gsu_self="$(basename $0)"
184         gsu_init_errors
185         gsu_available_commands
186         gsu_cmds="$result"
187         if test $# -eq 0; then
188                 gsu_usage
189                 gsu_print_available_commands
190                 exit 1
191         fi
192         arg="$1"
193         shift
194         for i in $gsu_cmds; do
195                 if test "$arg" = "$i"; then
196                         com_$arg $*
197                         if test $ret -lt 0; then
198                                 gsu_err_msg
199                                 exit 1
200                         fi
201                         exit 0
202                 fi
203         done
204         ret=-$E_GSU_BAD_COMMAND
205         result="$arg"
206         gsu_err_msg
207         gsu_print_available_commands
208         exit 1
209 }
210 # no need to export this