From 1dd7f546afc1e305d3c53d06242ce8fcf917fe90 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 23 Sep 2015 12:03:44 +0200 Subject: [PATCH] CommandLineParser: add special value to disallow empty strings some mandatory string keys like paths must not be empty. Add the special default value `` so the CommandLineParser can enforce this and generate an according error message for us. --- modules/core/include/opencv2/core/utility.hpp | 5 ++- modules/core/src/command_line_parser.cpp | 42 ++++++++++--------- modules/core/test/test_utils.cpp | 23 ++++++++-- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index 22011ddd2f..4d7d7df668 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -609,7 +609,7 @@ For example: const String keys = "{help h usage ? | | print this message }" "{@image1 | | image1 for compare }" - "{@image2 | | image2 for compare }" + "{@image2 || image2 for compare }" "{@repeat |1 | number }" "{path |. | path to file }" "{fps | -1.0 | fps for output video }" @@ -623,6 +623,9 @@ Note that there are no default values for `help` and `timestamp` so we can check Arguments with default values are considered to be always present. Use the `get()` method in these cases to check their actual value instead. +String keys like `get("@image1")` return the empty string `""` by default - even with an empty default value. +Use the special `` default value to enforce that the returned string must not be empty. (like in `get("@image2")`) + ### Usage For the described keys: diff --git a/modules/core/src/command_line_parser.cpp b/modules/core/src/command_line_parser.cpp index 4ef4f7dee2..658c3c7007 100644 --- a/modules/core/src/command_line_parser.cpp +++ b/modules/core/src/command_line_parser.cpp @@ -4,6 +4,20 @@ namespace cv { +namespace { +static const char* noneValue = ""; + +static String cat_string(const String& str) +{ + int left = 0, right = (int)str.length(); + while( left <= right && str[left] == ' ' ) + left++; + while( right > left && str[right-1] == ' ' ) + right--; + return left >= right ? String("") : str.substr(left, right-left); +} +} + struct CommandLineParserParams { public: @@ -27,7 +41,6 @@ struct CommandLineParser::Impl std::vector split_range_string(const String& str, char fs, char ss) const; std::vector split_string(const String& str, char symbol = ' ', bool create_empty_item = false) const; - String cat_string(const String& str) const; void apply_params(const String& key, const String& value); void apply_params(int i, String value); @@ -98,10 +111,10 @@ void CommandLineParser::getByName(const String& name, bool space_delete, int typ { String v = impl->data[i].def_value; if (space_delete) - v = impl->cat_string(v); + v = cat_string(v); // the key was neither specified nor has it a default value - if(v.empty() && type != Param::STRING) { + if((v.empty() && type != Param::STRING) || v == noneValue) { impl->error = true; impl->error_message = impl->error_message + "Missing parameter: '" + name + "'\n"; return; @@ -133,10 +146,10 @@ void CommandLineParser::getByIndex(int index, bool space_delete, int type, void* if (impl->data[i].number == index) { String v = impl->data[i].def_value; - if (space_delete == true) v = impl->cat_string(v); + if (space_delete == true) v = cat_string(v); // the key was neither specified nor has it a default value - if(v.empty() && type != Param::STRING) { + if((v.empty() && type != Param::STRING) || v == noneValue) { impl->error = true; impl->error_message = impl->error_message + format("Missing parameter #%d\n", index); return; @@ -198,7 +211,7 @@ CommandLineParser::CommandLineParser(int argc, const char* const argv[], const S CommandLineParserParams p; p.keys = impl->split_string(l[0]); p.def_value = l[1]; - p.help_message = impl->cat_string(l[2]); + p.help_message = cat_string(l[2]); p.number = -1; if (p.keys.size() <= 0) { @@ -317,16 +330,6 @@ void CommandLineParser::Impl::sort_params() std::sort (data.begin(), data.end(), cmp_params); } -String CommandLineParser::Impl::cat_string(const String& str) const -{ - int left = 0, right = (int)str.length(); - while( left <= right && str[left] == ' ' ) - left++; - while( right > left && str[right-1] == ' ' ) - right--; - return left >= right ? String("") : str.substr(left, right-left); -} - String CommandLineParser::getPathToApplication() const { return impl->path_to_app; @@ -340,7 +343,8 @@ bool CommandLineParser::has(const String& name) const { if (name == impl->data[i].keys[j]) { - return !impl->cat_string(impl->data[i].def_value).empty(); + const String v = cat_string(impl->data[i].def_value); + return !v.empty() && v != noneValue; } } } @@ -404,7 +408,7 @@ void CommandLineParser::printMessage() const printf(", "); } } - String dv = impl->cat_string(impl->data[i].def_value); + String dv = cat_string(impl->data[i].def_value); if (dv.compare("") != 0) { printf(" (value:%s)", dv.c_str()); @@ -424,7 +428,7 @@ void CommandLineParser::printMessage() const printf("%s", k.c_str()); - String dv = impl->cat_string(impl->data[i].def_value); + String dv = cat_string(impl->data[i].def_value); if (dv.compare("") != 0) { printf(" (value:%s)", dv.c_str()); diff --git a/modules/core/test/test_utils.cpp b/modules/core/test/test_utils.cpp index f961b93446..0f1188de0e 100644 --- a/modules/core/test/test_utils.cpp +++ b/modules/core/test/test_utils.cpp @@ -142,9 +142,8 @@ TEST(CommandLineParser, testPositional_noArgs) EXPECT_EQ("default1", parser.get("@arg1")); EXPECT_EQ("default1", parser.get(0)); - parser.get("@arg2"); - parser.get(1); - EXPECT_TRUE(parser.check()); + EXPECT_EQ("", parser.get("@arg2")); + EXPECT_EQ("", parser.get(1)); } TEST(CommandLineParser, testPositional_default) @@ -186,4 +185,22 @@ TEST(CommandLineParser, testPositional_withFlagsAfter) EXPECT_EQ("test2", parser.get(1)); } +TEST(CommandLineParser, testEmptyStringValue) +{ + static const char * const keys3 = + "{ @pos0 | | empty default value }" + "{ @pos1 | | forbid empty default value }"; + + const char* argv[] = {""}; + const int argc = 1; + cv::CommandLineParser parser(argc, argv, keys3); + // EXPECT_TRUE(parser.has("@pos0")); + EXPECT_EQ("", parser.get("@pos0")); + EXPECT_TRUE(parser.check()); + + EXPECT_FALSE(parser.has("@pos1")); + parser.get(1); + EXPECT_FALSE(parser.check()); +} + } // namespace -- GitLab