X-Git-Url: http://nitlanguage.org diff --git a/lib/opts.nit b/lib/opts.nit deleted file mode 100644 index a7789f8..0000000 --- a/lib/opts.nit +++ /dev/null @@ -1,406 +0,0 @@ -# This file is part of NIT ( http://www.nitlanguage.org ). -# -# Copyright 2008 Floréal Morandat -# Copyright 2008 Jean Privat -# -# This file is free software, which comes along with NIT. This software is -# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. You can modify it is you want, provided this header -# is kept unaltered, and a notification of the changes is added. -# You are allowed to redistribute it and sell it, alone or is a part of -# another product. - -# Management of options on the command line -module opts - -# Super class of all option's class -abstract class Option - # Names for the option (including long and short ones) - var names: Array[String] - - # Type of the value of the option - type VALUE: nullable Object - - # Human readable description of the option - var helptext: String - - # Gathering errors during parsing - var errors: Array[String] = new Array[String] - - # Is this option mandatory? - var mandatory: Bool = false is writable - - # Is this option hidden from `usage`? - var hidden: Bool = false is writable - - # Has this option been read? - var read: Bool = false is writable - - # Current value of this option - var value: VALUE is writable - - # Default value of this option - var default_value: VALUE is writable - - # Create a new option - init(help: String, default: VALUE, names: nullable Array[String]) is old_style_init do - init_opt(help, default, names) - end - - # Init option `helptext`, `default_value` and `names`. - # - # Also set current `value` to `default`. - fun init_opt(help: String, default: VALUE, names: nullable Array[String]) - do - if names == null then - self.names = new Array[String] - else - self.names = names.to_a - end - helptext = help - default_value = default - value = default - end - - # Add new aliases for this option - fun add_aliases(names: String...) do names.add_all(names) - - # An help text for this option with default settings - redef fun to_s do return pretty(2) - - # A pretty print for this help - fun pretty(off: Int): String - do - var text = new FlatBuffer.from(" ") - text.append(names.join(", ")) - text.append(" ") - var rest = off - text.length - if rest > 0 then text.append(" " * rest) - text.append(helptext) - #text.append(pretty_default) - return text.to_s - end - - # Pretty print the default value. - fun pretty_default: String - do - var dv = default_value - if dv != null then return " ({dv.to_s})" - return "" - end - - # Consume parameters for this option - protected fun read_param(opts: OptionContext, it: Iterator[String]) - do - read = true - end -end - -# Not really an option. Just add a line of text when displaying the usage -class OptionText - super Option - - # Init a new OptionText with `text`. - init(text: String) is old_style_init do super(text, null, null) - - redef fun pretty(off) do return to_s - - redef fun to_s do return helptext -end - -# A boolean option, `true` when present, `false` if not -class OptionBool - super Option - redef type VALUE: Bool - - # Init a new OptionBool with a `help` message and `names`. - init(help: String, names: String...) is old_style_init do super(help, false, names) - - redef fun read_param(opts, it) - do - super - value = true - end -end - -# A count option. Count the number of time this option is present -class OptionCount - super Option - redef type VALUE: Int is fixed - - # Init a new OptionCount with a `help` message and `names`. - init(help: String, names: String...) is old_style_init do super(help, 0, names) - - redef fun read_param(opts, it) - do - super - value += 1 - end -end - -# Option with one parameter (mandatory by default) -abstract class OptionParameter - super Option - - # Convert `str` to a value of type `VALUE`. - protected fun convert(str: String): VALUE is abstract - - # Is the parameter mandatory? - var parameter_mandatory = true is writable - - redef fun read_param(opts, it) - do - super - - var ok = it.is_ok - if ok and not parameter_mandatory and not it.item.is_empty and it.item.chars.first == '-' then - # The next item may looks like a known command - # Only check if `not parameter_mandatory` - for opt in opts.options do - if opt.names.has(it.item) then - # The next item is a known command - ok = false - break - end - end - end - - if ok then - value = convert(it.item) - it.next - else - errors.add("Parameter expected for option {names.first}.") - end - end -end - -# An option with a `String` as parameter -class OptionString - super OptionParameter - redef type VALUE: nullable String - - # Init a new OptionString with a `help` message and `names`. - init(help: String, names: String...) is old_style_init do super(help, null, names) - - redef fun convert(str) do return str -end - -# An option to choose from an enumeration -# -# Declare an enumeration option with all its possible values as an array. -# Once the arguments are processed, `value` is set as the index of the selected value, if any. -class OptionEnum - super OptionParameter - redef type VALUE: Int - - # Values in the enumeration. - var values: Array[String] - - # Init a new OptionEnum from `values` with a `help` message and `names`. - # - # `default` is the index of the default value in `values`. - init(values: Array[String], help: String, default: Int, names: String...) is old_style_init do - assert values.length > 0 - self.values = values.to_a - super("{help} <{values.join(", ")}>", default, names) - end - - redef fun convert(str) - do - var id = values.index_of(str) - if id == -1 then - var e = "Unrecognized value for option {names.join(", ")}.\n" - e += "Expected values are: {values.join(", ")}." - errors.add(e) - end - return id - end - - # Get the value name from `values`. - fun value_name: String do return values[value] - - redef fun pretty_default - do - return " ({values[default_value]})" - end -end - -# An option with an Int as parameter -class OptionInt - super OptionParameter - redef type VALUE: Int - - # Init a new OptionInt with a `help` message, a `default` value and `names`. - init(help: String, default: Int, names: String...) is old_style_init do - super(help, default, names) - end - - redef fun convert(str) - do - if str.is_int then return str.to_i - - errors.add "Expected an integer for option {names.join(", ")}." - return 0 - end -end - -# An option with a Float as parameter -class OptionFloat - super OptionParameter - redef type VALUE: Float - - # Init a new OptionFloat with a `help` message, a `default` value and `names`. - init(help: String, default: Float, names: String...) is old_style_init do - super(help, default, names) - end - - redef fun convert(str) do return str.to_f -end - -# An option with an array as parameter -# `myprog -optA arg1 -optA arg2` is giving an Array `["arg1", "arg2"]` -class OptionArray - super OptionParameter - redef type VALUE: Array[String] - - # Init a new OptionArray with a `help` message and `names`. - init(help: String, names: String...) is old_style_init do - values = new Array[String] - super(help, values, names) - end - - private var values: Array[String] - redef fun convert(str) - do - values.add(str) - return values - end -end - -# Context where the options process -class OptionContext - # Options present in the context - var options = new Array[Option] - - # Rest of the options after `parse` is called - var rest = new Array[String] - - # Errors found in the context after parsing - var context_errors = new Array[String] - - private var optmap = new HashMap[String, Option] - - # Add one or more options to the context - fun add_option(opts: Option...) do options.add_all(opts) - - # Display all the options available - fun usage - do - var lmax = 1 - for i in options do - var l = 3 - for n in i.names do - l += n.length + 2 - end - if lmax < l then lmax = l - end - - for i in options do - if not i.hidden then - print(i.pretty(lmax)) - end - end - end - - # Parse and assign options in `argv` or `args` - fun parse(argv: nullable Collection[String]) - do - if argv == null then argv = args - var it = argv.iterator - parse_intern(it) - end - - # Must all option be given before the first argument? - # - # When set to `false` (the default), options of the command line are - # all parsed until the end of the list of arguments or until "--" is met (in this case "--" is discarded). - # - # When set to `true` options are parsed until the first non-option is met. - var options_before_rest = false is writable - - # Parse the command line - protected fun parse_intern(it: Iterator[String]) - do - var parseargs = true - build - var rest = rest - - while parseargs and it.is_ok do - var str = it.item - if str == "--" then - it.next - rest.add_all(it.to_a) - parseargs = false - else - # We're looking for packed short options - if str.chars.last_index_of('-') == 0 and str.length > 2 then - var next_called = false - for i in [1..str.length[ do - var short_opt = "-" + str.chars[i].to_s - if optmap.has_key(short_opt) then - var option = optmap[short_opt] - if option isa OptionParameter then - it.next - next_called = true - end - option.read_param(self, it) - end - end - if not next_called then it.next - else - if optmap.has_key(str) then - var opt = optmap[str] - it.next - opt.read_param(self, it) - else - rest.add(it.item) - it.next - if options_before_rest then - rest.add_all(it.to_a) - parseargs = false - end - end - end - end - end - - for opt in options do - if opt.mandatory and not opt.read then - context_errors.add("Mandatory option {opt.names.join(", ")} not found.") - end - end - end - - private fun build - do - for o in options do - for n in o.names do - optmap[n] = o - end - end - end - - # Options parsing errors. - fun errors: Array[String] - do - var errors = new Array[String] - errors.add_all context_errors - for o in options do - for e in o.errors do - errors.add(e) - end - end - return errors - end -end