File: cmStringReplaceHelper.cxx

package info (click to toggle)
cmake 4.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 147,412 kB
  • sloc: ansic: 403,924; cpp: 290,826; sh: 4,091; python: 3,357; yacc: 3,106; lex: 1,189; f90: 532; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 230; perl: 217; objc: 215; xml: 198; makefile: 98; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (125 lines) | stat: -rw-r--r-- 3,891 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* 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(std::string const& 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, 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;
  }
}