From b335d47b72e0ea4c5b9b0152e0ef4a3a67266b23 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 23 Mar 2021 21:28:44 +0200 Subject: [PATCH] flag: fix Flag.free(), workaround -autofree limitations --- vlib/flag/flag.v | 179 ++++++++++++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 63 deletions(-) diff --git a/vlib/flag/flag.v b/vlib/flag/flag.v index a2cda98dfe..08329e4a85 100644 --- a/vlib/flag/flag.v +++ b/vlib/flag/flag.v @@ -10,6 +10,15 @@ pub: // 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 { return '' + ' flag:\n' + ' name: $f.name\n' + ' abbr: $f.abbr\n' + ' usag: $f.usage\n' + ' desc: $f.val_desc' @@ -41,8 +50,16 @@ pub mut: [unsafe] fn (mut f FlagParser) free() { unsafe { + for a in f.args { + a.free() + } f.args.free() + // + for flag in f.flags { + flag.free() + } f.flags.free() + // f.application_name.free() f.application_version.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 // - found arguments and corresponding values are removed from args list +[manualfree] fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string { full := '--$longhand' + defer { + unsafe { full.free() } + } mut found_entries := []string{} mut to_delete := []int{} + defer { + unsafe { to_delete.free() } + } mut should_skip_one := false for i, arg in fs.args { if should_skip_one { @@ -127,10 +151,15 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand byte) []string { return [] } nextarg := fs.args[i + 1] - if nextarg.len > 2 && nextarg[..2] == '--' { - // It could be end of input (--) or another argument (--abc). - // Both are invalid so die. - return [] + if nextarg.len > 2 { + nextarg_rest := nextarg[..2] + if nextarg_rest == '--' { + // 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] 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 equal to '--flag=true' fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand byte) ?string { - full := '--$longhand' - for i, arg in fs.args { - if arg == '--' { - // End of input. We're done. - break - } - if arg.len == 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']) { - val := fs.args[i + 1] - fs.args.delete(i + 1) + { + full := '--$longhand' + for i, arg in fs.args { + if arg == '--' { + // End of input. We're done. + break + } + if arg.len == 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']) { + 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) 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' } } - 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") } @@ -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. // 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 { - fs.add_flag(name, abbr, usage, '') - parsed := fs.parse_bool_value(name, abbr) or { return error("parameter '$name' not provided") } - return parsed == 'true' + mut res := false + { + fs.add_flag(name, abbr, usage, '') + 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 @@ -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. // 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 { - fs.add_flag(name, abbr, usage, '') - parsed := fs.parse_value(name, abbr) - if parsed.len == 0 { - return error("parameter '$name' not provided") + mut res := 0 + { + fs.add_flag(name, abbr, usage, '') + 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 @@ -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. // 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 { - fs.add_flag(name, abbr, usage, '') - parsed := fs.parse_value(name, abbr) - if parsed.len == 0 { - return error("parameter '$name' not provided") + mut res := 0.0 + { + fs.add_flag(name, abbr, usage, '') + 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 @@ -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. // 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 { - fs.add_flag(name, abbr, usage, '') - parsed := fs.parse_value(name, abbr) - if parsed.len == 0 { - return error("parameter '$name' not provided") + mut res := '' + { + fs.add_flag(name, abbr, usage, '') + 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 @@ -358,22 +408,23 @@ pub fn (fs FlagParser) usage() string { if no_arguments { adesc = '' } - mut use := '' + mut use := []string{} if fs.application_version != '' { - use += '$fs.application_name $fs.application_version\n' - use += '$flag.underline\n' + use << '$fs.application_name $fs.application_version' + use << '$flag.underline' } - use += 'Usage: $fs.application_name [options] $adesc\n' - use += '\n' + use << 'Usage: $fs.application_name [options] $adesc' + use << '' if fs.application_description != '' { - use += 'Description:\n' - use += '$fs.application_description' - use += '\n\n' + use << 'Description: $fs.application_description' + use << '' + use << '' } // show a message about the [ARGS]: if positive_min_arg || positive_max_arg || 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 { mut s := []string{} if positive_min_arg { @@ -386,11 +437,12 @@ pub fn (fs FlagParser) usage() string { s = ['exactly $fs.min_free_args'] } 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 { - use += 'Options:\n' + use << 'Options:' for f in fs.flags { mut onames := []string{} if f.abbr != 0 { @@ -410,10 +462,11 @@ pub fn (fs FlagParser) usage() string { } else { 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).