2 ** Do shell-style pattern matching for ?, \, [], and * characters.
5 ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
6 ** Rich $alz is now <rsalz@bbn.com>.
8 ** Modified by Wayne Davison to special-case '/' matching, to make '**'
9 ** work differently than '*', and to fix the character-class code.
14 /* What character marks an inverted character class? */
15 #define NEGATE_CLASS '!'
16 #define NEGATE_CLASS2 '^'
21 #define ABORT_TO_STARSTAR -2
23 #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 && strncmp(class, litmatch, len) == 0)
25 #ifdef WILD_TEST_ITERATIONS
26 int wildmatch_iteration_count;
29 static int domatch(const unsigned char *p, const unsigned char *text)
32 unsigned char ch, prev;
34 #ifdef WILD_TEST_ITERATIONS
35 wildmatch_iteration_count++;
38 for ( ; (ch = *p) != '\0'; text++, p++) {
39 if (*text == '\0' && ch != '*')
43 /* Literal match with following character. Note that the test
44 * in "default" handles the p[1] == '\0' failure case. */
52 /* Match anything but '/'. */
58 while (*++p == '*') {}
64 /* Trailing "**" matches everything. Trailing "*" matches
65 * only if there are no more slash characters. */
66 return special? TRUE : strchr(text, '/') == NULL;
68 for ( ; *text; text++) {
69 if ((matched = domatch(p, text)) != FALSE) {
70 if (!special || matched != ABORT_TO_STARSTAR)
73 else if (!special && *text == '/')
74 return ABORT_TO_STARSTAR;
80 if (ch == NEGATE_CLASS2)
83 /* Assign literal TRUE/FALSE because of "matched" comparison. */
84 special = ch == NEGATE_CLASS? TRUE : FALSE;
86 /* Inverted character class. */
101 else if (ch == '-' && prev && p[1] && p[1] != ']') {
108 if (*text <= ch && *text >= prev)
110 ch = 0; /* This makes "prev" get set to 0. */
112 else if (ch == '[' && p[1] == ':') {
113 unsigned const char *s = p += 2;
115 while ((ch = *p) && (ch != ':' || p[1] != ']')) p++;
120 if ((CC_EQ(s,i, "alnum") && isalnum(ch))
121 || (CC_EQ(s,i, "alpha") && isalpha(ch))
122 || (CC_EQ(s,i, "blank") && isblank(ch))
123 || (CC_EQ(s,i, "cntrl") && iscntrl(ch))
124 || (CC_EQ(s,i, "digit") && isdigit(ch))
125 || (CC_EQ(s,i, "graph") && isgraph(ch))
126 || (CC_EQ(s,i, "lower") && islower(ch))
127 || (CC_EQ(s,i, "print") && isprint(ch))
128 || (CC_EQ(s,i, "punct") && ispunct(ch))
129 || (CC_EQ(s,i, "space") && isspace(ch))
130 || (CC_EQ(s,i, "upper") && isupper(ch))
131 || (CC_EQ(s,i,"xdigit") && isxdigit(ch)))
134 ch = 0; /* This makes "prev" get set to 0. */
136 else if (*text == ch)
138 } while (prev = ch, (ch = *++p) != ']');
139 if (matched == special)
145 return *text == '\0';
148 /* Find the pattern (p) in the text string (t). */
149 int wildmatch(const char *p, const char *t)
151 #ifdef WILD_TEST_ITERATIONS
152 wildmatch_iteration_count = 0;
154 return domatch((const unsigned char*)p, (const unsigned char*)t) == TRUE;