1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
4 # Copyright 2008 Jean Privat <jean@pryen.org>
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
14 # Management of options on the command line
17 # Super class of all option's class
19 # Names for the option (including long and short ones)
20 var names
: Array[String]
22 # Type of the value of the option
23 type VALUE: nullable Object
25 # Human readable description of the option
28 # Gathering errors during parsing
29 var errors
: Array[String] = new Array[String]
31 # Is this option mandatory?
32 var mandatory
: Bool = false is writable
34 # Is this option hidden from `usage`?
35 var hidden
: Bool = false is writable
37 # Has this option been read?
38 var read
: Bool = false is writable
40 # Current value of this option
41 var value
: VALUE is writable
43 # Default value of this option
44 var default_value
: VALUE is writable
47 init(help
: String, default
: VALUE, names
: nullable Array[String])
49 init_opt
(help
, default
, names
)
52 fun init_opt
(help
: String, default
: VALUE, names
: nullable Array[String])
55 self.names
= new Array[String]
57 self.names
= names
.to_a
60 default_value
= default
64 # Add new aliases for this option
65 fun add_aliases
(names
: String...) do names
.add_all
(names
)
67 # An help text for this option with default settings
68 redef fun to_s
do return pretty
(2)
70 # A pretty print for this help
71 fun pretty
(off
: Int): String
73 var text
= new FlatBuffer.from
(" ")
74 text
.append
(names
.join
(", "))
76 var rest
= off
- text
.length
77 if rest
> 0 then text
.append
(" " * rest
)
79 #text.append(pretty_default)
83 fun pretty_default
: String
85 var dv
= default_value
86 if dv
!= null then return " ({dv.to_s})"
90 # Consume parameters for this option
91 protected fun read_param
(it
: Iterator[String])
97 # Not really an option. Just add a line of text when displaying the usage
100 init(text
: String) do super(text
, null, null)
102 redef fun pretty
(off
) do return to_s
104 redef fun to_s
do return helptext
107 # A boolean option, `true` when present, `false` if not
110 redef type VALUE: Bool
112 init(help
: String, names
: String...) do super(help
, false, names
)
114 redef fun read_param
(it
)
121 # A count option. Count the number of time this option is present
124 redef type VALUE: Int
126 init(help
: String, names
: String...) do super(help
, 0, names
)
128 redef fun read_param
(it
)
135 # Option with one parameter (mandatory by default)
136 abstract class OptionParameter
138 protected fun convert
(str
: String): VALUE is abstract
140 # Is the parameter mandatory?
141 var parameter_mandatory
: Bool = true is writable
143 redef fun read_param
(it
)
146 if it
.is_ok
and it
.item
.chars
.first
!= '-' then
147 value
= convert
(it
.item
)
150 if parameter_mandatory
then
151 errors
.add
("Parameter expected for option {names.first}.")
157 # An option with a String as parameter
159 super OptionParameter
160 redef type VALUE: nullable String
162 init(help
: String, names
: String...) do super(help
, null, names
)
164 redef fun convert
(str
) do return str
167 # An option with an enum as parameter
168 # In the code, declaring an option enum (-e) with an enum like `["zero", "one", "two"]
169 # In the command line, typing `myprog -e one` is giving 1 as value
171 super OptionParameter
172 redef type VALUE: Int
173 var values
: Array[String]
175 init(values
: Array[String], help
: String, default
: Int, names
: String...)
177 assert values
.length
> 0
178 self.values
= values
.to_a
179 super("{help} <{values.join(", ")}>", default
, names
)
182 redef fun convert
(str
)
184 var id
= values
.index_of
(str
)
186 var e
= "Unrecognized value for option {names.join(", ")}.\n"
187 e
+= "Expected values are: {values.join(", ")}."
193 fun value_name
: String do return values
[value
]
195 redef fun pretty_default
197 return " ({values[default_value]})"
201 # An option with an Int as parameter
203 super OptionParameter
204 redef type VALUE: Int
206 init(help
: String, default
: Int, names
: String...) do super(help
, default
, names
)
208 redef fun convert
(str
) do return str
.to_i
211 # An option with a Float as parameter
213 super OptionParameter
214 redef type VALUE: Float
216 init(help
: String, default
: Float, names
: String...) do super(help
, default
, names
)
218 redef fun convert
(str
) do return str
.to_f
221 # An option with an array as parameter
222 # `myprog -optA arg1 -optA arg2` is giving an Array `["arg1", "arg2"]`
224 super OptionParameter
225 redef type VALUE: Array[String]
227 init(help
: String, names
: String...)
229 values
= new Array[String]
230 super(help
, values
, names
)
233 private var values
: Array[String]
234 redef fun convert
(str
)
241 # Context where the options process
243 # Options present in the context
244 var options
= new Array[Option]
246 # Rest of the options after `parse` is called
247 var rest
= new Array[String]
249 # Errors found in the context after parsing
250 var errors
= new Array[String]
252 private var optmap
= new HashMap[String, Option]
254 # Add one or more options to the context
255 fun add_option
(opts
: Option...) do
256 options
.add_all
(opts
)
259 # Display all the options available
268 if lmax
< l
then lmax
= l
273 print
(i
.pretty
(lmax
))
278 # Parse and assign options everywhere in the argument list
279 fun parse
(argv
: Collection[String])
281 var it
= argv
.iterator
285 # Parse the command line
286 protected fun parse_intern
(it
: Iterator[String])
292 while parseargs
and it
.is_ok
do
296 rest
.add_all
(it
.to_a
)
299 # We're looking for packed short options
300 if str
.chars
.last_index_of
('-') == 0 and str
.length
> 2 then
301 var next_called
= false
302 for i
in [1..str
.length
[ do
303 var short_opt
= "-" + str
.chars
[i
].to_s
304 if optmap
.has_key
(short_opt
) then
305 var option
= optmap
[short_opt
]
306 if option
isa OptionParameter then
310 option
.read_param
(it
)
313 if not next_called
then it
.next
315 if optmap
.has_key
(str
) then
316 var opt
= optmap
[str
]
327 for opt
in options
do
328 if opt
.mandatory
and not opt
.read
then
329 errors
.add
("Mandatory option {opt.names.join(", ")} not found.")
343 fun get_errors
: Array[String]
345 var errors
: Array[String] = new Array[String]
346 errors
.add_all
(errors
)