PageRenderTime 165ms CodeModel.GetById 136ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/Ruby/lib/ruby/1.8/getoptlong.rb

http://github.com/agross/netopenspace
Ruby | 621 lines | 244 code | 49 blank | 328 comment | 69 complexity | 1d9afade1330b02bd0ff31ced760aa3a MD5 | raw file
  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