summaryrefslogtreecommitdiff
path: root/jni/ruby/lib/getoptlong.rb
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/getoptlong.rb
Fresh start
Diffstat (limited to 'jni/ruby/lib/getoptlong.rb')
-rw-r--r--jni/ruby/lib/getoptlong.rb612
1 files changed, 612 insertions, 0 deletions
diff --git a/jni/ruby/lib/getoptlong.rb b/jni/ruby/lib/getoptlong.rb
new file mode 100644
index 0000000..cf635f0
--- /dev/null
+++ b/jni/ruby/lib/getoptlong.rb
@@ -0,0 +1,612 @@
+#
+# GetoptLong for Ruby
+#
+# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara.
+#
+# You may redistribute and/or modify this library under the same license
+# terms as Ruby.
+#
+# See GetoptLong for documentation.
+#
+# Additional documents and the latest version of `getoptlong.rb' can be
+# found at http://www.sra.co.jp/people/m-kasahr/ruby/getoptlong/
+
+# The GetoptLong class allows you to parse command line options similarly to
+# the GNU getopt_long() C library call. Note, however, that GetoptLong is a
+# pure Ruby implementation.
+#
+# GetoptLong allows for POSIX-style options like <tt>--file</tt> as well
+# as single letter options like <tt>-f</tt>
+#
+# The empty option <tt>--</tt> (two minus symbols) is used to end option
+# processing. This can be particularly important if options have optional
+# arguments.
+#
+# Here is a simple example of usage:
+#
+# require 'getoptlong'
+#
+# opts = GetoptLong.new(
+# [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
+# [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ],
+# [ '--name', GetoptLong::OPTIONAL_ARGUMENT ]
+# )
+#
+# dir = nil
+# name = nil
+# repetitions = 1
+# opts.each do |opt, arg|
+# case opt
+# when '--help'
+# puts <<-EOF
+# hello [OPTION] ... DIR
+#
+# -h, --help:
+# show help
+#
+# --repeat x, -n x:
+# repeat x times
+#
+# --name [name]:
+# greet user by name, if name not supplied default is John
+#
+# DIR: The directory in which to issue the greeting.
+# EOF
+# when '--repeat'
+# repetitions = arg.to_i
+# when '--name'
+# if arg == ''
+# name = 'John'
+# else
+# name = arg
+# end
+# end
+# end
+#
+# if ARGV.length != 1
+# puts "Missing dir argument (try --help)"
+# exit 0
+# end
+#
+# dir = ARGV.shift
+#
+# Dir.chdir(dir)
+# for i in (1..repetitions)
+# print "Hello"
+# if name
+# print ", #{name}"
+# end
+# puts
+# end
+#
+# Example command line:
+#
+# hello -n 6 --name -- /tmp
+#
+class GetoptLong
+ #
+ # Orderings.
+ #
+ ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
+
+ #
+ # Argument flags.
+ #
+ ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
+ OPTIONAL_ARGUMENT = 2]
+
+ #
+ # Status codes.
+ #
+ STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2
+
+ #
+ # Error types.
+ #
+ class Error < StandardError; end
+ class AmbiguousOption < Error; end
+ class NeedlessArgument < Error; end
+ class MissingArgument < Error; end
+ class InvalidOption < Error; end
+
+ #
+ # Set up option processing.
+ #
+ # The options to support are passed to new() as an array of arrays.
+ # Each sub-array contains any number of String option names which carry
+ # the same meaning, and one of the following flags:
+ #
+ # GetoptLong::NO_ARGUMENT :: Option does not take an argument.
+ #
+ # GetoptLong::REQUIRED_ARGUMENT :: Option always takes an argument.
+ #
+ # GetoptLong::OPTIONAL_ARGUMENT :: Option may or may not take an argument.
+ #
+ # The first option name is considered to be the preferred (canonical) name.
+ # Other than that, the elements of each sub-array can be in any order.
+ #
+ def initialize(*arguments)
+ #
+ # Current ordering.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = PERMUTE
+ end
+
+ #
+ # Hash table of option names.
+ # Keys of the table are option names, and their values are canonical
+ # names of the options.
+ #
+ @canonical_names = Hash.new
+
+ #
+ # Hash table of argument flags.
+ # Keys of the table are option names, and their values are argument
+ # flags of the options.
+ #
+ @argument_flags = Hash.new
+
+ #
+ # Whether error messages are output to $stderr.
+ #
+ @quiet = FALSE
+
+ #
+ # Status code.
+ #
+ @status = STATUS_YET
+
+ #
+ # Error code.
+ #
+ @error = nil
+
+ #
+ # Error message.
+ #
+ @error_message = nil
+
+ #
+ # Rest of catenated short options.
+ #
+ @rest_singles = ''
+
+ #
+ # List of non-option-arguments.
+ # Append them to ARGV when option processing is terminated.
+ #
+ @non_option_arguments = Array.new
+
+ if 0 < arguments.length
+ set_options(*arguments)
+ end
+ end
+
+ #
+ # Set the handling of the ordering of options and arguments.
+ # A RuntimeError is raised if option processing has already started.
+ #
+ # The supplied value must be a member of GetoptLong::ORDERINGS. It alters
+ # the processing of options as follows:
+ #
+ # <b>REQUIRE_ORDER</b> :
+ #
+ # Options are required to occur before non-options.
+ #
+ # Processing of options ends as soon as a word is encountered that has not
+ # been preceded by an appropriate option flag.
+ #
+ # For example, if -a and -b are options which do not take arguments,
+ # parsing command line arguments of '-a one -b two' would result in
+ # 'one', '-b', 'two' being left in ARGV, and only ('-a', '') being
+ # processed as an option/arg pair.
+ #
+ # This is the default ordering, if the environment variable
+ # POSIXLY_CORRECT is set. (This is for compatibility with GNU getopt_long.)
+ #
+ # <b>PERMUTE</b> :
+ #
+ # Options can occur anywhere in the command line parsed. This is the
+ # default behavior.
+ #
+ # Every sequence of words which can be interpreted as an option (with or
+ # without argument) is treated as an option; non-option words are skipped.
+ #
+ # For example, if -a does not require an argument and -b optionally takes
+ # an argument, parsing '-a one -b two three' would result in ('-a','') and
+ # ('-b', 'two') being processed as option/arg pairs, and 'one','three'
+ # being left in ARGV.
+ #
+ # If the ordering is set to PERMUTE but the environment variable
+ # POSIXLY_CORRECT is set, REQUIRE_ORDER is used instead. This is for
+ # compatibility with GNU getopt_long.
+ #
+ # <b>RETURN_IN_ORDER</b> :
+ #
+ # All words on the command line are processed as options. Words not
+ # preceded by a short or long option flag are passed as arguments
+ # with an option of '' (empty string).
+ #
+ # For example, if -a requires an argument but -b does not, a command line
+ # of '-a one -b two three' would result in option/arg pairs of ('-a', 'one')
+ # ('-b', ''), ('', 'two'), ('', 'three') being processed.
+ #
+ def ordering=(ordering)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ set_error(ArgumentError, "argument error")
+ raise RuntimeError,
+ "invoke ordering=, but option processing has already started"
+ end
+
+ #
+ # Check ordering.
+ #
+ if !ORDERINGS.include?(ordering)
+ raise ArgumentError, "invalid ordering `#{ordering}'"
+ end
+ if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = ordering
+ end
+ end
+
+ #
+ # Return ordering.
+ #
+ attr_reader :ordering
+
+ #
+ # Set options. Takes the same argument as GetoptLong.new.
+ #
+ # Raises a RuntimeError if option processing has already started.
+ #
+ def set_options(*arguments)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ raise RuntimeError,
+ "invoke set_options, but option processing has already started"
+ end
+
+ #
+ # Clear tables of option names and argument flags.
+ #
+ @canonical_names.clear
+ @argument_flags.clear
+
+ arguments.each do |arg|
+ if !arg.is_a?(Array)
+ raise ArgumentError, "the option list contains non-Array argument"
+ end
+
+ #
+ # Find an argument flag and it set to `argument_flag'.
+ #
+ argument_flag = nil
+ arg.each do |i|
+ if ARGUMENT_FLAGS.include?(i)
+ if argument_flag != nil
+ raise ArgumentError, "too many argument-flags"
+ end
+ argument_flag = i
+ end
+ end
+
+ raise ArgumentError, "no argument-flag" if argument_flag == nil
+
+ canonical_name = nil
+ arg.each do |i|
+ #
+ # Check an option name.
+ #
+ next if i == argument_flag
+ begin
+ if !i.is_a?(String) || i !~ /^-([^-]|-.+)$/
+ raise ArgumentError, "an invalid option `#{i}'"
+ end
+ if (@canonical_names.include?(i))
+ raise ArgumentError, "option redefined `#{i}'"
+ end
+ rescue
+ @canonical_names.clear
+ @argument_flags.clear
+ raise
+ end
+
+ #
+ # Register the option (`i') to the `@canonical_names' and
+ # `@canonical_names' Hashes.
+ #
+ if canonical_name == nil
+ canonical_name = i
+ end
+ @canonical_names[i] = canonical_name
+ @argument_flags[i] = argument_flag
+ end
+ raise ArgumentError, "no option name" if canonical_name == nil
+ end
+ return self
+ end
+
+ #
+ # Set/Unset `quiet' mode.
+ #
+ attr_writer :quiet
+
+ #
+ # Return the flag of `quiet' mode.
+ #
+ attr_reader :quiet
+
+ #
+ # `quiet?' is an alias of `quiet'.
+ #
+ alias quiet? quiet
+
+ #
+ # Explicitly terminate option processing.
+ #
+ def terminate
+ return nil if @status == STATUS_TERMINATED
+ raise RuntimeError, "an error has occurred" if @error != nil
+
+ @status = STATUS_TERMINATED
+ @non_option_arguments.reverse_each do |argument|
+ ARGV.unshift(argument)
+ end
+
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ return self
+ end
+
+ #
+ # Returns true if option processing has terminated, false otherwise.
+ #
+ def terminated?
+ return @status == STATUS_TERMINATED
+ end
+
+ #
+ # Set an error (a protected method).
+ #
+ def set_error(type, message)
+ $stderr.print("#{$0}: #{message}\n") if !@quiet
+
+ @error = type
+ @error_message = message
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ raise type, message
+ end
+ protected :set_error
+
+ #
+ # Examine whether an option processing is failed.
+ #
+ attr_reader :error
+
+ #
+ # `error?' is an alias of `error'.
+ #
+ alias error? error
+
+ # Return the appropriate error message in POSIX-defined format.
+ # If no error has occurred, returns nil.
+ #
+ def error_message
+ return @error_message
+ end
+
+ #
+ # Get next option name and its argument, as an Array of two elements.
+ #
+ # The option name is always converted to the first (preferred)
+ # name given in the original options to GetoptLong.new.
+ #
+ # Example: ['--option', 'value']
+ #
+ # Returns nil if the processing is complete (as determined by
+ # STATUS_TERMINATED).
+ #
+ def get
+ option_name, option_argument = nil, ''
+
+ #
+ # Check status.
+ #
+ return nil if @error != nil
+ case @status
+ when STATUS_YET
+ @status = STATUS_STARTED
+ when STATUS_TERMINATED
+ return nil
+ end
+
+ #
+ # Get next option argument.
+ #
+ if 0 < @rest_singles.length
+ argument = '-' + @rest_singles
+ elsif (ARGV.length == 0)
+ terminate
+ return nil
+ elsif @ordering == PERMUTE
+ while 0 < ARGV.length && ARGV[0] !~ /^-./
+ @non_option_arguments.push(ARGV.shift)
+ end
+ if ARGV.length == 0
+ terminate
+ return nil
+ end
+ argument = ARGV.shift
+ elsif @ordering == REQUIRE_ORDER
+ if (ARGV[0] !~ /^-./)
+ terminate
+ return nil
+ end
+ argument = ARGV.shift
+ else
+ argument = ARGV.shift
+ end
+
+ #
+ # Check the special argument `--'.
+ # `--' indicates the end of the option list.
+ #
+ if argument == '--' && @rest_singles.length == 0
+ terminate
+ return nil
+ end
+
+ #
+ # Check for long and short options.
+ #
+ if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0
+ #
+ # This is a long style option, which start with `--'.
+ #
+ pattern = $1
+ if @canonical_names.include?(pattern)
+ option_name = pattern
+ else
+ #
+ # The option `option_name' is not registered in `@canonical_names'.
+ # It may be an abbreviated.
+ #
+ matches = []
+ @canonical_names.each_key do |key|
+ if key.index(pattern) == 0
+ option_name = key
+ matches << key
+ end
+ end
+ if 2 <= matches.length
+ set_error(AmbiguousOption, "option `#{argument}' is ambiguous between #{matches.join(', ')}")
+ elsif matches.length == 0
+ set_error(InvalidOption, "unrecognized option `#{argument}'")
+ end
+ end
+
+ #
+ # Check an argument to the option.
+ #
+ if @argument_flags[option_name] == REQUIRED_ARGUMENT
+ if argument =~ /=(.*)$/
+ option_argument = $1
+ elsif 0 < ARGV.length
+ option_argument = ARGV.shift
+ else
+ set_error(MissingArgument,
+ "option `#{argument}' requires an argument")
+ end
+ elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
+ if argument =~ /=(.*)$/
+ option_argument = $1
+ elsif 0 < ARGV.length && ARGV[0] !~ /^-./
+ option_argument = ARGV.shift
+ else
+ option_argument = ''
+ end
+ elsif argument =~ /=(.*)$/
+ set_error(NeedlessArgument,
+ "option `#{option_name}' doesn't allow an argument")
+ end
+
+ elsif argument =~ /^(-(.))(.*)/
+ #
+ # This is a short style option, which start with `-' (not `--').
+ # Short options may be catenated (e.g. `-l -g' is equivalent to
+ # `-lg').
+ #
+ option_name, ch, @rest_singles = $1, $2, $3
+
+ if @canonical_names.include?(option_name)
+ #
+ # The option `option_name' is found in `@canonical_names'.
+ # Check its argument.
+ #
+ if @argument_flags[option_name] == REQUIRED_ARGUMENT
+ if 0 < @rest_singles.length
+ option_argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length
+ option_argument = ARGV.shift
+ else
+ # 1003.2 specifies the format of this message.
+ set_error(MissingArgument, "option requires an argument -- #{ch}")
+ end
+ elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
+ if 0 < @rest_singles.length
+ option_argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length && ARGV[0] !~ /^-./
+ option_argument = ARGV.shift
+ else
+ option_argument = ''
+ end
+ end
+ else
+ #
+ # This is an invalid option.
+ # 1003.2 specifies the format of this message.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ set_error(InvalidOption, "invalid option -- #{ch}")
+ else
+ set_error(InvalidOption, "invalid option -- #{ch}")
+ end
+ end
+ else
+ #
+ # This is a non-option argument.
+ # Only RETURN_IN_ORDER falled into here.
+ #
+ return '', argument
+ end
+
+ return @canonical_names[option_name], option_argument
+ end
+
+ #
+ # `get_option' is an alias of `get'.
+ #
+ alias get_option get
+
+ # Iterator version of `get'.
+ #
+ # The block is called repeatedly with two arguments:
+ # The first is the option name.
+ # The second is the argument which followed it (if any).
+ # Example: ('--opt', 'value')
+ #
+ # The option name is always converted to the first (preferred)
+ # name given in the original options to GetoptLong.new.
+ #
+ def each
+ loop do
+ option_name, option_argument = get_option
+ break if option_name == nil
+ yield option_name, option_argument
+ end
+ end
+
+ #
+ # `each_option' is an alias of `each'.
+ #
+ alias each_option each
+end