From 6d0712c225013161abe1c491db13726cbd90f9ec Mon Sep 17 00:00:00 2001 From: Asit Dhal Date: Sun, 13 Dec 2020 09:45:11 +0100 Subject: file(configure): Order of named options should be specified in any order Fixes: #20915 --- Source/cmFileCommand.cxx | 85 ++++++++++++++-------- Tests/RunCMake/File_Configure/AtOnly.cmake | 12 +++ Tests/RunCMake/File_Configure/BadArg-result.txt | 1 - Tests/RunCMake/File_Configure/BadArg-stderr.txt | 4 - Tests/RunCMake/File_Configure/BadArg.cmake | 1 - .../File_Configure/BadArgContent-result.txt | 0 .../File_Configure/BadArgContent-stderr.txt | 4 + Tests/RunCMake/File_Configure/BadArgContent.cmake | 1 + .../File_Configure/BadArgOutput-result.txt | 1 + .../File_Configure/BadArgOutput-stderr.txt | 4 + Tests/RunCMake/File_Configure/BadArgOutput.cmake | 1 + Tests/RunCMake/File_Configure/EscapeQuotes.cmake | 12 +++ Tests/RunCMake/File_Configure/RunCMakeTest.cmake | 6 +- .../File_Configure/UnrecognizedArgs-result.txt | 1 + .../File_Configure/UnrecognizedArgs-stderr.txt | 4 + .../RunCMake/File_Configure/UnrecognizedArgs.cmake | 1 + 16 files changed, 101 insertions(+), 37 deletions(-) create mode 100644 Tests/RunCMake/File_Configure/AtOnly.cmake delete mode 100644 Tests/RunCMake/File_Configure/BadArg-result.txt delete mode 100644 Tests/RunCMake/File_Configure/BadArg-stderr.txt delete mode 100644 Tests/RunCMake/File_Configure/BadArg.cmake create mode 100644 Tests/RunCMake/File_Configure/BadArgContent-result.txt create mode 100644 Tests/RunCMake/File_Configure/BadArgContent-stderr.txt create mode 100644 Tests/RunCMake/File_Configure/BadArgContent.cmake create mode 100644 Tests/RunCMake/File_Configure/BadArgOutput-result.txt create mode 100644 Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt create mode 100644 Tests/RunCMake/File_Configure/BadArgOutput.cmake create mode 100644 Tests/RunCMake/File_Configure/EscapeQuotes.cmake create mode 100644 Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt create mode 100644 Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt create mode 100644 Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index cd440ad..9467c03 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -2946,17 +2946,60 @@ bool HandleGetRuntimeDependenciesCommand(std::vector const& args, bool HandleConfigureCommand(std::vector const& args, cmExecutionStatus& status) { - if (args.size() < 5) { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); + struct Arguments + { + std::string Output; + std::string Content; + bool EscapeQuotes = false; + bool AtOnly = false; + std::string NewlineStyle; + }; + + static auto const parser = + cmArgumentParser{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("CONTENT"_s, &Arguments::Content) + .Bind("ESCAPE_QUOTES"_s, &Arguments::EscapeQuotes) + .Bind("@ONLY"_s, &Arguments::AtOnly) + .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle); + + std::vector unrecognizedArguments; + std::vector keywordsMissingArguments; + std::vector parsedKeywords; + auto parsedArgs = + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, + &keywordsMissingArguments, &parsedKeywords); + + auto argIt = unrecognizedArguments.begin(); + if (argIt != unrecognizedArguments.end()) { + status.SetError( + cmStrCat("CONFIGURE Unrecognized argument: \"", *argIt, "\"")); + cmSystemTools::SetFatalErrorOccured(); return false; } - if (args[1] != "OUTPUT") { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); - return false; + + std::vector 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::SetFatalErrorOccured(); + return false; + } } - if (args[3] != "CONTENT") { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); - 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::SetFatalErrorOccured(); + return false; + } } std::string errorMessage; @@ -2966,28 +3009,9 @@ bool HandleConfigureCommand(std::vector const& args, return false; } - bool escapeQuotes = false; - bool atOnly = false; - for (unsigned int i = 5; i < args.size(); ++i) { - if (args[i] == "@ONLY") { - atOnly = true; - } else if (args[i] == "ESCAPE_QUOTES") { - escapeQuotes = true; - } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" || - args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" || - args[i] == "DOS") { - /* Options handled by NewLineStyle member above. */ - } else { - status.SetError( - cmStrCat("CONFIGURE Unrecognized argument \"", args[i], "\"")); - return false; - } - } - // Check for generator expressions - const std::string input = args[4]; std::string outputFile = cmSystemTools::CollapseFullPath( - args[2], status.GetMakefile().GetCurrentBinaryDirectory()); + parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory()); std::string::size_type pos = outputFile.find_first_of("<>"); if (pos != std::string::npos) { @@ -3036,12 +3060,13 @@ bool HandleConfigureCommand(std::vector const& args, fout.SetCopyIfDifferent(true); // copy input to output and expand variables from input at the same time - std::stringstream sin(input, std::ios::in); + std::stringstream sin(parsedArgs.Content, std::ios::in); std::string inLine; std::string outLine; while (cmSystemTools::GetLineFromStream(sin, inLine)) { outLine.clear(); - makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes); + makeFile.ConfigureString(inLine, outLine, parsedArgs.AtOnly, + parsedArgs.EscapeQuotes); fout << outLine << newLineCharacters; } diff --git a/Tests/RunCMake/File_Configure/AtOnly.cmake b/Tests/RunCMake/File_Configure/AtOnly.cmake new file mode 100644 index 0000000..cc5304a --- /dev/null +++ b/Tests/RunCMake/File_Configure/AtOnly.cmake @@ -0,0 +1,12 @@ +set(file_name ${CMAKE_CURRENT_BINARY_DIR}/atonly.txt) +set(var_a "a") +set(var_b "b") +file(CONFIGURE + OUTPUT ${file_name} + CONTENT "-->@var_a@<-- -->${var_b}<--" + @ONLY +) +file(READ ${file_name} file_content) +if(NOT file_content STREQUAL "-->a<-- -->${var_b}<--") + message(FATAL_ERROR "@ONLY doesn't work") +endif() diff --git a/Tests/RunCMake/File_Configure/BadArg-result.txt b/Tests/RunCMake/File_Configure/BadArg-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/File_Configure/BadArg-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/File_Configure/BadArg-stderr.txt b/Tests/RunCMake/File_Configure/BadArg-stderr.txt deleted file mode 100644 index 5423a28..0000000 --- a/Tests/RunCMake/File_Configure/BadArg-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at BadArg.cmake:[0-9]+ \(file\): - file Incorrect arguments to CONFIGURE subcommand. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/BadArg.cmake b/Tests/RunCMake/File_Configure/BadArg.cmake deleted file mode 100644 index 7c7fcda..0000000 --- a/Tests/RunCMake/File_Configure/BadArg.cmake +++ /dev/null @@ -1 +0,0 @@ -file(CONFIGURE OUTPUT) diff --git a/Tests/RunCMake/File_Configure/BadArgContent-result.txt b/Tests/RunCMake/File_Configure/BadArgContent-result.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt new file mode 100644 index 0000000..a6ea314 --- /dev/null +++ b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at BadArgContent.cmake:[0-9]+ \(file\): + file CONFIGURE CONTENT option needs a value. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/BadArgContent.cmake b/Tests/RunCMake/File_Configure/BadArgContent.cmake new file mode 100644 index 0000000..282dc18 --- /dev/null +++ b/Tests/RunCMake/File_Configure/BadArgContent.cmake @@ -0,0 +1 @@ +file(CONFIGURE CONTENT) diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-result.txt b/Tests/RunCMake/File_Configure/BadArgOutput-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/File_Configure/BadArgOutput-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt new file mode 100644 index 0000000..b5a924c --- /dev/null +++ b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at BadArgOutput.cmake:[0-9]+ \(file\): + file CONFIGURE OUTPUT option needs a value. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/File_Configure/BadArgOutput.cmake b/Tests/RunCMake/File_Configure/BadArgOutput.cmake new file mode 100644 index 0000000..7c7fcda --- /dev/null +++ b/Tests/RunCMake/File_Configure/BadArgOutput.cmake @@ -0,0 +1 @@ +file(CONFIGURE OUTPUT) diff --git a/Tests/RunCMake/File_Configure/EscapeQuotes.cmake b/Tests/RunCMake/File_Configure/EscapeQuotes.cmake new file mode 100644 index 0000000..1136c87 --- /dev/null +++ b/Tests/RunCMake/File_Configure/EscapeQuotes.cmake @@ -0,0 +1,12 @@ +set(file_name ${CMAKE_CURRENT_BINARY_DIR}/escape_quotes.txt) +set(var "\t") +set(ref "${var}") +file(CONFIGURE + CONTENT "-->@ref@<--" + OUTPUT ${file_name} + ESCAPE_QUOTES +) +file(READ ${file_name} file_content) +if(NOT file_content MATCHES "^-->\t<--$") + message(FATAL_ERROR "ESCAPE_QUOTES doesn't work") +endif() diff --git a/Tests/RunCMake/File_Configure/RunCMakeTest.cmake b/Tests/RunCMake/File_Configure/RunCMakeTest.cmake index e79de79..5022985 100644 --- a/Tests/RunCMake/File_Configure/RunCMakeTest.cmake +++ b/Tests/RunCMake/File_Configure/RunCMakeTest.cmake @@ -1,10 +1,14 @@ include(RunCMake) run_cmake(AngleBracketsContent) -run_cmake(BadArg) +run_cmake(BadArgOutput) +run_cmake(BadArgContent) run_cmake(BadArgGeneratorExpressionOutput) +run_cmake(UnrecognizedArgs) run_cmake(DirOutput) run_cmake(NewLineStyle-NoArg) run_cmake(NewLineStyle-ValidArg) run_cmake(NewLineStyle-WrongArg) run_cmake(SubDir) +run_cmake(AtOnly) +run_cmake(EscapeQuotes) diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt b/Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt b/Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt new file mode 100644 index 0000000..1dd1a20 --- /dev/null +++ b/Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at UnrecognizedArgs.cmake:[0-9]+ \(file\): + file CONFIGURE Unrecognized argument: "INPUT" +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake b/Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake new file mode 100644 index 0000000..93ea7b5 --- /dev/null +++ b/Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake @@ -0,0 +1 @@ +file(CONFIGURE INPUT) -- cgit v0.12