mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 07:04:39 +00:00
Added support for compound arguments, e.g., ./main -aux foo bar
This commit is contained in:
parent
41009046f2
commit
07cad7ac9e
@ -70,6 +70,7 @@ struct Argument {
|
|||||||
|
|
||||||
Argument& implicit_value(std::any aImplicitValue) {
|
Argument& implicit_value(std::any aImplicitValue) {
|
||||||
mImplicitValue = aImplicitValue;
|
mImplicitValue = aImplicitValue;
|
||||||
|
mNumArgs = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ class ArgumentParser {
|
|||||||
add_argument_internal(tArgument, Fargs...);
|
add_argument_internal(tArgument, Fargs...);
|
||||||
|
|
||||||
for (auto& mName : tArgument->mNames) {
|
for (auto& mName : tArgument->mNames) {
|
||||||
if (starts_with(mName, "--") || starts_with(mName, "-"))
|
if (is_optional(mName))
|
||||||
tArgument->mIsOptional = true;
|
tArgument->mIsOptional = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,8 +190,8 @@ class ArgumentParser {
|
|||||||
// Check to see if implicit value should be used
|
// Check to see if implicit value should be used
|
||||||
// Two cases to handle here:
|
// Two cases to handle here:
|
||||||
// (1) User has explicitly programmed nargs to be 0
|
// (1) User has explicitly programmed nargs to be 0
|
||||||
// (2) User has left nargs to be default, i.e., 1 and provided an implicit value
|
// (2) User has provided an implicit value, which also sets nargs to 0
|
||||||
if (tCount == 0 || (tArgument->mImplicitValue.has_value() && tCount == 1)) {
|
if (tCount == 0) {
|
||||||
// Use implicit value for this optional argument
|
// Use implicit value for this optional argument
|
||||||
tArgument->mValues.push_back(tArgument->mImplicitValue);
|
tArgument->mValues.push_back(tArgument->mImplicitValue);
|
||||||
tArgument->mRawValues.push_back("");
|
tArgument->mRawValues.push_back("");
|
||||||
@ -213,32 +214,57 @@ class ArgumentParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This is a positional argument.
|
if (is_optional(argv[i])) {
|
||||||
// Parse and save into mPositionalArguments vector
|
// This is possibly a compound optional argument
|
||||||
auto tArgument = mPositionalArguments[mNextPositionalArgument];
|
// Example: We have three optional arguments -a, -u and -x
|
||||||
auto tCount = tArgument->mNumArgs - tArgument->mRawValues.size();
|
// The user provides ./main -aux ...
|
||||||
while (tCount > 0) {
|
// Here -aux is a compound optional argument
|
||||||
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(argv[i]);
|
std::string tCompoundArgument = std::string(argv[i]);
|
||||||
if (tIterator != mArgumentMap.end()) {
|
for (size_t j = 1; j < tCompoundArgument.size(); j++) {
|
||||||
i = i - 1;
|
std::string tArgument(1, tCompoundArgument[j]);
|
||||||
break;
|
size_t tNumArgs = 0;
|
||||||
}
|
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find("-" + tArgument);
|
||||||
if (i < argc) {
|
if (tIterator != mArgumentMap.end()) {
|
||||||
tArgument->mRawValues.push_back(argv[i]);
|
auto tArgumentObject = tIterator->second;
|
||||||
if (tArgument->mAction != nullptr)
|
tNumArgs = tArgumentObject->mNumArgs;
|
||||||
tArgument->mValues.push_back(tArgument->mAction(argv[i]));
|
|
||||||
else {
|
|
||||||
if (tArgument->mDefaultValue.has_value())
|
|
||||||
tArgument->mValues.push_back(tArgument->mDefaultValue);
|
|
||||||
else
|
|
||||||
tArgument->mValues.push_back(std::string(argv[i]));
|
|
||||||
}
|
}
|
||||||
|
std::vector<std::string> tArgumentsForRecursiveParsing = { "", "-" + tArgument };
|
||||||
|
while (tNumArgs > 0) {
|
||||||
|
i += 1;
|
||||||
|
tArgumentsForRecursiveParsing.push_back(argv[i]);
|
||||||
|
tNumArgs -= 1;
|
||||||
|
}
|
||||||
|
parse_args(tArgumentsForRecursiveParsing);
|
||||||
}
|
}
|
||||||
tCount -= 1;
|
|
||||||
if (tCount > 0) i += 1;
|
|
||||||
}
|
}
|
||||||
if (tCount == 0)
|
else {
|
||||||
mNextPositionalArgument += 1;
|
// This is a positional argument.
|
||||||
|
// Parse and save into mPositionalArguments vector
|
||||||
|
auto tArgument = mPositionalArguments[mNextPositionalArgument];
|
||||||
|
auto tCount = tArgument->mNumArgs - tArgument->mRawValues.size();
|
||||||
|
while (tCount > 0) {
|
||||||
|
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(argv[i]);
|
||||||
|
if (tIterator != mArgumentMap.end()) {
|
||||||
|
i = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < argc) {
|
||||||
|
tArgument->mRawValues.push_back(argv[i]);
|
||||||
|
if (tArgument->mAction != nullptr)
|
||||||
|
tArgument->mValues.push_back(tArgument->mAction(argv[i]));
|
||||||
|
else {
|
||||||
|
if (tArgument->mDefaultValue.has_value())
|
||||||
|
tArgument->mValues.push_back(tArgument->mDefaultValue);
|
||||||
|
else
|
||||||
|
tArgument->mValues.push_back(std::string(argv[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tCount -= 1;
|
||||||
|
if (tCount > 0) i += 1;
|
||||||
|
}
|
||||||
|
if (tCount == 0)
|
||||||
|
mNextPositionalArgument += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,6 +305,15 @@ class ArgumentParser {
|
|||||||
return *aArgument;
|
return *aArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_optional(const std::string& aName) {
|
||||||
|
return (starts_with(aName, "--") || starts_with(aName, "-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid_argument(const std::string& aName) {
|
||||||
|
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aName);
|
||||||
|
return (tIterator != mArgumentMap.end());
|
||||||
|
}
|
||||||
|
|
||||||
std::string mProgramName;
|
std::string mProgramName;
|
||||||
std::vector<std::shared_ptr<Argument>> mPositionalArguments;
|
std::vector<std::shared_ptr<Argument>> mPositionalArguments;
|
||||||
size_t mNextPositionalArgument;
|
size_t mNextPositionalArgument;
|
||||||
|
@ -24,4 +24,73 @@ TEST_CASE("Parse toggle arguments with implicit value", "[parse_args]") {
|
|||||||
auto arguments = program.get_arguments();
|
auto arguments = program.get_arguments();
|
||||||
REQUIRE(arguments.size() == 1);
|
REQUIRE(arguments.size() == 1);
|
||||||
REQUIRE(program.get<bool>("--verbose") == true);
|
REQUIRE(program.get<bool>("--verbose") == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse multiple toggle arguments with implicit values", "[parse_args]") {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("-a")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-u")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-x")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.parse_args({ "./test.exe", "-a", "-x" });
|
||||||
|
auto arguments = program.get_arguments();
|
||||||
|
REQUIRE(arguments.size() == 3);
|
||||||
|
REQUIRE(program.get<bool>("-a") == true);
|
||||||
|
REQUIRE(program.get<bool>("-u") == false);
|
||||||
|
REQUIRE(program.get<bool>("-x") == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse compound toggle arguments with implicit values", "[parse_args]") {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("-a")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-u")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-x")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.parse_args({ "./test.exe", "-aux" });
|
||||||
|
auto arguments = program.get_arguments();
|
||||||
|
REQUIRE(arguments.size() == 3);
|
||||||
|
REQUIRE(program.get<bool>("-a") == true);
|
||||||
|
REQUIRE(program.get<bool>("-u") == true);
|
||||||
|
REQUIRE(program.get<bool>("-x") == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse compound toggle arguments with implicit values and nargs", "[parse_args]") {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("-a")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-b")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-c")
|
||||||
|
.nargs(2)
|
||||||
|
.action([](const std::string& value) { return std::stof(value); });
|
||||||
|
|
||||||
|
program.parse_args({ "./test.exe", "-abc", "3.14", "2.718" });
|
||||||
|
auto arguments = program.get_arguments();
|
||||||
|
REQUIRE(arguments.size() == 3);
|
||||||
|
REQUIRE(program.get<bool>("-a") == true);
|
||||||
|
REQUIRE(program.get<bool>("-b") == true);
|
||||||
|
auto c = program.get<std::vector<float>>("-c");
|
||||||
|
REQUIRE(c.size() == 2);
|
||||||
|
REQUIRE(c[0] == 3.14f);
|
||||||
|
REQUIRE(c[1] == 2.718f);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user