diff options
34 files changed, 294 insertions, 254 deletions
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index 7432d08..97b0a89 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -4,7 +4,6 @@ #include <set> -#include <cmext/algorithm> #include <cmext/string_view> #include "cmCTest.h" @@ -18,13 +17,6 @@ void cmCTestCoverageCommand::BindArguments() this->Bind("LABELS"_s, this->Labels); } -void cmCTestCoverageCommand::CheckArguments( - std::vector<std::string> const& keywords) -{ - this->LabelsMentioned = - !this->Labels.empty() || cm::contains(keywords, "LABELS"); -} - cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() { this->CTest->SetCTestConfigurationFromCMakeVariable( @@ -36,9 +28,9 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() handler->Initialize(); // If a LABELS option was given, select only files with the labels. - if (this->LabelsMentioned) { + if (this->Labels) { handler->SetLabelFilter( - std::set<std::string>(this->Labels.begin(), this->Labels.end())); + std::set<std::string>(this->Labels->begin(), this->Labels->end())); } handler->SetQuiet(this->Quiet); diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index 9344852..dc8f71e 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -9,6 +9,7 @@ #include <vector> #include <cm/memory> +#include <cm/optional> #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -41,9 +42,7 @@ public: protected: void BindArguments() override; - void CheckArguments(std::vector<std::string> const& keywords) override; cmCTestGenericHandler* InitializeHandler() override; - bool LabelsMentioned; - std::vector<std::string> Labels; + cm::optional<std::vector<std::string>> Labels; }; diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 5494d20..af365ad 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -7,6 +7,7 @@ #include <cstring> #include <sstream> +#include <cm/string_view> #include <cmext/string_view> #include "cmCTest.h" @@ -81,11 +82,10 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, // Process input arguments. std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValue; - std::vector<std::string> parsedKeywords; - this->Parse(args, &unparsedArguments, &keywordsMissingValue, + std::vector<cm::string_view> parsedKeywords; + this->Parse(args, &unparsedArguments, /*keywordsMissingValue=*/nullptr, &parsedKeywords); - this->CheckArguments(keywordsMissingValue); + this->CheckArguments(); std::sort(parsedKeywords.begin(), parsedKeywords.end()); auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end()); @@ -242,6 +242,6 @@ void cmCTestHandlerCommand::BindArguments() this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex); } -void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&) +void cmCTestHandlerCommand::CheckArguments() { } diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h index 756952d..31942c8 100644 --- a/Source/CTest/cmCTestHandlerCommand.h +++ b/Source/CTest/cmCTestHandlerCommand.h @@ -42,7 +42,7 @@ protected: // Command argument handling. virtual void BindArguments(); - virtual void CheckArguments(std::vector<std::string> const& keywords); + virtual void CheckArguments(); bool Append = false; bool Quiet = false; diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index a2dc615..a1933cc 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -8,7 +8,6 @@ #include <cm/memory> #include <cm/vector> -#include <cmext/algorithm> #include <cmext/string_view> #include "cmCTest.h" @@ -87,7 +86,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() // If FILES are given, but not PARTS, only the FILES are submitted // and *no* PARTS are submitted. // (This is why we select the empty "noParts" set in the - // FilesMentioned block below...) + // if(this->Files) block below...) // // If PARTS are given, only the selected PARTS are submitted. // @@ -96,7 +95,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() // If given explicit FILES to submit, pass them to the handler. // - if (this->FilesMentioned) { + if (this->Files) { // Intentionally select *no* PARTS. (Pass an empty set.) If PARTS // were also explicitly mentioned, they will be selected below... // But FILES with no PARTS mentioned should just submit the FILES @@ -104,14 +103,14 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() // handler->SelectParts(std::set<cmCTest::Part>()); handler->SelectFiles( - std::set<std::string>(this->Files.begin(), this->Files.end())); + std::set<std::string>(this->Files->begin(), this->Files->end())); } // If a PARTS option was given, select only the named parts for submission. // - if (this->PartsMentioned) { + if (this->Parts) { auto parts = - cmMakeRange(this->Parts).transform([this](std::string const& arg) { + cmMakeRange(*(this->Parts)).transform([this](std::string const& arg) { return this->CTest->GetPartFromName(arg); }); handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end())); @@ -172,33 +171,31 @@ void cmCTestSubmitCommand::BindArguments() this->cmCTestHandlerCommand::BindArguments(); } -void cmCTestSubmitCommand::CheckArguments( - std::vector<std::string> const& keywords) +void cmCTestSubmitCommand::CheckArguments() { - this->PartsMentioned = - !this->Parts.empty() || cm::contains(keywords, "PARTS"); - this->FilesMentioned = - !this->Files.empty() || cm::contains(keywords, "FILES"); - - cm::erase_if(this->Parts, [this](std::string const& arg) -> bool { - cmCTest::Part p = this->CTest->GetPartFromName(arg); - if (p == cmCTest::PartCount) { - std::ostringstream e; - e << "Part name \"" << arg << "\" is invalid."; - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return true; - } - return false; - }); - - cm::erase_if(this->Files, [this](std::string const& arg) -> bool { - if (!cmSystemTools::FileExists(arg)) { - std::ostringstream e; - e << "File \"" << arg << "\" does not exist. Cannot submit " - << "a non-existent file."; - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return true; - } - return false; - }); + if (this->Parts) { + cm::erase_if(*(this->Parts), [this](std::string const& arg) -> bool { + cmCTest::Part p = this->CTest->GetPartFromName(arg); + if (p == cmCTest::PartCount) { + std::ostringstream e; + e << "Part name \"" << arg << "\" is invalid."; + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return true; + } + return false; + }); + } + + if (this->Files) { + cm::erase_if(*(this->Files), [this](std::string const& arg) -> bool { + if (!cmSystemTools::FileExists(arg)) { + std::ostringstream e; + e << "File \"" << arg << "\" does not exist. Cannot submit " + << "a non-existent file."; + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return true; + } + return false; + }); + } } diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index c5d11df..903bb64 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -8,6 +8,8 @@ #include <string> #include <vector> +#include <cm/optional> + #include "cmCTestHandlerCommand.h" class cmCommand; @@ -35,13 +37,11 @@ public: protected: void BindArguments() override; - void CheckArguments(std::vector<std::string> const& keywords) override; + void CheckArguments() override; cmCTestGenericHandler* InitializeHandler() override; bool CDashUpload = false; - bool FilesMentioned = false; bool InternalTest = false; - bool PartsMentioned = false; std::string BuildID; std::string CDashUploadFile; @@ -50,7 +50,7 @@ protected: std::string RetryDelay; std::string SubmitURL; - std::vector<std::string> Files; + cm::optional<std::vector<std::string>> Files; std::vector<std::string> HttpHeaders; - std::vector<std::string> Parts; + cm::optional<std::vector<std::string>> Parts; }; diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index f86ee0d..2ed671c 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -21,7 +21,7 @@ void cmCTestUploadCommand::BindArguments() this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError); } -void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&) +void cmCTestUploadCommand::CheckArguments() { cm::erase_if(this->Files, [this](std::string const& arg) -> bool { if (!cmSystemTools::FileExists(arg)) { diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index fe155f6..0dad2bf 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -42,7 +42,7 @@ public: protected: void BindArguments() override; - void CheckArguments(std::vector<std::string> const&) override; + void CheckArguments() override; cmCTestGenericHandler* InitializeHandler() override; std::vector<std::string> Files; diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 4624f1c..1a05dbc 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -44,14 +44,14 @@ void Instance::Bind(std::string& val) this->ExpectValue = true; } -void Instance::Bind(StringList& val) +void Instance::Bind(std::vector<std::string>& val) { this->CurrentString = nullptr; this->CurrentList = &val; this->ExpectValue = true; } -void Instance::Bind(MultiStringList& val) +void Instance::Bind(std::vector<std::vector<std::string>>& val) { this->CurrentString = nullptr; this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back()); @@ -60,17 +60,17 @@ void Instance::Bind(MultiStringList& val) void Instance::Consume(cm::string_view arg, void* result, std::vector<std::string>* unparsedArguments, - std::vector<std::string>* keywordsMissingValue, - std::vector<std::string>* parsedKeywords) + std::vector<cm::string_view>* keywordsMissingValue, + std::vector<cm::string_view>* parsedKeywords) { auto const it = this->Bindings.Find(arg); if (it != this->Bindings.end()) { if (parsedKeywords != nullptr) { - parsedKeywords->emplace_back(arg); + parsedKeywords->emplace_back(it->first); } it->second(*this, result); if (this->ExpectValue && keywordsMissingValue != nullptr) { - keywordsMissingValue->emplace_back(arg); + keywordsMissingValue->emplace_back(it->first); } return; } diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 71ed844..8be5a9c 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -10,14 +10,12 @@ #include <utility> #include <vector> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> namespace ArgumentParser { -using StringList = std::vector<std::string>; -using MultiStringList = std::vector<StringList>; - class Instance; using Action = std::function<void(Instance&, void*)>; @@ -39,18 +37,28 @@ public: void Bind(bool& val); void Bind(std::string& val); - void Bind(StringList& val); - void Bind(MultiStringList& val); + void Bind(std::vector<std::string>& val); + void Bind(std::vector<std::vector<std::string>>& val); + + // cm::optional<> records the presence the keyword to which it binds. + template <typename T> + void Bind(cm::optional<T>& optVal) + { + if (!optVal) { + optVal.emplace(); + } + this->Bind(*optVal); + } void Consume(cm::string_view arg, void* result, std::vector<std::string>* unparsedArguments, - std::vector<std::string>* keywordsMissingValue, - std::vector<std::string>* parsedKeywords); + std::vector<cm::string_view>* keywordsMissingValue, + std::vector<cm::string_view>* parsedKeywords); private: ActionMap const& Bindings; std::string* CurrentString = nullptr; - StringList* CurrentList = nullptr; + std::vector<std::string>* CurrentList = nullptr; bool ExpectValue = false; }; @@ -78,9 +86,9 @@ public: template <typename Range> void Parse(Result& result, Range const& args, - std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr, - std::vector<std::string>* parsedKeywords = nullptr) const + std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { ArgumentParser::Instance instance(this->Bindings); for (cm::string_view arg : args) { @@ -90,10 +98,9 @@ public: } template <typename Range> - Result Parse(Range const& args, - std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr, - std::vector<std::string>* parsedKeywords = nullptr) const + Result Parse(Range const& args, std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { Result result; this->Parse(result, args, unparsedArguments, keywordsMissingValue, @@ -118,10 +125,9 @@ public: } template <typename Range> - void Parse(Range const& args, - std::vector<std::string>* unparsedArguments = nullptr, - std::vector<std::string>* keywordsMissingValue = nullptr, - std::vector<std::string>* parsedKeywords = nullptr) const + void Parse(Range const& args, std::vector<std::string>* unparsedArguments, + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { ArgumentParser::Instance instance(this->Bindings); for (cm::string_view arg : args) { diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 0750eea..033dd6d 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -491,7 +491,7 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status, .Bind("SEPARATOR"_s, &Arguments::Separator) .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable); std::vector<std::string> invalidArgs; - std::vector<std::string> keywordsMissingValue; + std::vector<cm::string_view> keywordsMissingValue; Arguments const arguments = parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue); diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx index bf94c2d..adcffa9 100644 --- a/Source/cmCMakePathCommand.cxx +++ b/Source/cmCMakePathCommand.cxx @@ -44,8 +44,8 @@ public: template <int Advance = 2> Result Parse(std::vector<std::string> const& args, - std::vector<std::string>* keywordsMissingValue = nullptr, - std::vector<std::string>* parsedKeywords = nullptr) const + std::vector<cm::string_view>* keywordsMissingValue = nullptr, + std::vector<cm::string_view>* parsedKeywords = nullptr) const { this->Inputs.clear(); @@ -89,11 +89,11 @@ public: args, &this->KeywordsMissingValue, &this->ParsedKeywords); } - const std::vector<std::string>& GetKeywordsMissingValue() const + const std::vector<cm::string_view>& GetKeywordsMissingValue() const { return this->KeywordsMissingValue; } - const std::vector<std::string>& GetParsedKeywords() const + const std::vector<cm::string_view>& GetParsedKeywords() const { return this->ParsedKeywords; } @@ -121,8 +121,8 @@ public: } private: - mutable std::vector<std::string> KeywordsMissingValue; - mutable std::vector<std::string> ParsedKeywords; + mutable std::vector<cm::string_view> KeywordsMissingValue; + mutable std::vector<cm::string_view> ParsedKeywords; }; struct OutputVariable diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 222ea80..af56e2d 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -95,13 +95,13 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, .Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal); std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValue; + std::vector<cm::string_view> keywordsMissingValue; Arguments const arguments = parser.Parse(args, &unparsedArguments, &keywordsMissingValue); if (!keywordsMissingValue.empty()) { - status.SetError(" called with no value for " + - keywordsMissingValue.front() + "."); + status.SetError(cmStrCat(" called with no value for ", + keywordsMissingValue.front(), ".")); return false; } if (!unparsedArguments.empty()) { diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 63440a3..198874e 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -7,7 +7,7 @@ #include <utility> #include <cm/memory> -#include <cmext/algorithm> +#include <cm/optional> #include <cmext/string_view> #include "cmsys/RegularExpression.hxx" @@ -57,7 +57,7 @@ bool cmExportCommand(std::vector<std::string> const& args, struct Arguments { std::string ExportSetName; - std::vector<std::string> Targets; + cm::optional<std::vector<std::string>> Targets; std::string Namespace; std::string Filename; std::string AndroidMKFile; @@ -79,9 +79,7 @@ bool cmExportCommand(std::vector<std::string> const& args, } std::vector<std::string> unknownArgs; - std::vector<std::string> keywordsMissingValue; - Arguments const arguments = - parser.Parse(args, &unknownArgs, &keywordsMissingValue); + Arguments const arguments = parser.Parse(args, &unknownArgs); if (!unknownArgs.empty()) { status.SetError("Unknown argument: \"" + unknownArgs.front() + "\"."); @@ -145,9 +143,8 @@ bool cmExportCommand(std::vector<std::string> const& args, return false; } exportSet = &it->second; - } else if (!arguments.Targets.empty() || - cm::contains(keywordsMissingValue, "TARGETS")) { - for (std::string const& currentTarget : arguments.Targets) { + } else if (arguments.Targets) { + for (std::string const& currentTarget : *arguments.Targets) { if (mf.IsAlias(currentTarget)) { std::ostringstream e; e << "given ALIAS target \"" << currentTarget diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 1cfe29c..1082387 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -172,7 +172,8 @@ bool HandleReadCommand(std::vector<std::string> const& args, .Bind("LIMIT"_s, &Arguments::Limit) .Bind("HEX"_s, &Arguments::Hex); - Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3)); + Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3), + /*unparsedArguments=*/nullptr); std::string fileName = fileNameArg; if (!cmsys::SystemTools::FileIsFullPath(fileName)) { @@ -958,8 +959,8 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args, bool removeEnvironmentRPath = false; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<std::string> missingArgs; - std::vector<std::string> parsedArgs; + std::vector<cm::string_view> missingArgs; + std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file) .Bind("OLD_RPATH"_s, oldRPath) .Bind("NEW_RPATH"_s, newRPath) @@ -1028,8 +1029,8 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args, std::string newRPath; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<std::string> missingArgs; - std::vector<std::string> parsedArgs; + std::vector<cm::string_view> missingArgs; + std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath); parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs, &parsedArgs); @@ -1087,7 +1088,7 @@ bool HandleRPathRemoveCommand(std::vector<std::string> const& args, std::string file; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<std::string> missingArgs; + std::vector<cm::string_view> missingArgs; parser.Bind("FILE"_s, file); parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs); if (!unknownArgs.empty()) { @@ -1138,8 +1139,8 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args, std::string rpath; cmArgumentParser<void> parser; std::vector<std::string> unknownArgs; - std::vector<std::string> missingArgs; - std::vector<std::string> parsedArgs; + std::vector<cm::string_view> missingArgs; + std::vector<cm::string_view> parsedArgs; parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath); parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs, &parsedArgs); @@ -1197,7 +1198,8 @@ bool HandleReadElfCommand(std::vector<std::string> const& args, .Bind("RPATH"_s, &Arguments::RPath) .Bind("RUNPATH"_s, &Arguments::RunPath) .Bind("CAPTURE_ERROR"_s, &Arguments::Error); - Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2)); + Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2), + /*unparsedArguments=*/nullptr); if (!cmSystemTools::FileExists(fileNameArg, true)) { status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg, @@ -1252,7 +1254,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, struct Arguments { - std::string BaseDirectory; + cm::optional<std::string> BaseDirectory; bool ExpandTilde = false; }; static auto const parser = @@ -1261,11 +1263,9 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, .Bind("EXPAND_TILDE"_s, &Arguments::ExpandTilde); std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValue; - std::vector<std::string> parsedKeywords; - auto arguments = - parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments, - &keywordsMissingValue, &parsedKeywords); + std::vector<cm::string_view> keywordsMissingValue; + auto arguments = parser.Parse(cmMakeRange(args).advance(3), + &unparsedArguments, &keywordsMissingValue); if (!unparsedArguments.empty()) { status.SetError("REAL_PATH called with unexpected arguments"); @@ -1276,7 +1276,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, return false; } - if (parsedKeywords.empty()) { + if (!arguments.BaseDirectory) { arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory(); } @@ -1295,7 +1295,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, } cmCMakePath path(input, cmCMakePath::auto_format); - path = path.Absolute(arguments.BaseDirectory).Normal(); + path = path.Absolute(*arguments.BaseDirectory).Normal(); auto realPath = cmSystemTools::GetRealPath(path.GenericString()); status.GetMakefile().AddDefinition(args[2], realPath); @@ -2497,12 +2497,12 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, struct Arguments { - std::string Output; - std::string Input; - std::string Content; - std::string Condition; - std::string Target; - std::string NewLineStyle; + cm::optional<std::string> Output; + cm::optional<std::string> Input; + cm::optional<std::string> Content; + cm::optional<std::string> Condition; + cm::optional<std::string> Target; + cm::optional<std::string> NewLineStyle; bool NoSourcePermissions = false; bool UseSourcePermissions = false; std::vector<std::string> FilePermissions; @@ -2521,14 +2521,16 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle); std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValues; - std::vector<std::string> parsedKeywords; + std::vector<cm::string_view> keywordsMissingValues; + std::vector<cm::string_view> parsedKeywords; Arguments const arguments = parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments, &keywordsMissingValues, &parsedKeywords); if (!keywordsMissingValues.empty()) { - status.SetError("Incorrect arguments to GENERATE subcommand."); + status.SetError( + cmStrCat("GENERATE keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); return false; } @@ -2537,56 +2539,41 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, return false; } - bool mandatoryOptionsSpecified = false; - if (parsedKeywords.size() > 1) { - const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s; - const bool inputOrContentSpecified = - parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s; - if (outputOprionSpecified && inputOrContentSpecified) { - mandatoryOptionsSpecified = true; - } + if (!arguments.Output || parsedKeywords[0] != "OUTPUT"_s) { + status.SetError("GENERATE requires OUTPUT as first option."); + return false; } - if (!mandatoryOptionsSpecified) { - status.SetError("Incorrect arguments to GENERATE subcommand."); + std::string const& output = *arguments.Output; + + if (!arguments.Input && !arguments.Content) { + status.SetError("GENERATE requires INPUT or CONTENT option."); return false; } + const bool inputIsContent = parsedKeywords[1] == "CONTENT"_s; + if (!inputIsContent && parsedKeywords[1] == "INPUT") { + status.SetError("Unknown argument to GENERATE subcommand."); + } + std::string const& input = + inputIsContent ? *arguments.Content : *arguments.Input; - const bool conditionOptionSpecified = - std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) != - parsedKeywords.end(); - if (conditionOptionSpecified && arguments.Condition.empty()) { + if (arguments.Condition && arguments.Condition->empty()) { status.SetError("CONDITION of sub-command GENERATE must not be empty " "if specified."); return false; } + std::string const& condition = + arguments.Condition ? *arguments.Condition : std::string(); - const bool targetOptionSpecified = - std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) != - parsedKeywords.end(); - if (targetOptionSpecified && arguments.Target.empty()) { + if (arguments.Target && arguments.Target->empty()) { status.SetError("TARGET of sub-command GENERATE must not be empty " "if specified."); return false; } + std::string const& target = + arguments.Target ? *arguments.Target : std::string(); - const bool outputOptionSpecified = - std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) != - parsedKeywords.end(); - if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) { - status.SetError("Incorrect arguments to GENERATE subcommand."); - return false; - } - - const bool inputIsContent = parsedKeywords[1] != "INPUT"_s; - if (inputIsContent && parsedKeywords[1] != "CONTENT") { - status.SetError("Unknown argument to GENERATE subcommand."); - } - - const bool newLineStyleSpecified = - std::find(parsedKeywords.begin(), parsedKeywords.end(), - "NEWLINE_STYLE"_s) != parsedKeywords.end(); cmNewLineStyle newLineStyle; - if (newLineStyleSpecified) { + if (arguments.NewLineStyle) { std::string errorMessage; if (!newLineStyle.ReadFromArguments(args, errorMessage)) { status.SetError(cmStrCat("GENERATE ", errorMessage)); @@ -2594,11 +2581,6 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, } } - std::string input = arguments.Input; - if (inputIsContent) { - input = arguments.Content; - } - if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) { status.SetError("given both NO_SOURCE_PERMISSIONS and " "USE_SOURCE_PERMISSIONS. Only one option allowed."); @@ -2656,8 +2638,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, } } - AddEvaluationFile(input, arguments.Target, arguments.Output, - arguments.Condition, inputIsContent, + AddEvaluationFile(input, target, output, condition, inputIsContent, newLineStyle.GetCharacters(), permissions, status); return true; } @@ -3102,7 +3083,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, .Bind("POST_EXCLUDE_FILES_STRICT"_s, &Arguments::PostExcludeFilesStrict); std::vector<std::string> unrecognizedArguments; - std::vector<std::string> keywordsMissingValues; + std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, &keywordsMissingValues); @@ -3114,18 +3095,18 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, } // Arguments that are allowed to be empty lists. Keep entries sorted! - const std::vector<std::string> LIST_ARGS = { - "DIRECTORIES", - "EXECUTABLES", - "LIBRARIES", - "MODULES", - "POST_EXCLUDE_FILES", - "POST_EXCLUDE_FILES_STRICT", - "POST_EXCLUDE_REGEXES", - "POST_INCLUDE_FILES", - "POST_INCLUDE_REGEXES", - "PRE_EXCLUDE_REGEXES", - "PRE_INCLUDE_REGEXES", + static const std::vector<cm::string_view> LIST_ARGS = { + "DIRECTORIES"_s, + "EXECUTABLES"_s, + "LIBRARIES"_s, + "MODULES"_s, + "POST_EXCLUDE_FILES"_s, + "POST_EXCLUDE_FILES_STRICT"_s, + "POST_EXCLUDE_REGEXES"_s, + "POST_INCLUDE_FILES"_s, + "POST_INCLUDE_REGEXES"_s, + "PRE_EXCLUDE_REGEXES"_s, + "PRE_INCLUDE_REGEXES"_s, }; auto kwbegin = keywordsMissingValues.cbegin(); auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); @@ -3235,8 +3216,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, { struct Arguments { - std::string Output; - std::string Content; + cm::optional<std::string> Output; + cm::optional<std::string> Content; bool EscapeQuotes = false; bool AtOnly = false; std::string NewlineStyle; @@ -3251,11 +3232,10 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle); std::vector<std::string> unrecognizedArguments; - std::vector<std::string> keywordsMissingArguments; - std::vector<std::string> parsedKeywords; + std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, - &keywordsMissingArguments, &parsedKeywords); + &keywordsMissingValues); auto argIt = unrecognizedArguments.begin(); if (argIt != unrecognizedArguments.end()) { @@ -3265,28 +3245,28 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, return false; } - std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" }; - for (auto const& e : mandatoryOptions) { - const bool optionHasNoValue = - std::find(keywordsMissingArguments.begin(), - keywordsMissingArguments.end(), - e) != keywordsMissingArguments.end(); - if (optionHasNoValue) { - status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value.")); - cmSystemTools::SetFatalErrorOccurred(); - return false; - } + // Arguments that are allowed to be empty lists. Keep entries sorted! + static const std::vector<cm::string_view> LIST_ARGS = { + "NEWLINE_STYLE"_s, // Filter here so we can issue a custom error below. + }; + auto kwbegin = keywordsMissingValues.cbegin(); + auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); + if (kwend != kwbegin) { + status.SetError(cmStrCat("CONFIGURE keywords missing values:\n ", + cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + cmSystemTools::SetFatalErrorOccurred(); + return false; } - for (auto const& e : mandatoryOptions) { - const bool optionGiven = - std::find(parsedKeywords.begin(), parsedKeywords.end(), e) != - parsedKeywords.end(); - if (!optionGiven) { - status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory.")); - cmSystemTools::SetFatalErrorOccurred(); - return false; - } + if (!parsedArgs.Output) { + status.SetError("CONFIGURE OUTPUT option is mandatory."); + cmSystemTools::SetFatalErrorOccurred(); + return false; + } + if (!parsedArgs.Content) { + status.SetError("CONFIGURE CONTENT option is mandatory."); + cmSystemTools::SetFatalErrorOccurred(); + return false; } std::string errorMessage; @@ -3298,7 +3278,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, // Check for generator expressions std::string outputFile = cmSystemTools::CollapseFullPath( - parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory()); + *parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory()); std::string::size_type pos = outputFile.find_first_of("<>"); if (pos != std::string::npos) { @@ -3347,7 +3327,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, fout.SetCopyIfDifferent(true); // copy input to output and expand variables from input at the same time - std::stringstream sin(parsedArgs.Content, std::ios::in); + std::stringstream sin(*parsedArgs.Content, std::ios::in); std::string inLine; std::string outLine; bool hasNewLine = false; @@ -3392,7 +3372,7 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, .Bind("PATHS"_s, &Arguments::Paths); std::vector<std::string> unrecognizedArguments; - std::vector<std::string> keywordsMissingValues; + std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, &keywordsMissingValues); @@ -3404,12 +3384,12 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, } // Arguments that are allowed to be empty lists. Keep entries sorted! - const std::vector<std::string> LIST_ARGS = { - "MTIME", // "MTIME" should not be in this list because it requires one - // value, but it has long been accidentally accepted without - // one and treated as if an empty value were given. - // Fixing this would require a policy. - "PATHS", // "PATHS" is here only so we can issue a custom error below. + static const std::vector<cm::string_view> LIST_ARGS = { + "MTIME"_s, // "MTIME" should not be in this list because it requires one + // value, but it has long been accidentally accepted without + // one and treated as if an empty value were given. + // Fixing this would require a policy. + "PATHS"_s, // "PATHS" is here only so we can issue a custom error below. }; auto kwbegin = keywordsMissingValues.cbegin(); auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); @@ -3525,7 +3505,7 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, .Bind("TOUCH"_s, &Arguments::Touch); std::vector<std::string> unrecognizedArguments; - std::vector<std::string> keywordsMissingValues; + std::vector<cm::string_view> keywordsMissingValues; auto parsedArgs = parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, &keywordsMissingValues); @@ -3537,7 +3517,7 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, } // Arguments that are allowed to be empty lists. Keep entries sorted! - const std::vector<std::string> LIST_ARGS = { "PATTERNS" }; + static const std::vector<cm::string_view> LIST_ARGS = { "PATTERNS"_s }; auto kwbegin = keywordsMissingValues.cbegin(); auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); if (kwend != kwbegin) { @@ -3648,7 +3628,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, .Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions); std::vector<std::string> pathEntries; - std::vector<std::string> keywordsMissingValues; + std::vector<cm::string_view> keywordsMissingValues; Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1), &pathEntries, &keywordsMissingValues); @@ -3672,7 +3652,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, if (!keywordsMissingValues.empty()) { for (const auto& i : keywordsMissingValues) { - status.SetError(i + " is not given any arguments"); + status.SetError(cmStrCat(i, " is not given any arguments")); cmSystemTools::SetFatalErrorOccurred(); } return false; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 7ca5b23..c03c205 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -12,6 +12,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> @@ -436,24 +437,22 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // These generic args also contain the targets and the export stuff std::vector<std::string> targetList; std::string exports; - std::vector<std::string> runtimeDependenciesArgVector; + cm::optional<std::vector<std::string>> runtimeDependenciesArgVector; std::string runtimeDependencySetArg; std::vector<std::string> unknownArgs; - std::vector<std::string> parsedArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); genericArgs.Bind("TARGETS"_s, targetList); genericArgs.Bind("EXPORT"_s, exports); genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector); genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg); - genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs); + genericArgs.Parse(genericArgVector, &unknownArgs); bool success = genericArgs.Finalize(); - bool withRuntimeDependencies = - std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") != - parsedArgs.end(); RuntimeDependenciesArgs runtimeDependenciesArgs = - RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector, - &unknownArgs); + runtimeDependenciesArgVector + ? RuntimeDependenciesArgHelper.Parse(*runtimeDependenciesArgVector, + &unknownArgs) + : RuntimeDependenciesArgs(); cmInstallCommandArguments archiveArgs(helper.DefaultComponentName); cmInstallCommandArguments libraryArgs(helper.DefaultComponentName); @@ -597,7 +596,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr; - if (withRuntimeDependencies) { + if (runtimeDependenciesArgVector) { if (!runtimeDependencySetArg.empty()) { status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and " "RUNTIME_DEPENDENCY_SET."); @@ -1137,7 +1136,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } } - if (withRuntimeDependencies && !runtimeDependencySet->Empty()) { + if (runtimeDependenciesArgVector && !runtimeDependencySet->Empty()) { AddInstallRuntimeDependenciesGenerator( helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs, std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary, @@ -2106,7 +2105,7 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args, // These generic args also contain the runtime dependency set std::string runtimeDependencySetArg; std::vector<std::string> runtimeDependencyArgVector; - std::vector<std::string> parsedArgs; + std::vector<cm::string_view> parsedArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg); genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr, diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 95f3e7e..5ea35e8 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -42,7 +42,7 @@ namespace { using options_map = std::map<std::string, bool>; using single_map = std::map<std::string, std::string>; using multi_map = std::map<std::string, std::vector<std::string>>; -using options_set = std::set<std::string>; +using options_set = std::set<cm::string_view>; struct UserArgumentParser : public cmArgumentParser<void> { @@ -208,7 +208,7 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args, } } - std::vector<std::string> keywordsMissingValues; + std::vector<cm::string_view> keywordsMissingValues; parser.Parse(list, &unparsed, &keywordsMissingValues); diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index e4244a6..76b0384 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -197,7 +197,7 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent( bool TargetSourcesImpl::HandleFileSetMode( const std::string& scope, const std::vector<std::string>& content) { - auto args = FileSetsArgsParser.Parse(content); + auto args = FileSetsArgsParser.Parse(content, /*unparsedArguments=*/nullptr); for (auto& argList : args.FileSets) { argList.emplace(argList.begin(), "FILE_SET"_s); diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 965690c..52c5861 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -6,6 +6,7 @@ #include <string> #include <vector> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> @@ -19,39 +20,50 @@ struct Result bool Option2 = false; std::string String1; - std::string String2; + cm::optional<std::string> String2; + cm::optional<std::string> String3; std::vector<std::string> List1; std::vector<std::string> List2; - std::vector<std::string> List3; + cm::optional<std::vector<std::string>> List3; + cm::optional<std::vector<std::string>> List4; + cm::optional<std::vector<std::string>> List5; std::vector<std::vector<std::string>> Multi1; std::vector<std::vector<std::string>> Multi2; - std::vector<std::vector<std::string>> Multi3; + cm::optional<std::vector<std::vector<std::string>>> Multi3; + cm::optional<std::vector<std::vector<std::string>>> Multi4; }; std::initializer_list<cm::string_view> const args = { /* clang-format off */ "OPTION_1", // option + // "OPTION_2", // option that is not present "STRING_1", // string arg missing value - "STRING_2", "foo", "bar", // string arg + unparsed value + "STRING_2", "foo", "bar", // string arg + unparsed value, presence captured + // "STRING_3", // string arg that is not present "LIST_1", // list arg missing values "LIST_2", "foo", "bar", // list arg with 2 elems "LIST_3", "bar", // list arg ... "LIST_3", "foo", // ... with continuation + "LIST_4", // list arg missing values, presence captured + // "LIST_5", // list arg that is not present "MULTI_2", // multi list with 0 lists "MULTI_3", "foo", "bar", // multi list with first list with two elems "MULTI_3", "bar", "foo", // multi list with second list with two elems + // "MULTI_4", // multi list arg that is not present /* clang-format on */ }; bool verifyResult(Result const& result, std::vector<std::string> const& unparsedArguments, - std::vector<std::string> const& keywordsMissingValue) + std::vector<cm::string_view> const& keywordsMissingValue) { static std::vector<std::string> const foobar = { "foo", "bar" }; static std::vector<std::string> const barfoo = { "bar", "foo" }; - static std::vector<std::string> const missing = { "STRING_1", "LIST_1" }; + static std::vector<cm::string_view> const missing = { "STRING_1"_s, + "LIST_1"_s, + "LIST_4"_s }; #define ASSERT_TRUE(x) \ do { \ @@ -65,18 +77,26 @@ bool verifyResult(Result const& result, ASSERT_TRUE(!result.Option2); ASSERT_TRUE(result.String1.empty()); - ASSERT_TRUE(result.String2 == "foo"); + ASSERT_TRUE(result.String2); + ASSERT_TRUE(*result.String2 == "foo"); + ASSERT_TRUE(!result.String3); ASSERT_TRUE(result.List1.empty()); ASSERT_TRUE(result.List2 == foobar); - ASSERT_TRUE(result.List3 == barfoo); + ASSERT_TRUE(result.List3); + ASSERT_TRUE(*result.List3 == barfoo); + ASSERT_TRUE(result.List4); + ASSERT_TRUE(result.List4->empty()); + ASSERT_TRUE(!result.List5); ASSERT_TRUE(result.Multi1.empty()); ASSERT_TRUE(result.Multi2.size() == 1); ASSERT_TRUE(result.Multi2[0].empty()); - ASSERT_TRUE(result.Multi3.size() == 2); - ASSERT_TRUE(result.Multi3[0] == foobar); - ASSERT_TRUE(result.Multi3[1] == barfoo); + ASSERT_TRUE(result.Multi3); + ASSERT_TRUE((*result.Multi3).size() == 2); + ASSERT_TRUE((*result.Multi3)[0] == foobar); + ASSERT_TRUE((*result.Multi3)[1] == barfoo); + ASSERT_TRUE(!result.Multi4); ASSERT_TRUE(unparsedArguments.size() == 1); ASSERT_TRUE(unparsedArguments[0] == "bar"); @@ -89,19 +109,23 @@ bool testArgumentParserDynamic() { Result result; std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValue; + std::vector<cm::string_view> keywordsMissingValue; cmArgumentParser<void>{} .Bind("OPTION_1"_s, result.Option1) .Bind("OPTION_2"_s, result.Option2) .Bind("STRING_1"_s, result.String1) .Bind("STRING_2"_s, result.String2) + .Bind("STRING_3"_s, result.String3) .Bind("LIST_1"_s, result.List1) .Bind("LIST_2"_s, result.List2) .Bind("LIST_3"_s, result.List3) + .Bind("LIST_4"_s, result.List4) + .Bind("LIST_5"_s, result.List5) .Bind("MULTI_1"_s, result.Multi1) .Bind("MULTI_2"_s, result.Multi2) .Bind("MULTI_3"_s, result.Multi3) + .Bind("MULTI_4"_s, result.Multi4) .Parse(args, &unparsedArguments, &keywordsMissingValue); return verifyResult(result, unparsedArguments, keywordsMissingValue); @@ -115,15 +139,19 @@ bool testArgumentParserStatic() .Bind("OPTION_2"_s, &Result::Option2) .Bind("STRING_1"_s, &Result::String1) .Bind("STRING_2"_s, &Result::String2) + .Bind("STRING_3"_s, &Result::String3) .Bind("LIST_1"_s, &Result::List1) .Bind("LIST_2"_s, &Result::List2) .Bind("LIST_3"_s, &Result::List3) + .Bind("LIST_4"_s, &Result::List4) + .Bind("LIST_5"_s, &Result::List5) .Bind("MULTI_1"_s, &Result::Multi1) .Bind("MULTI_2"_s, &Result::Multi2) - .Bind("MULTI_3"_s, &Result::Multi3); + .Bind("MULTI_3"_s, &Result::Multi3) + .Bind("MULTI_4"_s, &Result::Multi4); std::vector<std::string> unparsedArguments; - std::vector<std::string> keywordsMissingValue; + std::vector<cm::string_view> keywordsMissingValue; Result const result = parser.Parse(args, &unparsedArguments, &keywordsMissingValue); diff --git a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt index a6ea314..dd6a2e7 100644 --- a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt +++ b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt @@ -1,4 +1,6 @@ CMake Error at BadArgContent.cmake:[0-9]+ \(file\): - file CONFIGURE CONTENT option needs a value. + file CONFIGURE keywords missing values: + + CONTENT Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt index b5a924c..e1bf7b4 100644 --- a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt +++ b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt @@ -1,4 +1,6 @@ CMake Error at BadArgOutput.cmake:[0-9]+ \(file\): - file CONFIGURE OUTPUT option needs a value. + file CONFIGURE keywords missing values: + + OUTPUT Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/NoArgContent-result.txt b/Tests/RunCMake/File_Configure/NoArgContent-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgContent-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/File_Configure/NoArgContent-stderr.txt b/Tests/RunCMake/File_Configure/NoArgContent-stderr.txt new file mode 100644 index 0000000..2e8dd9a --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgContent-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at NoArgContent.cmake:[0-9]+ \(file\): + file CONFIGURE CONTENT option is mandatory. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/File_Configure/NoArgContent.cmake b/Tests/RunCMake/File_Configure/NoArgContent.cmake new file mode 100644 index 0000000..cf52c46 --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgContent.cmake @@ -0,0 +1 @@ +file(CONFIGURE OUTPUT "") diff --git a/Tests/RunCMake/File_Configure/NoArgOutput-result.txt b/Tests/RunCMake/File_Configure/NoArgOutput-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgOutput-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/File_Configure/NoArgOutput-stderr.txt b/Tests/RunCMake/File_Configure/NoArgOutput-stderr.txt new file mode 100644 index 0000000..53de48b --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgOutput-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at NoArgOutput.cmake:[0-9]+ \(file\): + file CONFIGURE OUTPUT option is mandatory. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/File_Configure/NoArgOutput.cmake b/Tests/RunCMake/File_Configure/NoArgOutput.cmake new file mode 100644 index 0000000..77e9cdc --- /dev/null +++ b/Tests/RunCMake/File_Configure/NoArgOutput.cmake @@ -0,0 +1 @@ +file(CONFIGURE CONTENT "") diff --git a/Tests/RunCMake/File_Configure/RunCMakeTest.cmake b/Tests/RunCMake/File_Configure/RunCMakeTest.cmake index 5022985..008ce67 100644 --- a/Tests/RunCMake/File_Configure/RunCMakeTest.cmake +++ b/Tests/RunCMake/File_Configure/RunCMakeTest.cmake @@ -9,6 +9,8 @@ run_cmake(DirOutput) run_cmake(NewLineStyle-NoArg) run_cmake(NewLineStyle-ValidArg) run_cmake(NewLineStyle-WrongArg) +run_cmake(NoArgOutput) +run_cmake(NoArgContent) run_cmake(SubDir) run_cmake(AtOnly) run_cmake(EscapeQuotes) diff --git a/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt b/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt index e823b25..4278bce 100644 --- a/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt +++ b/Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt @@ -1,4 +1,6 @@ CMake Error at EmptyCondition1.cmake:2 \(file\): - file Incorrect arguments to GENERATE subcommand. + file GENERATE keywords missing values: + + CONDITION Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/File_Generate/InputAndContent-check.cmake b/Tests/RunCMake/File_Generate/InputAndContent-check.cmake new file mode 100644 index 0000000..5c9b803 --- /dev/null +++ b/Tests/RunCMake/File_Generate/InputAndContent-check.cmake @@ -0,0 +1,8 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/output-INPUT.txt" input) +if(NOT input MATCHES "INPUT file") + string(APPEND RunCMake_TEST_FAILED "INPUT incorrectly overridden by CONTENT") +endif() +file(READ "${RunCMake_TEST_BINARY_DIR}/output-CONTENT.txt" content) +if(NOT content MATCHES "CONTENT argument") + string(APPEND RunCMake_TEST_FAILED "CONTENT incorrectly overridden by INPUT") +endif() diff --git a/Tests/RunCMake/File_Generate/InputAndContent-input.txt b/Tests/RunCMake/File_Generate/InputAndContent-input.txt new file mode 100644 index 0000000..73f162b --- /dev/null +++ b/Tests/RunCMake/File_Generate/InputAndContent-input.txt @@ -0,0 +1 @@ +INPUT file diff --git a/Tests/RunCMake/File_Generate/InputAndContent.cmake b/Tests/RunCMake/File_Generate/InputAndContent.cmake new file mode 100644 index 0000000..9c3977a --- /dev/null +++ b/Tests/RunCMake/File_Generate/InputAndContent.cmake @@ -0,0 +1,10 @@ +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-INPUT.txt" + INPUT "${CMAKE_CURRENT_SOURCE_DIR}/InputAndContent-input.txt" + CONTENT "CONTENT argument" +) +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-CONTENT.txt" + CONTENT "CONTENT argument" + INPUT "${CMAKE_CURRENT_SOURCE_DIR}/InputAndContent-input.txt" +) diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt index bc71f2f..4059bf8 100644 --- a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt +++ b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt @@ -1,4 +1,6 @@ CMake Error at NewLineStyle-NoArg.cmake:[0-9]+ \(file\): - file Incorrect arguments to GENERATE subcommand. + file GENERATE keywords missing values: + + NEWLINE_STYLE Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/File_Generate/RunCMakeTest.cmake b/Tests/RunCMake/File_Generate/RunCMakeTest.cmake index be3bf04..5a670ae 100644 --- a/Tests/RunCMake/File_Generate/RunCMakeTest.cmake +++ b/Tests/RunCMake/File_Generate/RunCMakeTest.cmake @@ -17,6 +17,7 @@ run_cmake(EmptyCondition2) run_cmake(BadCondition) run_cmake(DebugEvaluate) run_cmake(GenerateSource) +run_cmake(InputAndContent) run_cmake(OutputNameMatchesSources) run_cmake(OutputNameMatchesObjects) run_cmake(OutputNameMatchesOtherSources) |