| 58 | } |
| 59 | |
| 60 | bool matchglob(const std::string& pattern, const std::string& name, bool caseInsensitive) |
| 61 | { |
| 62 | const char* p = pattern.c_str(); |
| 63 | const char* n = name.c_str(); |
| 64 | std::stack<std::pair<const char*, const char*>, std::vector<std::pair<const char*, const char*>>> backtrack; |
| 65 | |
| 66 | for (;;) { |
| 67 | bool matching = true; |
| 68 | while (*p != '\0' && matching) { |
| 69 | switch (*p) { |
| 70 | case '*': |
| 71 | // Step forward until we match the next character after * |
| 72 | while (*n != '\0' && *n != p[1]) { |
| 73 | n++; |
| 74 | } |
| 75 | if (*n != '\0') { |
| 76 | // If this isn't the last possibility, save it for later |
| 77 | backtrack.emplace(p, n); |
| 78 | } |
| 79 | break; |
| 80 | case '?': |
| 81 | // Any character matches unless we're at the end of the name |
| 82 | if (*n != '\0') { |
| 83 | n++; |
| 84 | } else { |
| 85 | matching = false; |
| 86 | } |
| 87 | break; |
| 88 | default: |
| 89 | // Non-wildcard characters match literally |
| 90 | if (*n == *p) { |
| 91 | n++; |
| 92 | } else if (caseInsensitive && tolower(*n) == tolower(*p)) { |
| 93 | n++; |
| 94 | } else { |
| 95 | matching = false; |
| 96 | } |
| 97 | break; |
| 98 | } |
| 99 | p++; |
| 100 | } |
| 101 | |
| 102 | // If we haven't failed matching and we've reached the end of the name, then success |
| 103 | if (matching && *n == '\0') { |
| 104 | return true; |
| 105 | } |
| 106 | |
| 107 | // If there are no other paths to try, then fail |
| 108 | if (backtrack.empty()) { |
| 109 | return false; |
| 110 | } |
| 111 | |
| 112 | // Restore pointers from backtrack stack |
| 113 | p = backtrack.top().first; |
| 114 | n = backtrack.top().second; |
| 115 | backtrack.pop(); |
| 116 | |
| 117 | // Advance name pointer by one because the current position didn't work |