xs_match.h 2.0 KB

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