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
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmStringReplaceHelper.h"
#include <sstream>
#include <utility>
#include "cmMakefile.h"
cmStringReplaceHelper::cmStringReplaceHelper(const std::string& regex,
std::string replace_expr,
cmMakefile* makefile)
: RegExString(regex)
, RegularExpression(regex)
, ReplaceExpression(std::move(replace_expr))
, Makefile(makefile)
{
this->ParseReplaceExpression();
}
bool cmStringReplaceHelper::Replace(const std::string& input,
std::string& output)
{
output.clear();
// Scan through the input for all matches.
std::string::size_type base = 0;
while (this->RegularExpression.find(input.c_str() + base)) {
if (this->Makefile != nullptr) {
this->Makefile->ClearMatches();
this->Makefile->StoreMatches(this->RegularExpression);
}
auto l2 = this->RegularExpression.start();
auto r = this->RegularExpression.end();
// Concatenate the part of the input that was not matched.
output += input.substr(base, l2);
// Make sure the match had some text.
if (r - l2 == 0) {
std::ostringstream error;
error << "regex \"" << this->RegExString << "\" matched an empty string";
this->ErrorString = error.str();
return false;
}
// Concatenate the replacement for the match.
for (const auto& 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;
auto start = this->RegularExpression.start(n);
auto end = this->RegularExpression.end(n);
auto len = input.length() - base;
if ((start != std::string::npos) && (end != std::string::npos) &&
(start <= len) && (end <= len)) {
output += input.substr(base + start, end - start);
} else {
std::ostringstream error;
error << "replace expression \"" << this->ReplaceExpression
<< "\" contains an out-of-range escape for regex \""
<< this->RegExString << "\"";
this->ErrorString = error.str();
return false;
}
}
}
// Move past the match.
base += r;
}
// Concatenate the text after the last match.
output += input.substr(base, input.length() - 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;
}
}
|