2.71 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 */