Fix: timer_expire_entry changed in 4.19.312
[lttng-modules.git] / src / lttng-string-utils.c
CommitLineData
b7cdc182 1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
231b5333 2 *
9f36eaed 3 * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
231b5333
PP
4 */
5
6#include <linux/types.h>
c190d76e 7#include <wrapper/compiler_attributes.h>
231b5333 8
2df37e95 9#include <lttng/string-utils.h>
231b5333
PP
10
11enum 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),
15};
16
17static
18enum star_glob_pattern_type_flags strutils_test_glob_pattern(const char *pattern)
19{
20 enum star_glob_pattern_type_flags ret =
21 STAR_GLOB_PATTERN_TYPE_FLAG_NONE;
22 const char *p;
23
24 for (p = pattern; *p != '\0'; p++) {
25 switch (*p) {
26 case '*':
27 ret = STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
28
29 if (p[1] == '\0') {
30 ret |= STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
31 }
32 goto end;
33 case '\\':
34 p++;
35
36 if (*p == '\0') {
37 goto end;
38 }
39 break;
40 default:
41 break;
42 }
43 }
44
45end:
46 return ret;
47}
48
49/*
50 * Returns true if `pattern` is a star-only globbing pattern, that is,
51 * it contains at least one non-escaped `*`.
52 */
53bool strutils_is_star_glob_pattern(const char *pattern)
54{
55 return strutils_test_glob_pattern(pattern) &
56 STAR_GLOB_PATTERN_TYPE_FLAG_PATTERN;
57}
58
59/*
60 * Returns true if `pattern` is a globbing pattern with a globbing,
61 * non-escaped star only at its very end.
62 */
63bool strutils_is_star_at_the_end_only_glob_pattern(const char *pattern)
64{
65 return strutils_test_glob_pattern(pattern) &
66 STAR_GLOB_PATTERN_TYPE_FLAG_END_ONLY;
67}
68
69struct string_with_len {
70 const char *str;
71 size_t len;
72};
73
74static
75char string_get_char_at_cb(size_t at, void *data)
76{
77 struct string_with_len *string_with_len = data;
78
79 if (at >= string_with_len->len) {
80 return '\0';
81 }
82
83 return string_with_len->str[at];
84}
85
86/*
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
90 * `pattern`.
91 *
92 * `pattern_len` or `candidate_len` can be greater than the actual
93 * string length of `pattern` or `candidate` if the string is
94 * null-terminated.
95 */
96bool 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 = {
99 pattern, pattern_len
100 };
101 struct string_with_len candidate_with_len = {
102 candidate, candidate_len
103 };
104
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);
108}
109
110bool 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)
115{
116 size_t retry_p_at = 0, retry_c_at = 0, c_at, p_at;
117 char c, p, prev_p;
118 bool got_a_star = false;
119
120retry:
121 c_at = retry_c_at;
122 c = candidate_get_char_at_cb(c_at, candidate_get_char_at_cb_data);
123 p_at = retry_p_at;
124 p = pattern_get_char_at_cb(p_at, pattern_get_char_at_cb_data);
125
126 /*
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.
132 *
133 * Example:
134 *
135 * candidate: hi ev every onyx one
e755fa6d 136 * ^
231b5333 137 * pattern: hi*every*one
e755fa6d 138 * ^
231b5333
PP
139 *
140 * candidate: hi ev every onyx one
e755fa6d 141 * ^
231b5333 142 * pattern: hi*every*one
e755fa6d 143 * ^
231b5333
PP
144 *
145 * candidate: hi ev every onyx one
e755fa6d 146 * ^
231b5333 147 * pattern: hi*every*one
e755fa6d 148 * ^
231b5333
PP
149 *
150 * candidate: hi ev every onyx one
e755fa6d 151 * ^
231b5333 152 * pattern: hi*every*one
e755fa6d 153 * ^ MISMATCH
231b5333
PP
154 *
155 * candidate: hi ev every onyx one
e755fa6d 156 * ^
231b5333 157 * pattern: hi*every*one
e755fa6d 158 * ^
231b5333
PP
159 *
160 * candidate: hi ev every onyx one
e755fa6d 161 * ^^
231b5333 162 * pattern: hi*every*one
e755fa6d 163 * ^^
231b5333
PP
164 *
165 * candidate: hi ev every onyx one
e755fa6d 166 * ^ ^
231b5333 167 * pattern: hi*every*one
e755fa6d 168 * ^ ^ MISMATCH
231b5333
PP
169 *
170 * candidate: hi ev every onyx one
e755fa6d 171 * ^
231b5333 172 * pattern: hi*every*one
e755fa6d 173 * ^ MISMATCH
231b5333
PP
174 *
175 * candidate: hi ev every onyx one
e755fa6d 176 * ^
231b5333 177 * pattern: hi*every*one
e755fa6d 178 * ^ MISMATCH
231b5333
PP
179 *
180 * candidate: hi ev every onyx one
e755fa6d 181 * ^
231b5333 182 * pattern: hi*every*one
e755fa6d 183 * ^
231b5333
PP
184 *
185 * candidate: hi ev every onyx one
e755fa6d 186 * ^^
231b5333 187 * pattern: hi*every*one
e755fa6d 188 * ^^
231b5333
PP
189 *
190 * candidate: hi ev every onyx one
e755fa6d 191 * ^ ^
231b5333 192 * pattern: hi*every*one
e755fa6d 193 * ^ ^
231b5333
PP
194 *
195 * candidate: hi ev every onyx one
e755fa6d 196 * ^ ^
231b5333 197 * pattern: hi*every*one
e755fa6d 198 * ^ ^
231b5333
PP
199 *
200 * candidate: hi ev every onyx one
e755fa6d 201 * ^ ^
231b5333 202 * pattern: hi*every*one
e755fa6d 203 * ^ ^
231b5333
PP
204 *
205 * candidate: hi ev every onyx one
e755fa6d 206 * ^
231b5333 207 * pattern: hi*every*one
e755fa6d 208 * ^
231b5333
PP
209 *
210 * candidate: hi ev every onyx one
e755fa6d 211 * ^
231b5333 212 * pattern: hi*every*one
e755fa6d 213 * ^ MISMATCH
231b5333
PP
214 *
215 * candidate: hi ev every onyx one
e755fa6d 216 * ^
231b5333 217 * pattern: hi*every*one
e755fa6d 218 * ^
231b5333
PP
219 *
220 * candidate: hi ev every onyx one
e755fa6d 221 * ^^
231b5333 222 * pattern: hi*every*one
e755fa6d 223 * ^^
231b5333
PP
224 *
225 * candidate: hi ev every onyx one
e755fa6d 226 * ^ ^
231b5333 227 * pattern: hi*every*one
e755fa6d 228 * ^ ^ MISMATCH
231b5333
PP
229 *
230 * candidate: hi ev every onyx one
e755fa6d 231 * ^
231b5333 232 * pattern: hi*every*one
e755fa6d 233 * ^ MISMATCH
231b5333
PP
234 *
235 * candidate: hi ev every onyx one
e755fa6d 236 * ^
231b5333 237 * pattern: hi*every*one
e755fa6d 238 * ^ MISMATCH
231b5333
PP
239 *
240 * candidate: hi ev every onyx one
e755fa6d 241 * ^
231b5333 242 * pattern: hi*every*one
e755fa6d 243 * ^ MISMATCH
231b5333
PP
244 *
245 * candidate: hi ev every onyx one
e755fa6d 246 * ^
231b5333 247 * pattern: hi*every*one
e755fa6d 248 * ^ MISMATCH
231b5333
PP
249 *
250 * candidate: hi ev every onyx one
e755fa6d 251 * ^
231b5333 252 * pattern: hi*every*one
e755fa6d 253 * ^
231b5333
PP
254 *
255 * candidate: hi ev every onyx one
e755fa6d 256 * ^^
231b5333 257 * pattern: hi*every*one
e755fa6d 258 * ^^
231b5333
PP
259 *
260 * candidate: hi ev every onyx one
e755fa6d 261 * ^ ^
231b5333 262 * pattern: hi*every*one
e755fa6d 263 * ^ ^
231b5333
PP
264 *
265 * candidate: hi ev every onyx one
e755fa6d 266 * ^ ^
231b5333 267 * pattern: hi*every*one
e755fa6d 268 * ^ ^ SUCCESS
231b5333
PP
269 */
270 while (c != '\0') {
271 if (p == '\0') {
272 goto end_of_pattern;
273 }
274
275 switch (p) {
276 case '*':
277 {
278 char retry_p;
279 got_a_star = true;
280
281 /*
282 * Our first try starts at the current candidate
283 * character and after the star in the pattern.
284 */
285 retry_c_at = c_at;
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);
289
290 if (retry_p == '\0') {
291 /*
292 * Star at the end of the pattern at
293 * this point: automatic match.
294 */
295 return true;
296 }
297
298 goto retry;
299 }
300 case '\\':
301 /* Go to escaped character. */
302 p_at++;
303 p = pattern_get_char_at_cb(p_at,
304 pattern_get_char_at_cb_data);
305
c190d76e 306 lttng_fallthrough;
4e47802a 307 default:
231b5333 308 /*
4e47802a
MD
309 * Default case which will compare the escaped
310 * character now.
231b5333 311 */
231b5333
PP
312 if (p == '\0' || c != p) {
313end_of_pattern:
314 /* Character mismatch OR end of pattern. */
315 if (!got_a_star) {
316 /*
317 * We didn't get any star yet,
318 * so this first mismatch
319 * automatically makes the whole
320 * test fail.
321 */
322 return false;
323 }
324
325 /*
326 * Next try: next candidate character,
327 * original pattern character (following
328 * the most recent star).
329 */
330 retry_c_at++;
331 goto retry;
332 }
333 break;
334 }
335
336 /* Next pattern and candidate characters. */
337 c_at++;
338 c = candidate_get_char_at_cb(c_at,
339 candidate_get_char_at_cb_data);
340 p_at++;
341 p = pattern_get_char_at_cb(p_at, pattern_get_char_at_cb_data);
342 }
343
344 /*
345 * We checked every candidate character and we're still in a
346 * success state: the only pattern character allowed to remain
347 * is a star.
348 */
349 if (p == '\0') {
350 return true;
351 }
352
353 prev_p = p;
354 p_at++;
355 p = pattern_get_char_at_cb(p_at, pattern_get_char_at_cb_data);
356 return prev_p == '*' && p == '\0';
357}
This page took 0.063512 seconds and 4 git commands to generate.