X-Git-Url: https://git.distorted.org.uk/~mdw/anag/blobdiff_plain/650bb9da7cf5b677960c03e0a6a5616d48340845..904ac13a4c7d86c18d031ad3f113659440ab86b8:/wildcard.c?ds=sidebyside diff --git a/wildcard.c b/wildcard.c index 78b3168..82f33f0 100644 --- a/wildcard.c +++ b/wildcard.c @@ -51,81 +51,96 @@ typedef struct node_wild { static int match(const char *p, const char *s) { - for (;;) { - char pch = *p++, pche, sch; - int sense; + char pch, pche, sch; + int sense; + for (;;) { + pch = *p++; switch (pch) { + case '?': - if (!*s) - return (0); - s++; + /* If there's no character left, then we fail; otherwise consume + * anything and move on. + */ + + if (!*s++) return (0); break; + case '*': - if (!*p) - return (1); - while (*s) { - if (match(p, s)) - return (1); + /* If there's no more pattern then we win. */ + if (!*p) return (1); + + /* Try skipping any number of characters from the pattern looking for + * a match. + */ + do { + if (match(p, s)) return (1); s++; - } + } while (*s); return (0); + case '[': - if (!*s) - return (0); + /* Character sets. This is the hard part. */ + + /* If there is no character left, then we fail. */ + if (!*s) return (0); + + /* Fetch the string character, and start munching through the + * pattern. + */ sch = *s++; - pch = *p++; - sense = 1; - if (pch == '^' || pch == '!') { - sense = !sense; - pch = *p++; - } + pch = *p++; sense = 1; + + /* Maybe we need to negate. */ + if (pch == '^' || pch == '!') { sense = !sense; pch = *p++; } + + /* A close bracket here is literal. Watch for ranges. */ if (pch == ']') { if (*p == '-' && p[1] && p[1] != ']') { - pche = p[1]; - p += 2; - if (pch <= sch && sch <= pche) - goto class_match; - } else if (pch == sch) - goto class_match; + pche = p[1]; p += 2; + if (pch <= sch && sch <= pche) goto class_match; + } else if (pch == sch) goto class_match; pch = *p++; } + + /* Work through the other characters and ranges in the set. */ for (;; pch = *p++) { - if (!pch || pch == ']') - goto class_nomatch; + if (!pch || pch == ']') goto class_nomatch; if (*p == '-' && p[1] && p[1] != ']') { - pche = p[1]; - p += 2; - if (pch <= sch && sch <= pche) - goto class_match; - } else if (pch == sch) - goto class_match; + pche = p[1]; p += 2; + if (pch <= sch && sch <= pche) goto class_match; + } else if (pch == sch) goto class_match; } + class_match: - if (!sense) - return (0); + /* Found a match. Chew through the rest of the pattern. */ + if (!sense) return (0); for (;;) { - pch = *p++; - if (!pch) - return (0); - if (pch == ']') - break; - if (*p == '-' && p[1] && p[1] != ']') - p += 2; + pch = *p++; if (!pch) return (0); + if (pch == ']') break; + if (*p == '-' && p[1] && p[1] != ']') p += 2; } break; + class_nomatch: - if (sense) - return (0); + /* Found the end of the set, so it's a mismatch. */ + if (sense) return (0); break; + case '\\': + /* Treat the next thing literally. */ pch = *p++; + /* fall through... */ + default: - if (pch != *s) - return (0); - if (!pch) - return (1); - s++; + /* A plain character match. + * + * Trick: If this is the end of the pattern, we expect the end of + * the string. + */ + + if (pch != *s++) return (0); + if (!pch) return (1); break; } }