snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

xs_match.h (2166B)


      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 
     14 int xs_match(const char *str, const char *spec);
     15 
     16 #ifdef XS_IMPLEMENTATION
     17 
     18 int xs_match(const char *str, const char *spec)
     19 {
     20     const char *b_str = NULL;
     21     const char *b_spec = NULL;
     22     const char *o_str  = str;
     23 
     24 retry:
     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 */