IPv6 support (hopefully with fewer future transition pains)
[ircu2.10.12-pk.git] / ircd / match.c
1 /*
2  * IRC - Internet Relay Chat, common/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  * $Id$
20  */
21 #include "config.h"
22
23 #include "match.h"
24 #include "ircd_chattr.h"
25 #include "ircd_string.h"
26 #include "ircd_snprintf.h"
27 #include "support.h"
28
29 /*
30  * mmatch()
31  *
32  * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
33  *
34  *
35  * From: Carlo Wood <carlo@runaway.xs4all.nl>
36  * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
37  * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
38  * To: coder-com@mail.undernet.org (coder committee)
39  * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
40  *
41  * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
42  * which returns `true' likewise the current `match' (start with copying it),
43  * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
44  * as follows:  a '*' in `new_mask' does not match a '?' in `old_mask' and
45  * a '?' in `new_mask' does not match a '\?' in `old_mask'.
46  * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
47  * And last but not least, '\?' and '\*' in `new_mask' now become one character.
48  */
49
50 int mmatch(const char *old_mask, const char *new_mask)
51 {
52   const char *m = old_mask;
53   const char *n = new_mask;
54   const char *ma = m;
55   const char *na = n;
56   int wild = 0;
57   int mq = 0, nq = 0;
58
59   while (1)
60   {
61     if (*m == '*')
62     {
63       while (*m == '*')
64         m++;
65       wild = 1;
66       ma = m;
67       na = n;
68     }
69
70     if (!*m)
71     {
72       if (!*n)
73         return 0;
74       for (m--; (m > old_mask) && (*m == '?'); m--)
75         ;
76       if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
77         return 0;
78       if (!wild)
79         return 1;
80       m = ma;
81
82       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
83       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
84         ++na;
85
86       n = ++na;
87     }
88     else if (!*n)
89     {
90       while (*m == '*')
91         m++;
92       return (*m != 0);
93     }
94     if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
95     {
96       m++;
97       mq = 1;
98     }
99     else
100       mq = 0;
101
102     /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
103     if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
104     {
105       n++;
106       nq = 1;
107     }
108     else
109       nq = 0;
110
111 /*
112  * This `if' has been changed compared to match() to do the following:
113  * Match when:
114  *   old (m)         new (n)         boolean expression
115  *    *               any             (*m == '*' && !mq) ||
116  *    ?               any except '*'  (*m == '?' && !mq && (*n != '*' || nq)) ||
117  * any except * or ?  same as m       (!((*m == '*' || *m == '?') && !mq) &&
118  *                                      ToLower(*m) == ToLower(*n) &&
119  *                                        !((mq && !nq) || (!mq && nq)))
120  *
121  * Here `any' also includes \* and \? !
122  *
123  * After reworking the boolean expressions, we get:
124  * (Optimized to use boolean shortcircuits, with most frequently occuring
125  *  cases upfront (which took 2 hours!)).
126  */
127     if ((*m == '*' && !mq) ||
128         ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
129         (*m == '?' && !mq && (*n != '*' || nq)))
130     {
131       if (*m)
132         m++;
133       if (*n)
134         n++;
135     }
136     else
137     {
138       if (!wild)
139         return 1;
140       m = ma;
141
142       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
143       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
144         ++na;
145
146       n = ++na;
147     }
148   }
149 }
150
151 /*
152  * Compare if a given string (name) matches the given
153  * mask (which can contain wild cards: '*' - match any
154  * number of chars, '?' - match any single character.
155  *
156  * return  0, if match
157  *         1, if no match
158  *
159  *  Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
160  *  Rewritten by Timothy Vogelsang (netski), net@astrolink.org
161  */
162
163 int match(const char *mask, const char *name)
164 {
165   const char *m = mask, *n = name;
166   const char *m_tmp = mask, *n_tmp = name;
167   int wild = 0;
168
169   for (;;)
170   {
171     if (*m == '*') {
172       while (*m == '*')  /* clean up any additional wildcards */
173         m++;
174
175       m_tmp = m;
176       n_tmp = n;
177       wild = 1;
178     }
179     if (*m == '\\')  /* next wildcard is disregarded */
180       m++;
181
182     if (!*m) {
183       if (!*n)
184         return 0;  /* match */
185
186       for (m--; (m > mask) && (*m == '?'); m--);
187         ;
188
189       if (*m == '*' && (m > mask))
190         return 0;  /* match */
191
192       if (!wild)
193         return 1;
194
195       m = m_tmp;
196       n = ++n_tmp;
197     }
198     else if (!*n) {
199       while (*m == '*')  /* clean up any additional wildcards */
200         m++;
201
202       return (*m != 0);
203     }
204     if (ToLower(*m) != ToLower(*n) && *m != '?') {
205       if (!wild)
206         return 1;  /* failure! */
207
208       m = m_tmp;
209       n = ++n_tmp;
210     }
211     else {
212       if (*m)
213         m++;
214       if (*n)
215         n++;
216     }
217   }
218
219   return 1;  /* no match! */
220 }
221
222 /*
223  * collapse()
224  * Collapse a pattern string into minimal components.
225  * This particular version is "in place", so that it changes the pattern
226  * which is to be reduced to a "minimal" size.
227  *
228  * (C) Carlo Wood - 6 Oct 1998
229  * Speedup rewrite by Andrea Cocito, December 1998.
230  * Note that this new optimized alghoritm can *only* work in place.
231  */
232
233 char *collapse(char *mask)
234 {
235   int star = 0;
236   char *m = mask;
237   char *b;
238
239   if (m)
240   {
241     do
242     {
243       if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
244       {
245         b = m;
246         do
247         {
248           if (*m == '*')
249             star = 1;
250           else
251           {
252             if (star && (*m != '?'))
253             {
254               *b++ = '*';
255               star = 0;
256             };
257             *b++ = *m;
258             if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
259               *b++ = *++m;
260           };
261         }
262         while (*m++);
263         break;
264       }
265       else
266       {
267         if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
268           m++;
269       };
270     }
271     while (*m++);
272   };
273   return mask;
274 }
275
276 /*
277  ***************** Nemesi's matchcomp() / matchexec() **************
278  */
279
280 /* These functions allow the use of "compiled" masks, you compile a mask
281  * by means of matchcomp() that gets the plain text mask as input and writes
282  * its result in the memory locations addressed by the 3 parameters:
283  * - *cmask will contain the text of the compiled mask
284  * - *minlen will contain the lenght of the shortest string that can match 
285  *   the mask
286  * - *charset will contain the minimal set of chars needed to match the mask
287  * You can pass NULL as *charset and it will be simply not returned, but you
288  * MUST pass valid pointers for *minlen and *cmask (wich must be big enough 
289  * to contain the compiled mask text that is in the worst case as long as the 
290  * text of the mask itself in plaintext format) and the return value of 
291  * matchcomp() will be the number of chars actually written there (excluded 
292  * the trailing zero). cmask can be == mask, matchcomp() can work in place.
293  * The {cmask, minlen} couple of values make the real compiled mask and
294  * need to be passed to the functions that use the compiled mask, if you pass
295  * the wrong minlen or something wrong in cmask to one of these expect a
296  * coredump. This means that when you record a compiled mask you must store
297  * *both* these values.
298  * Once compiled the mask can be used to match a string by means of 
299  * matchexec(), it can be printed back to human-readable format by means
300  * of sprintmatch() or it can be compared to another compiled mask by means
301  * of mmexec() that will tell if it completely overrides that mask (a lot like
302  * what mmatch() does for plain text masks).
303  * You can gain a lot of speed in many situations avoiding to matchexec() when:
304  * - The maximum lenght of the field you are about to match() the mask to is
305  *   shorter than minlen, in example when matching abc*def*ghil with a nick:
306  *   It just cannot match since a nick is at most 9 chars long and the mask
307  *   needs at least 10 chars (10 will be the value returned in minlen).
308  * - The charset allowed for the field you are about to match to doesn't
309  *   "contain" the charset returned by matchcomp(), in example when you
310  *   have *.* as mask it makes no sense to try to match it against a nick
311  *   because, again, a nick can't contain a '.', you can check this with
312  *   a simple (charset & NTL_IRCNK) in this case.
313  * - As a special case, since compiled masks are forced to lowercase,
314  *   it would make no sense to use the NTL_LOWER and NTL_UPPER on a compiled
315  *   mask, thus they are reused as follows: if the NTL_LOWER bit of charset
316  *   is set it means that the mask contains only non-wilds chars (i.e. you can
317  *   use strCasecmp() to match it or a direct hash lookup), if the NTL_UPPER
318  *   bit is set it means that it contains only wild chars (and you can
319  *   match it with strlen(field)>=minlen).
320  * Do these optimizations ONLY when the data you are about to pass to
321  * matchexec() are *known* to be invalid in advance, using strChattr() 
322  * or strlen() on the text would be slower than calling matchexec() directly
323  * and let it fail.
324  * Internally a compiled mask contain in the *cmask area the text of
325  * the plain text form of the mask itself with applied the following hacks:
326  * - All characters are forced to lowercase (so that uppercase letters and
327  *   specifically the symbols 'A' and 'Z' are reserved for special use)
328  * - All non-escaped stars '*' are replaced by the letter 'Z'
329  * - All non-escaped question marks '?' are replaced by the letter 'A' 
330  * - All escape characters are removed, the wilds escaped by them are
331  *   then passed by without the escape since they don't collide anymore
332  *   with the real wilds (encoded as A/Z) 
333  * - Finally the part of the mask that follows the last asterisk is
334  *   reversed (byte order mirroring) and moved right after the first
335  *   asterisk.
336  * After all this a mask like:   Head*CHUNK1*chu\*nK2*ch??k3*TaIl 
337  *               .... becomes:   headZliatZchunk1Zchu*nk2ZchAAk3
338  * This can still be printed on a console, more or less understood by an
339  * human and handled with the usual str*() library functions.
340  * When you store somewhere the compiled mask you can avoid storing the
341  * textform of it since it can be "decompiled" by means of sprintmatch(),
342  * but at that time the following things are changed in the mask:
343  * - All chars have been forced to lowercase.
344  * - The mask is collapsed.
345  * The balance point of using compiled masks in terms of CPU is when you expect
346  * to use matchexec() instead of match() at least 20 times on the same mask
347  * or when you expect to use mmexec() instead of mmatch() 3 times.
348  */
349
350  /* 
351     * matchcomp()
352     *
353     * Compiles a mask into a form suitable for using in matchexec().
354   */
355
356 int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
357 {
358   const char *m = mask;
359   char *b = cmask;
360   char *fs = 0;
361   char *ls = 0;
362   char *x1, *x2;
363   int l1, l2, lmin, loop, sign;
364   int star = 0;
365   int cnt = 0;
366   char ch;
367   int chset = ~0;
368   int chset2 = (NTL_LOWER | NTL_UPPER);
369
370   if (m)
371     while ((ch = *m++))
372       switch (ch)
373       {
374         case '*':
375           star = 1;
376           break;
377         case '?':
378           cnt++;
379           *b++ = 'A';
380           chset2 &= ~NTL_LOWER;
381           break;
382         case '\\':
383           if ((*m == '?') || (*m == '*'))
384             ch = *m++;
385         default:
386           if (star)
387           {
388             ls = b;
389             fs = fs ? fs : b;
390             *b++ = 'Z';
391             chset2 &= ~NTL_LOWER;
392             star = 0;
393           };
394           cnt++;
395           *b = ToLower(ch);
396           chset &= IRCD_CharAttrTab[*b++ - CHAR_MIN];
397           chset2 &= ~NTL_UPPER;
398       };
399
400   if (charset)
401     *charset = (chset | chset2);
402
403   if (star)
404   {
405     ls = b;
406     fs = (fs ? fs : b);
407     *b++ = 'Z';
408   };
409
410   if (ls)
411   {
412     for (x1 = ls + 1, x2 = (b - 1); x1 < x2; x1++, x2--)
413     {
414       ch = *x1;
415       *x1 = *x2;
416       *x2 = ch;
417     };
418     l1 = (ls - fs);
419     l2 = (b - ls);
420     x1 = fs;
421     while ((lmin = (l1 < l2) ? l1 : l2))
422     {
423       x2 = x1 + l1;
424       for (loop = 0; loop < lmin; loop++)
425       {
426         ch = x1[loop];
427         x1[loop] = x2[loop];
428         x2[loop] = ch;
429       };
430       x1 += lmin;
431       sign = l1 - l2;
432       l1 -= (sign < 0) ? 0 : lmin;
433       l2 -= (sign > 0) ? 0 : lmin;
434     };
435   };
436
437   *b = '\0';
438   *minlen = cnt;
439   return (b - cmask);
440
441 }
442
443 /*
444  * matchexec()
445  *
446  * Executes a match with a mask previosuly compiled with matchcomp()
447  * Note 1: If the mask isn't correctly produced by matchcomp() I will core
448  * Note 2: 'min' MUST be the value returned by matchcomp on that mask,
449  *         or.... I will core even faster :-)
450  * Note 3: This piece of code is not intended to be nice but efficient.
451  */
452
453 int matchexec(const char *string, const char *cmask, int minlen)
454 {
455   const char *s = string - 1;
456   const char *b = cmask - 1;
457   int trash;
458   const char *bb, *bs;
459   char ch;
460
461 tryhead:
462   while ((ToLower(*++s) == *++b) && *s);
463   if (!*s)
464     return ((*b != '\0') && ((*b++ != 'Z') || (*b != '\0')));
465   if (*b != 'Z')
466   {
467     if (*b == 'A')
468       goto tryhead;
469     return 1;
470   };
471
472   bs = s;
473   while (*++s);
474
475   if ((trash = (s - string - minlen)) < 0)
476     return 2;
477
478 trytail:
479   while ((ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b
480       && (ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b);
481   if (*b != 'Z')
482   {
483     if (*b == 'A')
484       goto trytail;
485     return (*b != '\0');
486   };
487
488   s = --bs;
489   bb = b;
490
491   while ((ch = *++b))
492   {
493     while ((ToLower(*++s) != ch))
494       if (--trash < 0)
495         return 4;
496     bs = s;
497
498 trychunk:
499     while ((ToLower(*++s) == *++b) && *b);
500     if (!*b)
501       return 0;
502     if (*b == 'Z')
503     {
504       bs = --s;
505       bb = b;
506       continue;
507     };
508     if (*b == 'A')
509       goto trychunk;
510
511     b = bb;
512     s = bs;
513     if (--trash < 0)
514       return 5;
515   };
516
517   return 0;
518 }
519
520 /*
521  * matchdecomp()
522  * Prints the human readable version of *cmask into *mask, (decompiles
523  * cmask).
524  * The area pointed by *mask MUST be big enough (the mask might be up to
525  * twice the size of its compiled form if it's made all of \? or \*, and
526  * this function can NOT work in place since it might enflate the mask)
527  * The printed mask is not identical to the one that was compiled to cmask,
528  * infact it is 1) forced to all lowercase, 2) collapsed, both things
529  * are supposed to NOT change it's meaning.
530  * It returns the number of chars actually written to *mask;
531  */
532
533 int matchdecomp(char *mask, const char *cmask)
534 {
535   char *rtb = mask;
536   const char *rcm = cmask;
537   const char *begtail, *endtail;
538
539   if (rtb ==0)
540     return (-1);
541
542   if (rcm == 0)
543     return (-2);
544
545   for (; (*rcm != 'Z'); rcm++, rtb++)
546   {
547     if ((*rcm == '?') || (*rcm == '*'))
548       *rtb++ = '\\';
549     if (!((*rtb = ((*rcm == 'A') ? '?' : *rcm))))
550       return (rtb - mask);
551   };
552
553   begtail = rcm++;
554   *rtb++ = '*';
555
556   while (*rcm && (*rcm != 'Z'))
557     rcm++;
558
559   endtail = rcm;
560
561   if (*rcm)
562   {
563     while (*++rcm)
564       switch (*rcm)
565       {
566         case 'A':
567           *rtb++ = '?';
568           break;
569         case 'Z':
570           *rtb++ = '*';
571           break;
572         case '*':
573         case '?':
574           *rtb++ = '\\';
575         default:
576           *rtb++ = *rcm;
577       };
578     *rtb++ = '*';
579   };
580
581   for (rcm = endtail; (--rcm) > begtail; *rtb++ = ((*rcm == 'A') ? '?' : *rcm))
582     if ((*rcm == '?') || (*rcm == '*'))
583       *rtb++ = '\\';
584
585   *rtb = '\0';
586   return (rtb - mask);
587 }
588
589 /*
590  * mmexec()
591  * Checks if a wider compiled mask (wcm/wminlen) completely overrides
592  * a more restrict one (rcm/rminlen), basically what mmatch() does for
593  * non-compiled masks, returns 0 if the override is true (like mmatch()).
594  * "the wider overrides the restrict" means that any string that matches
595  * the restrict one _will_ also match the wider one, always. 
596  * In this we behave differently from mmatch() because in example we return 
597  * true for " a?*cd overrides a*bcd " for wich the override happens for how 
598  * we literally defined it, here mmatch() would have returned false.
599  * The original concepts and the base alghoritm are copied from mmatch() 
600  * written by Run (Carlo Wood), this function is written by
601  * Nemesi (Andrea Cocito)
602  */
603
604 int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
605 {
606   const char *w, *r, *br, *bw, *rx, *rz;
607   int eat, trash;
608
609   /* First of all rm must have enough non-stars to 'contain' wm */
610   if ((trash = rminlen - wminlen) < 0)
611     return 1;
612   w = wcm;
613   r = rcm;
614   eat = 0;
615
616   /* Let's start the game, remember that '*' is mapped to 'Z', '?'
617      is mapped to 'A' and that head?*??*?chunk*???*tail becomes
618      headAAAAZliatAAAZchunk for compiled masks */
619
620   /* Match the head of wm with the head of rm */
621   for (; (*r) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); r++, w++);
622   if (*r == 'Z')
623     while (*w == 'A')           /* Eat extra '?' before '*' in wm if got '*' in rm */
624       w++, eat++;
625   if (*w != 'Z')                /* head1<any>.. can't match head2<any>.. */
626     return ((*w) || (*r)) ? 1 : 0;      /* and head<nul> matches only head<nul> */
627   if (!*++w)
628     return 0;                   /* headZ<nul> matches head<anything>    */
629
630   /* Does rm have any stars in it ? let's check */
631   for (rx = r; *r && (*r != 'Z'); r++);
632   if (!*r)
633   {
634     /* rm has no stars and thus isn't a mask but it's just a flat
635        string: special handling occurs here, note that eat must be 0 here */
636
637     /* match the tail */
638     if (*w != 'Z')
639     {
640       for (; r--, (*w) && ((*w == *r) || (*w == 'A')); w++);
641       if (*w != 'Z')            /* headZliat1<any> fails on head<any>2tail  */
642         return (*w) ? 1 : 0;    /* but headZliat<nul> matches head<any>tail */
643     }
644
645     /* match the chunks */
646     while (1)
647     {                           /* This loop can't break but only return   */
648
649       for (bw = w++; (*w != *rx); rx++) /* Seek the 1st char of the chunk */
650         if (--trash < 0)        /* See if we can trash one more char of rm */
651           return 1;             /* If not we can only fail of course       */
652       for (r = ++rx, w++; (*w) && ((*w == *r) || (*w == 'A')); r++, w++);
653       if (!*w)                  /* Did last loop match the rest of chunk ? */
654         return 0;               /* ... Yes, end of wm, matched !           */
655       if (*w != 'Z')
656       {                         /* ... No, hitted non-star                 */
657         w = bw;                 /* Rollback at beginning of chunk          */
658         if (--trash < 0)        /* Trashed the char where this try started */
659           return 1;             /* if we can't trash more chars fail       */
660       }
661       else
662       {
663         rx = r;                 /* Successfully matched a chunk, move rx   */
664       }                 /* and go on with the next one             */
665     }
666   }
667
668   /* rm has at least one '*' and thus is a 'real' mask */
669   rz = r++;                     /* rx = unused of head, rz = beg-tail */
670
671   /* Match the tail of wm (if any) against the tail of rm */
672   if (*w != 'Z')
673   {
674     for (; (*w) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); w++, r++);
675     if (*r == 'Z')              /* extra '?' before tail are fluff, just flush 'em */
676       while (*w == 'A')
677         w++;
678     if (*w != 'Z')              /* We aren't matching a chunk, can't rollback      */
679       return (*w) ? 1 : 0;
680   }
681
682   /* Match the chunks of wm against what remains of the head of rm */
683   while (1)
684   {
685     bw = w;
686     for (bw++; (rx < rz) && (*bw != *rx); rx++) /* Seek the first           */
687       if (--trash < 0)          /* waste some trash reserve */
688         return 1;
689     if (!(rx < rz))             /* head finished            */
690       break;
691     for (bw++, (br = ++rx);
692         (br < rz) && (*bw) && ((*bw == *br) || (*bw == 'A')); br++, bw++);
693     if (!(br < rz))             /* Note that we didn't use any 'eat' char yet, if  */
694       while (*bw == 'A')        /* there were eat-en chars the head would be over  */
695         bw++, eat++;            /* Happens only at end of head, and eat is still 0 */
696     if (!*bw)
697       return 0;
698     if (*bw != 'Z')
699     {
700       eat = 0;
701       if (!(br < rz))
702       {                         /* If we failed because we got the end of head */
703         trash -= (br - rx);     /* it makes no sense to rollback, just trash   */
704         if (--trash < 0)        /* all the rest of the head wich isn't long    */
705           return 1;             /* enough for this chunk and go out of this    */
706         break;                  /* loop, then we try with the chunks of rm     */
707       };
708       if (--trash < 0)
709         return 1;
710     }
711     else
712     {
713       w = bw;
714       rx = br;
715     }
716   }
717
718   /* Match the unused chunks of wm against the chunks of rm */
719   rx = r;
720   for (; *r && (*r != 'Z'); r++);
721   rz = r;
722   if (*r++)
723   {
724     while (*r)
725     {
726       bw = w;
727       while (eat && *r)         /* the '?' we had eated make us skip as many chars */
728         if (*r++ != 'Z')        /* here, but can't skip stars or trailing zero     */
729           eat--;
730       for (bw++; (*r) && (*bw != *r); r++)
731         if ((*r != 'Z') && (--trash < 0))
732           return 1;
733       if (!*r)
734         break;
735       for ((br = ++r), bw++;
736           (*br) && (*br != 'Z') && ((*bw == *br) || (*bw == 'A')); br++, bw++);
737       if (*br == 'Z')
738         while (*bw == 'A')
739           bw++, eat++;
740       if (!*bw)
741         return 0;
742       if (*bw != 'Z')
743       {
744         eat = 0;
745         if ((!*br) || (*r == 'Z'))
746         {                       /* If we hit the end of rm or a star in it */
747           trash -= (br - r);    /* makes no sense to rollback within this  */
748           if (trash < 0)        /* same chunk of br, skip it all and then  */
749             return 1;           /* either rollback or break this loop if   */
750           if (!*br)             /* it was the end of rm                    */
751             break;
752           r = br;
753         }
754         if (--trash < 0)
755           return 1;
756       }
757       else
758       {
759         r = br;
760         w = bw;
761       }
762     }
763   }
764
765   /* match the remaining chunks of wm against what remains of the tail of rm */
766   r = rz - eat - 1;             /* can't have <nul> or 'Z'within the tail, so just move r */
767   while (r >= rx)
768   {
769     bw = w;
770     for (bw++; (*bw != *r); r--)
771       if (--trash < 0)
772         return 1;
773     if (!(r >= rx))
774       return 1;
775     for ((br = --r), bw++;
776         (*bw) && (br >= rx) && ((*bw == *br) || (*bw == 'A')); br--, bw++);
777     if (!*bw)
778       return 0;
779     if (!(br >= rx))
780       return 1;
781     if (*bw != 'Z')
782     {
783       if (--trash < 0)
784         return 1;
785     }
786     else
787     {
788       r = br;
789       w = bw;
790     }
791   }
792   return 1;                     /* Auch... something left out ? Fail */
793 }
794
795 #include <stdio.h>
796 #include <stdlib.h>
797 #include <string.h>
798 #include <sys/socket.h>
799 #include <netinet/in.h>
800 #include <arpa/inet.h>
801
802 static int ipmask_parse_ipv4(const char *in, struct in_addr *out)
803 {
804   int class;
805   char ipname[16];
806   int ad[4] = { 0 };
807   int bits = 0;
808
809   class = sscanf(in, "%d.%d.%d.%d/%d", &ad[0], &ad[1], &ad[2], &ad[3], &bits);
810   if (class != 5)
811     bits = class * 8;
812   ircd_snprintf(0, ipname, sizeof(ipname), "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
813   out->s_addr = inet_addr(ipname);
814   return bits;
815 }
816
817 int ipmask_parse(const char *in, struct irc_in_addr *mask, unsigned char *bits_ptr)
818 {
819   struct in_addr ipv4;
820   char *p;
821   int bits = 0;
822
823   if (check_if_ipmask(in)) {
824     bits = ipmask_parse_ipv4(in, &ipv4);
825     mask->in6_16[0] = mask->in6_16[1] = mask->in6_16[2] = 0;
826     mask->in6_16[3] = mask->in6_16[4] = mask->in6_16[5] = 0;
827     memcpy(&mask->in6_16[6], &ipv4.s_addr, sizeof(ipv4.s_addr));
828     bits += 96;
829   } else {
830     if (!(p = strchr(in, '/')))
831       bits = 128;
832     else
833       *p = 0;
834     if (!ircd_aton(mask, in)) {
835       if (p)
836         *p = '/';
837       return 0;
838     }
839     if (p) {
840       bits = atoi(p + 1);
841       *p = '/';
842     }
843   }
844
845   if (bits_ptr)
846     *bits_ptr = bits;
847   return 1;
848 }
849
850 int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits)
851 {
852   int k;
853
854   for (k = 0; k < 8; k++) {
855     if (bits < 16)
856       return (addr->in6_16[k] & ((unsigned char) (0xffff << (16-bits)))) == mask->in6_16[k];
857     if (addr->in6_16[k] != mask->in6_16[k])
858       return 0;
859     if (!(bits -= 16))
860       return 1;
861   }
862   return -1;
863 }