]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - match.patch
whonoidle: hide idle time of users with mode +I in non-HIS setup in WHO
[irc/quakenet/snircd-patchqueue.git] / match.patch
CommitLineData
c2ba8a45
P
1diff -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
c7b68605
P
4@@ -27,6 +27,9 @@
5 #include "ircd_string.h"
6 #include "ircd_snprintf.h"
7
8+#define likely(x) __builtin_expect((x),1)
9+#define unlikely(x) __builtin_expect((x),0)
10+
11 /*
12 * mmatch()
13 *
aaeaaa08 14@@ -62,53 +65,73 @@
c7b68605
P
15 *
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.
20 */
21-int mmatch(const char *old_mask, const char *new_mask)
c7b68605
P
22+__inline__ int _mmatch(const char *old_mask, const char *new_mask, int rfcmatch)
23 {
24 const char *m = old_mask;
25 const char *n = new_mask;
26- const char *ma = m;
27- const char *na = n;
28- int wild = 0;
29- int mq = 0, nq = 0;
30+ /* Note that ma / na never point to a character escaped by a backslash. */
aaeaaa08 31+ const char *ma = NULL; /* Remembered m for backtracking. */
c7b68605 32+ const char *na = NULL;
c2ba8a45 33+ int mq = 0, nq = 0; /* Is *m / *n escaped? */
c7b68605
P
34+ int match;
35+
36+ if ( m[0] == '*' && m[1] == '\0' ) {
37+ return 0;
38+ } else if ( n[0] == '*' && n[1] == '\0' ) {
39+ return 1;
40+ }
41
42 while (1)
43 {
44- if (*m == '*')
45+ if (unlikely(*m == '*'))
46 {
47+ /* Optimization: Skip redundant *'s */
48 while (*m == '*')
49 m++;
50- wild = 1;
51+ /* And remember this position for backtracking. */
52 ma = m;
53 na = n;
54 }
55
56- if (!*m)
57+ if (unlikely(!*m))
58 {
59 if (!*n)
60 return 0;
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--)
65- ;
66- if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
67- return 0;
68- if (!wild)
69+ ; /* Skip trailing ?'s */
70+ if (*m == '*') {
71+ if ((--m >= old_mask) && (*m != '\\'))
72+ return 0;
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 != '\\'))
78+ return 0;
79+ }
80+ if (!ma)
81 return 1;
82 m = ma;
83-
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] == '?'))
88 ++na;
89-
90 n = ++na;
91 }
92- else if (!*n)
93+
94+ if (unlikely(!*n))
95 {
96- while (*m == '*')
97+ while (unlikely(*m == '*'))
98 m++;
99 return (*m != 0);
100 }
101- if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
102+
103+ if (unlikely(*m == '\\' && (!rfcmatch || m[1] == '*' || m[1] == '?')))
104 {
105 m++;
106 mq = 1;
aaeaaa08 107@@ -116,8 +139,7 @@
c7b68605
P
108 else
109 mq = 0;
110
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] == '?')))
114 {
115 n++;
116 nq = 1;
aaeaaa08 117@@ -126,45 +148,47 @@
c7b68605
P
118 nq = 0;
119
120 /*
121- * This `if' has been changed compared to match() to do the following:
122- * Match when:
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)))
129- *
130- * Here `any' also includes \* and \? !
131- *
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
138 */
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
aaeaaa08 143+ * same character if quoting is irrelevant. */
c7b68605
P
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. */
149+ match=1;
150+ } else /* m is neither quoted nor special */
151+ {
152+ match = (ToLower(*m) == ToLower(*n));
153+ }
154+
155+ if (unlikely(match))
156 {
157 if (*m)
158 m++;
aaeaaa08 159 if (*n)
c7b68605
P
160 n++;
161 }
aaeaaa08
P
162- else
163+ else
164 {
c7b68605
P
165- if (!wild)
166+ if (unlikely(!ma))
167 return 1;
168 m = ma;
169-
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] == '?')))
174 ++na;
175-
176 n = ++na;
177 }
178 }
aaeaaa08
P
179 }
180
181+int mmatch(const char *old_mask, const char *new_mask) {
182+ return _mmatch(old_mask, new_mask, 1);
183+}
184+
185 /*
186 * Compare if a given string (name) matches the given
187 * mask (which can contain wild cards: '*' - match any
188@@ -186,7 +210,7 @@
c7b68605
P
189 * @param[in] name String to check against \a mask.
190 * @return Zero if \a mask matches \a name, non-zero if no match.
191 */
aaeaaa08
P
192-int match(const char *mask, const char *name)
193+__inline__ int _match(const char *mask, const char *name, int rfcmatch)
c7b68605 194 {
c7b68605
P
195 const char *m = mask, *n = name;
196 const char *m_tmp = mask, *n_tmp = name;
aaeaaa08 197@@ -205,10 +229,14 @@
c7b68605
P
198 return 1;
199 break;
200 case '\\':
201- m++;
202 /* allow escaping to force capitalization */
203- if (*m++ != *n++)
204- goto backtrack;
205+ if (!rfcmatch) {
206+ m++;
207+ if (*m++ != *n++)
208+ goto backtrack;
209+ } else {
210+ goto fallthrough;
211+ }
212 break;
213 case '*': case '?':
214 for (star_p = 0; ; m++) {
aaeaaa08 215@@ -234,6 +262,7 @@
c7b68605
P
216 }
217 /* and fall through */
218 default:
219+ fallthrough:
220 if (!*n)
221 return *m != '\0';
222 if (ToLower(*m) != ToLower(*n))
aaeaaa08
P
223@@ -244,6 +273,11 @@
224 }
225 }
226
227+int match(const char *mask, const char *name)
228+{
229+ return _match(mask, name, 1);
230+}
231+
232 /*
233 * collapse()
234 * Collapse a pattern string into minimal components.