1 /**************************************************************************************************
2 $Id: wildcard.c,v 1.7 2005/04/20 16:49:11 bboy Exp $
3
4 wildcard.c: Wildcard matching routines.
5
6 Originally authored and placed in the public domain by J. Kercheval.
7
8 Copyright (C) 2002-2005 Don Moore <bboy@bboy.net>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at Your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 **************************************************************************************************/
24
25 #include "mydnsutil.h"
26
27 #define _WC_MATCH_PATTERN 6 /* bad pattern */
28 #define _WC_MATCH_LITERAL 5 /* match failure on literal match */
29 #define _WC_MATCH_RANGE 4 /* match failure on [..] construct */
30 #define _WC_MATCH_ABORT 3 /* premature end of text string */
31 #define _WC_MATCH_END 2 /* premature end of pattern string */
32 #define _WC_MATCH_VALID 1 /* valid match */
33
34
35 /**************************************************************************************************
36 WILDCARD_VALID
37 Returns 1 if the specified string is valid, 0 if it contains a syntax error.
38 **************************************************************************************************/
39 int
wildcard_valid(char * p)40 wildcard_valid(char *p) {
41 /* loop through pattern to EOS */
42 while (*p) {
43 switch (*p) {
44 case '\\':
45 if (!*++p)
46 return 0;
47 p++;
48 break;
49
50 case '[':
51 p++;
52 if (*p == ']')
53 return 0;
54 if (!*p)
55 return 0;
56
57 while (*p != ']') {
58 if (*p == '\\') {
59 p++;
60
61 if (!*p++)
62 return 0;
63 } else
64 p++;
65
66 if (!*p)
67 return 0;
68
69 if (*p == '-') {
70 if (!*++p || *p == ']')
71 return 0;
72 else {
73 if (*p == '\\')
74 p++;
75 if (!*p++)
76 return 0;
77 }
78 }
79 }
80 break;
81
82 case '*':
83 case '?':
84 default:
85 p++;
86 break;
87 }
88 }
89 return 1;
90 }
91 /*--- wildcard_valid() --------------------------------------------------------------------------*/
92
93
94 /**************************************************************************************************
95 MATCH_AFTER_STAR
96 Recursively call wildcard_match() with final segment of PATTERN and of TEXT.
97 **************************************************************************************************/
98 static int
match_after_star(register char * p,register char * t)99 match_after_star(register char *p, register char *t) {
100 register int match = 0, nextp;
101
102 while (*p == '?' || *p == '*') {
103 if (*p == '?') {
104 if (!*t++)
105 return _WC_MATCH_ABORT;
106 }
107 p++;
108 }
109
110 if (!*p)
111 return _WC_MATCH_VALID;
112
113 nextp = *p;
114 if (nextp == '\\') {
115 nextp = p[1];
116
117 if (!nextp)
118 return _WC_MATCH_PATTERN;
119 }
120
121 do {
122 if (nextp == *t || nextp == '[')
123 match = wildcard_match(p, t);
124
125 if (!*t++)
126 match = _WC_MATCH_ABORT;
127 } while (match != _WC_MATCH_VALID && match != _WC_MATCH_ABORT && match != _WC_MATCH_PATTERN);
128
129 return match;
130 }
131 /*--- match_after_star() ------------------------------------------------------------------------*/
132
133
134 /**************************************************************************************************
135 _WILDCARD_MATCH
136 Match pattern (p) against text (t).
137 **************************************************************************************************/
138 static int
_wildcard_match(register char * p,register char * t)139 _wildcard_match(register char *p, register char *t) {
140 register char range_start, range_end; /* start and end in range */
141
142 int invert; /* is this [..] or [!..] */
143 int member_match; /* have I matched the [..] construct? */
144 int loop; /* should I terminate? */
145
146 for (; *p; p++, t++) {
147 /* if this is the end of the text
148 then this is the end of the match */
149
150 if (!*t) {
151 return (*p == '*' && *++p == '\0') ? _WC_MATCH_VALID : _WC_MATCH_ABORT;
152 }
153
154 /* determine and react to pattern type */
155
156 switch (*p) {
157 case '?': /* single any character match */
158 break;
159
160 case '*': /* multiple any character match */
161 return match_after_star(p, t);
162
163 /* [..] construct, single member/exclusion character match */
164 case '[':
165 {
166 /* move to beginning of range */
167
168 p++;
169
170 /* check if this is a member match or exclusion match */
171
172 invert = 0;
173 if (*p == '!' || *p == '^') {
174 invert = 1;
175 p++;
176 }
177
178 /* if closing bracket here or at range start then we have a
179 malformed pattern */
180
181 if (*p == ']') {
182 return _WC_MATCH_PATTERN;
183 }
184
185 member_match = 0;
186 loop = 1;
187
188 while (loop) {
189 /* if end of construct then loop is done */
190
191 if (*p == ']') {
192 loop = 0;
193 continue;
194 }
195
196 /* matching a '!', '^', '-', '\' or a ']' */
197
198 if (*p == '\\') {
199 range_start = range_end = *++p;
200 } else
201 range_start = range_end = *p;
202
203 /* if end of pattern then bad pattern (Missing ']') */
204
205 if (!*p)
206 return _WC_MATCH_PATTERN;
207
208 /* check for range bar */
209 if (*++p == '-') {
210 /* get the range end */
211
212 range_end = *++p;
213
214 /* if end of pattern or construct
215 then bad pattern */
216
217 if (range_end == '\0' || range_end == ']')
218 return _WC_MATCH_PATTERN;
219
220 /* special character range end */
221 if (range_end == '\\') {
222 range_end = *++p;
223
224 /* if end of text then
225 we have a bad pattern */
226 if (!range_end)
227 return _WC_MATCH_PATTERN;
228 }
229
230 /* move just beyond this range */
231 p++;
232 }
233
234 /* if the text character is in range then match found.
235 make sure the range letters have the proper
236 relationship to one another before comparison */
237
238 if (range_start < range_end) {
239 if (*t >= range_start && *t <= range_end) {
240 member_match = 1;
241 loop = 0;
242 }
243 } else {
244 if (*t >= range_end && *t <= range_start) {
245 member_match = 1;
246 loop = 0;
247 }
248 }
249 }
250
251 /* if there was a match in an exclusion set then no match */
252 /* if there was no match in a member set then no match */
253
254 if ((invert && member_match) || !(invert || member_match))
255 return _WC_MATCH_RANGE;
256
257 /* if this is not an exclusion then skip the rest of
258 the [...] construct that already matched. */
259
260 if (member_match) {
261 while (*p != ']') {
262 /* bad pattern (Missing ']') */
263 if (!*p)
264 return _WC_MATCH_PATTERN;
265
266 /* skip exact match */
267 if (*p == '\\') {
268 p++;
269
270 /* if end of text then
271 we have a bad pattern */
272
273 if (!*p)
274 return _WC_MATCH_PATTERN;
275 }
276
277 /* move to next pattern char */
278
279 p++;
280 }
281 }
282 break;
283 }
284 case '\\': /* next character is quoted and must match exactly */
285
286 /* move pattern pointer to quoted char and fall through */
287
288 p++;
289
290 /* if end of text then we have a bad pattern */
291
292 if (!*p)
293 return _WC_MATCH_PATTERN;
294
295 /* must match this character exactly */
296
297 default:
298 if (*p != *t)
299 return _WC_MATCH_LITERAL;
300 }
301 }
302 /* if end of text not reached then the pattern fails */
303
304 if (*t)
305 return _WC_MATCH_END;
306 else
307 return _WC_MATCH_VALID;
308 }
309 /*--- _wildcard_match() -------------------------------------------------------------------------*/
310
311
312 /**************************************************************************************************
313 WILDCARD_MATCH
314 Match pattern (p) against text (t).
315 **************************************************************************************************/
316 int
wildcard_match(register char * p,register char * t)317 wildcard_match(register char *p, register char *t) {
318 return (_wildcard_match(p, t) == _WC_MATCH_VALID);
319 }
320 /*--- wildcard_match() --------------------------------------------------------------------------*/
321
322 /* vi:set ts=3: */
323