resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmStringReplaceHelper.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3
4 #include "cmStringReplaceHelper.h"
5
6 #include <sstream>
7 #include <utility>
8
9 #include "cmMakefile.h"
10
11 cmStringReplaceHelper::cmStringReplaceHelper(const std::string& regex,
12                                              std::string replace_expr,
13                                              cmMakefile* makefile)
14   : RegExString(regex)
15   , RegularExpression(regex)
16   , ReplaceExpression(std::move(replace_expr))
17   , Makefile(makefile)
18 {
19   this->ParseReplaceExpression();
20 }
21
22 bool cmStringReplaceHelper::Replace(const std::string& input,
23                                     std::string& output)
24 {
25   output.clear();
26
27   // Scan through the input for all matches.
28   std::string::size_type base = 0;
29   while (this->RegularExpression.find(input.c_str() + base)) {
30     if (this->Makefile != nullptr) {
31       this->Makefile->ClearMatches();
32       this->Makefile->StoreMatches(this->RegularExpression);
33     }
34     auto l2 = this->RegularExpression.start();
35     auto r = this->RegularExpression.end();
36
37     // Concatenate the part of the input that was not matched.
38     output += input.substr(base, l2);
39
40     // Make sure the match had some text.
41     if (r - l2 == 0) {
42       std::ostringstream error;
43       error << "regex \"" << this->RegExString << "\" matched an empty string";
44       this->ErrorString = error.str();
45       return false;
46     }
47
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;
53       } else {
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);
62         } else {
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();
68           return false;
69         }
70       }
71     }
72
73     // Move past the match.
74     base += r;
75   }
76
77   // Concatenate the text after the last match.
78   output += input.substr(base, input.length() - base);
79
80   return true;
81 }
82
83 void cmStringReplaceHelper::ParseReplaceExpression()
84 {
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));
92     } else {
93       if (r - l > 0) {
94         this->Replacements.emplace_back(
95           this->ReplaceExpression.substr(l, r - l));
96       }
97       if (r == (this->ReplaceExpression.length() - 1)) {
98         this->ValidReplaceExpression = false;
99         this->ErrorString = "replace-expression ends in a backslash";
100         return;
101       }
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("\\");
109       } else {
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();
115         return;
116       }
117       r += 2;
118     }
119     l = r;
120   }
121 }