diff options
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r-- | Source/cmFileCommand.cxx | 280 |
1 files changed, 216 insertions, 64 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 8a3aad2df..f674833ea 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -15,6 +15,7 @@ #include <vector> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -63,7 +64,7 @@ # include "cmFileLockResult.h" #endif -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) # include "cmELF.h" #endif @@ -333,7 +334,7 @@ bool HandleStringsCommand(std::vector<std::string> const& args, arg_limit_count, arg_length_minimum, arg_length_maximum, - arg__maximum, + arg_maximum, arg_regex, arg_encoding }; @@ -557,8 +558,7 @@ bool HandleStringsCommand(std::vector<std::string> const& args, // back subsequent characters if ((current_str.length() != num_utf8_bytes)) { for (unsigned int j = 0; j < current_str.size() - 1; j++) { - c = current_str[current_str.size() - 1 - j]; - fin.putback(static_cast<char>(c)); + fin.putback(current_str[current_str.size() - 1 - j]); } current_str.clear(); } @@ -1198,7 +1198,7 @@ bool HandleReadElfCommand(std::vector<std::string> const& args, return false; } -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) cmELF elf(fileNameArg.c_str()); if (!arguments.RPath.empty()) { @@ -2290,6 +2290,7 @@ void AddEvaluationFile(const std::string& inputName, const std::string& targetName, const std::string& outputExpr, const std::string& condition, bool inputIsContent, + const std::string& newLineCharacter, mode_t permissions, cmExecutionStatus& status) { cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace(); @@ -2304,7 +2305,7 @@ void AddEvaluationFile(const std::string& inputName, status.GetMakefile().AddEvaluationFile( inputName, targetName, std::move(outputCge), std::move(conditionCge), - inputIsContent); + newLineCharacter, permissions, inputIsContent); } bool HandleGenerateCommand(std::vector<std::string> const& args, @@ -2314,49 +2315,171 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - if (args[1] != "OUTPUT") { + + struct Arguments + { + std::string Output; + std::string Input; + std::string Content; + std::string Condition; + std::string Target; + std::string NewLineStyle; + bool NoSourcePermissions = false; + bool UseSourcePermissions = false; + std::vector<std::string> FilePermissions; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("INPUT"_s, &Arguments::Input) + .Bind("CONTENT"_s, &Arguments::Content) + .Bind("CONDITION"_s, &Arguments::Condition) + .Bind("TARGET"_s, &Arguments::Target) + .Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions) + .Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions) + .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions) + .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle); + + std::vector<std::string> unparsedArguments; + std::vector<std::string> keywordsMissingValues; + std::vector<std::string> parsedKeywords; + Arguments const arguments = + parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments, + &keywordsMissingValues, &parsedKeywords); + + if (!keywordsMissingValues.empty()) { + status.SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + + if (!unparsedArguments.empty()) { + status.SetError("Unknown argument to GENERATE subcommand."); + 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 (!mandatoryOptionsSpecified) { status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - std::string condition; - std::string target; + const bool conditionOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) != + parsedKeywords.end(); + if (conditionOptionSpecified && arguments.Condition.empty()) { + status.SetError("CONDITION of sub-command GENERATE must not be empty " + "if specified."); + return false; + } - for (std::size_t i = 5; i < args.size();) { - const std::string& arg = args[i++]; + const bool targetOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) != + parsedKeywords.end(); + if (targetOptionSpecified && arguments.Target.empty()) { + status.SetError("TARGET of sub-command GENERATE must not be empty " + "if specified."); + return false; + } + + 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; + } - if (args.size() - i == 0) { - status.SetError("Incorrect arguments to GENERATE subcommand."); + 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) { + std::string errorMessage; + if (!newLineStyle.ReadFromArguments(args, errorMessage)) { + status.SetError(cmStrCat("GENERATE ", errorMessage)); return false; } + } - const std::string& value = args[i++]; + std::string input = arguments.Input; + if (inputIsContent) { + input = arguments.Content; + } - if (value.empty()) { - status.SetError( - arg + " of sub-command GENERATE must not be empty if specified."); + if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) { + status.SetError("given both NO_SOURCE_PERMISSIONS and " + "USE_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + + if (!arguments.FilePermissions.empty()) { + if (arguments.NoSourcePermissions) { + status.SetError("given both NO_SOURCE_PERMISSIONS and " + "FILE_PERMISSIONS. Only one option allowed."); + return false; + } + if (arguments.UseSourcePermissions) { + status.SetError("given both USE_SOURCE_PERMISSIONS and " + "FILE_PERMISSIONS. Only one option allowed."); return false; } + } - if (arg == "CONDITION") { - condition = value; - } else if (arg == "TARGET") { - target = value; - } else { - status.SetError("Unknown argument to GENERATE subcommand."); + if (arguments.UseSourcePermissions) { + if (inputIsContent) { + status.SetError("given USE_SOURCE_PERMISSIONS without a file INPUT."); return false; } } - std::string output = args[2]; - const bool inputIsContent = args[3] != "INPUT"; - if (inputIsContent && args[3] != "CONTENT") { - status.SetError("Incorrect arguments to GENERATE subcommand."); - return false; + mode_t permisiions = 0; + if (arguments.NoSourcePermissions) { + permisiions |= cmFSPermissions::mode_owner_read; + permisiions |= cmFSPermissions::mode_owner_write; + permisiions |= cmFSPermissions::mode_group_read; + permisiions |= cmFSPermissions::mode_world_read; } - std::string input = args[4]; - AddEvaluationFile(input, target, output, condition, inputIsContent, status); + if (!arguments.FilePermissions.empty()) { + std::vector<std::string> invalidOptions; + for (auto const& e : arguments.FilePermissions) { + if (!cmFSPermissions::stringToModeT(e, permisiions)) { + invalidOptions.push_back(e); + } + } + if (!invalidOptions.empty()) { + std::ostringstream oss; + oss << "given invalid permission "; + for (auto i = 0u; i < invalidOptions.size(); i++) { + if (i == 0u) { + oss << "\"" << invalidOptions[i] << "\""; + } else { + oss << ",\"" << invalidOptions[i] << "\""; + } + } + oss << "."; + status.SetError(oss.str()); + return false; + } + } + + AddEvaluationFile(input, arguments.Target, arguments.Output, + arguments.Condition, inputIsContent, + newLineStyle.GetCharacters(), permisiions, status); return true; } @@ -2902,17 +3025,60 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, bool HandleConfigureCommand(std::vector<std::string> 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<Arguments>{} + .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<std::string> unrecognizedArguments; + std::vector<std::string> keywordsMissingArguments; + std::vector<std::string> 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<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::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; @@ -2922,28 +3088,9 @@ bool HandleConfigureCommand(std::vector<std::string> 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) { @@ -2974,11 +3121,11 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, cmSystemTools::MakeDirectory(path); } - std::string newLineCharacters; + std::string newLineCharacters = "\n"; bool open_with_binary_flag = false; if (newLineStyle.IsValid()) { - open_with_binary_flag = true; newLineCharacters = newLineStyle.GetCharacters(); + open_with_binary_flag = true; } cmGeneratedFileStream fout; @@ -2992,13 +3139,18 @@ 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(input, std::ios::in); + std::stringstream sin(parsedArgs.Content, std::ios::in); std::string inLine; std::string outLine; - while (cmSystemTools::GetLineFromStream(sin, inLine)) { + bool hasNewLine = false; + while (cmSystemTools::GetLineFromStream(sin, inLine, &hasNewLine)) { outLine.clear(); - makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes); - fout << outLine << newLineCharacters; + makeFile.ConfigureString(inLine, outLine, parsedArgs.AtOnly, + parsedArgs.EscapeQuotes); + fout << outLine; + if (hasNewLine || newLineStyle.IsValid()) { + fout << newLineCharacters; + } } // close file before attempting to copy |