If a non-positional argument doesn't get the number of required values,
a generic "Too few arguments" error is generated, without its name, when
it is not the last argument (but if it is the last argument, we get its
name)
This bug [1] causes GCC to emit a wrong warning when adding a short
string literal to a std::string. Wrapping the literal in a std::string
doesn't have a large impact and avoids the warning.
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
The argparse.hpp copy inside GDAL has caused Coverity Scan to emit a
(false-positive) warning about x not being initialized.
```
________________________________________________________________________________________________________
*** CID 1544814: Uninitialized variables (UNINIT)
/gdal/apps/argparse/argparse.hpp: 257 in gdal_argparse::details::do_from_chars<unsigned char, (int)10>(std::basic_string_view<char, std::char_traits<char>>)()
251 if (ec == std::errc::invalid_argument) {
252 throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"};
253 }
254 if (ec == std::errc::result_out_of_range) {
255 throw std::range_error{"'" + std::string(s) + "' not representable"};
256 }
>>> CID 1544814: Uninitialized variables (UNINIT)
>>> Using uninitialized value "x".
```
Let's initialize it to 0 to make the analyzer happy
- Display mutually exclusive arguments as ``[[-a]|[-b]]`` in usage
- Add ... trailer to repeatable arguments in usage: ``[-x]...``
- Implement the following enhancements:
By default usage is reported on a single line.
The ``ArgumentParser::set_usage_max_line_width(width)`` method can be used
to display the usage() on multiple lines, by defining the maximum line width.
It can be combined with a call to ``ArgumentParser::set_usage_break_on_mutex()``
to ask grouped mutually exclusive arguments to be displayed on a separate line.
``ArgumentParser::add_usage_newline()`` can also be used to force the next
argument to be displayed on a new line in the usage output.
The following snippet
```cpp
argparse::ArgumentParser program("program");
program.set_usage_max_line_width(80);
program.set_usage_break_on_mutex();
program.add_argument("--quite-long-option-name").flag();
auto &group = program.add_mutually_exclusive_group();
group.add_argument("-a").flag();
group.add_argument("-b").flag();
program.add_argument("-c").flag();
program.add_argument("--another-one").flag();
program.add_argument("-d").flag();
program.add_argument("--yet-another-long-one").flag();
program.add_argument("--will-go-on-new-line").flag();
program.add_usage_newline();
program.add_argument("--new-line").flag();
std::cout << program.usage() << std::endl;
```
will display:
```console
Usage: program [--help] [--version] [--quite-long-option-name]
[[-a]|[-b]]
[-c] [--another-one] [-d] [--yet-another-long-one]
[--will-go-on-new-line]
[--new-line]
```
Furthermore arguments can be separated into several groups by calling
``ArgumentParser::add_group(group_name)``. Only optional arguments should
be specified after the first call to add_group().
```cpp
argparse::ArgumentParser program("program");
program.set_usage_max_line_width(80);
program.add_argument("-a").flag().help("help_a");
program.add_group("Advanced options");
program.add_argument("-b").flag().help("help_b");
```
will display:
```console
Usage: program [--help] [--version] [-a]
Advanced options:
[-b]
```
Both changes are needed in the special case of GDAL where our existing
hand-made argument parser accepts positional arguments placed anywhere
in the arguments, not just after optional arguments.
In the GDAL code, in 8bb3455eed (diff-4592e7daae8543536dbeadf05a3c110282ea0fc089216186138c923a0d4d8000R170) ,
I've implemented a preliminary pass before calling
ArgumentParser::process_args() that re-order arguments. For that, I need
to be able to call consume() but without side-effects (dry_run=False)
and accept members that are private