2 * IRC - Internet Relay Chat, common/match.c
3 * Copyright (C) 1990 Jarkko Oikarinen
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)
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.
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.
19 * $Id: Match.cpp,v 1.2 2005/08/15 10:08:50 shroud23 Exp $
25 #define ToLower tolower
30 * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
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)
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.
49 int mmatch(const char *old_mask, const char *new_mask)
51 const char *m = old_mask;
52 const char *n = new_mask;
73 for (m--; (m > old_mask) && (*m == '?'); m--)
75 if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
81 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
82 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
93 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
101 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
102 if ((*n == '\\') && ((n[1] == '*') || (n[1] == '?')))
111 * This `if' has been changed compared to match() to do the following:
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)))
120 * Here `any' also includes \* and \? !
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!)).
126 if ((*m == '*' && !mq) ||
127 ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
128 (*m == '?' && !mq && (*n != '*' || nq)))
141 /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
142 if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
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.
163 * Rewritten by Andrea Cocito (Nemesi), November 1998.
167 /****************** Nemesi's match() ***************/
169 int match(const char *mask, const char *str)
171 const char *m = mask, *s = str;
173 const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */
175 /* Process the "head" of the mask, if any */
176 while ((ch = *m++) && (ch != '*'))
180 if (*m == '?' || *m == '*')
183 if (ToLower(*s) != ToLower(ch))
192 /* We got a star: quickly find if/where we match the next char */
194 bm = m; /* Next try rollback here */
203 continue; /* while */
205 if (*m == '?' || *m == '*')
208 goto break_while; /* C is structured ? */
212 return 0; /* mask ends with '*', we got it */
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)
219 bs = s; /* Next try start from here */
221 /* Check the rest of the "chunk" */
229 if (*m == '?' || *m == '*')
232 if (ToLower(*s) != ToLower(ch))
234 /* If we've run out of string, give up */
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.
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.
267 char *collapse(char *pattern)
277 if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
286 if (star && (*m != '?'))
292 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
301 if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))