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