Commit 1dd7f546 authored by Pavel Rojtberg's avatar Pavel Rojtberg

CommandLineParser: add special <none> value to disallow empty strings

some mandatory string keys like paths must not be empty. Add the special
default value `<none>` so the CommandLineParser can enforce this and
generate an according error message for us.
parent a3888065
...@@ -609,7 +609,7 @@ For example: ...@@ -609,7 +609,7 @@ For example:
const String keys = const String keys =
"{help h usage ? | | print this message }" "{help h usage ? | | print this message }"
"{@image1 | | image1 for compare }" "{@image1 | | image1 for compare }"
"{@image2 | | image2 for compare }" "{@image2 |<none>| image2 for compare }"
"{@repeat |1 | number }" "{@repeat |1 | number }"
"{path |. | path to file }" "{path |. | path to file }"
"{fps | -1.0 | fps for output video }" "{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 ...@@ -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 Arguments with default values are considered to be always present. Use the `get()` method in these cases to check their
actual value instead. actual value instead.
String keys like `get<String>("@image1")` return the empty string `""` by default - even with an empty default value.
Use the special `<none>` default value to enforce that the returned string must not be empty. (like in `get<String>("@image2")`)
### Usage ### Usage
For the described keys: For the described keys:
......
...@@ -4,6 +4,20 @@ ...@@ -4,6 +4,20 @@
namespace cv namespace cv
{ {
namespace {
static const char* noneValue = "<none>";
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 struct CommandLineParserParams
{ {
public: public:
...@@ -27,7 +41,6 @@ struct CommandLineParser::Impl ...@@ -27,7 +41,6 @@ struct CommandLineParser::Impl
std::vector<String> split_range_string(const String& str, char fs, char ss) const; std::vector<String> split_range_string(const String& str, char fs, char ss) const;
std::vector<String> split_string(const String& str, char symbol = ' ', bool create_empty_item = false) const; std::vector<String> 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(const String& key, const String& value);
void apply_params(int i, String value); void apply_params(int i, String value);
...@@ -98,10 +111,10 @@ void CommandLineParser::getByName(const String& name, bool space_delete, int typ ...@@ -98,10 +111,10 @@ void CommandLineParser::getByName(const String& name, bool space_delete, int typ
{ {
String v = impl->data[i].def_value; String v = impl->data[i].def_value;
if (space_delete) if (space_delete)
v = impl->cat_string(v); v = cat_string(v);
// the key was neither specified nor has it a default value // 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 = true;
impl->error_message = impl->error_message + "Missing parameter: '" + name + "'\n"; impl->error_message = impl->error_message + "Missing parameter: '" + name + "'\n";
return; return;
...@@ -133,10 +146,10 @@ void CommandLineParser::getByIndex(int index, bool space_delete, int type, void* ...@@ -133,10 +146,10 @@ void CommandLineParser::getByIndex(int index, bool space_delete, int type, void*
if (impl->data[i].number == index) if (impl->data[i].number == index)
{ {
String v = impl->data[i].def_value; 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 // 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 = true;
impl->error_message = impl->error_message + format("Missing parameter #%d\n", index); impl->error_message = impl->error_message + format("Missing parameter #%d\n", index);
return; return;
...@@ -198,7 +211,7 @@ CommandLineParser::CommandLineParser(int argc, const char* const argv[], const S ...@@ -198,7 +211,7 @@ CommandLineParser::CommandLineParser(int argc, const char* const argv[], const S
CommandLineParserParams p; CommandLineParserParams p;
p.keys = impl->split_string(l[0]); p.keys = impl->split_string(l[0]);
p.def_value = l[1]; p.def_value = l[1];
p.help_message = impl->cat_string(l[2]); p.help_message = cat_string(l[2]);
p.number = -1; p.number = -1;
if (p.keys.size() <= 0) if (p.keys.size() <= 0)
{ {
...@@ -317,16 +330,6 @@ void CommandLineParser::Impl::sort_params() ...@@ -317,16 +330,6 @@ void CommandLineParser::Impl::sort_params()
std::sort (data.begin(), data.end(), cmp_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 String CommandLineParser::getPathToApplication() const
{ {
return impl->path_to_app; return impl->path_to_app;
...@@ -340,7 +343,8 @@ bool CommandLineParser::has(const String& name) const ...@@ -340,7 +343,8 @@ bool CommandLineParser::has(const String& name) const
{ {
if (name == impl->data[i].keys[j]) 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 ...@@ -404,7 +408,7 @@ void CommandLineParser::printMessage() const
printf(", "); printf(", ");
} }
} }
String dv = impl->cat_string(impl->data[i].def_value); String dv = cat_string(impl->data[i].def_value);
if (dv.compare("") != 0) if (dv.compare("") != 0)
{ {
printf(" (value:%s)", dv.c_str()); printf(" (value:%s)", dv.c_str());
...@@ -424,7 +428,7 @@ void CommandLineParser::printMessage() const ...@@ -424,7 +428,7 @@ void CommandLineParser::printMessage() const
printf("%s", k.c_str()); 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) if (dv.compare("") != 0)
{ {
printf(" (value:%s)", dv.c_str()); printf(" (value:%s)", dv.c_str());
......
...@@ -142,9 +142,8 @@ TEST(CommandLineParser, testPositional_noArgs) ...@@ -142,9 +142,8 @@ TEST(CommandLineParser, testPositional_noArgs)
EXPECT_EQ("default1", parser.get<String>("@arg1")); EXPECT_EQ("default1", parser.get<String>("@arg1"));
EXPECT_EQ("default1", parser.get<String>(0)); EXPECT_EQ("default1", parser.get<String>(0));
parser.get<String>("@arg2"); EXPECT_EQ("", parser.get<String>("@arg2"));
parser.get<String>(1); EXPECT_EQ("", parser.get<String>(1));
EXPECT_TRUE(parser.check());
} }
TEST(CommandLineParser, testPositional_default) TEST(CommandLineParser, testPositional_default)
...@@ -186,4 +185,22 @@ TEST(CommandLineParser, testPositional_withFlagsAfter) ...@@ -186,4 +185,22 @@ TEST(CommandLineParser, testPositional_withFlagsAfter)
EXPECT_EQ("test2", parser.get<String>(1)); EXPECT_EQ("test2", parser.get<String>(1));
} }
TEST(CommandLineParser, testEmptyStringValue)
{
static const char * const keys3 =
"{ @pos0 | | empty default value }"
"{ @pos1 | <none> | forbid empty default value }";
const char* argv[] = {"<bin>"};
const int argc = 1;
cv::CommandLineParser parser(argc, argv, keys3);
// EXPECT_TRUE(parser.has("@pos0"));
EXPECT_EQ("", parser.get<String>("@pos0"));
EXPECT_TRUE(parser.check());
EXPECT_FALSE(parser.has("@pos1"));
parser.get<String>(1);
EXPECT_FALSE(parser.check());
}
} // namespace } // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment