From db3b133f8817673da5728b06d9d1325e36cfcd47 Mon Sep 17 00:00:00 2001 From: BodgeMaster <> Date: Wed, 20 Jul 2022 18:30:25 +0200 Subject: [PATCH] lib/cli: fix trailing incomplete unpositional arguments The parser used to rely on the next iteration of the loop to detect if an unpositional argument was missing its value, this has now been fixed by adding an additional check on unpositional arguments waiting for a value that detects if the end of the loop has been reached --- src/lib/cli.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/cli.cpp b/src/lib/cli.cpp index bef1dcc..7e695f5 100644 --- a/src/lib/cli.cpp +++ b/src/lib/cli.cpp @@ -107,6 +107,10 @@ namespace CLI { // unpositional argument argumentsByLongName[argumentName]->present = true; argumentWaitingForValue = argumentsByLongName[argumentName]; + if (i+1 == argc) { + this->wrongUsage = true; + this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argumentName); + } } else { this->wrongUsage = true; this->wrongUsageMessages.push_back(std::string("Unknown argument or flag: ")+argument); @@ -129,23 +133,27 @@ namespace CLI { // length is defined as // (std::__cxx11::basic_string::size_type ?) // starting at 1 because 0 is '-' - for (int i=1; i<(int) argument.length(); i++) { + for (int j=1; j<(int) argument.length(); j++) { //is argument or flag? - if (flagsByShortName.contains(argument[i])) { - flagsByShortName[argument[i]]->present = true; - } else if (argumentsByShortName.contains(argument[i])) { - argumentsByShortName[argument[i]]->present = true; + if (flagsByShortName.contains(argument[j])) { + flagsByShortName[argument[j]]->present = true; + } else if (argumentsByShortName.contains(argument[j])) { + argumentsByShortName[argument[j]]->present = true; //FIXME: see above - if (i+1==(int) argument.length()) { - argumentWaitingForValue = argumentsByShortName[argument[i]]; + if (j+1==(int) argument.length()) { + argumentWaitingForValue = argumentsByShortName[argument[j]]; + if (i+1 == argc) { + this->wrongUsage = true; + this->wrongUsageMessages.push_back(std::string("Argument expects value but has none: ")+argument.substr(j, 1)); + } } else { //assume the rest of the argv is a concatenated argument value - argumentsByShortName[argument[i]]->value = argument.substr(i+1, argument.length()-i-1); + argumentsByShortName[argument[j]]->value = argument.substr(j+1, argument.length()-j-1); break; } } else { this->wrongUsage = true; - this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(i, argument.length()-i)); + this->wrongUsageMessages.push_back(std::string("Unknown argument or flag(s): ")+argument.substr(j, argument.length()-j)); // err on the side of caution to ensure that // no unwanted options get activated on programs // that deal gracefully with unrecognized command