Browse Source

Backport from xs.

default 1 year ago
parent
commit
8775424f13
2 changed files with 58 additions and 36 deletions
  1. 57 35
      xs_match.h
  2. 1 1
      xs_version.h

+ 57 - 35
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;

+ 1 - 1
xs_version.h

@@ -1 +1 @@
-/* 06767a70773865042a70680aef50f7ecb077681a */
+/* 263e97c8ac21ff8524e3c890fe4310c696d01056 */