1 /*
2  * The original was spagetti. I have replaced Michael's code with some of
3  * my own which is a thousand times more readable and can also handle '%',
4  * which substitutes anything except a space. This should enable people
5  * to position things better based on argument. I have also added '?', which
6  * substitutes to any single character. And of course it still handles '*'.
7  * this should be more efficient than the previous version too.
8  *
9  * Thus this whole file becomes:
10  *
11  * Written By Troy Rollo
12  *
13  * Copyright(c) 1992
14  *
15  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
16  */
17 
18 #include "irc.h"
19 #include "ircaux.h"
20 #include "output.h"
21 
22 static int total_explicit;
23 
24 /*
25  * The following #define is here because we *know* its behaviour.
26  * The behaviour of toupper tends to be undefined when it's given
27  * a non lower case letter.
28  * All the systems supported by IRCII should be ASCII
29  */
30 #define	mkupper(c)	(((c) >= 'a' && (c) <= 'z') ? ((c) - 'a' + 'A') : c)
31 
32 #ifdef __STDC__
33 int
match(u_char * pattern,u_char * string)34 match(u_char *pattern, u_char *string)
35 #else
36 int
37 match(pattern, string)
38    u_char *pattern, *string;
39 #endif
40 {
41    u_char type;
42 
43 #if 0
44    if ((!pattern || !string) && !x_debug)
45      {
46 	yell("match: pattern or string is NULL!");
47 	return 0;
48      }
49 #endif
50 
51    while (*string && *pattern && *pattern != '*' && *pattern != '%')
52      {
53 	if (*pattern == '\\' && *(pattern + 1))
54 	  {
55 	     if (!*++pattern || !(mkupper(*pattern) ==
56 				  mkupper(*string)))
57 		return 0;
58 	     else
59 		pattern++, string++, total_explicit++;
60 	  }
61 
62 	if (*pattern == '?')
63 	   pattern++, string++;
64 	else if (mkupper(*pattern) == mkupper(*string))
65 	   pattern++, string++, total_explicit++;
66 	else
67 	   break;
68      }
69    if (*pattern == '*' || *pattern == '%')
70      {
71 	type = (*pattern++);
72 	while (*string)
73 	  {
74 	     if (match(pattern, string))
75 		return 1;
76 	     else if (type == '*' || *string != ' ')
77 		string++;
78 	     else
79 		break;
80 	  }
81      }
82    if (!*string && !*pattern)
83       return 1;
84    return 0;
85 }
86 
87 /*
88  * This version of wild_match returns 1 + the  count  of characters
89  * explicitly matched if a match occurs. That way we can look for
90  * the best match in a list
91  */
92 /* \\[ and \\] handling done by Jeremy Nelson
93  * EPIC will not use the new pattern matcher currently used by
94  * ircii because i am not convinced that it is 1) better * and
95  * 2) i think the \\[ \\] stuff is important.
96  */
97 #ifdef __STDC__
98 int
wild_match(u_char * pattern,u_char * str)99 wild_match(u_char *pattern, u_char *str)
100 #else
101 int
102 wild_match(pattern, str)
103    u_char *pattern, *str;
104 #endif
105 {
106    u_char *ptr;
107    u_char *ptr2 = pattern;
108    int nest = 0;
109    u_char my_buff[2048];
110    u_char *arg;
111    int best_total = 0;
112 
113    total_explicit = 0;
114 
115    if (!str)
116      {
117 	put_error("string is null calling wild_match().. caller contains a bug");
118 	return 0;
119      }
120    /* Is there a \[ in the pattern to be expanded? */
121    /* This stuff here just reduces the \[ \] set into a series of
122     * one-simpler patterns and then recurses */
123    if ((ptr2 = strstr(pattern, "\\[")))
124      {
125 	/* we will have to null this out, but not until weve used it */
126 	u_char *placeholder = ptr2;
127 	ptr = ptr2;
128 
129 	/* yes. whats the character after it? (first time
130 	   through is a trivial case) */
131 	do
132 	  {
133 	     switch (ptr[1])
134 	       {
135 		     /* step over it and add to nest */
136 		  case '[':
137 		     ptr2 = ptr + 2;
138 		     nest++;
139 		     break;
140 		     /* step over it and remove nest */
141 		  case ']':
142 		     ptr2 = ptr + 2;
143 		     nest--;
144 		     break;
145 	       }
146 	  }
147 	/* Repeat while there are more backslashes to look at and
148 	 * we have are still in nested \[ \] sets
149 	 */
150 	while ((nest) && (ptr = index(ptr2, '\\')));
151 
152 	/* right now, we know ptr points to a \] or to null */
153 	/* remember that && short circuits and that ptr will
154 	   not be set to null if (nest) is zero... */
155 	if (ptr)
156 	  {
157 	     /* null out and step over the original \[ */
158 	     *placeholder = '\0';
159 	     placeholder += 2;
160 
161 	     /* null out and step over the matching \] */
162 	     *ptr = '\0';
163 	     ptr += 2;
164 
165 	     /* grab words ("" sets or space words) one at a time
166 	      * and attempt to match all of them.  The best value
167 	      * matched is the one used.
168 	      */
169 	     while ((arg = new_next_arg(placeholder, &placeholder)))
170 	       {
171 		  int tmpval;
172 
173 		  strncpy(my_buff, pattern, sizeof(my_buff)-1);
174 		  strmcat(my_buff, arg, sizeof(my_buff)-1);
175 		  strmcat(my_buff, ptr, sizeof(my_buff)-1);
176 		  /* the total_explicit we return is whichever
177 		   * pattern has the highest total_explicit */
178 		  if ((tmpval = wild_match(my_buff, str)))
179 		    {
180 		       if (tmpval > best_total)
181 			  best_total = tmpval;
182 		    }
183 	       }
184 	     return best_total;	/* end of expansion section */
185 	  }
186 	/* Possibly an unmatched \[ \] set */
187 	else
188 	  {
189 	     total_explicit = 0;
190 	     if (match(pattern, str))
191 		return total_explicit + 1;
192 	     else
193 	       {
194 #if 0
195 		  yell("Unmatched \\[ !");
196 #endif
197 		  return 0;
198 	       }
199 	  }
200      }
201    /* trivial case (no expansion) when weve expanded all the way out */
202    else if (match(pattern, str))
203       return total_explicit + 1;
204    else
205       return 0;
206 }
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 /*
225  * IP match().. only matches for digits and dots.
226  *
227  * - doesn't support \<char>
228  * - returns 0 if anything other than a digit or dot is found..
229  *
230  */
231 #ifdef __STDC__
232 int
ip_match(u_char * pattern,u_char * string)233 ip_match(u_char *pattern, u_char *string)
234 #else
235 int
236 ip_match(pattern, string)
237    u_char *pattern, *string;
238 #endif
239 {
240    u_char type;
241 
242 #if 0
243    if ((!pattern || !string) && !x_debug)
244      {
245 	yell("ip_match: pattern or string is NULL!");
246 	return 0;
247      }
248 #endif
249 
250    while (*string && *pattern && *pattern != '*' && *pattern != '%')
251      {
252 	if (*pattern == '?')
253 	   pattern++, string++;
254 	/* not digit or dot? */
255 	else if ((!isdigit(*pattern) && *pattern != '.') || (!isdigit(*string) && *string != '.'))
256 	  break;
257 	else if (*pattern == *string)
258 	   pattern++, string++;
259 	else
260 	   break;
261      }
262    if (*pattern == '*' || *pattern == '%')
263      {
264 	type = (*pattern++);
265 	while (*string)
266 	  {
267 	     /* not digit or dot ? */
268 	     if (!isdigit(*string) && *string != '.')
269 	       break;
270 	     else if (ip_match(pattern, string))
271 		return 1;
272 	     else if (type == '*' || *string != ' ')
273 		string++;
274 	     else
275 		break;
276 	  }
277      }
278    if (!*string && !*pattern)
279       return 1;
280    return 0;
281 }
282 
283 /*
284  * case sensitive match()..
285  *
286  */
287 #ifdef __STDC__
288 int
cs_match(u_char * pattern,u_char * string)289 cs_match(u_char *pattern, u_char *string)
290 #else
291 int
292 cs_match(pattern, string)
293    u_char *pattern, *string;
294 #endif
295 {
296    u_char type;
297 
298 #if 0
299    if ((!pattern || !string) && !x_debug)
300      {
301 	yell("ip_match: pattern or string is NULL!");
302 	return 0;
303      }
304 #endif
305 
306    while (*string && *pattern && *pattern != '*' && *pattern != '%')
307      {
308 	if (*pattern == '\\' && *(pattern + 1))
309 	  {
310 	     if (!*++pattern || !(*pattern == *string))
311 		return 0;
312 	     else
313 		pattern++, string++;
314 	  }
315 
316 	if (*pattern == '?')
317 	   pattern++, string++;
318 	else if (*pattern == *string)
319 	  pattern++, string++;
320 	else
321 	  break;
322      }
323    if (*pattern == '*' || *pattern == '%')
324      {
325 	type = (*pattern++);
326 	while (*string)
327 	  {
328 	     if (cs_match(pattern, string))
329 		return 1;
330 	     else if (type == '*' || *string != ' ')
331 		string++;
332 	     else
333 		break;
334 	  }
335      }
336    if (!*string && !*pattern)
337       return 1;
338    return 0;
339 }
340