diff options
-rw-r--r-- | Source/cmArgumentParser.cxx | 14 | ||||
-rw-r--r-- | Source/cmArgumentParser.h | 1 | ||||
-rw-r--r-- | Source/cmArgumentParserTypes.h | 5 | ||||
-rw-r--r-- | Source/cmCMakePathCommand.cxx | 44 | ||||
-rw-r--r-- | Tests/CMakeLib/testArgumentParser.cxx | 16 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-empty-stderr.txt | 4 | ||||
-rw-r--r-- | Tests/RunCMake/cmake_path/RunCMakeTest.cmake | 3 |
7 files changed, 48 insertions, 39 deletions
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 05f8ce8..614d00d 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -76,6 +76,20 @@ void Instance::Bind(std::string& val) ExpectAtLeast{ 1 }); } +void Instance::Bind(NonEmpty<std::string>& val) +{ + this->Bind( + [this, &val](cm::string_view arg) -> Continue { + if (arg.empty() && this->ParseResults) { + this->ParseResults->AddKeywordError(this->Keyword, + " empty string not allowed\n"); + } + val.assign(std::string(arg)); + return Continue::No; + }, + ExpectAtLeast{ 1 }); +} + void Instance::Bind(Maybe<std::string>& val) { this->Bind( diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index c25e2f6..ac78872 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -171,6 +171,7 @@ public: void Bind(std::function<Continue(cm::string_view)> f, ExpectAtLeast expect); void Bind(bool& val); void Bind(std::string& val); + void Bind(NonEmpty<std::string>& val); void Bind(Maybe<std::string>& val); void Bind(MaybeEmpty<std::vector<std::string>>& val); void Bind(NonEmpty<std::vector<std::string>>& val); diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h index fe8e4ca..7daae09 100644 --- a/Source/cmArgumentParserTypes.h +++ b/Source/cmArgumentParserTypes.h @@ -34,6 +34,11 @@ struct NonEmpty<std::vector<T>> : public std::vector<T> { using std::vector<T>::vector; }; +template <> +struct NonEmpty<std::string> : public std::string +{ + using std::string::basic_string; +}; } // namespace ArgumentParser diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx index b955bcf..7755082 100644 --- a/Source/cmCMakePathCommand.cxx +++ b/Source/cmCMakePathCommand.cxx @@ -15,6 +15,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmCMakePath.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -82,22 +83,11 @@ public: return this->CMakePathArgumentParser<Result>::template Parse<Advance>( args); } - - bool checkOutputVariable(const Result& arguments, - cmExecutionStatus& status) const - { - if (arguments.Output && arguments.Output->empty()) { - status.SetError("Invalid name for output variable."); - return false; - } - - return true; - } }; struct OutputVariable : public ArgumentParser::ParseResult { - cm::optional<std::string> Output; + cm::optional<ArgumentParser::NonEmpty<std::string>> Output; }; // Usable when OUTPUT_VARIABLE is the only option class OutputVariableParser @@ -270,9 +260,6 @@ bool HandleAppendCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } cmCMakePath path(status.GetMakefile().GetSafeDefinition(args[1])); for (const auto& input : parser.GetInputs()) { @@ -295,9 +282,6 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } std::string inputPath; if (!getInputPath(args[1], status, inputPath)) { @@ -325,9 +309,6 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (!parser.GetInputs().empty()) { status.SetError("REMOVE_FILENAME called with unexpected arguments."); @@ -358,9 +339,6 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (parser.GetInputs().size() > 1) { status.SetError("REPLACE_FILENAME called with unexpected arguments."); @@ -387,7 +365,7 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, { struct Arguments : public ArgumentParser::ParseResult { - cm::optional<std::string> Output; + cm::optional<ArgumentParser::NonEmpty<std::string>> Output; bool LastOnly = false; }; @@ -400,9 +378,6 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (!parser.GetInputs().empty()) { status.SetError("REMOVE_EXTENSION called with unexpected arguments."); @@ -433,7 +408,7 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args, { struct Arguments : public ArgumentParser::ParseResult { - cm::optional<std::string> Output; + cm::optional<ArgumentParser::NonEmpty<std::string>> Output; bool LastOnly = false; }; @@ -446,9 +421,6 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (parser.GetInputs().size() > 1) { status.SetError("REPLACE_EXTENSION called with unexpected arguments."); @@ -486,9 +458,6 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args, if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (!parser.GetInputs().empty()) { status.SetError("NORMAL_PATH called with unexpected arguments."); @@ -516,7 +485,7 @@ bool HandleTransformPathCommand( { struct Arguments : public ArgumentParser::ParseResult { - cm::optional<std::string> Output; + cm::optional<ArgumentParser::NonEmpty<std::string>> Output; cm::optional<std::string> BaseDirectory; bool Normalize = false; }; @@ -532,9 +501,6 @@ bool HandleTransformPathCommand( if (arguments.MaybeReportError(status.GetMakefile())) { return true; } - if (!parser.checkOutputVariable(arguments, status)) { - return false; - } if (!parser.GetInputs().empty()) { status.SetError(cmStrCat(args[0], " called with unexpected arguments.")); diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 496b873..58c0418 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -27,6 +27,8 @@ struct Result : public ArgumentParser::ParseResult cm::optional<std::string> String2; cm::optional<std::string> String3; ArgumentParser::Maybe<std::string> String4; + ArgumentParser::NonEmpty<std::string> String5; + ArgumentParser::NonEmpty<std::string> String6; ArgumentParser::NonEmpty<std::vector<std::string>> List1; ArgumentParser::NonEmpty<std::vector<std::string>> List2; @@ -87,6 +89,8 @@ struct Result : public ArgumentParser::ParseResult ArgumentParser::NonEmpty<std::vector<std::string>> UnboundNonEmpty{ 1, "unbound" }; + ArgumentParser::NonEmpty<std::string> UnboundNonEmptyStr{ 'u', 'n', 'b', 'o', + 'u', 'n', 'd' }; std::vector<cm::string_view> ParsedKeywords; }; @@ -100,6 +104,8 @@ std::initializer_list<cm::string_view> const args = { "STRING_2", "foo", "bar", // string arg + unparsed value, presence captured // "STRING_3", // string arg that is not present "STRING_4", // string arg allowed to be missing value + "STRING_5", "foo", // string arg that is not empty + "STRING_6", "", // string arg that is empty "LIST_1", // list arg missing values "LIST_2", "foo", "bar", // list arg with 2 elems "LIST_3", "bar", // list arg ... @@ -133,6 +139,8 @@ bool verifyResult(Result const& result, "STRING_1", "STRING_2", "STRING_4", + "STRING_5", + "STRING_6", "LIST_1", "LIST_2", "LIST_3", @@ -159,6 +167,7 @@ bool verifyResult(Result const& result, }; static std::map<cm::string_view, std::string> const keywordErrors = { { "STRING_1"_s, " missing required value\n" }, + { "STRING_6"_s, " empty string not allowed\n" }, { "LIST_1"_s, " missing required value\n" }, { "LIST_4"_s, " missing required value\n" }, { "FUNC_0"_s, " missing required value\n" } @@ -184,6 +193,8 @@ bool verifyResult(Result const& result, ASSERT_TRUE(*result.String2 == "foo"); ASSERT_TRUE(!result.String3); ASSERT_TRUE(result.String4.empty()); + ASSERT_TRUE(result.String5 == "foo"); + ASSERT_TRUE(result.String6.empty()); ASSERT_TRUE(result.List1.empty()); ASSERT_TRUE(result.List2 == foobar); @@ -217,6 +228,7 @@ bool verifyResult(Result const& result, ASSERT_TRUE(result.UnboundMaybe == "unbound"); ASSERT_TRUE(result.UnboundMaybeEmpty == unbound); ASSERT_TRUE(result.UnboundNonEmpty == unbound); + ASSERT_TRUE(result.UnboundNonEmptyStr == "unbound"); ASSERT_TRUE(result.ParsedKeywords == parsedKeywords); @@ -249,6 +261,8 @@ bool testArgumentParserDynamic() .Bind("STRING_2"_s, result.String2) .Bind("STRING_3"_s, result.String3) .Bind("STRING_4"_s, result.String4) + .Bind("STRING_5"_s, result.String5) + .Bind("STRING_6"_s, result.String6) .Bind("LIST_1"_s, result.List1) .Bind("LIST_2"_s, result.List2) .Bind("LIST_3"_s, result.List3) @@ -299,6 +313,8 @@ static auto const parserStatic = // .Bind("STRING_2"_s, &Result::String2) .Bind("STRING_3"_s, &Result::String3) .Bind("STRING_4"_s, &Result::String4) + .Bind("STRING_5"_s, &Result::String5) + .Bind("STRING_6"_s, &Result::String6) .Bind("LIST_1"_s, &Result::List1) .Bind("LIST_2"_s, &Result::List2) .Bind("LIST_3"_s, &Result::List3) diff --git a/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-empty-stderr.txt b/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-empty-stderr.txt new file mode 100644 index 0000000..f1b52cc --- /dev/null +++ b/Tests/RunCMake/cmake_path/OUTPUT_VARIABLE-empty-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at .+/call-cmake_path.cmake:[0-9]+ \(cmake_path\): + Error after keyword "OUTPUT_VARIABLE": + + empty string not allowed diff --git a/Tests/RunCMake/cmake_path/RunCMakeTest.cmake b/Tests/RunCMake/cmake_path/RunCMakeTest.cmake index 8a2dd95..1742b06 100644 --- a/Tests/RunCMake/cmake_path/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_path/RunCMakeTest.cmake @@ -114,6 +114,9 @@ foreach (command IN ITEMS NATIVE_PATH run_cmake_command (${command}-invalid-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path ${extra_args}" -DCHECK_INVALID_OUTPUT=ON -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake") endforeach() +# OUTPUT_VARIABLE empty name +set (RunCMake-stderr-file "OUTPUT_VARIABLE-empty-stderr.txt") + foreach (command IN ITEMS APPEND APPEND_STRING REMOVE_FILENAME REPLACE_FILENAME REMOVE_EXTENSION REPLACE_EXTENSION NORMAL_PATH RELATIVE_PATH ABSOLUTE_PATH) |