After upgrading g++ package to 12.1.0 on archlinux I see the following
compilation error:
/usr/include/argparse/argparse.hpp: In member function ‘void argparse::ArgumentParser::index_argument(list_iterator)’:
/usr/include/argparse/argparse.hpp:1167:34: error: ‘as_const’ is not a member of ‘std’; did you mean ‘is_const’?
1167 | for (const auto &name : std::as_const(it->m_names)) {
| ^~~~~~~~
| is_const
It turns out that std::as_const comes from <utility> header [1] which
was not explicitly included.
[1] https://en.cppreference.com/w/cpp/utility/as_const
As far as I can tell, this statement is never true.
When m_values.size() < *expected, ::consume has already thrown "Too few
arguments..." before ::validate is called.
When m_values.size() > *expected, ArgumentParser::parse_args_internal
has already thrown "Maximum number of positional arguments exceeded"
before ::validate is called.
If ::remaining is used to avoid the last exception, this Argument will
always consume the expected number of values, hence this expression is
again false.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
This regression was caused by commit
ea1f7ef663, which didn't add "\n" to the
version printing statement. We use std::endl now for compatibility
across platforms.
The 'unused' variable in both cases is most-definitely unused in the loop.
This is a cppcheck warning that appeared after moving these two loops to
range-for.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
This code was previously moved from ::parse_args to its own method, but
has since been simplified. Moving the actual work to Argument::validate
in commit 603e87ae6 leaves a single loop that fits back into ::parse_args.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
The new naming pattern is CamelCase for structs, except parse_number as a
primarily callable interface. Trait structs are named Has*Traits
and constexpr variables to the struct template are named Is*.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Most changes are to better fit within "ColumnLimit: 80".
The change from "T &&... var" to "T &&...var" is caused by
"PointerAlignment: Right".
Member functions chained from add_argument() use ContinuationIndentWidth,
which is set to 4. Setting ContinuationIndentWidth to 2 causes many
other continuation lines to change. So, this commit uses the original
value (i.e. 4) as the preferred size.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Also converts most C-style arrays to a std::array onjects. The check is
disabled for ArgumentParser::parse_args(int, const char *const[]) as this
is a helper function to convert away from a common input format.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
A common pattern in the previous code was goto/return/throw if a condition
is true, else goto/return/throw something different. The new pattern
uses the fact that the second goto/return/throw is only reachable when the
first goto/return/throw is not called.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Following the clang-tidy suggested fix in consume_digits causes compile
failures with MSVC 19.29 in our CI.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Adds names recommended by clang-tidy (e.g. "unused").
Note that clang-tidy v12 appears to detect unnamed parameters in lambdas,
while clang-tidy v13 does not.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
operator& should return combined values of the same type, not a new type
(i.e. bool). This is much more verbose, but easier to reason about
without implied conversion.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
cppcheck reports "Variable 'sen' is assigned a value that is never used.
[unreadVariable]" for this line.
As far as I understand, std::ostream::sentry is used to prepare access to
the stream buffer. But, we are never directly accessing the stream
buffer. Stream access in this function uses other operator<< functions.
Most noise in this patch is about unindenting after if() removal.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
These were respectively reported as constParameter and functionConst
style issues by cppcheck.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Now message contains information which argument is the source of error.
It's easier to spot typo/understand which part of more complex command
is the source of problem.
The help and version arguments are still included by default, but which
default arguments to include can be overridden at ArgumentParser creation.
argparse generally copies Python argparse behavior. This includes a
default `--help`/`-h` argument to print a help message and exit. Some
developers using argparse find the automatic exit to be undesirable.
The Python argparse has an opt-out parameter when constructing an
ArgumentParser. Using `add_help=False` avoids adding a default `--help`
argument and allows the developer to implement a custom help.
This commit adds a similar opt-out to our C++ argparse, but keeps the
current behavior as the default. The `--help`/`-h` and `--version`/`-v`
Arguments handle their own output and exit rather than specially treating
them in ArgumentParser::parse_args_internal.
Closes#119Closes#138Closes#139
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Previously, only arguments with one or more parameters would run actions.
But, at times it can be useful to run an action when an argument does not
expect any parameters.
Closes#104
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
These variables with the same name are not the same variables because of
scope rules. While the compiler is not confused by this naming, it may
be less readable by someone attempting to edit this code.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
MSVC 19.16 appears to be doing a copy rather than a move in
test_const_correct. The copy ctor does not handle mIsParsed, so the
initial false value is kept. This commit adds copying mIsParsed during
copy construction.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
I reimplemented remaining() method for backward compatibility.
It consumes "all" remaining args.
So, I added mAcceptsOptionalLikeValue flag and handle it by using this
flag.
Currently, remaining() behavior is slightly different from the original when no
args are provided and get<Container<T>>() method is called.
Originally it raises an exception. But current implementation returns
an empty container instead of exception.
It is possible to implement complete backward compatibility by
referencing mAcceptsOptionalLikeValue flag and raises an exception in get() method,
but I did not do this.
I think that is too much.
To handle variable length nargs, I replaced mNumArgs with mNumArgsRange.
I defined SizeRange class for mNumArgsRange, which has simply min and
max std::size_t member.
To concentrate on this big change, I tentatively deleted remaining
feature, which was originally implemented in the way that mNumArgs = -1
internally and maybe_args() -> Optional wrap method.
Library users may make use of 4 types of interface to set
mNumArgsRange.
1. nargs(std::size_t)
2. nargs(std::size_t, std::size_t)
3. nargs(SizeRange)
4. nargs(NArgsPattern)
1. is expected to behave same as original. This mthod sets min=max
SizeRange to mNumArgsRange, which is actually, not a range, but an
"exact" number.
2. sets min and max.
3. uses SizeRange class. This interface may be unnecessary. It is also
an option to delete this method and make SizeRange class internal.
4. is provided to set common patterns. In Python, they are "?", "*" and
"+". NArgsPattern is an enum class for type safety. std::string
interface is also an option to mimic Python argparse. char interface
would be ambiguous with 1.
Changes on consume method is important.
The parser tries to consume args until the count reaches mNumArgsRanges::max or
it meets another optional like string.
If consumed args count is under mNumArgsRanges::min, the parser fails.
Now, when the required number of arguments are not provided, the parser
will fail.
So, we have to take care of get() method as well.
get() failed when argument count is 0 and default value not provided.
But now there are 0..1 or 0..* nargs are OK.
So this behaviour has to be fixed.
When T is container_v, it returns empty container.
I implemented validate method so that it shows kind message.
If the developer forgot to call ArgumentParser::parse_args<>, attempts to
use ::get, ::present, etc., would raise "No value provided...". With this
change, the error better describes what went wrong.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Here, the user gave an argument name but failed to provide the required
parameters to the argument. Tell the user which argument wants more.
This is an API change that may affect programs trying to match the
specific "Too few arguments" message. The new error message appends the
user-supplied argument that caused the error.
A solution which works with both versions is to look for "Too few
arguments" at the beginning of the error message.
- if (err.what() == "Too few arguments")
+ if (std:string(err.what()).rfind("Too few arguments", 0) == 0)
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
As the user did not include the argument, the longest name for the unused
argument is in the last position of mNames.
This is an API change that may affect programs trying to match the
specific "No value provided" message. The new error message appends the
argument that caused the error.
A solution which works with both versions is to look for "No value
provided" at the beginning of the error message.
- if (err.what() == "No value provided")
+ if (std:string(err.what()).rfind("No value provided", 0) == 0)
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
It's too early to use std::chars_format as there is not wide enough
support in stdlib implementations. After the following stdlib become our
supported versions, this can be revisited.
GCC >= 10.1.0
Clang >= 7.0.0 (already our minimum)
MSVC >= 19.4
Reverts commit 1c61082a4c.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
I believe the Supported Toolchains all now include <charconv> (and
std::chars_format) and we can use the stdlib-defined values.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
.present returns std::nullopt if the optional argument is not given by the
user -- as long as a .default_value is not defined. With a .default_value,
.present cannot be used to determine if a value is user-provided or the
default.
.is_used fills that role and only returns true if the argument was passed
by the user.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
The default behavior with optional arguments is to allow only a single use
per invocation. One alternative is to use .nargs, but this requires
previously knowing, and limiting, the quantity of values. The .append
method removes the restriction on repeats for a single Argument.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
While the implicit conversions from `1` to `true` work correctly, this
avoids the conversions.
Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
Previously, it printed ": expected 1 argument(s). 0 provided." when one positional argument is defined but nothing is provided. Now it prints "1 argument(s) expected. 0 provided."
Two differences that diverge from the existing behavior:
1. Leading zeros are not allowed for integers. Negative
octal numbers such as `-066` are not meant to be treated
as positional arguments, but existing code recognize them
as decimal numbers. Note that negative floating-point
numbers with leading zeros (`-003.`) are unambiguous and
are recognized.
2. Inf and NaN are not recognized. This is because options
like `-inf` is indistinguishable from a compound argument
that meant to be a shorthand for `-i -n -f`.
fixes: p-ranav/argparse#55
The change also fixes a rare bug introduced in 9007958:
when there are duplicated keys, insert_or_update overrides
previously inserted ones, emplace doesn't.
fixes: p-ranav/argparse#59
Before this change:
1. When the input is built-in string literal or cv-`char*`,
`is_optional` constructs temporary `std::string` while
`mNames` initializer is also constructing `std::string`
due to the use of `std::initializer_list`.
2. When the input is `std::string_view`, doesn't compile.
3. When the input is `std::string`, `mNames` initializer
moves `args`. If argument name is longer than
`std::string`'s SSO buffer, bad thing will happen because
`is_optional` will be accessing `args` in moved-from
states.
Because of the use of `strtol` which expects nul-terminated
input, `is_*` series functions must take `std::string`. This
restriction may be removed after AppleClang adds `<charconv>`.
But for now, it complicates the patch. My solution is to
create an array prvalue still, but use a array reference
rather than `std::initializer_list` to refer to it, so that
the code in delegated constructor can keep using fold
expressions after the necessary `std::string` objects being
created.