summaryrefslogtreecommitdiff
path: root/xs_match.h
diff options
context:
space:
mode:
authordefault <nobody@localhost>2023-09-21 11:37:51 +0200
committerdefault <nobody@localhost>2023-09-21 11:37:51 +0200
commit8775424f1383ca9a6e97852029d244e4e51abfc4 (patch)
treeaa6f7fe3e772667f30800d02582ab66fe74de38d /xs_match.h
parent8698b3f59edd554024fc680325c98bdb388a511a (diff)
Backport from xs.
Diffstat (limited to 'xs_match.h')
-rw-r--r--xs_match.h92
1 files changed, 57 insertions, 35 deletions
diff --git a/xs_match.h b/xs_match.h
index 9f12c15..dac7e2e 100644
--- a/xs_match.h
+++ b/xs_match.h
@@ -17,50 +17,72 @@ int xs_match(const char *str, const char *spec);
int xs_match(const char *str, const char *spec)
{
- const char *o_str = str;
+ const char *b_str;
+ const char *b_spec = NULL;
+ const char *o_str = str;
-again:
- if (*spec == '*') {
- spec++; /* wildcard */
+retry:
- do {
- if (xs_match(str, spec))
- return 1;
- str++;
- } while (*str);
+ for (;;) {
+ char c = *str++;
+ char p = *spec++;
- return 0;
- }
+ if (c == '\0') {
+ /* end of string; also end of spec? */
+ if (p == '\0' || p == '|')
+ return 1;
+ else
+ break;
+ }
+ else
+ if (p == '?') {
+ /* match anything except the end */
+ if (c == '\0')
+ return 0;
+ }
+ else
+ if (p == '*') {
+ /* end of spec? match */
+ if (*spec == '\0')
+ return 1;
- if (*spec == '?' && *str) {
- spec++; /* any character */
- str++;
- goto again;
+ /* store spec for later */
+ b_spec = spec;
+
+ /* back one char */
+ b_str = --str;
+ }
+ else {
+ if (p == '\\')
+ p = *spec++;
+
+ if (c != p) {
+ /* mismatch; do we have a backtrack? */
+ if (b_spec) {
+ /* continue where we left, one char forward */
+ spec = b_spec;
+ str = ++b_str;
+ }
+ else
+ break;
+ }
+ }
}
- if (*spec == '|')
- return 1; /* alternative separator? positive match */
-
- if (!*spec)
- return 1; /* end of spec? positive match */
-
- if (*spec == '\\')
- spec++; /* escaped char */
+ /* try to find an alternative mark */
+ while (*spec) {
+ char p = *spec++;
- if (*spec == *str) {
- spec++; /* matched 1 char */
- str++;
- goto again;
- }
+ if (p == '\\')
+ p = *spec++;
- /* not matched; are there any alternatives? */
- while (*spec) {
- if (*spec == '|')
- return xs_match(o_str, spec + 1); /* try next alternative */
+ if (p == '|') {
+ /* no backtrack spec, restart str from the beginning */
+ b_spec = NULL;
+ str = o_str;
- if (*spec == '\\')
- spec++; /* escaped char */
- spec++;
+ goto retry;
+ }
}
return 0;