ghp 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1012 @@
1
+ # $Id$
2
+ # vim:et:ft=sh:sts=2:sw=2
3
+ #
4
+ # Copyright 2008 Kate Ward. All Rights Reserved.
5
+ # Released under the LGPL (GNU Lesser General Public License)
6
+ #
7
+ # shFlags -- Advanced command-line flag library for Unix shell scripts.
8
+ # http://code.google.com/p/shflags/
9
+ #
10
+ # Author: kate.ward@forestent.com (Kate Ward)
11
+ #
12
+ # This module implements something like the google-gflags library available
13
+ # from http://code.google.com/p/google-gflags/.
14
+ #
15
+ # FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take
16
+ # a name, default value, help-string, and optional 'short' name (one-letter
17
+ # name). Some flags have other arguments, which are described with the flag.
18
+ #
19
+ # DEFINE_string: takes any input, and intreprets it as a string.
20
+ #
21
+ # DEFINE_boolean: typically does not take any argument: say --myflag to set
22
+ # FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false.
23
+ # Alternately, you can say
24
+ # --myflag=true or --myflag=t or --myflag=0 or
25
+ # --myflag=false or --myflag=f or --myflag=1
26
+ # Passing an option has the same affect as passing the option once.
27
+ #
28
+ # DEFINE_float: takes an input and intreprets it as a floating point number. As
29
+ # shell does not support floats per-se, the input is merely validated as
30
+ # being a valid floating point value.
31
+ #
32
+ # DEFINE_integer: takes an input and intreprets it as an integer.
33
+ #
34
+ # SPECIAL FLAGS: There are a few flags that have special meaning:
35
+ # --help (or -?) prints a list of all the flags in a human-readable fashion
36
+ # --flagfile=foo read flags from foo. (not implemented yet)
37
+ # -- as in getopt(), terminates flag-processing
38
+ #
39
+ # EXAMPLE USAGE:
40
+ #
41
+ # -- begin hello.sh --
42
+ # #! /bin/sh
43
+ # . ./shflags
44
+ # DEFINE_string name 'world' "somebody's name" n
45
+ # FLAGS "$@" || exit $?
46
+ # eval set -- "${FLAGS_ARGV}"
47
+ # echo "Hello, ${FLAGS_name}."
48
+ # -- end hello.sh --
49
+ #
50
+ # $ ./hello.sh -n Kate
51
+ # Hello, Kate.
52
+ #
53
+ # NOTE: Not all systems include a getopt version that supports long flags. On
54
+ # these systems, only short flags are recognized.
55
+
56
+ #==============================================================================
57
+ # shFlags
58
+ #
59
+ # Shared attributes:
60
+ # flags_error: last error message
61
+ # flags_return: last return value
62
+ #
63
+ # __flags_longNames: list of long names for all flags
64
+ # __flags_shortNames: list of short names for all flags
65
+ # __flags_boolNames: list of boolean flag names
66
+ #
67
+ # __flags_opts: options parsed by getopt
68
+ #
69
+ # Per-flag attributes:
70
+ # FLAGS_<flag_name>: contains value of flag named 'flag_name'
71
+ # __flags_<flag_name>_default: the default flag value
72
+ # __flags_<flag_name>_help: the flag help string
73
+ # __flags_<flag_name>_short: the flag short name
74
+ # __flags_<flag_name>_type: the flag type
75
+ #
76
+ # Notes:
77
+ # - lists of strings are space separated, and a null value is the '~' char.
78
+
79
+ # return if FLAGS already loaded
80
+ [ -n "${FLAGS_VERSION:-}" ] && return 0
81
+ FLAGS_VERSION='1.0.3'
82
+
83
+ # return values
84
+ FLAGS_TRUE=0
85
+ FLAGS_FALSE=1
86
+ FLAGS_ERROR=2
87
+
88
+ # reserved flag names
89
+ FLAGS_RESERVED='ARGC ARGV ERROR FALSE HELP PARENT RESERVED TRUE VERSION'
90
+
91
+ _flags_debug() { echo "flags:DEBUG $@" >&2; }
92
+ _flags_warn() { echo "flags:WARN $@" >&2; }
93
+ _flags_error() { echo "flags:ERROR $@" >&2; }
94
+ _flags_fatal() { echo "flags:FATAL $@" >&2; }
95
+
96
+ # specific shell checks
97
+ if [ -n "${ZSH_VERSION:-}" ]; then
98
+ setopt |grep "^shwordsplit$" >/dev/null
99
+ if [ $? -ne ${FLAGS_TRUE} ]; then
100
+ _flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
101
+ exit ${FLAGS_ERROR}
102
+ fi
103
+ if [ -z "${FLAGS_PARENT:-}" ]; then
104
+ _flags_fatal "zsh does not pass \$0 through properly. please declare' \
105
+ \"FLAGS_PARENT=\$0\" before calling shFlags"
106
+ exit ${FLAGS_ERROR}
107
+ fi
108
+ fi
109
+
110
+ #
111
+ # constants
112
+ #
113
+
114
+ # getopt version
115
+ __FLAGS_GETOPT_VERS_STD=0
116
+ __FLAGS_GETOPT_VERS_ENH=1
117
+ __FLAGS_GETOPT_VERS_BSD=2
118
+
119
+ getopt >/dev/null 2>&1
120
+ case $? in
121
+ 0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt
122
+ 2)
123
+ # TODO(kward): look into '-T' option to test the internal getopt() version
124
+ if [ "`getopt --version`" = '-- ' ]; then
125
+ __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD}
126
+ else
127
+ __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
128
+ fi
129
+ ;;
130
+ *)
131
+ _flags_fatal 'unable to determine getopt version'
132
+ exit ${FLAGS_ERROR}
133
+ ;;
134
+ esac
135
+
136
+ # getopt optstring lengths
137
+ __FLAGS_OPTSTR_SHORT=0
138
+ __FLAGS_OPTSTR_LONG=1
139
+
140
+ __FLAGS_NULL='~'
141
+
142
+ # flag info strings
143
+ __FLAGS_INFO_DEFAULT='default'
144
+ __FLAGS_INFO_HELP='help'
145
+ __FLAGS_INFO_SHORT='short'
146
+ __FLAGS_INFO_TYPE='type'
147
+
148
+ # flag lengths
149
+ __FLAGS_LEN_SHORT=0
150
+ __FLAGS_LEN_LONG=1
151
+
152
+ # flag types
153
+ __FLAGS_TYPE_NONE=0
154
+ __FLAGS_TYPE_BOOLEAN=1
155
+ __FLAGS_TYPE_FLOAT=2
156
+ __FLAGS_TYPE_INTEGER=3
157
+ __FLAGS_TYPE_STRING=4
158
+
159
+ # set the constants readonly
160
+ __flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'`
161
+ for __flags_const in ${__flags_constants}; do
162
+ # skip certain flags
163
+ case ${__flags_const} in
164
+ FLAGS_HELP) continue ;;
165
+ FLAGS_PARENT) continue ;;
166
+ esac
167
+ # set flag readonly
168
+ if [ -z "${ZSH_VERSION:-}" ]; then
169
+ readonly ${__flags_const}
170
+ else # handle zsh
171
+ case ${ZSH_VERSION} in
172
+ [123].*) readonly ${__flags_const} ;;
173
+ *) readonly -g ${__flags_const} ;; # declare readonly constants globally
174
+ esac
175
+ fi
176
+ done
177
+ unset __flags_const __flags_constants
178
+
179
+ #
180
+ # internal variables
181
+ #
182
+
183
+ __flags_boolNames=' ' # space separated list of boolean flag names
184
+ __flags_longNames=' ' # space separated list of long flag names
185
+ __flags_shortNames=' ' # space separated list of short flag names
186
+
187
+ __flags_columns='' # screen width in columns
188
+ __flags_opts='' # temporary storage for parsed getopt flags
189
+
190
+ #------------------------------------------------------------------------------
191
+ # private functions
192
+ #
193
+
194
+ # Define a flag.
195
+ #
196
+ # Calling this function will define the following info variables for the
197
+ # specified flag:
198
+ # FLAGS_flagname - the name for this flag (based upon the long flag name)
199
+ # __flags_<flag_name>_default - the default value
200
+ # __flags_flagname_help - the help string
201
+ # __flags_flagname_short - the single letter alias
202
+ # __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*)
203
+ #
204
+ # Args:
205
+ # _flags__type: integer: internal type of flag (__FLAGS_TYPE_*)
206
+ # _flags__name: string: long flag name
207
+ # _flags__default: default flag value
208
+ # _flags__help: string: help string
209
+ # _flags__short: string: (optional) short flag name
210
+ # Returns:
211
+ # integer: success of operation, or error
212
+ _flags_define()
213
+ {
214
+ if [ $# -lt 4 ]; then
215
+ flags_error='DEFINE error: too few arguments'
216
+ flags_return=${FLAGS_ERROR}
217
+ _flags_error "${flags_error}"
218
+ return ${flags_return}
219
+ fi
220
+
221
+ _flags_type_=$1
222
+ _flags_name_=$2
223
+ _flags_default_=$3
224
+ _flags_help_=$4
225
+ _flags_short_=${5:-${__FLAGS_NULL}}
226
+
227
+ _flags_return_=${FLAGS_TRUE}
228
+
229
+ # TODO(kward): check for validity of the flag name (e.g. dashes)
230
+
231
+ # check whether the flag name is reserved
232
+ echo " ${FLAGS_RESERVED} " |grep " ${_flags_name_} " >/dev/null
233
+ if [ $? -eq 0 ]; then
234
+ flags_error="flag name (${_flags_name_}) is reserved"
235
+ _flags_return_=${FLAGS_ERROR}
236
+ fi
237
+
238
+ # require short option for getopt that don't support long options
239
+ if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
240
+ -a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \
241
+ -a "${_flags_short_}" = "${__FLAGS_NULL}" ]
242
+ then
243
+ flags_error="short flag required for (${_flags_name_}) on this platform"
244
+ _flags_return_=${FLAGS_ERROR}
245
+ fi
246
+
247
+ # check for existing long name definition
248
+ if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
249
+ if _flags_itemInList "${_flags_name_}" \
250
+ ${__flags_longNames} ${__flags_boolNames}
251
+ then
252
+ flags_error="flag name ([no]${_flags_name_}) already defined"
253
+ _flags_warn "${flags_error}"
254
+ _flags_return_=${FLAGS_FALSE}
255
+ fi
256
+ fi
257
+
258
+ # check for existing short name definition
259
+ if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
260
+ -a "${_flags_short_}" != "${__FLAGS_NULL}" ]
261
+ then
262
+ if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then
263
+ flags_error="flag short name (${_flags_short_}) already defined"
264
+ _flags_warn "${flags_error}"
265
+ _flags_return_=${FLAGS_FALSE}
266
+ fi
267
+ fi
268
+
269
+ # handle default value. note, on several occasions the 'if' portion of an
270
+ # if/then/else contains just a ':' which does nothing. a binary reversal via
271
+ # '!' is not done because it does not work on all shells.
272
+ if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
273
+ case ${_flags_type_} in
274
+ ${__FLAGS_TYPE_BOOLEAN})
275
+ if _flags_validateBoolean "${_flags_default_}"; then
276
+ case ${_flags_default_} in
277
+ true|t|0) _flags_default_=${FLAGS_TRUE} ;;
278
+ false|f|1) _flags_default_=${FLAGS_FALSE} ;;
279
+ esac
280
+ else
281
+ flags_error="invalid default flag value '${_flags_default_}'"
282
+ _flags_return_=${FLAGS_ERROR}
283
+ fi
284
+ ;;
285
+
286
+ ${__FLAGS_TYPE_FLOAT})
287
+ if _flags_validateFloat "${_flags_default_}"; then
288
+ :
289
+ else
290
+ flags_error="invalid default flag value '${_flags_default_}'"
291
+ _flags_return_=${FLAGS_ERROR}
292
+ fi
293
+ ;;
294
+
295
+ ${__FLAGS_TYPE_INTEGER})
296
+ if _flags_validateInteger "${_flags_default_}"; then
297
+ :
298
+ else
299
+ flags_error="invalid default flag value '${_flags_default_}'"
300
+ _flags_return_=${FLAGS_ERROR}
301
+ fi
302
+ ;;
303
+
304
+ ${__FLAGS_TYPE_STRING}) ;; # everything in shell is a valid string
305
+
306
+ *)
307
+ flags_error="unrecognized flag type '${_flags_type_}'"
308
+ _flags_return_=${FLAGS_ERROR}
309
+ ;;
310
+ esac
311
+ fi
312
+
313
+ if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
314
+ # store flag information
315
+ eval "FLAGS_${_flags_name_}='${_flags_default_}'"
316
+ eval "__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}=${_flags_type_}"
317
+ eval "__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}=\
318
+ \"${_flags_default_}\""
319
+ eval "__flags_${_flags_name_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\""
320
+ eval "__flags_${_flags_name_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'"
321
+
322
+ # append flag name(s) to list of names
323
+ __flags_longNames="${__flags_longNames}${_flags_name_} "
324
+ __flags_shortNames="${__flags_shortNames}${_flags_short_} "
325
+ [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \
326
+ __flags_boolNames="${__flags_boolNames}no${_flags_name_} "
327
+ fi
328
+
329
+ flags_return=${_flags_return_}
330
+ unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ _flags_short_ \
331
+ _flags_type_
332
+ [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
333
+ return ${flags_return}
334
+ }
335
+
336
+ # Return valid getopt options using currently defined list of long options.
337
+ #
338
+ # This function builds a proper getopt option string for short (and long)
339
+ # options, using the current list of long options for reference.
340
+ #
341
+ # Args:
342
+ # _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*)
343
+ # Output:
344
+ # string: generated option string for getopt
345
+ # Returns:
346
+ # boolean: success of operation (always returns True)
347
+ _flags_genOptStr()
348
+ {
349
+ _flags_optStrType_=$1
350
+
351
+ _flags_opts_=''
352
+
353
+ for _flags_flag_ in ${__flags_longNames}; do
354
+ _flags_type_=`_flags_getFlagInfo ${_flags_flag_} ${__FLAGS_INFO_TYPE}`
355
+ case ${_flags_optStrType_} in
356
+ ${__FLAGS_OPTSTR_SHORT})
357
+ _flags_shortName_=`_flags_getFlagInfo \
358
+ ${_flags_flag_} ${__FLAGS_INFO_SHORT}`
359
+ if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then
360
+ _flags_opts_="${_flags_opts_}${_flags_shortName_}"
361
+ # getopt needs a trailing ':' to indicate a required argument
362
+ [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
363
+ _flags_opts_="${_flags_opts_}:"
364
+ fi
365
+ ;;
366
+
367
+ ${__FLAGS_OPTSTR_LONG})
368
+ _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}"
369
+ # getopt needs a trailing ':' to indicate a required argument
370
+ [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
371
+ _flags_opts_="${_flags_opts_}:"
372
+ ;;
373
+ esac
374
+ done
375
+
376
+ echo "${_flags_opts_}"
377
+ unset _flags_flag_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \
378
+ _flags_type_
379
+ return ${FLAGS_TRUE}
380
+ }
381
+
382
+ # Returns flag details based on a flag name and flag info.
383
+ #
384
+ # Args:
385
+ # string: long flag name
386
+ # string: flag info (see the _flags_define function for valid info types)
387
+ # Output:
388
+ # string: value of dereferenced flag variable
389
+ # Returns:
390
+ # integer: one of FLAGS_{TRUE|FALSE|ERROR}
391
+ _flags_getFlagInfo()
392
+ {
393
+ _flags_name_=$1
394
+ _flags_info_=$2
395
+
396
+ _flags_nameVar_="__flags_${_flags_name_}_${_flags_info_}"
397
+ _flags_strToEval_="_flags_value_=\"\${${_flags_nameVar_}:-}\""
398
+ eval "${_flags_strToEval_}"
399
+ if [ -n "${_flags_value_}" ]; then
400
+ flags_return=${FLAGS_TRUE}
401
+ else
402
+ # see if the _flags_name_ variable is a string as strings can be empty...
403
+ # note: the DRY principle would say to have this function call itself for
404
+ # the next three lines, but doing so results in an infinite loop as an
405
+ # invalid _flags_name_ will also not have the associated _type variable.
406
+ # Because it doesn't (it will evaluate to an empty string) the logic will
407
+ # try to find the _type variable of the _type variable, and so on. Not so
408
+ # good ;-)
409
+ _flags_typeVar_="__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}"
410
+ _flags_strToEval_="_flags_type_=\"\${${_flags_typeVar_}:-}\""
411
+ eval "${_flags_strToEval_}"
412
+ if [ "${_flags_type_}" = "${__FLAGS_TYPE_STRING}" ]; then
413
+ flags_return=${FLAGS_TRUE}
414
+ else
415
+ flags_return=${FLAGS_ERROR}
416
+ flags_error="invalid flag name (${_flags_nameVar_})"
417
+ fi
418
+ fi
419
+
420
+ echo "${_flags_value_}"
421
+ unset _flags_info_ _flags_name_ _flags_strToEval_ _flags_type_ _flags_value_ \
422
+ _flags_nameVar_ _flags_typeVar_
423
+ [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
424
+ return ${flags_return}
425
+ }
426
+
427
+ # check for presense of item in a list. passed a string (e.g. 'abc'), this
428
+ # function will determine if the string is present in the list of strings (e.g.
429
+ # ' foo bar abc ').
430
+ #
431
+ # Args:
432
+ # _flags__str: string: string to search for in a list of strings
433
+ # unnamed: list: list of strings
434
+ # Returns:
435
+ # boolean: true if item is in the list
436
+ _flags_itemInList()
437
+ {
438
+ _flags_str_=$1
439
+ shift
440
+
441
+ echo " ${*:-} " |grep " ${_flags_str_} " >/dev/null
442
+ if [ $? -eq 0 ]; then
443
+ flags_return=${FLAGS_TRUE}
444
+ else
445
+ flags_return=${FLAGS_FALSE}
446
+ fi
447
+
448
+ unset _flags_str_
449
+ return ${flags_return}
450
+ }
451
+
452
+ # Returns the width of the current screen.
453
+ #
454
+ # Output:
455
+ # integer: width in columns of the current screen.
456
+ _flags_columns()
457
+ {
458
+ if [ -z "${__flags_columns}" ]; then
459
+ # determine the value and store it
460
+ if eval stty size >/dev/null 2>&1; then
461
+ # stty size worked :-)
462
+ set -- `stty size`
463
+ __flags_columns=$2
464
+ elif eval tput cols >/dev/null 2>&1; then
465
+ set -- `tput cols`
466
+ __flags_columns=$1
467
+ else
468
+ __flags_columns=80 # default terminal width
469
+ fi
470
+ fi
471
+ echo ${__flags_columns}
472
+ }
473
+
474
+ # Validate a boolean.
475
+ #
476
+ # Args:
477
+ # _flags__bool: boolean: value to validate
478
+ # Returns:
479
+ # bool: true if the value is a valid boolean
480
+ _flags_validateBoolean()
481
+ {
482
+ _flags_bool_=$1
483
+
484
+ flags_return=${FLAGS_TRUE}
485
+ case "${_flags_bool_}" in
486
+ true|t|0) ;;
487
+ false|f|1) ;;
488
+ *) flags_return=${FLAGS_FALSE} ;;
489
+ esac
490
+
491
+ unset _flags_bool_
492
+ return ${flags_return}
493
+ }
494
+
495
+ # Validate a float.
496
+ #
497
+ # Args:
498
+ # _flags__float: float: value to validate
499
+ # Returns:
500
+ # bool: true if the value is a valid float
501
+ _flags_validateFloat()
502
+ {
503
+ _flags_float_=$1
504
+
505
+ if _flags_validateInteger ${_flags_float_}; then
506
+ flags_return=${FLAGS_TRUE}
507
+ else
508
+ flags_return=${FLAGS_TRUE}
509
+ case ${_flags_float_} in
510
+ -*) # negative floats
511
+ _flags_test_=`expr "${_flags_float_}" : '\(-[0-9][0-9]*\.[0-9][0-9]*\)'`
512
+ ;;
513
+ *) # positive floats
514
+ _flags_test_=`expr "${_flags_float_}" : '\([0-9][0-9]*\.[0-9][0-9]*\)'`
515
+ ;;
516
+ esac
517
+ [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE}
518
+ fi
519
+
520
+ unset _flags_float_ _flags_test_
521
+ return ${flags_return}
522
+ }
523
+
524
+ # Validate an integer.
525
+ #
526
+ # Args:
527
+ # _flags__integer: interger: value to validate
528
+ # Returns:
529
+ # bool: true if the value is a valid integer
530
+ _flags_validateInteger()
531
+ {
532
+ _flags_int_=$1
533
+
534
+ flags_return=${FLAGS_TRUE}
535
+ case ${_flags_int_} in
536
+ -*) # negative ints
537
+ _flags_test_=`expr "${_flags_int_}" : '\(-[0-9][0-9]*\)'`
538
+ ;;
539
+ *) # positive ints
540
+ _flags_test_=`expr "${_flags_int_}" : '\([0-9][0-9]*\)'`
541
+ ;;
542
+ esac
543
+ [ "${_flags_test_}" != "${_flags_int_}" ] && flags_return=${FLAGS_FALSE}
544
+
545
+ unset _flags_int_ _flags_test_
546
+ return ${flags_return}
547
+ }
548
+
549
+ # Parse command-line options using the standard getopt.
550
+ #
551
+ # Note: the flag options are passed around in the global __flags_opts so that
552
+ # the formatting is not lost due to shell parsing and such.
553
+ #
554
+ # Args:
555
+ # @: varies: command-line options to parse
556
+ # Returns:
557
+ # integer: a FLAGS success condition
558
+ _flags_getoptStandard()
559
+ {
560
+ flags_return=${FLAGS_TRUE}
561
+ _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
562
+
563
+ # check for spaces in passed options
564
+ for _flags_opt_ in "$@"; do
565
+ # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
566
+ _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'`
567
+ if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then
568
+ flags_error='the available getopt does not support spaces in options'
569
+ flags_return=${FLAGS_ERROR}
570
+ break
571
+ fi
572
+ done
573
+
574
+ if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
575
+ __flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1`
576
+ _flags_rtrn_=$?
577
+ if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
578
+ _flags_warn "${__flags_opts}"
579
+ flags_error='unable to parse provided options with getopt.'
580
+ flags_return=${FLAGS_ERROR}
581
+ fi
582
+ fi
583
+
584
+ unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_
585
+ return ${flags_return}
586
+ }
587
+
588
+ # Parse command-line options using the enhanced getopt.
589
+ #
590
+ # Note: the flag options are passed around in the global __flags_opts so that
591
+ # the formatting is not lost due to shell parsing and such.
592
+ #
593
+ # Args:
594
+ # @: varies: command-line options to parse
595
+ # Returns:
596
+ # integer: a FLAGS success condition
597
+ _flags_getoptEnhanced()
598
+ {
599
+ flags_return=${FLAGS_TRUE}
600
+ _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
601
+ _flags_boolOpts_=`echo "${__flags_boolNames}" \
602
+ |sed 's/^ *//;s/ *$//;s/ /,/g'`
603
+ _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}`
604
+
605
+ __flags_opts=`getopt \
606
+ -o ${_flags_shortOpts_} \
607
+ -l "${_flags_longOpts_},${_flags_boolOpts_}" \
608
+ -- "$@" 2>&1`
609
+ _flags_rtrn_=$?
610
+ if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
611
+ _flags_warn "${__flags_opts}"
612
+ flags_error='unable to parse provided options with getopt.'
613
+ flags_return=${FLAGS_ERROR}
614
+ fi
615
+
616
+ unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_
617
+ return ${flags_return}
618
+ }
619
+
620
+ # Dynamically parse a getopt result and set appropriate variables.
621
+ #
622
+ # This function does the actual conversion of getopt output and runs it through
623
+ # the standard case structure for parsing. The case structure is actually quite
624
+ # dynamic to support any number of flags.
625
+ #
626
+ # Args:
627
+ # argc: int: original command-line argument count
628
+ # @: varies: output from getopt parsing
629
+ # Returns:
630
+ # integer: a FLAGS success condition
631
+ _flags_parseGetopt()
632
+ {
633
+ _flags_argc_=$1
634
+ shift
635
+
636
+ flags_return=${FLAGS_TRUE}
637
+
638
+ if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
639
+ set -- $@
640
+ else
641
+ # note the quotes around the `$@' -- they are essential!
642
+ eval set -- "$@"
643
+ fi
644
+
645
+ # provide user with number of arguments to shift by later
646
+ # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not
647
+ # properly give user access to non-flag arguments mixed in between flag
648
+ # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only
649
+ # for backwards compatibility reasons.
650
+ FLAGS_ARGC=`expr $# - 1 - ${_flags_argc_}`
651
+
652
+ # handle options. note options with values must do an additional shift
653
+ while true; do
654
+ _flags_opt_=$1
655
+ _flags_arg_=${2:-}
656
+ _flags_type_=${__FLAGS_TYPE_NONE}
657
+ _flags_name_=''
658
+
659
+ # determine long flag name
660
+ case "${_flags_opt_}" in
661
+ --) shift; break ;; # discontinue option parsing
662
+
663
+ --*) # long option
664
+ _flags_opt_=`expr "${_flags_opt_}" : '--\(.*\)'`
665
+ _flags_len_=${__FLAGS_LEN_LONG}
666
+ if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then
667
+ _flags_name_=${_flags_opt_}
668
+ else
669
+ # check for negated long boolean version
670
+ if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then
671
+ _flags_name_=`expr "${_flags_opt_}" : 'no\(.*\)'`
672
+ _flags_type_=${__FLAGS_TYPE_BOOLEAN}
673
+ _flags_arg_=${__FLAGS_NULL}
674
+ fi
675
+ fi
676
+ ;;
677
+
678
+ -*) # short option
679
+ _flags_opt_=`expr "${_flags_opt_}" : '-\(.*\)'`
680
+ _flags_len_=${__FLAGS_LEN_SHORT}
681
+ if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then
682
+ # yes. match short name to long name. note purposeful off-by-one
683
+ # (too high) with awk calculations.
684
+ _flags_pos_=`echo "${__flags_shortNames}" \
685
+ |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
686
+ e=${_flags_opt_}`
687
+ _flags_name_=`echo "${__flags_longNames}" \
688
+ |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
689
+ fi
690
+ ;;
691
+ esac
692
+
693
+ # die if the flag was unrecognized
694
+ if [ -z "${_flags_name_}" ]; then
695
+ flags_error="unrecognized option (${_flags_opt_})"
696
+ flags_return=${FLAGS_ERROR}
697
+ break
698
+ fi
699
+
700
+ # set new flag value
701
+ [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \
702
+ _flags_type_=`_flags_getFlagInfo \
703
+ "${_flags_name_}" ${__FLAGS_INFO_TYPE}`
704
+ case ${_flags_type_} in
705
+ ${__FLAGS_TYPE_BOOLEAN})
706
+ if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
707
+ if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
708
+ eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}"
709
+ else
710
+ eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}"
711
+ fi
712
+ else
713
+ _flags_strToEval_="_flags_val_=\
714
+ \${__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}}"
715
+ eval "${_flags_strToEval_}"
716
+ if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then
717
+ eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}"
718
+ else
719
+ eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}"
720
+ fi
721
+ fi
722
+ ;;
723
+
724
+ ${__FLAGS_TYPE_FLOAT})
725
+ if _flags_validateFloat "${_flags_arg_}"; then
726
+ eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
727
+ else
728
+ flags_error="invalid float value (${_flags_arg_})"
729
+ flags_return=${FLAGS_ERROR}
730
+ break
731
+ fi
732
+ ;;
733
+
734
+ ${__FLAGS_TYPE_INTEGER})
735
+ if _flags_validateInteger "${_flags_arg_}"; then
736
+ eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
737
+ else
738
+ flags_error="invalid integer value (${_flags_arg_})"
739
+ flags_return=${FLAGS_ERROR}
740
+ break
741
+ fi
742
+ ;;
743
+
744
+ ${__FLAGS_TYPE_STRING})
745
+ eval "FLAGS_${_flags_name_}='${_flags_arg_}'"
746
+ ;;
747
+ esac
748
+
749
+ # handle special case help flag
750
+ if [ "${_flags_name_}" = 'help' ]; then
751
+ if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
752
+ flags_error='help requested'
753
+ flags_return=${FLAGS_FALSE}
754
+ break
755
+ fi
756
+ fi
757
+
758
+ # shift the option and non-boolean arguements out.
759
+ shift
760
+ [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift
761
+ done
762
+
763
+ # give user back non-flag arguments
764
+ FLAGS_ARGV=''
765
+ while [ $# -gt 0 ]; do
766
+ FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
767
+ shift
768
+ done
769
+
770
+ unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \
771
+ _flags_strToEval_ _flags_type_ _flags_val_
772
+ return ${flags_return}
773
+ }
774
+
775
+ #------------------------------------------------------------------------------
776
+ # public functions
777
+ #
778
+
779
+ # A basic boolean flag. Boolean flags do not take any arguments, and their
780
+ # value is either 1 (false) or 0 (true). For long flags, the false value is
781
+ # specified on the command line by prepending the word 'no'. With short flags,
782
+ # the presense of the flag toggles the current value between true and false.
783
+ # Specifying a short boolean flag twice on the command results in returning the
784
+ # value back to the default value.
785
+ #
786
+ # A default value is required for boolean flags.
787
+ #
788
+ # For example, lets say a Boolean flag was created whose long name was 'update'
789
+ # and whose short name was 'x', and the default value was 'false'. This flag
790
+ # could be explicitly set to 'true' with '--update' or by '-x', and it could be
791
+ # explicitly set to 'false' with '--noupdate'.
792
+ DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@" || return "$?"; }
793
+
794
+ # Other basic flags.
795
+ DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@" || return "$?"; }
796
+ DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@" || return "$?"; }
797
+ DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@" || return "$?"; }
798
+
799
+ # Parse the flags.
800
+ #
801
+ # Args:
802
+ # unnamed: list: command-line flags to parse
803
+ # Returns:
804
+ # integer: success of operation, or error
805
+ FLAGS()
806
+ {
807
+ # define a standard 'help' flag if one isn't already defined
808
+ [ -z "${__flags_help_type:-}" ] && \
809
+ DEFINE_boolean 'help' false 'show this help' 'h'
810
+
811
+ # parse options
812
+ if [ $# -gt 0 ]; then
813
+ if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
814
+ _flags_getoptStandard "$@"
815
+ else
816
+ _flags_getoptEnhanced "$@"
817
+ fi
818
+ flags_return=$?
819
+ else
820
+ # nothing passed; won't bother running getopt
821
+ __flags_opts='--'
822
+ flags_return=${FLAGS_TRUE}
823
+ fi
824
+
825
+ if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
826
+ _flags_parseGetopt $# "${__flags_opts}"
827
+ flags_return=$?
828
+ fi
829
+
830
+ [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}"
831
+ return ${flags_return}
832
+ }
833
+
834
+ # This is a helper function for determining the `getopt` version for platforms
835
+ # where the detection isn't working. It simply outputs debug information that
836
+ # can be included in a bug report.
837
+ #
838
+ # Args:
839
+ # none
840
+ # Output:
841
+ # debug info that can be included in a bug report
842
+ # Returns:
843
+ # nothing
844
+ flags_getoptInfo()
845
+ {
846
+ # platform info
847
+ _flags_debug "uname -a: `uname -a`"
848
+ _flags_debug "PATH: ${PATH}"
849
+
850
+ # shell info
851
+ if [ -n "${BASH_VERSION:-}" ]; then
852
+ _flags_debug 'shell: bash'
853
+ _flags_debug "BASH_VERSION: ${BASH_VERSION}"
854
+ elif [ -n "${ZSH_VERSION:-}" ]; then
855
+ _flags_debug 'shell: zsh'
856
+ _flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
857
+ fi
858
+
859
+ # getopt info
860
+ getopt >/dev/null
861
+ _flags_getoptReturn=$?
862
+ _flags_debug "getopt return: ${_flags_getoptReturn}"
863
+ _flags_debug "getopt --version: `getopt --version 2>&1`"
864
+
865
+ unset _flags_getoptReturn
866
+ }
867
+
868
+ # Returns whether the detected getopt version is the enhanced version.
869
+ #
870
+ # Args:
871
+ # none
872
+ # Output:
873
+ # none
874
+ # Returns:
875
+ # bool: true if getopt is the enhanced version
876
+ flags_getoptIsEnh()
877
+ {
878
+ test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH}
879
+ }
880
+
881
+ # Returns whether the detected getopt version is the standard version.
882
+ #
883
+ # Args:
884
+ # none
885
+ # Returns:
886
+ # bool: true if getopt is the standard version
887
+ flags_getoptIsStd()
888
+ {
889
+ test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD}
890
+ }
891
+
892
+ # This is effectively a 'usage()' function. It prints usage information and
893
+ # exits the program with ${FLAGS_FALSE} if it is ever found in the command line
894
+ # arguments. Note this function can be overridden so other apps can define
895
+ # their own --help flag, replacing this one, if they want.
896
+ #
897
+ # Args:
898
+ # none
899
+ # Returns:
900
+ # integer: success of operation (always returns true)
901
+ flags_help()
902
+ {
903
+ if [ -n "${FLAGS_HELP:-}" ]; then
904
+ echo "${FLAGS_HELP}" >&2
905
+ else
906
+ echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2
907
+ fi
908
+ if [ -n "${__flags_longNames}" ]; then
909
+ echo 'flags:' >&2
910
+ for flags_name_ in ${__flags_longNames}; do
911
+ flags_flagStr_=''
912
+ flags_boolStr_=''
913
+
914
+ flags_default_=`_flags_getFlagInfo \
915
+ "${flags_name_}" ${__FLAGS_INFO_DEFAULT}`
916
+ flags_help_=`_flags_getFlagInfo \
917
+ "${flags_name_}" ${__FLAGS_INFO_HELP}`
918
+ flags_short_=`_flags_getFlagInfo \
919
+ "${flags_name_}" ${__FLAGS_INFO_SHORT}`
920
+ flags_type_=`_flags_getFlagInfo \
921
+ "${flags_name_}" ${__FLAGS_INFO_TYPE}`
922
+
923
+ [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
924
+ && flags_flagStr_="-${flags_short_}"
925
+
926
+ if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
927
+ [ "${flags_short_}" != "${__FLAGS_NULL}" ] \
928
+ && flags_flagStr_="${flags_flagStr_},"
929
+ [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] \
930
+ && flags_boolStr_='[no]'
931
+ flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:"
932
+ fi
933
+
934
+ case ${flags_type_} in
935
+ ${__FLAGS_TYPE_BOOLEAN})
936
+ if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then
937
+ flags_defaultStr_='true'
938
+ else
939
+ flags_defaultStr_='false'
940
+ fi
941
+ ;;
942
+ ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER})
943
+ flags_defaultStr_=${flags_default_} ;;
944
+ ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;;
945
+ esac
946
+ flags_defaultStr_="(default: ${flags_defaultStr_})"
947
+
948
+ flags_helpStr_=" ${flags_flagStr_} ${flags_help_} ${flags_defaultStr_}"
949
+ flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
950
+ flags_columns_=`_flags_columns`
951
+ if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
952
+ echo "${flags_helpStr_}" >&2
953
+ else
954
+ echo " ${flags_flagStr_} ${flags_help_}" >&2
955
+ # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
956
+ # because it doesn't like empty strings when used in this manner.
957
+ flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
958
+ |awk '{printf "%"length($0)-2"s", ""}'`"
959
+ flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}"
960
+ flags_helpStrLen_=`expr "${flags_helpStr_}" : '.*'`
961
+ if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \
962
+ -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
963
+ # indented to match help string
964
+ echo "${flags_helpStr_}" >&2
965
+ else
966
+ # indented four from left to allow for longer defaults as long flag
967
+ # names might be used too, making things too long
968
+ echo " ${flags_defaultStr_}" >&2
969
+ fi
970
+ fi
971
+ done
972
+ fi
973
+
974
+ unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \
975
+ flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \
976
+ flags_columns_ flags_short_ flags_type_
977
+ return ${FLAGS_TRUE}
978
+ }
979
+
980
+ # Reset shflags back to an uninitialized state.
981
+ #
982
+ # Args:
983
+ # none
984
+ # Returns:
985
+ # nothing
986
+ flags_reset()
987
+ {
988
+ for flags_name_ in ${__flags_longNames}; do
989
+ flags_strToEval_="unset FLAGS_${flags_name_}"
990
+ for flags_type_ in \
991
+ ${__FLAGS_INFO_DEFAULT} \
992
+ ${__FLAGS_INFO_HELP} \
993
+ ${__FLAGS_INFO_SHORT} \
994
+ ${__FLAGS_INFO_TYPE}
995
+ do
996
+ flags_strToEval_=\
997
+ "${flags_strToEval_} __flags_${flags_name_}_${flags_type_}"
998
+ done
999
+ eval ${flags_strToEval_}
1000
+ done
1001
+
1002
+ # reset internal variables
1003
+ __flags_boolNames=' '
1004
+ __flags_longNames=' '
1005
+ __flags_shortNames=' '
1006
+
1007
+ unset flags_name_ flags_type_ flags_strToEval_
1008
+ }
1009
+
1010
+ # parse stops on first non-option arg
1011
+ FLAGS_SUB="$FLAGS_FALSE"
1012
+