| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- /* 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
- }
- }
|