2.85
xs_match.h
1/* copyright (c) 2022 - 2025 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 const char *q = spec;
28 char c = *str++;
29 char p = *spec++;
30
31 if (c == '\0') {
32 /* end of string; also end of spec? */
33 if (p == '\0' || p == '|')
34 return 1;
35 else
36 break;
37 }
38 else
39 if (p == '?') {
40 /* match anything except the end */
41 if (c == '\0')
42 return 0;
43 }
44 else
45 if (p == '*') {
46 /* end of spec? match */
47 if (*spec == '\0')
48 return 1;
49
50 /* store spec for later */
51 b_spec = spec;
52
53 /* back one char */
54 b_str = --str;
55 }
56 else {
57 if (p == '\\')
58 p = *spec++;
59
60 if (c != p) {
61 /* mismatch; do we have a backtrack? */
62 if (b_spec) {
63 /* continue where we left, one char forward */
64 spec = b_spec;
65 str = ++b_str;
66 }
67 else {
68 if (*q == '|')
69 spec = q;
70
71 break;
72 }
73 }
74 }
75 }
76
77 /* try to find an alternative mark */
78 while (*spec) {
79 char p = *spec++;
80
81 if (p == '\\')
82 p = *spec++;
83
84 if (p == '|') {
85 /* no backtrack spec, restart str from the beginning */
86 b_spec = NULL;
87 str = o_str;
88
89 goto retry;
90 }
91 }
92
93 return 0;
94}
95
96#endif /* XS_IMPLEMENTATION */
97
98#endif /* XS_MATCH_H */