]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/quickbook/src/glob.cpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / tools / quickbook / src / glob.cpp
CommitLineData
7c673cae
FG
1/*=============================================================================
2 Copyright (c) 2013 Daniel James
3
4 Use, modification and distribution is subject to the Boost Software
5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt)
7=============================================================================*/
8
9#include "glob.hpp"
10#include <cassert>
11
12namespace quickbook
13{
14 typedef boost::string_ref::const_iterator glob_iterator;
15
16 void check_glob_range(glob_iterator&, glob_iterator);
17 void check_glob_escape(glob_iterator&, glob_iterator);
18
19 bool match_section(glob_iterator& pattern_begin, glob_iterator pattern_end,
20 glob_iterator& filename_begin, glob_iterator& filename_end);
21 bool match_range(glob_iterator& pattern_begin, glob_iterator pattern_end,
22 unsigned char x);
23
24 bool check_glob(boost::string_ref pattern)
25 {
26 bool is_glob = false;
27 bool is_ascii = true;
28
29 glob_iterator begin = pattern.begin();
30 glob_iterator end = pattern.end();
31
32 while (begin != end) {
33 if (*begin < 32 || *begin > 127)
34 is_ascii = false;
35
36 switch(*begin) {
37 case '\\':
38 check_glob_escape(begin, end);
39 break;
40
41 case '[':
42 check_glob_range(begin, end);
43 is_glob = true;
44 break;
45
46 case ']':
47 throw glob_error("uneven square brackets");
48
49 case '?':
50 is_glob = true;
51 ++begin;
52 break;
53
54 case '*':
55 is_glob = true;
56 ++begin;
57
58 if (begin != end && *begin == '*') {
59 throw glob_error("'**' not supported");
60 }
61 break;
62
63 default:
64 ++begin;
65 }
66 }
67
68 if (is_glob && !is_ascii)
69 throw glob_error("invalid character, globs are ascii only");
70
71 return is_glob;
72 }
73
74 void check_glob_range(glob_iterator& begin, glob_iterator end)
75 {
76 assert(begin != end && *begin == '[');
77 ++begin;
78
79 if (*begin == ']')
80 throw glob_error("empty range");
81
82 while (begin != end) {
83 switch (*begin) {
84 case '\\':
85 ++begin;
86
87 if (begin == end) {
88 throw glob_error("trailing escape");
89 }
90 else if (*begin == '\\' || *begin == '/') {
91 throw glob_error("contains escaped slash");
92 }
93
94 ++begin;
95 break;
96 case '[':
97 // TODO: Allow?
98 throw glob_error("nested square brackets");
99 case ']':
100 ++begin;
101 return;
102 case '/':
103 throw glob_error("slash in square brackets");
104 default:
105 ++begin;
106 }
107 }
108
109 throw glob_error("uneven square brackets");
110 }
111
112 void check_glob_escape(glob_iterator& begin, glob_iterator end)
113 {
114 assert(begin != end && *begin == '\\');
115
116 ++begin;
117
118 if (begin == end) {
119 throw glob_error("trailing escape");
120 }
121 else if (*begin == '\\' || *begin == '/') {
122 throw glob_error("contains escaped slash");
123 }
124
125 ++begin;
126 }
127
128 bool glob(boost::string_ref const& pattern,
129 boost::string_ref const& filename)
130 {
131 // If there wasn't this special case then '*' would match an
132 // empty string.
133 if (filename.empty()) return pattern.empty();
134
135 glob_iterator pattern_it = pattern.begin();
136 glob_iterator pattern_end = pattern.end();
137
138 glob_iterator filename_it = filename.begin();
139 glob_iterator filename_end = filename.end();
140
141 if (!match_section(pattern_it, pattern_end, filename_it, filename_end))
142 return false;
143
144 while (pattern_it != pattern_end) {
145 assert(*pattern_it == '*');
146 ++pattern_it;
147
148 if (pattern_it == pattern_end) return true;
149
150 // TODO: Error?
151 if (*pattern_it == '*') return false;
152
153 while (true) {
154 if (filename_it == filename_end) return false;
155 if (match_section(pattern_it, pattern_end, filename_it, filename_end))
156 break;
157 ++filename_it;
158 }
159 }
160
161 return filename_it == filename_end;
162 }
163
164 bool match_section(glob_iterator& pattern_begin, glob_iterator pattern_end,
165 glob_iterator& filename_begin, glob_iterator& filename_end)
166 {
167 glob_iterator pattern_it = pattern_begin;
168 glob_iterator filename_it = filename_begin;
169
170 while (pattern_it != pattern_end && *pattern_it != '*') {
171 if (filename_it == filename_end) return false;
172
173 switch(*pattern_it) {
174 case '*':
175 assert(false);
176 return false;
177 case '[':
178 if (!match_range(pattern_it, pattern_end, *filename_it))
179 return false;
180 ++filename_it;
181 break;
182 case '?':
183 ++pattern_it;
184 ++filename_it;
185 break;
186 case '\\':
187 ++pattern_it;
188 if (pattern_it == pattern_end) return false;
189 BOOST_FALLTHROUGH;
190 default:
191 if (*pattern_it != *filename_it) return false;
192 ++pattern_it;
193 ++filename_it;
194 }
195 }
196
197 if (pattern_it == pattern_end && filename_it != filename_end)
198 return false;
199
200 pattern_begin = pattern_it;
201 filename_begin = filename_it;
202 return true;
203 }
204
205 bool match_range(glob_iterator& pattern_begin, glob_iterator pattern_end,
206 unsigned char x)
207 {
208 assert(pattern_begin != pattern_end && *pattern_begin == '[');
209 ++pattern_begin;
210 if (pattern_begin == pattern_end) return false;
211
212 bool invert_match = false;
213 bool matched = false;
214
215 if (*pattern_begin == '^') {
216 invert_match = true;
217 ++pattern_begin;
218 if (pattern_begin == pattern_end) return false;
219 }
220
221 // Search for a match
222 while (true) {
223 unsigned char first = *pattern_begin;
224 ++pattern_begin;
225 if (first == ']') break;
226 if (pattern_begin == pattern_end) return false;
227
228 if (first == '\\') {
229 first = *pattern_begin;
230 ++pattern_begin;
231 if (pattern_begin == pattern_end) return false;
232 }
233
234 if (*pattern_begin != '-') {
235 matched = matched || (first == x);
236 }
237 else {
238 ++pattern_begin;
239 if (pattern_begin == pattern_end) return false;
240
241 unsigned char second = *pattern_begin;
242 ++pattern_begin;
243 if (second == ']') {
244 matched = matched || (first == x) || (x == '-');
245 break;
246 }
247 if (pattern_begin == pattern_end) return false;
248
249 if (second == '\\') {
250 second = *pattern_begin;
251 ++pattern_begin;
252 if (pattern_begin == pattern_end) return false;
253 }
254
255 // TODO: What if second < first?
256 matched = matched || (first <= x && x <= second);
257 }
258 }
259
260 return invert_match != matched;
261 }
262
263 std::size_t find_glob_char(boost::string_ref pattern,
264 std::size_t pos)
265 {
266 // Weird style is because boost::string_ref's find_first_of
267 // doesn't take a position argument.
268 std::size_t removed = 0;
269
270 while (true) {
271 pos = pattern.find_first_of("[]?*\\");
272 if (pos == boost::string_ref::npos) return pos;
273 if (pattern[pos] != '\\') return pos + removed;
274 pattern.remove_prefix(pos + 2);
275 removed += pos + 2;
276 }
277 }
278
279 std::string glob_unescape(boost::string_ref pattern)
280 {
281 std::string result;
282
283 while (true) {
284 std::size_t pos = pattern.find("\\");
285 if (pos == boost::string_ref::npos) {
286 result.append(pattern.data(), pattern.size());
287 break;
288 }
289
290 result.append(pattern.data(), pos);
291 ++pos;
292 if (pos < pattern.size()) {
293 result += pattern[pos];
294 ++pos;
295 }
296 pattern.remove_prefix(pos);
297 }
298
299 return result;
300 }
301}