From 996f7882ca6b5040ed9ac2844b921f23576b2b8e Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Sat, 30 Mar 2019 21:09:05 -0400 Subject: [PATCH] Implemented support for parsing both positional and optional arguments --- src/argparse.hpp | 23 ++++++++++++++- tests/main.cpp | 1 + tests/test_positional_arguments.hpp | 45 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/test_positional_arguments.hpp diff --git a/src/argparse.hpp b/src/argparse.hpp index 85c1869..cfb3f73 100644 --- a/src/argparse.hpp +++ b/src/argparse.hpp @@ -140,7 +140,8 @@ struct Argument { class ArgumentParser { public: ArgumentParser(const std::string& aProgramName) : - mProgramName(aProgramName) {} + mProgramName(aProgramName), + mNextPositionalArgument(0) {} template Argument& add_argument(T value, Targs... Fargs) { @@ -196,6 +197,25 @@ class ArgumentParser { else { // This is a positional argument. // 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::vector> mPositionalArguments; + size_t mNextPositionalArgument; std::map> mArgumentMap; }; diff --git a/tests/main.cpp b/tests/main.cpp index 1858f58..06e37bd 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -3,3 +3,4 @@ #include #include #include +#include diff --git a/tests/test_positional_arguments.hpp b/tests/test_positional_arguments.hpp new file mode 100644 index 0000000..4eeea94 --- /dev/null +++ b/tests/test_positional_arguments.hpp @@ -0,0 +1,45 @@ +#pragma once +#include +#include + +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>("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("--num_iterations") == 15); + REQUIRE(program.get("input") == "rocket.mesh"); + auto outputs = program.get>("output"); + REQUIRE(outputs.size() == 2); + REQUIRE(outputs[0] == "thrust_profile.csv"); + REQUIRE(outputs[1] == "output.mesh"); +} \ No newline at end of file