]> granicus.if.org Git - icinga2/blob - third-party/mmatch/mmatch.c
Merge pull request #5928 from Icinga/fix/build-fix-msvc
[icinga2] / third-party / mmatch / mmatch.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: Match.cpp,v 1.2 2005/08/15 10:08:50 shroud23 Exp $
20  */
21
22 #include <ctype.h>
23 #include "mmatch.h"
24
25 #define ToLower tolower
26
27 /*
28  * mmatch()
29  *
30  * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
31  *
32  *
33  * From: Carlo Wood <carlo@runaway.xs4all.nl>
34  * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
35  * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
36  * To: coder-com@mail.undernet.org (coder committee)
37  * Date: Mon, 2 Sep 1996 12:26:01 +0200 (MET DST)
38  *
39  * We need a new function `mmatch(const char *old_mask, const char *new_mask)'
40  * which returns `true' likewise the current `match' (start with copying it),
41  * but which treats '*' and '?' in `new_mask' differently (not "\*" and "\?" !)
42  * as follows:  a '*' in `new_mask' does not match a '?' in `old_mask' and
43  * a '?' in `new_mask' does not match a '\?' in `old_mask'.
44  * And ofcourse... a '*' in `new_mask' does not match a '\*' in `old_mask'...
45  * And last but not least, '\?' and '\*' in `new_mask' now become one character.
46  */
47
48 #if 0
49 int mmatch(const char *old_mask, const char *new_mask)
50 {
51   const char *m = old_mask;
52   const char *n = new_mask;
53   const char *ma = m;
54   const char *na = n;
55   int wild = 0;
56   int mq = 0, nq = 0;
57
58   while (1)
59   {
60     if (*m == '*')
61     {
62       while (*m == '*')
63         m++;
64       wild = 1;
65       ma = m;
66       na = n;
67     }
68
69     if (!*m)
70     {
71       if (!*n)
72         return 0;
73       for (m--; (m > old_mask) && (*m == '?'); m--)
74         ;
75       if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
76         return 0;
77       if (!wild)
78         return 1;
79       m = ma;
80
81       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
82       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
83         ++na;
84
85       n = ++na;
86     }
87     else if (!*n)
88     {
89       while (*m == '*')
90         m++;
91       return (*m != 0);
92     }
93     if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
94     {
95       m++;
96       mq = 1;
97     }
98     else
99       mq = 0;
100
101     /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
102     if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
103     {
104       n++;
105       nq = 1;
106     }
107     else
108       nq = 0;
109
110 /*
111  * This `if' has been changed compared to match() to do the following:
112  * Match when:
113  *   old (m)         new (n)         boolean expression
114  *    *               any             (*m == '*' && !mq) ||
115  *    ?               any except '*'  (*m == '?' && !mq && (*n != '*' || nq)) ||
116  * any except * or ?  same as m       (!((*m == '*' || *m == '?') && !mq) &&
117  *                                      ToLower(*m) == ToLower(*n) &&
118  *                                        !((mq && !nq) || (!mq && nq)))
119  *
120  * Here `any' also includes \* and \? !
121  *
122  * After reworking the boolean expressions, we get:
123  * (Optimized to use boolean shortcircuits, with most frequently occuring
124  *  cases upfront (which took 2 hours!)).
125  */
126     if ((*m == '*' && !mq) ||
127         ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
128         (*m == '?' && !mq && (*n != '*' || nq)))
129     {
130       if (*m)
131         m++;
132       if (*n)
133         n++;
134     }
135     else
136     {
137       if (!wild)
138         return 1;
139       m = ma;
140
141       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
142       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
143         ++na;
144
145       n = ++na;
146     }
147   }
148 }
149 #endif
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
160 /*
161  * match
162  *
163  * Rewritten by Andrea Cocito (Nemesi), November 1998.
164  *
165  */
166
167 /****************** Nemesi's match() ***************/
168
169 int match(const char *mask, const char *str)
170 {
171   const char *m = mask, *s = str;
172   char ch;
173   const char *bm, *bs;          /* Will be reg anyway on a decent CPU/compiler */
174
175   /* Process the "head" of the mask, if any */
176   while ((ch = *m++) && (ch != '*'))
177     switch (ch)
178     {
179       case '\\':
180         if (*m == '?' || *m == '*')
181           ch = *m++;
182       default:
183         if (ToLower(*s) != ToLower(ch))
184           return 1;
185       case '?':
186         if (!*s++)
187           return 1;
188     };
189   if (!ch)
190     return *s;
191
192   /* We got a star: quickly find if/where we match the next char */
193 got_star:
194   bm = m;                       /* Next try rollback here */
195   while ((ch = *m++))
196     switch (ch)
197     {
198       case '?':
199         if (!*s++)
200           return 1;
201       case '*':
202         bm = m;
203         continue;               /* while */
204       case '\\':
205         if (*m == '?' || *m == '*')
206           ch = *m++;
207       default:
208         goto break_while;       /* C is structured ? */
209     };
210 break_while:
211   if (!ch)
212     return 0;                   /* mask ends with '*', we got it */
213   ch = ToLower(ch);
214   if (!*s)                      /* String is already empty, don't continue */
215     return 1;                   /* This fixes the #quakenet access denied bug */
216   while (ToLower(*s++) != ch)
217     if (!*s)
218       return 1;
219   bs = s;                       /* Next try start from here */
220
221   /* Check the rest of the "chunk" */
222   while ((ch = *m++))
223   {
224     switch (ch)
225     {
226       case '*':
227         goto got_star;
228       case '\\':
229         if (*m == '?' || *m == '*')
230           ch = *m++;
231       default:
232         if (ToLower(*s) != ToLower(ch))
233         {
234           /* If we've run out of string, give up */
235           if (!*bs)
236             return 1;
237           m = bm;
238           s = bs;
239           goto got_star;
240         };
241       case '?':
242         if (!*s++)
243           return 1;
244     };
245   };
246   if (*s)
247   {
248     m = bm;
249     s = bs;
250     goto got_star;
251   };
252   return 0;
253 }
254
255 /*
256  * collapse()
257  * Collapse a pattern string into minimal components.
258  * This particular version is "in place", so that it changes the pattern
259  * which is to be reduced to a "minimal" size.
260  *
261  * (C) Carlo Wood - 6 Oct 1998
262  * Speedup rewrite by Andrea Cocito, December 1998.
263  * Note that this new optimized alghoritm can *only* work in place.
264  */
265
266 #if 0
267 char *collapse(char *pattern)
268 {
269   int star = 0;
270   char *m = pattern;
271   char *b;
272
273   if (m)
274   {
275     do
276     {
277       if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
278       {
279         b = m;
280         do
281         {
282           if (*m == '*')
283             star = 1;
284           else
285           {
286             if (star && (*m != '?'))
287             {
288               *b++ = '*';
289               star = 0;
290             };
291             *b++ = *m;
292             if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
293               *b++ = *++m;
294           };
295         }
296         while (*m++);
297         break;
298       }
299       else
300       {
301         if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
302           m++;
303       };
304     }
305     while (*m++);
306   };
307   return pattern;
308 }
309 #endif