| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file LICENSE.rst or https://cmake.org/licensing for details. */
- #include "cmStringReplaceHelper.h"
- #include <sstream>
- #include <utility>
- #include "cmMakefile.h"
- #include "cmPolicies.h"
- cmStringReplaceHelper::cmStringReplaceHelper(std::string const& regex,
- std::string replace_expr,
- cmMakefile* makefile)
- : RegExString(regex)
- , RegularExpression(regex)
- , ReplaceExpression(std::move(replace_expr))
- , Makefile(makefile)
- {
- this->ParseReplaceExpression();
- }
- bool cmStringReplaceHelper::Replace(cm::string_view input, std::string& output)
- {
- output.clear();
- unsigned optAnchor = 0;
- if (this->Makefile &&
- this->Makefile->GetPolicyStatus(cmPolicies::CMP0186) !=
- cmPolicies::NEW) {
- optAnchor = cmsys::RegularExpression::BOL_AT_OFFSET;
- }
- // Scan through the input for all matches.
- auto& re = this->RegularExpression;
- std::string::size_type base = 0;
- unsigned optNonEmpty = 0;
- while (re.find(input.data(), base, optAnchor | optNonEmpty)) {
- if (this->Makefile) {
- this->Makefile->ClearMatches();
- this->Makefile->StoreMatches(re);
- }
- // Concatenate the part of the input that was not matched.
- output += input.substr(base, re.start() - base);
- // Concatenate the replacement for the match.
- for (auto const& replacement : this->Replacements) {
- if (replacement.Number < 0) {
- // This is just a plain-text part of the replacement.
- output += replacement.Value;
- } else {
- // Replace with part of the match.
- auto n = replacement.Number;
- if (n > re.num_groups()) {
- std::ostringstream error;
- error << "replace expression \"" << this->ReplaceExpression
- << "\" contains an out-of-range escape for regex \""
- << this->RegExString << "\"";
- this->ErrorString = error.str();
- return false;
- }
- output += re.match(n);
- }
- }
- // Move past the match.
- base = re.end();
- if (re.start() == input.length()) {
- break;
- }
- if (re.start() == re.end()) {
- optNonEmpty = cmsys::RegularExpression::NONEMPTY_AT_OFFSET;
- } else {
- optNonEmpty = 0;
- }
- }
- // Concatenate the text after the last match.
- output += input.substr(base);
- return true;
- }
- void cmStringReplaceHelper::ParseReplaceExpression()
- {
- std::string::size_type l = 0;
- while (l < this->ReplaceExpression.length()) {
- auto r = this->ReplaceExpression.find('\\', l);
- if (r == std::string::npos) {
- r = this->ReplaceExpression.length();
- this->Replacements.emplace_back(
- this->ReplaceExpression.substr(l, r - l));
- } else {
- if (r - l > 0) {
- this->Replacements.emplace_back(
- this->ReplaceExpression.substr(l, r - l));
- }
- if (r == (this->ReplaceExpression.length() - 1)) {
- this->ValidReplaceExpression = false;
- this->ErrorString = "replace-expression ends in a backslash";
- return;
- }
- if ((this->ReplaceExpression[r + 1] >= '0') &&
- (this->ReplaceExpression[r + 1] <= '9')) {
- this->Replacements.emplace_back(this->ReplaceExpression[r + 1] - '0');
- } else if (this->ReplaceExpression[r + 1] == 'n') {
- this->Replacements.emplace_back("\n");
- } else if (this->ReplaceExpression[r + 1] == '\\') {
- this->Replacements.emplace_back("\\");
- } else {
- this->ValidReplaceExpression = false;
- std::ostringstream error;
- error << "Unknown escape \"" << this->ReplaceExpression.substr(r, 2)
- << "\" in replace-expression";
- this->ErrorString = error.str();
- return;
- }
- r += 2;
- }
- l = r;
- }
- }
|