source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/getoptlong.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 14.9 KB
Line 
1#
2# GetoptLong for Ruby
3#
4# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara.
5#
6# You may redistribute and/or modify this library under the same license
7# terms as Ruby.
8#
9# See GetoptLong for documentation.
10#
11# Additional documents and the latest version of `getoptlong.rb' can be
12# found at http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/
13
14# The GetoptLong class allows you to parse command line options similarly to
15# the GNU getopt_long() C library call. Note, however, that GetoptLong is a
16# pure Ruby implementation.
17#
18# GetoptLong allows for POSIX-style options like <tt>--file</tt> as well
19# as single letter options like <tt>-f</tt>
20#
21# The empty option <tt>--</tt> (two minus symbols) is used to end option
22# processing. This can be particularly important if options have optional
23# arguments.
24#
25# Here is a simple example of usage:
26#
27# # == Synopsis
28# #
29# # hello: greets user, demonstrates command line parsing
30# #
31# # == Usage
32# #
33# # hello [OPTION] ... DIR
34# #
35# # -h, --help:
36# # show help
37# #
38# # --repeat x, -n x:
39# # repeat x times
40# #
41# # --name [name]:
42# # greet user by name, if name not supplied default is John
43# #
44# # DIR: The directory in which to issue the greeting.
45#
46# require 'getoptlong'
47# require 'rdoc/usage'
48#
49# opts = GetoptLong.new(
50# [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
51# [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ],
52# [ '--name', GetoptLong::OPTIONAL_ARGUMENT ]
53# )
54#
55# dir = nil
56# name = nil
57# repetitions = 1
58# opts.each do |opt, arg|
59# case opt
60# when '--help'
61# RDoc::usage
62# when '--repeat'
63# repetitions = arg.to_i
64# when '--name'
65# if arg == ''
66# name = 'John'
67# else
68# name = arg
69# end
70# end
71# end
72#
73# if ARGV.length != 1
74# puts "Missing dir argument (try --help)"
75# exit 0
76# end
77#
78# dir = ARGV.shift
79#
80# Dir.chdir(dir)
81# for i in (1..repetitions)
82# print "Hello"
83# if name
84# print ", #{name}"
85# end
86# puts
87# end
88#
89# Example command line:
90#
91# hello -n 6 --name -- /tmp
92#
93class GetoptLong
94 #
95 # Orderings.
96 #
97 ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
98
99 #
100 # Argument flags.
101 #
102 ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
103 OPTIONAL_ARGUMENT = 2]
104
105 #
106 # Status codes.
107 #
108 STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2
109
110 #
111 # Error types.
112 #
113 class Error < StandardError; end
114 class AmbigousOption < Error; end
115 class NeedlessArgument < Error; end
116 class MissingArgument < Error; end
117 class InvalidOption < Error; end
118
119 #
120 # Set up option processing.
121 #
122 # The options to support are passed to new() as an array of arrays.
123 # Each sub-array contains any number of String option names which carry
124 # the same meaning, and one of the following flags:
125 #
126 # GetoptLong::NO_ARGUMENT :: Option does not take an argument.
127 #
128 # GetoptLong::REQUIRED_ARGUMENT :: Option always takes an argument.
129 #
130 # GetoptLong::OPTIONAL_ARGUMENT :: Option may or may not take an argument.
131 #
132 # The first option name is considered to be the preferred (canonical) name.
133 # Other than that, the elements of each sub-array can be in any order.
134 #
135 def initialize(*arguments)
136 #
137 # Current ordering.
138 #
139 if ENV.include?('POSIXLY_CORRECT')
140 @ordering = REQUIRE_ORDER
141 else
142 @ordering = PERMUTE
143 end
144
145 #
146 # Hash table of option names.
147 # Keys of the table are option names, and their values are canonical
148 # names of the options.
149 #
150 @canonical_names = Hash.new
151
152 #
153 # Hash table of argument flags.
154 # Keys of the table are option names, and their values are argument
155 # flags of the options.
156 #
157 @argument_flags = Hash.new
158
159 #
160 # Whether error messages are output to $deferr.
161 #
162 @quiet = FALSE
163
164 #
165 # Status code.
166 #
167 @status = STATUS_YET
168
169 #
170 # Error code.
171 #
172 @error = nil
173
174 #
175 # Error message.
176 #
177 @error_message = nil
178
179 #
180 # Rest of catenated short options.
181 #
182 @rest_singles = ''
183
184 #
185 # List of non-option-arguments.
186 # Append them to ARGV when option processing is terminated.
187 #
188 @non_option_arguments = Array.new
189
190 if 0 < arguments.length
191 set_options(*arguments)
192 end
193 end
194
195 #
196 # Set the handling of the ordering of options and arguments.
197 # A RuntimeError is raised if option processing has already started.
198 #
199 # The supplied value must be a member of GetoptLong::ORDERINGS. It alters
200 # the processing of options as follows:
201 #
202 # <b>REQUIRE_ORDER</b> :
203 #
204 # Options are required to occur before non-options.
205 #
206 # Processing of options ends as soon as a word is encountered that has not
207 # been preceded by an appropriate option flag.
208 #
209 # For example, if -a and -b are options which do not take arguments,
210 # parsing command line arguments of '-a one -b two' would result in
211 # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being
212 # processed as an option/arg pair.
213 #
214 # This is the default ordering, if the environment variable
215 # POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.)
216 #
217 # <b>PERMUTE</b> :
218 #
219 # Options can occur anywhere in the command line parsed. This is the
220 # default behavior.
221 #
222 # Every sequence of words which can be interpreted as an option (with or
223 # without argument) is treated as an option; non-option words are skipped.
224 #
225 # For example, if -a does not require an argument and -b optionally takes
226 # an argument, parsing '-a one -b two three' would result in ('-a','') and
227 # ('-b', 'two') being processed as option/arg pairs, and 'one','three'
228 # being left in ARGV.
229 #
230 # If the ordering is set to PERMUTE but the environment variable
231 # POSIXLY_CORRECT is set, REQUIRE_ORDER is used instead. This is for
232 # compatibility with GNU getopt_long.
233 #
234 # <b>RETURN_IN_ORDER</b> :
235 #
236 # All words on the command line are processed as options. Words not
237 # preceded by a short or long option flag are passed as arguments
238 # with an option of '' (empty string).
239 #
240 # For example, if -a requires an argument but -b does not, a command line
241 # of '-a one -b two three' would result in option/arg pairs of ('-a', 'one')
242 # ('-b', ''), ('', 'two'), ('', 'three') being processed.
243 #
244 def ordering=(ordering)
245 #
246 # The method is failed if option processing has already started.
247 #
248 if @status != STATUS_YET
249 set_error(ArgumentError, "argument error")
250 raise RuntimeError,
251 "invoke ordering=, but option processing has already started"
252 end
253
254 #
255 # Check ordering.
256 #
257 if !ORDERINGS.include?(ordering)
258 raise ArgumentError, "invalid ordering `#{ordering}'"
259 end
260 if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
261 @ordering = REQUIRE_ORDER
262 else
263 @ordering = ordering
264 end
265 end
266
267 #
268 # Return ordering.
269 #
270 attr_reader :ordering
271
272 #
273 # Set options. Takes the same argument as GetoptLong.new.
274 #
275 # Raises a RuntimeError if option processing has already started.
276 #
277 def set_options(*arguments)
278 #
279 # The method is failed if option processing has already started.
280 #
281 if @status != STATUS_YET
282 raise RuntimeError,
283 "invoke set_options, but option processing has already started"
284 end
285
286 #
287 # Clear tables of option names and argument flags.
288 #
289 @canonical_names.clear
290 @argument_flags.clear
291
292 arguments.each do |arg|
293 #
294 # Each argument must be an Array.
295 #
296 if !arg.is_a?(Array)
297 raise ArgumentError, "the option list contains non-Array argument"
298 end
299
300 #
301 # Find an argument flag and it set to `argument_flag'.
302 #
303 argument_flag = nil
304 arg.each do |i|
305 if ARGUMENT_FLAGS.include?(i)
306 if argument_flag != nil
307 raise ArgumentError, "too many argument-flags"
308 end
309 argument_flag = i
310 end
311 end
312 raise ArgumentError, "no argument-flag" if argument_flag == nil
313
314 canonical_name = nil
315 arg.each do |i|
316 #
317 # Check an option name.
318 #
319 next if i == argument_flag
320 begin
321 if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/
322 raise ArgumentError, "an invalid option `#{i}'"
323 end
324 if (@canonical_names.include?(i))
325 raise ArgumentError, "option redefined `#{i}'"
326 end
327 rescue
328 @canonical_names.clear
329 @argument_flags.clear
330 raise
331 end
332
333 #
334 # Register the option (`i') to the `@canonical_names' and
335 # `@canonical_names' Hashes.
336 #
337 if canonical_name == nil
338 canonical_name = i
339 end
340 @canonical_names[i] = canonical_name
341 @argument_flags[i] = argument_flag
342 end
343 raise ArgumentError, "no option name" if canonical_name == nil
344 end
345 return self
346 end
347
348 #
349 # Set/Unset `quiet' mode.
350 #
351 attr_writer :quiet
352
353 #
354 # Return the flag of `quiet' mode.
355 #
356 attr_reader :quiet
357
358 #
359 # `quiet?' is an alias of `quiet'.
360 #
361 alias quiet? quiet
362
363 #
364 # Explicitly terminate option processing.
365 #
366 def terminate
367 return nil if @status == STATUS_TERMINATED
368 raise RuntimeError, "an error has occured" if @error != nil
369
370 @status = STATUS_TERMINATED
371 @non_option_arguments.reverse_each do |argument|
372 ARGV.unshift(argument)
373 end
374
375 @canonical_names = nil
376 @argument_flags = nil
377 @rest_singles = nil
378 @non_option_arguments = nil
379
380 return self
381 end
382
383 #
384 # Returns true if option processing has terminated, false otherwise.
385 #
386 def terminated?
387 return @status == STATUS_TERMINATED
388 end
389
390 #
391 # Set an error (protected).
392 #
393 def set_error(type, message)
394 $deferr.print("#{$0}: #{message}\n") if !@quiet
395
396 @error = type
397 @error_message = message
398 @canonical_names = nil
399 @argument_flags = nil
400 @rest_singles = nil
401 @non_option_arguments = nil
402
403 raise type, message
404 end
405 protected :set_error
406
407 #
408 # Examine whether an option processing is failed.
409 #
410 attr_reader :error
411
412 #
413 # `error?' is an alias of `error'.
414 #
415 alias error? error
416
417 # Return the appropriate error message in POSIX-defined format.
418 # If no error has occurred, returns nil.
419 #
420 def error_message
421 return @error_message
422 end
423
424 #
425 # Get next option name and its argument, as an Array of two elements.
426 #
427 # The option name is always converted to the first (preferred)
428 # name given in the original options to GetoptLong.new.
429 #
430 # Example: ['--option', 'value']
431 #
432 # Returns nil if the processing is complete (as determined by
433 # STATUS_TERMINATED).
434 #
435 def get
436 option_name, option_argument = nil, ''
437
438 #
439 # Check status.
440 #
441 return nil if @error != nil
442 case @status
443 when STATUS_YET
444 @status = STATUS_STARTED
445 when STATUS_TERMINATED
446 return nil
447 end
448
449 #
450 # Get next option argument.
451 #
452 if 0 < @rest_singles.length
453 argument = '-' + @rest_singles
454 elsif (ARGV.length == 0)
455 terminate
456 return nil
457 elsif @ordering == PERMUTE
458 while 0 < ARGV.length && ARGV[0] !~ /^-./
459 @non_option_arguments.push(ARGV.shift)
460 end
461 if ARGV.length == 0
462 terminate
463 return nil
464 end
465 argument = ARGV.shift
466 elsif @ordering == REQUIRE_ORDER
467 if (ARGV[0] !~ /^-./)
468 terminate
469 return nil
470 end
471 argument = ARGV.shift
472 else
473 argument = ARGV.shift
474 end
475
476 #
477 # Check the special argument `--'.
478 # `--' indicates the end of the option list.
479 #
480 if argument == '--' && @rest_singles.length == 0
481 terminate
482 return nil
483 end
484
485 #
486 # Check for long and short options.
487 #
488 if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0
489 #
490 # This is a long style option, which start with `--'.
491 #
492 pattern = $1
493 if @canonical_names.include?(pattern)
494 option_name = pattern
495 else
496 #
497 # The option `option_name' is not registered in `@canonical_names'.
498 # It may be an abbreviated.
499 #
500 match_count = 0
501 @canonical_names.each_key do |key|
502 if key.index(pattern) == 0
503 option_name = key
504 match_count += 1
505 end
506 end
507 if 2 <= match_count
508 set_error(AmbigousOption, "option `#{argument}' is ambiguous")
509 elsif match_count == 0
510 set_error(InvalidOption, "unrecognized option `#{argument}'")
511 end
512 end
513
514 #
515 # Check an argument to the option.
516 #
517 if @argument_flags[option_name] == REQUIRED_ARGUMENT
518 if argument =~ /=(.*)$/
519 option_argument = $1
520 elsif 0 < ARGV.length
521 option_argument = ARGV.shift
522 else
523 set_error(MissingArgument,
524 "option `#{argument}' requires an argument")
525 end
526 elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
527 if argument =~ /=(.*)$/
528 option_argument = $1
529 elsif 0 < ARGV.length && ARGV[0] !~ /^-./
530 option_argument = ARGV.shift
531 else
532 option_argument = ''
533 end
534 elsif argument =~ /=(.*)$/
535 set_error(NeedlessArgument,
536 "option `#{option_name}' doesn't allow an argument")
537 end
538
539 elsif argument =~ /^(-(.))(.*)/
540 #
541 # This is a short style option, which start with `-' (not `--').
542 # Short options may be catenated (e.g. `-l -g' is equivalent to
543 # `-lg').
544 #
545 option_name, ch, @rest_singles = $1, $2, $3
546
547 if @canonical_names.include?(option_name)
548 #
549 # The option `option_name' is found in `@canonical_names'.
550 # Check its argument.
551 #
552 if @argument_flags[option_name] == REQUIRED_ARGUMENT
553 if 0 < @rest_singles.length
554 option_argument = @rest_singles
555 @rest_singles = ''
556 elsif 0 < ARGV.length
557 option_argument = ARGV.shift
558 else
559 # 1003.2 specifies the format of this message.
560 set_error(MissingArgument, "option requires an argument -- #{ch}")
561 end
562 elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
563 if 0 < @rest_singles.length
564 option_argument = @rest_singles
565 @rest_singles = ''
566 elsif 0 < ARGV.length && ARGV[0] !~ /^-./
567 option_argument = ARGV.shift
568 else
569 option_argument = ''
570 end
571 end
572 else
573 #
574 # This is an invalid option.
575 # 1003.2 specifies the format of this message.
576 #
577 if ENV.include?('POSIXLY_CORRECT')
578 set_error(InvalidOption, "illegal option -- #{ch}")
579 else
580 set_error(InvalidOption, "invalid option -- #{ch}")
581 end
582 end
583 else
584 #
585 # This is a non-option argument.
586 # Only RETURN_IN_ORDER falled into here.
587 #
588 return '', argument
589 end
590
591 return @canonical_names[option_name], option_argument
592 end
593
594 #
595 # `get_option' is an alias of `get'.
596 #
597 alias get_option get
598
599 # Iterator version of `get'.
600 #
601 # The block is called repeatedly with two arguments:
602 # The first is the option name.
603 # The second is the argument which followed it (if any).
604 # Example: ('--opt', 'value')
605 #
606 # The option name is always converted to the first (preferred)
607 # name given in the original options to GetoptLong.new.
608 #
609 def each
610 loop do
611 option_name, option_argument = get_option
612 break if option_name == nil
613 yield option_name, option_argument
614 end
615 end
616
617 #
618 # `each_option' is an alias of `each'.
619 #
620 alias each_option each
621end
Note: See TracBrowser for help on using the repository browser.