1 /*
2 * The original was spagetti. I have replaced Michael's code with some of
3 * my own which is a thousand times more readable and can also handle '%',
4 * which substitutes anything except a space. This should enable people
5 * to position things better based on argument. I have also added '?', which
6 * substitutes to any single character. And of course it still handles '*'.
7 * this should be more efficient than the previous version too.
8 *
9 * Thus this whole file becomes:
10 *
11 * Written By Troy Rollo
12 *
13 * Copyright(c) 1992
14 *
15 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
16 */
17
18 #include "irc.h"
19 #include "ircaux.h"
20 #include "output.h"
21
22 static int total_explicit;
23
24 /*
25 * The following #define is here because we *know* its behaviour.
26 * The behaviour of toupper tends to be undefined when it's given
27 * a non lower case letter.
28 * All the systems supported by IRCII should be ASCII
29 */
30 #define mkupper(c) (((c) >= 'a' && (c) <= 'z') ? ((c) - 'a' + 'A') : c)
31
32 #ifdef __STDC__
33 int
match(u_char * pattern,u_char * string)34 match(u_char *pattern, u_char *string)
35 #else
36 int
37 match(pattern, string)
38 u_char *pattern, *string;
39 #endif
40 {
41 u_char type;
42
43 #if 0
44 if ((!pattern || !string) && !x_debug)
45 {
46 yell("match: pattern or string is NULL!");
47 return 0;
48 }
49 #endif
50
51 while (*string && *pattern && *pattern != '*' && *pattern != '%')
52 {
53 if (*pattern == '\\' && *(pattern + 1))
54 {
55 if (!*++pattern || !(mkupper(*pattern) ==
56 mkupper(*string)))
57 return 0;
58 else
59 pattern++, string++, total_explicit++;
60 }
61
62 if (*pattern == '?')
63 pattern++, string++;
64 else if (mkupper(*pattern) == mkupper(*string))
65 pattern++, string++, total_explicit++;
66 else
67 break;
68 }
69 if (*pattern == '*' || *pattern == '%')
70 {
71 type = (*pattern++);
72 while (*string)
73 {
74 if (match(pattern, string))
75 return 1;
76 else if (type == '*' || *string != ' ')
77 string++;
78 else
79 break;
80 }
81 }
82 if (!*string && !*pattern)
83 return 1;
84 return 0;
85 }
86
87 /*
88 * This version of wild_match returns 1 + the count of characters
89 * explicitly matched if a match occurs. That way we can look for
90 * the best match in a list
91 */
92 /* \\[ and \\] handling done by Jeremy Nelson
93 * EPIC will not use the new pattern matcher currently used by
94 * ircii because i am not convinced that it is 1) better * and
95 * 2) i think the \\[ \\] stuff is important.
96 */
97 #ifdef __STDC__
98 int
wild_match(u_char * pattern,u_char * str)99 wild_match(u_char *pattern, u_char *str)
100 #else
101 int
102 wild_match(pattern, str)
103 u_char *pattern, *str;
104 #endif
105 {
106 u_char *ptr;
107 u_char *ptr2 = pattern;
108 int nest = 0;
109 u_char my_buff[2048];
110 u_char *arg;
111 int best_total = 0;
112
113 total_explicit = 0;
114
115 if (!str)
116 {
117 put_error("string is null calling wild_match().. caller contains a bug");
118 return 0;
119 }
120 /* Is there a \[ in the pattern to be expanded? */
121 /* This stuff here just reduces the \[ \] set into a series of
122 * one-simpler patterns and then recurses */
123 if ((ptr2 = strstr(pattern, "\\[")))
124 {
125 /* we will have to null this out, but not until weve used it */
126 u_char *placeholder = ptr2;
127 ptr = ptr2;
128
129 /* yes. whats the character after it? (first time
130 through is a trivial case) */
131 do
132 {
133 switch (ptr[1])
134 {
135 /* step over it and add to nest */
136 case '[':
137 ptr2 = ptr + 2;
138 nest++;
139 break;
140 /* step over it and remove nest */
141 case ']':
142 ptr2 = ptr + 2;
143 nest--;
144 break;
145 }
146 }
147 /* Repeat while there are more backslashes to look at and
148 * we have are still in nested \[ \] sets
149 */
150 while ((nest) && (ptr = index(ptr2, '\\')));
151
152 /* right now, we know ptr points to a \] or to null */
153 /* remember that && short circuits and that ptr will
154 not be set to null if (nest) is zero... */
155 if (ptr)
156 {
157 /* null out and step over the original \[ */
158 *placeholder = '\0';
159 placeholder += 2;
160
161 /* null out and step over the matching \] */
162 *ptr = '\0';
163 ptr += 2;
164
165 /* grab words ("" sets or space words) one at a time
166 * and attempt to match all of them. The best value
167 * matched is the one used.
168 */
169 while ((arg = new_next_arg(placeholder, &placeholder)))
170 {
171 int tmpval;
172
173 strncpy(my_buff, pattern, sizeof(my_buff)-1);
174 strmcat(my_buff, arg, sizeof(my_buff)-1);
175 strmcat(my_buff, ptr, sizeof(my_buff)-1);
176 /* the total_explicit we return is whichever
177 * pattern has the highest total_explicit */
178 if ((tmpval = wild_match(my_buff, str)))
179 {
180 if (tmpval > best_total)
181 best_total = tmpval;
182 }
183 }
184 return best_total; /* end of expansion section */
185 }
186 /* Possibly an unmatched \[ \] set */
187 else
188 {
189 total_explicit = 0;
190 if (match(pattern, str))
191 return total_explicit + 1;
192 else
193 {
194 #if 0
195 yell("Unmatched \\[ !");
196 #endif
197 return 0;
198 }
199 }
200 }
201 /* trivial case (no expansion) when weve expanded all the way out */
202 else if (match(pattern, str))
203 return total_explicit + 1;
204 else
205 return 0;
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 /*
225 * IP match().. only matches for digits and dots.
226 *
227 * - doesn't support \<char>
228 * - returns 0 if anything other than a digit or dot is found..
229 *
230 */
231 #ifdef __STDC__
232 int
ip_match(u_char * pattern,u_char * string)233 ip_match(u_char *pattern, u_char *string)
234 #else
235 int
236 ip_match(pattern, string)
237 u_char *pattern, *string;
238 #endif
239 {
240 u_char type;
241
242 #if 0
243 if ((!pattern || !string) && !x_debug)
244 {
245 yell("ip_match: pattern or string is NULL!");
246 return 0;
247 }
248 #endif
249
250 while (*string && *pattern && *pattern != '*' && *pattern != '%')
251 {
252 if (*pattern == '?')
253 pattern++, string++;
254 /* not digit or dot? */
255 else if ((!isdigit(*pattern) && *pattern != '.') || (!isdigit(*string) && *string != '.'))
256 break;
257 else if (*pattern == *string)
258 pattern++, string++;
259 else
260 break;
261 }
262 if (*pattern == '*' || *pattern == '%')
263 {
264 type = (*pattern++);
265 while (*string)
266 {
267 /* not digit or dot ? */
268 if (!isdigit(*string) && *string != '.')
269 break;
270 else if (ip_match(pattern, string))
271 return 1;
272 else if (type == '*' || *string != ' ')
273 string++;
274 else
275 break;
276 }
277 }
278 if (!*string && !*pattern)
279 return 1;
280 return 0;
281 }
282
283 /*
284 * case sensitive match()..
285 *
286 */
287 #ifdef __STDC__
288 int
cs_match(u_char * pattern,u_char * string)289 cs_match(u_char *pattern, u_char *string)
290 #else
291 int
292 cs_match(pattern, string)
293 u_char *pattern, *string;
294 #endif
295 {
296 u_char type;
297
298 #if 0
299 if ((!pattern || !string) && !x_debug)
300 {
301 yell("ip_match: pattern or string is NULL!");
302 return 0;
303 }
304 #endif
305
306 while (*string && *pattern && *pattern != '*' && *pattern != '%')
307 {
308 if (*pattern == '\\' && *(pattern + 1))
309 {
310 if (!*++pattern || !(*pattern == *string))
311 return 0;
312 else
313 pattern++, string++;
314 }
315
316 if (*pattern == '?')
317 pattern++, string++;
318 else if (*pattern == *string)
319 pattern++, string++;
320 else
321 break;
322 }
323 if (*pattern == '*' || *pattern == '%')
324 {
325 type = (*pattern++);
326 while (*string)
327 {
328 if (cs_match(pattern, string))
329 return 1;
330 else if (type == '*' || *string != ' ')
331 string++;
332 else
333 break;
334 }
335 }
336 if (!*string && !*pattern)
337 return 1;
338 return 0;
339 }
340