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;
}
}