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