From 13230cdda0c2565c7f501e2f29c9871b11ca84f5 Mon Sep 17 00:00:00 2001 From: Verte Date: Wed, 17 Apr 2024 11:10:18 -0700 Subject: [PATCH] Rewrite wgetopt.rs to Rustier syntax and naming From https://github.com/fish-shell/fish-shell/pull/9515 Closes #9515 --- src/bin/fish.rs | 54 +-- src/bin/fish_indent.rs | 46 +- src/bin/fish_key_reader.rs | 20 +- src/builtins/abbr.rs | 40 +- src/builtins/argparse.rs | 86 ++-- src/builtins/bind.rs | 38 +- src/builtins/block.rs | 22 +- src/builtins/builtin.rs | 20 +- src/builtins/command.rs | 22 +- src/builtins/commandline.rs | 72 ++- src/builtins/complete.rs | 80 ++-- src/builtins/contains.rs | 18 +- src/builtins/echo.rs | 18 +- src/builtins/function.rs | 42 +- src/builtins/functions.rs | 38 +- src/builtins/history.rs | 46 +- src/builtins/jobs.rs | 32 +- src/builtins/math.rs | 18 +- src/builtins/mod.rs | 6 +- src/builtins/path.rs | 36 +- src/builtins/pwd.rs | 18 +- src/builtins/random.rs | 16 +- src/builtins/read.rs | 58 ++- src/builtins/realpath.rs | 18 +- src/builtins/return.rs | 14 +- src/builtins/set.rs | 46 +- src/builtins/set_color.rs | 40 +- src/builtins/shared.rs | 20 +- src/builtins/status.rs | 48 +- src/builtins/string.rs | 20 +- src/builtins/string/collect.rs | 6 +- src/builtins/string/escape.rs | 8 +- src/builtins/string/join.rs | 6 +- src/builtins/string/length.rs | 6 +- src/builtins/string/match.rs | 18 +- src/builtins/string/pad.rs | 8 +- src/builtins/string/repeat.rs | 10 +- src/builtins/string/replace.rs | 12 +- src/builtins/string/shorten.rs | 12 +- src/builtins/string/split.rs | 14 +- src/builtins/string/sub.rs | 10 +- src/builtins/string/transform.rs | 2 +- src/builtins/string/trim.rs | 10 +- src/builtins/string/unescape.rs | 8 +- src/builtins/type.rs | 30 +- src/builtins/ulimit.rs | 90 ++-- src/builtins/wait.rs | 18 +- src/tests/wgetopt.rs | 10 +- src/wgetopt.rs | 787 ++++++++++++++----------------- 49 files changed, 1005 insertions(+), 1112 deletions(-) diff --git a/src/bin/fish.rs b/src/bin/fish.rs index ae3c85079..61fd05cee 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -313,44 +313,40 @@ fn run_command_list(parser: &Parser, cmds: &[OsString]) -> i32 { } fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> ControlFlow { - use fish::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t::*}; + use fish::wgetopt::{wopt, ArgType::*, WGetopter, WOption}; const RUSAGE_ARG: char = 1 as char; const PRINT_DEBUG_CATEGORIES_ARG: char = 2 as char; const PROFILE_STARTUP_ARG: char = 3 as char; const SHORT_OPTS: &wstr = L!("+hPilNnvc:C:p:d:f:D:o:"); - const LONG_OPTS: &[woption<'static>] = &[ - wopt(L!("command"), required_argument, 'c'), - wopt(L!("init-command"), required_argument, 'C'), - wopt(L!("features"), required_argument, 'f'), - wopt(L!("debug"), required_argument, 'd'), - wopt(L!("debug-output"), required_argument, 'o'), - wopt(L!("debug-stack-frames"), required_argument, 'D'), - wopt(L!("interactive"), no_argument, 'i'), - wopt(L!("login"), no_argument, 'l'), - wopt(L!("no-config"), no_argument, 'N'), - wopt(L!("no-execute"), no_argument, 'n'), - wopt(L!("print-rusage-self"), no_argument, RUSAGE_ARG), + const LONG_OPTS: &[WOption<'static>] = &[ + wopt(L!("command"), RequiredArgument, 'c'), + wopt(L!("init-command"), RequiredArgument, 'C'), + wopt(L!("features"), RequiredArgument, 'f'), + wopt(L!("debug"), RequiredArgument, 'd'), + wopt(L!("debug-output"), RequiredArgument, 'o'), + wopt(L!("debug-stack-frames"), RequiredArgument, 'D'), + wopt(L!("interactive"), NoArgument, 'i'), + wopt(L!("login"), NoArgument, 'l'), + wopt(L!("no-config"), NoArgument, 'N'), + wopt(L!("no-execute"), NoArgument, 'n'), + wopt(L!("print-rusage-self"), NoArgument, RUSAGE_ARG), wopt( L!("print-debug-categories"), - no_argument, + NoArgument, PRINT_DEBUG_CATEGORIES_ARG, ), - wopt(L!("profile"), required_argument, 'p'), - wopt( - L!("profile-startup"), - required_argument, - PROFILE_STARTUP_ARG, - ), - wopt(L!("private"), no_argument, 'P'), - wopt(L!("help"), no_argument, 'h'), - wopt(L!("version"), no_argument, 'v'), + wopt(L!("profile"), RequiredArgument, 'p'), + wopt(L!("profile-startup"), RequiredArgument, PROFILE_STARTUP_ARG), + wopt(L!("private"), NoArgument, 'P'), + wopt(L!("help"), NoArgument, 'h'), + wopt(L!("version"), NoArgument, 'v'), ]; let mut shim_args: Vec<&wstr> = args.iter().map(|s| s.as_ref()).collect(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, &mut shim_args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, &mut shim_args); + while let Some(c) = w.next_opt() { match c { 'c' => opts .batch_cmds @@ -419,21 +415,21 @@ fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> ControlFlow { eprintln!( "{}", - wgettext_fmt!(BUILTIN_ERR_UNKNOWN, "fish", args[w.woptind - 1]) + wgettext_fmt!(BUILTIN_ERR_UNKNOWN, "fish", args[w.wopt_index - 1]) ); return ControlFlow::Break(1); } ':' => { eprintln!( "{}", - wgettext_fmt!(BUILTIN_ERR_MISSING, "fish", args[w.woptind - 1]) + wgettext_fmt!(BUILTIN_ERR_MISSING, "fish", args[w.wopt_index - 1]) ); return ControlFlow::Break(1); } - _ => panic!("unexpected retval from wgetopter_t"), + _ => panic!("unexpected retval from WGetopter"), } } - let optind = w.woptind; + let optind = w.wopt_index; // If our command name begins with a dash that implies we're a login shell. opts.is_login |= args[0].char_at(0) == '-'; diff --git a/src/bin/fish_indent.rs b/src/bin/fish_indent.rs index 282a0eb41..87bc41b47 100644 --- a/src/bin/fish_indent.rs +++ b/src/bin/fish_indent.rs @@ -44,7 +44,7 @@ use fish::tokenizer::{TokenType, Tokenizer, TOK_SHOW_BLANK_LINES, TOK_SHOW_COMME use fish::topic_monitor::topic_monitor_init; use fish::wchar::prelude::*; use fish::wcstringutil::count_preceding_backslashes; -use fish::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t}; +use fish::wgetopt::{wopt, ArgType, WGetopter, WOption}; use fish::wutil::perror; use fish::wutil::{fish_iswalnum, write_to_fd}; use fish::{ @@ -779,38 +779,30 @@ fn throwing_main() -> i32 { let mut debug_output = None; let short_opts: &wstr = L!("+d:hvwicD:"); - let long_opts: &[woption] = &[ - wopt(L!("debug"), woption_argument_t::required_argument, 'd'), - wopt( - L!("debug-output"), - woption_argument_t::required_argument, - 'o', - ), - wopt( - L!("debug-stack-frames"), - woption_argument_t::required_argument, - 'D', - ), - wopt(L!("dump-parse-tree"), woption_argument_t::no_argument, 'P'), - wopt(L!("no-indent"), woption_argument_t::no_argument, 'i'), - wopt(L!("only-indent"), woption_argument_t::no_argument, '\x04'), - wopt(L!("only-unindent"), woption_argument_t::no_argument, '\x05'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("version"), woption_argument_t::no_argument, 'v'), - wopt(L!("write"), woption_argument_t::no_argument, 'w'), - wopt(L!("html"), woption_argument_t::no_argument, '\x01'), - wopt(L!("ansi"), woption_argument_t::no_argument, '\x02'), - wopt(L!("pygments"), woption_argument_t::no_argument, '\x03'), - wopt(L!("check"), woption_argument_t::no_argument, 'c'), + let long_opts: &[WOption] = &[ + wopt(L!("debug"), ArgType::RequiredArgument, 'd'), + wopt(L!("debug-output"), ArgType::RequiredArgument, 'o'), + wopt(L!("debug-stack-frames"), ArgType::RequiredArgument, 'D'), + wopt(L!("dump-parse-tree"), ArgType::NoArgument, 'P'), + wopt(L!("no-indent"), ArgType::NoArgument, 'i'), + wopt(L!("only-indent"), ArgType::NoArgument, '\x04'), + wopt(L!("only-unindent"), ArgType::NoArgument, '\x05'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("version"), ArgType::NoArgument, 'v'), + wopt(L!("write"), ArgType::NoArgument, 'w'), + wopt(L!("html"), ArgType::NoArgument, '\x01'), + wopt(L!("ansi"), ArgType::NoArgument, '\x02'), + wopt(L!("pygments"), ArgType::NoArgument, '\x03'), + wopt(L!("check"), ArgType::NoArgument, 'c'), ]; let args: Vec = std::env::args_os() .map(|osstr| str2wcstring(osstr.as_bytes())) .collect(); let mut shim_args: Vec<&wstr> = args.iter().map(|s| s.as_ref()).collect(); - let mut w = wgetopter_t::new(short_opts, long_opts, &mut shim_args); + let mut w = WGetopter::new(short_opts, long_opts, &mut shim_args); - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 'P' => DUMP_PARSE_TREE.store(true), 'h' => { @@ -855,7 +847,7 @@ fn throwing_main() -> i32 { } } - let args = &w.argv[w.woptind..]; + let args = &w.argv[w.wopt_index..]; // Direct any debug output right away. if let Some(debug_output) = debug_output { diff --git a/src/bin/fish_key_reader.rs b/src/bin/fish_key_reader.rs index ce124ce5e..3422e4b9e 100644 --- a/src/bin/fish_key_reader.rs +++ b/src/bin/fish_key_reader.rs @@ -30,7 +30,7 @@ use fish::{ threads, topic_monitor::topic_monitor_init, wchar::prelude::*, - wgetopt::{wgetopter_t, wopt, woption, woption_argument_t}, + wgetopt::{wopt, ArgType, WGetopter, WOption}, }; /// Return true if the recent sequence of characters indicates the user wants to exit the program. @@ -145,19 +145,19 @@ fn setup_and_process_keys(continuous_mode: bool) -> i32 { fn parse_flags(continuous_mode: &mut bool) -> ControlFlow { let short_opts: &wstr = L!("+chvV"); - let long_opts: &[woption] = &[ - wopt(L!("continuous"), woption_argument_t::no_argument, 'c'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("version"), woption_argument_t::no_argument, 'v'), - wopt(L!("verbose"), woption_argument_t::no_argument, 'V'), // Removed + let long_opts: &[WOption] = &[ + wopt(L!("continuous"), ArgType::NoArgument, 'c'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("version"), ArgType::NoArgument, 'v'), + wopt(L!("verbose"), ArgType::NoArgument, 'V'), // Removed ]; let args: Vec = std::env::args_os() .map(|osstr| str2wcstring(osstr.as_bytes())) .collect(); let mut shim_args: Vec<&wstr> = args.iter().map(|s| s.as_ref()).collect(); - let mut w = wgetopter_t::new(short_opts, long_opts, &mut shim_args); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(short_opts, long_opts, &mut shim_args); + while let Some(opt) = w.next_opt() { match opt { 'c' => { *continuous_mode = true; @@ -184,7 +184,7 @@ fn parse_flags(continuous_mode: &mut bool) -> ControlFlow { wgettext_fmt!( BUILTIN_ERR_UNKNOWN, "fish_key_reader", - w.argv[w.woptind - 1] + w.argv[w.wopt_index - 1] ) ); return ControlFlow::Break(1); @@ -193,7 +193,7 @@ fn parse_flags(continuous_mode: &mut bool) -> ControlFlow { } } - let argc = args.len() - w.woptind; + let argc = args.len() - w.wopt_index; if argc != 0 { eprintf!("Expected no arguments, got %d\n", argc); return ControlFlow::Break(1); diff --git a/src/builtins/abbr.rs b/src/builtins/abbr.rs index acf7360b1..8e33f2633 100644 --- a/src/builtins/abbr.rs +++ b/src/builtins/abbr.rs @@ -435,30 +435,30 @@ pub fn abbr(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt // could be given literally, for example `abbr e emacs -nw`. const short_options: &wstr = L!("-:af:r:seqgUh"); - const longopts: &[woption] = &[ - wopt(L!("add"), woption_argument_t::no_argument, 'a'), - wopt(L!("position"), woption_argument_t::required_argument, 'p'), - wopt(L!("regex"), woption_argument_t::required_argument, 'r'), + const longopts: &[WOption] = &[ + wopt(L!("add"), ArgType::NoArgument, 'a'), + wopt(L!("position"), ArgType::RequiredArgument, 'p'), + wopt(L!("regex"), ArgType::RequiredArgument, 'r'), wopt( L!("set-cursor"), - woption_argument_t::optional_argument, + ArgType::OptionalArgument, SET_CURSOR_SHORT, ), - wopt(L!("function"), woption_argument_t::required_argument, 'f'), - wopt(L!("rename"), woption_argument_t::no_argument, RENAME_SHORT), - wopt(L!("erase"), woption_argument_t::no_argument, 'e'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), - wopt(L!("show"), woption_argument_t::no_argument, 's'), - wopt(L!("list"), woption_argument_t::no_argument, 'l'), - wopt(L!("global"), woption_argument_t::no_argument, 'g'), - wopt(L!("universal"), woption_argument_t::no_argument, 'U'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), + wopt(L!("function"), ArgType::RequiredArgument, 'f'), + wopt(L!("rename"), ArgType::NoArgument, RENAME_SHORT), + wopt(L!("erase"), ArgType::NoArgument, 'e'), + wopt(L!("query"), ArgType::NoArgument, 'q'), + wopt(L!("show"), ArgType::NoArgument, 's'), + wopt(L!("list"), ArgType::NoArgument, 'l'), + wopt(L!("global"), ArgType::NoArgument, 'g'), + wopt(L!("universal"), ArgType::NoArgument, 'U'), + wopt(L!("help"), ArgType::NoArgument, 'h'), ]; let mut opts = Options::default(); - let mut w = wgetopter_t::new(short_options, longopts, argv); + let mut w = WGetopter::new(short_options, longopts, argv); - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { NON_OPTION_ARGUMENT => { // If --add is specified (or implied by specifying no other commands), all @@ -538,7 +538,7 @@ pub fn abbr(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt streams.err.append(wgettext_fmt!( "%ls: Warning: Option '%ls' was removed and is now ignored", cmd, - argv_read[w.woptind - 1] + argv_read[w.wopt_index - 1] )); builtin_print_error_trailer(parser, streams.err, cmd); } @@ -547,11 +547,11 @@ pub fn abbr(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } _ => { @@ -560,7 +560,7 @@ pub fn abbr(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt } } - for arg in argv_read[w.woptind..].iter() { + for arg in argv_read[w.wopt_index..].iter() { opts.args.push((*arg).into()); } diff --git a/src/builtins/argparse.rs b/src/builtins/argparse.rs index 564c4c3f5..ef654cb0e 100644 --- a/src/builtins/argparse.rs +++ b/src/builtins/argparse.rs @@ -72,14 +72,14 @@ impl ArgParseCmdOpts<'_> { } const SHORT_OPTIONS: &wstr = L!("+:hn:six:N:X:"); -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("stop-nonopt"), woption_argument_t::no_argument, 's'), - wopt(L!("ignore-unknown"), woption_argument_t::no_argument, 'i'), - wopt(L!("name"), woption_argument_t::required_argument, 'n'), - wopt(L!("exclusive"), woption_argument_t::required_argument, 'x'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("min-args"), woption_argument_t::required_argument, 'N'), - wopt(L!("max-args"), woption_argument_t::required_argument, 'X'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("stop-nonopt"), ArgType::NoArgument, 's'), + wopt(L!("ignore-unknown"), ArgType::NoArgument, 'i'), + wopt(L!("name"), ArgType::RequiredArgument, 'n'), + wopt(L!("exclusive"), ArgType::RequiredArgument, 'x'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("min-args"), ArgType::RequiredArgument, 'N'), + wopt(L!("max-args"), ArgType::RequiredArgument, 'X'), ]; // Check if any pair of mutually exclusive options was seen. Note that since every option must have @@ -485,8 +485,8 @@ fn parse_cmd_opts<'args>( let mut args_read = Vec::with_capacity(args.len()); args_read.extend_from_slice(args); - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, args); + while let Some(c) = w.next_opt() { match c { 'n' => opts.name = w.woptarg.unwrap().to_owned(), 's' => opts.stop_nonopt = true, @@ -528,16 +528,16 @@ fn parse_cmd_opts<'args>( parser, streams, cmd, - args[w.woptind - 1], + args[w.wopt_index - 1], /* print_hints */ false, ); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from next_opt"), } } @@ -545,11 +545,11 @@ fn parse_cmd_opts<'args>( return STATUS_CMD_OK; } - if "--" == args_read[w.woptind - 1] { - w.woptind -= 1; + if "--" == args_read[w.wopt_index - 1] { + w.wopt_index -= 1; } - if argc == w.woptind { + if argc == w.wopt_index { // The user didn't specify any option specs. streams .err @@ -565,14 +565,14 @@ fn parse_cmd_opts<'args>( .unwrap_or_else(|| L!("argparse").to_owned()); } - *optind = w.woptind; + *optind = w.wopt_index; return collect_option_specs(opts, optind, argc, args, streams); } fn populate_option_strings<'args>( opts: &ArgParseCmdOpts<'args>, short_options: &mut WString, - long_options: &mut Vec>, + long_options: &mut Vec>, ) { for opt_spec in opts.options.values() { if opt_spec.short_flag_valid { @@ -584,15 +584,15 @@ fn populate_option_strings<'args>( if opt_spec.short_flag_valid { short_options.push_str("::"); } - woption_argument_t::optional_argument + ArgType::OptionalArgument } ArgCardinality::Once | ArgCardinality::AtLeastOnce => { if opt_spec.short_flag_valid { short_options.push_str(":"); } - woption_argument_t::required_argument + ArgType::RequiredArgument } - ArgCardinality::None => woption_argument_t::no_argument, + ArgCardinality::None => ArgType::NoArgument, }; if !opt_spec.long_flag.is_empty() { @@ -668,7 +668,7 @@ fn validate_and_store_implicit_int<'args>( parser: &Parser, opts: &mut ArgParseCmdOpts<'args>, val: &'args wstr, - w: &mut wgetopter_t, + w: &mut WGetopter, is_long_flag: bool, streams: &mut IoStreams, ) -> Option { @@ -683,7 +683,7 @@ fn validate_and_store_implicit_int<'args>( opt_spec.vals.clear(); opt_spec.vals.push(val.into()); opt_spec.num_seen += 1; - w.nextchar = L!(""); + w.remaining_text = L!(""); return STATUS_CMD_OK; } @@ -721,7 +721,7 @@ fn handle_flag<'args>( match opt_spec.num_allowed { ArgCardinality::Optional | ArgCardinality::Once => { - // We're depending on `wgetopt_long()` to report that a mandatory value is missing if + // We're depending on `next_opt()` to report that a mandatory value is missing if // `opt_spec->num_allowed == 1` and thus return ':' so that we don't take this branch if // the mandatory arg is missing. opt_spec.vals.clear(); @@ -754,23 +754,23 @@ fn argparse_parse_flags<'args>( let mut long_options = vec![]; populate_option_strings(opts, &mut short_options, &mut long_options); - let mut long_idx: usize = usize::MAX; - let mut w = wgetopter_t::new(&short_options, &long_options, args); - while let Some(opt) = w.wgetopt_long_idx(&mut long_idx) { + let mut w = WGetopter::new(&short_options, &long_options, args); + while let Some((opt, longopt_idx)) = w.next_opt_indexed() { + let is_long_flag = longopt_idx.is_some(); let retval = match opt { ':' => { builtin_missing_argument( parser, streams, &opts.name, - args_read[w.woptind - 1], + args_read[w.wopt_index - 1], false, ); STATUS_INVALID_ARGS } '?' => { // It's not a recognized flag. See if it's an implicit int flag. - let arg_contents = &args_read[w.woptind - 1].slice_from(1); + let arg_contents = &args_read[w.wopt_index - 1].slice_from(1); if is_implicit_int(opts, arg_contents) { validate_and_store_implicit_int( @@ -778,61 +778,53 @@ fn argparse_parse_flags<'args>( opts, arg_contents, &mut w, - long_idx != usize::MAX, + is_long_flag, streams, ) } else if !opts.ignore_unknown { streams.err.append(wgettext_fmt!( BUILTIN_ERR_UNKNOWN, opts.name, - args_read[w.woptind - 1] + args_read[w.wopt_index - 1] )); STATUS_INVALID_ARGS } else { // Any unrecognized option is put back if ignore_unknown is used. // This allows reusing the same argv in multiple argparse calls, // or just ignoring the error (e.g. in completions). - opts.args.push(args_read[w.woptind - 1]); + opts.args.push(args_read[w.wopt_index - 1]); // Work around weirdness with wgetopt, which crashes if we `continue` here. - if w.woptind == argc { + if w.wopt_index == argc { break; } // Explain to wgetopt that we want to skip to the next arg, // because we can't handle this opt group. - w.nextchar = L!(""); + w.remaining_text = L!(""); STATUS_CMD_OK } } - NONOPTION_CHAR_CODE => { + NON_OPTION_CHAR => { // A non-option argument. // We use `-` as the first option-string-char to disable GNU getopt's reordering, // otherwise we'd get ignored options first and normal arguments later. // E.g. `argparse -i -- -t tango -w` needs to keep `-t tango -w` in $argv, not `-t -w // tango`. - opts.args.push(args_read[w.woptind - 1]); + opts.args.push(args_read[w.wopt_index - 1]); continue; } // It's a recognized flag. - _ => handle_flag( - parser, - opts, - opt, - long_idx != usize::MAX, - w.woptarg, - streams, - ), + _ => handle_flag(parser, opts, opt, is_long_flag, w.woptarg, streams), }; if retval != STATUS_CMD_OK { return retval; } - long_idx = usize::MAX; } - *optind = w.woptind; + *optind = w.wopt_index; return STATUS_CMD_OK; } -// This function mimics the `wgetopt_long()` usage found elsewhere in our other builtin commands. +// This function mimics the `next_opt()` usage found elsewhere in our other builtin commands. // It's different in that the short and long option structures are constructed dynamically based on // arguments provided to the `argparse` command. fn argparse_parse_args<'args>( diff --git a/src/builtins/bind.rs b/src/builtins/bind.rs index 68a75922d..5be6aebd0 100644 --- a/src/builtins/bind.rs +++ b/src/builtins/bind.rs @@ -451,23 +451,23 @@ fn parse_cmd_opts( ) -> Option { let cmd = argv[0]; let short_options = L!(":aehkKfM:Lm:s"); - const long_options: &[woption] = &[ - wopt(L!("all"), no_argument, 'a'), - wopt(L!("erase"), no_argument, 'e'), - wopt(L!("function-names"), no_argument, 'f'), - wopt(L!("help"), no_argument, 'h'), - wopt(L!("key"), no_argument, 'k'), - wopt(L!("key-names"), no_argument, 'K'), - wopt(L!("list-modes"), no_argument, 'L'), - wopt(L!("mode"), required_argument, 'M'), - wopt(L!("preset"), no_argument, 'p'), - wopt(L!("sets-mode"), required_argument, 'm'), - wopt(L!("silent"), no_argument, 's'), - wopt(L!("user"), no_argument, 'u'), + const long_options: &[WOption] = &[ + wopt(L!("all"), NoArgument, 'a'), + wopt(L!("erase"), NoArgument, 'e'), + wopt(L!("function-names"), NoArgument, 'f'), + wopt(L!("help"), NoArgument, 'h'), + wopt(L!("key"), NoArgument, 'k'), + wopt(L!("key-names"), NoArgument, 'K'), + wopt(L!("list-modes"), NoArgument, 'L'), + wopt(L!("mode"), RequiredArgument, 'M'), + wopt(L!("preset"), NoArgument, 'p'), + wopt(L!("sets-mode"), RequiredArgument, 'm'), + wopt(L!("silent"), NoArgument, 's'), + wopt(L!("user"), NoArgument, 'u'), ]; - let mut w = wgetopter_t::new(short_options, long_options, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(short_options, long_options, argv); + while let Some(c) = w.next_opt() { match c { 'a' => opts.all = true, 'e' => opts.mode = BIND_ERASE, @@ -511,19 +511,19 @@ fn parse_cmd_opts( opts.user = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } _ => { - panic!("unexpected retval from wgetopt_long") + panic!("unexpected retval from WGetopter") } } } - *optind = w.woptind; + *optind = w.wopt_index; return STATUS_CMD_OK; } diff --git a/src/builtins/block.rs b/src/builtins/block.rs index 10348e8a6..3d3071af1 100644 --- a/src/builtins/block.rs +++ b/src/builtins/block.rs @@ -31,17 +31,17 @@ fn parse_options( let cmd = args[0]; const SHORT_OPTS: &wstr = L!(":eghl"); - const LONG_OPTS: &[woption] = &[ - wopt(L!("erase"), woption_argument_t::no_argument, 'e'), - wopt(L!("local"), woption_argument_t::no_argument, 'l'), - wopt(L!("global"), woption_argument_t::no_argument, 'g'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), + const LONG_OPTS: &[WOption] = &[ + wopt(L!("erase"), ArgType::NoArgument, 'e'), + wopt(L!("local"), ArgType::NoArgument, 'l'), + wopt(L!("global"), ArgType::NoArgument, 'g'), + wopt(L!("help"), ArgType::NoArgument, 'h'), ]; let mut opts = Options::default(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); + while let Some(c) = w.next_opt() { match c { 'h' => { opts.print_help = true; @@ -56,20 +56,20 @@ fn parse_options( opts.erase = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// The block builtin, used for temporarily blocking events. diff --git a/src/builtins/builtin.rs b/src/builtins/builtin.rs index 7dfe55223..322e9c0f1 100644 --- a/src/builtins/builtin.rs +++ b/src/builtins/builtin.rs @@ -13,14 +13,14 @@ pub fn r#builtin(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - let mut opts: builtin_cmd_opts_t = Default::default(); const shortopts: &wstr = L!(":hnq"); - const longopts: &[woption] = &[ - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("names"), woption_argument_t::no_argument, 'n'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), + const longopts: &[WOption] = &[ + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("names"), ArgType::NoArgument, 'n'), + wopt(L!("query"), ArgType::NoArgument, 'q'), ]; - let mut w = wgetopter_t::new(shortopts, longopts, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(shortopts, longopts, argv); + while let Some(c) = w.next_opt() { match c { 'q' => opts.query = true, 'n' => opts.list_names = true, @@ -29,15 +29,15 @@ pub fn r#builtin(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } _ => { - panic!("unexpected retval from wgeopter.next()"); + panic!("unexpected retval from WGetopter"); } } } @@ -60,7 +60,7 @@ pub fn r#builtin(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - } if opts.query { - let optind = w.woptind; + let optind = w.wopt_index; for arg in argv.iter().take(argc).skip(optind) { if builtin_exists(arg) { return STATUS_CMD_OK; diff --git a/src/builtins/command.rs b/src/builtins/command.rs index d237204d8..cd579c1c2 100644 --- a/src/builtins/command.rs +++ b/src/builtins/command.rs @@ -15,16 +15,16 @@ pub fn r#command(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - let mut opts: command_cmd_opts_t = Default::default(); const shortopts: &wstr = L!(":hasqv"); - const longopts: &[woption] = &[ - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("all"), woption_argument_t::no_argument, 'a'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), - wopt(L!("quiet"), woption_argument_t::no_argument, 'q'), - wopt(L!("search"), woption_argument_t::no_argument, 's'), + const longopts: &[WOption] = &[ + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("all"), ArgType::NoArgument, 'a'), + wopt(L!("query"), ArgType::NoArgument, 'q'), + wopt(L!("quiet"), ArgType::NoArgument, 'q'), + wopt(L!("search"), ArgType::NoArgument, 's'), ]; - let mut w = wgetopter_t::new(shortopts, longopts, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(shortopts, longopts, argv); + while let Some(c) = w.next_opt() { match c { 'a' => opts.all = true, 'q' => opts.quiet = true, @@ -36,11 +36,11 @@ pub fn r#command(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } _ => { @@ -56,7 +56,7 @@ pub fn r#command(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - } let mut res = false; - let optind = w.woptind; + let optind = w.wopt_index; for arg in argv.iter().take(argc).skip(optind) { let paths = if opts.all { path_get_paths(arg, parser.vars()) diff --git a/src/builtins/commandline.rs b/src/builtins/commandline.rs index bda10b41f..1d9d6278c 100644 --- a/src/builtins/commandline.rs +++ b/src/builtins/commandline.rs @@ -206,40 +206,36 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) let mut override_buffer = None; const short_options: &wstr = L!(":abijpctfxorhI:CBELSsP"); - let long_options: &[woption] = &[ - wopt(L!("append"), woption_argument_t::no_argument, 'a'), - wopt(L!("insert"), woption_argument_t::no_argument, 'i'), - wopt(L!("replace"), woption_argument_t::no_argument, 'r'), - wopt(L!("current-buffer"), woption_argument_t::no_argument, 'b'), - wopt(L!("current-job"), woption_argument_t::no_argument, 'j'), - wopt(L!("current-process"), woption_argument_t::no_argument, 'p'), - wopt( - L!("current-selection"), - woption_argument_t::no_argument, - 's', - ), - wopt(L!("current-token"), woption_argument_t::no_argument, 't'), - wopt(L!("cut-at-cursor"), woption_argument_t::no_argument, 'c'), - wopt(L!("function"), woption_argument_t::no_argument, 'f'), - wopt(L!("tokens-expanded"), woption_argument_t::no_argument, 'x'), - wopt(L!("tokens-raw"), woption_argument_t::no_argument, '\x02'), - wopt(L!("tokenize"), woption_argument_t::no_argument, 'o'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("input"), woption_argument_t::required_argument, 'I'), - wopt(L!("cursor"), woption_argument_t::no_argument, 'C'), - wopt(L!("selection-start"), woption_argument_t::no_argument, 'B'), - wopt(L!("selection-end"), woption_argument_t::no_argument, 'E'), - wopt(L!("line"), woption_argument_t::no_argument, 'L'), - wopt(L!("search-mode"), woption_argument_t::no_argument, 'S'), - wopt(L!("paging-mode"), woption_argument_t::no_argument, 'P'), - wopt(L!("paging-full-mode"), woption_argument_t::no_argument, 'F'), - wopt(L!("search-field"), woption_argument_t::no_argument, '\x03'), - wopt(L!("is-valid"), woption_argument_t::no_argument, '\x01'), + let long_options: &[WOption] = &[ + wopt(L!("append"), ArgType::NoArgument, 'a'), + wopt(L!("insert"), ArgType::NoArgument, 'i'), + wopt(L!("replace"), ArgType::NoArgument, 'r'), + wopt(L!("current-buffer"), ArgType::NoArgument, 'b'), + wopt(L!("current-job"), ArgType::NoArgument, 'j'), + wopt(L!("current-process"), ArgType::NoArgument, 'p'), + wopt(L!("current-selection"), ArgType::NoArgument, 's'), + wopt(L!("current-token"), ArgType::NoArgument, 't'), + wopt(L!("cut-at-cursor"), ArgType::NoArgument, 'c'), + wopt(L!("function"), ArgType::NoArgument, 'f'), + wopt(L!("tokens-expanded"), ArgType::NoArgument, 'x'), + wopt(L!("tokens-raw"), ArgType::NoArgument, '\x02'), + wopt(L!("tokenize"), ArgType::NoArgument, 'o'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("input"), ArgType::RequiredArgument, 'I'), + wopt(L!("cursor"), ArgType::NoArgument, 'C'), + wopt(L!("selection-start"), ArgType::NoArgument, 'B'), + wopt(L!("selection-end"), ArgType::NoArgument, 'E'), + wopt(L!("line"), ArgType::NoArgument, 'L'), + wopt(L!("search-mode"), ArgType::NoArgument, 'S'), + wopt(L!("paging-mode"), ArgType::NoArgument, 'P'), + wopt(L!("paging-full-mode"), ArgType::NoArgument, 'F'), + wopt(L!("search-field"), ArgType::NoArgument, '\x03'), + wopt(L!("is-valid"), ArgType::NoArgument, '\x01'), ]; - let mut w = wgetopter_t::new(short_options, long_options, args); + let mut w = WGetopter::new(short_options, long_options, args); let cmd = w.argv[0]; - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 'a' => append_mode = Some(AppendMode::Append), 'b' => buffer_part = Some(TextScope::String), @@ -286,18 +282,18 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, w.argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, w.argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, w.argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, w.argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } _ => panic!(), } } - let positional_args = w.argv.len() - w.woptind; + let positional_args = w.argv.len() - w.wopt_index; if function_mode { // Check for invalid switch combinations. @@ -323,7 +319,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) } type rl = ReadlineCmd; - for arg in &w.argv[w.woptind..] { + for arg in &w.argv[w.wopt_index..] { let Some(cmd) = input_function_get_code(arg) else { streams .err @@ -535,7 +531,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) if cursor_mode { if positional_args != 0 { - let arg = w.argv[w.woptind]; + let arg = w.argv[w.wopt_index]; let new_pos = match fish_wcstol(arg) { Err(_) => { streams @@ -573,14 +569,14 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) } else if positional_args == 1 { replace_part( range, - args[w.woptind], + args[w.wopt_index], append_mode, current_buffer, current_cursor_pos, search_field_mode, ); } else { - let sb = join_strings(&w.argv[w.woptind..], '\n'); + let sb = join_strings(&w.argv[w.wopt_index..], '\n'); replace_part( range, &sb, diff --git a/src/builtins/complete.rs b/src/builtins/complete.rs index 9ec9b759f..508a8da8a 100644 --- a/src/builtins/complete.rs +++ b/src/builtins/complete.rs @@ -240,54 +240,34 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> let mut unescape_output = true; const short_options: &wstr = L!(":a:c:p:s:l:o:d:fFrxeuAn:C::w:hk"); - const long_options: &[woption] = &[ - wopt(L!("exclusive"), woption_argument_t::no_argument, 'x'), - wopt(L!("no-files"), woption_argument_t::no_argument, 'f'), - wopt(L!("force-files"), woption_argument_t::no_argument, 'F'), - wopt( - L!("require-parameter"), - woption_argument_t::no_argument, - 'r', - ), - wopt(L!("path"), woption_argument_t::required_argument, 'p'), - wopt(L!("command"), woption_argument_t::required_argument, 'c'), - wopt( - L!("short-option"), - woption_argument_t::required_argument, - 's', - ), - wopt( - L!("long-option"), - woption_argument_t::required_argument, - 'l', - ), - wopt(L!("old-option"), woption_argument_t::required_argument, 'o'), - wopt(L!("subcommand"), woption_argument_t::required_argument, 'S'), - wopt( - L!("description"), - woption_argument_t::required_argument, - 'd', - ), - wopt(L!("arguments"), woption_argument_t::required_argument, 'a'), - wopt(L!("erase"), woption_argument_t::no_argument, 'e'), - wopt(L!("unauthoritative"), woption_argument_t::no_argument, 'u'), - wopt(L!("authoritative"), woption_argument_t::no_argument, 'A'), - wopt(L!("condition"), woption_argument_t::required_argument, 'n'), - wopt(L!("wraps"), woption_argument_t::required_argument, 'w'), - wopt( - L!("do-complete"), - woption_argument_t::optional_argument, - 'C', - ), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("keep-order"), woption_argument_t::no_argument, 'k'), - wopt(L!("escape"), woption_argument_t::no_argument, OPT_ESCAPE), + const long_options: &[WOption] = &[ + wopt(L!("exclusive"), ArgType::NoArgument, 'x'), + wopt(L!("no-files"), ArgType::NoArgument, 'f'), + wopt(L!("force-files"), ArgType::NoArgument, 'F'), + wopt(L!("require-parameter"), ArgType::NoArgument, 'r'), + wopt(L!("path"), ArgType::RequiredArgument, 'p'), + wopt(L!("command"), ArgType::RequiredArgument, 'c'), + wopt(L!("short-option"), ArgType::RequiredArgument, 's'), + wopt(L!("long-option"), ArgType::RequiredArgument, 'l'), + wopt(L!("old-option"), ArgType::RequiredArgument, 'o'), + wopt(L!("subcommand"), ArgType::RequiredArgument, 'S'), + wopt(L!("description"), ArgType::RequiredArgument, 'd'), + wopt(L!("arguments"), ArgType::RequiredArgument, 'a'), + wopt(L!("erase"), ArgType::NoArgument, 'e'), + wopt(L!("unauthoritative"), ArgType::NoArgument, 'u'), + wopt(L!("authoritative"), ArgType::NoArgument, 'A'), + wopt(L!("condition"), ArgType::RequiredArgument, 'n'), + wopt(L!("wraps"), ArgType::RequiredArgument, 'w'), + wopt(L!("do-complete"), ArgType::OptionalArgument, 'C'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("keep-order"), ArgType::NoArgument, 'k'), + wopt(L!("escape"), ArgType::NoArgument, OPT_ESCAPE), ]; let mut have_x = false; - let mut w = wgetopter_t::new(short_options, long_options, argv); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(short_options, long_options, argv); + while let Some(opt) = w.next_opt() { match opt { 'x' => { result_mode.no_files = true; @@ -399,14 +379,14 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from WGetopter"), } } @@ -429,12 +409,12 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> return STATUS_INVALID_ARGS; } - if w.woptind != argc { + if w.wopt_index != argc { // Use one left-over arg as the do-complete argument // to enable `complete -C "git check"`. - if do_complete && do_complete_param.is_none() && argc == w.woptind + 1 { + if do_complete && do_complete_param.is_none() && argc == w.wopt_index + 1 { do_complete_param = Some(argv[argc - 1].to_owned()); - } else if !do_complete && cmd_to_complete.is_empty() && argc == w.woptind + 1 { + } else if !do_complete && cmd_to_complete.is_empty() && argc == w.wopt_index + 1 { // Or use one left-over arg as the command to complete cmd_to_complete.push(argv[argc - 1].to_owned()); } else { diff --git a/src/builtins/contains.rs b/src/builtins/contains.rs index 5ea927343..b2b275aa6 100644 --- a/src/builtins/contains.rs +++ b/src/builtins/contains.rs @@ -15,33 +15,33 @@ fn parse_options( let cmd = args[0]; const SHORT_OPTS: &wstr = L!("+:hi"); - const LONG_OPTS: &[woption] = &[ - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("index"), woption_argument_t::no_argument, 'i'), + const LONG_OPTS: &[WOption] = &[ + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("index"), ArgType::NoArgument, 'i'), ]; let mut opts = Options::default(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); + while let Some(c) = w.next_opt() { match c { 'h' => opts.print_help = true, 'i' => opts.print_index = true, ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// Implementation of the builtin contains command, used to check if a specified string is part of diff --git a/src/builtins/echo.rs b/src/builtins/echo.rs index 638a3b469..c8b99101c 100644 --- a/src/builtins/echo.rs +++ b/src/builtins/echo.rs @@ -28,29 +28,29 @@ fn parse_options( let cmd = args[0]; const SHORT_OPTS: &wstr = L!("+:Eens"); - const LONG_OPTS: &[woption] = &[]; + const LONG_OPTS: &[WOption] = &[]; let mut opts = Options::default(); let mut oldopts = opts; let mut oldoptind = 0; - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); + while let Some(c) = w.next_opt() { match c { 'n' => opts.print_newline = false, 'e' => opts.interpret_special_chars = true, 's' => opts.print_spaces = false, 'E' => opts.interpret_special_chars = false, ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], true); return Err(STATUS_INVALID_ARGS); } '?' => { - return Ok((oldopts, w.woptind - 1)); + return Ok((oldopts, w.wopt_index - 1)); } _ => { - panic!("unexpected retval from wgetopter::wgetopt_long()"); + panic!("unexpected retval from WGetopter"); } } @@ -60,13 +60,13 @@ fn parse_options( // We need to keep it one out-of-date so we can ignore the *last* option. // (this might be an issue in wgetopt, but that's a whole other can of worms // and really only occurs with our weird "put it back" option parsing) - if w.woptind == oldoptind + 2 { + if w.wopt_index == oldoptind + 2 { oldopts = opts; - oldoptind = w.woptind; + oldoptind = w.wopt_index; } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// Parse a numeric escape sequence in `s`, returning the number of characters consumed and the diff --git a/src/builtins/function.rs b/src/builtins/function.rs index 885fb8b29..04852ea2b 100644 --- a/src/builtins/function.rs +++ b/src/builtins/function.rs @@ -40,18 +40,18 @@ impl Default for FunctionCmdOpts { // This is needed due to the semantics of the -a/--argument-names flag. const SHORT_OPTIONS: &wstr = L!("-:a:d:e:hj:p:s:v:w:SV:"); #[rustfmt::skip] -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("description"), woption_argument_t::required_argument, 'd'), - wopt(L!("on-signal"), woption_argument_t::required_argument, 's'), - wopt(L!("on-job-exit"), woption_argument_t::required_argument, 'j'), - wopt(L!("on-process-exit"), woption_argument_t::required_argument, 'p'), - wopt(L!("on-variable"), woption_argument_t::required_argument, 'v'), - wopt(L!("on-event"), woption_argument_t::required_argument, 'e'), - wopt(L!("wraps"), woption_argument_t::required_argument, 'w'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("argument-names"), woption_argument_t::required_argument, 'a'), - wopt(L!("no-scope-shadowing"), woption_argument_t::no_argument, 'S'), - wopt(L!("inherit-variable"), woption_argument_t::required_argument, 'V'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("description"), ArgType::RequiredArgument, 'd'), + wopt(L!("on-signal"), ArgType::RequiredArgument, 's'), + wopt(L!("on-job-exit"), ArgType::RequiredArgument, 'j'), + wopt(L!("on-process-exit"), ArgType::RequiredArgument, 'p'), + wopt(L!("on-variable"), ArgType::RequiredArgument, 'v'), + wopt(L!("on-event"), ArgType::RequiredArgument, 'e'), + wopt(L!("wraps"), ArgType::RequiredArgument, 'w'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("argument-names"), ArgType::RequiredArgument, 'a'), + wopt(L!("no-scope-shadowing"), ArgType::NoArgument, 'S'), + wopt(L!("inherit-variable"), ArgType::RequiredArgument, 'V'), ]; /// \return the internal_job_id for a pid, or None if none. @@ -79,14 +79,14 @@ fn parse_cmd_opts( let cmd = L!("function"); let print_hints = false; let mut handling_named_arguments = false; - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, argv); - while let Some(opt) = w.wgetopt_long() { - // NONOPTION_CHAR_CODE is returned when we reach a non-permuted non-option. - if opt != 'a' && opt != NONOPTION_CHAR_CODE { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, argv); + while let Some(opt) = w.next_opt() { + // NON_OPTION_CHAR is returned when we reach a non-permuted non-option. + if opt != 'a' && opt != NON_OPTION_CHAR { handling_named_arguments = false; } match opt { - NONOPTION_CHAR_CODE => { + NON_OPTION_CHAR => { // A positional argument we got because we use RETURN_IN_ORDER. let woptarg = w.woptarg.unwrap().to_owned(); if handling_named_arguments { @@ -197,20 +197,20 @@ fn parse_cmd_opts( opts.print_help = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } other => { - panic!("Unexpected retval from wgetopt_long: {}", other); + panic!("Unexpected retval from WGetopter: {}", other); } } } - *optind = w.woptind; + *optind = w.wopt_index; STATUS_CMD_OK } diff --git a/src/builtins/functions.rs b/src/builtins/functions.rs index 01d13aee2..827db0d04 100644 --- a/src/builtins/functions.rs +++ b/src/builtins/functions.rs @@ -51,19 +51,19 @@ const NO_METADATA_SHORT: char = 2 as char; const SHORT_OPTIONS: &wstr = L!(":Ht:Dacd:ehnqv"); #[rustfmt::skip] -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("erase"), woption_argument_t::no_argument, 'e'), - wopt(L!("description"), woption_argument_t::required_argument, 'd'), - wopt(L!("names"), woption_argument_t::no_argument, 'n'), - wopt(L!("all"), woption_argument_t::no_argument, 'a'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), - wopt(L!("copy"), woption_argument_t::no_argument, 'c'), - wopt(L!("details"), woption_argument_t::no_argument, 'D'), - wopt(L!("no-details"), woption_argument_t::no_argument, NO_METADATA_SHORT), - wopt(L!("verbose"), woption_argument_t::no_argument, 'v'), - wopt(L!("handlers"), woption_argument_t::no_argument, 'H'), - wopt(L!("handlers-type"), woption_argument_t::required_argument, 't'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("erase"), ArgType::NoArgument, 'e'), + wopt(L!("description"), ArgType::RequiredArgument, 'd'), + wopt(L!("names"), ArgType::NoArgument, 'n'), + wopt(L!("all"), ArgType::NoArgument, 'a'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("query"), ArgType::NoArgument, 'q'), + wopt(L!("copy"), ArgType::NoArgument, 'c'), + wopt(L!("details"), ArgType::NoArgument, 'D'), + wopt(L!("no-details"), ArgType::NoArgument, NO_METADATA_SHORT), + wopt(L!("verbose"), ArgType::NoArgument, 'v'), + wopt(L!("handlers"), ArgType::NoArgument, 'H'), + wopt(L!("handlers-type"), ArgType::RequiredArgument, 't'), ]; /// Parses options to builtin function, populating opts. @@ -77,8 +77,8 @@ fn parse_cmd_opts<'args>( ) -> Option { let cmd = L!("functions"); let print_hints = false; - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, argv); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, argv); + while let Some(opt) = w.next_opt() { match opt { 'v' => opts.verbose = true, 'e' => opts.erase = true, @@ -98,20 +98,20 @@ fn parse_cmd_opts<'args>( opts.handlers_type = Some(w.woptarg.unwrap()); } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } other => { - panic!("Unexpected retval from wgetopt_long: {}", other); + panic!("Unexpected retval from WGetopter: {}", other); } } } - *optind = w.woptind; + *optind = w.wopt_index; STATUS_CMD_OK } diff --git a/src/builtins/history.rs b/src/builtins/history.rs index 04158f4d0..b94d41204 100644 --- a/src/builtins/history.rs +++ b/src/builtins/history.rs @@ -67,21 +67,21 @@ struct HistoryCmdOpts { /// supported at least until fish 3.0 and possibly longer to avoid breaking everyones /// config.fish and other scripts. const short_options: &wstr = L!(":CRcehmn:pt::z"); -const longopts: &[woption] = &[ - wopt(L!("prefix"), woption_argument_t::no_argument, 'p'), - wopt(L!("contains"), woption_argument_t::no_argument, 'c'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("show-time"), woption_argument_t::optional_argument, 't'), - wopt(L!("exact"), woption_argument_t::no_argument, 'e'), - wopt(L!("max"), woption_argument_t::required_argument, 'n'), - wopt(L!("null"), woption_argument_t::no_argument, 'z'), - wopt(L!("case-sensitive"), woption_argument_t::no_argument, 'C'), - wopt(L!("delete"), woption_argument_t::no_argument, '\x01'), - wopt(L!("search"), woption_argument_t::no_argument, '\x02'), - wopt(L!("save"), woption_argument_t::no_argument, '\x03'), - wopt(L!("clear"), woption_argument_t::no_argument, '\x04'), - wopt(L!("merge"), woption_argument_t::no_argument, '\x05'), - wopt(L!("reverse"), woption_argument_t::no_argument, 'R'), +const longopts: &[WOption] = &[ + wopt(L!("prefix"), ArgType::NoArgument, 'p'), + wopt(L!("contains"), ArgType::NoArgument, 'c'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("show-time"), ArgType::OptionalArgument, 't'), + wopt(L!("exact"), ArgType::NoArgument, 'e'), + wopt(L!("max"), ArgType::RequiredArgument, 'n'), + wopt(L!("null"), ArgType::NoArgument, 'z'), + wopt(L!("case-sensitive"), ArgType::NoArgument, 'C'), + wopt(L!("delete"), ArgType::NoArgument, '\x01'), + wopt(L!("search"), ArgType::NoArgument, '\x02'), + wopt(L!("save"), ArgType::NoArgument, '\x03'), + wopt(L!("clear"), ArgType::NoArgument, '\x04'), + wopt(L!("merge"), ArgType::NoArgument, '\x05'), + wopt(L!("reverse"), ArgType::NoArgument, 'R'), ]; /// Remember the history subcommand and disallow selecting more than one history subcommand. @@ -141,8 +141,8 @@ fn parse_cmd_opts( streams: &mut IoStreams, ) -> Option { let cmd = argv[0]; - let mut w = wgetopter_t::new(short_options, longopts, argv); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(short_options, longopts, argv); + while let Some(opt) = w.next_opt() { match opt { '\x01' => { if !set_hist_cmd(cmd, &mut opts.hist_cmd, HistCmd::HIST_DELETE, streams) { @@ -205,27 +205,27 @@ fn parse_cmd_opts( opts.print_help = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { // Try to parse it as a number; e.g., "-123". - match fish_wcstol(&w.argv[w.woptind - 1][1..]) { + match fish_wcstol(&w.argv[w.wopt_index - 1][1..]) { Ok(x) => opts.max_items = Some(x as _), // todo!("historical behavior is to cast") Err(_) => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } } - w.nextchar = L!(""); + w.remaining_text = L!(""); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } - *optind = w.woptind; + *optind = w.wopt_index; STATUS_CMD_OK } diff --git a/src/builtins/jobs.rs b/src/builtins/jobs.rs index fcef1b79d..db4248c0f 100644 --- a/src/builtins/jobs.rs +++ b/src/builtins/jobs.rs @@ -10,7 +10,7 @@ use crate::job_group::{JobId, MaybeJobId}; use crate::parser::Parser; use crate::proc::{clock_ticks_to_seconds, have_proc_stat, proc_get_jiffies, Job, INVALID_PID}; use crate::wchar_ext::WExt; -use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t}; +use crate::wgetopt::{wopt, ArgType, WGetopter, WOption}; use crate::wutil::wgettext; use crate::{ builtins::shared::STATUS_CMD_OK, @@ -127,14 +127,14 @@ fn builtin_jobs_print(j: &Job, mode: JobsPrintMode, header: bool, streams: &mut } const SHORT_OPTIONS: &wstr = L!(":cghlpq"); -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("command"), woption_argument_t::no_argument, 'c'), - wopt(L!("group"), woption_argument_t::no_argument, 'g'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("last"), woption_argument_t::no_argument, 'l'), - wopt(L!("pid"), woption_argument_t::no_argument, 'p'), - wopt(L!("quiet"), woption_argument_t::no_argument, 'q'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("command"), ArgType::NoArgument, 'c'), + wopt(L!("group"), ArgType::NoArgument, 'g'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("last"), ArgType::NoArgument, 'l'), + wopt(L!("pid"), ArgType::NoArgument, 'p'), + wopt(L!("quiet"), ArgType::NoArgument, 'q'), + wopt(L!("query"), ArgType::NoArgument, 'q'), ]; /// The jobs builtin. Used for printing running jobs. Defined in builtin_jobs.c. @@ -145,8 +145,8 @@ pub fn jobs(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt let mut mode = JobsPrintMode::Default; let mut print_last = false; - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, argv); + while let Some(c) = w.next_opt() { match c { 'p' => { mode = JobsPrintMode::PrintPid; @@ -168,14 +168,14 @@ pub fn jobs(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from WGetopter"), } } @@ -190,8 +190,8 @@ pub fn jobs(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt return STATUS_CMD_ERROR; } - if w.woptind < argc { - for arg in &w.argv[w.woptind..] { + if w.wopt_index < argc { + for arg in &w.argv[w.wopt_index..] { let j; if arg.char_at(0) == '%' { match fish_wcstoi(&arg[1..]).ok().filter(|&job_id| job_id >= 0) { diff --git a/src/builtins/math.rs b/src/builtins/math.rs index e09f503ed..8f08bf683 100644 --- a/src/builtins/math.rs +++ b/src/builtins/math.rs @@ -25,10 +25,10 @@ fn parse_cmd_opts( // This command is atypical in using the "+" (REQUIRE_ORDER) option for flag parsing. // This is needed because of the minus, `-`, operator in math expressions. const SHORT_OPTS: &wstr = L!("+:hs:b:"); - const LONG_OPTS: &[woption] = &[ - wopt(L!("scale"), woption_argument_t::required_argument, 's'), - wopt(L!("base"), woption_argument_t::required_argument, 'b'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), + const LONG_OPTS: &[WOption] = &[ + wopt(L!("scale"), ArgType::RequiredArgument, 's'), + wopt(L!("base"), ArgType::RequiredArgument, 'b'), + wopt(L!("help"), ArgType::NoArgument, 'h'), ]; let mut opts = Options { @@ -39,8 +39,8 @@ fn parse_cmd_opts( let mut have_scale = false; - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); + while let Some(c) = w.next_opt() { match c { 's' => { let optarg = w.woptarg.unwrap(); @@ -86,13 +86,13 @@ fn parse_cmd_opts( opts.print_help = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], print_hints); return Err(STATUS_INVALID_ARGS); } '?' => { // For most commands this is an error. We ignore it because a math expression // can begin with a minus sign. - return Ok((opts, w.woptind - 1)); + return Ok((opts, w.wopt_index - 1)); } _ => { panic!("unexpected retval from wgeopter.next()"); @@ -110,7 +110,7 @@ fn parse_cmd_opts( return Err(STATUS_INVALID_ARGS); } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// Return a formatted version of the value `v` respecting the given `opts`. diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 64125ced9..4b497b254 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -55,9 +55,9 @@ mod prelude { parser::Parser, wchar::prelude::*, wgetopt::{ - wgetopter_t, wopt, woption, - woption_argument_t::{self, *}, - NONOPTION_CHAR_CODE, + wopt, + ArgType::{self, *}, + WGetopter, WOption, NON_OPTION_CHAR, }, wutil::{fish_wcstoi, fish_wcstol, fish_wcstoul}, }; diff --git a/src/builtins/path.rs b/src/builtins/path.rs index f87a9213d..da078674b 100644 --- a/src/builtins/path.rs +++ b/src/builtins/path.rs @@ -203,17 +203,17 @@ fn construct_short_opts(opts: &Options) -> WString { /// Note that several long flags share the same short flag. That is okay. The caller is expected /// to indicate that a max of one of the long flags sharing a short flag is valid. /// Remember: adjust the completions in share/completions/ when options change -const LONG_OPTIONS: [woption<'static>; 10] = [ - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("null-in"), no_argument, 'z'), - wopt(L!("null-out"), no_argument, 'Z'), - wopt(L!("perm"), required_argument, 'p'), - wopt(L!("type"), required_argument, 't'), - wopt(L!("invert"), no_argument, 'v'), - wopt(L!("relative"), no_argument, 'R'), - wopt(L!("reverse"), no_argument, 'r'), - wopt(L!("unique"), no_argument, 'u'), - wopt(L!("key"), required_argument, NONOPTION_CHAR_CODE), +const LONG_OPTIONS: [WOption<'static>; 10] = [ + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("null-in"), NoArgument, 'z'), + wopt(L!("null-out"), NoArgument, 'Z'), + wopt(L!("perm"), RequiredArgument, 'p'), + wopt(L!("type"), RequiredArgument, 't'), + wopt(L!("invert"), NoArgument, 'v'), + wopt(L!("relative"), NoArgument, 'R'), + wopt(L!("reverse"), NoArgument, 'r'), + wopt(L!("unique"), NoArgument, 'u'), + wopt(L!("key"), RequiredArgument, NON_OPTION_CHAR), ]; fn parse_opts<'args>( @@ -230,16 +230,16 @@ fn parse_opts<'args>( let short_opts = construct_short_opts(opts); - let mut w = wgetopter_t::new(&short_opts, &LONG_OPTIONS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(&short_opts, &LONG_OPTIONS, args); + while let Some(c) = w.next_opt() { match c { ':' => { streams.err.append(L!("path ")); // clone of string_error - builtin_missing_argument(parser, streams, cmd, args_read[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args_read[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } '?' => { - path_unknown_option(parser, streams, cmd, args_read[w.woptind - 1]); + path_unknown_option(parser, streams, cmd, args_read[w.wopt_index - 1]); return STATUS_INVALID_ARGS; } 'q' => { @@ -324,19 +324,19 @@ fn parse_opts<'args>( opts.relative = true; continue; } - NONOPTION_CHAR_CODE => { + NON_OPTION_CHAR => { assert!(w.woptarg.is_some()); opts.key = w.woptarg; continue; } _ => { - path_unknown_option(parser, streams, cmd, args_read[w.woptind - 1]); + path_unknown_option(parser, streams, cmd, args_read[w.wopt_index - 1]); return STATUS_INVALID_ARGS; } } } - *optind = w.woptind; + *optind = w.wopt_index; if n_req_args != 0 { assert!(n_req_args == 1); diff --git a/src/builtins/pwd.rs b/src/builtins/pwd.rs index 70243fbb8..130d9da9e 100644 --- a/src/builtins/pwd.rs +++ b/src/builtins/pwd.rs @@ -6,18 +6,18 @@ use crate::{env::Environment, wutil::wrealpath}; // The pwd builtin. Respect -P to resolve symbolic links. Respect -L to not do that (the default). const short_options: &wstr = L!("LPh"); -const long_options: &[woption] = &[ - wopt(L!("help"), no_argument, 'h'), - wopt(L!("logical"), no_argument, 'L'), - wopt(L!("physical"), no_argument, 'P'), +const long_options: &[WOption] = &[ + wopt(L!("help"), NoArgument, 'h'), + wopt(L!("logical"), NoArgument, 'L'), + wopt(L!("physical"), NoArgument, 'P'), ]; pub fn pwd(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Option { let cmd = argv[0]; let argc = argv.len(); let mut resolve_symlinks = false; - let mut w = wgetopter_t::new(short_options, long_options, argv); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(short_options, long_options, argv); + while let Some(opt) = w.next_opt() { match opt { 'L' => resolve_symlinks = false, 'P' => resolve_symlinks = true, @@ -26,14 +26,14 @@ pub fn pwd(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opti return STATUS_CMD_OK; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from WGetopter"), } } - if w.woptind != argc { + if w.wopt_index != argc { streams .err .append(wgettext_fmt!(BUILTIN_ERR_ARG_COUNT1, cmd, 0, argc - 1)); diff --git a/src/builtins/random.rs b/src/builtins/random.rs index 37f61b721..4ff31c236 100644 --- a/src/builtins/random.rs +++ b/src/builtins/random.rs @@ -14,26 +14,26 @@ pub fn random(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> O let print_hints = false; const shortopts: &wstr = L!("+:h"); - const longopts: &[woption] = &[wopt(L!("help"), woption_argument_t::no_argument, 'h')]; + const longopts: &[WOption] = &[wopt(L!("help"), ArgType::NoArgument, 'h')]; - let mut w = wgetopter_t::new(shortopts, longopts, argv); + let mut w = WGetopter::new(shortopts, longopts, argv); #[allow(clippy::never_loop)] - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 'h' => { builtin_print_help(parser, streams, cmd); return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } _ => { - panic!("unexpected retval from wgeopter.next()"); + panic!("unexpected retval from WGetopter"); } } } @@ -41,8 +41,8 @@ pub fn random(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> O let mut start = 0; let mut end = 32767; let mut step = 1; - let arg_count = argc - w.woptind; - let i = w.woptind; + let arg_count = argc - w.wopt_index; + let i = w.wopt_index; if arg_count >= 1 && argv[i] == "choice" { if arg_count == 1 { streams diff --git a/src/builtins/read.rs b/src/builtins/read.rs index 423bb2ec7..8987f8fc8 100644 --- a/src/builtins/read.rs +++ b/src/builtins/read.rs @@ -61,31 +61,27 @@ impl Options { } const SHORT_OPTIONS: &wstr = L!(":ac:d:fghiLln:p:sStuxzP:UR:L"); -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("array"), woption_argument_t::no_argument, 'a'), - wopt(L!("command"), woption_argument_t::required_argument, 'c'), - wopt(L!("delimiter"), woption_argument_t::required_argument, 'd'), - wopt(L!("export"), woption_argument_t::no_argument, 'x'), - wopt(L!("function"), woption_argument_t::no_argument, 'f'), - wopt(L!("global"), woption_argument_t::no_argument, 'g'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("line"), woption_argument_t::no_argument, 'L'), - wopt(L!("list"), woption_argument_t::no_argument, 'a'), - wopt(L!("local"), woption_argument_t::no_argument, 'l'), - wopt(L!("nchars"), woption_argument_t::required_argument, 'n'), - wopt(L!("null"), woption_argument_t::no_argument, 'z'), - wopt(L!("prompt"), woption_argument_t::required_argument, 'p'), - wopt(L!("prompt-str"), woption_argument_t::required_argument, 'P'), - wopt( - L!("right-prompt"), - woption_argument_t::required_argument, - 'R', - ), - wopt(L!("shell"), woption_argument_t::no_argument, 'S'), - wopt(L!("silent"), woption_argument_t::no_argument, 's'), - wopt(L!("tokenize"), woption_argument_t::no_argument, 't'), - wopt(L!("unexport"), woption_argument_t::no_argument, 'u'), - wopt(L!("universal"), woption_argument_t::no_argument, 'U'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("array"), ArgType::NoArgument, 'a'), + wopt(L!("command"), ArgType::RequiredArgument, 'c'), + wopt(L!("delimiter"), ArgType::RequiredArgument, 'd'), + wopt(L!("export"), ArgType::NoArgument, 'x'), + wopt(L!("function"), ArgType::NoArgument, 'f'), + wopt(L!("global"), ArgType::NoArgument, 'g'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("line"), ArgType::NoArgument, 'L'), + wopt(L!("list"), ArgType::NoArgument, 'a'), + wopt(L!("local"), ArgType::NoArgument, 'l'), + wopt(L!("nchars"), ArgType::RequiredArgument, 'n'), + wopt(L!("null"), ArgType::NoArgument, 'z'), + wopt(L!("prompt"), ArgType::RequiredArgument, 'p'), + wopt(L!("prompt-str"), ArgType::RequiredArgument, 'P'), + wopt(L!("right-prompt"), ArgType::RequiredArgument, 'R'), + wopt(L!("shell"), ArgType::NoArgument, 'S'), + wopt(L!("silent"), ArgType::NoArgument, 's'), + wopt(L!("tokenize"), ArgType::NoArgument, 't'), + wopt(L!("unexport"), ArgType::NoArgument, 'u'), + wopt(L!("universal"), ArgType::NoArgument, 'U'), ]; fn parse_cmd_opts( @@ -95,8 +91,8 @@ fn parse_cmd_opts( ) -> Result<(Options, usize), Option> { let cmd = args[0]; let mut opts = Options::new(); - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, args); - while let Some(opt) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, args); + while let Some(opt) = w.next_opt() { match opt { 'a' => { opts.array = true; @@ -186,20 +182,20 @@ fn parse_cmd_opts( opts.split_null = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], true); return Err(STATUS_INVALID_ARGS); } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], true); return Err(STATUS_INVALID_ARGS); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// Read from the tty. This is only valid when the stream is stdin and it is attached to a tty and diff --git a/src/builtins/realpath.rs b/src/builtins/realpath.rs index 69257de62..b93c27c70 100644 --- a/src/builtins/realpath.rs +++ b/src/builtins/realpath.rs @@ -16,9 +16,9 @@ struct Options { } const short_options: &wstr = L!("+:hs"); -const long_options: &[woption] = &[ - wopt(L!("no-symlinks"), no_argument, 's'), - wopt(L!("help"), no_argument, 'h'), +const long_options: &[WOption] = &[ + wopt(L!("no-symlinks"), NoArgument, 's'), + wopt(L!("help"), NoArgument, 'h'), ]; fn parse_options( @@ -30,25 +30,25 @@ fn parse_options( let mut opts = Options::default(); - let mut w = wgetopter_t::new(short_options, long_options, args); + let mut w = WGetopter::new(short_options, long_options, args); - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 's' => opts.no_symlinks = true, 'h' => opts.print_help = true, ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from WGetopter"), } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// An implementation of the external realpath command. Doesn't support any options. diff --git a/src/builtins/return.rs b/src/builtins/return.rs index 0be3680d6..2c514b677 100644 --- a/src/builtins/return.rs +++ b/src/builtins/return.rs @@ -15,32 +15,32 @@ fn parse_options( let cmd = args[0]; const SHORT_OPTS: &wstr = L!(":h"); - const LONG_OPTS: &[woption] = &[wopt(L!("help"), woption_argument_t::no_argument, 'h')]; + const LONG_OPTS: &[WOption] = &[wopt(L!("help"), ArgType::NoArgument, 'h')]; let mut opts = Options::default(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 'h' => opts.print_help = true, ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], true); return Err(STATUS_INVALID_ARGS); } '?' => { // We would normally invoke builtin_unknown_option() and return an error. // But for this command we want to let it try and parse the value as a negative // return value. - return Ok((opts, w.woptind - 1)); + return Ok((opts, w.wopt_index - 1)); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from next_opt"); } } } - Ok((opts, w.woptind)) + Ok((opts, w.wopt_index)) } /// Function for handling the return builtin. diff --git a/src/builtins/set.rs b/src/builtins/set.rs index e20955d1f..ba9e50d03 100644 --- a/src/builtins/set.rs +++ b/src/builtins/set.rs @@ -102,29 +102,29 @@ impl Options { // (REQUIRE_ORDER) option for flag parsing. This is not typical of most fish commands. It means // we stop scanning for flags when the first non-flag argument is seen. const SHORT_OPTS: &wstr = L!("+:LSUaefghlnpqux"); - const LONG_OPTS: &[woption] = &[ - wopt(L!("export"), no_argument, 'x'), - wopt(L!("global"), no_argument, 'g'), - wopt(L!("function"), no_argument, 'f'), - wopt(L!("local"), no_argument, 'l'), - wopt(L!("erase"), no_argument, 'e'), - wopt(L!("names"), no_argument, 'n'), - wopt(L!("unexport"), no_argument, 'u'), - wopt(L!("universal"), no_argument, 'U'), - wopt(L!("long"), no_argument, 'L'), - wopt(L!("query"), no_argument, 'q'), - wopt(L!("show"), no_argument, 'S'), - wopt(L!("append"), no_argument, 'a'), - wopt(L!("prepend"), no_argument, 'p'), - wopt(L!("path"), no_argument, PATH_ARG), - wopt(L!("unpath"), no_argument, UNPATH_ARG), - wopt(L!("help"), no_argument, 'h'), + const LONG_OPTS: &[WOption] = &[ + wopt(L!("export"), NoArgument, 'x'), + wopt(L!("global"), NoArgument, 'g'), + wopt(L!("function"), NoArgument, 'f'), + wopt(L!("local"), NoArgument, 'l'), + wopt(L!("erase"), NoArgument, 'e'), + wopt(L!("names"), NoArgument, 'n'), + wopt(L!("unexport"), NoArgument, 'u'), + wopt(L!("universal"), NoArgument, 'U'), + wopt(L!("long"), NoArgument, 'L'), + wopt(L!("query"), NoArgument, 'q'), + wopt(L!("show"), NoArgument, 'S'), + wopt(L!("append"), NoArgument, 'a'), + wopt(L!("prepend"), NoArgument, 'p'), + wopt(L!("path"), NoArgument, PATH_ARG), + wopt(L!("unpath"), NoArgument, UNPATH_ARG), + wopt(L!("help"), NoArgument, 'h'), ]; let mut opts = Self::default(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); + while let Some(c) = w.next_opt() { match c { 'a' => opts.append = true, 'e' => { @@ -155,12 +155,12 @@ impl Options { opts.preserve_failure_exit_status = false; } ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], false); return Err(STATUS_INVALID_ARGS); } '?' => { // Specifically detect `set -o` because people might be bringing over bashisms. - let optind = w.woptind; + let optind = w.wopt_index; // implicit drop(w); here if args[optind - 1].starts_with("-o") { // TODO: translate this @@ -184,12 +184,12 @@ impl Options { return Err(STATUS_INVALID_ARGS); } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } - let optind = w.woptind; + let optind = w.wopt_index; if opts.print_help { builtin_print_help(parser, streams, cmd); diff --git a/src/builtins/set_color.rs b/src/builtins/set_color.rs index 65f555d32..58727d03c 100644 --- a/src/builtins/set_color.rs +++ b/src/builtins/set_color.rs @@ -104,15 +104,15 @@ fn print_colors( } const SHORT_OPTIONS: &wstr = L!(":b:hoidrcu"); -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("background"), woption_argument_t::required_argument, 'b'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("bold"), woption_argument_t::no_argument, 'o'), - wopt(L!("underline"), woption_argument_t::no_argument, 'u'), - wopt(L!("italics"), woption_argument_t::no_argument, 'i'), - wopt(L!("dim"), woption_argument_t::no_argument, 'd'), - wopt(L!("reverse"), woption_argument_t::no_argument, 'r'), - wopt(L!("print-colors"), woption_argument_t::no_argument, 'c'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("background"), ArgType::RequiredArgument, 'b'), + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("bold"), ArgType::NoArgument, 'o'), + wopt(L!("underline"), ArgType::NoArgument, 'u'), + wopt(L!("italics"), ArgType::NoArgument, 'i'), + wopt(L!("dim"), ArgType::NoArgument, 'd'), + wopt(L!("reverse"), ArgType::NoArgument, 'r'), + wopt(L!("print-colors"), ArgType::NoArgument, 'c'), ]; /// set_color builtin. @@ -134,8 +134,8 @@ pub fn set_color(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - let mut reverse = false; let mut print = false; - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, argv); + while let Some(c) = w.next_opt() { match c { 'b' => { assert!(w.woptarg.is_some(), "Arg should have been set"); @@ -161,16 +161,16 @@ pub fn set_color(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - parser, streams, L!("set_color"), - argv[w.woptind - 1], + argv[w.wopt_index - 1], true, /* print_hints */ ); return STATUS_INVALID_ARGS; } - _ => unreachable!("unexpected retval from wgeopter_t::wgetopt_long"), + _ => unreachable!("unexpected retval from WGetopter"), } } - // We want to reclaim argv so grab woptind now. - let mut woptind = w.woptind; + // We want to reclaim argv so grab wopt_index now. + let mut wopt_index = w.wopt_index; let mut bg = RgbColor::from_wstr(bgcolor.unwrap_or(L!(""))).unwrap_or(RgbColor::NONE); if bgcolor.is_some() && bg.is_none() { @@ -189,25 +189,25 @@ pub fn set_color(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) - if bgcolor.is_some() && bg.is_special() { bg = RgbColor::from_wstr(L!("")).unwrap_or(RgbColor::NONE); } - let args = &argv[woptind..argc]; + let args = &argv[wopt_index..argc]; print_colors(streams, args, bold, underline, italics, dim, reverse, bg); return STATUS_CMD_OK; } // Remaining arguments are foreground color. let mut fgcolors = Vec::new(); - while woptind < argc { - let fg = RgbColor::from_wstr(argv[woptind]).unwrap_or(RgbColor::NONE); + while wopt_index < argc { + let fg = RgbColor::from_wstr(argv[wopt_index]).unwrap_or(RgbColor::NONE); if fg.is_none() { streams.err.append(wgettext_fmt!( "%ls: Unknown color '%ls'\n", argv[0], - argv[woptind] + argv[wopt_index] )); return STATUS_INVALID_ARGS; }; fgcolors.push(fg); - woptind += 1; + wopt_index += 1; } // #1323: We may have multiple foreground colors. Choose the best one. If we had no foreground diff --git a/src/builtins/shared.rs b/src/builtins/shared.rs index 7651153ef..039c86924 100644 --- a/src/builtins/shared.rs +++ b/src/builtins/shared.rs @@ -650,11 +650,11 @@ impl HelpOnlyCmdOpts { let print_hints = true; const shortopts: &wstr = L!("+:h"); - const longopts: &[woption] = &[wopt(L!("help"), woption_argument_t::no_argument, 'h')]; + const longopts: &[WOption] = &[wopt(L!("help"), ArgType::NoArgument, 'h')]; let mut print_help = false; - let mut w = wgetopter_t::new(shortopts, longopts, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(shortopts, longopts, args); + while let Some(c) = w.next_opt() { match c { 'h' => { print_help = true; @@ -664,24 +664,30 @@ impl HelpOnlyCmdOpts { parser, streams, cmd, - args[w.woptind - 1], + args[w.wopt_index - 1], print_hints, ); return Err(STATUS_INVALID_ARGS); } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], print_hints); + builtin_unknown_option( + parser, + streams, + cmd, + args[w.wopt_index - 1], + print_hints, + ); return Err(STATUS_INVALID_ARGS); } _ => { - panic!("unexpected retval from wgetopter::wgetopt_long()"); + panic!("unexpected retval from WGetopter"); } } } Ok(HelpOnlyCmdOpts { print_help, - optind: w.woptind, + optind: w.wopt_index, }) } } diff --git a/src/builtins/status.rs b/src/builtins/status.rs index b9a49162d..748a5162d 100644 --- a/src/builtins/status.rs +++ b/src/builtins/status.rs @@ -141,32 +141,32 @@ const IS_INTERACTIVE_JOB_CTRL_SHORT: char = '\x03'; const IS_NO_JOB_CTRL_SHORT: char = '\x04'; const SHORT_OPTIONS: &wstr = L!(":L:cbilfnhj:t"); -const LONG_OPTIONS: &[woption] = &[ - wopt(L!("help"), no_argument, 'h'), - wopt(L!("current-filename"), no_argument, 'f'), - wopt(L!("current-line-number"), no_argument, 'n'), - wopt(L!("filename"), no_argument, 'f'), - wopt(L!("fish-path"), no_argument, FISH_PATH_SHORT), - wopt(L!("is-block"), no_argument, 'b'), - wopt(L!("is-command-substitution"), no_argument, 'c'), +const LONG_OPTIONS: &[WOption] = &[ + wopt(L!("help"), NoArgument, 'h'), + wopt(L!("current-filename"), NoArgument, 'f'), + wopt(L!("current-line-number"), NoArgument, 'n'), + wopt(L!("filename"), NoArgument, 'f'), + wopt(L!("fish-path"), NoArgument, FISH_PATH_SHORT), + wopt(L!("is-block"), NoArgument, 'b'), + wopt(L!("is-command-substitution"), NoArgument, 'c'), wopt( L!("is-full-job-control"), - no_argument, + NoArgument, IS_FULL_JOB_CTRL_SHORT, ), - wopt(L!("is-interactive"), no_argument, 'i'), + wopt(L!("is-interactive"), NoArgument, 'i'), wopt( L!("is-interactive-job-control"), - no_argument, + NoArgument, IS_INTERACTIVE_JOB_CTRL_SHORT, ), - wopt(L!("is-login"), no_argument, 'l'), - wopt(L!("is-no-job-control"), no_argument, IS_NO_JOB_CTRL_SHORT), - wopt(L!("job-control"), required_argument, 'j'), - wopt(L!("level"), required_argument, 'L'), - wopt(L!("line"), no_argument, 'n'), - wopt(L!("line-number"), no_argument, 'n'), - wopt(L!("print-stack-trace"), no_argument, 't'), + wopt(L!("is-login"), NoArgument, 'l'), + wopt(L!("is-no-job-control"), NoArgument, IS_NO_JOB_CTRL_SHORT), + wopt(L!("job-control"), RequiredArgument, 'j'), + wopt(L!("level"), RequiredArgument, 'L'), + wopt(L!("line"), NoArgument, 'n'), + wopt(L!("line-number"), NoArgument, 'n'), + wopt(L!("print-stack-trace"), NoArgument, 't'), ]; /// Print the features and their values. @@ -205,8 +205,8 @@ fn parse_cmd_opts( let mut args_read = Vec::with_capacity(args.len()); args_read.extend_from_slice(args); - let mut w = wgetopter_t::new(SHORT_OPTIONS, LONG_OPTIONS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(SHORT_OPTIONS, LONG_OPTIONS, args); + while let Some(c) = w.next_opt() { match c { 'L' => { opts.level = { @@ -281,18 +281,18 @@ fn parse_cmd_opts( } 'h' => opts.print_help = true, ':' => { - builtin_missing_argument(parser, streams, cmd, args[w.woptind - 1], false); + builtin_missing_argument(parser, streams, cmd, args[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, args[w.woptind - 1], false); + builtin_unknown_option(parser, streams, cmd, args[w.wopt_index - 1], false); return STATUS_INVALID_ARGS; } - _ => panic!("unexpected retval from wgetopt_long"), + _ => panic!("unexpected retval from WGetopter"), } } - *optind = w.woptind; + *optind = w.wopt_index; return STATUS_CMD_OK; } diff --git a/src/builtins/string.rs b/src/builtins/string.rs index de6262e07..1c36457f9 100644 --- a/src/builtins/string.rs +++ b/src/builtins/string.rs @@ -37,7 +37,7 @@ fn string_unknown_option(parser: &Parser, streams: &mut IoStreams, subcmd: &wstr trait StringSubCommand<'args> { const SHORT_OPTIONS: &'static wstr; - const LONG_OPTIONS: &'static [woption<'static>]; + const LONG_OPTIONS: &'static [WOption<'static>]; /// Parse and store option specified by the associated short or long option. fn parse_opt( @@ -57,29 +57,35 @@ trait StringSubCommand<'args> { let mut args_read = Vec::with_capacity(args.len()); args_read.extend_from_slice(args); - let mut w = wgetopter_t::new(Self::SHORT_OPTIONS, Self::LONG_OPTIONS, args); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(Self::SHORT_OPTIONS, Self::LONG_OPTIONS, args); + while let Some(c) = w.next_opt() { match c { ':' => { streams.err.append(L!("string ")); // clone of string_error - builtin_missing_argument(parser, streams, cmd, args_read[w.woptind - 1], false); + builtin_missing_argument( + parser, + streams, + cmd, + args_read[w.wopt_index - 1], + false, + ); return Err(STATUS_INVALID_ARGS); } '?' => { - string_unknown_option(parser, streams, cmd, args_read[w.woptind - 1]); + string_unknown_option(parser, streams, cmd, args_read[w.wopt_index - 1]); return Err(STATUS_INVALID_ARGS); } c => { let retval = self.parse_opt(cmd, c, w.woptarg); if let Err(e) = retval { - e.print_error(&args_read, parser, streams, w.woptarg, w.woptind); + e.print_error(&args_read, parser, streams, w.woptarg, w.wopt_index); return Err(e.retval()); } } } } - return Ok(w.woptind); + return Ok(w.wopt_index); } /// Take any positional arguments after options have been parsed. diff --git a/src/builtins/string/collect.rs b/src/builtins/string/collect.rs index a50b56f34..7718a9a1f 100644 --- a/src/builtins/string/collect.rs +++ b/src/builtins/string/collect.rs @@ -7,9 +7,9 @@ pub struct Collect { } impl StringSubCommand<'_> for Collect { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("allow-empty"), no_argument, 'a'), - wopt(L!("no-trim-newlines"), no_argument, 'N'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("allow-empty"), NoArgument, 'a'), + wopt(L!("no-trim-newlines"), NoArgument, 'N'), ]; const SHORT_OPTIONS: &'static wstr = L!(":Na"); diff --git a/src/builtins/string/escape.rs b/src/builtins/string/escape.rs index f6c1edd6c..ad32dd3bf 100644 --- a/src/builtins/string/escape.rs +++ b/src/builtins/string/escape.rs @@ -8,16 +8,16 @@ pub struct Escape { } impl StringSubCommand<'_> for Escape { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("no-quoted"), no_argument, 'n'), - wopt(L!("style"), required_argument, NONOPTION_CHAR_CODE), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("no-quoted"), NoArgument, 'n'), + wopt(L!("style"), RequiredArgument, NON_OPTION_CHAR), ]; const SHORT_OPTIONS: &'static wstr = L!(":n"); fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), StringError> { match c { 'n' => self.no_quoted = true, - NONOPTION_CHAR_CODE => { + NON_OPTION_CHAR => { self.style = arg .unwrap() .try_into() diff --git a/src/builtins/string/join.rs b/src/builtins/string/join.rs index 355aa3c4c..5dc4d2462 100644 --- a/src/builtins/string/join.rs +++ b/src/builtins/string/join.rs @@ -19,9 +19,9 @@ impl Default for Join<'_> { } impl<'args> StringSubCommand<'args> for Join<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("no-empty"), no_argument, 'n'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("no-empty"), NoArgument, 'n'), ]; const SHORT_OPTIONS: &'static wstr = L!(":qn"); diff --git a/src/builtins/string/length.rs b/src/builtins/string/length.rs index bfe862eaa..997854b2d 100644 --- a/src/builtins/string/length.rs +++ b/src/builtins/string/length.rs @@ -9,9 +9,9 @@ pub struct Length { } impl StringSubCommand<'_> for Length { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("visible"), no_argument, 'V'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("visible"), NoArgument, 'V'), ]; const SHORT_OPTIONS: &'static wstr = L!(":qV"); diff --git a/src/builtins/string/match.rs b/src/builtins/string/match.rs index c670cc3ca..e625f9eb3 100644 --- a/src/builtins/string/match.rs +++ b/src/builtins/string/match.rs @@ -22,15 +22,15 @@ pub struct Match<'args> { } impl<'args> StringSubCommand<'args> for Match<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("all"), no_argument, 'a'), - wopt(L!("entire"), no_argument, 'e'), - wopt(L!("groups-only"), no_argument, 'g'), - wopt(L!("ignore-case"), no_argument, 'i'), - wopt(L!("invert"), no_argument, 'v'), - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("regex"), no_argument, 'r'), - wopt(L!("index"), no_argument, 'n'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("all"), NoArgument, 'a'), + wopt(L!("entire"), NoArgument, 'e'), + wopt(L!("groups-only"), NoArgument, 'g'), + wopt(L!("ignore-case"), NoArgument, 'i'), + wopt(L!("invert"), NoArgument, 'v'), + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("regex"), NoArgument, 'r'), + wopt(L!("index"), NoArgument, 'n'), ]; const SHORT_OPTIONS: &'static wstr = L!(":aegivqrn"); diff --git a/src/builtins/string/pad.rs b/src/builtins/string/pad.rs index 35a04a056..adc4505df 100644 --- a/src/builtins/string/pad.rs +++ b/src/builtins/string/pad.rs @@ -20,11 +20,11 @@ impl Default for Pad { } impl StringSubCommand<'_> for Pad { - const LONG_OPTIONS: &'static [woption<'static>] = &[ + const LONG_OPTIONS: &'static [WOption<'static>] = &[ // FIXME docs say `--char`, there was no long_opt with `--char` in C++ - wopt(L!("chars"), required_argument, 'c'), - wopt(L!("right"), no_argument, 'r'), - wopt(L!("width"), required_argument, 'w'), + wopt(L!("chars"), RequiredArgument, 'c'), + wopt(L!("right"), NoArgument, 'r'), + wopt(L!("width"), RequiredArgument, 'w'), ]; const SHORT_OPTIONS: &'static wstr = L!(":c:rw:"); diff --git a/src/builtins/string/repeat.rs b/src/builtins/string/repeat.rs index 64698e1bf..4b5de4d5b 100644 --- a/src/builtins/string/repeat.rs +++ b/src/builtins/string/repeat.rs @@ -9,11 +9,11 @@ pub struct Repeat { } impl StringSubCommand<'_> for Repeat { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("count"), required_argument, 'n'), - wopt(L!("max"), required_argument, 'm'), - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("no-newline"), no_argument, 'N'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("count"), RequiredArgument, 'n'), + wopt(L!("max"), RequiredArgument, 'm'), + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("no-newline"), NoArgument, 'N'), ]; const SHORT_OPTIONS: &'static wstr = L!(":n:m:qN"); diff --git a/src/builtins/string/replace.rs b/src/builtins/string/replace.rs index 9694a595d..c5d7d86ce 100644 --- a/src/builtins/string/replace.rs +++ b/src/builtins/string/replace.rs @@ -15,12 +15,12 @@ pub struct Replace<'args> { } impl<'args> StringSubCommand<'args> for Replace<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("all"), no_argument, 'a'), - wopt(L!("filter"), no_argument, 'f'), - wopt(L!("ignore-case"), no_argument, 'i'), - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("regex"), no_argument, 'r'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("all"), NoArgument, 'a'), + wopt(L!("filter"), NoArgument, 'f'), + wopt(L!("ignore-case"), NoArgument, 'i'), + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("regex"), NoArgument, 'r'), ]; const SHORT_OPTIONS: &'static wstr = L!(":afiqr"); diff --git a/src/builtins/string/shorten.rs b/src/builtins/string/shorten.rs index 0b7bf7873..e74b48e55 100644 --- a/src/builtins/string/shorten.rs +++ b/src/builtins/string/shorten.rs @@ -25,13 +25,13 @@ impl Default for Shorten<'_> { } impl<'args> StringSubCommand<'args> for Shorten<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ + const LONG_OPTIONS: &'static [WOption<'static>] = &[ // FIXME: documentation says it's --char - wopt(L!("chars"), required_argument, 'c'), - wopt(L!("max"), required_argument, 'm'), - wopt(L!("no-newline"), no_argument, 'N'), - wopt(L!("left"), no_argument, 'l'), - wopt(L!("quiet"), no_argument, 'q'), + wopt(L!("chars"), RequiredArgument, 'c'), + wopt(L!("max"), RequiredArgument, 'm'), + wopt(L!("no-newline"), NoArgument, 'N'), + wopt(L!("left"), NoArgument, 'l'), + wopt(L!("quiet"), NoArgument, 'q'), ]; const SHORT_OPTIONS: &'static wstr = L!(":c:m:Nlq"); diff --git a/src/builtins/string/split.rs b/src/builtins/string/split.rs index 01501c447..0b1218f72 100644 --- a/src/builtins/string/split.rs +++ b/src/builtins/string/split.rs @@ -102,14 +102,14 @@ impl<'args> TryFrom<&'args wstr> for Fields { } impl<'args> StringSubCommand<'args> for Split<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("quiet"), no_argument, 'q'), - wopt(L!("right"), no_argument, 'r'), - wopt(L!("max"), required_argument, 'm'), - wopt(L!("no-empty"), no_argument, 'n'), - wopt(L!("fields"), required_argument, 'f'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("quiet"), NoArgument, 'q'), + wopt(L!("right"), NoArgument, 'r'), + wopt(L!("max"), RequiredArgument, 'm'), + wopt(L!("no-empty"), NoArgument, 'n'), + wopt(L!("fields"), RequiredArgument, 'f'), // FIXME: allow-empty is not documented - wopt(L!("allow-empty"), no_argument, 'a'), + wopt(L!("allow-empty"), NoArgument, 'a'), ]; const SHORT_OPTIONS: &'static wstr = L!(":qrm:nf:a"); diff --git a/src/builtins/string/sub.rs b/src/builtins/string/sub.rs index ce41b8f95..14d1d3630 100644 --- a/src/builtins/string/sub.rs +++ b/src/builtins/string/sub.rs @@ -11,11 +11,11 @@ pub struct Sub { } impl StringSubCommand<'_> for Sub { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("length"), required_argument, 'l'), - wopt(L!("start"), required_argument, 's'), - wopt(L!("end"), required_argument, 'e'), - wopt(L!("quiet"), no_argument, 'q'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("length"), RequiredArgument, 'l'), + wopt(L!("start"), RequiredArgument, 's'), + wopt(L!("end"), RequiredArgument, 'e'), + wopt(L!("quiet"), NoArgument, 'q'), ]; const SHORT_OPTIONS: &'static wstr = L!(":l:qs:e:"); diff --git a/src/builtins/string/transform.rs b/src/builtins/string/transform.rs index a3d76bb66..cc2e8de54 100644 --- a/src/builtins/string/transform.rs +++ b/src/builtins/string/transform.rs @@ -6,7 +6,7 @@ pub struct Transform { } impl StringSubCommand<'_> for Transform { - const LONG_OPTIONS: &'static [woption<'static>] = &[wopt(L!("quiet"), no_argument, 'q')]; + const LONG_OPTIONS: &'static [WOption<'static>] = &[wopt(L!("quiet"), NoArgument, 'q')]; const SHORT_OPTIONS: &'static wstr = L!(":q"); fn parse_opt(&mut self, _n: &wstr, c: char, _arg: Option<&wstr>) -> Result<(), StringError> { match c { diff --git a/src/builtins/string/trim.rs b/src/builtins/string/trim.rs index f565775e8..14ec11281 100644 --- a/src/builtins/string/trim.rs +++ b/src/builtins/string/trim.rs @@ -20,11 +20,11 @@ impl Default for Trim<'_> { } impl<'args> StringSubCommand<'args> for Trim<'args> { - const LONG_OPTIONS: &'static [woption<'static>] = &[ - wopt(L!("chars"), required_argument, 'c'), - wopt(L!("left"), no_argument, 'l'), - wopt(L!("right"), no_argument, 'r'), - wopt(L!("quiet"), no_argument, 'q'), + const LONG_OPTIONS: &'static [WOption<'static>] = &[ + wopt(L!("chars"), RequiredArgument, 'c'), + wopt(L!("left"), NoArgument, 'l'), + wopt(L!("right"), NoArgument, 'r'), + wopt(L!("quiet"), NoArgument, 'q'), ]; const SHORT_OPTIONS: &'static wstr = L!(":c:lrq"); diff --git a/src/builtins/string/unescape.rs b/src/builtins/string/unescape.rs index ee08b75b2..6e38c3c82 100644 --- a/src/builtins/string/unescape.rs +++ b/src/builtins/string/unescape.rs @@ -8,18 +8,18 @@ pub struct Unescape { } impl StringSubCommand<'_> for Unescape { - const LONG_OPTIONS: &'static [woption<'static>] = &[ + const LONG_OPTIONS: &'static [WOption<'static>] = &[ // FIXME: this flag means nothing, but was present in the C++ code // should be removed - wopt(L!("no-quoted"), no_argument, 'n'), - wopt(L!("style"), required_argument, NONOPTION_CHAR_CODE), + wopt(L!("no-quoted"), NoArgument, 'n'), + wopt(L!("style"), RequiredArgument, NON_OPTION_CHAR), ]; const SHORT_OPTIONS: &'static wstr = L!(":n"); fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), StringError> { match c { 'n' => self.no_quoted = true, - NONOPTION_CHAR_CODE => { + NON_OPTION_CHAR => { self.style = arg .unwrap() .try_into() diff --git a/src/builtins/type.rs b/src/builtins/type.rs index 52a9c996b..7a6c5727d 100644 --- a/src/builtins/type.rs +++ b/src/builtins/type.rs @@ -24,20 +24,20 @@ pub fn r#type(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> O let mut opts: type_cmd_opts_t = Default::default(); const shortopts: &wstr = L!(":hasftpPq"); - const longopts: &[woption] = &[ - wopt(L!("help"), woption_argument_t::no_argument, 'h'), - wopt(L!("all"), woption_argument_t::no_argument, 'a'), - wopt(L!("short"), woption_argument_t::no_argument, 's'), - wopt(L!("no-functions"), woption_argument_t::no_argument, 'f'), - wopt(L!("type"), woption_argument_t::no_argument, 't'), - wopt(L!("path"), woption_argument_t::no_argument, 'p'), - wopt(L!("force-path"), woption_argument_t::no_argument, 'P'), - wopt(L!("query"), woption_argument_t::no_argument, 'q'), - wopt(L!("quiet"), woption_argument_t::no_argument, 'q'), + const longopts: &[WOption] = &[ + wopt(L!("help"), ArgType::NoArgument, 'h'), + wopt(L!("all"), ArgType::NoArgument, 'a'), + wopt(L!("short"), ArgType::NoArgument, 's'), + wopt(L!("no-functions"), ArgType::NoArgument, 'f'), + wopt(L!("type"), ArgType::NoArgument, 't'), + wopt(L!("path"), ArgType::NoArgument, 'p'), + wopt(L!("force-path"), ArgType::NoArgument, 'P'), + wopt(L!("query"), ArgType::NoArgument, 'q'), + wopt(L!("quiet"), ArgType::NoArgument, 'q'), ]; - let mut w = wgetopter_t::new(shortopts, longopts, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(shortopts, longopts, argv); + while let Some(c) = w.next_opt() { match c { 'a' => opts.all = true, 's' => opts.short_output = true, @@ -51,11 +51,11 @@ pub fn r#type(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> O return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } _ => { @@ -71,7 +71,7 @@ pub fn r#type(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> O let mut res = false; - let optind = w.woptind; + let optind = w.wopt_index; for arg in argv.iter().take(argc).skip(optind) { let mut found = 0; if !opts.force_path && !opts.no_functions { diff --git a/src/builtins/ulimit.rs b/src/builtins/ulimit.rs index 4f771a371..27b684916 100644 --- a/src/builtins/ulimit.rs +++ b/src/builtins/ulimit.rs @@ -176,54 +176,38 @@ pub fn ulimit(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O const SHORT_OPTS: &wstr = L!(":HSabcdefilmnqrstuvwyKPTh"); - const LONG_OPTS: &[woption] = &[ - wopt(L!("all"), woption_argument_t::no_argument, 'a'), - wopt(L!("hard"), woption_argument_t::no_argument, 'H'), - wopt(L!("soft"), woption_argument_t::no_argument, 'S'), - wopt(L!("socket-buffers"), woption_argument_t::no_argument, 'b'), - wopt(L!("core-size"), woption_argument_t::no_argument, 'c'), - wopt(L!("data-size"), woption_argument_t::no_argument, 'd'), - wopt(L!("nice"), woption_argument_t::no_argument, 'e'), - wopt(L!("file-size"), woption_argument_t::no_argument, 'f'), - wopt(L!("pending-signals"), woption_argument_t::no_argument, 'i'), - wopt(L!("lock-size"), woption_argument_t::no_argument, 'l'), - wopt( - L!("resident-set-size"), - woption_argument_t::no_argument, - 'm', - ), - wopt( - L!("file-descriptor-count"), - woption_argument_t::no_argument, - 'n', - ), - wopt(L!("queue-size"), woption_argument_t::no_argument, 'q'), - wopt( - L!("realtime-priority"), - woption_argument_t::no_argument, - 'r', - ), - wopt(L!("stack-size"), woption_argument_t::no_argument, 's'), - wopt(L!("cpu-time"), woption_argument_t::no_argument, 't'), - wopt(L!("process-count"), woption_argument_t::no_argument, 'u'), - wopt( - L!("virtual-memory-size"), - woption_argument_t::no_argument, - 'v', - ), - wopt(L!("swap-size"), woption_argument_t::no_argument, 'w'), - wopt(L!("realtime-maxtime"), woption_argument_t::no_argument, 'y'), - wopt(L!("kernel-queues"), woption_argument_t::no_argument, 'K'), - wopt(L!("ptys"), woption_argument_t::no_argument, 'P'), - wopt(L!("threads"), woption_argument_t::no_argument, 'T'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), + const LONG_OPTS: &[WOption] = &[ + wopt(L!("all"), ArgType::NoArgument, 'a'), + wopt(L!("hard"), ArgType::NoArgument, 'H'), + wopt(L!("soft"), ArgType::NoArgument, 'S'), + wopt(L!("socket-buffers"), ArgType::NoArgument, 'b'), + wopt(L!("core-size"), ArgType::NoArgument, 'c'), + wopt(L!("data-size"), ArgType::NoArgument, 'd'), + wopt(L!("nice"), ArgType::NoArgument, 'e'), + wopt(L!("file-size"), ArgType::NoArgument, 'f'), + wopt(L!("pending-signals"), ArgType::NoArgument, 'i'), + wopt(L!("lock-size"), ArgType::NoArgument, 'l'), + wopt(L!("resident-set-size"), ArgType::NoArgument, 'm'), + wopt(L!("file-descriptor-count"), ArgType::NoArgument, 'n'), + wopt(L!("queue-size"), ArgType::NoArgument, 'q'), + wopt(L!("realtime-priority"), ArgType::NoArgument, 'r'), + wopt(L!("stack-size"), ArgType::NoArgument, 's'), + wopt(L!("cpu-time"), ArgType::NoArgument, 't'), + wopt(L!("process-count"), ArgType::NoArgument, 'u'), + wopt(L!("virtual-memory-size"), ArgType::NoArgument, 'v'), + wopt(L!("swap-size"), ArgType::NoArgument, 'w'), + wopt(L!("realtime-maxtime"), ArgType::NoArgument, 'y'), + wopt(L!("kernel-queues"), ArgType::NoArgument, 'K'), + wopt(L!("ptys"), ArgType::NoArgument, 'P'), + wopt(L!("threads"), ArgType::NoArgument, 'T'), + wopt(L!("help"), ArgType::NoArgument, 'h'), ]; let mut opts = Options::default(); - let mut w = wgetopter_t::new(SHORT_OPTS, LONG_OPTS, args); + let mut w = WGetopter::new(SHORT_OPTS, LONG_OPTS, args); - while let Some(c) = w.wgetopt_long() { + while let Some(c) = w.next_opt() { match c { 'a' => opts.report_all = true, 'H' => opts.hard = true, @@ -253,15 +237,15 @@ pub fn ulimit(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O return STATUS_CMD_OK; } ':' => { - builtin_missing_argument(parser, streams, cmd, w.argv[w.woptind - 1], true); + builtin_missing_argument(parser, streams, cmd, w.argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, w.argv[w.woptind - 1], true); + builtin_unknown_option(parser, streams, cmd, w.argv[w.wopt_index - 1], true); return STATUS_INVALID_ARGS; } _ => { - panic!("unexpected retval from wgetopt_long"); + panic!("unexpected retval from WGetopter"); } } } @@ -283,7 +267,7 @@ pub fn ulimit(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O let what: c_uint = opts.what.try_into().unwrap(); let argc = w.argv.len(); - let arg_count = argc - w.woptind; + let arg_count = argc - w.wopt_index; if arg_count == 0 { print(what, opts.hard, streams); return STATUS_CMD_OK; @@ -304,32 +288,32 @@ pub fn ulimit(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O soft = true; } - let new_limit: rlim_t = if w.woptind == argc { + let new_limit: rlim_t = if w.wopt_index == argc { streams.err.append(wgettext_fmt!( "%ls: New limit cannot be an empty string\n", cmd )); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; - } else if wcscasecmp(w.argv[w.woptind], L!("unlimited")) == Ordering::Equal { + } else if wcscasecmp(w.argv[w.wopt_index], L!("unlimited")) == Ordering::Equal { RLIM_INFINITY - } else if wcscasecmp(w.argv[w.woptind], L!("hard")) == Ordering::Equal { + } else if wcscasecmp(w.argv[w.wopt_index], L!("hard")) == Ordering::Equal { match get(what, true) { Some(limit) => limit, None => return STATUS_CMD_ERROR, } - } else if wcscasecmp(w.argv[w.woptind], L!("soft")) == Ordering::Equal { + } else if wcscasecmp(w.argv[w.wopt_index], L!("soft")) == Ordering::Equal { match get(what, soft) { Some(limit) => limit, None => return STATUS_CMD_ERROR, } - } else if let Ok(limit) = fish_wcstol(w.argv[w.woptind]) { + } else if let Ok(limit) = fish_wcstol(w.argv[w.wopt_index]) { limit as rlim_t * get_multiplier(what) } else { streams.err.append(wgettext_fmt!( "%ls: Invalid limit '%ls'\n", cmd, - w.argv[w.woptind] + w.argv[w.wopt_index] )); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; diff --git a/src/builtins/wait.rs b/src/builtins/wait.rs index d4d3e5f4a..1859e14ed 100644 --- a/src/builtins/wait.rs +++ b/src/builtins/wait.rs @@ -134,13 +134,13 @@ pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt let print_hints = false; const shortopts: &wstr = L!(":nh"); - const longopts: &[woption] = &[ - wopt(L!("any"), woption_argument_t::no_argument, 'n'), - wopt(L!("help"), woption_argument_t::no_argument, 'h'), + const longopts: &[WOption] = &[ + wopt(L!("any"), ArgType::NoArgument, 'n'), + wopt(L!("help"), ArgType::NoArgument, 'h'), ]; - let mut w = wgetopter_t::new(shortopts, longopts, argv); - while let Some(c) = w.wgetopt_long() { + let mut w = WGetopter::new(shortopts, longopts, argv); + while let Some(c) = w.next_opt() { match c { 'n' => { any_flag = true; @@ -149,11 +149,11 @@ pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt print_help = true; } ':' => { - builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_missing_argument(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } '?' => { - builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1], print_hints); + builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints); return STATUS_INVALID_ARGS; } _ => { @@ -167,7 +167,7 @@ pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt return STATUS_CMD_OK; } - if w.woptind == argc { + if w.wopt_index == argc { // No jobs specified. // Note this may succeed with an empty wait list. return wait_for_completion(parser, &get_all_wait_handles(parser), any_flag); @@ -175,7 +175,7 @@ pub fn wait(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt // Get the list of wait handles for our waiting. let mut wait_handles: Vec = Vec::new(); - let optind = w.woptind; + let optind = w.wopt_index; for item in &argv[optind..argc] { if iswnumeric(item) { // argument is pid diff --git a/src/tests/wgetopt.rs b/src/tests/wgetopt.rs index 94a94c8c0..b4cf020ed 100644 --- a/src/tests/wgetopt.rs +++ b/src/tests/wgetopt.rs @@ -1,12 +1,12 @@ use crate::wchar::prelude::*; use crate::wcstringutil::join_strings; -use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t}; +use crate::wgetopt::{wopt, ArgType, WGetopter, WOption}; #[test] fn test_wgetopt() { // Regression test for a crash. const short_options: &wstr = L!("-a"); - const long_options: &[woption] = &[wopt(L!("add"), woption_argument_t::no_argument, 'a')]; + const long_options: &[WOption] = &[wopt(L!("add"), ArgType::NoArgument, 'a')]; let mut argv = [ L!("abbr"), L!("--add"), @@ -14,10 +14,10 @@ fn test_wgetopt() { L!("emacs"), L!("-nw"), ]; - let mut w = wgetopter_t::new(short_options, long_options, &mut argv); + let mut w = WGetopter::new(short_options, long_options, &mut argv); let mut a_count = 0; let mut arguments = vec![]; - while let Some(opt) = w.wgetopt_long() { + while let Some(opt) = w.next_opt() { match opt { 'a' => { a_count += 1; @@ -28,7 +28,7 @@ fn test_wgetopt() { } '?' => { // unrecognized option - if let Some(arg) = w.argv.get(w.woptind - 1) { + if let Some(arg) = w.argv.get(w.wopt_index - 1) { arguments.push(arg.to_owned()); } } diff --git a/src/wgetopt.rs b/src/wgetopt.rs index 514a536f3..d6dab5ab5 100644 --- a/src/wgetopt.rs +++ b/src/wgetopt.rs @@ -1,4 +1,5 @@ -//! A version of the getopt library for use with wide character strings. +//! A version of the getopt library for use with wide character strings, rewritten in +//! Rust. //! //! Note wgetopter expects an mutable array of const strings. It modifies the order of the //! strings, but not their contents. @@ -25,242 +26,233 @@ Cambridge, MA 02139, USA. */ use crate::wchar::prelude::*; -/// Describe how to deal with options that follow non-option ARGV-elements. -/// -/// If the caller did not specify anything, the default is PERMUTE. -/// -/// REQUIRE_ORDER means don't recognize them as options; stop option processing when the first -/// non-option is seen. This is what Unix does. This mode of operation is selected by using `+' -/// as the first character of the list of option characters. -/// -/// PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all -/// the non-options are at the end. This allows options to be given in any order, even with -/// programs that were not written to expect this. -/// -/// RETURN_IN_ORDER is an option available to programs that were written to expect options and -/// other ARGV-elements in any order and that care about the ordering of the two. We describe -/// each non-option ARGV-element as if it were the argument of an option with character code 1. -/// Using `-` as the first character of the list of option characters selects this mode of -/// operation. -/// -/// The special argument `--` forces an end of option-scanning regardless of the value of -/// `ordering`. In the case of RETURN_IN_ORDER, only `--` can cause `getopt` to return EOF with -/// `woptind` != ARGC. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(clippy::upper_case_acronyms)] -enum Ordering { - REQUIRE_ORDER, - PERMUTE, - RETURN_IN_ORDER, -} - -/// The special character code, enabled via RETURN_IN_ORDER, indicating a non-option argument. -pub const NONOPTION_CHAR_CODE: char = '\x01'; - -impl Default for Ordering { - fn default() -> Self { - Ordering::PERMUTE - } -} +/// Special char used with [`Ordering::ReturnInOrder`]. +pub const NON_OPTION_CHAR: char = '\x01'; +/// Utility function to quickly return a reference to an empty wstr. fn empty_wstr() -> &'static wstr { Default::default() } -pub struct wgetopter_t<'opts, 'args, 'argarray> { - /// Argv. - pub argv: &'argarray mut [&'args wstr], - - /// For communication from `getopt` to the caller. When `getopt` finds an option that takes an - /// argument, the argument value is returned here. Also, when `ordering` is RETURN_IN_ORDER, each - /// non-option ARGV-element is returned here. - pub woptarg: Option<&'args wstr>, - - shortopts: &'opts wstr, - longopts: &'opts [woption<'opts>], - - /// The next char to be scanned in the option-element in which the last option character we - /// returned was found. This allows us to pick up the scan where we left off. +/// Describes how to deal with options that follow non-option elements in `argv`. +/// +/// Note that any arguments passed after `--` will be treated as non-option elements, +/// regardless of [Ordering]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +enum Ordering { + /// Stop processing options when the first non-option element is encountered. + /// Traditionally used by Unix systems. /// - /// If this is empty, it means resume the scan by advancing to the next ARGV-element. - pub nextchar: &'args wstr, - - /// Index in ARGV of the next element to be scanned. This is used for communication to and from - /// the caller and for communication between successive calls to `getopt`. + /// Indicated by using `+` as the first character in the optstring. + RequireOrder, + /// The elements in `argv` are reordered so that non-option arguments end up + /// at the end. This allows options to be given in any order, even with programs + /// that were not written to expect this. + #[default] + Permute, + /// Return both options and non-options in the order. Non-option arguments are + /// treated as if they were arguments to an option identified by [NON_OPTION_CHAR]. /// - /// On entry to `getopt`, zero means this is the first call; initialize. - /// - /// When `getopt` returns EOF, this is the index of the first of the non-option elements that the - /// caller should itself scan. - /// - /// Otherwise, `woptind` communicates from one call to the next how much of ARGV has been scanned - /// so far. - // XXX 1003.2 says this must be 1 before any call. - pub woptind: usize, - - /// Set to an option character which was unrecognized. - woptopt: char, - - /// Describe how to deal with options that follow non-option ARGV-elements. - ordering: Ordering, - - /// Handle permutation of arguments. - /// - /// Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt` - /// is the index in ARGV of the first of them; `last_nonopt` is the index after the last of them. - pub first_nonopt: usize, - pub last_nonopt: usize, - - missing_arg_return_colon: bool, - initialized: bool, + /// Indicated by using `-` as the first character in the optstring. + ReturnInOrder, } -/// Names for the values of the `has_arg` field of `woption`. +/// Indicates whether an option takes an argument, and whether that argument +/// is optional. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum woption_argument_t { - no_argument, - required_argument, - optional_argument, +pub enum ArgType { + /// The option takes no arguments. + NoArgument, + /// The option takes a required argument. + RequiredArgument, + /// The option takes an optional argument. + OptionalArgument, } -/// Describe the long-named options requested by the application. The LONG_OPTIONS argument to -/// getopt_long or getopt_long_only is a vector of `struct option' terminated by an element -/// containing a name which is zero. -/// -/// The field `has_arg` is: -/// no_argument (or 0) if the option does not take an argument, -/// required_argument (or 1) if the option requires an argument, -/// optional_argument (or 2) if the option takes an optional argument. -/// -/// If the field `flag` is not NULL, it points to a variable that is set to the value given in the -/// field `val` when the option is found, but left unchanged if the option is not found. -/// -/// To have a long-named option do something other than set an `int` to a compiled-in constant, such -/// as set a value from `optarg`, set the option's `flag` field to zero and its `val` field to a -/// nonzero value (the equivalent single-letter option character, if there is one). For long -/// options that have a zero `flag` field, `getopt` returns the contents of the `val` field. +/// Used to describe the properties of a long-named option. #[derive(Debug, Clone, Copy)] -pub struct woption<'a> { - /// Long name for switch. +pub struct WOption<'a> { + /// The long name of the option. pub name: &'a wstr, - - pub has_arg: woption_argument_t, - - /// If \c flag is non-null, this is the value that flag will be set to. Otherwise, this is the - /// return-value of the function call. + /// Whether the option takes an argument. + pub arg_type: ArgType, + /// If the option is found during scanning, this value will be returned to identify it. pub val: char, } -/// Helper function to create a woption. -pub const fn wopt(name: &wstr, has_arg: woption_argument_t, val: char) -> woption<'_> { - woption { name, has_arg, val } +/// Helper function to create a `WOption`. +pub const fn wopt(name: &wstr, arg_type: ArgType, val: char) -> WOption<'_> { + WOption { + name, + arg_type, + val, + } } -impl<'opts, 'args, 'argarray> wgetopter_t<'opts, 'args, 'argarray> { +/// Used internally by [Wgetopter::find_matching_long_opt]. See there for further +/// details. +#[derive(Default)] +enum LongOptMatch<'a> { + Exact(WOption<'a>, usize), + NonExact(WOption<'a>, usize), + Ambiguous, + #[default] + NoMatch, +} + +/// Used internally by [Wgetopter::next_argv]. See there for further details. +enum NextArgv { + Finished, + UnpermutedNonOption, + FoundOption, +} + +pub struct WGetopter<'opts, 'args, 'argarray> { + /// List of arguments. Will not be resized, but can be modified. + pub argv: &'argarray mut [&'args wstr], + /// Stores the arg of an argument-taking option, including the pseudo-arguments + /// used by [Ordering::ReturnInOrder]. + pub woptarg: Option<&'args wstr>, + /// Stores the optstring for short-named options. + shortopts: &'opts wstr, + /// Stores the data for long options. + longopts: &'opts [WOption<'opts>], + /// The remaining text of the current element, recorded so that we can pick up the + /// scan from where we left off. + pub remaining_text: &'args wstr, + /// Index of the next element in `argv` to be scanned. If the value is `0`, then + /// the next call will initialize. When scanning is finished, this marks the index + /// of the first non-option element that should be parsed by the caller. + // XXX 1003.2 says this must be 1 before any call. + pub wopt_index: usize, + /// Set when a (short) option is unrecognized. + unrecognized_opt: char, + /// How to deal with non-option elements following options. + ordering: Ordering, + /// Used when reordering elements. After scanning is finished, indicates the index + /// of the first non-option skipped during parsing. + pub first_nonopt: usize, + /// Used when reordering elements. After scanning is finished, indicates the index + /// after the final non-option skipped during parsing. + pub last_nonopt: usize, + /// Return `:` if an arg is missing. + return_colon: bool, + /// Prevents redundant initialization. + initialized: bool, +} + +impl<'opts, 'args, 'argarray> WGetopter<'opts, 'args, 'argarray> { pub fn new( shortopts: &'opts wstr, - longopts: &'opts [woption], + longopts: &'opts [WOption], argv: &'argarray mut [&'args wstr], ) -> Self { - return wgetopter_t { - woptopt: '?', + Self { argv, + woptarg: None, shortopts, longopts, + remaining_text: Default::default(), + wopt_index: 0, + unrecognized_opt: '?', + ordering: Ordering::Permute, first_nonopt: 0, - initialized: false, last_nonopt: 0, - missing_arg_return_colon: false, - nextchar: Default::default(), - ordering: Ordering::PERMUTE, - woptarg: None, - woptind: 0, - }; + return_colon: false, + initialized: false, + } } - pub fn wgetopt_long(&mut self) -> Option { - assert!(self.woptind <= self.argc(), "woptind is out of range"); + /// Try to get the next option. + pub fn next_opt(&mut self) -> Option { + assert!( + self.wopt_index <= self.argv.len(), + "wopt_index is out of range" + ); + let mut ignored = 0; - return self._wgetopt_internal(&mut ignored, false); + self.wgetopt_inner(&mut ignored) } - pub fn wgetopt_long_idx(&mut self, opt_index: &mut usize) -> Option { - return self._wgetopt_internal(opt_index, false); + // Tries to get the next option, additionally returning the index of the long option + // if found. + pub fn next_opt_indexed(&mut self) -> Option<(char, Option)> { + let mut longopt_index = usize::MAX; + let option = self.wgetopt_inner(&mut longopt_index); + if longopt_index != usize::MAX { + option.map(|c| (c, Some(longopt_index))) + } else { + option.map(|c| (c, None)) + } } - /// \return the number of arguments. - fn argc(&self) -> usize { - return self.argv.len(); - } - - /// Exchange two adjacent subsequences of ARGV. One subsequence is elements - /// [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The - /// other is elements [last_nonopt,woptind), which contains all the options processed since those - /// non-options were skipped. + /// Swaps two subsequences in `argv`, one which contains all non-options skipped + /// during scanning (defined by the range `[first_nonopt, last_nonopt)`), and + /// the other containing all options scanned after (defined by the range + /// `[last_nonopt, wopt_index)`). /// - /// `first_nonopt` and `last_nonopt` are relocated so that they describe the new indices of the - /// non-options in ARGV after they are moved. + /// Elements are then swapped between the list so that all options end up + /// in the former list, and non-options in the latter. fn exchange(&mut self) { - let mut bottom = self.first_nonopt; + let mut left = self.first_nonopt; let middle = self.last_nonopt; - let mut top = self.woptind; + let mut right = self.wopt_index; - // Exchange the shorter segment with the far end of the longer segment. That puts the shorter - // segment into the right place. It leaves the longer segment in the right place overall, but it - // consists of two parts that need to be swapped next. - while top > middle && middle > bottom { - if top - middle > middle - bottom { - // Bottom segment is the short one. - let len = middle - bottom; + while right > middle && middle > left { + if right - middle > middle - left { + // The left segment is the short one. + let len = middle - left; - // Swap it with the top part of the top segment. + // Swap it with the top part of the right segment. for i in 0..len { - self.argv.swap(bottom + i, top - (middle - bottom) + i); + self.argv.swap(left + i, right - len + i); } - // Exclude the moved bottom segment from further swapping. - top -= len; + + // Exclude the moved elements from further swapping. + right -= len; } else { - // Top segment is the short one. - let len = top - middle; + // The right segment is the short one. + let len = right - middle; - // Swap it with the bottom part of the bottom segment. + // Swap it with the bottom part of the left segment. for i in 0..len { - self.argv.swap(bottom + i, middle + i); + self.argv.swap(left + i, middle + i); } - // Exclude the moved top segment from further swapping. - bottom += len; + + // Exclude the moved elements from further swapping. + left += len; } } - // Update records for the slots the non-options now occupy. - self.first_nonopt += self.woptind - self.last_nonopt; - self.last_nonopt = self.woptind; + // Update the indices to indicate the new positions of the non-option + // arguments. + self.first_nonopt += self.wopt_index - self.last_nonopt; + self.last_nonopt = self.wopt_index; } /// Initialize the internal data when the first call is made. - fn _wgetopt_initialize(&mut self) { - // Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the - // sequence of previously skipped non-option ARGV-elements is empty. + fn initialize(&mut self) { + // Skip the first element since it's just the program name. self.first_nonopt = 1; self.last_nonopt = 1; - self.woptind = 1; - self.nextchar = empty_wstr(); + self.wopt_index = 1; + self.remaining_text = empty_wstr(); let mut optstring = self.shortopts; - // Determine how to handle the ordering of options and nonoptions. + // Set ordering and strip markers. if optstring.char_at(0) == '-' { - self.ordering = Ordering::RETURN_IN_ORDER; + self.ordering = Ordering::ReturnInOrder; optstring = &optstring[1..]; } else if optstring.char_at(0) == '+' { - self.ordering = Ordering::REQUIRE_ORDER; + self.ordering = Ordering::RequireOrder; optstring = &optstring[1..]; } else { - self.ordering = Ordering::PERMUTE; + self.ordering = Ordering::Permute; } if optstring.char_at(0) == ':' { - self.missing_arg_return_colon = true; + self.return_colon = true; optstring = &optstring[1..]; } @@ -268,98 +260,104 @@ impl<'opts, 'args, 'argarray> wgetopter_t<'opts, 'args, 'argarray> { self.initialized = true; } - /// Advance to the next ARGV-element. - /// \return Some(\0) on success, or None or another value if we should stop. - fn _advance_to_next_argv(&mut self) -> Option { - let argc = self.argc(); - if self.ordering == Ordering::PERMUTE { - // If we have just processed some options following some non-options, exchange them so - // that the options come first. - if self.first_nonopt != self.last_nonopt && self.last_nonopt != self.woptind { - self.exchange(); - } else if self.last_nonopt != self.woptind { - self.first_nonopt = self.woptind; + /// Advance to the next element in `argv`. + fn next_argv(&mut self) -> NextArgv { + let argc = self.argv.len(); + + if self.ordering == Ordering::Permute { + // Permute the args if we've found options following non-options. + if self.last_nonopt != self.wopt_index { + if self.first_nonopt == self.last_nonopt { + self.first_nonopt = self.wopt_index; + } else { + self.exchange(); + } } - // Skip any additional non-options and extend the range of non-options previously - // skipped. - while self.woptind < argc - && (self.argv[self.woptind].char_at(0) != '-' || self.argv[self.woptind].len() == 1) + // Skip any further non-options, adjusting the relevant indices as + // needed. + while self.wopt_index < argc + && (self.argv[self.wopt_index].char_at(0) != '-' + || self.argv[self.wopt_index].len() == 1) { - self.woptind += 1; + self.wopt_index += 1; } - self.last_nonopt = self.woptind; + + self.last_nonopt = self.wopt_index; } - // The special ARGV-element `--' means premature end of options. Skip it like a null option, - // then exchange with previous non-options as if it were an option, then skip everything - // else like a non-option. - if self.woptind != argc && self.argv[self.woptind] == "--" { - self.woptind += 1; + // The `--` element prevents any further scanning of options. We skip it like + // a null option, then swap with non-options as if were an option, then skip + // everything else like a non-option. + if self.wopt_index != argc && self.argv[self.wopt_index] == "--" { + self.wopt_index += 1; - if self.first_nonopt != self.last_nonopt && self.last_nonopt != self.woptind { + if self.first_nonopt == self.last_nonopt { + self.first_nonopt = self.wopt_index; + } else if self.last_nonopt != self.wopt_index { self.exchange(); - } else if self.first_nonopt == self.last_nonopt { - self.first_nonopt = self.woptind; } + self.last_nonopt = argc; - self.woptind = argc; + self.wopt_index = argc; } - // If we have done all the ARGV-elements, stop the scan and back over any non-options that - // we skipped and permuted. - - if self.woptind == argc { - // Set the next-arg-index to point at the non-options that we previously skipped, so the - // caller will digest them. + // If we're done with all the elements, stop scanning and back over any + // non-options that were skipped and permuted. + if self.wopt_index == argc { + // Set `wopt_index` to point at the skipped non-options so that the + // caller knows where to begin. if self.first_nonopt != self.last_nonopt { - self.woptind = self.first_nonopt; + self.wopt_index = self.first_nonopt; } - return None; + + return NextArgv::Finished; } - // If we have come to a non-option and did not permute it, either stop the scan or describe + // If we find a non-option and don't permute it, either stop the scan or signal // it to the caller and pass it by. - if self.argv[self.woptind].char_at(0) != '-' || self.argv[self.woptind].len() == 1 { - if self.ordering == Ordering::REQUIRE_ORDER { - return None; + if self.argv[self.wopt_index].char_at(0) != '-' || self.argv[self.wopt_index].len() == 1 { + if self.ordering == Ordering::RequireOrder { + return NextArgv::Finished; } - self.woptarg = Some(self.argv[self.woptind]); - self.woptind += 1; - return Some(NONOPTION_CHAR_CODE); + + self.woptarg = Some(self.argv[self.wopt_index]); + self.wopt_index += 1; + return NextArgv::UnpermutedNonOption; } - // We have found another option-ARGV-element. Skip the initial punctuation. - let skip = if !self.longopts.is_empty() && self.argv[self.woptind].char_at(1) == '-' { + // We've found an option, so we need to skip the initial punctuation. + let skip = if !self.longopts.is_empty() && self.argv[self.wopt_index].char_at(1) == '-' { 2 } else { 1 }; - self.nextchar = self.argv[self.woptind][skip..].into(); - return Some(char::from(0)); + + self.remaining_text = self.argv[self.wopt_index][skip..].into(); + NextArgv::FoundOption } - /// Check for a matching short opt. - fn _handle_short_opt(&mut self) -> char { - // Look at and handle the next short option-character. - let mut c = self.nextchar.char_at(0); - self.nextchar = &self.nextchar[1..]; + /// Check for a matching short-named option. + fn handle_short_opt(&mut self) -> char { + // Look at and handle the next short-named option + let mut c = self.remaining_text.char_at(0); + self.remaining_text = &self.remaining_text[1..]; - let temp = match self.shortopts.chars().position(|sc| sc == c) { - Some(pos) => &self.shortopts[pos..], - None => L!(""), - }; + let temp = self + .shortopts + .chars() + .position(|sc| sc == c) + .map_or(L!(""), |pos| &self.shortopts[pos..]); - // Increment `woptind' when we start to process its last character. - if self.nextchar.is_empty() { - self.woptind += 1; + // Increment `wopt_index' when we run out of text. + if self.remaining_text.is_empty() { + self.wopt_index += 1; } if temp.is_empty() || c == ':' { - self.woptopt = c; - - if !self.nextchar.is_empty() { - self.woptind += 1; + self.unrecognized_opt = c; + if !self.remaining_text.is_empty() { + self.wopt_index += 1; } return '?'; } @@ -369,251 +367,198 @@ impl<'opts, 'args, 'argarray> wgetopter_t<'opts, 'args, 'argarray> { } if temp.char_at(2) == ':' { - // This is an option that accepts an argument optionally. - if !self.nextchar.is_empty() { - self.woptarg = Some(self.nextchar); - self.woptind += 1; + // This option accepts an optional argument. + if !self.remaining_text.is_empty() { + // Consume the remaining text. + self.woptarg = Some(self.remaining_text); + self.wopt_index += 1; } else { self.woptarg = None; } - self.nextchar = empty_wstr(); } else { - // This is an option that requires an argument. - if !self.nextchar.is_empty() { - self.woptarg = Some(self.nextchar); - // If we end this ARGV-element by taking the rest as an arg, we must advance to - // the next element now. - self.woptind += 1; - } else if self.woptind == self.argc() { - self.woptopt = c; - c = if self.missing_arg_return_colon { - ':' - } else { - '?' - }; + // This option requires an argument. + if !self.remaining_text.is_empty() { + // Consume the remaining text. + self.woptarg = Some(self.remaining_text); + self.wopt_index += 1; + } else if self.wopt_index == self.argv.len() { + // If there's nothing in `remaining_text` and there's + // no following element to consume, then the option + // has no argument. + self.unrecognized_opt = c; + c = if self.return_colon { ':' } else { '?' }; } else { - // We already incremented `woptind' once; increment it again when taking next - // ARGV-elt as argument. - self.woptarg = Some(self.argv[self.woptind]); - self.woptind += 1; + // Consume the next element. + self.woptarg = Some(self.argv[self.wopt_index]); + self.wopt_index += 1; } - self.nextchar = empty_wstr(); } - return c; + self.remaining_text = empty_wstr(); + c } - fn _update_long_opt( + fn update_long_opt( &mut self, - pfound: &woption, - nameend: usize, - longind: &mut usize, + opt_found: &WOption, + name_end: usize, + longopt_index: &mut usize, option_index: usize, - retval: &mut char, - ) { - self.woptind += 1; - assert!(self.nextchar.char_at(nameend) == '\0' || self.nextchar.char_at(nameend) == '='); - if self.nextchar.char_at(nameend) == '=' { - if pfound.has_arg != woption_argument_t::no_argument { - self.woptarg = Some(self.nextchar[(nameend + 1)..].into()); + ) -> char { + self.wopt_index += 1; + assert!(matches!(self.remaining_text.char_at(name_end), '\0' | '=')); + + if self.remaining_text.char_at(name_end) == '=' { + if opt_found.arg_type == ArgType::NoArgument { + self.remaining_text = empty_wstr(); + return '?'; } else { - self.nextchar = empty_wstr(); - *retval = '?'; - return; + self.woptarg = Some(self.remaining_text[(name_end + 1)..].into()); } - } else if pfound.has_arg == woption_argument_t::required_argument { - if self.woptind < self.argc() { - self.woptarg = Some(self.argv[self.woptind]); - self.woptind += 1; + } else if opt_found.arg_type == ArgType::RequiredArgument { + if self.wopt_index < self.argv.len() { + self.woptarg = Some(self.argv[self.wopt_index]); + self.wopt_index += 1; } else { - self.nextchar = empty_wstr(); - *retval = if self.missing_arg_return_colon { - ':' - } else { - '?' - }; - return; + self.remaining_text = empty_wstr(); + return if self.return_colon { ':' } else { '?' }; } } - self.nextchar = empty_wstr(); - *longind = option_index; - *retval = pfound.val; + self.remaining_text = empty_wstr(); + *longopt_index = option_index; + opt_found.val } - /// Find a matching long opt. - fn _find_matching_long_opt( - &self, - nameend: usize, - exact: &mut bool, - ambig: &mut bool, - indfound: &mut usize, - ) -> Option> { - let mut pfound: Option = None; + /// Find a matching long-named option. + fn find_matching_long_opt(&self, name_end: usize) -> LongOptMatch<'opts> { + let mut opt = None; + let mut index = 0; + let mut exact = false; + let mut ambiguous = false; // Test all long options for either exact match or abbreviated matches. - for (option_index, p) in self.longopts.iter().enumerate() { + for (i, potential_match) in self.longopts.iter().enumerate() { // Check if current option is prefix of long opt - if p.name.starts_with(&self.nextchar[..nameend]) { - if nameend == p.name.len() { - // The current option is exact match of this long option - pfound = Some(*p); - *indfound = option_index; - *exact = true; + if potential_match + .name + .starts_with(&self.remaining_text[..name_end]) + { + if name_end == potential_match.name.len() { + // The option matches the text exactly, so we're finished. + opt = Some(*potential_match); + index = i; + exact = true; break; - } else if pfound.is_none() { - // current option is first prefix match but not exact match - pfound = Some(*p); - *indfound = option_index; + } else if opt.is_none() { + // The option begins with the matching text, but is not + // exactly equal. + opt = Some(*potential_match); + index = i; } else { - // current option is second or later prefix match but not exact match - *ambig = true; + // There are multiple options that match the text non-exactly. + ambiguous = true; } } } - return pfound; + + opt.map_or(LongOptMatch::NoMatch, |opt| { + if exact { + LongOptMatch::Exact(opt, index) + } else if ambiguous { + LongOptMatch::Ambiguous + } else { + LongOptMatch::NonExact(opt, index) + } + }) } - /// Check for a matching long opt. - fn _handle_long_opt( - &mut self, - longind: &mut usize, - long_only: bool, - retval: &mut char, - ) -> bool { - let mut exact = false; - let mut ambig = false; - let mut indfound: usize = 0; + /// Check for a matching long-named option. + fn handle_long_opt(&mut self, longopt_index: &mut usize) -> Option { + let name_end = if let Some(index) = self.remaining_text.find(['=']) { + index + } else { + self.remaining_text.len() + }; - let mut nameend = 0; - while self.nextchar.char_at(nameend) != '\0' && self.nextchar.char_at(nameend) != '=' { - nameend += 1; + match self.find_matching_long_opt(name_end) { + LongOptMatch::Exact(opt, index) | LongOptMatch::NonExact(opt, index) => { + return Some(self.update_long_opt(&opt, name_end, longopt_index, index)); + } + LongOptMatch::Ambiguous => { + self.remaining_text = empty_wstr(); + self.wopt_index += 1; + return Some('?'); + } + LongOptMatch::NoMatch => {} } - let pfound = self._find_matching_long_opt(nameend, &mut exact, &mut ambig, &mut indfound); - - if ambig && !exact { - self.nextchar = empty_wstr(); - self.woptind += 1; - *retval = '?'; - return true; - } - - if let Some(pfound) = pfound { - self._update_long_opt(&pfound, nameend, longind, indfound, retval); - return true; - } - - // Can't find it as a long option. If this is not getopt_long_only, or the option starts - // with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a - // short option. - if !long_only - || self.argv[self.woptind].char_at(1) == '-' + // If we can't find a long option, try to interpret it as a short option. + // If it isn't a short option either, return an error. + if self.argv[self.wopt_index].char_at(1) == '-' || !self .shortopts .as_char_slice() - .contains(&self.nextchar.char_at(0)) + .contains(&self.remaining_text.char_at(0)) { - self.nextchar = empty_wstr(); - self.woptind += 1; - *retval = '?'; - return true; + self.remaining_text = empty_wstr(); + self.wopt_index += 1; + + return Some('?'); } - return false; + None } - /// Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. + /// Goes through `argv` to try and find options. /// - /// If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option - /// element. The characters of this element (aside from the initial '-') are option characters. If - /// `getopt` is called repeatedly, it returns successively each of the option characters from each of - /// the option elements. + /// Any element that begins with `-` or `--` and is not just `-` or `--` is an option + /// element. The characters of this element (aside from the initial `-` or `--`) are + /// option characters. Repeated calls return each option character successively. /// - /// If `getopt` finds another option character, it returns that character, updating `woptind` and - /// `nextchar` so that the next call to `getopt` can resume the scan with the following option - /// character or ARGV-element. + /// Options that begin with `--` are long-named. Long-named options can be abbreviated + /// so long as the abbreviation is unique or is an exact match for some defined option. /// - /// If there are no more option characters, `getopt` returns `EOF`. Then `woptind` is the index in - /// ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so - /// that those that are not options now come last.) + /// Arguments to options follow their option name, optionally separated by an `=`. /// - /// OPTSTRING is a string containing the legitimate option characters. If an option character is seen - /// that is not listed in OPTSTRING, return '?'. - /// - /// If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text - /// in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg`. - /// Two colons mean an option that wants an optional arg; if there is text in the current - /// ARGV-element, it is returned in `w.woptarg`, otherwise `w.woptarg` is set to zero. - /// - /// If OPTSTRING starts with `-` or `+', it requests different methods of handling the non-option - /// ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - /// - /// Long-named options begin with `--` instead of `-`. Their names may be abbreviated as long as the - /// abbreviation is unique or is an exact match for some defined option. If they have an argument, - /// it follows the option name in the same ARGV-element, separated from the option name by a `=', or - /// else the in next ARGV-element. When `getopt` finds a long-named option, it returns 0 if that - /// option's `flag` field is nonzero, the value of the option's `val` field if the `flag` field is - /// zero. - /// - /// LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. - /// - /// LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a - /// long-named option has been found by the most recent call. - /// - /// If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. - fn _wgetopt_internal(&mut self, longind: &mut usize, long_only: bool) -> Option { + /// `longopt_index` contains the index of the most recent long-named option + /// found by the most recent call. Returns the next short-named option if + /// found. + fn wgetopt_inner(&mut self, longopt_index: &mut usize) -> Option { if !self.initialized { - self._wgetopt_initialize(); + self.initialize(); } - self.woptarg = None; - if self.nextchar.is_empty() { - let narg = self._advance_to_next_argv(); - if narg != Some(char::from(0)) { - return narg; + self.woptarg = None; + if self.remaining_text.is_empty() { + match self.next_argv() { + NextArgv::UnpermutedNonOption => return Some(NON_OPTION_CHAR), + NextArgv::Finished => return None, + NextArgv::FoundOption => (), } } - // Decode the current option-ARGV-element. + // We set things up so that `-f` is parsed as a short-named option if there + // is a valid option to match it to, otherwise we parse it as a long-named + // option. We also make sure that `-fu` is *not* parsed as `-f` with + // an arg `u`. + if !self.longopts.is_empty() && self.wopt_index < self.argv.len() { + let arg = self.argv[self.wopt_index]; - // Check whether the ARGV-element is a long option. - // - // If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't - // consider it an abbreviated form of a long option that starts with f. Otherwise there would - // be no way to give the -f short option. - // - // On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do - // consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg - // "u". - // - // This distinction seems to be the most useful approach. - if !self.longopts.is_empty() && self.woptind < self.argc() { - let arg = self.argv[self.woptind]; - - #[allow(clippy::if_same_then_else)] - #[allow(clippy::needless_bool)] - let try_long = if arg.char_at(0) == '-' && arg.char_at(1) == '-' { - // Like --foo - true - } else if long_only && arg.len() >= 3 { - // Like -fu - true - } else if !self.shortopts.as_char_slice().contains(&arg.char_at(1)) { - // Like -f, but f is not a short arg. - true - } else { - false - }; + let try_long = + // matches options like `--foo` + arg.char_at(0) == '-' && arg.char_at(1) == '-' + // matches options like `-f` if `f` is not a valid shortopt. + || !self.shortopts.as_char_slice().contains(&arg.char_at(1)); if try_long { - let mut retval = '\0'; - if self._handle_long_opt(longind, long_only, &mut retval) { - return Some(retval); + let retval = self.handle_long_opt(longopt_index); + if retval.is_some() { + return retval; } } } - return Some(self._handle_short_opt()); + Some(self.handle_short_opt()) } }