1 /*
2  *   Unreal Internet Relay Chat Daemon, src/match.c
3  *   Copyright (C) 1990 Jarkko Oikarinen
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 
21 #include "struct.h"
22 #include "common.h"
23 #include "sys.h"
24 
25 ID_Copyright("(C) 1990 Jarkko Oikarinen");
26 
27 /*
28  *  Compare if a given string (name) matches the given
29  *  mask (which can contain wild cards: '*' - match any
30  *  number of chars, '?' - match any single character.
31  *
32  *	return	0, if match
33  *		1, if no match
34  */
35 
36 #ifndef USE_LOCALE
37 u_char touppertab[], tolowertab[];
38 #define tolowertab2 tolowertab
39 #endif
40 
41 #ifndef USE_LOCALE
42 #define lc(x) tolowertab2[x]	/* use mylowertab, because registers are FASTER */
43 #else				/* maybe in the old 4mb hard drive days but not anymore -- codemastr */
44 #define lc(x) tolower(x)
45 #endif
46 
47 
48 /* Match routine for special cases where escaping is needed in a normal fashion.
49  * Checks a string ('name') against a globbing(+more) pattern ('mask').
50  * Original by Douglas A Lewis (dalewis@acsu.buffalo.edu).
51  * Code based on hybrid7's version (match_esc()).
52  * Various modifications by Bram Matthys (Syzop).
53  * Instead of our previous code, this one is less optimized but actually  _readable_ ;).
54  * Modifications I (Syzop) had to do vs the hybrid7 code:
55  * - Got rid of (u_char *) casts, since we already compile with
56  *   chars defaulting to unsigned [or else major things break] ;).
57  * - Use 0 for match and non-zero for no match (a la strcmp), not the reverse.
58  * - Support for '_'.
59  * - Rip out support for '#'.
60  */
match_esc(const char * mask,const char * name)61 int match_esc(const char *mask, const char *name)
62 {
63 const u_char *m = mask;
64 const u_char *n = name;
65 const u_char *ma = NULL;
66 const u_char *na = name;
67 
68 	while(1)
69 	{
70 		if (*m == '*')
71 		{
72 			while (*m == '*') /* collapse.. */
73 				m++;
74 			ma = m;
75 			na = n;
76 		}
77 
78 		if (!*m)
79 		{
80 			if (!*n)
81 				return 0;
82 			if (!ma)
83 				return 1;
84 			for (m--; (m > (const u_char *)mask) && (*m == '?'); m--);
85 			if (*m == '*')
86 				return 0;
87 			m = ma;
88 			n = ++na;
89 		} else
90 		if (!*n)
91 		{
92 			while (*m == '*') /* collapse.. */
93 				m++;
94 			return (*m != 0);
95 		}
96 
97 		if (*m != '?')
98 		{
99 			if (*m == '\\')
100 				if (!*++m)
101 					return 1; /* unfinished escape sequence */
102 			if ((lc(*m) != lc(*n)) && !((*m == '_') && (*n == ' ')))
103 			{
104 				if (!ma)
105 					return 1;
106 				m = ma;
107 				n = ++na;
108 			} else
109 			{
110 				m++;
111 				n++;
112 			}
113 		} else
114 		{
115 			m++;
116 			n++;
117 		}
118 	}
119 	return 1;
120 }
121 
122 /** Same credit/copyright as match_esc() applies, except escaping removed.. ;p */
match2(const char * mask,const char * name)123 static inline int match2(const char *mask, const char *name)
124 {
125 const u_char *m = mask;
126 const u_char *n = name;
127 const u_char *ma = NULL;
128 const u_char *na = name;
129 
130 	while(1)
131 	{
132 		if (*m == '*')
133 		{
134 			while (*m == '*') /* collapse.. */
135 				m++;
136 			ma = m;
137 			na = n;
138 		}
139 
140 		if (!*m)
141 		{
142 			if (!*n)
143 				return 0;
144 			if (!ma)
145 				return 1;
146 			for (m--; (m > (const u_char *)mask) && (*m == '?'); m--);
147 			if (*m == '*')
148 				return 0;
149 			m = ma;
150 			n = ++na;
151 		} else
152 		if (!*n)
153 		{
154 			while (*m == '*') /* collapse.. */
155 				m++;
156 			return (*m != 0);
157 		}
158 
159 		if ((lc(*m) != lc(*n)) && !((*m == '_') && (*n == ' ')) && (*m != '?'))
160 		{
161 			if (!ma)
162 				return 1;
163 			m = ma;
164 			n = ++na;
165 		} else
166 		{
167 			m++;
168 			n++;
169 		}
170 	}
171 	return 1;
172 }
173 
174 /*
175  * collapse a pattern string into minimal components.
176  * This particular version is "in place", so that it changes the pattern
177  * which is to be reduced to a "minimal" size.
178  */
collapse(char * pattern)179 char *collapse(char *pattern)
180 {
181 	char *s;
182 	char *s1;
183 	char *t;
184 
185 	s = pattern;
186 
187 	if (BadPtr(pattern))
188 		return pattern;
189 	/*
190 	 * Collapse all \** into \*, \*[?]+\** into \*[?]+
191 	 */
192 	for (; *s; s++)
193 		if (*s == '\\')
194 		{
195 			if (!*(s + 1))
196 				break;
197 			else
198 				s++;
199 		}
200 		else if (*s == '*')
201 		{
202 			if (*(t = s1 = s + 1) == '*')
203 				while (*t == '*')
204 					t++;
205 			else if (*t == '?')
206 				for (t++, s1++; *t == '*' || *t == '?'; t++)
207 					if (*t == '?')
208 						*s1++ = *t;
209 			while ((*s1++ = *t++))
210 				;
211 		}
212 	return pattern;
213 }
214 
215 
216 /*
217  *  Case insensitive comparison of two NULL terminated strings.
218  *
219  *	returns	 0, if s1 equal to s2
220  *		<0, if s1 lexicographically less than s2
221  *		>0, if s1 lexicographically greater than s2
222  */
smycmp(const char * s1,const char * s2)223 int  smycmp(const char *s1, const char *s2)
224 {
225 	u_char *str1;
226 	u_char *str2;
227 	int  res;
228 
229 	str1 = (u_char *)s1;
230 	str2 = (u_char *)s2;
231 
232 	while ((res = toupper(*str1) - toupper(*str2)) == 0)
233 	{
234 		if (*str1 == '\0')
235 			return 0;
236 		str1++;
237 		str2++;
238 	}
239 	return (res);
240 }
241 
242 
myncmp(const char * str1,const char * str2,int n)243 int  myncmp(const char *str1, const char *str2, int n)
244 {
245 	u_char *s1;
246 	u_char *s2;
247 	int  res;
248 
249 	s1 = (u_char *)str1;
250 	s2 = (u_char *)str2;
251 
252 	while ((res = toupper(*s1) - toupper(*s2)) == 0)
253 	{
254 		s1++;
255 		s2++;
256 		n--;
257 		if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
258 			return 0;
259 	}
260 	return (res);
261 }
262 
263 #ifndef USE_LOCALE
264 u_char tolowertab[] = {
265 	0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
266 	0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
267 	0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
268 	0x1e, 0x1f,
269 	' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
270 	'*', '+', ',', '-', '.', '/',
271 	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
272 	':', ';', '<', '=', '>', '?',
273 	'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
274 	'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
275 	't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^',
276 	'_',
277 	'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
278 	'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
279 	't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
280 	0x7f,
281 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
282 	0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
283 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
284 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
285 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
286 	0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
287 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
288 	0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
289 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
290 	0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
291 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
292 	0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
293 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
294 	0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
295 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
296 	0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
297 };
298 
299 u_char touppertab[] = {
300 	0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
301 	0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
302 	0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
303 	0x1e, 0x1f,
304 	' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
305 	'*', '+', ',', '-', '.', '/',
306 	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
307 	':', ';', '<', '=', '>', '?',
308 	'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
309 	'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
310 	'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
311 	0x5f,
312 	'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
313 	'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
314 	'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',
315 	0x7f,
316 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
317 	0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
318 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
319 	0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
320 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
321 	0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
322 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
323 	0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
324 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
325 	0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
326 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
327 	0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
328 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
329 	0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
330 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
331 	0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
332 };
333 
334 #endif
335 u_char char_atribs[] = {
336 /* 0-7 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
337 /* 8-12 */ CNTRL, CNTRL | SPACE, CNTRL | SPACE, CNTRL | SPACE,
338 	CNTRL | SPACE,
339 /* 13-15 */ CNTRL | SPACE, CNTRL, CNTRL,
340 /* 16-23 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
341 /* 24-31 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
342 /* space */ PRINT | SPACE,
343 /* !"#$%&'( */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
344 /* )*+,-./ */ PRINT, PRINT, PRINT, PRINT, PRINT | ALLOW, PRINT | ALLOW,
345 	PRINT,
346 /* 012 */ PRINT | DIGIT | ALLOW, PRINT | DIGIT | ALLOW,
347 	PRINT | DIGIT | ALLOW,
348 /* 345 */ PRINT | DIGIT | ALLOW, PRINT | DIGIT | ALLOW,
349 	PRINT | DIGIT | ALLOW,
350 /* 678 */ PRINT | DIGIT | ALLOW, PRINT | DIGIT | ALLOW,
351 	PRINT | DIGIT | ALLOW,
352 /* 9:; */ PRINT | DIGIT | ALLOW, PRINT, PRINT,
353 /* <=>? */ PRINT, PRINT, PRINT, PRINT,
354 /* @ */ PRINT,
355 /* ABC */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
356 	PRINT | ALPHA | ALLOW,
357 /* DEF */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
358 	PRINT | ALPHA | ALLOW,
359 /* GHI */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
360 	PRINT | ALPHA | ALLOW,
361 /* JKL */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
362 	PRINT | ALPHA | ALLOW,
363 /* MNO */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
364 	PRINT | ALPHA | ALLOW,
365 /* PQR */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
366 	PRINT | ALPHA | ALLOW,
367 /* STU */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
368 	PRINT | ALPHA | ALLOW,
369 /* VWX */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
370 	PRINT | ALPHA | ALLOW,
371 /* YZ[ */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW, PRINT,
372 /* \]^ */ PRINT, PRINT, PRINT,
373 /* _`  */ PRINT | ALLOW, PRINT,
374 /* abc */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
375 	PRINT | ALPHA | ALLOW,
376 /* def */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
377 	PRINT | ALPHA | ALLOW,
378 /* ghi */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
379 	PRINT | ALPHA | ALLOW,
380 /* jkl */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
381 	PRINT | ALPHA | ALLOW,
382 /* mno */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
383 	PRINT | ALPHA | ALLOW,
384 /* pqr */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
385 	PRINT | ALPHA | ALLOW,
386 /* stu */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
387 	PRINT | ALPHA | ALLOW,
388 /* vwx */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW,
389 	PRINT | ALPHA | ALLOW,
390 /* yz{ */ PRINT | ALPHA | ALLOW, PRINT | ALPHA | ALLOW, PRINT,
391 /* |}~ */ PRINT, PRINT, PRINT,
392 /* del */ 0,
393 /* 80-8f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394 /* 90-9f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395 /* a0-af */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 /* b0-bf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 /* c0-cf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 /* d0-df */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399 /* e0-ef */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400 /* f0-ff */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
401 };
402 
403 /* Old match() */
_match(const char * mask,const char * name)404 int _match(const char *mask, const char *name) {
405 	return match2(mask,name);
406 }
407 
408 
409 /* Old match() plus some optimizations from bahamut */
match(const char * mask,const char * name)410 int match(const char *mask, const char *name) {
411 	if (mask[0] == '*' && mask[1] == '!') {
412 		mask += 2;
413 		while (*name != '!' && *name)
414 			name++;
415 		if (!*name)
416 			return 1;
417 		name++;
418 	}
419 
420 	if (mask[0] == '*' && mask[1] == '@') {
421 		mask += 2;
422 		while (*name != '@' && *name)
423 			name++;
424 		if (!*name)
425 			return 1;
426 		name++;
427 	}
428 	return match2(mask,name);
429 }
430