mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-24 09:09:43 -05:00
introduce cm::CMakeString class as helper for string() command
This class will be used, as helper for: * string() command * future $<STRING> generator expression
This commit is contained in:
@@ -135,6 +135,8 @@ add_library(
|
|||||||
cmCMakePresetsGraphReadJSONPackagePresets.cxx
|
cmCMakePresetsGraphReadJSONPackagePresets.cxx
|
||||||
cmCMakePresetsGraphReadJSONTestPresets.cxx
|
cmCMakePresetsGraphReadJSONTestPresets.cxx
|
||||||
cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
|
cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
|
||||||
|
cmCMakeString.hxx
|
||||||
|
cmCMakeString.cxx
|
||||||
cmCommandLineArgument.h
|
cmCommandLineArgument.h
|
||||||
cmCommonTargetGenerator.cxx
|
cmCommonTargetGenerator.cxx
|
||||||
cmCommonTargetGenerator.h
|
cmCommonTargetGenerator.h
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||||
|
|
||||||
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include "cmCMakeString.hxx"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "cmsys/RegularExpression.hxx"
|
||||||
|
|
||||||
|
#include "cmCryptoHash.h"
|
||||||
|
#include "cmGeneratorExpression.h"
|
||||||
|
#include "cmMakefile.h"
|
||||||
|
#include "cmPolicies.h"
|
||||||
|
#include "cmStringAlgorithms.h"
|
||||||
|
#include "cmStringReplaceHelper.h"
|
||||||
|
#include "cmSystemTools.h"
|
||||||
|
#include "cmTimestamp.h"
|
||||||
|
#include "cmUuid.h"
|
||||||
|
|
||||||
|
namespace cm {
|
||||||
|
bool CMakeString::Compare(CompOperator op, cm::string_view other)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case CompOperator::EQUAL:
|
||||||
|
return this->String_ == other;
|
||||||
|
case CompOperator::LESS:
|
||||||
|
return this->String_ < other;
|
||||||
|
case CompOperator::LESS_EQUAL:
|
||||||
|
return this->String_ <= other;
|
||||||
|
case CompOperator::GREATER:
|
||||||
|
return this->String_ > other;
|
||||||
|
case CompOperator::GREATER_EQUAL:
|
||||||
|
return this->String_ >= other;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Replace(std::string const& matchExpression,
|
||||||
|
std::string const& replaceExpression,
|
||||||
|
Regex regex, cmMakefile* makefile)
|
||||||
|
{
|
||||||
|
if (regex == Regex::Yes) {
|
||||||
|
if (makefile) {
|
||||||
|
makefile->ClearMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmStringReplaceHelper replaceHelper(matchExpression, replaceExpression,
|
||||||
|
makefile);
|
||||||
|
if (!replaceHelper.IsReplaceExpressionValid()) {
|
||||||
|
throw std::invalid_argument(replaceHelper.GetError());
|
||||||
|
}
|
||||||
|
if (!replaceHelper.IsRegularExpressionValid()) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
cmStrCat("Failed to compile regex \"", matchExpression, '"'));
|
||||||
|
}
|
||||||
|
|
||||||
|
std ::string output;
|
||||||
|
if (!replaceHelper.Replace(this->String_, output)) {
|
||||||
|
throw std::runtime_error(replaceHelper.GetError());
|
||||||
|
}
|
||||||
|
this->String_ = std::move(output);
|
||||||
|
} else {
|
||||||
|
std::string output = this->String_.str();
|
||||||
|
cmsys::SystemTools::ReplaceString(output, matchExpression,
|
||||||
|
replaceExpression);
|
||||||
|
this->String_ = std::move(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
cmList CMakeString::Match(std::string const& matchExpression,
|
||||||
|
MatchItems matchItems, cmMakefile* makefile) const
|
||||||
|
{
|
||||||
|
if (makefile) {
|
||||||
|
makefile->ClearMatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the regular expression.
|
||||||
|
cmsys::RegularExpression re;
|
||||||
|
if (!re.compile(matchExpression)) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
cmStrCat("Failed to compile regex \"", matchExpression, '"'));
|
||||||
|
}
|
||||||
|
|
||||||
|
cmList output;
|
||||||
|
if (matchItems == MatchItems::Once) {
|
||||||
|
if (re.find(this->String_.data())) {
|
||||||
|
if (makefile) {
|
||||||
|
makefile->StoreMatches(re);
|
||||||
|
}
|
||||||
|
output = re.match();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned optAnchor = 0;
|
||||||
|
if (makefile &&
|
||||||
|
makefile->GetPolicyStatus(cmPolicies::CMP0186) != cmPolicies::NEW) {
|
||||||
|
optAnchor = cmsys::RegularExpression::BOL_AT_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan through the input for all matches.
|
||||||
|
std::string::size_type base = 0;
|
||||||
|
unsigned optNonEmpty = 0;
|
||||||
|
while (re.find(this->String_.data(), base, optAnchor | optNonEmpty)) {
|
||||||
|
if (makefile) {
|
||||||
|
makefile->ClearMatches();
|
||||||
|
makefile->StoreMatches(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_back(re.match());
|
||||||
|
base = re.end();
|
||||||
|
|
||||||
|
if (re.start() == this->String_.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (re.start() == re.end()) {
|
||||||
|
optNonEmpty = cmsys::RegularExpression::NONEMPTY_AT_OFFSET;
|
||||||
|
} else {
|
||||||
|
optNonEmpty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString CMakeString::Substring(long begin, long count) const
|
||||||
|
{
|
||||||
|
if (begin < 0 || static_cast<size_type>(begin) > this->String_.size()) {
|
||||||
|
throw std::out_of_range(cmStrCat(
|
||||||
|
"begin index: ", begin, " is out of range 0 - ", this->String_.size()));
|
||||||
|
}
|
||||||
|
if (count < -1) {
|
||||||
|
throw std::out_of_range(
|
||||||
|
cmStrCat("end index: ", count, " should be -1 or greater"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->String_.substr(static_cast<size_type>(begin),
|
||||||
|
count == -1 ? npos
|
||||||
|
: static_cast<size_type>(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Strip(StripItems stripItems)
|
||||||
|
{
|
||||||
|
if (stripItems == StripItems::Space) {
|
||||||
|
this->String_ = cmTrimWhitespace(this->String_);
|
||||||
|
} else {
|
||||||
|
this->String_ = cmGeneratorExpression::Preprocess(
|
||||||
|
this->String_, cmGeneratorExpression::StripAllGeneratorExpressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Repeat(size_type count)
|
||||||
|
{
|
||||||
|
switch (this->Size()) {
|
||||||
|
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.
|
||||||
|
this->String_ = std::string(count, this->String_[0]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::string result;
|
||||||
|
auto size = this->Size();
|
||||||
|
|
||||||
|
result.reserve(size * count);
|
||||||
|
for (auto i = 0u; i < count; ++i) {
|
||||||
|
result.insert(i * size, this->String_.data(), size);
|
||||||
|
}
|
||||||
|
this->String_ = std::move(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Quote(QuoteItems)
|
||||||
|
{
|
||||||
|
std ::string output;
|
||||||
|
// Escape all regex special characters
|
||||||
|
cmStringReplaceHelper replaceHelper("([][()+*^.$?|\\\\])", R"(\\\1)");
|
||||||
|
if (!replaceHelper.Replace(this->String_, output)) {
|
||||||
|
throw std::runtime_error(replaceHelper.GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
this->String_ = std::move(output);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Hash(cm::string_view hashAlgorithm)
|
||||||
|
{
|
||||||
|
std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(hashAlgorithm));
|
||||||
|
if (hash) {
|
||||||
|
this->String_ = hash->HashString(this->String_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::invalid_argument(
|
||||||
|
cmStrCat(hashAlgorithm, ": invalid hash algorithm."));
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::FromASCII(string_range codes)
|
||||||
|
{
|
||||||
|
std::string output;
|
||||||
|
output.reserve(codes.size());
|
||||||
|
|
||||||
|
for (auto const& code : codes) {
|
||||||
|
try {
|
||||||
|
auto ch = std::stoi(code);
|
||||||
|
if (ch > 0 && ch < 256) {
|
||||||
|
output += static_cast<char>(ch);
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
cmStrCat("Character with code ", code, " does not exist."));
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
cmStrCat("Character with code ", code, " does not exist."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->String_ = std::move(output);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::ToHexadecimal(cm::string_view str)
|
||||||
|
{
|
||||||
|
std::string output(str.size() * 2, ' ');
|
||||||
|
std::string::size_type hexIndex = 0;
|
||||||
|
|
||||||
|
for (auto const& c : str) {
|
||||||
|
std::snprintf(&output[hexIndex], 3, "%.2x", c & 0xFFu);
|
||||||
|
hexIndex += 2;
|
||||||
|
}
|
||||||
|
this->String_ = output;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm::string_view const CMakeString::RandomDefaultAlphabet{
|
||||||
|
"qwertyuiopasdfghjklzxcvbnm"
|
||||||
|
"QWERTYUIOPASDFGHJKLZXCVBNM"
|
||||||
|
"0123456789"
|
||||||
|
};
|
||||||
|
bool CMakeString::Seeded = false;
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Random(unsigned int seed, std::size_t length,
|
||||||
|
cm::string_view alphabet)
|
||||||
|
{
|
||||||
|
if (alphabet.empty()) {
|
||||||
|
alphabet = RandomDefaultAlphabet;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < 1) {
|
||||||
|
throw std::out_of_range("Invoked with bad length.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->Seeded) {
|
||||||
|
this->Seeded = true;
|
||||||
|
std::srand(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
double alphabetSize = static_cast<double>(alphabet.size());
|
||||||
|
std::vector<char> result;
|
||||||
|
result.reserve(length + 1);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < length; i++) {
|
||||||
|
auto index = static_cast<std::string::size_type>(
|
||||||
|
alphabetSize * std::rand() / (RAND_MAX + 1.0));
|
||||||
|
result.push_back(alphabet[index]);
|
||||||
|
}
|
||||||
|
result.push_back(0);
|
||||||
|
|
||||||
|
this->String_ = result.data();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::Timestamp(cm::string_view format, UTC utc)
|
||||||
|
{
|
||||||
|
cmTimestamp timestamp;
|
||||||
|
this->String_ = timestamp.CurrentTime(format, utc == UTC::Yes);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& CMakeString::UUID(cm::string_view nameSpace, cm::string_view name,
|
||||||
|
UUIDType type, Case uuidCase)
|
||||||
|
{
|
||||||
|
#if !defined(CMAKE_BOOTSTRAP)
|
||||||
|
cmUuid uuidGenerator;
|
||||||
|
std::vector<unsigned char> uuidNamespace;
|
||||||
|
std::string uuid;
|
||||||
|
|
||||||
|
if (!uuidGenerator.StringToBinary(nameSpace, uuidNamespace)) {
|
||||||
|
throw std::invalid_argument("malformed NAMESPACE UUID");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == UUIDType::MD5) {
|
||||||
|
uuid = uuidGenerator.FromMd5(uuidNamespace, name);
|
||||||
|
} else if (type == UUIDType::SHA1) {
|
||||||
|
uuid = uuidGenerator.FromSha1(uuidNamespace, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid.empty()) {
|
||||||
|
throw std::runtime_error("generation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuidCase == Case::Upper) {
|
||||||
|
uuid = cmSystemTools::UpperCase(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->String_ = std::move(uuid);
|
||||||
|
return *this;
|
||||||
|
#else
|
||||||
|
throw std::runtime_error("not available during bootstrap");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cmConfigure.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cm/string_view>
|
||||||
|
|
||||||
|
#include "cmList.h"
|
||||||
|
#include "cmRange.h"
|
||||||
|
#include "cmString.hxx"
|
||||||
|
#include "cmStringAlgorithms.h"
|
||||||
|
#include "cmSystemTools.h"
|
||||||
|
#include "cmValue.h"
|
||||||
|
|
||||||
|
class cmMakefile;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Class offering various string operations which is used by
|
||||||
|
// * CMake string() command
|
||||||
|
// * $<STRING> generator expression
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace cm {
|
||||||
|
|
||||||
|
class CMakeString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using size_type = cm::String::size_type;
|
||||||
|
static auto const npos = cm::String::npos;
|
||||||
|
|
||||||
|
using string_range = cmRange<std::vector<std::string>::const_iterator>;
|
||||||
|
|
||||||
|
CMakeString(std::string const& str)
|
||||||
|
: String_(cm::String::borrow(str))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CMakeString(cm::string_view str)
|
||||||
|
: String_(cm::String::borrow(str))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CMakeString(cm::String const& str)
|
||||||
|
: String_(str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CMakeString(cm::String&& str)
|
||||||
|
: String_(std::move(str))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CMakeString(cmValue value)
|
||||||
|
: String_(cm::String::borrow(*value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CMakeString(string_range range,
|
||||||
|
cm::string_view separator = cm::string_view{})
|
||||||
|
: String_(cmJoin(range, separator))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString() = default;
|
||||||
|
CMakeString(CMakeString const&) = default;
|
||||||
|
CMakeString(CMakeString&&) = default;
|
||||||
|
|
||||||
|
CMakeString& operator=(CMakeString const& string)
|
||||||
|
{
|
||||||
|
if (this != &string) {
|
||||||
|
this->String_ = string.String_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& operator=(CMakeString&& string) noexcept
|
||||||
|
{
|
||||||
|
if (this != &string) {
|
||||||
|
this->String_ = std::move(string.String_);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& operator=(cm::string_view string)
|
||||||
|
{
|
||||||
|
this->String_ = string;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// conversions
|
||||||
|
string_view view() const noexcept { return this->String_.view(); }
|
||||||
|
operator cm::string_view() noexcept { return this->String_.view(); }
|
||||||
|
operator std::string const&() { return this->String_.str(); }
|
||||||
|
|
||||||
|
size_type Size() const { return this->String_.size(); }
|
||||||
|
size_type Length() const { return this->String_.size(); }
|
||||||
|
|
||||||
|
enum class CompOperator
|
||||||
|
{
|
||||||
|
EQUAL,
|
||||||
|
LESS,
|
||||||
|
LESS_EQUAL,
|
||||||
|
GREATER,
|
||||||
|
GREATER_EQUAL
|
||||||
|
};
|
||||||
|
bool Compare(CompOperator op, cm::string_view other);
|
||||||
|
|
||||||
|
enum class FindFrom
|
||||||
|
{
|
||||||
|
Begin,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
size_type Find(cm::string_view substring,
|
||||||
|
FindFrom from = FindFrom::Begin) const
|
||||||
|
{
|
||||||
|
return from == FindFrom::Begin ? this->String_.find(substring)
|
||||||
|
: this->String_.rfind(substring);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Regex
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Yes
|
||||||
|
};
|
||||||
|
// Throw std::invalid_argument if regular expression is invalid
|
||||||
|
// std::runtime_error if replacement failed
|
||||||
|
CMakeString& Replace(std::string const& matchExpression,
|
||||||
|
std::string const& replaceExpression,
|
||||||
|
Regex regex = Regex::No,
|
||||||
|
cmMakefile* makefile = nullptr);
|
||||||
|
|
||||||
|
enum class MatchItems
|
||||||
|
{
|
||||||
|
Once,
|
||||||
|
All
|
||||||
|
};
|
||||||
|
// Throw std::invalid_argument if regular expression is invalid
|
||||||
|
cmList Match(std::string const& matchExpression,
|
||||||
|
MatchItems matchItems = MatchItems::Once,
|
||||||
|
cmMakefile* makefile = nullptr) const;
|
||||||
|
|
||||||
|
CMakeString& Append(cm::string_view str)
|
||||||
|
{
|
||||||
|
this->String_.append(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& Append(string_range range)
|
||||||
|
{
|
||||||
|
this->Append(cmJoin(range, {}));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& Prepend(cm::string_view str)
|
||||||
|
{
|
||||||
|
this->String_.insert(0, str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& Prepend(string_range range)
|
||||||
|
{
|
||||||
|
this->Prepend(cmJoin(range, {}));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeString& ToLower()
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::LowerCase(this->String_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& ToLower(cm::string_view str)
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::LowerCase(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& ToUpper()
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::UpperCase(this->String_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& ToUpper(cm::string_view str)
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::UpperCase(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw std::out_of_range if pos or count are outside of the expected range
|
||||||
|
CMakeString Substring(long pos = 0, long count = -1) const;
|
||||||
|
|
||||||
|
enum class StripItems
|
||||||
|
{
|
||||||
|
Space,
|
||||||
|
Genex
|
||||||
|
};
|
||||||
|
CMakeString& Strip(StripItems stripItems = StripItems::Space);
|
||||||
|
|
||||||
|
// Throw std::runtime_error if quoting string failed
|
||||||
|
enum class QuoteItems
|
||||||
|
{
|
||||||
|
Regex
|
||||||
|
};
|
||||||
|
CMakeString& Quote(QuoteItems quoteItems = QuoteItems::Regex);
|
||||||
|
|
||||||
|
CMakeString& Repeat(size_type count);
|
||||||
|
|
||||||
|
// Throw std::invalid_argument if the hash algorithm is invalid
|
||||||
|
CMakeString& Hash(cm::string_view hashAlgorithm);
|
||||||
|
|
||||||
|
// Throw std::invalid_argument if one of the codes is invalid
|
||||||
|
CMakeString& FromASCII(string_range codes);
|
||||||
|
CMakeString& ToHexadecimal() { return this->ToHexadecimal(this->String_); }
|
||||||
|
CMakeString& ToHexadecimal(cm::string_view str);
|
||||||
|
|
||||||
|
CMakeString& MakeCIdentifier()
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::MakeCidentifier(this->String_.str());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CMakeString& MakeCIdentifier(std::string const& str)
|
||||||
|
{
|
||||||
|
this->String_ = cmSystemTools::MakeCidentifier(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cm::string_view const RandomDefaultAlphabet;
|
||||||
|
// Throw std::invalid_argument if the alphabet is invalid
|
||||||
|
// std::out_of_range if length is outside valid range
|
||||||
|
CMakeString& Random(std::size_t length = 5,
|
||||||
|
cm::string_view alphabet = RandomDefaultAlphabet)
|
||||||
|
{
|
||||||
|
return this->Random(cmSystemTools::RandomSeed(), length, alphabet);
|
||||||
|
}
|
||||||
|
CMakeString& Random(unsigned int seed, std::size_t length = 5,
|
||||||
|
cm::string_view alphabet = RandomDefaultAlphabet);
|
||||||
|
|
||||||
|
enum class UTC
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Yes
|
||||||
|
};
|
||||||
|
CMakeString& Timestamp(cm::string_view format, UTC utc = UTC::No);
|
||||||
|
|
||||||
|
enum class UUIDType
|
||||||
|
{
|
||||||
|
MD5,
|
||||||
|
SHA1
|
||||||
|
};
|
||||||
|
enum class Case
|
||||||
|
{
|
||||||
|
Lower,
|
||||||
|
Upper
|
||||||
|
};
|
||||||
|
// Throw std::invalid_argument if namespace or the type are invalid
|
||||||
|
// std::runtime_error if the UUID cannot be generated
|
||||||
|
CMakeString& UUID(cm::string_view nameSpace, cm::string_view name,
|
||||||
|
UUIDType type, Case uuidCase = Case::Lower);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool Seeded;
|
||||||
|
cm::String String_;
|
||||||
|
};
|
||||||
|
}
|
||||||
+181
-357
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#include "cmStringCommand.h"
|
#include "cmStringCommand.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -22,22 +22,14 @@
|
|||||||
#include <cm3p/json/value.h>
|
#include <cm3p/json/value.h>
|
||||||
#include <cm3p/json/writer.h>
|
#include <cm3p/json/writer.h>
|
||||||
|
|
||||||
#include "cmsys/RegularExpression.hxx"
|
#include "cmCMakeString.hxx"
|
||||||
|
|
||||||
#include "cmCryptoHash.h"
|
|
||||||
#include "cmExecutionStatus.h"
|
#include "cmExecutionStatus.h"
|
||||||
#include "cmGeneratorExpression.h"
|
#include "cmList.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
#include "cmPolicies.h"
|
|
||||||
#include "cmRange.h"
|
#include "cmRange.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
#include "cmStringReplaceHelper.h"
|
|
||||||
#include "cmSubcommandTable.h"
|
#include "cmSubcommandTable.h"
|
||||||
#include "cmSystemTools.h"
|
|
||||||
#include "cmTimestamp.h"
|
|
||||||
#include "cmUuid.h"
|
|
||||||
#include "cmValue.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -62,13 +54,16 @@ bool HandleHashCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0]));
|
cm::CMakeString data{ args[2] };
|
||||||
if (hash) {
|
|
||||||
std::string out = hash->HashString(args[2]);
|
try {
|
||||||
status.GetMakefile().AddDefinition(args[1], out);
|
data.Hash(args[0]);
|
||||||
|
status.GetMakefile().AddDefinition(args[1], data);
|
||||||
return true;
|
return true;
|
||||||
|
} catch (std::exception const& e) {
|
||||||
|
status.SetError(e.what());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
|
bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
|
||||||
@@ -80,16 +75,16 @@ bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string const& outvar = args[2];
|
std::string const& outvar = args[2];
|
||||||
std::string output;
|
cm::CMakeString data{ args[1] };
|
||||||
|
|
||||||
if (toUpper) {
|
if (toUpper) {
|
||||||
output = cmSystemTools::UpperCase(args[1]);
|
data.ToUpper();
|
||||||
} else {
|
} else {
|
||||||
output = cmSystemTools::LowerCase(args[1]);
|
data.ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the output in the provided variable.
|
// Store the output in the provided variable.
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
status.GetMakefile().AddDefinition(outvar, data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,23 +107,17 @@ bool HandleAsciiCommand(std::vector<std::string> const& args,
|
|||||||
status.SetError("No output variable specified");
|
status.SetError("No output variable specified");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::string::size_type cc;
|
|
||||||
std::string const& outvar = args.back();
|
try {
|
||||||
std::string output;
|
std::string const& outvar = args.back();
|
||||||
for (cc = 1; cc < args.size() - 1; cc++) {
|
cm::CMakeString data;
|
||||||
int ch = atoi(args[cc].c_str());
|
data.FromASCII(cmMakeRange(args).advance(1).retreat(1));
|
||||||
if (ch > 0 && ch < 256) {
|
status.GetMakefile().AddDefinition(outvar, data);
|
||||||
output += static_cast<char>(ch);
|
return true;
|
||||||
} else {
|
} catch (std::exception const& e) {
|
||||||
std::string error =
|
status.SetError(e.what());
|
||||||
cmStrCat("Character with code ", args[cc], " does not exist.");
|
return false;
|
||||||
status.SetError(error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Store the output in the provided variable.
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleHexCommand(std::vector<std::string> const& args,
|
bool HandleHexCommand(std::vector<std::string> const& args,
|
||||||
@@ -138,17 +127,13 @@ bool HandleHexCommand(std::vector<std::string> const& args,
|
|||||||
status.SetError("Incorrect number of arguments");
|
status.SetError("Incorrect number of arguments");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto const& instr = args[1];
|
|
||||||
auto const& outvar = args[2];
|
auto const& outvar = args[2];
|
||||||
std::string output(instr.size() * 2, ' ');
|
cm::CMakeString data{ args[1] };
|
||||||
|
|
||||||
std::string::size_type hexIndex = 0;
|
data.ToHexadecimal();
|
||||||
for (auto const& c : instr) {
|
|
||||||
snprintf(&output[hexIndex], 3, "%.2x", c & 0xFFu);
|
|
||||||
hexIndex += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
status.GetMakefile().AddDefinition(outvar, data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,33 +224,21 @@ bool RegexMatch(std::vector<std::string> const& args,
|
|||||||
{
|
{
|
||||||
//"STRING(REGEX MATCH <regular_expression> <output variable>
|
//"STRING(REGEX MATCH <regular_expression> <output variable>
|
||||||
// <input> [<input>...])\n";
|
// <input> [<input>...])\n";
|
||||||
std::string const& regex = args[2];
|
try {
|
||||||
std::string const& outvar = args[3];
|
std::string const& regex = args[2];
|
||||||
|
std::string const& outvar = args[3];
|
||||||
|
cm::CMakeString data{ cmMakeRange(args).advance(4) };
|
||||||
|
|
||||||
status.GetMakefile().ClearMatches();
|
auto result = data.Match(regex, cm::CMakeString::MatchItems::Once,
|
||||||
// Compile the regular expression.
|
&status.GetMakefile());
|
||||||
cmsys::RegularExpression re;
|
// Store the result in the provided variable.
|
||||||
if (!re.compile(regex)) {
|
status.GetMakefile().AddDefinition(outvar, result.to_string());
|
||||||
std::string e =
|
return true;
|
||||||
"sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
|
} catch (std::exception const& e) {
|
||||||
"\".";
|
status.SetError(
|
||||||
status.SetError(e);
|
cmStrCat("sub-command REGEX, mode MATCH: ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenate all the last arguments together.
|
|
||||||
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
|
|
||||||
|
|
||||||
// Scan through the input for all matches.
|
|
||||||
std::string output;
|
|
||||||
if (re.find(input)) {
|
|
||||||
status.GetMakefile().StoreMatches(re);
|
|
||||||
output = re.match();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the output in the provided variable.
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegexMatchAll(std::vector<std::string> const& args,
|
bool RegexMatchAll(std::vector<std::string> const& args,
|
||||||
@@ -273,55 +246,21 @@ bool RegexMatchAll(std::vector<std::string> const& args,
|
|||||||
{
|
{
|
||||||
//"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
|
//"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
|
||||||
// [<input>...])\n";
|
// [<input>...])\n";
|
||||||
std::string const& regex = args[2];
|
try {
|
||||||
std::string const& outvar = args[3];
|
std::string const& regex = args[2];
|
||||||
|
std::string const& outvar = args[3];
|
||||||
|
cm::CMakeString data{ cmMakeRange(args).advance(4) };
|
||||||
|
|
||||||
status.GetMakefile().ClearMatches();
|
auto result = data.Match(regex, cm::CMakeString::MatchItems::All,
|
||||||
// Compile the regular expression.
|
&status.GetMakefile());
|
||||||
cmsys::RegularExpression re;
|
// Store the result in the provided variable.
|
||||||
if (!re.compile(regex)) {
|
status.GetMakefile().AddDefinition(outvar, result.to_string());
|
||||||
std::string e =
|
return true;
|
||||||
"sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
|
} catch (std::exception const& e) {
|
||||||
"\".";
|
status.SetError(
|
||||||
status.SetError(e);
|
cmStrCat("sub-command REGEX, mode MATCHALL: ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concatenate all the last arguments together.
|
|
||||||
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
|
|
||||||
|
|
||||||
unsigned optAnchor = 0;
|
|
||||||
if (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0186) !=
|
|
||||||
cmPolicies::NEW) {
|
|
||||||
optAnchor = cmsys::RegularExpression::BOL_AT_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan through the input for all matches.
|
|
||||||
std::string output;
|
|
||||||
std::string::size_type base = 0;
|
|
||||||
unsigned optNonEmpty = 0;
|
|
||||||
while (re.find(input, base, optAnchor | optNonEmpty)) {
|
|
||||||
status.GetMakefile().ClearMatches();
|
|
||||||
status.GetMakefile().StoreMatches(re);
|
|
||||||
if (!output.empty() || optNonEmpty) {
|
|
||||||
output += ";";
|
|
||||||
}
|
|
||||||
output += re.match();
|
|
||||||
base = re.end();
|
|
||||||
|
|
||||||
if (re.start() == input.length()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (re.start() == re.end()) {
|
|
||||||
optNonEmpty = cmsys::RegularExpression::NONEMPTY_AT_OFFSET;
|
|
||||||
} else {
|
|
||||||
optNonEmpty = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the output in the provided variable.
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegexReplace(std::vector<std::string> const& args,
|
bool RegexReplace(std::vector<std::string> const& args,
|
||||||
@@ -332,38 +271,20 @@ bool RegexReplace(std::vector<std::string> const& args,
|
|||||||
std::string const& regex = args[2];
|
std::string const& regex = args[2];
|
||||||
std::string const& replace = args[3];
|
std::string const& replace = args[3];
|
||||||
std::string const& outvar = args[4];
|
std::string const& outvar = args[4];
|
||||||
cmStringReplaceHelper replaceHelper(regex, replace, &status.GetMakefile());
|
|
||||||
|
|
||||||
if (!replaceHelper.IsReplaceExpressionValid()) {
|
try {
|
||||||
|
cm::CMakeString data{ cmMakeRange(args).advance(5) };
|
||||||
|
|
||||||
|
data.Replace(regex, replace, cm::CMakeString::Regex::Yes,
|
||||||
|
&status.GetMakefile());
|
||||||
|
// Store the result in the provided variable.
|
||||||
|
status.GetMakefile().AddDefinition(outvar, data);
|
||||||
|
return true;
|
||||||
|
} catch (std::exception const& e) {
|
||||||
status.SetError(
|
status.SetError(
|
||||||
"sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
|
cmStrCat("sub-command REGEX, mode REPLACE: ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.GetMakefile().ClearMatches();
|
|
||||||
|
|
||||||
if (!replaceHelper.IsRegularExpressionValid()) {
|
|
||||||
std::string e =
|
|
||||||
"sub-command REGEX, mode REPLACE failed to compile regex \"" + regex +
|
|
||||||
"\".";
|
|
||||||
status.SetError(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concatenate all the last arguments together.
|
|
||||||
std::string const input =
|
|
||||||
cmJoin(cmMakeRange(args).advance(5), std::string());
|
|
||||||
std::string output;
|
|
||||||
|
|
||||||
if (!replaceHelper.Replace(input, output)) {
|
|
||||||
status.SetError(
|
|
||||||
"sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the output in the provided variable.
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegexQuote(std::vector<std::string> const& args,
|
bool RegexQuote(std::vector<std::string> const& args,
|
||||||
@@ -371,21 +292,19 @@ bool RegexQuote(std::vector<std::string> const& args,
|
|||||||
{
|
{
|
||||||
//"STRING(REGEX QUOTE <output variable> <input> [<input>...]\n"
|
//"STRING(REGEX QUOTE <output variable> <input> [<input>...]\n"
|
||||||
std::string const& outvar = args[2];
|
std::string const& outvar = args[2];
|
||||||
std::string const input =
|
cm::CMakeString data{ cmMakeRange(args).advance(3) };
|
||||||
cmJoin(cmMakeRange(args).advance(3), std::string());
|
|
||||||
std::string output;
|
|
||||||
|
|
||||||
// Escape all regex special characters
|
try {
|
||||||
cmStringReplaceHelper replaceHelper("([][()+*^.$?|\\\\])", R"(\\\1)");
|
// Escape all regex special characters
|
||||||
if (!replaceHelper.Replace(input, output)) {
|
data.Quote();
|
||||||
|
// Store the output in the provided variable.
|
||||||
|
status.GetMakefile().AddDefinition(outvar, data);
|
||||||
|
return true;
|
||||||
|
} catch (std::exception const& e) {
|
||||||
status.SetError(
|
status.SetError(
|
||||||
"sub-command REGEX, mode QUOTE: " + replaceHelper.GetError() + ".");
|
cmStrCat("sub-command REGEX, mode QUOTE: ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the output in the provided variable.
|
|
||||||
status.GetMakefile().AddDefinition(outvar, output);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleFindCommand(std::vector<std::string> const& args,
|
bool HandleFindCommand(std::vector<std::string> const& args,
|
||||||
@@ -423,19 +342,14 @@ bool HandleFindCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to find the character and return its position
|
// try to find the character and return its position
|
||||||
size_t pos;
|
auto pos = cm::CMakeString{ sstring }.Find(
|
||||||
if (!reverseMode) {
|
schar,
|
||||||
pos = sstring.find(schar);
|
reverseMode ? cm::CMakeString::FindFrom::End
|
||||||
} else {
|
: cm::CMakeString::FindFrom::Begin);
|
||||||
pos = sstring.rfind(schar);
|
|
||||||
}
|
status.GetMakefile().AddDefinition(
|
||||||
if (std::string::npos != pos) {
|
outvar, pos != cm::CMakeString::npos ? std::to_string(pos) : "-1");
|
||||||
status.GetMakefile().AddDefinition(outvar, std::to_string(pos));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the character was not found, but this is not really an error
|
|
||||||
status.GetMakefile().AddDefinition(outvar, "-1");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,25 +376,22 @@ bool HandleCompareCommand(std::vector<std::string> const& args,
|
|||||||
std::string const& right = args[3];
|
std::string const& right = args[3];
|
||||||
std::string const& outvar = args[4];
|
std::string const& outvar = args[4];
|
||||||
bool result;
|
bool result;
|
||||||
|
cm::CMakeString::CompOperator op = cm::CMakeString::CompOperator::EQUAL;
|
||||||
if (mode == "LESS") {
|
if (mode == "LESS") {
|
||||||
result = (left < right);
|
op = cm::CMakeString::CompOperator::LESS;
|
||||||
} else if (mode == "LESS_EQUAL") {
|
} else if (mode == "LESS_EQUAL") {
|
||||||
result = (left <= right);
|
op = cm::CMakeString::CompOperator::LESS_EQUAL;
|
||||||
} else if (mode == "GREATER") {
|
} else if (mode == "GREATER") {
|
||||||
result = (left > right);
|
op = cm::CMakeString::CompOperator::GREATER;
|
||||||
} else if (mode == "GREATER_EQUAL") {
|
} else if (mode == "GREATER_EQUAL") {
|
||||||
result = (left >= right);
|
op = cm::CMakeString::CompOperator::GREATER_EQUAL;
|
||||||
} else if (mode == "EQUAL") {
|
|
||||||
result = (left == right);
|
|
||||||
} else // if(mode == "NOTEQUAL")
|
|
||||||
{
|
|
||||||
result = !(left == right);
|
|
||||||
}
|
}
|
||||||
if (result) {
|
result = cm::CMakeString{ left }.Compare(op, right);
|
||||||
status.GetMakefile().AddDefinition(outvar, "1");
|
if (mode == "NOTEQUAL") {
|
||||||
} else {
|
result = !result;
|
||||||
status.GetMakefile().AddDefinition(outvar, "0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status.GetMakefile().AddDefinition(outvar, result ? "1" : "0");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
std::string e = "sub-command COMPARE does not recognize mode " + mode;
|
std::string e = "sub-command COMPARE does not recognize mode " + mode;
|
||||||
@@ -496,17 +407,19 @@ bool HandleReplaceCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& matchExpression = args[1];
|
try {
|
||||||
std::string const& replaceExpression = args[2];
|
std::string const& matchExpression = args[1];
|
||||||
std::string const& variableName = args[3];
|
std::string const& replaceExpression = args[2];
|
||||||
|
std::string const& variableName = args[3];
|
||||||
|
cm::CMakeString data{ cmMakeRange(args).advance(4) };
|
||||||
|
|
||||||
std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
|
data.Replace(matchExpression, replaceExpression);
|
||||||
|
status.GetMakefile().AddDefinition(variableName, data);
|
||||||
cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
|
return true;
|
||||||
replaceExpression.c_str());
|
} catch (std::exception const& e) {
|
||||||
|
status.SetError(cmStrCat("sub-command REPLACE: ", e.what(), '.'));
|
||||||
status.GetMakefile().AddDefinition(variableName, input);
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleSubstringCommand(std::vector<std::string> const& args,
|
bool HandleSubstringCommand(std::vector<std::string> const& args,
|
||||||
@@ -517,25 +430,19 @@ bool HandleSubstringCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& stringValue = args[1];
|
try {
|
||||||
int begin = atoi(args[2].c_str());
|
std::string const& stringValue = args[1];
|
||||||
int end = atoi(args[3].c_str());
|
int begin = atoi(args[2].c_str());
|
||||||
std::string const& variableName = args[4];
|
int end = atoi(args[3].c_str());
|
||||||
|
std::string const& variableName = args[4];
|
||||||
|
|
||||||
size_t stringLength = stringValue.size();
|
cm::CMakeString data{ stringValue };
|
||||||
int intStringLength = static_cast<int>(stringLength);
|
status.GetMakefile().AddDefinition(variableName,
|
||||||
if (begin < 0 || begin > intStringLength) {
|
data.Substring(begin, end));
|
||||||
status.SetError(
|
} catch (std::exception const& e) {
|
||||||
cmStrCat("begin index: ", begin, " is out of range 0 - ", stringLength));
|
status.SetError(e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (end < -1) {
|
|
||||||
status.SetError(cmStrCat("end index: ", end, " should be -1 or greater"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName,
|
|
||||||
stringValue.substr(begin, end));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,11 +457,8 @@ bool HandleLengthCommand(std::vector<std::string> const& args,
|
|||||||
std::string const& stringValue = args[1];
|
std::string const& stringValue = args[1];
|
||||||
std::string const& variableName = args[2];
|
std::string const& variableName = args[2];
|
||||||
|
|
||||||
size_t length = stringValue.size();
|
status.GetMakefile().AddDefinition(
|
||||||
char buffer[1024];
|
variableName, std::to_string(cm::CMakeString{ stringValue }.Length()));
|
||||||
snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(length));
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName, buffer);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,12 +476,10 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const& variableName = args[1];
|
auto const& variableName = args[1];
|
||||||
|
cm::CMakeString data{ status.GetMakefile().GetDefinition(variableName) };
|
||||||
|
|
||||||
cm::string_view oldView{ status.GetMakefile().GetSafeDefinition(
|
data.Append(cmMakeRange(args).advance(2));
|
||||||
variableName) };
|
status.GetMakefile().AddDefinition(variableName, data);
|
||||||
|
|
||||||
auto const newValue = cmJoin(cmMakeRange(args).advance(2), {}, oldView);
|
|
||||||
status.GetMakefile().AddDefinition(variableName, newValue);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -596,13 +498,10 @@ bool HandlePrependCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string const& variable = args[1];
|
std::string const& variable = args[1];
|
||||||
|
cm::CMakeString data{ status.GetMakefile().GetDefinition(variable) };
|
||||||
|
|
||||||
std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
|
data.Prepend(cmMakeRange(args).advance(2));
|
||||||
cmValue oldValue = status.GetMakefile().GetDefinition(variable);
|
status.GetMakefile().AddDefinition(variable, data);
|
||||||
if (oldValue) {
|
|
||||||
value += *oldValue;
|
|
||||||
}
|
|
||||||
status.GetMakefile().AddDefinition(variable, value);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,9 +533,9 @@ bool joinImpl(std::vector<std::string> const& args, std::string const& glue,
|
|||||||
std::string const& variableName = args[varIdx];
|
std::string const& variableName = args[varIdx];
|
||||||
// NOTE Items to concat/join placed right after the variable for
|
// NOTE Items to concat/join placed right after the variable for
|
||||||
// both `CONCAT` and `JOIN` sub-commands.
|
// both `CONCAT` and `JOIN` sub-commands.
|
||||||
std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue);
|
cm::CMakeString data{ cmMakeRange(args).advance(varIdx + 1), glue };
|
||||||
|
|
||||||
makefile.AddDefinition(variableName, value);
|
makefile.AddDefinition(variableName, data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +551,7 @@ bool HandleMakeCIdentifierCommand(std::vector<std::string> const& args,
|
|||||||
std::string const& variableName = args[2];
|
std::string const& variableName = args[2];
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName,
|
status.GetMakefile().AddDefinition(variableName,
|
||||||
cmSystemTools::MakeCidentifier(input));
|
cm::CMakeString{}.MakeCIdentifier(input));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,14 +563,11 @@ bool HandleGenexStripCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& input = args[1];
|
cm::CMakeString data{ args[1] };
|
||||||
|
|
||||||
std::string result = cmGeneratorExpression::Preprocess(
|
|
||||||
input, cmGeneratorExpression::StripAllGeneratorExpressions);
|
|
||||||
|
|
||||||
std::string const& variableName = args[2];
|
std::string const& variableName = args[2];
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName, result);
|
status.GetMakefile().AddDefinition(
|
||||||
|
variableName, data.Strip(cm::CMakeString::StripItems::Genex));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,36 +579,10 @@ bool HandleStripCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& stringValue = args[1];
|
cm::CMakeString data{ args[1] };
|
||||||
std::string const& variableName = args[2];
|
std::string const& variableName = args[2];
|
||||||
size_t inStringLength = stringValue.size();
|
|
||||||
size_t startPos = inStringLength + 1;
|
|
||||||
size_t endPos = 0;
|
|
||||||
char const* ptr = stringValue.c_str();
|
|
||||||
size_t cc;
|
|
||||||
for (cc = 0; cc < inStringLength; ++cc) {
|
|
||||||
if (!cmIsSpace(*ptr)) {
|
|
||||||
if (startPos > inStringLength) {
|
|
||||||
startPos = cc;
|
|
||||||
}
|
|
||||||
endPos = cc;
|
|
||||||
}
|
|
||||||
++ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t outLength = 0;
|
status.GetMakefile().AddDefinition(variableName, data.Strip());
|
||||||
|
|
||||||
// if the input string didn't contain any non-space characters, return
|
|
||||||
// an empty string
|
|
||||||
if (startPos > inStringLength) {
|
|
||||||
outLength = 0;
|
|
||||||
startPos = 0;
|
|
||||||
} else {
|
|
||||||
outLength = endPos - startPos + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName,
|
|
||||||
stringValue.substr(startPos, outLength));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,30 +614,12 @@ bool HandleRepeatCommand(std::vector<std::string> const& args,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const& stringValue = args[ArgPos::VALUE];
|
cm::CMakeString data{ args[ArgPos::VALUE] };
|
||||||
|
data.Repeat(times);
|
||||||
|
|
||||||
auto const& variableName = args[ArgPos::OUTPUT_VARIABLE];
|
auto const& variableName = args[ArgPos::OUTPUT_VARIABLE];
|
||||||
auto const inStringLength = stringValue.size();
|
|
||||||
|
|
||||||
std::string result;
|
makefile.AddDefinition(variableName, data);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
makefile.AddDefinition(variableName, result);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,14 +631,10 @@ bool HandleRandomCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool seeded = false;
|
int length = 5;
|
||||||
|
cm::string_view alphabet;
|
||||||
bool force_seed = false;
|
bool force_seed = false;
|
||||||
unsigned int seed = 0;
|
unsigned int seed = 0;
|
||||||
int length = 5;
|
|
||||||
char const cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
|
|
||||||
"QWERTYUIOPASDFGHJKLZXCVBNM"
|
|
||||||
"0123456789";
|
|
||||||
std::string alphabet;
|
|
||||||
|
|
||||||
if (args.size() > 3) {
|
if (args.size() > 3) {
|
||||||
size_t i = 1;
|
size_t i = 1;
|
||||||
@@ -806,37 +654,22 @@ bool HandleRandomCommand(std::vector<std::string> const& args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (alphabet.empty()) {
|
|
||||||
alphabet = cmStringCommandDefaultAlphabet;
|
|
||||||
}
|
|
||||||
|
|
||||||
double sizeofAlphabet = static_cast<double>(alphabet.size());
|
try {
|
||||||
if (sizeofAlphabet < 1) {
|
cm::CMakeString data;
|
||||||
status.SetError("sub-command RANDOM invoked with bad alphabet.");
|
std::string const& variableName = args.back();
|
||||||
|
|
||||||
|
if (force_seed) {
|
||||||
|
data.Random(seed, length, alphabet);
|
||||||
|
} else {
|
||||||
|
data.Random(length, alphabet);
|
||||||
|
}
|
||||||
|
status.GetMakefile().AddDefinition(variableName, data);
|
||||||
|
return true;
|
||||||
|
} catch (std::exception const& e) {
|
||||||
|
status.SetError(cmStrCat("sub-command RANDOM: ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (length < 1) {
|
|
||||||
status.SetError("sub-command RANDOM invoked with bad length.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::string const& variableName = args.back();
|
|
||||||
|
|
||||||
std::vector<char> result;
|
|
||||||
|
|
||||||
if (!seeded || force_seed) {
|
|
||||||
seeded = true;
|
|
||||||
srand(force_seed ? seed : cmSystemTools::RandomSeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* alphaPtr = alphabet.c_str();
|
|
||||||
for (int cc = 0; cc < length; cc++) {
|
|
||||||
int idx = static_cast<int>(sizeofAlphabet * rand() / (RAND_MAX + 1.0));
|
|
||||||
result.push_back(*(alphaPtr + idx));
|
|
||||||
}
|
|
||||||
result.push_back(0);
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(variableName, result.data());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleTimestampCommand(std::vector<std::string> const& args,
|
bool HandleTimestampCommand(std::vector<std::string> const& args,
|
||||||
@@ -855,26 +688,28 @@ bool HandleTimestampCommand(std::vector<std::string> const& args,
|
|||||||
|
|
||||||
std::string const& outputVariable = args[argsIndex++];
|
std::string const& outputVariable = args[argsIndex++];
|
||||||
|
|
||||||
std::string formatString;
|
cm::string_view formatString;
|
||||||
if (args.size() > argsIndex && args[argsIndex] != "UTC") {
|
if (args.size() > argsIndex && args[argsIndex] != "UTC") {
|
||||||
formatString = args[argsIndex++];
|
formatString = args[argsIndex++];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool utcFlag = false;
|
cm::CMakeString::UTC utcFlag = cm::CMakeString::UTC::No;
|
||||||
if (args.size() > argsIndex) {
|
if (args.size() > argsIndex) {
|
||||||
if (args[argsIndex] == "UTC") {
|
if (args[argsIndex] == "UTC") {
|
||||||
utcFlag = true;
|
utcFlag = cm::CMakeString::UTC::Yes;
|
||||||
} else {
|
} else {
|
||||||
std::string e = " TIMESTAMP sub-command does not recognize option " +
|
std::string e =
|
||||||
args[argsIndex] + ".";
|
cmStrCat(" TIMESTAMP sub-command does not recognize option ",
|
||||||
|
args[argsIndex], '.');
|
||||||
status.SetError(e);
|
status.SetError(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmTimestamp timestamp;
|
cm::CMakeString data;
|
||||||
std::string result = timestamp.CurrentTime(formatString, utcFlag);
|
|
||||||
status.GetMakefile().AddDefinition(outputVariable, result);
|
status.GetMakefile().AddDefinition(outputVariable,
|
||||||
|
data.Timestamp(formatString, utcFlag));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -892,10 +727,10 @@ bool HandleUuidCommand(std::vector<std::string> const& args,
|
|||||||
|
|
||||||
std::string const& outputVariable = args[argsIndex++];
|
std::string const& outputVariable = args[argsIndex++];
|
||||||
|
|
||||||
std::string uuidNamespaceString;
|
cm::string_view uuidNamespaceString;
|
||||||
std::string uuidName;
|
cm::string_view uuidName;
|
||||||
std::string uuidType;
|
cm::CMakeString::UUIDType uuidType = cm::CMakeString::UUIDType::MD5;
|
||||||
bool uuidUpperCase = false;
|
cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower;
|
||||||
|
|
||||||
while (args.size() > argsIndex) {
|
while (args.size() > argsIndex) {
|
||||||
if (args[argsIndex] == "NAMESPACE") {
|
if (args[argsIndex] == "NAMESPACE") {
|
||||||
@@ -918,50 +753,39 @@ bool HandleUuidCommand(std::vector<std::string> const& args,
|
|||||||
status.SetError("UUID sub-command, TYPE requires a value.");
|
status.SetError("UUID sub-command, TYPE requires a value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uuidType = args[argsIndex++];
|
if (args[argsIndex] == "MD5") {
|
||||||
|
uuidType = cm::CMakeString::UUIDType::MD5;
|
||||||
|
} else if (args[argsIndex] == "SHA1") {
|
||||||
|
uuidType = cm::CMakeString::UUIDType::SHA1;
|
||||||
|
} else {
|
||||||
|
status.SetError(
|
||||||
|
cmStrCat("UUID sub-command, unknown TYPE '", args[argsIndex], "'."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
argsIndex++;
|
||||||
} else if (args[argsIndex] == "UPPER") {
|
} else if (args[argsIndex] == "UPPER") {
|
||||||
++argsIndex;
|
++argsIndex;
|
||||||
uuidUpperCase = true;
|
uuidCase = cm::CMakeString::Case::Upper;
|
||||||
} else {
|
} else {
|
||||||
std::string e =
|
std::string e = cmStrCat("UUID sub-command does not recognize option ",
|
||||||
"UUID sub-command does not recognize option " + args[argsIndex] + ".";
|
args[argsIndex], '.');
|
||||||
status.SetError(e);
|
status.SetError(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string uuid;
|
try {
|
||||||
cmUuid uuidGenerator;
|
cm::CMakeString data;
|
||||||
|
|
||||||
std::vector<unsigned char> uuidNamespace;
|
data.UUID(uuidNamespaceString, uuidName, uuidType, uuidCase);
|
||||||
if (!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace)) {
|
status.GetMakefile().AddDefinition(outputVariable, data);
|
||||||
status.SetError("UUID sub-command, malformed NAMESPACE UUID.");
|
return true;
|
||||||
|
} catch (std::exception const& e) {
|
||||||
|
status.SetError(cmStrCat("UUID sub-command, ", e.what(), '.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uuidType == "MD5") {
|
|
||||||
uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
|
|
||||||
} else if (uuidType == "SHA1") {
|
|
||||||
uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
|
|
||||||
} else {
|
|
||||||
std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
|
|
||||||
status.SetError(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuid.empty()) {
|
|
||||||
status.SetError("UUID sub-command, generation failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuidUpperCase) {
|
|
||||||
uuid = cmSystemTools::UpperCase(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
status.GetMakefile().AddDefinition(outputVariable, uuid);
|
|
||||||
return true;
|
|
||||||
#else
|
#else
|
||||||
status.SetError(cmStrCat(args[0], " not available during bootstrap"));
|
status.SetError("UUID sub-command not available during bootstrap.");
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ CMAKE_CXX_SOURCES="\
|
|||||||
cmCMakePath \
|
cmCMakePath \
|
||||||
cmCMakePathCommand \
|
cmCMakePathCommand \
|
||||||
cmCMakePolicyCommand \
|
cmCMakePolicyCommand \
|
||||||
|
cmCMakeString \
|
||||||
cmCPackPropertiesGenerator \
|
cmCPackPropertiesGenerator \
|
||||||
cmCacheManager \
|
cmCacheManager \
|
||||||
cmCommands \
|
cmCommands \
|
||||||
|
|||||||
Reference in New Issue
Block a user