/[cvs]/eggdrop1.9/src/match.c
ViewVC logotype

Contents of /eggdrop1.9/src/match.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.12 - (show annotations) (download) (as text)
Tue Feb 18 10:37:18 2003 UTC (16 years, 8 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +1 -1 lines
File MIME type: text/x-chdr
FILE REMOVED
*** empty log message ***

1 /*
2 * match.c --
3 *
4 * wildcard matching functions
5 */
6 /*
7 * Once this code was working, I added support for % so that I could
8 * use the same code both in Eggdrop and in my IrcII client.
9 * Pleased with this, I added the option of a fourth wildcard, ~,
10 * which matches varying amounts of whitespace (at LEAST one space,
11 * though, for sanity reasons).
12 *
13 * This code would not have been possible without the prior work and
14 * suggestions of various sources. Special thanks to Robey for
15 * all his time/help tracking down bugs and his ever-helpful advice.
16 *
17 * 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
18 *
19 * Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
20 * crf@cfox.bchs.uh.edu
21 *
22 * I hereby release this code into the public domain
23 */
24
25 #ifndef lint
26 static const char rcsid[] = "$Id: match.c,v 1.11 2002/05/05 20:04:33 stdarg Exp $";
27 #endif
28
29 /* prototypes */
30 #include "match.h"
31 #include "irccmp.h" /* irctoupper() */
32
33
34 /* The quoting character -- what overrides wildcards */
35 #define QUOTE '\\'
36
37 /* The "matches ANYTHING" wildcard */
38 #define WILDS '*'
39
40 /* The "matches ANY NUMBER OF NON-SPACE CHARS" wildcard */
41 #define WILDP '%'
42
43 /* The "matches EXACTLY ONE CHARACTER" wildcard */
44 #define WILDQ '?'
45
46 /* The "matches AT LEAST ONE SPACE" wildcard */
47 #define WILDT '~'
48
49 /* Changing these is probably counter-productive :) */
50 #define UNQUOTED (0x7FFF)
51 #define QUOTED (0x8000)
52 #define NOMATCH 0
53 #define MATCH ((match+sofar)&UNQUOTED)
54 #define MATCH_PER (match+saved+sofar)
55
56
57 /*
58 * wild_match(char *ma, char *na)
59 *
60 * Features: Backwards, case-insensitive, ?, *
61 * Best use: Matching of hostmasks (since they are likely to begin
62 * with a * rather than end with one).
63 */
64 /*
65 * sofar's high bit is used as a flag of whether or not we are quoting.
66 * The other matchers don't need this because when you're going forward,
67 * you just skip over the quote char.
68 * No "saved" is used to track "%" and no special quoting ability is
69 * needed, so we just have (match+sofar) as the result.
70 */
71 int wild_match(const unsigned char *m, const unsigned char *n)
72 {
73 const unsigned char *ma = m, *na = n, *lsm = 0, *lsn = 0;
74 int match = 1;
75 int sofar = 0;
76
77 /* take care of null strings (should never match) */
78 if ((ma == 0) || (na == 0) || (!*ma) || (!*na))
79 return NOMATCH;
80 /* find the end of each string */
81 while (*(++m));
82 m--;
83 while (*(++n));
84 n--;
85
86 while (n >= na) {
87 if ((m <= ma) || (m[-1] != QUOTE)) { /* Only look if no quote */
88 switch (*m) {
89 case WILDS: /* Matches anything */
90 do
91 m--; /* Zap redundant wilds */
92 while ((m >= ma) && ((*m == WILDS) || (*m == WILDP)));
93 if ((m >= ma) && (*m == '\\'))
94 m++; /* Keep quoted wildcard! */
95 lsm = m;
96 lsn = n;
97 match += sofar;
98 sofar = 0; /* Update fallback pos */
99 continue; /* Next char, please */
100 case WILDQ:
101 m--;
102 n--;
103 continue; /* '?' always matches */
104 }
105 sofar &= UNQUOTED; /* Remember not quoted */
106 } else
107 sofar |= QUOTED; /* Remember quoted */
108 if (irctoupper(*m) == irctoupper(*n)) { /* If matching char */
109 m--;
110 n--;
111 sofar++; /* Tally the match */
112 if (sofar & QUOTED)
113 m--; /* Skip the quote char */
114 continue; /* Next char, please */
115 }
116 if (lsm) { /* To to fallback on '*' */
117 n = --lsn;
118 m = lsm;
119 if (n < na)
120 lsm = 0; /* Rewind to saved pos */
121 sofar = 0;
122 continue; /* Next char, please */
123 }
124 return NOMATCH; /* No fallback=No match */
125 }
126 while ((m >= ma) && ((*m == WILDS) || (*m == WILDP)))
127 m--; /* Zap leftover %s & *s */
128 return (m >= ma) ? NOMATCH : MATCH; /* Start of both = match */
129 }
130
131
132 /*
133 * wild_match_per(char *m, char *n)
134 *
135 * Features: Forward, case-insensitive, ?, *, %, ~(optional)
136 * Best use: Generic string matching, such as in IrcII-esque bindings
137 */
138 int wild_match_per(const unsigned char *m, const unsigned char *n)
139 {
140 const unsigned char *ma = m, *lsm = 0, *lsn = 0, *lpm = 0, *lpn = 0;
141 int match = 1, saved = 0, space;
142 unsigned int sofar = 0;
143
144 /* take care of null strings (should never match) */
145 if ((m == 0) || (n == 0) || (!*n))
146 return NOMATCH;
147 /* (!*m) test used to be here, too, but I got rid of it. After all,
148 * If (!*n) was false, there must be a character in the name (the
149 * second string), so if the mask is empty it is a non-match. Since
150 * the algorithm handles this correctly without testing for it here
151 * and this shouldn't be called with null masks anyway, it should be
152 * a bit faster this way */
153
154 while (*n) {
155 /* Used to test for (!*m) here, but this scheme seems to work better */
156 if (*m == WILDT) { /* Match >=1 space */
157 space = 0; /* Don't need any spaces */
158 do {
159 m++;
160 space++;
161 } /* Tally 1 more space ... */
162 while ((*m == WILDT) || (*m == ' ')); /* for each space or ~ */
163 sofar += space; /* Each counts as exact */
164 while (*n == ' ') {
165 n++;
166 space--;
167 } /* Do we have enough? */
168 if (space <= 0)
169 continue; /* Had enough spaces! */
170 }
171 /* Do the fallback */
172 else {
173 switch (*m) {
174 case 0:
175 do
176 m--; /* Search backwards */
177 while ((m > ma) && (*m == '?')); /* For first non-? char */
178 if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
179 return MATCH_PER; /* nonquoted * = match */
180 break;
181 case WILDP:
182 while (*(++m) == WILDP); /* Zap redundant %s */
183 if (*m != WILDS) { /* Don't both if next=* */
184 if (*n != ' ') { /* WILDS can't match ' ' */
185 lpm = m;
186 lpn = n; /* Save '%' fallback spot */
187 saved += sofar;
188 sofar = 0; /* And save tally count */
189 }
190 continue; /* Done with '%' */
191 }
192 /* FALL THROUGH */
193 case WILDS:
194 do
195 m++; /* Zap redundant wilds */
196 while ((*m == WILDS) || (*m == WILDP));
197 lsm = m;
198 lsn = n;
199 lpm = 0; /* Save '*' fallback spot */
200 match += (saved + sofar); /* Save tally count */
201 saved = sofar = 0;
202 continue; /* Done with '*' */
203 case WILDQ:
204 m++;
205 n++;
206 continue; /* Match one char */
207 case QUOTE:
208 m++; /* Handle quoting */
209 }
210 if (irctoupper(*m) == irctoupper(*n)) { /* If matching */
211 m++;
212 n++;
213 sofar++;
214 continue; /* Tally the match */
215 }
216 }
217 if (lpm) { /* Try to fallback on '%' */
218 n = ++lpn;
219 m = lpm;
220 sofar = 0; /* Restore position */
221 if ((*n | 32) == 32)
222 lpm = 0; /* Can't match 0 or ' ' */
223 continue; /* Next char, please */
224 }
225 if (lsm) { /* Try to fallback on '*' */
226 n = ++lsn;
227 m = lsm; /* Restore position */
228 /* Used to test for (!*n) here but it wasn't necessary so it's gone */
229 saved = sofar = 0;
230 continue; /* Next char, please */
231 }
232 return NOMATCH; /* No fallbacks=No match */
233 }
234 while ((*m == WILDS) || (*m == WILDP))
235 m++; /* Zap leftover %s & *s */
236 return (*m) ? NOMATCH : MATCH_PER; /* End of both = match */
237 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23