diff options
Diffstat (limited to 'Source/cmStringCommand.cxx')
-rw-r--r-- | Source/cmStringCommand.cxx | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 252d985..998f904 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -1,9 +1,13 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#define _SCL_SECURE_NO_WARNINGS + #include "cmStringCommand.h" #include "cmsys/RegularExpression.hxx" +#include <algorithm> #include <ctype.h> +#include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> @@ -13,6 +17,7 @@ #include "cmCryptoHash.h" #include "cmGeneratorExpression.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmStringReplaceHelper.h" #include "cmSystemTools.h" @@ -79,6 +84,9 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "STRIP") { return this->HandleStripCommand(args); } + if (subCommand == "REPEAT") { + return this->HandleRepeatCommand(args); + } if (subCommand == "RANDOM") { return this->HandleRandomCommand(args); } @@ -709,6 +717,59 @@ bool cmStringCommand::HandleStripCommand(std::vector<std::string> const& args) return true; } +bool cmStringCommand::HandleRepeatCommand(std::vector<std::string> const& args) +{ + // `string(REPEAT "<str>" <times> OUTPUT_VARIABLE)` + enum ArgPos : std::size_t + { + SUB_COMMAND, + VALUE, + TIMES, + OUTPUT_VARIABLE, + TOTAL_ARGS + }; + + if (args.size() != ArgPos::TOTAL_ARGS) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "sub-command REPEAT requires three arguments."); + return true; + } + + unsigned long times; + if (!cmSystemTools::StringToULong(args[ArgPos::TIMES].c_str(), ×)) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "repeat count is not a positive number."); + return true; + } + + const auto& stringValue = args[ArgPos::VALUE]; + const auto& variableName = args[ArgPos::OUTPUT_VARIABLE]; + const auto inStringLength = stringValue.size(); + + std::string result; + switch (inStringLength) { + case 0u: + // Nothing to do for zero length input strings + break; + case 1u: + // NOTE If the string to repeat consists of the only character, + // use the appropriate constructor. + result = std::string(times, stringValue[0]); + break; + default: + result = std::string(inStringLength * times, char{}); + for (auto i = 0u; i < times; ++i) { + std::copy(cm::cbegin(stringValue), cm::cend(stringValue), + &result[i * inStringLength]); + } + break; + } + + this->Makefile->AddDefinition(variableName, result.c_str()); + return true; +} + bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args) { if (args.size() < 2 || args.size() == 3 || args.size() == 5) { |