Directory: | cvmfs/ |
---|---|
File: | cvmfs/pathspec/pathspec_pattern.cc |
Date: | 2025-04-20 02:34:28 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 147 | 149 | 98.7% |
Branches: | 134 | 182 | 73.6% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | |||
6 | #include "pathspec_pattern.h" | ||
7 | |||
8 | #include <cassert> | ||
9 | |||
10 | #include "pathspec/pathspec.h" | ||
11 | |||
12 | 363 | PathspecElementPattern::PathspecElementPattern( | |
13 | const std::string::const_iterator begin, | ||
14 | 363 | const std::string::const_iterator &end) | |
15 | 363 | : valid_(true) | |
16 | { | ||
17 |
1/2✓ Branch 1 taken 363 times.
✗ Branch 2 not taken.
|
363 | Parse(begin, end); |
18 | 363 | } | |
19 | |||
20 | 1049 | PathspecElementPattern::PathspecElementPattern( | |
21 | 1049 | const PathspecElementPattern& other) | |
22 | 1049 | : valid_(other.valid_) | |
23 | { | ||
24 |
1/2✓ Branch 2 taken 1049 times.
✗ Branch 3 not taken.
|
1049 | subpatterns_.reserve(other.subpatterns_.size()); |
25 | 1049 | SubPatterns::const_iterator i = other.subpatterns_.begin(); | |
26 | 1049 | SubPatterns::const_iterator iend = other.subpatterns_.end(); | |
27 |
2/2✓ Branch 1 taken 1174 times.
✓ Branch 2 taken 1049 times.
|
2223 | for (; i != iend; ++i) { |
28 |
2/4✓ Branch 2 taken 1174 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1174 times.
✗ Branch 6 not taken.
|
1174 | subpatterns_.push_back((*i)->Clone()); |
29 | } | ||
30 | 1049 | } | |
31 | |||
32 | 7 | PathspecElementPattern& PathspecElementPattern::operator=( | |
33 | const PathspecElementPattern& other) | ||
34 | { | ||
35 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (this != &other) { |
36 | 7 | valid_ = other.valid_; | |
37 | 7 | subpatterns_.clear(); | |
38 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | subpatterns_.reserve(other.subpatterns_.size()); |
39 | 7 | SubPatterns::const_iterator i = other.subpatterns_.begin(); | |
40 | 7 | SubPatterns::const_iterator iend = other.subpatterns_.end(); | |
41 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 7 times.
|
18 | for (; i != iend; ++i) { |
42 |
2/4✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
|
11 | subpatterns_.push_back((*i)->Clone()); |
43 | } | ||
44 | } | ||
45 | |||
46 | 7 | return *this; | |
47 | } | ||
48 | |||
49 | |||
50 | 1412 | PathspecElementPattern::~PathspecElementPattern() { | |
51 | 1412 | SubPatterns::const_iterator i = subpatterns_.begin(); | |
52 | 1412 | SubPatterns::const_iterator iend = subpatterns_.end(); | |
53 |
2/2✓ Branch 2 taken 1611 times.
✓ Branch 3 taken 1412 times.
|
3023 | for (; i != iend; ++i) { |
54 |
1/2✓ Branch 1 taken 1611 times.
✗ Branch 2 not taken.
|
1611 | delete *i; |
55 | } | ||
56 | 1412 | subpatterns_.clear(); | |
57 | 1412 | } | |
58 | |||
59 | |||
60 | 363 | void PathspecElementPattern::Parse(const std::string::const_iterator &begin, | |
61 | const std::string::const_iterator &end) { | ||
62 | 363 | std::string::const_iterator i = begin; | |
63 |
2/2✓ Branch 1 taken 434 times.
✓ Branch 2 taken 363 times.
|
797 | while (i != end) { |
64 | 434 | SubPattern* next = (Pathspec::IsSpecialChar(*i)) | |
65 |
3/4✓ Branch 0 taken 97 times.
✓ Branch 1 taken 337 times.
✓ Branch 3 taken 97 times.
✗ Branch 4 not taken.
|
434 | ? ParseSpecialChar(end, &i) |
66 |
1/2✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
|
337 | : ParsePlaintext(end, &i); |
67 |
3/4✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 433 times.
|
434 | if (next->IsEmpty()) { |
68 | 1 | valid_ = false; | |
69 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | delete next; |
70 | } else { | ||
71 |
1/2✓ Branch 1 taken 433 times.
✗ Branch 2 not taken.
|
433 | subpatterns_.push_back(next); |
72 | } | ||
73 | } | ||
74 | 363 | } | |
75 | |||
76 | |||
77 | 337 | PathspecElementPattern::SubPattern* PathspecElementPattern::ParsePlaintext( | |
78 | const std::string::const_iterator &end, | ||
79 | std::string::const_iterator *i | ||
80 | ) { | ||
81 | 337 | PlaintextSubPattern *pattern = new PlaintextSubPattern(); | |
82 | 337 | bool next_is_escaped = false; | |
83 | |||
84 |
2/2✓ Branch 1 taken 1466 times.
✓ Branch 2 taken 310 times.
|
1776 | while (*i < end) { |
85 |
6/6✓ Branch 2 taken 40 times.
✓ Branch 3 taken 1426 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 1439 times.
|
1466 | if (Pathspec::IsSpecialChar(**i) && !next_is_escaped) { |
86 | 27 | break; | |
87 | } | ||
88 | |||
89 |
6/6✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1416 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 1420 times.
|
1439 | if (**i == Pathspec::kEscaper && !next_is_escaped) { |
90 | 19 | next_is_escaped = true; | |
91 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1395 times.
|
1420 | } else if (next_is_escaped) { |
92 |
6/6✓ Branch 2 taken 12 times.
✓ Branch 3 taken 13 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 17 times.
✓ Branch 8 taken 8 times.
|
25 | if (Pathspec::IsSpecialChar(**i) || **i == Pathspec::kEscaper) { |
93 | 17 | pattern->AddChar(**i); | |
94 | 17 | next_is_escaped = false; | |
95 | } else { | ||
96 | 8 | valid_ = false; | |
97 | } | ||
98 | } else { | ||
99 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1395 times.
|
1395 | assert(!Pathspec::IsSpecialChar(**i)); |
100 | 1395 | pattern->AddChar(**i); | |
101 | } | ||
102 | |||
103 | 1439 | ++(*i); | |
104 | } | ||
105 | |||
106 | 337 | return pattern; | |
107 | } | ||
108 | |||
109 | 97 | PathspecElementPattern::SubPattern* PathspecElementPattern::ParseSpecialChar( | |
110 | const std::string::const_iterator &end, | ||
111 | std::string::const_iterator *i | ||
112 | ) { | ||
113 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
|
97 | assert(Pathspec::IsSpecialChar(**i)); |
114 | 97 | const char chr = **i; | |
115 | 97 | ++(*i); | |
116 | |||
117 |
2/3✓ Branch 0 taken 57 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
97 | switch (chr) { |
118 | 57 | case Pathspec::kWildcard: | |
119 | 57 | return new WildcardSubPattern(); | |
120 | 40 | case Pathspec::kPlaceholder: | |
121 | 40 | return new PlaceholderSubPattern(); | |
122 | ✗ | default: | |
123 | ✗ | assert(false && "unrecognized special character"); | |
124 | } | ||
125 | } | ||
126 | |||
127 | 227 | std::string PathspecElementPattern::GenerateRegularExpression( | |
128 | const bool is_relaxed) const { | ||
129 | 227 | std::string result; | |
130 | 227 | SubPatterns::const_iterator i = subpatterns_.begin(); | |
131 | 227 | const SubPatterns::const_iterator iend = subpatterns_.end(); | |
132 |
2/2✓ Branch 1 taken 284 times.
✓ Branch 2 taken 227 times.
|
511 | for (; i != iend; ++i) { |
133 |
2/4✓ Branch 2 taken 284 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 284 times.
✗ Branch 6 not taken.
|
284 | result += (*i)->GenerateRegularExpression(is_relaxed); |
134 | } | ||
135 | 454 | return result; | |
136 | } | ||
137 | |||
138 | 34 | std::string PathspecElementPattern::GenerateGlobString() const { | |
139 | 34 | std::string result; | |
140 | 34 | SubPatterns::const_iterator i = subpatterns_.begin(); | |
141 | 34 | const SubPatterns::const_iterator iend = subpatterns_.end(); | |
142 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 34 times.
|
74 | for (; i != iend; ++i) { |
143 |
2/4✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
|
40 | result += (*i)->GenerateGlobString(); |
144 | } | ||
145 | 68 | return result; | |
146 | } | ||
147 | |||
148 | 102 | bool PathspecElementPattern::operator== ( | |
149 | const PathspecElementPattern &other) const | ||
150 | { | ||
151 |
5/6✓ Branch 2 taken 92 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 92 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 92 times.
|
194 | if (subpatterns_.size() != other.subpatterns_.size() || |
152 | 92 | IsValid() != other.IsValid()) { | |
153 | 10 | return false; | |
154 | } | ||
155 | |||
156 | 92 | SubPatterns::const_iterator i = subpatterns_.begin(); | |
157 | 92 | const SubPatterns::const_iterator iend = subpatterns_.end(); | |
158 | 92 | SubPatterns::const_iterator j = other.subpatterns_.begin(); | |
159 | 92 | const SubPatterns::const_iterator jend = other.subpatterns_.end(); | |
160 | |||
161 |
5/6✓ Branch 3 taken 106 times.
✓ Branch 4 taken 69 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 106 times.
✓ Branch 9 taken 69 times.
|
175 | for (; i != iend && j != jend; ++i, ++j) { |
162 |
3/4✓ Branch 3 taken 106 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
✓ Branch 6 taken 83 times.
|
106 | if (!(*i)->Compare(*j)) { |
163 | 23 | return false; | |
164 | } | ||
165 | } | ||
166 | |||
167 | 69 | return true; | |
168 | } | ||
169 | |||
170 | |||
171 | //------------------------------------------------------------------------------ | ||
172 | |||
173 | |||
174 | 1412 | void PathspecElementPattern::PlaintextSubPattern::AddChar(const char chr) { | |
175 | 1412 | chars_.push_back(chr); | |
176 | 1412 | } | |
177 | |||
178 | std::string | ||
179 | 222 | PathspecElementPattern::PlaintextSubPattern::GenerateRegularExpression( | |
180 | const bool is_relaxed) const | ||
181 | { | ||
182 | // Note: strict and relaxed regex are the same! | ||
183 | 222 | std::string::const_iterator i = chars_.begin(); | |
184 | 222 | const std::string::const_iterator iend = chars_.end(); | |
185 | 222 | std::string regex; | |
186 |
2/2✓ Branch 2 taken 971 times.
✓ Branch 3 taken 222 times.
|
1193 | for (; i != iend; ++i) { |
187 |
2/2✓ Branch 2 taken 56 times.
✓ Branch 3 taken 915 times.
|
971 | if (IsSpecialRegexCharacter(*i)) { |
188 |
1/2✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
|
56 | regex += "\\"; |
189 | } | ||
190 |
1/2✓ Branch 2 taken 971 times.
✗ Branch 3 not taken.
|
971 | regex += *i; |
191 | } | ||
192 | 444 | return regex; | |
193 | } | ||
194 | |||
195 | |||
196 | std::string | ||
197 | 36 | PathspecElementPattern::PlaintextSubPattern::GenerateGlobString() const | |
198 | { | ||
199 | 36 | std::string::const_iterator i = chars_.begin(); | |
200 | 36 | const std::string::const_iterator iend = chars_.end(); | |
201 | 36 | std::string glob_string; | |
202 |
2/2✓ Branch 2 taken 184 times.
✓ Branch 3 taken 36 times.
|
220 | for (; i != iend; ++i) { |
203 |
2/2✓ Branch 2 taken 4 times.
✓ Branch 3 taken 180 times.
|
184 | if (Pathspec::IsSpecialChar(*i)) { |
204 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | glob_string += "\\"; |
205 | } | ||
206 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | glob_string += *i; |
207 | } | ||
208 | 72 | return glob_string; | |
209 | } | ||
210 | |||
211 | 971 | bool PathspecElementPattern::PlaintextSubPattern::IsSpecialRegexCharacter( | |
212 | const char chr) const | ||
213 | { | ||
214 |
2/2✓ Branch 0 taken 934 times.
✓ Branch 1 taken 2 times.
|
936 | return (chr == '.' || |
215 |
2/2✓ Branch 0 taken 931 times.
✓ Branch 1 taken 3 times.
|
934 | chr == '\\' || |
216 |
2/2✓ Branch 0 taken 927 times.
✓ Branch 1 taken 4 times.
|
931 | chr == '*' || |
217 |
2/2✓ Branch 0 taken 925 times.
✓ Branch 1 taken 2 times.
|
927 | chr == '?' || |
218 |
2/2✓ Branch 0 taken 923 times.
✓ Branch 1 taken 2 times.
|
925 | chr == '[' || |
219 |
2/2✓ Branch 0 taken 922 times.
✓ Branch 1 taken 1 times.
|
923 | chr == ']' || |
220 |
2/2✓ Branch 0 taken 921 times.
✓ Branch 1 taken 1 times.
|
922 | chr == '(' || |
221 |
2/2✓ Branch 0 taken 920 times.
✓ Branch 1 taken 1 times.
|
921 | chr == ')' || |
222 |
2/2✓ Branch 0 taken 919 times.
✓ Branch 1 taken 1 times.
|
920 | chr == '{' || |
223 |
2/2✓ Branch 0 taken 918 times.
✓ Branch 1 taken 1 times.
|
919 | chr == '}' || |
224 |
2/2✓ Branch 0 taken 917 times.
✓ Branch 1 taken 1 times.
|
918 | chr == '^' || |
225 |
4/4✓ Branch 0 taken 936 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 915 times.
|
1907 | chr == '$' || |
226 | 971 | chr == '+'); | |
227 | } | ||
228 | |||
229 | 80 | bool PathspecElementPattern::PlaintextSubPattern::Compare( | |
230 | const SubPattern *other) const | ||
231 | { | ||
232 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 79 times.
|
80 | if (!other->IsPlaintext()) { |
233 | 1 | return false; | |
234 | } | ||
235 | |||
236 | const PlaintextSubPattern *pt_other = | ||
237 |
1/2✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
|
79 | dynamic_cast<const PlaintextSubPattern*>(other); |
238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
|
79 | assert(pt_other != NULL); |
239 | 79 | return chars_ == pt_other->chars_; | |
240 | } | ||
241 | |||
242 | |||
243 | std::string | ||
244 | 41 | PathspecElementPattern::WildcardSubPattern::GenerateRegularExpression( | |
245 | const bool is_relaxed) const | ||
246 | { | ||
247 | return (is_relaxed) | ||
248 | ? std::string(".*") | ||
249 |
14/27✓ Branch 0 taken 14 times.
✓ Branch 1 taken 27 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 27 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 27 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 27 times.
✓ Branch 17 taken 14 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 27 times.
✓ Branch 20 taken 14 times.
✓ Branch 22 taken 27 times.
✓ Branch 23 taken 14 times.
✓ Branch 25 taken 14 times.
✓ Branch 26 taken 27 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
|
82 | : std::string("[^") + Pathspec::kSeparator + "]*"; |
250 | } | ||
251 | |||
252 | |||
253 | std::string | ||
254 | 2 | PathspecElementPattern::WildcardSubPattern::GenerateGlobString() const | |
255 | { | ||
256 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | return "*"; |
257 | } | ||
258 | |||
259 | |||
260 | 14 | bool PathspecElementPattern::WildcardSubPattern::Compare( | |
261 | const SubPattern *other) const | ||
262 | { | ||
263 | 14 | return other->IsWildcard(); | |
264 | } | ||
265 | |||
266 | |||
267 | std::string | ||
268 | 21 | PathspecElementPattern::PlaceholderSubPattern::GenerateRegularExpression( | |
269 | const bool is_relaxed) const | ||
270 | { | ||
271 | // Note: strict and relaxed regex are the same! | ||
272 |
3/6✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
|
42 | return std::string("[^") + Pathspec::kSeparator + "]"; |
273 | } | ||
274 | |||
275 | std::string | ||
276 | 2 | PathspecElementPattern::PlaceholderSubPattern::GenerateGlobString() const | |
277 | { | ||
278 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | return "?"; |
279 | } | ||
280 | |||
281 | 12 | bool PathspecElementPattern::PlaceholderSubPattern::Compare( | |
282 | const SubPattern *other) const | ||
283 | { | ||
284 | 12 | return other->IsPlaceholder(); | |
285 | } | ||
286 |