1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
3 * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
6 #include <linux/types.h>
7 #include <wrapper/compiler_attributes.h>
9 #include <lttng/string-utils.h>
11 enum star_glob_pattern_type_flags
{
12 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
= 0,
13 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
= (1U << 0),
14 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
= (1U << 1),
18 enum star_glob_pattern_type_flags
strutils_test_glob_pattern(const char *pattern
)
20 enum star_glob_pattern_type_flags ret
=
21 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
;
24 for (p
= pattern
; *p
!= '\0'; p
++) {
27 ret
= STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
30 ret
|= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
50 * Returns true if `pattern` is a star-only globbing pattern, that is,
51 * it contains at least one non-escaped `*`.
53 bool strutils_is_star_glob_pattern(const char *pattern
)
55 return strutils_test_glob_pattern(pattern
) &
56 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
60 * Returns true if `pattern` is a globbing pattern with a globbing,
61 * non-escaped star only at its very end.
63 bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern
)
65 return strutils_test_glob_pattern(pattern
) &
66 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
69 struct string_with_len
{
75 char string_get_char_at_cb(size_t at
, void *data
)
77 struct string_with_len
*string_with_len
= data
;
79 if (at
>= string_with_len
->len
) {
83 return string_with_len
->str
[at
];
87 * Globbing matching function with the star feature only (`?` and
88 * character sets are not supported). This matches `candidate` (plain
89 * string) against `pattern`. A literal star can be escaped with `\` in
92 * `pattern_len` or `candidate_len` can be greater than the actual
93 * string length of `pattern` or `candidate` if the string is
96 bool strutils_star_glob_match(const char *pattern
, size_t pattern_len
,
97 const char *candidate
, size_t candidate_len
) {
98 struct string_with_len pattern_with_len
= {
101 struct string_with_len candidate_with_len
= {
102 candidate
, candidate_len
105 return strutils_star_glob_match_char_cb(string_get_char_at_cb
,
106 &pattern_with_len
, string_get_char_at_cb
,
107 &candidate_with_len
);
110 bool strutils_star_glob_match_char_cb(
111 strutils_get_char_at_cb pattern_get_char_at_cb
,
112 void *pattern_get_char_at_cb_data
,
113 strutils_get_char_at_cb candidate_get_char_at_cb
,
114 void *candidate_get_char_at_cb_data
)
116 size_t retry_p_at
= 0, retry_c_at
= 0, c_at
, p_at
;
118 bool got_a_star
= false;
122 c
= candidate_get_char_at_cb(c_at
, candidate_get_char_at_cb_data
);
124 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
127 * The concept here is to retry a match in the specific case
128 * where we already got a star. The retry position for the
129 * pattern is just after the most recent star, and the retry
130 * position for the candidate is the character following the
131 * last try's first character.
135 * candidate: hi ev every onyx one
137 * pattern: hi*every*one
140 * candidate: hi ev every onyx one
142 * pattern: hi*every*one
145 * candidate: hi ev every onyx one
147 * pattern: hi*every*one
150 * candidate: hi ev every onyx one
152 * pattern: hi*every*one
155 * candidate: hi ev every onyx one
157 * pattern: hi*every*one
160 * candidate: hi ev every onyx one
162 * pattern: hi*every*one
165 * candidate: hi ev every onyx one
167 * pattern: hi*every*one
170 * candidate: hi ev every onyx one
172 * pattern: hi*every*one
175 * candidate: hi ev every onyx one
177 * pattern: hi*every*one
180 * candidate: hi ev every onyx one
182 * pattern: hi*every*one
185 * candidate: hi ev every onyx one
187 * pattern: hi*every*one
190 * candidate: hi ev every onyx one
192 * pattern: hi*every*one
195 * candidate: hi ev every onyx one
197 * pattern: hi*every*one
200 * candidate: hi ev every onyx one
202 * pattern: hi*every*one
205 * candidate: hi ev every onyx one
207 * pattern: hi*every*one
210 * candidate: hi ev every onyx one
212 * pattern: hi*every*one
215 * candidate: hi ev every onyx one
217 * pattern: hi*every*one
220 * candidate: hi ev every onyx one
222 * pattern: hi*every*one
225 * candidate: hi ev every onyx one
227 * pattern: hi*every*one
230 * candidate: hi ev every onyx one
232 * pattern: hi*every*one
235 * candidate: hi ev every onyx one
237 * pattern: hi*every*one
240 * candidate: hi ev every onyx one
242 * pattern: hi*every*one
245 * candidate: hi ev every onyx one
247 * pattern: hi*every*one
250 * candidate: hi ev every onyx one
252 * pattern: hi*every*one
255 * candidate: hi ev every onyx one
257 * pattern: hi*every*one
260 * candidate: hi ev every onyx one
262 * pattern: hi*every*one
265 * candidate: hi ev every onyx one
267 * pattern: hi*every*one
282 * Our first try starts at the current candidate
283 * character and after the star in the pattern.
286 retry_p_at
= p_at
+ 1;
287 retry_p
= pattern_get_char_at_cb(retry_p_at
,
288 pattern_get_char_at_cb_data
);
290 if (retry_p
== '\0') {
292 * Star at the end of the pattern at
293 * this point: automatic match.
301 /* Go to escaped character. */
303 p
= pattern_get_char_at_cb(p_at
,
304 pattern_get_char_at_cb_data
);
309 * Default case which will compare the escaped
312 if (p
== '\0' || c
!= p
) {
314 /* Character mismatch OR end of pattern. */
317 * We didn't get any star yet,
318 * so this first mismatch
319 * automatically makes the whole
326 * Next try: next candidate character,
327 * original pattern character (following
328 * the most recent star).
336 /* Next pattern and candidate characters. */
338 c
= candidate_get_char_at_cb(c_at
,
339 candidate_get_char_at_cb_data
);
341 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
345 * We checked every candidate character and we're still in a
346 * success state: the only pattern character allowed to remain
355 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
356 return prev_p
== '*' && p
== '\0';