|
|
@@ -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) {
|