ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/match.C
Revision: 1.1
Committed: Thu Jul 19 08:24:59 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Log Message:
initial import. the most important changes since Atheme are:
- fixed many memory leaks
- fixed many bugs
- converted to C++ and use more STL containers
- added a (not very enhanced yet) perl module
- greatly improved XML-RPC speed
- added a JSON-RPC module with code from json-cpp
- added a valgrind memcheck module to operserv
- added a more object oriented base64 implementation
- added a specialised unit test framework
- improved stability
- use gettimeofday() if available
- reworked adding/removing commands
- MemoServ IGNORE DEL can now remove indices

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * match.C: Casemapping and matching functions.
3     * Rights to this code are documented in doc/LICENSE.
4     *
5     * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6     */
7    
8     static char const rcsid[] = "$Id";
9    
10     #include "atheme.h"
11    
12     #define BadPtr(x) (!(x) || (*(x) == '\0'))
13    
14     int match_mapping = MATCH_RFC1459;
15    
16     const unsigned char ToLowerTab[] = {
17     0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
18     0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
19     0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
20     0x1e, 0x1f,
21     ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
22     '*', '+', ',', '-', '.', '/',
23     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
24     ':', ';', '<', '=', '>', '?',
25     '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
26     'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
27     't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
28     '_',
29     '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
30     'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
31     't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
32     0x7f,
33     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
34     0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
35     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
36     0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
37     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
38     0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
39     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
40     0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
41     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
42     0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
43     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
44     0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
45     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
46     0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
47     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
48     0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
49     };
50    
51     const unsigned char ToUpperTab[] = {
52     0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
53     0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
54     0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
55     0x1e, 0x1f,
56     ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
57     '*', '+', ',', '-', '.', '/',
58     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
59     ':', ';', '<', '=', '>', '?',
60     '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
61     'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
62     'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
63     0x5f,
64     '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
65     'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
66     'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
67     0x7f,
68     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
69     0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
70     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
71     0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
72     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
73     0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
74     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
75     0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
76     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
77     0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
78     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
79     0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
80     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
81     0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
82     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
83     0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
84     };
85    
86     int
87     ToLower (int c)
88     {
89     if (match_mapping == MATCH_ASCII)
90     return tolower (c);
91     /* else */
92     return (ToLowerTab[(unsigned char) (c)]);
93     }
94    
95     int
96     ToUpper (int c)
97     {
98     if (match_mapping == MATCH_ASCII)
99     return toupper (c);
100     /* else */
101     return (ToUpperTab[(unsigned char) (c)]);
102     }
103    
104     void
105     set_match_mapping (int type)
106     {
107     match_mapping = type;
108     }
109    
110     #define MAX_ITERATIONS 512
111     /*
112     ** Compare if a given string (name) matches the given
113     ** mask (which can contain wild cards: '*' - match any
114     ** number of chars, '?' - match any single character.
115     **
116     ** return 0, if match
117     ** 1, if no match
118     */
119    
120     /*
121     ** match()
122     ** Iterative matching function, rather than recursive.
123     ** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
124     */
125    
126     int
127     match (const char *mask, const char *name)
128     {
129     const u_char *m = (const u_char *) mask, *n = (const u_char *) name;
130     const char *ma = mask, *na = name;
131     int wild = 0, q = 0, calls = 0;
132    
133     if (!mask || !name)
134     return 1;
135    
136     /* if the mask is "*", it matches everything */
137     if ((*m == '*') && (*(m + 1) == '\0'))
138     return 0;
139    
140     while (1)
141     {
142     #ifdef MAX_ITERATIONS
143     if (calls++ > MAX_ITERATIONS)
144     break;
145     #endif
146    
147     if (*m == '*')
148     {
149     while (*m == '*')
150     m++;
151     wild = 1;
152     ma = (const char *) m;
153     na = (const char *) n;
154     }
155    
156     if (!*m)
157     {
158     if (!*n)
159     return 0;
160     for (m--; (m > (const u_char *) mask) && (*m == '?' || *m == '&' || *m == '#'); m--)
161     ;
162     if ((m > (const u_char *) mask) && (*m == '*') && (m[-1] != '\\'))
163     return 0;
164     if (!wild)
165     return 1;
166     m = (const u_char *) ma;
167     n = (const u_char *) ++na;
168     }
169     else if (!*n)
170     return 1;
171     if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?') || (m[1] == '&') || (m[1] == '#') || (m[1] == '%')))
172     {
173     m++;
174     q = 1;
175     }
176     else
177     q = 0;
178    
179     if ((ToLower (*m) != ToLower (*n)) && (((*m != '?') && !(*m == '&' && IsAlpha (*n)) && !(*m == '#' && IsDigit (*n)) && !(*m == '%' && IsNon (*n))) || q))
180     {
181     if (!wild)
182     return 1;
183     m = (const u_char *) ma;
184     n = (const u_char *) ++na;
185     }
186     else
187     {
188     if (*m)
189     m++;
190     if (*n)
191     n++;
192     }
193     }
194    
195     return 1;
196     }
197    
198    
199     /*
200     ** collapse a pattern string into minimal components.
201     ** This particular version is "in place", so that it changes the pattern
202     ** which is to be reduced to a "minimal" size.
203     */
204     char *
205     collapse (char *pattern)
206     {
207     char *s = pattern, *s1, *t;
208    
209     if (BadPtr (pattern))
210     return pattern;
211     /*
212     * Collapse all \** into \*, \*[?]+\** into \*[?]+
213     */
214     for (; *s; s++)
215     if (*s == '\\')
216     if (!*(s + 1))
217     break;
218     else
219     s++;
220     else if (*s == '*')
221     {
222     if (*(t = s1 = s + 1) == '*')
223     while (*t == '*')
224     t++;
225     else if (*t == '?')
226     for (t++, s1++; *t == '*' || *t == '?'; t++)
227     if (*t == '?')
228     *s1++ = *t;
229     while ((*s1++ = *t++))
230     ;
231     }
232     return pattern;
233     }
234    
235     /*
236     ** Case insensitive comparison of two null terminated strings.
237     **
238     ** returns 0, if s1 equal to s2
239     ** <0, if s1 lexicographically less than s2
240     ** >0, if s1 lexicographically greater than s2
241     */
242     int
243     irccasecmp (const char *s1, const char *s2)
244     {
245     const unsigned char *str1 = (const unsigned char *) s1;
246     const unsigned char *str2 = (const unsigned char *) s2;
247     int res;
248    
249     if (!s1 || !s2)
250     return -1;
251    
252     if (match_mapping == MATCH_ASCII)
253     return strcasecmp (s1, s2);
254    
255     while ((res = ToUpper (*str1) - ToUpper (*str2)) == 0)
256     {
257     if (*str1 == '\0')
258     return 0;
259     str1++;
260     str2++;
261     }
262     return (res);
263     }
264    
265     int
266     ircncasecmp (const char *str1, const char *str2, int n)
267     {
268     const unsigned char *s1 = (const unsigned char *) str1;
269     const unsigned char *s2 = (const unsigned char *) str2;
270     int res;
271    
272     if (match_mapping == MATCH_ASCII)
273     return strncasecmp (str1, str2, n);
274    
275     while ((res = ToUpper (*s1) - ToUpper (*s2)) == 0)
276     {
277     s1++;
278     s2++;
279     n--;
280     if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
281     return 0;
282     }
283     return (res);
284     }
285    
286     const unsigned int charattrs[] = {
287     /* 0 */ 0,
288     /* 1 */ 0,
289     /* 2 */ 0,
290     /* 3 */ 0,
291     /* 4 */ 0,
292     /* 5 */ 0,
293     /* 6 */ 0,
294     /* 7 BEL */ 0,
295     /* 8 \b */ 0,
296     /* 9 \t */ 0,
297     /* 10 \n */ 0,
298     /* 11 \v */ 0,
299     /* 12 \f */ 0,
300     /* 13 \r */ 0,
301     /* 14 */ 0,
302     /* 15 */ 0,
303     /* 16 */ 0,
304     /* 17 */ 0,
305     /* 18 */ 0,
306     /* 19 */ 0,
307     /* 20 */ 0,
308     /* 21 */ 0,
309     /* 22 */ 0,
310     /* 23 */ 0,
311     /* 24 */ 0,
312     /* 25 */ 0,
313     /* 26 */ 0,
314     /* 27 */ 0,
315     /* 28 */ 0,
316     /* 29 */ 0,
317     /* 30 */ 0,
318     /* 31 */ 0,
319     /* SP */ 0,
320     /* ! */ 0,
321     /* " */ 0,
322     /* # */ 0,
323     /* $ */ 0,
324     /* % */ 0,
325     /* & */ 0,
326     /* ' */ 0,
327     /* ( */ 0,
328     /* ) */ 0,
329     /* * */ 0,
330     /* + */ 0,
331     /* , */ 0,
332     /* - */ 0,
333     /* . */ 0,
334     /* / */ 0,
335     /* 0 */ C_DIGIT,
336     /* 1 */ C_DIGIT,
337     /* 2 */ C_DIGIT,
338     /* 3 */ C_DIGIT,
339     /* 4 */ C_DIGIT,
340     /* 5 */ C_DIGIT,
341     /* 6 */ C_DIGIT,
342     /* 7 */ C_DIGIT,
343     /* 8 */ C_DIGIT,
344     /* 9 */ C_DIGIT,
345     /* : */ 0,
346     /* ; */ 0,
347     /* < */ 0,
348     /* = */ 0,
349     /* > */ 0,
350     /* ? */ 0,
351     /* @ */ 0,
352     /* A */ C_ALPHA,
353     /* B */ C_ALPHA,
354     /* C */ C_ALPHA,
355     /* D */ C_ALPHA,
356     /* E */ C_ALPHA,
357     /* F */ C_ALPHA,
358     /* G */ C_ALPHA,
359     /* H */ C_ALPHA,
360     /* I */ C_ALPHA,
361     /* J */ C_ALPHA,
362     /* K */ C_ALPHA,
363     /* L */ C_ALPHA,
364     /* M */ C_ALPHA,
365     /* N */ C_ALPHA,
366     /* O */ C_ALPHA,
367     /* P */ C_ALPHA,
368     /* Q */ C_ALPHA,
369     /* R */ C_ALPHA,
370     /* S */ C_ALPHA,
371     /* T */ C_ALPHA,
372     /* U */ C_ALPHA,
373     /* V */ C_ALPHA,
374     /* W */ C_ALPHA,
375     /* X */ C_ALPHA,
376     /* Y */ C_ALPHA,
377     /* Z */ C_ALPHA,
378     /* [ */ 0,
379     /* \ */ 0,
380     /* ] */ 0,
381     /* ^ */ 0,
382     /* _ */ 0,
383     /* ` */ 0,
384     /* a */ C_ALPHA,
385     /* b */ C_ALPHA,
386     /* c */ C_ALPHA,
387     /* d */ C_ALPHA,
388     /* e */ C_ALPHA,
389     /* f */ C_ALPHA,
390     /* g */ C_ALPHA,
391     /* h */ C_ALPHA,
392     /* i */ C_ALPHA,
393     /* j */ C_ALPHA,
394     /* k */ C_ALPHA,
395     /* l */ C_ALPHA,
396     /* m */ C_ALPHA,
397     /* n */ C_ALPHA,
398     /* o */ C_ALPHA,
399     /* p */ C_ALPHA,
400     /* q */ C_ALPHA,
401     /* r */ C_ALPHA,
402     /* s */ C_ALPHA,
403     /* t */ C_ALPHA,
404     /* u */ C_ALPHA,
405     /* v */ C_ALPHA,
406     /* w */ C_ALPHA,
407     /* x */ C_ALPHA,
408     /* y */ C_ALPHA,
409     /* z */ C_ALPHA,
410     /* { */ 0,
411     /* | */ 0,
412     /* } */ 0,
413     /* ~ */ 0,
414     /* del */ 0,
415     /* 0x80 */ 0,
416     /* 0x81 */ 0,
417     /* 0x82 */ 0,
418     /* 0x83 */ 0,
419     /* 0x84 */ 0,
420     /* 0x85 */ 0,
421     /* 0x86 */ 0,
422     /* 0x87 */ 0,
423     /* 0x88 */ 0,
424     /* 0x89 */ 0,
425     /* 0x8A */ 0,
426     /* 0x8B */ 0,
427     /* 0x8C */ 0,
428     /* 0x8D */ 0,
429     /* 0x8E */ 0,
430     /* 0x8F */ 0,
431     /* 0x90 */ 0,
432     /* 0x91 */ 0,
433     /* 0x92 */ 0,
434     /* 0x93 */ 0,
435     /* 0x94 */ 0,
436     /* 0x95 */ 0,
437     /* 0x96 */ 0,
438     /* 0x97 */ 0,
439     /* 0x98 */ 0,
440     /* 0x99 */ 0,
441     /* 0x9A */ 0,
442     /* 0x9B */ 0,
443     /* 0x9C */ 0,
444     /* 0x9D */ 0,
445     /* 0x9E */ 0,
446     /* 0x9F */ 0,
447     /* 0xA0 */ 0,
448     /* 0xA1 */ 0,
449     /* 0xA2 */ 0,
450     /* 0xA3 */ 0,
451     /* 0xA4 */ 0,
452     /* 0xA5 */ 0,
453     /* 0xA6 */ 0,
454     /* 0xA7 */ 0,
455     /* 0xA8 */ 0,
456     /* 0xA9 */ 0,
457     /* 0xAA */ 0,
458     /* 0xAB */ 0,
459     /* 0xAC */ 0,
460     /* 0xAD */ 0,
461     /* 0xAE */ 0,
462     /* 0xAF */ 0,
463     /* 0xB0 */ 0,
464     /* 0xB1 */ 0,
465     /* 0xB2 */ 0,
466     /* 0xB3 */ 0,
467     /* 0xB4 */ 0,
468     /* 0xB5 */ 0,
469     /* 0xB6 */ 0,
470     /* 0xB7 */ 0,
471     /* 0xB8 */ 0,
472     /* 0xB9 */ 0,
473     /* 0xBA */ 0,
474     /* 0xBB */ 0,
475     /* 0xBC */ 0,
476     /* 0xBD */ 0,
477     /* 0xBE */ 0,
478     /* 0xBF */ 0,
479     /* 0xC0 */ 0,
480     /* 0xC1 */ 0,
481     /* 0xC2 */ 0,
482     /* 0xC3 */ 0,
483     /* 0xC4 */ 0,
484     /* 0xC5 */ 0,
485     /* 0xC6 */ 0,
486     /* 0xC7 */ 0,
487     /* 0xC8 */ 0,
488     /* 0xC9 */ 0,
489     /* 0xCA */ 0,
490     /* 0xCB */ 0,
491     /* 0xCC */ 0,
492     /* 0xCD */ 0,
493     /* 0xCE */ 0,
494     /* 0xCF */ 0,
495     /* 0xD0 */ 0,
496     /* 0xD1 */ 0,
497     /* 0xD2 */ 0,
498     /* 0xD3 */ 0,
499     /* 0xD4 */ 0,
500     /* 0xD5 */ 0,
501     /* 0xD6 */ 0,
502     /* 0xD7 */ 0,
503     /* 0xD8 */ 0,
504     /* 0xD9 */ 0,
505     /* 0xDA */ 0,
506     /* 0xDB */ 0,
507     /* 0xDC */ 0,
508     /* 0xDD */ 0,
509     /* 0xDE */ 0,
510     /* 0xDF */ 0,
511     /* 0xE0 */ 0,
512     /* 0xE1 */ 0,
513     /* 0xE2 */ 0,
514     /* 0xE3 */ 0,
515     /* 0xE4 */ 0,
516     /* 0xE5 */ 0,
517     /* 0xE6 */ 0,
518     /* 0xE7 */ 0,
519     /* 0xE8 */ 0,
520     /* 0xE9 */ 0,
521     /* 0xEA */ 0,
522     /* 0xEB */ 0,
523     /* 0xEC */ 0,
524     /* 0xED */ 0,
525     /* 0xEE */ 0,
526     /* 0xEF */ 0,
527     /* 0xF0 */ 0,
528     /* 0xF1 */ 0,
529     /* 0xF2 */ 0,
530     /* 0xF3 */ 0,
531     /* 0xF4 */ 0,
532     /* 0xF5 */ 0,
533     /* 0xF6 */ 0,
534     /* 0xF7 */ 0,
535     /* 0xF8 */ 0,
536     /* 0xF9 */ 0,
537     /* 0xFA */ 0,
538     /* 0xFB */ 0,
539     /* 0xFC */ 0,
540     /* 0xFD */ 0,
541     /* 0xFE */ 0,
542     /* 0xFF */ 0,
543     };
544    
545     /*
546     * regex_compile()
547     * Compile a regex of `pattern' and return it.
548     */
549     regex_t *
550     regex_create (char *pattern, int flags)
551     {
552     static char errmsg[BUFSIZE];
553     int errnum;
554     regex_t *preg;
555    
556     if (pattern == NULL)
557     {
558     return NULL;
559     }
560    
561     preg = (regex_t *) malloc (sizeof (regex_t));
562     errnum = regcomp (preg, pattern, (flags & AREGEX_ICASE ? REG_ICASE : 0) | REG_EXTENDED);
563    
564     if (errnum != 0)
565     {
566     regerror (errnum, preg, errmsg, BUFSIZE);
567     slog (LG_ERROR, "regex_match(): %s\n", errmsg);
568     regfree (preg);
569     free (preg);
570     return NULL;
571     }
572    
573     return preg;
574     }
575    
576     char *
577     regex_extract (char *pattern, char **pend, int *pflags)
578     {
579     char c, *p, *p2;
580     bool backslash = false;
581    
582     c = *pattern;
583     if (isalnum (c) || isspace (c) || c == '\\')
584     return NULL;
585     p = pattern + 1;
586     while (*p != c || backslash)
587     {
588     if (*p == '\0')
589     return NULL;
590     if (backslash || *p == '\\')
591     backslash = !backslash;
592     p++;
593     }
594     p2 = p;
595     p++;
596     *pflags = 0;
597     while (*p != '\0' && *p != ' ')
598     {
599     if (*p == 'i')
600     *pflags |= AREGEX_ICASE;
601     else if (!isalnum (*p))
602     return NULL;
603     p++;
604     }
605     *pend = p;
606     *p2 = '\0';
607     return pattern + 1;
608     }
609    
610     /*
611     * regex_match()
612     * Internal wrapper API for POSIX-based regex matching.
613     * `preg' is the regex to check with, `string' needs to be checked against.
614     * Returns `true' on match, `false' else.
615     */
616     bool
617     regex_match (regex_t * preg, char *string)
618     {
619     bool retval;
620    
621     if (preg == NULL || string == NULL)
622     {
623     slog (LG_ERROR, "regex_match(): we were given NULL string or pattern, bad!");
624     return false;
625     }
626    
627     /* match it */
628     if (regexec (preg, string, 0, NULL, 0) == 0)
629     retval = true;
630     else
631     retval = false;
632    
633     return retval;
634     }
635    
636     /*
637     * regex_destroy()
638     * Perform cleanup with regex `preg', free associated memory.
639     */
640     bool
641     regex_destroy (regex_t * preg)
642     {
643     regfree (preg);
644     free (preg);
645     return true;
646     }
647    
648     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
649     * vim:ts=8
650     * vim:sw=8
651     * vim:noexpandtab
652     */