#define FALSE 0
#define TRUE 1
-#define NOMATCH 1
-#define MATCH 0
-#define ABORT_ALL -1
-#define ABORT_TO_STARSTAR -2
-
#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
&& *(class) == *(litmatch) \
&& strncmp((char*)class, litmatch, len) == 0)
static int dowild(const uchar *p, const uchar *text, int force_lower_case)
{
uchar p_ch;
+ const uchar *pattern = p;
for ( ; (p_ch = *p) != '\0'; text++, p++) {
- int matched, special;
+ int matched, match_slash, negated;
uchar t_ch, prev_ch;
if ((t_ch = *text) == '\0' && p_ch != '*')
return ABORT_ALL;
continue;
case '*':
if (*++p == '*') {
+ const uchar *prev_p = p - 2;
while (*++p == '*') {}
- special = TRUE;
+ if ((prev_p < pattern || *prev_p == '/') &&
+ (*p == '\0' || *p == '/' ||
+ (p[0] == '\\' && p[1] == '/'))) {
+ /*
+ * Assuming we already match 'foo/' and are at
+ * <star star slash>, just assume it matches
+ * nothing and go ahead match the rest of the
+ * pattern with the remaining string. This
+ * helps make foo/<*><*>/bar (<> because
+ * otherwise it breaks C comment syntax) match
+ * both foo/bar and foo/a/bar.
+ */
+ if (p[0] == '/' &&
+ dowild(p + 1, text, force_lower_case) == MATCH)
+ return MATCH;
+ match_slash = TRUE;
+ } else
+ return ABORT_MALFORMED;
} else
- special = FALSE;
+ match_slash = FALSE;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
- if (!special) {
+ if (!match_slash) {
if (strchr((char*)text, '/') != NULL)
return NOMATCH;
}
if (t_ch == '\0')
break;
if ((matched = dowild(p, text, force_lower_case)) != NOMATCH) {
- if (!special || matched != ABORT_TO_STARSTAR)
+ if (!match_slash || matched != ABORT_TO_STARSTAR)
return matched;
- } else if (!special && t_ch == '/')
+ } else if (!match_slash && t_ch == '/')
return ABORT_TO_STARSTAR;
t_ch = *++text;
}
p_ch = NEGATE_CLASS;
#endif
/* Assign literal TRUE/FALSE because of "matched" comparison. */
- special = p_ch == NEGATE_CLASS? TRUE : FALSE;
- if (special) {
+ negated = p_ch == NEGATE_CLASS? TRUE : FALSE;
+ if (negated) {
/* Inverted character class. */
p_ch = *++p;
}
} else if (t_ch == p_ch)
matched = TRUE;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
- if (matched == special || t_ch == '/')
+ if (matched == negated || t_ch == '/')
return NOMATCH;
continue;
}