Rewrite wgetopt.rs to Rustier syntax and naming

From https://github.com/fish-shell/fish-shell/pull/9515

Closes #9515
This commit is contained in:
Verte 2024-04-17 11:10:18 -07:00 committed by ridiculousfish
parent 2e42d80dc9
commit 13230cdda0
49 changed files with 1005 additions and 1112 deletions

View File

@ -313,44 +313,40 @@ fn run_command_list(parser: &Parser, cmds: &[OsString]) -> i32 {
}
fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> ControlFlow<i32, usize> {
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<i
'?' => {
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) == '-';

View File

@ -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<WString> = 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 {

View File

@ -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<i32> {
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<WString> = 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<i32> {
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<i32> {
}
}
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);

View File

@ -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());
}

View File

@ -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<woption<'args>>,
long_options: &mut Vec<WOption<'args>>,
) {
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<c_int> {
@ -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>(

View File

@ -451,23 +451,23 @@ fn parse_cmd_opts(
) -> Option<i32> {
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;
}

View File

@ -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.

View File

@ -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;

View File

@ -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())

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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<c_int> {
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
}

View File

@ -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<c_int> {
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
}

View File

@ -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) {

View File

@ -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`.

View File

@ -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},
};

View File

@ -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);

View File

@ -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<c_int> {
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));

View File

@ -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

View File

@ -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<c_int>> {
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

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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,
})
}
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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");

View File

@ -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()

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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:");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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:");

View File

@ -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 {

View File

@ -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");

View File

@ -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()

View File

@ -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 {

View File

@ -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;

View File

@ -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<WaitHandleRef> = Vec::new();
let optind = w.woptind;
let optind = w.wopt_index;
for item in &argv[optind..argc] {
if iswnumeric(item) {
// argument is pid

View File

@ -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());
}
}

View File

@ -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<char> {
assert!(self.woptind <= self.argc(), "woptind is out of range");
/// Try to get the next option.
pub fn next_opt(&mut self) -> Option<char> {
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<char> {
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<usize>)> {
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<char> {
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<woption<'opts>> {
let mut pfound: Option<woption> = 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<char> {
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<char> {
/// `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<char> {
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())
}
}