]> git.tuebingen.mpg.de Git - gsu.git/blob - funcs/gsu
gsu improvements.
[gsu.git] / funcs / gsu
1 #!/bin/sh
2 # gsu -- the global subcommand utility
3 # (C) 2006-2009 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 E_GSU_SOURCE                    error in config file
12 E_GSU_CONFIG                    bad/missing config file option
13 $gsu_errors
14 "
15         local a b i=0
16         while read a b; do
17                 if test -z "$a"; then
18                         continue
19                 fi
20                 #echo "a:$a,  b: $b"
21                 gsu_error_txt[i]="$b"
22                 eval $a=$i
23                 i=$(($i + 1))
24         done << EOF
25         $gsu_errors
26 EOF
27 }
28 export -f _gsu_init_errors
29
30 # check if $1 is a number
31 gsu_is_a_number()
32 {
33         result="$1"
34         if test "$1" -eq "$1" &> /dev/null; then
35                 ret=$GSU_SUCCESS
36         else
37                 ret=-$E_GSU_NOT_A_NUMBER
38         fi
39 }
40 export -f gsu_is_a_number
41
42 gsu_short_msg()
43 {
44         echo "$1" 1>&2
45 }
46 export -f gsu_short_msg
47
48 gsu_msg()
49 {
50         gsu_short_msg "$_gsu_self: $1"
51 }
52 export -f gsu_msg
53
54 gsu_date_msg()
55 {
56         gsu_short_msg "$_gsu_self $(date): $1"
57 }
58 export -f gsu_date_msg
59
60 _gsu_banner_msg()
61 {
62         local txt="*** $_gsu_self --"
63         if test -z "$gsu_banner_txt"; then
64                 txt="$txt set \$gsu_banner_txt to customize this message"
65         else
66                 txt="$txt $gsu_banner_txt"
67         fi
68         gsu_short_msg "$txt ***"
69 }
70 export -f _gsu_banner_msg
71
72 gsu_err_msg()
73 {
74         local txt="$result" err
75
76         gsu_is_a_number "$ret"
77         if test $ret -lt 0; then
78                 gsu_msg "unknown error ($ret:$txt)"
79                 exit 1
80         fi
81         if test $result -ge 0; then
82                 gsu_msg "unknown error ($result:$txt)"
83                 exit 1
84         fi
85         err=$((0 - $result))
86         if test -n "$txt"; then
87                 txt="$txt: ${gsu_error_txt[$err]}"
88         else
89                 txt="${gsu_error_txt[$err]}"
90         fi
91         gsu_msg "$txt"
92 }
93 export -f gsu_err_msg
94
95 _gsu_usage()
96 {
97         gsu_short_msg "Usage: $_gsu_self command [options]"
98 }
99 export -f _gsu_usage
100
101 _gsu_available_commands()
102 {
103         result="$( (printf "help\nman\n"; grep "^com_[a-z_]\+()" $0) \
104                 | sed -e 's/^com_//' -e 's/()//' \
105                 | sort \
106                 | tr '\n' ' ')"
107         ret=$GSU_SUCCESS
108 }
109 export -f _gsu_available_commands
110
111 _gsu_print_available_commands()
112 {(
113         local i count
114         gsu_short_msg "Available commands:"
115         for i in $gsu_cmds; do
116                 printf "$i"
117                 count=$(($count + 1))
118                 if test $(($count % 4)) -eq 0; then
119                         echo
120                 else
121                         printf "\t"
122                         if test ${#i} -lt 8; then
123                                 printf "\t"
124                         fi
125                 fi
126         done
127         echo
128 ) 2>&1
129 }
130 export -f _gsu_print_available_commands
131
132 export gsu_man_txt="
133 Print the manual.
134
135 Usage: man"
136
137 com_man()
138 {
139         local equal_signs="=================================================="
140         local minus_signs="--------------------------------------------------"
141         local com num
142
143         echo "$_gsu_self (_${gsu_banner_txt}_) manual"
144         echo "${equal_signs:0:${#_gsu_self} + ${#gsu_banner_txt} + 16}"
145         echo
146
147         sed -e '1,/^#\{70,\}/d' -e '/^#\{70,\}/,$d' $0 -e 's/^# *//'
148         echo "----"
149         echo
150         echo "$_gsu_self usage"
151         echo "${minus_signs:0:${#_gsu_self} + 6}"
152         printf "\t"
153         _gsu_usage 2>&1
154         echo "Each command has its own set of options as described below."
155         echo
156         echo "----"
157         echo
158         echo "Available commands:"
159
160         _gsu_available_commands
161         for com in $result; do
162                 num=${#com}
163                 if test $num -lt 4; then
164                         num=4
165                 fi
166                 echo "${minus_signs:0:$num}"
167                 echo "$com"
168                 echo "${minus_signs:0:$num}"
169                 $0 help $com
170                 echo
171         done
172         ret=$GSU_SUCCESS
173 }
174 export -f com_man
175
176 export gsu_help_txt="
177 Print online help.
178
179 Usage: help [command]
180
181 Without arguments, print the list of available commands. Otherwise,
182 print the help text for the given command."
183
184 com_help()
185 {
186         local a b
187         if test -z "$1"; then
188                 _gsu_banner_msg 2>&1
189                 _gsu_usage 2>&1
190                 # sed is magic, baby
191                 (printf "com_help()\n$gsu_help_txt" | head -n 4; echo "--"
192                 printf "com_man()\n$gsu_man_txt" | head -n 4; echo "--"
193
194                 grep -A 2 "^com_\([a-zA-Z_0-9]\+\)()" $0) \
195                         | grep -v -- '--' \
196                         | sed -e '/^com_\([a-zA-Z_0-9]\+\)()/bs' \
197                                 -e 'H;$!d;x;s/\n//g;b' \
198                                 -e :s \
199                                 -e 'x;s/\n//g;${p;x;}' \
200                         | sed -e 's/^com_\([a-zA-Z_0-9]\+\)()#*/\1\t/' \
201                         | sort \
202                         | while read a b; do
203                                 printf "$a\t"
204                                 if test ${#a} -lt 8; then
205                                         printf "\t"
206                                 fi
207                                 echo "$b"
208                         done
209                 echo
210                 echo "Try $_gsu_self help <command> for info on <command>."
211                 ret=$GSU_SUCCESS
212                 return
213         fi
214         if test "$1" = "help"; then
215                 echo "$gsu_help_txt"
216                 ret=$GSU_SUCCESS
217                 return
218         fi
219         if test "$1" = "man"; then
220                 echo "$gsu_man_txt"
221                 ret=$GSU_SUCCESS
222                 return
223         fi
224         ret=$GSU_SUCCESS
225         if grep -q "^com_$1()" $0; then
226                 sed -e "1,/com_$1()/d" -e '/^{/,$d' -e 's/^## *//' $0
227                 return
228         fi
229         _gsu_print_available_commands
230         result="$1"
231         ret=-$E_GSU_BAD_COMMAND
232 }
233 export -f com_help
234
235 _gsu_init_config()
236 {
237         local name val default_val required ty comment
238
239         # set default values
240         while read name default_val required ty comment; do
241                 if test -z "$name"; then
242                         continue
243                 fi
244                 eval ${gsu_self}_$name="$default_val"
245         done << EOF
246         $gsu_config_vars
247 EOF
248         result="$HOME/.${gsu_self}rc"
249         # overwrite by custom configuration
250         if [ -r "$result" ]; then
251                 ret=-$E_GSU_SOURCE
252                 if ! . "$result"; then
253                         gsu_err_msg
254                         exit 1
255                 fi
256         fi
257         while read name default_val required ty comment; do
258                 [ -z "$name" ] && continue
259                 eval val="\$$name"
260                 # abort if any required config var remains unset
261                 ret=-$_E_GSU_CONFIG
262                 if [ "$val" = "-" -a "$required" = "required" ]; then
263                         result="$name"
264                         gsu_err_msg
265                         exit 1
266                 fi
267                 if [ $ty == "number" ]; then
268                         gsu_is_a_number "$val"
269                         if [ $ret -lt 0];  then
270                                 gsu_err_msg
271                                 exit 1
272                         fi
273                 fi
274                 eval export ${gsu_self}_$name
275         done << EOF
276         $config_vars
277 EOF
278 }
279 export -f _gsu_init_config
280
281 gsu()
282 {
283         local i
284
285         _gsu_self="$(basename $0)"
286         _gsu_init_errors
287         _gsu_init_config
288         _gsu_available_commands
289         gsu_cmds="$result"
290         if test $# -eq 0; then
291                 _gsu_usage
292                 _gsu_print_available_commands
293                 exit 1
294         fi
295         arg="$1"
296         shift
297         for i in $gsu_cmds; do
298                 if test "$arg" = "$i"; then
299                         com_$arg "$@"
300                         if test $ret -lt 0; then
301                                 gsu_err_msg
302                                 exit 1
303                         fi
304                         exit 0
305                 fi
306         done
307         ret=-$E_GSU_BAD_COMMAND
308         result="$arg"
309         gsu_err_msg
310         _gsu_print_available_commands
311         exit 1
312 }
313 export -f gsu