1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmStringReplaceHelper.h"
9 #include "cmMakefile.h"
11 cmStringReplaceHelper::cmStringReplaceHelper(const std::string
& regex
,
12 std::string replace_expr
,
15 , RegularExpression(regex
)
16 , ReplaceExpression(std::move(replace_expr
))
19 this->ParseReplaceExpression();
22 bool cmStringReplaceHelper::Replace(const std::string
& input
,
27 // Scan through the input for all matches.
28 std::string::size_type base
= 0;
29 while (this->RegularExpression
.find(input
.c_str() + base
)) {
31 this->Makefile
->ClearMatches();
32 this->Makefile
->StoreMatches(this->RegularExpression
);
34 auto l2
= this->RegularExpression
.start();
35 auto r
= this->RegularExpression
.end();
37 // Concatenate the part of the input that was not matched.
38 output
+= input
.substr(base
, l2
);
40 // Make sure the match had some text.
42 std::ostringstream error
;
43 error
<< "regex \"" << this->RegExString
<< "\" matched an empty string";
44 this->ErrorString
= error
.str();
48 // Concatenate the replacement for the match.
49 for (const auto& replacement
: this->Replacements
) {
50 if (replacement
.Number
< 0) {
51 // This is just a plain-text part of the replacement.
52 output
+= replacement
.Value
;
54 // Replace with part of the match.
55 auto n
= replacement
.Number
;
56 auto start
= this->RegularExpression
.start(n
);
57 auto end
= this->RegularExpression
.end(n
);
58 auto len
= input
.length() - base
;
59 if ((start
!= std::string::npos
) && (end
!= std::string::npos
) &&
60 (start
<= len
) && (end
<= len
)) {
61 output
+= input
.substr(base
+ start
, end
- start
);
63 std::ostringstream error
;
64 error
<< "replace expression \"" << this->ReplaceExpression
65 << "\" contains an out-of-range escape for regex \""
66 << this->RegExString
<< "\"";
67 this->ErrorString
= error
.str();
73 // Move past the match.
77 // Concatenate the text after the last match.
78 output
+= input
.substr(base
, input
.length() - base
);
83 void cmStringReplaceHelper::ParseReplaceExpression()
85 std::string::size_type l
= 0;
86 while (l
< this->ReplaceExpression
.length()) {
87 auto r
= this->ReplaceExpression
.find('\\', l
);
88 if (r
== std::string::npos
) {
89 r
= this->ReplaceExpression
.length();
90 this->Replacements
.emplace_back(
91 this->ReplaceExpression
.substr(l
, r
- l
));
94 this->Replacements
.emplace_back(
95 this->ReplaceExpression
.substr(l
, r
- l
));
97 if (r
== (this->ReplaceExpression
.length() - 1)) {
98 this->ValidReplaceExpression
= false;
99 this->ErrorString
= "replace-expression ends in a backslash";
102 if ((this->ReplaceExpression
[r
+ 1] >= '0') &&
103 (this->ReplaceExpression
[r
+ 1] <= '9')) {
104 this->Replacements
.emplace_back(this->ReplaceExpression
[r
+ 1] - '0');
105 } else if (this->ReplaceExpression
[r
+ 1] == 'n') {
106 this->Replacements
.emplace_back("\n");
107 } else if (this->ReplaceExpression
[r
+ 1] == '\\') {
108 this->Replacements
.emplace_back("\\");
110 this->ValidReplaceExpression
= false;
111 std::ostringstream error
;
112 error
<< "Unknown escape \"" << this->ReplaceExpression
.substr(r
, 2)
113 << "\" in replace-expression";
114 this->ErrorString
= error
.str();