mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 23:24:39 +00:00
First bit of error checking - Cleaned up parse_args methods - Added parse_args_validate() method that checks if all positional arguments have been provided or not and prints help
This commit is contained in:
parent
6a4c92726b
commit
70c2fcfdf1
222
src/argparse.hpp
222
src/argparse.hpp
@ -275,108 +275,13 @@ class ArgumentParser {
|
||||
}
|
||||
|
||||
void parse_args(const std::vector<std::string>& aArguments) {
|
||||
std::vector<char*> argv;
|
||||
for (const auto& arg : aArguments)
|
||||
argv.push_back((char*)arg.data());
|
||||
argv.push_back(nullptr);
|
||||
return parse_args(argv.size() - 1, argv.data());
|
||||
parse_args_internal(aArguments);
|
||||
parse_args_validate();
|
||||
}
|
||||
|
||||
void parse_args(int argc, char * argv[]) {
|
||||
if (mProgramName == "" && argc > 0)
|
||||
mProgramName = argv[0];
|
||||
for (int i = 1; i < argc; i++) {
|
||||
auto tCurrentArgument = std::string(argv[i]);
|
||||
if (tCurrentArgument == "-h" || tCurrentArgument == "--help") {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(argv[i]);
|
||||
if (tIterator != mArgumentMap.end()) {
|
||||
// Start parsing optional argument
|
||||
auto tArgument = tIterator->second;
|
||||
auto tCount = tArgument->mNumArgs;
|
||||
|
||||
// Check to see if implicit value should be used
|
||||
// Two cases to handle here:
|
||||
// (1) User has explicitly programmed nargs to be 0
|
||||
// (2) User has provided an implicit value, which also sets nargs to 0
|
||||
if (tCount == 0) {
|
||||
// Use implicit value for this optional argument
|
||||
tArgument->mValues.push_back(tArgument->mImplicitValue);
|
||||
tArgument->mRawValues.push_back("");
|
||||
tCount = 0;
|
||||
}
|
||||
while (tCount > 0) {
|
||||
i = i + 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_optional(argv[i])) {
|
||||
// This is possibly a compound optional argument
|
||||
// Example: We have three optional arguments -a, -u and -x
|
||||
// The user provides ./main -aux ...
|
||||
// Here -aux is a compound optional argument
|
||||
std::string tCompoundArgument = std::string(argv[i]);
|
||||
for (size_t j = 1; j < tCompoundArgument.size(); j++) {
|
||||
std::string tArgument(1, tCompoundArgument[j]);
|
||||
size_t tNumArgs = 0;
|
||||
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find("-" + tArgument);
|
||||
if (tIterator != mArgumentMap.end()) {
|
||||
auto tArgumentObject = tIterator->second;
|
||||
tNumArgs = tArgumentObject->mNumArgs;
|
||||
}
|
||||
std::vector<std::string> tArgumentsForRecursiveParsing = { "", "-" + tArgument };
|
||||
while (tNumArgs > 0) {
|
||||
i += 1;
|
||||
tArgumentsForRecursiveParsing.push_back(argv[i]);
|
||||
tNumArgs -= 1;
|
||||
}
|
||||
parse_args(tArgumentsForRecursiveParsing);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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() || is_optional(argv[i])) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_args_internal(argc, argv);
|
||||
parse_args_validate();
|
||||
}
|
||||
|
||||
template <typename T = std::string>
|
||||
@ -508,6 +413,125 @@ class ArgumentParser {
|
||||
return (tIterator != mArgumentMap.end());
|
||||
}
|
||||
|
||||
void parse_args_internal(const std::vector<std::string>& aArguments) {
|
||||
std::vector<char*> argv;
|
||||
for (const auto& arg : aArguments)
|
||||
argv.push_back((char*)arg.data());
|
||||
argv.push_back(nullptr);
|
||||
return parse_args_internal(argv.size() - 1, argv.data());
|
||||
}
|
||||
|
||||
void parse_args_internal(int argc, char * argv[]) {
|
||||
if (mProgramName == "" && argc > 0)
|
||||
mProgramName = argv[0];
|
||||
for (int i = 1; i < argc; i++) {
|
||||
auto tCurrentArgument = std::string(argv[i]);
|
||||
if (tCurrentArgument == "-h" || tCurrentArgument == "--help") {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(argv[i]);
|
||||
if (tIterator != mArgumentMap.end()) {
|
||||
// Start parsing optional argument
|
||||
auto tArgument = tIterator->second;
|
||||
auto tCount = tArgument->mNumArgs;
|
||||
|
||||
// Check to see if implicit value should be used
|
||||
// Two cases to handle here:
|
||||
// (1) User has explicitly programmed nargs to be 0
|
||||
// (2) User has provided an implicit value, which also sets nargs to 0
|
||||
if (tCount == 0) {
|
||||
// Use implicit value for this optional argument
|
||||
tArgument->mValues.push_back(tArgument->mImplicitValue);
|
||||
tArgument->mRawValues.push_back("");
|
||||
tCount = 0;
|
||||
}
|
||||
while (tCount > 0) {
|
||||
i = i + 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_optional(argv[i])) {
|
||||
// This is possibly a compound optional argument
|
||||
// Example: We have three optional arguments -a, -u and -x
|
||||
// The user provides ./main -aux ...
|
||||
// Here -aux is a compound optional argument
|
||||
std::string tCompoundArgument = std::string(argv[i]);
|
||||
for (size_t j = 1; j < tCompoundArgument.size(); j++) {
|
||||
std::string tArgument(1, tCompoundArgument[j]);
|
||||
size_t tNumArgs = 0;
|
||||
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find("-" + tArgument);
|
||||
if (tIterator != mArgumentMap.end()) {
|
||||
auto tArgumentObject = tIterator->second;
|
||||
tNumArgs = tArgumentObject->mNumArgs;
|
||||
}
|
||||
std::vector<std::string> tArgumentsForRecursiveParsing = { "", "-" + tArgument };
|
||||
while (tNumArgs > 0) {
|
||||
i += 1;
|
||||
tArgumentsForRecursiveParsing.push_back(argv[i]);
|
||||
tNumArgs -= 1;
|
||||
}
|
||||
parse_args_internal(tArgumentsForRecursiveParsing);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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() || is_optional(argv[i])) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_args_validate() {
|
||||
// Check if all positional arguments are parsed
|
||||
for (size_t i = 0; i < mPositionalArguments.size(); i++) {
|
||||
auto tArgument = mPositionalArguments[i];
|
||||
if (tArgument->mValues.size() != tArgument->mNumArgs) {
|
||||
std::cout << "error: " << tArgument->mNames[0] << ": expected "
|
||||
<< tArgument->mNumArgs << " arguments. "
|
||||
<< tArgument->mValues.size() << " provided.\n" << std::endl;
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_length_of_longest_argument() {
|
||||
size_t tResult = 0;
|
||||
for (size_t i = 0; i < mPositionalArguments.size(); i++) {
|
||||
|
@ -30,20 +30,20 @@ TEST_CASE("Parse list of arguments", "[vector]") {
|
||||
|
||||
TEST_CASE("Parse list of arguments with default values", "[vector]") {
|
||||
argparse::ArgumentParser program("test");
|
||||
program.add_argument("input")
|
||||
program.add_argument("--input")
|
||||
.default_value(std::list<int>{1, 2, 3, 4, 5})
|
||||
.nargs(2);
|
||||
.nargs(5);
|
||||
|
||||
program.parse_args({ "test" });
|
||||
|
||||
auto inputs = program.get<std::list<int>>("input");
|
||||
auto inputs = program.get<std::list<int>>("--input");
|
||||
REQUIRE(inputs.size() == 5);
|
||||
REQUIRE(argparse::get_from_list(inputs, 0) == 1);
|
||||
REQUIRE(argparse::get_from_list(inputs, 1) == 2);
|
||||
REQUIRE(argparse::get_from_list(inputs, 2) == 3);
|
||||
REQUIRE(argparse::get_from_list(inputs, 3) == 4);
|
||||
REQUIRE(argparse::get_from_list(inputs, 4) == 5);
|
||||
REQUIRE(program["input"] == std::list<int>{1, 2, 3, 4, 5});
|
||||
REQUIRE(program["--input"] == std::list<int>{1, 2, 3, 4, 5});
|
||||
}
|
||||
|
||||
TEST_CASE("Parse list of arguments and save in an object", "[vector]") {
|
||||
|
Loading…
Reference in New Issue
Block a user