ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/match.C
Revision: 1.6
Committed: Sat Sep 22 14:27:30 2007 UTC (16 years, 7 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -407 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# Content
1 /*
2 * match.C: Casemapping and matching functions.
3 *
4 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5 * Rights to this code are as documented in COPYING.
6 *
7 *
8 * Portions of this file were derived from sources bearing the following license:
9 * Rights to this code are documented in doc/pod/license.pod.
10 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 */
12
13 static char const rcsid[] = "$Id: match.C,v 1.5 2007-09-16 18:54:45 pippijn Exp $";
14
15 #include "atheme.h"
16
17 #define BadPtr(x) (!(x) || (*(x) == '\0'))
18
19 #define MAX_ITERATIONS 512
20 /*
21 ** Compare if a given string (name) matches the given
22 ** mask (which can contain wild cards: '*' - match any
23 ** number of chars, '?' - match any single character.
24 **
25 ** return 0, if match
26 ** 1, if no match
27 */
28
29 /*
30 ** match()
31 ** Iterative matching function, rather than recursive.
32 ** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
33 */
34
35 int
36 match (char const * const mask, char const * const name)
37 {
38 const u_char *m = (const u_char *) mask, *n = (const u_char *) name;
39 char const *ma = mask, *na = name;
40 int wild = 0, q = 0, calls = 0;
41
42 if (!mask || !name)
43 return 1;
44
45 /* if the mask is "*", it matches everything */
46 if ((*m == '*') && (*(m + 1) == '\0'))
47 return 0;
48
49 while (1)
50 {
51 #ifdef MAX_ITERATIONS
52 if (calls++ > MAX_ITERATIONS)
53 break;
54 #endif
55
56 if (*m == '*')
57 {
58 while (*m == '*')
59 m++;
60 wild = 1;
61 ma = reinterpret_cast<char const *> (m);
62 na = reinterpret_cast<char const *> (n);
63 }
64
65 if (!*m)
66 {
67 if (!*n)
68 return 0;
69 for (m--; (m > (const u_char *) mask) && (*m == '?' || *m == '&' || *m == '#'); m--)
70 ;
71 if ((m > (const u_char *) mask) && (*m == '*') && (m[-1] != '\\'))
72 return 0;
73 if (!wild)
74 return 1;
75 m = (const u_char *) ma;
76 n = (const u_char *) ++na;
77 }
78 else if (!*n)
79 return 1;
80 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?') || (m[1] == '&') || (m[1] == '#') || (m[1] == '%')))
81 {
82 m++;
83 q = 1;
84 }
85 else
86 q = 0;
87
88 if ((ToLower (*m) != ToLower (*n)) && (((*m != '?') && !(*m == '&' && IsAlpha (*n)) && !(*m == '#' && IsDigit (*n)) && !(*m == '%' && IsNon (*n))) || q))
89 {
90 if (!wild)
91 return 1;
92 m = (const u_char *) ma;
93 n = (const u_char *) ++na;
94 }
95 else
96 {
97 if (*m)
98 m++;
99 if (*n)
100 n++;
101 }
102 }
103
104 return 1;
105 }
106
107
108 /*
109 ** collapse a pattern string into minimal components.
110 ** This particular version is "in place", so that it changes the pattern
111 ** which is to be reduced to a "minimal" size.
112 */
113 char *
114 collapse (char *pattern)
115 {
116 char *s = pattern, *s1, *t;
117
118 if (BadPtr (pattern))
119 return pattern;
120 /*
121 * Collapse all \** into \*, \*[?]+\** into \*[?]+
122 */
123 for (; *s; s++)
124 if (*s == '\\')
125 if (!*(s + 1))
126 break;
127 else
128 s++;
129 else if (*s == '*')
130 {
131 if (*(t = s1 = s + 1) == '*')
132 while (*t == '*')
133 t++;
134 else if (*t == '?')
135 for (t++, s1++; *t == '*' || *t == '?'; t++)
136 if (*t == '?')
137 *s1++ = *t;
138 while ((*s1++ = *t++))
139 ;
140 }
141 return pattern;
142 }
143
144 /*
145 * regex_compile()
146 * Compile a regex of `pattern' and return it.
147 */
148 regex_t *
149 regex_create (char *pattern, int flags)
150 {
151 static char errmsg[BUFSIZE];
152 int errnum;
153 regex_t *preg;
154
155 if (pattern == NULL)
156 {
157 return NULL;
158 }
159
160 preg = new regex_t;
161 errnum = regcomp (preg, pattern, (flags & AREGEX_ICASE ? REG_ICASE : 0) | REG_EXTENDED);
162
163 if (errnum != 0)
164 {
165 regerror (errnum, preg, errmsg, BUFSIZE);
166 slog (LG_ERROR, "regex_match(): %s\n", errmsg);
167 regfree (preg);
168 delete preg;
169 return NULL;
170 }
171
172 return preg;
173 }
174
175 char *
176 regex_extract (char *pattern, char **pend, int *pflags)
177 {
178 char c, *p, *p2;
179 bool backslash = false;
180
181 c = *pattern;
182 if (isalnum (c) || isspace (c) || c == '\\')
183 return NULL;
184 p = pattern + 1;
185 while (*p != c || backslash)
186 {
187 if (*p == '\0')
188 return NULL;
189 if (backslash || *p == '\\')
190 backslash = !backslash;
191 p++;
192 }
193 p2 = p;
194 p++;
195 *pflags = 0;
196 while (*p != '\0' && *p != ' ')
197 {
198 if (*p == 'i')
199 *pflags |= AREGEX_ICASE;
200 else if (!isalnum (*p))
201 return NULL;
202 p++;
203 }
204 *pend = p;
205 *p2 = '\0';
206 return pattern + 1;
207 }
208
209 /*
210 * regex_match()
211 * Internal wrapper API for POSIX-based regex matching.
212 * `preg' is the regex to check with, `string' needs to be checked against.
213 * Returns `true' on match, `false' else.
214 */
215 bool
216 regex_match (regex_t * preg, char *string)
217 {
218 bool retval;
219
220 if (preg == NULL || string == NULL)
221 {
222 slog (LG_ERROR, "regex_match(): we were given NULL string or pattern, bad!");
223 return false;
224 }
225
226 /* match it */
227 if (regexec (preg, string, 0, NULL, 0) == 0)
228 retval = true;
229 else
230 retval = false;
231
232 return retval;
233 }
234
235 /*
236 * regex_destroy()
237 * Perform cleanup with regex `preg', free associated memory.
238 */
239 bool
240 regex_destroy (regex_t * preg)
241 {
242 regfree (preg);
243 delete preg;
244 return true;
245 }