simple glob: * matches non-/ chars, ** matches anything including /, [] matches character class
| 705 | |
| 706 | // simple glob: * matches non-/ chars, ** matches anything including /, [] matches character class |
| 707 | static inline bool glob_match(const char * pattern, const char * str) { |
| 708 | if (*pattern == '\0') { |
| 709 | return *str == '\0'; |
| 710 | } |
| 711 | if (pattern[0] == '*' && pattern[1] == '*') { |
| 712 | const char * p = pattern + 2; |
| 713 | if (glob_match(p, str)) return true; |
| 714 | if (*str != '\0') return glob_match(pattern, str + 1); |
| 715 | return false; |
| 716 | } |
| 717 | if (*pattern == '*') { |
| 718 | const char * p = pattern + 1; |
| 719 | for (; *str != '\0' && *str != '/'; str++) { |
| 720 | if (glob_match(p, str)) return true; |
| 721 | } |
| 722 | return glob_match(p, str); |
| 723 | } |
| 724 | if (*pattern == '?' && *str != '\0' && *str != '/') { |
| 725 | return glob_match(pattern + 1, str + 1); |
| 726 | } |
| 727 | if (*pattern == '[') { |
| 728 | const char * class_end = pattern + 1; |
| 729 | // If first character after '[' is ']' or '-', treat it as literal |
| 730 | if (*class_end == ']' || *class_end == '-') { |
| 731 | class_end++; |
| 732 | } |
| 733 | while (*class_end != '\0' && *class_end != ']') { |
| 734 | class_end++; |
| 735 | } |
| 736 | if (*class_end == ']') { |
| 737 | if (*str == '\0') return false; |
| 738 | bool matched = glob_class_match(*str, pattern + 1, class_end); |
| 739 | return matched && glob_match(class_end + 1, str + 1); |
| 740 | } else { |
| 741 | if (*str == '[') { |
| 742 | return glob_match(pattern + 1, str + 1); |
| 743 | } |
| 744 | return false; |
| 745 | } |
| 746 | } |
| 747 | if (*pattern == *str) { |
| 748 | return glob_match(pattern + 1, str + 1); |
| 749 | } |
| 750 | return false; |
| 751 | } |
| 752 | |
| 753 | bool glob_match(const std::string & pattern, const std::string & str) { |
| 754 | return glob_match(pattern.c_str(), str.c_str()); |
no test coverage detected