1 diff -r 19854df2b7c2 ircd/match.c
2 --- a/ircd/match.c Mon Jan 26 18:42:26 2009 +0000
3 +++ b/ircd/match.c Mon Jan 26 18:48:52 2009 +0000
5 #include "ircd_string.h"
6 #include "ircd_snprintf.h"
8 +#define likely(x) __builtin_expect((x),1)
9 +#define unlikely(x) __builtin_expect((x),0)
16 * @param[in] old_mask One wildcard mask.
17 * @param[in] new_mask Another wildcard mask.
18 + * @param[in] case_sensitive Indicate case sensitivity
19 * @return Zero if \a old_mask is a superset of \a new_mask, non-zero otherwise.
21 -int mmatch(const char *old_mask, const char *new_mask)
22 +__inline__ int _mmatch(const char *old_mask, const char *new_mask, int rfcmatch)
24 const char *m = old_mask;
25 const char *n = new_mask;
30 + /* Note that ma / na never point to a character escaped by a backslash. */
31 + const char *ma = NULL; /* Remembered m for backtracking. */
32 + const char *na = NULL;
33 + int mq = 0, nq = 0; /* Is *m / *n escaped? */
36 + if ( m[0] == '*' && m[1] == '\0' ) {
38 + } else if ( n[0] == '*' && n[1] == '\0' ) {
45 + if (unlikely(*m == '*'))
47 + /* Optimization: Skip redundant *'s */
51 + /* And remember this position for backtracking. */
61 + /* This construct speeds up matches of patterns ending with a *
62 + * followed by any number of ?. The tricky part is figuring
63 + * out whether or not that * was escaped. */
64 for (m--; (m > old_mask) && (*m == '?'); m--)
66 - if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
69 + ; /* Skip trailing ?'s */
71 + if ((--m >= old_mask) && (*m != '\\'))
73 + /* Now if there's an odd number of backslashes, the for loop
74 + * breaks out and we backtrack. */
75 + if (!rfcmatch) /* In rfc, backslashes can't be escaped. */
76 + for(--m; (m >= old_mask) && (*m == '\\'); m--)
77 + if ((--m >= old_mask) && (*m != '\\'))
84 - /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
85 - if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
86 + /* skip one escaped character */
87 + if (*na == '\\' && (!rfcmatch || na[1] == '*' || na[1] == '?'))
97 + while (unlikely(*m == '*'))
101 - if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
103 + if (unlikely(*m == '\\' && (!rfcmatch || m[1] == '*' || m[1] == '?')))
111 - /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
112 - if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
113 + if (unlikely(*n == '\\' && (!rfcmatch || n[1] == '*' || n[1] == '?')))
117 @@ -126,45 +148,47 @@
121 - * This `if' has been changed compared to match() to do the following:
123 - * old (m) new (n) boolean expression
124 - * * any (*m == '*' && !mq) ||
125 - * ? any except '*' (*m == '?' && !mq && (*n != '*' || nq)) ||
126 - * any except * or ? same as m (!((*m == '*' || *m == '?') && !mq) &&
127 - * ToLower(*m) == ToLower(*n) &&
128 - * !((mq && !nq) || (!mq && nq)))
130 - * Here `any' also includes \* and \? !
132 - * After reworking the boolean expressions, we get:
133 - * (Optimized to use boolean short-circuits, with most frequently occurring
134 - * cases upfront (which took 2 hours!)).
135 + * There was fancy short-circuit logic here. It got killed. Fuck 2 hours.
136 + * It was probably slower than the branches here now. Nobody will notice
137 + * in any case. -- BP
139 - if ((*m == '*' && !mq) ||
140 - ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
141 - (*m == '?' && !mq && (*n != '*' || nq)))
142 + if (unlikely(mq)) { /* m is quoted, match the exact same, or the
143 + * same character if quoting is irrelevant. */
144 + match = (*m == *n && (nq ||
145 + (*n != '*' && *n != '?' && ToUpper(*n) == ToLower(*n))));
146 + } else if (unlikely(*m == '?')) { /* m is '?', match anything but unquoted '*' */
147 + match = (*n != '*' || nq);
148 + } else if (unlikely(*m == '*')) { /* m is '*', match. */
150 + } else /* m is neither quoted nor special */
152 + match = (ToLower(*m) == ToLower(*n));
155 + if (unlikely(match))
170 - /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
171 - if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
172 + /* skip one escaped character */
173 + if (unlikely(*na == '\\' && (!rfcmatch || na[1] == '*' || na[1] == '?')))
181 +int mmatch(const char *old_mask, const char *new_mask) {
182 + return _mmatch(old_mask, new_mask, 1);
186 * Compare if a given string (name) matches the given
187 * mask (which can contain wild cards: '*' - match any
189 * @param[in] name String to check against \a mask.
190 * @return Zero if \a mask matches \a name, non-zero if no match.
192 -int match(const char *mask, const char *name)
193 +__inline__ int _match(const char *mask, const char *name, int rfcmatch)
195 const char *m = mask, *n = name;
196 const char *m_tmp = mask, *n_tmp = name;
197 @@ -205,10 +229,14 @@
202 /* allow escaping to force capitalization */
214 for (star_p = 0; ; m++) {
217 /* and fall through */
222 if (ToLower(*m) != ToLower(*n))
227 +int match(const char *mask, const char *name)
229 + return _match(mask, name, 1);
234 * Collapse a pattern string into minimal components.