Implemented support for parsing both positional and optional arguments

This commit is contained in:
Pranav Srinivas Kumar 2019-03-30 21:09:05 -04:00
parent d7d1880fe6
commit 996f7882ca
3 changed files with 68 additions and 1 deletions

View File

@ -140,7 +140,8 @@ struct Argument {
class ArgumentParser { class ArgumentParser {
public: public:
ArgumentParser(const std::string& aProgramName) : ArgumentParser(const std::string& aProgramName) :
mProgramName(aProgramName) {} mProgramName(aProgramName),
mNextPositionalArgument(0) {}
template<typename T, typename... Targs> template<typename T, typename... Targs>
Argument& add_argument(T value, Targs... Fargs) { Argument& add_argument(T value, Targs... Fargs) {
@ -196,6 +197,25 @@ class ArgumentParser {
else { else {
// This is a positional argument. // This is a positional argument.
// Parse and save into mPositionalArguments vector // Parse and save into mPositionalArguments vector
auto tArgument = mPositionalArguments[mNextPositionalArgument];
auto tCount = tArgument->mNumArgs;
while (tCount > 0) {
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;
} }
} }
} }
@ -238,6 +258,7 @@ class ArgumentParser {
std::string mProgramName; std::string mProgramName;
std::vector<std::shared_ptr<Argument>> mPositionalArguments; std::vector<std::shared_ptr<Argument>> mPositionalArguments;
size_t mNextPositionalArgument;
std::map<std::string, std::shared_ptr<Argument>> mArgumentMap; std::map<std::string, std::shared_ptr<Argument>> mArgumentMap;
}; };

View File

@ -3,3 +3,4 @@
#include <argparse.hpp> #include <argparse.hpp>
#include <test_add_argument.hpp> #include <test_add_argument.hpp>
#include <test_parse_args.hpp> #include <test_parse_args.hpp>
#include <test_positional_arguments.hpp>

View File

@ -0,0 +1,45 @@
#pragma once
#include <catch.hpp>
#include <argparse.hpp>
TEST_CASE("Parse positional arguments", "[parse_args]") {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output");
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv" });
auto arguments = program.get_arguments();
REQUIRE(arguments.size() == 2);
REQUIRE(program.get("input") == "rocket.mesh");
REQUIRE(program.get("output") == "thrust_profile.csv");
}
TEST_CASE("Parse positional arguments with fixed nargs", "[parse_args]") {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output").nargs(2);
program.parse_args({ "test", "rocket.mesh", "thrust_profile.csv", "output.mesh" });
auto arguments = program.get_arguments();
REQUIRE(arguments.size() == 2);
REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output");
REQUIRE(outputs.size() == 2);
REQUIRE(outputs[0] == "thrust_profile.csv");
REQUIRE(outputs[1] == "output.mesh");
}
TEST_CASE("Parse positional arguments with optional arguments", "[parse_args]") {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("output").nargs(2);
program.add_argument("--num_iterations")
.action([](const std::string& value) { return std::stoi(value); });
program.parse_args({ "test", "rocket.mesh", "--num_iterations", "15", "thrust_profile.csv", "output.mesh" });
auto arguments = program.get_arguments();
REQUIRE(arguments.size() == 3);
REQUIRE(program.get<int>("--num_iterations") == 15);
REQUIRE(program.get("input") == "rocket.mesh");
auto outputs = program.get<std::vector<std::string>>("output");
REQUIRE(outputs.size() == 2);
REQUIRE(outputs[0] == "thrust_profile.csv");
REQUIRE(outputs[1] == "output.mesh");
}