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