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 #if defined STDC_HEADERS || !defined isascii
28 # define ISASCII(c) isascii(c)
32 # define ISBLANK(c) (ISASCII(c) && isblank(c))
34 # define ISBLANK(c) ((c) == ' ' || (c) == '\t')
38 # define ISGRAPH(c) (ISASCII(c) && isgraph(c))
40 # define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
43 #define ISPRINT(c) (ISASCII(c) && isprint(c))
44 #define ISDIGIT(c) (ISASCII(c) && isdigit(c))
45 #define ISALNUM(c) (ISASCII(c) && isalnum(c))
46 #define ISALPHA(c) (ISASCII(c) && isalpha(c))
47 #define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
48 #define ISLOWER(c) (ISASCII(c) && islower(c))
49 #define ISPUNCT(c) (ISASCII(c) && ispunct(c))
50 #define ISSPACE(c) (ISASCII(c) && isspace(c))
51 #define ISUPPER(c) (ISASCII(c) && isupper(c))
52 #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
54 #ifdef WILD_TEST_ITERATIONS
55 int wildmatch_iteration_count;
58 static int domatch(const unsigned char *p, const unsigned char *text)
61 unsigned char ch, prev;
63 #ifdef WILD_TEST_ITERATIONS
64 wildmatch_iteration_count++;
67 for ( ; (ch = *p) != '\0'; text++, p++) {
68 if (*text == '\0' && ch != '*')
72 /* Literal match with following character. Note that the test
73 * in "default" handles the p[1] == '\0' failure case. */
81 /* Match anything but '/'. */
87 while (*++p == '*') {}
93 /* Trailing "**" matches everything. Trailing "*" matches
94 * only if there are no more slash characters. */
95 return special? TRUE : strchr(text, '/') == NULL;
97 for ( ; *text; text++) {
98 if ((matched = domatch(p, text)) != FALSE) {
99 if (!special || matched != ABORT_TO_STARSTAR)
102 else if (!special && *text == '/')
103 return ABORT_TO_STARSTAR;
109 if (ch == NEGATE_CLASS2)
112 /* Assign literal TRUE/FALSE because of "matched" comparison. */
113 special = ch == NEGATE_CLASS? TRUE : FALSE;
115 /* Inverted character class. */
130 else if (ch == '-' && prev && p[1] && p[1] != ']') {
137 if (*text <= ch && *text >= prev)
139 ch = 0; /* This makes "prev" get set to 0. */
141 else if (ch == '[' && p[1] == ':') {
142 unsigned const char *s = p += 2;
144 while ((ch = *p) && (ch != ':' || p[1] != ']')) p++;
149 if ((CC_EQ(s,i, "alnum") && ISALNUM(ch))
150 || (CC_EQ(s,i, "alpha") && ISALPHA(ch))
151 || (CC_EQ(s,i, "blank") && ISBLANK(ch))
152 || (CC_EQ(s,i, "cntrl") && ISCNTRL(ch))
153 || (CC_EQ(s,i, "digit") && ISDIGIT(ch))
154 || (CC_EQ(s,i, "graph") && ISGRAPH(ch))
155 || (CC_EQ(s,i, "lower") && ISLOWER(ch))
156 || (CC_EQ(s,i, "print") && ISPRINT(ch))
157 || (CC_EQ(s,i, "punct") && ISPUNCT(ch))
158 || (CC_EQ(s,i, "space") && ISSPACE(ch))
159 || (CC_EQ(s,i, "upper") && ISUPPER(ch))
160 || (CC_EQ(s,i,"xdigit") && ISXDIGIT(ch)))
163 ch = 0; /* This makes "prev" get set to 0. */
165 else if (*text == ch)
167 } while (prev = ch, (ch = *++p) != ']');
168 if (matched == special)
174 return *text == '\0';
177 /* Find the pattern (p) in the text string (t). */
178 int wildmatch(const char *p, const char *t)
180 #ifdef WILD_TEST_ITERATIONS
181 wildmatch_iteration_count = 0;
183 return domatch((const unsigned char*)p, (const unsigned char*)t) == TRUE;