1 /* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1)
3 * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
6 #include <linux/types.h>
8 #include <lttng-string-utils.h>
10 enum star_glob_pattern_type_flags
{
11 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
= 0,
12 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
= (1U << 0),
13 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
= (1U << 1),
17 enum star_glob_pattern_type_flags
strutils_test_glob_pattern(const char *pattern
)
19 enum star_glob_pattern_type_flags ret
=
20 STAR_GLOB_PATTERN_TYPE_FLAG_NONE
;
23 for (p
= pattern
; *p
!= '\0'; p
++) {
26 ret
= STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
29 ret
|= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
49 * Returns true if `pattern` is a star-only globbing pattern, that is,
50 * it contains at least one non-escaped `*`.
52 bool strutils_is_star_glob_pattern(const char *pattern
)
54 return strutils_test_glob_pattern(pattern
) &
55 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN
;
59 * Returns true if `pattern` is a globbing pattern with a globbing,
60 * non-escaped star only at its very end.
62 bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern
)
64 return strutils_test_glob_pattern(pattern
) &
65 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY
;
68 struct string_with_len
{
74 char string_get_char_at_cb(size_t at
, void *data
)
76 struct string_with_len
*string_with_len
= data
;
78 if (at
>= string_with_len
->len
) {
82 return string_with_len
->str
[at
];
86 * Globbing matching function with the star feature only (`?` and
87 * character sets are not supported). This matches `candidate` (plain
88 * string) against `pattern`. A literal star can be escaped with `\` in
91 * `pattern_len` or `candidate_len` can be greater than the actual
92 * string length of `pattern` or `candidate` if the string is
95 bool strutils_star_glob_match(const char *pattern
, size_t pattern_len
,
96 const char *candidate
, size_t candidate_len
) {
97 struct string_with_len pattern_with_len
= {
100 struct string_with_len candidate_with_len
= {
101 candidate
, candidate_len
104 return strutils_star_glob_match_char_cb(string_get_char_at_cb
,
105 &pattern_with_len
, string_get_char_at_cb
,
106 &candidate_with_len
);
109 bool strutils_star_glob_match_char_cb(
110 strutils_get_char_at_cb pattern_get_char_at_cb
,
111 void *pattern_get_char_at_cb_data
,
112 strutils_get_char_at_cb candidate_get_char_at_cb
,
113 void *candidate_get_char_at_cb_data
)
115 size_t retry_p_at
= 0, retry_c_at
= 0, c_at
, p_at
;
117 bool got_a_star
= false;
121 c
= candidate_get_char_at_cb(c_at
, candidate_get_char_at_cb_data
);
123 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
126 * The concept here is to retry a match in the specific case
127 * where we already got a star. The retry position for the
128 * pattern is just after the most recent star, and the retry
129 * position for the candidate is the character following the
130 * last try's first character.
134 * candidate: hi ev every onyx one
136 * pattern: hi*every*one
139 * candidate: hi ev every onyx one
141 * pattern: hi*every*one
144 * candidate: hi ev every onyx one
146 * pattern: hi*every*one
149 * candidate: hi ev every onyx one
151 * pattern: hi*every*one
154 * candidate: hi ev every onyx one
156 * pattern: hi*every*one
159 * candidate: hi ev every onyx one
161 * pattern: hi*every*one
164 * candidate: hi ev every onyx one
166 * pattern: hi*every*one
169 * candidate: hi ev every onyx one
171 * pattern: hi*every*one
174 * candidate: hi ev every onyx one
176 * pattern: hi*every*one
179 * candidate: hi ev every onyx one
181 * pattern: hi*every*one
184 * candidate: hi ev every onyx one
186 * pattern: hi*every*one
189 * candidate: hi ev every onyx one
191 * pattern: hi*every*one
194 * candidate: hi ev every onyx one
196 * pattern: hi*every*one
199 * candidate: hi ev every onyx one
201 * pattern: hi*every*one
204 * candidate: hi ev every onyx one
206 * pattern: hi*every*one
209 * candidate: hi ev every onyx one
211 * pattern: hi*every*one
214 * candidate: hi ev every onyx one
216 * pattern: hi*every*one
219 * candidate: hi ev every onyx one
221 * pattern: hi*every*one
224 * candidate: hi ev every onyx one
226 * pattern: hi*every*one
229 * candidate: hi ev every onyx one
231 * pattern: hi*every*one
234 * candidate: hi ev every onyx one
236 * pattern: hi*every*one
239 * candidate: hi ev every onyx one
241 * pattern: hi*every*one
244 * candidate: hi ev every onyx one
246 * pattern: hi*every*one
249 * candidate: hi ev every onyx one
251 * pattern: hi*every*one
254 * candidate: hi ev every onyx one
256 * pattern: hi*every*one
259 * candidate: hi ev every onyx one
261 * pattern: hi*every*one
264 * candidate: hi ev every onyx one
266 * pattern: hi*every*one
281 * Our first try starts at the current candidate
282 * character and after the star in the pattern.
285 retry_p_at
= p_at
+ 1;
286 retry_p
= pattern_get_char_at_cb(retry_p_at
,
287 pattern_get_char_at_cb_data
);
289 if (retry_p
== '\0') {
291 * Star at the end of the pattern at
292 * this point: automatic match.
300 /* Go to escaped character. */
302 p
= pattern_get_char_at_cb(p_at
,
303 pattern_get_char_at_cb_data
);
308 * Default case which will compare the escaped
311 if (p
== '\0' || c
!= p
) {
313 /* Character mismatch OR end of pattern. */
316 * We didn't get any star yet,
317 * so this first mismatch
318 * automatically makes the whole
325 * Next try: next candidate character,
326 * original pattern character (following
327 * the most recent star).
335 /* Next pattern and candidate characters. */
337 c
= candidate_get_char_at_cb(c_at
,
338 candidate_get_char_at_cb_data
);
340 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
344 * We checked every candidate character and we're still in a
345 * success state: the only pattern character allowed to remain
354 p
= pattern_get_char_at_cb(p_at
, pattern_get_char_at_cb_data
);
355 return prev_p
== '*' && p
== '\0';