GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/pathspec/pathspec_pattern.cc Lines: 125 126 99.2 %
Date: 2019-02-03 02:48:13 Branches: 105 127 82.7 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#include "cvmfs_config.h"
6
#include "pathspec_pattern.h"
7
8
#include <cassert>
9
10
#include "pathspec/pathspec.h"
11
12
627
PathspecElementPattern::PathspecElementPattern(
13
  const std::string::const_iterator begin,
14
  const std::string::const_iterator &end)
15
627
  : valid_(true)
16
{
17
627
  Parse(begin, end);
18
}
19
20
2192
PathspecElementPattern::PathspecElementPattern(
21
  const PathspecElementPattern& other)
22
2192
  : valid_(other.valid_)
23
{
24
2192
  subpatterns_.reserve(other.subpatterns_.size());
25
2192
  SubPatterns::const_iterator i    = other.subpatterns_.begin();
26
2192
  SubPatterns::const_iterator iend = other.subpatterns_.end();
27
4593
  for (; i != iend; ++i) {
28
2401
    subpatterns_.push_back((*i)->Clone());
29
  }
30
}
31
32
7
PathspecElementPattern& PathspecElementPattern::operator=(
33
                                            const PathspecElementPattern& other)
34
{
35
7
  if (this != &other) {
36
7
    valid_ = other.valid_;
37
7
    subpatterns_.clear();
38
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
18
    for (; i != iend; ++i) {
42
11
      subpatterns_.push_back((*i)->Clone());
43
    }
44
  }
45
46
7
  return *this;
47
}
48
49
50
2819
PathspecElementPattern::~PathspecElementPattern() {
51
2819
  SubPatterns::const_iterator i    = subpatterns_.begin();
52
2819
  SubPatterns::const_iterator iend = subpatterns_.end();
53
5942
  for (; i != iend; ++i) {
54
3123
    delete *i;
55
  }
56
2819
  subpatterns_.clear();
57
}
58
59
60
627
void PathspecElementPattern::Parse(const std::string::const_iterator  &begin,
61
                                   const std::string::const_iterator  &end) {
62
627
  std::string::const_iterator i = begin;
63
1976
  while (i != end) {
64
    SubPattern* next = (Pathspec::IsSpecialChar(*i))
65
                       ? ParseSpecialChar(end, &i)
66
722
                       : ParsePlaintext(end, &i);
67
722
    if (next->IsEmpty()) {
68
4
      valid_ = false;
69
4
      delete next;
70
    } else {
71
718
      subpatterns_.push_back(next);
72
    }
73
  }
74
627
}
75
76
77
538
PathspecElementPattern::SubPattern* PathspecElementPattern::ParsePlaintext(
78
  const std::string::const_iterator &end,
79
  std::string::const_iterator *i
80
) {
81
538
  PlaintextSubPattern *pattern = new PlaintextSubPattern();
82
538
  bool next_is_escaped = false;
83
84
3256
  while (*i < end) {
85

2216
    if (Pathspec::IsSpecialChar(**i) && !next_is_escaped) {
86
36
      break;
87
    }
88
89

2180
    if (**i == Pathspec::kEscaper && !next_is_escaped) {
90
22
      next_is_escaped = true;
91
2158
    } else if (next_is_escaped) {
92

34
      if (Pathspec::IsSpecialChar(**i) || **i == Pathspec::kEscaper) {
93
17
        pattern->AddChar(**i);
94
17
        next_is_escaped = false;
95
      } else {
96
17
        valid_ = false;
97
      }
98
    } else {
99
2124
      assert(!Pathspec::IsSpecialChar(**i));
100
2124
      pattern->AddChar(**i);
101
    }
102
103
2180
    ++(*i);
104
  }
105
106
538
  return pattern;
107
}
108
109
184
PathspecElementPattern::SubPattern* PathspecElementPattern::ParseSpecialChar(
110
  const std::string::const_iterator &end,
111
  std::string::const_iterator *i
112
) {
113
184
  assert(Pathspec::IsSpecialChar(**i));
114
184
  const char chr = **i;
115
184
  ++(*i);
116
117
184
  switch (chr) {
118
    case Pathspec::kWildcard:
119
123
      return new WildcardSubPattern();
120
    case Pathspec::kPlaceholder:
121
61
      return new PlaceholderSubPattern();
122
    default:
123
      assert(false && "unrecognized special character");
124
  }
125
}
126
127
338
std::string PathspecElementPattern::GenerateRegularExpression(
128
                                                  const bool is_relaxed) const {
129
338
  std::string result;
130
338
        SubPatterns::const_iterator i    = subpatterns_.begin();
131
338
  const SubPatterns::const_iterator iend = subpatterns_.end();
132
748
  for (; i != iend; ++i) {
133
410
    result += (*i)->GenerateRegularExpression(is_relaxed);
134
  }
135
338
  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
74
  for (; i != iend; ++i) {
143
40
    result += (*i)->GenerateGlobString();
144
  }
145
34
  return result;
146
}
147
148
180
bool PathspecElementPattern::operator== (
149
  const PathspecElementPattern &other) const
150
{
151

180
  if (subpatterns_.size() != other.subpatterns_.size() ||
152
      IsValid()           != other.IsValid()) {
153
22
    return false;
154
  }
155
156
158
        SubPatterns::const_iterator i    = subpatterns_.begin();
157
158
  const SubPatterns::const_iterator iend = subpatterns_.end();
158
158
        SubPatterns::const_iterator j    = other.subpatterns_.begin();
159
158
  const SubPatterns::const_iterator jend = other.subpatterns_.end();
160
161

286
  for (; i != iend && j != jend; ++i, ++j) {
162
172
    if (!(*i)->Compare(*j)) {
163
44
      return false;
164
    }
165
  }
166
167
114
  return true;
168
}
169
170
171
//------------------------------------------------------------------------------
172
173
174
2141
void PathspecElementPattern::PlaintextSubPattern::AddChar(const char chr) {
175
2141
  chars_.push_back(chr);
176
2141
}
177
178
std::string
179
312
  PathspecElementPattern::PlaintextSubPattern::GenerateRegularExpression(
180
  const bool is_relaxed) const
181
{
182
  // Note: strict and relaxed regex are the same!
183
312
        std::string::const_iterator i    = chars_.begin();
184
312
  const std::string::const_iterator iend = chars_.end();
185
312
  std::string regex;
186
1616
  for (; i != iend; ++i) {
187
1304
    if (IsSpecialRegexCharacter(*i)) {
188
74
      regex += "\\";
189
    }
190
1304
    regex += *i;
191
  }
192
312
  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
220
  for (; i != iend; ++i) {
203
184
    if (Pathspec::IsSpecialChar(*i)) {
204
4
      glob_string += "\\";
205
    }
206
184
    glob_string += *i;
207
  }
208
36
  return glob_string;
209
}
210
211
1304
bool PathspecElementPattern::PlaintextSubPattern::IsSpecialRegexCharacter(
212
  const char chr) const
213
{
214
  return (chr == '.'  ||
215
          chr == '\\' ||
216
          chr == '*'  ||
217
          chr == '?'  ||
218
          chr == '['  ||
219
          chr == ']'  ||
220
          chr == '('  ||
221
          chr == ')'  ||
222
          chr == '{'  ||
223
          chr == '}'  ||
224
          chr == '^'  ||
225
          chr == '$'  ||
226






1304
          chr == '+');
227
}
228
229
131
bool PathspecElementPattern::PlaintextSubPattern::Compare(
230
  const SubPattern *other) const
231
{
232
131
  if (!other->IsPlaintext()) {
233
1
    return false;
234
  }
235
236
  const PlaintextSubPattern *pt_other =
237
130
                                dynamic_cast<const PlaintextSubPattern*>(other);
238
130
  assert(pt_other != NULL);
239
130
  return chars_ == pt_other->chars_;
240
}
241
242
243
std::string
244
74
  PathspecElementPattern::WildcardSubPattern::GenerateRegularExpression(
245
  const bool is_relaxed) const
246
{
247
  return (is_relaxed)
248
         ? std::string(".*")
249





74
         : std::string("[^") + Pathspec::kSeparator + "]*";
250
}
251
252
253
std::string
254
2
  PathspecElementPattern::WildcardSubPattern::GenerateGlobString() const
255
{
256
2
  return "*";
257
}
258
259
260
29
bool PathspecElementPattern::WildcardSubPattern::Compare(
261
  const SubPattern *other) const
262
{
263
29
  return other->IsWildcard();
264
}
265
266
267
std::string
268
24
  PathspecElementPattern::PlaceholderSubPattern::GenerateRegularExpression(
269
  const bool is_relaxed) const
270
{
271
  // Note: strict and relaxed regex are the same!
272
24
  return std::string("[^") + Pathspec::kSeparator + "]";
273
}
274
275
std::string
276
2
  PathspecElementPattern::PlaceholderSubPattern::GenerateGlobString() const
277
{
278
2
  return "?";
279
}
280
281
12
bool PathspecElementPattern::PlaceholderSubPattern::Compare(
282
  const SubPattern *other) const
283
{
284
12
  return other->IsPlaceholder();
285
}