getopt2 - strict command line argument parser for Rust
======================================================
*Version 0.1.0* [MIT Licensed](https://spdx.org/licenses/MIT.html)
[](https://spdx.org/licenses/MIT.html)
[](https://crates.io/crates/getopt2)
[](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html)
[](https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html)
[](https://deps.rs/repo/gitlab/hsn10/getopt2)
[](https://docs.rs/getopt2)
[](https://crates.io/crates/getopt2/versions)
[](https://github.com/XAMPPRocky/tokei)
Features
--------
1. Simple argument parsing rules:
1. Unrecognised options or options with required value missing
are parsed as positional arguments.
1. No multiple options without an argument grouping together ("-abc") allowed.
1. No attaching value to the option without space ("-aValue").
1. GNU argument parsing rules by default. Options can be anywhere in command line before "--"
1. POSIX parsing rules activated by "+" extension or by setting the POSIXLY_CORRECT
environment variable.
In POSIX mode first non option stops option parsing. ("+a:")
1. Double dash "--" support. Anything after "--" is not treated as options.
1. If double dash follows an option with required argument, its used as option value, not a separator.
1. If double dash follows an option with optional argument, its parsed as separator.
1. Optional arguments support extension "::".
1. Original the "::" limitation:
1. The GNU "a::" syntax only supports the option value being immediately attached
to the flag (-aValue1). It does not support a space ("-a Value1").
1. Because *getopt2* do not supports attached values, space is used
for optional argument value separation.
1. Compatibility with ":" extension - allow to use "?" as option character.
Can be combined with POSIX mode as "+:".
### Code quality
1. [MSRV 1.56](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0/), accessible from entire *Rust 2021 Edition*.
1. Based on [getopt3 crate](https://crates.io/crates/getopt3).
1. Small code size. 270 LOC.
1. Zero dependencies.
1. No `unsafe` Rust.
1. Runs on *stable 2021 Edition Rust*.
1. 100 unit tests, 7 integration tests, and 7 doc tests.
Usage
-----
#### 1. Create getopt instance
let g = **getopt2::new**(_arguments_, _optstring_)
getopt2::new constructor arguments:
1. _arguments_ command line arguments. Can be anything what can be converted to
Iterator over String. You can use `std::env::args()` but you need to skip first
argument because its executable name. It can be done manually by `.skip(1)`
or by calling `hideBin` utility function which strips its first argument.
2. _optstring_ is a anything providing `AsRef <str>`. optstring is containing the legitimate option characters.
Valid option characters are alphanumeric plus '?'.
If such a character is followed by a colon, the option requires an
argument. If character is followed by a double collon, argument is
optional and space is used for argument separation.
##### Returned value:
1. Function returns `Result <getopt>`.
2. `Result` wraps parsing errors and *getopt* structure.
3. Parsing can fail *only if* optstring is invalid.
4. If required argument is missing function *new()* won't fail.
Call *validate()* on parsed result for optional strict argument checking.
#### 2. Check parsed options
*getopt* structure returned by constructor has following public members:
1. _arguments_ : `Vec <String>` command line arguments with options removed.
2. _options_map_ : `HashMap <char, argument>` map of recognized options.
Maps option character to argument enum.
3. _options_ : `HashMap <char, String>` options parsed.
If option do not have argument, it is mapped to empty "" `String`,
otherwise it is mapped to its argument as `String`.
Structure *getopt* supports `IntoIterator` and can transform itself into `Iterator`
over supplied command line arguments.
It supports consuming itself or use self immutable reference for enumerating arguments.
*getopt.iter()* returns `Iterator` over pub field _arguments_ without consuming itself.
*getopt.len()* returns number of command line arguments.
It's convience shortcut for *getopt.arguments.len()*.
*getopt.get()* returns value of command line option.
It's convience shortcut for *getopt.options.get()*.
*getopt.has()* returns if option got supplied on command line.
It's convience shortcut for *getopt.options.contains_key()*.
*getopt\[usize\]* returns nth command line argument.
It is a convenience shortcut for *getopt.arguments.index()*.
*getopt.is_empty()* returns if any *arguments* were supplied on command line.
It is a convenience shortcut for *getopt.arguments.is_empty()*.
#### 3. Optional - Check if correct options were provided
You can run strict parse checks by calling *validate(getopt)* function.
This function returns back `Result` with supplied *getopt instance* on success or
error as `String`. It can detect if unknown options were encountered or
required arguments are missing.
Example
-------
```rust
use std::env::args;
use getopt2::hideBin;
let rc = getopt2::new(hideBin(args()), "ab:c");
if let Ok(g) = rc {
// command line options parsed sucessfully
if let Some(arg) = g.options.get(&'b') {
// handle b argument stored in arg
};
};
```
#### Reference
1. [POSIX getopt](https://pubs.opengroup.org/onlinepubs/9799919799/functions/getopt.html) function.
1. [GNU libc getopt](https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html) function.
1. [OpenBSD getopt](https://man.openbsd.org/getopt.3) function.
1. [FreeBSD getopt](https://man.freebsd.org/cgi/man.cgi?query=getopt&apropos=0&sektion=3&arch=default&format=html) function.
#### Implemented getopt extensions
1. GNU getopt parsing rules:
1. Options can be anywhere in command line before --
1. double dash (--) support. Anything after -- is not treated as options.
1. double dash is *eaten by getopt*, not visible to user as argument.
1. POSIX extension in the *getopt* function where the argument string
specification can start with a colon (:). When the option string begins with
a colon, it modifies the behavior of getopt to handle error cases differently.
Specifically, it suppresses the default error messages that getopt prints
when it encounters an unrecognized option or a missing argument,
and it returns ":" instead of "?" for these error cases. This allows using "?" as
option because its possible to spot difference unknown option and "-?" option.
1. Extension is implemented in way that "?" as option is always supported.
":" at start of option string is fully optional and have no effect on
activating this extension.
1. Two colons in optstring (::) indicates that the argument is optional.
This is an extension not covered by POSIX.
1. In GNU getopt, if the option string (optstring) begins with a plus (+) character,
it triggers POSIX-compatible parsing. This means that the first non-option
argument will stop option parsing, similar to how setting the POSIXLY_CORRECT
environment variable behaves. Double dash is still supported in this mode.
#### Crates getopt2 and getopt3 compared
Following table compares crates [getopt3](https://crates.io/crates/getopt3) and
[getopt2](https://crates.io/crates/getopt2).
Both crates parse command line
arguments and have almost identical API. Both parsers won't fail parsing unless *optstring*
is invalid.
Only API difference is that
public struct getopt member _options_map_ is defined as `HashMap <char, argument>` in *getopt2*
while in *getopt3* it is `HashMap <char, bool>`.
Main difference between both parsers is that [getopt2](https://crates.io/crates/getopt2)
turns unrecognised options or options with mandatory argument missing into
positional arguments.
| *GNU* parsing mode | supported | supported |
| *POSIX* parsing mode | supported | not supported |
| *double dash* separator | supported | supported |
| *optional* arguments | supported | not supported |
| getopt (:) extension | always active | always active |
| value can follow option -aValue | not supported | supported |
| grouping multiple options -abc | not supported | supported |
| parsing never fails unless *optstring* is invalid | yes | yes |
| *validate()* for strict checks | yes | yes |
| unknown options | turned into arguments | kept as options |