flag: fix Flag.free(), workaround -autofree limitations

pull/9440/head
Delyan Angelov 2021-03-23 21:28:44 +02:00
parent a593ff930f
commit b335d47b72
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
1 changed files with 116 additions and 63 deletions

View File

@ -10,6 +10,15 @@ pub:
// and also the default value, when the flag is not given // and also the default value, when the flag is not given
} }
[unsafe]
fn (mut f Flag) free() {
unsafe {
f.name.free()
f.usage.free()
f.val_desc.free()
}
}
pub fn (f Flag) str() string { pub fn (f Flag) str() string {
return '' + ' flag:\n' + ' name: $f.name\n' + ' abbr: $f.abbr\n' + return '' + ' flag:\n' + ' name: $f.name\n' + ' abbr: $f.abbr\n' +
' usag: $f.usage\n' + ' desc: $f.val_desc' ' usag: $f.usage\n' + ' desc: $f.val_desc'
@ -41,8 +50,16 @@ pub mut:
[unsafe] [unsafe]
fn (mut f FlagParser) free() { fn (mut f FlagParser) free() {
unsafe { unsafe {
for a in f.args {
a.free()
}
f.args.free() f.args.free()
//
for flag in f.flags {
flag.free()
}
f.flags.free() f.flags.free()
//
f.application_name.free() f.application_name.free()
f.application_version.free() f.application_version.free()
f.application_description.free() f.application_description.free()
@ -105,10 +122,17 @@ fn (mut fs FlagParser) add_flag(name string, abbr byte, usage string, desc strin
// //
// - the name, usage are registered // - the name, usage are registered
// - found arguments and corresponding values are removed from args list // - found arguments and corresponding values are removed from args list
[manualfree]
fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string { fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string {
full := '--$longhand' full := '--$longhand'
defer {
unsafe { full.free() }
}
mut found_entries := []string{} mut found_entries := []string{}
mut to_delete := []int{} mut to_delete := []int{}
defer {
unsafe { to_delete.free() }
}
mut should_skip_one := false mut should_skip_one := false
for i, arg in fs.args { for i, arg in fs.args {
if should_skip_one { if should_skip_one {
@ -127,10 +151,15 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string {
return [] return []
} }
nextarg := fs.args[i + 1] nextarg := fs.args[i + 1]
if nextarg.len > 2 && nextarg[..2] == '--' { if nextarg.len > 2 {
// It could be end of input (--) or another argument (--abc). nextarg_rest := nextarg[..2]
// Both are invalid so die. if nextarg_rest == '--' {
return [] // It could be end of input (--) or another argument (--abc).
// Both are invalid so die.
unsafe { nextarg_rest.free() }
return []
}
unsafe { nextarg_rest.free() }
} }
found_entries << fs.args[i + 1] found_entries << fs.args[i + 1]
to_delete << i to_delete << i
@ -158,39 +187,41 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string {
// -> '--flag' is parsed as true // -> '--flag' is parsed as true
// -> '--flag' is equal to '--flag=true' // -> '--flag' is equal to '--flag=true'
fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand byte) ?string { fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand byte) ?string {
full := '--$longhand' {
for i, arg in fs.args { full := '--$longhand'
if arg == '--' { for i, arg in fs.args {
// End of input. We're done. if arg == '--' {
break // End of input. We're done.
} break
if arg.len == 0 { }
continue if arg.len == 0 {
} continue
if arg[0] != `-` { }
continue if arg[0] != `-` {
} continue
if (arg.len == 2 && arg[0] == `-` && arg[1] == shorthand) || arg == full { }
if fs.args.len > i + 1 && (fs.args[i + 1] in ['true', 'false']) { if (arg.len == 2 && arg[0] == `-` && arg[1] == shorthand) || arg == full {
val := fs.args[i + 1] if fs.args.len > i + 1 && (fs.args[i + 1] in ['true', 'false']) {
fs.args.delete(i + 1) val := fs.args[i + 1]
fs.args.delete(i + 1)
fs.args.delete(i)
return val
} else {
fs.args.delete(i)
return 'true'
}
}
if arg.len > full.len + 1 && arg[..full.len + 1] == '$full=' {
// Flag abc=true
val := arg[full.len + 1..]
fs.args.delete(i) fs.args.delete(i)
return val return val
} else { }
fs.args.delete(i) if arg.len > 1 && arg[0] == `-` && arg[1] != `-` && arg.index_byte(shorthand) != -1 {
// -abc is equivalent to -a -b -c
return 'true' return 'true'
} }
} }
if arg.len > full.len + 1 && arg[..full.len + 1] == '$full=' {
// Flag abc=true
val := arg[full.len + 1..]
fs.args.delete(i)
return val
}
if arg.len > 1 && arg[0] == `-` && arg[1] != `-` && arg.index_byte(shorthand) != -1 {
// -abc is equivalent to -a -b -c
return 'true'
}
} }
return error("parameter '$longhand' not found") return error("parameter '$longhand' not found")
} }
@ -198,9 +229,15 @@ fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand byte) ?string
// bool_opt returns an optional that returns the value associated with the flag. // bool_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (mut fs FlagParser) bool_opt(name string, abbr byte, usage string) ?bool { pub fn (mut fs FlagParser) bool_opt(name string, abbr byte, usage string) ?bool {
fs.add_flag(name, abbr, usage, '<bool>') mut res := false
parsed := fs.parse_bool_value(name, abbr) or { return error("parameter '$name' not provided") } {
return parsed == 'true' fs.add_flag(name, abbr, usage, '<bool>')
parsed := fs.parse_bool_value(name, abbr) or {
return error("parameter '$name' not provided")
}
res = parsed == 'true'
}
return res
} }
// defining and parsing a bool flag // defining and parsing a bool flag
@ -230,12 +267,17 @@ pub fn (mut fs FlagParser) int_multi(name string, abbr byte, usage string) []int
// int_opt returns an optional that returns the value associated with the flag. // int_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (mut fs FlagParser) int_opt(name string, abbr byte, usage string) ?int { pub fn (mut fs FlagParser) int_opt(name string, abbr byte, usage string) ?int {
fs.add_flag(name, abbr, usage, '<int>') mut res := 0
parsed := fs.parse_value(name, abbr) {
if parsed.len == 0 { fs.add_flag(name, abbr, usage, '<int>')
return error("parameter '$name' not provided") parsed := fs.parse_value(name, abbr)
if parsed.len == 0 {
return error("parameter '$name' not provided")
}
parsed0 := parsed[0]
res = parsed0.int()
} }
return parsed[0].int() return res
} }
// defining and parsing an int flag // defining and parsing an int flag
@ -265,12 +307,16 @@ pub fn (mut fs FlagParser) float_multi(name string, abbr byte, usage string) []f
// float_opt returns an optional that returns the value associated with the flag. // float_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (mut fs FlagParser) float_opt(name string, abbr byte, usage string) ?f64 { pub fn (mut fs FlagParser) float_opt(name string, abbr byte, usage string) ?f64 {
fs.add_flag(name, abbr, usage, '<float>') mut res := 0.0
parsed := fs.parse_value(name, abbr) {
if parsed.len == 0 { fs.add_flag(name, abbr, usage, '<float>')
return error("parameter '$name' not provided") parsed := fs.parse_value(name, abbr)
if parsed.len == 0 {
return error("parameter '$name' not provided")
}
res = parsed[0].f64()
} }
return parsed[0].f64() return res
} }
// defining and parsing a float flag // defining and parsing a float flag
@ -295,12 +341,16 @@ pub fn (mut fs FlagParser) string_multi(name string, abbr byte, usage string) []
// string_opt returns an optional that returns the value associated with the flag. // string_opt returns an optional that returns the value associated with the flag.
// In the situation that the flag was not provided, it returns null. // In the situation that the flag was not provided, it returns null.
pub fn (mut fs FlagParser) string_opt(name string, abbr byte, usage string) ?string { pub fn (mut fs FlagParser) string_opt(name string, abbr byte, usage string) ?string {
fs.add_flag(name, abbr, usage, '<string>') mut res := ''
parsed := fs.parse_value(name, abbr) {
if parsed.len == 0 { fs.add_flag(name, abbr, usage, '<string>')
return error("parameter '$name' not provided") parsed := fs.parse_value(name, abbr)
if parsed.len == 0 {
return error("parameter '$name' not provided")
}
res = parsed[0]
} }
return parsed[0] return res
} }
// defining and parsing a string flag // defining and parsing a string flag
@ -358,22 +408,23 @@ pub fn (fs FlagParser) usage() string {
if no_arguments { if no_arguments {
adesc = '' adesc = ''
} }
mut use := '' mut use := []string{}
if fs.application_version != '' { if fs.application_version != '' {
use += '$fs.application_name $fs.application_version\n' use << '$fs.application_name $fs.application_version'
use += '$flag.underline\n' use << '$flag.underline'
} }
use += 'Usage: $fs.application_name [options] $adesc\n' use << 'Usage: $fs.application_name [options] $adesc'
use += '\n' use << ''
if fs.application_description != '' { if fs.application_description != '' {
use += 'Description:\n' use << 'Description: $fs.application_description'
use += '$fs.application_description' use << ''
use += '\n\n' use << ''
} }
// show a message about the [ARGS]: // show a message about the [ARGS]:
if positive_min_arg || positive_max_arg || no_arguments { if positive_min_arg || positive_max_arg || no_arguments {
if no_arguments { if no_arguments {
use += 'This application does not expect any arguments\n\n' use << 'This application does not expect any arguments'
use << ''
} else { } else {
mut s := []string{} mut s := []string{}
if positive_min_arg { if positive_min_arg {
@ -386,11 +437,12 @@ pub fn (fs FlagParser) usage() string {
s = ['exactly $fs.min_free_args'] s = ['exactly $fs.min_free_args']
} }
sargs := s.join(' and ') sargs := s.join(' and ')
use += 'The arguments should be $sargs in number.\n\n' use << 'The arguments should be $sargs in number.'
use << ''
} }
} }
if fs.flags.len > 0 { if fs.flags.len > 0 {
use += 'Options:\n' use << 'Options:'
for f in fs.flags { for f in fs.flags {
mut onames := []string{} mut onames := []string{}
if f.abbr != 0 { if f.abbr != 0 {
@ -410,10 +462,11 @@ pub fn (fs FlagParser) usage() string {
} else { } else {
xspace = flag.space[option_names.len..] xspace = flag.space[option_names.len..]
} }
use += '$option_names$xspace$f.usage\n' fdesc := '$option_names$xspace$f.usage'
use << fdesc
} }
} }
return use.replace('- ,', ' ') return use.join('\n').replace('- ,', ' ')
} }
// finalize - return all remaining arguments (non options). // finalize - return all remaining arguments (non options).