2.66
xs_match.h
1/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
2
3#ifndef _XS_MATCH_H
4
5#define _XS_MATCH_H
6
7/* spec is very similar to shell file globbing:
8 an * matches anything;
9 a ? matches any character;
10 | select alternative strings to match;
11 a \\ escapes a special character;
12 any other char matches itself. */
13
14int xs_match(const char *str, const char *spec);
15
16#ifdef XS_IMPLEMENTATION
17
18int xs_match(const char *str, const char *spec)
19{
20 const char *b_str;
21 const char *b_spec = NULL;
22 const char *o_str = str;
23
24retry:
25
26 for (;;) {
27 char c = *str++;
28 char p = *spec++;
29
30 if (c == '\0') {
31 /* end of string; also end of spec? */
32 if (p == '\0' || p == '|')
33 return 1;
34 else
35 break;
36 }
37 else
38 if (p == '?') {
39 /* match anything except the end */
40 if (c == '\0')
41 return 0;
42 }
43 else
44 if (p == '*') {
45 /* end of spec? match */
46 if (*spec == '\0')
47 return 1;
48
49 /* store spec for later */
50 b_spec = spec;
51
52 /* back one char */
53 b_str = --str;
54 }
55 else {
56 if (p == '\\')
57 p = *spec++;
58
59 if (c != p) {
60 /* mismatch; do we have a backtrack? */
61 if (b_spec) {
62 /* continue where we left, one char forward */
63 spec = b_spec;
64 str = ++b_str;
65 }
66 else
67 break;
68 }
69 }
70 }
71
72 /* try to find an alternative mark */
73 while (*spec) {
74 char p = *spec++;
75
76 if (p == '\\')
77 p = *spec++;
78
79 if (p == '|') {
80 /* no backtrack spec, restart str from the beginning */
81 b_spec = NULL;
82 str = o_str;
83
84 goto retry;
85 }
86 }
87
88 return 0;
89}
90
91#endif /* XS_IMPLEMENTATION */
92
93#endif /* XS_MATCH_H */