Add greedy-flag for argument parser

This is useful if one needs to pass subsequent arguments as-is to another
nested argument parser.
This commit is contained in:
Martchus 2022-06-26 11:20:24 +02:00
parent 08194f5d32
commit 3c769fa242
3 changed files with 25 additions and 2 deletions

View File

@ -206,7 +206,8 @@ bool ArgumentReader::read(ArgumentVector &args)
// iterate through all argument denotations; loop might exit earlier when an denotation is unknown
while (argv != end) {
// check whether there are still values to read
if (values && lastArgInLevel->requiredValueCount() != Argument::varValueCount && values->size() < lastArgInLevel->requiredValueCount()) {
if (values && ((lastArgInLevel->requiredValueCount() != Argument::varValueCount) || (lastArgInLevel->flags() & Argument::Flags::Greedy))
&& values->size() < lastArgInLevel->requiredValueCount()) {
// read arg as value and continue with next arg
values->emplace_back(argDenotation ? argDenotation : *argv);
++index;
@ -1092,7 +1093,7 @@ void ArgumentParser::verifyArgs(const ArgumentVector &args)
assert(!arg->abbreviation() || find(abbreviations.cbegin(), abbreviations.cend(), arg->abbreviation()) == abbreviations.cend());
abbreviations.push_back(arg->abbreviation());
assert(!arg->name() || find_if(names.cbegin(), names.cend(), [arg](const char *name) { return !strcmp(arg->name(), name); }) == names.cend());
assert(arg->requiredValueCount() == 0 || arg->subArguments().size() == 0);
assert(arg->requiredValueCount() == 0 || arg->subArguments().size() == 0 || (arg->flags() & Argument::Flags::Greedy));
names.emplace_back(arg->name());
}
for (const Argument *arg : args) {

View File

@ -273,6 +273,7 @@ public:
Implicit = 0x2,
Operation = 0x4,
Deprecated = 0x8,
Greedy = 0x10,
};
Argument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);

View File

@ -452,6 +452,27 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT_EQUAL("fields"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT_EQUAL("album=test"sv, std::string_view(fieldsArg.values().at(1)));
// greedy-flag
const char *argv19[] = { "tageditor", "get", "--fields", "foo", "bar", "--help" };
parser.resetArgs();
try {
parser.parseArgs(6, argv19, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) {
CPPUNIT_ASSERT_EQUAL_MESSAGE("--help assumed to be an argument without greedy-flag (leading to error)",
"The argument \"help\" can not be combined with \"get\"."sv, std::string_view(e.what()));
}
parser.resetArgs();
fieldsArg.setFlags(Argument::Flags::Greedy, true);
parser.parseArgs(6, argv19, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT_MESSAGE("--help not considered an argument with greedy-flag", !parser.helpArg().isPresent());
CPPUNIT_ASSERT_EQUAL("foo"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT_EQUAL("bar"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT_EQUAL("--help"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(3), std::out_of_range);
}
/*!