2 * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; only
7 * version 2.1 of the License.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <linux/types.h>
21 #include <lttng-string-utils.h>
23 enum star_glob_pattern_type_flags
{
24 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
= 0,
25 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
= (1U << 0),
26 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
= (1U << 1),
30 enum star_glob_pattern_type_flags
strutils_test_glob_pattern(const char *pattern
)
32 enum star_glob_pattern_type_flags ret
=
33 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
;
36 for (p
= pattern
; *p
!= '\0'; p
++) {
39 ret
= STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
42 ret
|= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
62 * Returns true if `pattern` is a star-only globbing pattern, that is,
63 * it contains at least one non-escaped `*`.
65 bool strutils_is_star_glob_pattern(const char *pattern
)
67 return strutils_test_glob_pattern(pattern
) &
68 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
72 * Returns true if `pattern` is a globbing pattern with a globbing,
73 * non-escaped star only at its very end.
75 bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern
)
77 return strutils_test_glob_pattern(pattern
) &
78 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
81 struct string_with_len
{
87 char string_get_char_at_cb(size_t at
, void *data
)
89 struct string_with_len
*string_with_len
= data
;
91 if (at
>= string_with_len
->len
) {
95 return string_with_len
->str
[at
];
99 * Globbing matching function with the star feature only (`?` and
100 * character sets are not supported). This matches `candidate` (plain
101 * string) against `pattern`. A literal star can be escaped with `\` in
104 * `pattern_len` or `candidate_len` can be greater than the actual
105 * string length of `pattern` or `candidate` if the string is
108 bool strutils_star_glob_match(const char *pattern
, size_t pattern_len
,
109 const char *candidate
, size_t candidate_len
) {
110 struct string_with_len pattern_with_len
= {
113 struct string_with_len candidate_with_len
= {
114 candidate
, candidate_len
117 return strutils_star_glob_match_char_cb(string_get_char_at_cb
,
118 &pattern_with_len
, string_get_char_at_cb
,
119 &candidate_with_len
);
122 bool strutils_star_glob_match_char_cb(
123 strutils_get_char_at_cb pattern_get_char_at_cb
,
124 void *pattern_get_char_at_cb_data
,
125 strutils_get_char_at_cb candidate_get_char_at_cb
,
126 void *candidate_get_char_at_cb_data
)
128 size_t retry_p_at
= 0, retry_c_at
= 0, c_at
, p_at
;
130 bool got_a_star
= false;
134 c
= candidate_get_char_at_cb(c_at
, candidate_get_char_at_cb_data
);
136 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
139 * The concept here is to retry a match in the specific case
140 * where we already got a star. The retry position for the
141 * pattern is just after the most recent star, and the retry
142 * position for the candidate is the character following the
143 * last try's first character.
147 * candidate: hi ev every onyx one
149 * pattern: hi*every*one
152 * candidate: hi ev every onyx one
154 * pattern: hi*every*one
157 * candidate: hi ev every onyx one
159 * pattern: hi*every*one
162 * candidate: hi ev every onyx one
164 * pattern: hi*every*one
167 * candidate: hi ev every onyx one
169 * pattern: hi*every*one
172 * candidate: hi ev every onyx one
174 * pattern: hi*every*one
177 * candidate: hi ev every onyx one
179 * pattern: hi*every*one
182 * candidate: hi ev every onyx one
184 * pattern: hi*every*one
187 * candidate: hi ev every onyx one
189 * pattern: hi*every*one
192 * candidate: hi ev every onyx one
194 * pattern: hi*every*one
197 * candidate: hi ev every onyx one
199 * pattern: hi*every*one
202 * candidate: hi ev every onyx one
204 * pattern: hi*every*one
207 * candidate: hi ev every onyx one
209 * pattern: hi*every*one
212 * candidate: hi ev every onyx one
214 * pattern: hi*every*one
217 * candidate: hi ev every onyx one
219 * pattern: hi*every*one
222 * candidate: hi ev every onyx one
224 * pattern: hi*every*one
227 * candidate: hi ev every onyx one
229 * pattern: hi*every*one
232 * candidate: hi ev every onyx one
234 * pattern: hi*every*one
237 * candidate: hi ev every onyx one
239 * pattern: hi*every*one
242 * candidate: hi ev every onyx one
244 * pattern: hi*every*one
247 * candidate: hi ev every onyx one
249 * pattern: hi*every*one
252 * candidate: hi ev every onyx one
254 * pattern: hi*every*one
257 * candidate: hi ev every onyx one
259 * pattern: hi*every*one
262 * candidate: hi ev every onyx one
264 * pattern: hi*every*one
267 * candidate: hi ev every onyx one
269 * pattern: hi*every*one
272 * candidate: hi ev every onyx one
274 * pattern: hi*every*one
277 * candidate: hi ev every onyx one
279 * pattern: hi*every*one
294 * Our first try starts at the current candidate
295 * character and after the star in the pattern.
298 retry_p_at
= p_at
+ 1;
299 retry_p
= pattern_get_char_at_cb(retry_p_at
,
300 pattern_get_char_at_cb_data
);
302 if (retry_p
== '\0') {
304 * Star at the end of the pattern at
305 * this point: automatic match.
313 /* Go to escaped character. */
315 p
= pattern_get_char_at_cb(p_at
,
316 pattern_get_char_at_cb_data
);
319 * Fall through the default case which will
320 * compare the escaped character now.
323 if (p
== '\0' || c
!= p
) {
325 /* Character mismatch OR end of pattern. */
328 * We didn't get any star yet,
329 * so this first mismatch
330 * automatically makes the whole
337 * Next try: next candidate character,
338 * original pattern character (following
339 * the most recent star).
347 /* Next pattern and candidate characters. */
349 c
= candidate_get_char_at_cb(c_at
,
350 candidate_get_char_at_cb_data
);
352 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
356 * We checked every candidate character and we're still in a
357 * success state: the only pattern character allowed to remain
366 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
367 return prev_p
== '*' && p
== '\0';