argparse: Jump to the next option after an unknown one

Previously, when we got an unknown option with --ignore-unknown, we
would increment woptind but still try to read the same contents.

This means in e.g.

```
argparse -i h -- -ooo -h
```

The `-h` would also be skipped as an option, because after the first
`-o` getopt reads the other two `-o` and skips that many options.

This could be handled more extensively in wgetopt, but the simpler fix
is to just skip to the next argv entry once we have an unknown option
- there's nothing more we can do with it anyway!

Additionally, document this and clearly explain that we currently
don't transform the option.

Fixes #8637
This commit is contained in:
Fabian Homborg 2022-01-15 12:17:43 +01:00
parent 8e60f1b4a3
commit 0781473564
3 changed files with 29 additions and 0 deletions

View File

@ -184,3 +184,18 @@ Some OPTION_SPEC examples:
After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero. After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero.
If an error occurs during argparse processing it will exit with a non-zero status and print error messages to stderr. If an error occurs during argparse processing it will exit with a non-zero status and print error messages to stderr.
Limitations
-----------
One limitation with **--ignore-unknown** is that, if an unknown option is given in a group with known options, the entire group will be kept in $argv. ``argparse`` will not do any permutations here.
For instance::
argparse --ignore-unknown h -- -ho
echo $_flag_h # is -h, because -h was given
echo $argv # is still -ho
This limitation may be lifted in future.
Additionally, it can only parse known options up to the first unknown option in the group - the unknown option could take options, so it isn't clear what any character after an unknown option means.

View File

@ -596,6 +596,9 @@ static int argparse_parse_flags(parser_t &parser, argparse_cmd_opts_t &opts,
opts.argv.push_back(arg_contents - 1); opts.argv.push_back(arg_contents - 1);
// Work around weirdness with wgetopt, which crashes if we `continue` here. // Work around weirdness with wgetopt, which crashes if we `continue` here.
if (w.woptind == argc) break; if (w.woptind == argc) break;
// Explain to wgetopt that we want to skip to the next arg,
// because we can't handle this opt group.
w.nextchar = nullptr;
} }
if (retval != STATUS_CMD_OK) return retval; if (retval != STATUS_CMD_OK) return retval;
long_idx = -1; long_idx = -1;

View File

@ -498,3 +498,14 @@ begin
#CHECKERR: ^ #CHECKERR: ^
#CHECKERR: (Type 'help argparse' for related documentation) #CHECKERR: (Type 'help argparse' for related documentation)
end end
begin
argparse --ignore-unknown h i -- -hoa -oia
echo -- $argv
#CHECK: -hoa -oia
echo $_flag_h
#CHECK: -h
set -q _flag_i
or echo No flag I
#CHECK: No flag I
end