v / vlib / flag / flag.v
765 lines · 708 sloc · 25.0 KB · 6b8a901e8ff6f821514c65e4a0a820052af241d4
Raw
1module flag
2
3// data object storing information about a defined flag
4pub struct Flag {
5pub:
6 name string // name as it appears on command line
7 abbr u8 // shortcut
8 usage string // help message
9 val_desc string // something like '<arg>' that appears in usage,
10 // and also the default value, when the flag is not given
11 default_value string
12 has_default bool
13}
14
15struct UnknownFlagError {
16 Error
17 flag string
18}
19
20fn (err UnknownFlagError) msg() string {
21 return 'Unknown flag `${err.flag}`'
22}
23
24struct ArgsCountError {
25 Error
26 got int
27 want int
28}
29
30fn (err ArgsCountError) msg() string {
31 if err.want == 0 {
32 return 'Expected no arguments, but got ${err.got}'
33 } else if err.got > err.want {
34 return 'Expected at most ${err.want} arguments, but got ${err.got}'
35 } else {
36 return 'Expected at least ${err.want} arguments, but got ${err.got}'
37 }
38}
39
40// free frees the resources associated with a given Flag
41// It is called automatically when -autofree is used.
42// It should be called manually in functions that use Flags,
43// and are marked with [manualfree]. After you call .free() on
44// a Flag instance, you should NOT use that instance any more.
45@[unsafe]
46fn (mut f Flag) free() {
47 unsafe {
48 f.name.free()
49 f.usage.free()
50 f.val_desc.free()
51 f.default_value.free()
52 }
53}
54
55// str returns a string representation of the given Flag.
56pub fn (f Flag) str() string {
57 return ' flag:
58 name: ${f.name}
59 abbr: `${f.abbr.ascii_str()}`
60 usage: ${f.usage}
61 desc: ${f.val_desc}
62 default_value: ${f.default_value}
63 has_default: ${f.has_default}'
64}
65
66// str returns a string representation of the given array of Flags.
67pub fn (af []Flag) str() string {
68 mut res := []string{}
69 res << '\n []Flag = ['
70 for f in af {
71 res << f.str()
72 }
73 res << ' ]'
74 return res.join('\n')
75}
76
77// FlagParser is the heart of the `flag` module.
78// That structure is created with `mut parser := flag.new_flag_parser(os.args)`,
79// The returned instance can be further customised by calling various methods,
80// for specifying the accepted options and their values. The user should finally
81// call `rest := parser.finalize()!` to get the rest of the non optional arguments
82// (if there are any left).
83pub struct FlagParser {
84pub:
85 original_args []string // the original arguments to be parsed
86 idx_dashdash int // the index of a `--`, -1 if there is not any
87 all_after_dashdash []string // all options after `--` are ignored, and will be passed to the application unmodified
88pub mut:
89 usage_examples []string // when set, --help will print:
90 // Usage: ${appname} ${usage_examples[0]}`
91 // or: ${appname} ${usage_examples[1]}`
92 // etc
93 default_help_label string = 'display this help and exit'
94 default_version_label string = 'output version information and exit'
95 args []string // the current list of processed args
96 max_free_args int
97 flags []Flag // registered flags
98 application_name string
99 application_version string
100 application_description string
101 min_free_args int
102 args_description string
103 allow_unknown_args bool // whether passing undescribed arguments is allowed
104 footers []string // when set, --help will display all the collected footers at the bottom.
105 options DocOptions // documentation options
106}
107
108// free frees the resources allocated for the given FlagParser instance.
109// It should be called manually in functions that use it, and that are
110// marked with `@[manualfree]`, otherwise, it is called automatically
111// in programs, compiled with `-autofree`. Note: you should NOT use the
112// instance over which you have called .free() for anything after the call.
113@[unsafe]
114fn (mut f FlagParser) free() {
115 unsafe {
116 //
117 for flag in f.flags {
118 flag.free()
119 }
120 f.flags.free()
121 //
122 f.application_name.free()
123 f.application_version.free()
124 f.application_description.free()
125 f.args_description.free()
126 }
127}
128
129// used for formatting usage message
130pub const space = ' '
131pub const underline = '-----------------------------------------------'
132pub const max_args_number = 4048
133
134// new_flag_parser - create a new flag parser for the given args.
135@[manualfree]
136pub fn new_flag_parser(args []string) &FlagParser {
137 original_args := args.clone()
138 idx_dashdash := args.index('--')
139 mut all_before_dashdash := args.clone()
140 mut all_after_dashdash := []string{}
141 if idx_dashdash >= 0 {
142 all_before_dashdash.trim(idx_dashdash)
143 if idx_dashdash < original_args.len {
144 all_after_dashdash = unsafe { original_args[idx_dashdash + 1..] }
145 }
146 }
147 return &FlagParser{
148 original_args: original_args
149 idx_dashdash: idx_dashdash
150 all_after_dashdash: all_after_dashdash
151 args: all_before_dashdash
152 max_free_args: max_args_number
153 options: DocOptions{
154 show: ~Show.zero() ^ .name
155 }
156 }
157}
158
159// usage_example - add an usage example.
160// All examples will be listed in the help screen.
161// If you do not give any examples, then a default usage
162// will be shown, based on whether the application takes
163// options and expects additional parameters.
164pub fn (mut fs FlagParser) usage_example(example string) {
165 fs.usage_examples << example
166}
167
168// footer - adds a footnote, that will be shown at the bottom of the help screen.
169pub fn (mut fs FlagParser) footer(footer string) {
170 fs.footers << footer
171}
172
173// application changes the application name to be used in 'usage' output.
174pub fn (mut fs FlagParser) application(name string) {
175 fs.application_name = name
176}
177
178// version changes the application version to be used in 'usage' output.
179pub fn (mut fs FlagParser) version(vers string) {
180 fs.application_version = vers
181}
182
183// description appends to the application description lines, shown in the help/usage screen.
184pub fn (mut fs FlagParser) description(desc string) {
185 if fs.application_description.len == 0 {
186 fs.application_description = desc
187 } else {
188 fs.application_description += '\n${desc}'
189 }
190}
191
192// skip_executable - removes the first argv (it usually contains the executable name).
193// In most cases you do not need it for flag parsing.
194// This method, allows you to use `mut fp := flag.new_flag_parser(arguments())` directly.
195pub fn (mut fs FlagParser) skip_executable() {
196 fs.args.delete(0)
197}
198
199// allow_unknown_args - call this method, if your program has sub commands, that have their own arguments.
200// After calling it, the subcommand arguments (which generally are not known to your parent program),
201// will not cause the validation in .finalize() to fail.
202pub fn (mut fs FlagParser) allow_unknown_args() {
203 fs.allow_unknown_args = true
204}
205
206// private helper to register a flag.
207// This version supports abbreviations.
208fn (mut fs FlagParser) add_flag(name string, abbr u8, usage string, desc string, default_value ?string) {
209 mut has_default := false
210 mut resolved_default_value := ''
211 if value := default_value {
212 has_default = true
213 resolved_default_value = value
214 }
215 fs.flags << Flag{
216 name: name
217 abbr: abbr
218 usage: usage
219 val_desc: desc
220 default_value: resolved_default_value
221 has_default: has_default
222 }
223}
224
225fn flag_value_description(c FlagConfig, default_description string) string {
226 return if c.val_desc == '' {
227 default_description
228 } else {
229 c.val_desc
230 }
231}
232
233fn escape_default_string(value string) string {
234 return value.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r').replace('\t',
235 '\\t')
236}
237
238fn flag_default_value[T](value T) string {
239 $if T is string {
240 s := '${value}'
241 return '"${escape_default_string(s)}"'
242 } $else {
243 return '${value}'
244 }
245}
246
247fn (mut fs FlagParser) bool_flag(name string, abbr u8, usage string, c FlagConfig, default_value ?string) !bool {
248 val_desc := flag_value_description(c, '<bool>')
249 fs.add_flag(name, abbr, usage, val_desc, default_value)
250 parsed := fs.parse_bool_value(name, abbr) or {
251 return error("parameter '${name}' not provided")
252 }
253 return parsed == 'true'
254}
255
256fn (mut fs FlagParser) int_flag(name string, abbr u8, usage string, c FlagConfig, default_value ?string) !int {
257 val_desc := flag_value_description(c, '<int>')
258 fs.add_flag(name, abbr, usage, val_desc, default_value)
259 parsed := fs.parse_value(name, abbr)
260 if parsed.len == 0 {
261 return error("parameter '${name}' not provided")
262 }
263 return parsed[0].int()
264}
265
266fn (mut fs FlagParser) float_flag(name string, abbr u8, usage string, c FlagConfig, default_value ?string) !f64 {
267 val_desc := flag_value_description(c, '<float>')
268 fs.add_flag(name, abbr, usage, val_desc, default_value)
269 parsed := fs.parse_value(name, abbr)
270 if parsed.len == 0 {
271 return error("parameter '${name}' not provided")
272 }
273 return parsed[0].f64()
274}
275
276fn (mut fs FlagParser) string_flag(name string, abbr u8, usage string, c FlagConfig, default_value ?string) !string {
277 val_desc := flag_value_description(c, '<string>')
278 fs.add_flag(name, abbr, usage, val_desc, default_value)
279 parsed := fs.parse_value(name, abbr)
280 if parsed.len == 0 {
281 return error("parameter '${name}' not provided")
282 }
283 return parsed[0]
284}
285
286// private: general parsing a single argument
287// - search args for existence
288// if true
289// extract the defined value as string
290// else
291// return an (dummy) error -> argument is not defined
292//
293// - the name, usage are registered
294// - found arguments and corresponding values are removed from args list
295@[manualfree]
296fn (mut fs FlagParser) parse_value(longhand string, shorthand u8) []string {
297 full := '--${longhand}'
298 defer {
299 unsafe { full.free() }
300 }
301 mut found_entries := []string{}
302 mut to_delete := []int{}
303 defer {
304 unsafe { to_delete.free() }
305 }
306 mut should_skip_one := false
307 for i, arg in fs.args {
308 if should_skip_one {
309 should_skip_one = false
310 continue
311 }
312 if arg.len == 0 || arg[0] != `-` {
313 continue
314 }
315 if (arg.len == 2 && arg[0] == `-` && arg[1] == shorthand) || arg == full {
316 if i + 1 >= fs.args.len {
317 return []
318 }
319 nextarg := fs.args[i + 1]
320 if nextarg.len > 2 {
321 nextarg_rest := nextarg[..2]
322 if nextarg_rest == '--' {
323 // It could be end of input (--) or another argument (--abc).
324 // Both are invalid so die.
325 unsafe { nextarg_rest.free() }
326 return []
327 }
328 unsafe { nextarg_rest.free() }
329 }
330 found_entries << fs.args[i + 1]
331 to_delete << i
332 to_delete << i + 1
333 should_skip_one = true
334 continue
335 }
336 if arg.len > full.len + 1 && arg[..full.len + 1] == '${full}=' {
337 found_entries << arg[full.len + 1..]
338 to_delete << i
339 continue
340 }
341 }
342 for i, del in to_delete {
343 // i entries are deleted so it's shifted left i times.
344 fs.args.delete(del - i)
345 }
346 return found_entries
347}
348
349// special parsing for bool values
350// see also: parse_value
351//
352// special: it is allowed to define bool flags without value
353// -> '--flag' is parsed as true
354// -> '--flag' is equal to '--flag=true'
355fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) !string {
356 full := '--${longhand}'
357 for i, arg in fs.args {
358 if arg.len == 0 {
359 continue
360 }
361 if arg[0] != `-` {
362 continue
363 }
364 if (arg.len == 2 && arg[0] == `-` && arg[1] == shorthand) || arg == full {
365 if fs.args.len > i + 1 && fs.args[i + 1] in ['true', 'false'] {
366 val := fs.args[i + 1]
367 fs.args.delete(i + 1)
368 fs.args.delete(i)
369 return val
370 } else {
371 fs.args.delete(i)
372 return 'true'
373 }
374 }
375 if arg.len > full.len + 1 && arg[..full.len + 1] == '${full}=' {
376 // Flag abc=true
377 val := arg[full.len + 1..]
378 fs.args.delete(i)
379 return val
380 }
381 if arg.len > 1 && arg[0] == `-` && arg[1] != `-` {
382 mut found := false
383 for j in 1 .. arg.len {
384 if arg[j].is_space() {
385 break
386 } else if arg[j] == shorthand {
387 found = true
388 }
389 }
390 if found {
391 // -abc is equivalent to -a -b -c
392 fs.args[i] = arg.replace(shorthand.ascii_str(), '') // -abc -> -bc
393 return 'true'
394 }
395 }
396 }
397 return error("parameter '${longhand}' not found")
398}
399
400@[params]
401pub struct FlagConfig {
402pub:
403 val_desc string // descriptive string for an argument
404}
405
406// bool_opt returns an option with the bool value of the given command line flag, named `name`.
407// It returns an error, when the flag is not given by the user.
408// This version supports abbreviations.
409// This version supports a custom value description.
410pub fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string, c FlagConfig) !bool {
411 return fs.bool_flag(name, abbr, usage, c, none)
412}
413
414// bool defines and parses a bool flag/option named `name`.
415// If that flag is given by the user, then it returns its parsed bool value.
416// When it is not, it returns the default value in `bdefault`.
417// This version supports abbreviations.
418// This version supports a custom value description.
419pub fn (mut fs FlagParser) bool(name string, abbr u8, bdefault bool, usage string, c FlagConfig) bool {
420 value := fs.bool_flag(name, abbr, usage, c, flag_default_value(bdefault)) or { return bdefault }
421 return value
422}
423
424// bool_val is a generic version of `bool` that supports optional defaults.
425// Use `?bool(none)` as default to receive an optional result.
426pub fn (mut fs FlagParser) bool_val[T](name string, abbr u8, bdefault T, usage string, c FlagConfig) T {
427 value := fs.bool_flag(name, abbr, usage, c, flag_default_value(bdefault)) or { return bdefault }
428 return value
429}
430
431// int_multi returns all values associated with the provided flag in `name`.
432// When that flag has no values, it returns an empty array.
433// This version supports abbreviations.
434// This version supports a custom value description.
435pub fn (mut fs FlagParser) int_multi(name string, abbr u8, usage string, c FlagConfig) []int {
436 val_desc := flag_value_description(c, '<multiple ints>')
437
438 fs.add_flag(name, abbr, usage, val_desc, none)
439 parsed := fs.parse_value(name, abbr)
440 mut value := []int{}
441 for val in parsed {
442 value << val.int()
443 }
444 return value
445}
446
447// int_opt returns an option with the integer value, associated with the flag in `name`.
448// When the flag is not given by the user, it returns an error.
449// This version supports abbreviations.
450// This version supports a custom value description.
451pub fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string, c FlagConfig) !int {
452 return fs.int_flag(name, abbr, usage, c, none)
453}
454
455// int defines and parses an integer flag, named `name`.
456// When the flag is given by the user, it returns its parsed integer value.
457// When it is not, it returns the integer value in `idefault`.
458// This version supports abbreviations.
459// This version supports a custom value description.
460pub fn (mut fs FlagParser) int(name string, abbr u8, idefault int, usage string, c FlagConfig) int {
461 value := fs.int_flag(name, abbr, usage, c, flag_default_value(idefault)) or { return idefault }
462 return value
463}
464
465// int_val is a generic version of `int` that supports optional defaults.
466// Use `?int(none)` as default to receive an optional result.
467pub fn (mut fs FlagParser) int_val[T](name string, abbr u8, idefault T, usage string, c FlagConfig) T {
468 value := fs.int_flag(name, abbr, usage, c, flag_default_value(idefault)) or { return idefault }
469 return value
470}
471
472// float_multi returns all floating point values, associated with the flag named `name`.
473// When no values for that flag are found, it returns an empty array.
474// This version supports abbreviations.
475// This version supports a custom value description.
476pub fn (mut fs FlagParser) float_multi(name string, abbr u8, usage string, c FlagConfig) []f64 {
477 val_desc := flag_value_description(c, '<multiple floats>')
478
479 fs.add_flag(name, abbr, usage, val_desc, none)
480 parsed := fs.parse_value(name, abbr)
481 mut value := []f64{}
482 for val in parsed {
483 value << val.f64()
484 }
485 return value
486}
487
488// float_opt returns an option with the floating point value, associated with the flag in `name`.
489// When the flag is not given by the user, it returns an error.
490// This version supports abbreviations.
491// This version supports a custom value description.
492pub fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string, c FlagConfig) !f64 {
493 return fs.float_flag(name, abbr, usage, c, none)
494}
495
496// float defines and parses a floating point flag, named `name`.
497// When the flag is given by the user, it returns its parsed floating point value.
498// When it is not, it returns the value in `fdefault`.
499// This version supports abbreviations.
500// This version supports a custom value description.
501pub fn (mut fs FlagParser) float(name string, abbr u8, fdefault f64, usage string, c FlagConfig) f64 {
502 value := fs.float_flag(name, abbr, usage, c, flag_default_value(fdefault)) or {
503 return fdefault
504 }
505 return value
506}
507
508// float_val is a generic version of `float` that supports optional defaults.
509// Use `?f64(none)` as default to receive an optional result.
510pub fn (mut fs FlagParser) float_val[T](name string, abbr u8, fdefault T, usage string, c FlagConfig) T {
511 value := fs.float_flag(name, abbr, usage, c, flag_default_value(fdefault)) or {
512 return fdefault
513 }
514 return value
515}
516
517// string_multi returns all string values, associated with the flag named `name`.
518// When no values for that flag are found, it returns an empty array.
519// This version supports abbreviations.
520// This version supports a custom value description.
521pub fn (mut fs FlagParser) string_multi(name string, abbr u8, usage string, c FlagConfig) []string {
522 val_desc := flag_value_description(c, '<multiple strings>')
523
524 fs.add_flag(name, abbr, usage, val_desc, none)
525 return fs.parse_value(name, abbr)
526}
527
528// string_opt returns an option with the string value, associated with the flag in `name`.
529// When the flag is not given by the user, it returns an error.
530// This version supports abbreviations.
531// This version supports a custom value description.
532pub fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string, c FlagConfig) !string {
533 return fs.string_flag(name, abbr, usage, c, none)
534}
535
536// string defines and parses a string flag/option, named `name`.
537// If that flag is given as an option, then its parsed value is returned as a string.
538// When it is not, it returns the default string value in `sdefault`.
539// This version supports abbreviations.
540// This version supports a custom value description.
541pub fn (mut fs FlagParser) string(name string, abbr u8, sdefault string, usage string, c FlagConfig) string {
542 value := fs.string_flag(name, abbr, usage, c, flag_default_value(sdefault)) or {
543 return sdefault
544 }
545 return value
546}
547
548// string_val is a generic version of `string` that supports optional defaults.
549// Use `?string(none)` as default to receive an optional result.
550pub fn (mut fs FlagParser) string_val[T](name string, abbr u8, sdefault T, usage string, c FlagConfig) T {
551 value := fs.string_flag(name, abbr, usage, c, flag_default_value(sdefault)) or {
552 return sdefault
553 }
554 return value
555}
556
557// limit_free_args_to_at_least restricts the list of free arguments (non options) to be at least `n` in length.
558// If the user gives less free arguments to the program, the parser will return an error.
559pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ! {
560 if n > max_args_number {
561 return error('flag.limit_free_args_to_at_least expect n to be smaller than ${max_args_number}')
562 }
563 if n <= 0 {
564 return error('flag.limit_free_args_to_at_least expect n to be a positive number')
565 }
566 fs.min_free_args = n
567}
568
569// limit_free_args_to_exactly restricts the list of free arguments (non options) to be at exactly `n` in length.
570// If the user gives more or less free arguments to the program, the parser will return an error.
571pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ! {
572 if n > max_args_number {
573 return error('flag.limit_free_args_to_exactly expect n to be smaller than ${max_args_number}')
574 }
575 if n < 0 {
576 return error('flag.limit_free_args_to_exactly expect n to be a non negative number')
577 }
578 fs.min_free_args = n
579 fs.max_free_args = n
580}
581
582// limit_free_args restricts the list of free arguments (non options) to be between `min` and `max` in length.
583// If the user gives more or less free arguments to the program, the parser will return an error.
584pub fn (mut fs FlagParser) limit_free_args(min int, max int) ! {
585 if min > max {
586 return error('flag.limit_free_args expect min < max, got ${min} >= ${max}')
587 }
588 fs.min_free_args = min
589 fs.max_free_args = max
590}
591
592// arguments_description sets the description field of the parser.
593// This field is usually shown when the `--help` option is given to the program.
594pub fn (mut fs FlagParser) arguments_description(description string) {
595 fs.args_description = description
596}
597
598// usage returns a nicely formatted usage screen, containing all the possible options, as well as the description for the program.
599// That screen is usually shown when the `--help` option is given to the program.
600pub fn (fs &FlagParser) usage() string {
601 positive_min_arg := (fs.min_free_args > 0)
602 positive_max_arg := (fs.max_free_args > 0 && fs.max_free_args != max_args_number)
603 no_arguments := (fs.min_free_args == 0 && fs.max_free_args == 0)
604 mut adesc := if fs.args_description.len > 0 { fs.args_description } else { '[ARGS]' }
605 if no_arguments {
606 adesc = ''
607 }
608 mut use := []string{}
609 if doc_add_name_and_version(fs.application_name, fs.application_version, fs.options, mut use) {
610 use << '${underline}'
611 }
612 if fs.usage_examples.len == 0 {
613 use << 'Usage: ${fs.application_name} [options] ${adesc}'
614 } else {
615 for i, example in fs.usage_examples {
616 if i == 0 {
617 use << 'Usage: ${fs.application_name} ${example}'
618 } else {
619 use << ' or: ${fs.application_name} ${example}'
620 }
621 }
622 }
623 use << ''
624 if fs.options.show.has(.description) && fs.application_description != '' {
625 use << 'Description: ${fs.application_description}'
626 use << ''
627 }
628 // show a message about the [ARGS]:
629 if positive_min_arg || positive_max_arg || no_arguments {
630 if no_arguments {
631 use << 'This application does not expect any arguments'
632 use << ''
633 } else {
634 mut s := []string{}
635 if positive_min_arg {
636 s << 'at least ${fs.min_free_args}'
637 }
638 if positive_max_arg {
639 s << 'at most ${fs.max_free_args}'
640 }
641 if positive_min_arg && positive_max_arg && fs.min_free_args == fs.max_free_args {
642 s = ['exactly ${fs.min_free_args}']
643 }
644 sargs := s.join(' and ')
645 use << 'The arguments should be ${sargs} in number.'
646 use << ''
647 }
648 }
649 if fs.options.show.has(.flags) && fs.flags.len > 0 {
650 if fs.options.show.has(.flags_header) {
651 use << fs.options.flag_header.trim_space_left()
652 }
653 for f in fs.flags {
654 mut onames := []string{}
655 if f.abbr != 0 {
656 onames << '-${f.abbr.ascii_str()}'
657 }
658 if f.name != '' {
659 if !f.val_desc.contains('<bool>') {
660 onames << '--${f.name} ${f.val_desc}'
661 } else {
662 onames << '--${f.name}'
663 }
664 }
665 option_names := ' ' + onames.join(', ')
666 mut xspace := ''
667 if option_names.len > space.len - 2 {
668 xspace = '\n${space}'
669 } else {
670 xspace = space[option_names.len..]
671 }
672 mut fusage := f.usage
673 if f.has_default {
674 fusage += ' (default ${f.default_value})'
675 }
676 fdesc := '${option_names}${xspace}${fusage}'
677 use << fdesc
678 }
679 }
680 if fs.options.show.has(.footer) {
681 for footer in fs.footers {
682 use << footer
683 }
684 }
685 return use.join('\n').replace('- ,', ' ')
686}
687
688// find_existing_flag looks up the given flag by name, and returns
689// it, if it was found in the FlagParser. If it was not, it returns an error.
690fn (mut fs FlagParser) find_existing_flag(fname string) !Flag {
691 for f in fs.flags {
692 if f.name == fname {
693 return f
694 }
695 }
696 return error('no such flag')
697}
698
699// handle_builtin_options handles the default behaviour of the very frequently
700// given options: `--help` and `--version`.
701// You can change/customise that, by defining your own options with these names.
702fn (mut fs FlagParser) handle_builtin_options() {
703 mut show_version := false
704 mut show_help := false
705 fs.find_existing_flag('help') or {
706 show_help = fs.bool_opt('help', `h`, fs.default_help_label) or { false }
707 }
708 fs.find_existing_flag('version') or {
709 show_version = fs.bool_opt('version', 0, fs.default_version_label) or { false }
710 }
711 if show_help {
712 println(fs.usage())
713 exit(0)
714 }
715 if show_version {
716 println('${fs.application_name} ${fs.application_version}')
717 exit(0)
718 }
719}
720
721// finalize - return all remaining arguments (non options).
722// Call .finalize() after all arguments are defined.
723// The remaining arguments are returned in the same order they are
724// defined on the command line. If additional flags are found, i.e.
725// (things starting with '--' or '-'), it returns an error.
726pub fn (mut fs FlagParser) finalize() ![]string {
727 fs.handle_builtin_options()
728 mut remaining := fs.args.clone()
729 if !fs.allow_unknown_args {
730 for a in remaining {
731 if (a.len >= 2 && a[..2] == '--') || (a.len == 2 && a[0] == `-`) {
732 return &UnknownFlagError{
733 flag: a
734 }
735 }
736 }
737 }
738 remaining << fs.all_after_dashdash
739 if fs.min_free_args > remaining.len {
740 return &ArgsCountError{
741 want: fs.min_free_args
742 got: remaining.len
743 }
744 }
745 if fs.max_free_args < remaining.len {
746 return &ArgsCountError{
747 want: fs.max_free_args
748 got: remaining.len
749 }
750 }
751 return remaining
752}
753
754// remaining_parameters will return all remaining parameters.
755// Call .remaining_parameters() *AFTER* you have defined all options
756// that your program needs. remaining_parameters will also print any
757// parsing errors and stop the program. Use .finalize() instead, if
758// you want more control over the error handling.
759pub fn (mut fs FlagParser) remaining_parameters() []string {
760 return fs.finalize() or {
761 eprintln(err.msg())
762 println(fs.usage())
763 exit(1)
764 }
765}
766