From 536cca60ea1c037d751b03bf5da8385783856000 Mon Sep 17 00:00:00 2001 From: Alex Turbov Date: Sat, 6 Apr 2019 17:53:58 +0800 Subject: string: introduce `REPEAT` sub-command --- Help/command/string.rst | 9 ++++ Help/release/dev/string-repeat.rst | 4 ++ Source/cmStringCommand.cxx | 61 ++++++++++++++++++++++ Source/cmStringCommand.h | 1 + Tests/RunCMake/string/Repeat.cmake | 45 ++++++++++++++++ .../RunCMake/string/RepeatNegativeCount-result.txt | 1 + .../RunCMake/string/RepeatNegativeCount-stderr.txt | 4 ++ Tests/RunCMake/string/RepeatNegativeCount.cmake | 1 + Tests/RunCMake/string/RepeatNoArgs-result.txt | 1 + Tests/RunCMake/string/RepeatNoArgs-stderr.txt | 4 ++ Tests/RunCMake/string/RepeatNoArgs.cmake | 1 + Tests/RunCMake/string/RunCMakeTest.cmake | 4 ++ 12 files changed, 136 insertions(+) create mode 100644 Help/release/dev/string-repeat.rst create mode 100644 Tests/RunCMake/string/Repeat.cmake create mode 100644 Tests/RunCMake/string/RepeatNegativeCount-result.txt create mode 100644 Tests/RunCMake/string/RepeatNegativeCount-stderr.txt create mode 100644 Tests/RunCMake/string/RepeatNegativeCount.cmake create mode 100644 Tests/RunCMake/string/RepeatNoArgs-result.txt create mode 100644 Tests/RunCMake/string/RepeatNoArgs-stderr.txt create mode 100644 Tests/RunCMake/string/RepeatNoArgs.cmake diff --git a/Help/command/string.rst b/Help/command/string.rst index 893fb43..2e89d7b 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -28,6 +28,7 @@ Synopsis string(`SUBSTRING`_ ) string(`STRIP`_ ) string(`GENEX_STRIP`_ ) + string(`REPEAT`_ ) `Comparison`_ string(`COMPARE`_ ) @@ -269,6 +270,14 @@ trailing spaces removed. Strip any :manual:`generator expressions ` from the ``input string`` and store the result in the ``output variable``. +.. _REPEAT: + +.. code-block:: cmake + + string(REPEAT ) + +Produce the output string as repetion of ``input string`` ``count`` times. + Comparison ^^^^^^^^^^ diff --git a/Help/release/dev/string-repeat.rst b/Help/release/dev/string-repeat.rst new file mode 100644 index 0000000..4be0d5c --- /dev/null +++ b/Help/release/dev/string-repeat.rst @@ -0,0 +1,4 @@ +string-repeat +-------------- + +* The :command:`string` learned a new sub-command ``REPEAT``. 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 #include +#include #include // IWYU pragma: keep #include #include @@ -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 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 const& args) return true; } +bool cmStringCommand::HandleRepeatCommand(std::vector const& args) +{ + // `string(REPEAT "" 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 const& args) { if (args.size() < 2 || args.size() == 3 || args.size() == 5) { diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index cbff73e..acde605 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -51,6 +51,7 @@ protected: bool HandleConcatCommand(std::vector const& args); bool HandleJoinCommand(std::vector const& args); bool HandleStripCommand(std::vector const& args); + bool HandleRepeatCommand(std::vector const& args); bool HandleRandomCommand(std::vector const& args); bool HandleFindCommand(std::vector const& args); bool HandleTimestampCommand(std::vector const& args); diff --git a/Tests/RunCMake/string/Repeat.cmake b/Tests/RunCMake/string/Repeat.cmake new file mode 100644 index 0000000..fc390aa --- /dev/null +++ b/Tests/RunCMake/string/Repeat.cmake @@ -0,0 +1,45 @@ +string(REPEAT "q" 4 q_out) + +if(NOT DEFINED q_out) + message(FATAL_ERROR "q_out is not defined") +endif() + +if(NOT q_out STREQUAL "qqqq") + message(FATAL_ERROR "unexpected result") +endif() + +string(REPEAT "1234" 0 zero_out) + +if(NOT DEFINED zero_out) + message(FATAL_ERROR "zero_out is not defined") +endif() + +if(NOT zero_out STREQUAL "") + message(FATAL_ERROR "unexpected result") +endif() + +unset(zero_out) + +string(REPEAT "" 100 zero_out) + +if(NOT DEFINED zero_out) + message(FATAL_ERROR "zero_out is not defined") +endif() + +if(NOT zero_out STREQUAL "") + message(FATAL_ERROR "unexpected result") +endif() + +string(REPEAT "1" 1 one_out) + +if(NOT one_out STREQUAL "1") + message(FATAL_ERROR "unexpected result") +endif() + +unset(one_out) + +string(REPEAT "one" 1 one_out) + +if(NOT one_out STREQUAL "one") + message(FATAL_ERROR "unexpected result") +endif() diff --git a/Tests/RunCMake/string/RepeatNegativeCount-result.txt b/Tests/RunCMake/string/RepeatNegativeCount-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/string/RepeatNegativeCount-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt b/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt new file mode 100644 index 0000000..bbd498e --- /dev/null +++ b/Tests/RunCMake/string/RepeatNegativeCount-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at RepeatNegativeCount.cmake:[0-9]+ \(string\): + repeat count is not a positive number. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/string/RepeatNegativeCount.cmake b/Tests/RunCMake/string/RepeatNegativeCount.cmake new file mode 100644 index 0000000..769e7c0 --- /dev/null +++ b/Tests/RunCMake/string/RepeatNegativeCount.cmake @@ -0,0 +1 @@ +string(REPEAT "blah" -1 out) diff --git a/Tests/RunCMake/string/RepeatNoArgs-result.txt b/Tests/RunCMake/string/RepeatNoArgs-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/string/RepeatNoArgs-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/string/RepeatNoArgs-stderr.txt b/Tests/RunCMake/string/RepeatNoArgs-stderr.txt new file mode 100644 index 0000000..5abcb3b --- /dev/null +++ b/Tests/RunCMake/string/RepeatNoArgs-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at RepeatNoArgs.cmake:[0-9]+ \(string\): + sub-command REPEAT requires three arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/string/RepeatNoArgs.cmake b/Tests/RunCMake/string/RepeatNoArgs.cmake new file mode 100644 index 0000000..e327e99 --- /dev/null +++ b/Tests/RunCMake/string/RepeatNoArgs.cmake @@ -0,0 +1 @@ +string(REPEAT) diff --git a/Tests/RunCMake/string/RunCMakeTest.cmake b/Tests/RunCMake/string/RunCMakeTest.cmake index 211337a..c432b4e 100644 --- a/Tests/RunCMake/string/RunCMakeTest.cmake +++ b/Tests/RunCMake/string/RunCMakeTest.cmake @@ -33,3 +33,7 @@ run_cmake(UTF-16BE) run_cmake(UTF-16LE) run_cmake(UTF-32BE) run_cmake(UTF-32LE) + +run_cmake(Repeat) +run_cmake(RepeatNoArgs) +run_cmake(RepeatNegativeCount) -- cgit v0.12