src/server/util/shexp.c

changeset 14
b8bf95b39952
parent 9
30e51941a673
equal deleted inserted replaced
13:1fdbf4170ef4 14:b8bf95b39952
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
5 *
6 * THE BSD LICENSE
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * Neither the name of the nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * shexp.c: shell-like wildcard match routines
36 *
37 *
38 * See shexp.h for public documentation.
39 *
40 * Rob McCool
41 *
42 */
43
44 #include <ctype.h> /* isalpha, tolower */
45
46 #include "shexp.h"
47
48
49 /*
50 * The observant engineer will notice 2 distinct sets of functions here.
51 * All of the noicmp flavor of functions do case sensitive compares on all
52 * platforms. The other set (public set) does case insensitive compares on NT.
53 */
54 int _shexp_match_noicmp(const char *str, const char *exp) ;
55
56
57 /* ----------------------------- shexp_valid ------------------------------ */
58
59
60 int valid_subexp(const char *exp, char stop)
61 {
62 register int x,y,t;
63 int nsc,np,tld;
64
65 x=0;nsc=0;tld=0;
66
67 while(exp[x] && (exp[x] != stop)) {
68 switch(exp[x]) {
69 case '~':
70 if(tld) return INVALID_SXP;
71 else ++tld;
72 case '*':
73 case '?':
74 case '^':
75 case '$':
76 ++nsc;
77 break;
78 case '[':
79 ++nsc;
80 if((!exp[++x]) || (exp[x] == ']'))
81 return INVALID_SXP;
82 for(++x;exp[x] && (exp[x] != ']');++x)
83 if(exp[x] == '\\')
84 if(!exp[++x])
85 return INVALID_SXP;
86 if(!exp[x])
87 return INVALID_SXP;
88 break;
89 case '(':
90 ++nsc;
91 while(1) {
92 if(exp[++x] == ')')
93 return INVALID_SXP;
94 for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
95 if(exp[y] == '\\')
96 if(!exp[++y])
97 return INVALID_SXP;
98 if(!exp[y])
99 return INVALID_SXP;
100 t = valid_subexp(&exp[x],exp[y]);
101 if(t == INVALID_SXP)
102 return INVALID_SXP;
103 x+=t;
104 if(exp[x] == ')') {
105 break;
106 }
107 }
108 break;
109 case ')':
110 case ']':
111 return INVALID_SXP;
112 case '\\':
113 if(!exp[++x])
114 return INVALID_SXP;
115 default:
116 break;
117 }
118 ++x;
119 }
120 if((!stop) && (!nsc))
121 return NON_SXP;
122 return ((exp[x] == stop) ? x : INVALID_SXP);
123 }
124
125 NSAPI_PUBLIC int shexp_valid(const char *exp) {
126 int x;
127
128 x = valid_subexp(exp, '\0');
129 if (x < 0) {
130 if (x == INVALID_SXP) {
131 //NsprError::setError(PR_INVALID_ARGUMENT_ERROR,
132 // XP_GetAdminStr(DBT_invalidshexp));
133 // TODO
134 }
135 return x;
136 }
137 return VALID_SXP;
138 }
139
140
141 /* ----------------------------- shexp_match ----------------------------- */
142
143
144 #define MATCH 0
145 #define NOMATCH 1
146 #define ABORTED -1
147
148 int _shexp_match(const char *str, const char *exp);
149
150 int handle_union(const char *str, const char *exp)
151 {
152 char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
153 register int t,p2,p1 = 1;
154 int cp;
155
156 while(1) {
157 for(cp=1;exp[cp] != ')';cp++)
158 if(exp[cp] == '\\')
159 ++cp;
160 for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
161 if(exp[p1] == '\\')
162 e2[p2++] = exp[p1++];
163 e2[p2] = exp[p1];
164 }
165 for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
166 if(_shexp_match(str,e2) == MATCH) {
167 FREE(e2);
168 return MATCH;
169 }
170 if(p1 == cp) {
171 FREE(e2);
172 return NOMATCH;
173 }
174 else ++p1;
175 }
176 }
177
178 int handle_union_noicmp(const char *str, const char *exp)
179 {
180 char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
181 register int t,p2,p1 = 1;
182 int cp;
183
184 while(1) {
185 for(cp=1;exp[cp] != ')';cp++)
186 if(exp[cp] == '\\')
187 ++cp;
188 for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
189 if(exp[p1] == '\\')
190 e2[p2++] = exp[p1++];
191 e2[p2] = exp[p1];
192 }
193 for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
194 if(_shexp_match_noicmp(str,e2) == MATCH) {
195 FREE(e2);
196 return MATCH;
197 }
198 if(p1 == cp) {
199 FREE(e2);
200 return NOMATCH;
201 }
202 else ++p1;
203 }
204 }
205
206 int _shexp_match(const char *str, const char *exp)
207 {
208 register int x,y;
209 int ret,neg;
210
211 ret = 0;
212 for(x=0,y=0;exp[y];++y,++x) {
213 if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
214 ret = ABORTED;
215 else {
216 switch(exp[y]) {
217 case '$':
218 if( (str[x]) )
219 ret = NOMATCH;
220 else
221 --x; /* we don't want loop to increment x */
222 break;
223 case '*':
224 while(exp[++y] == '*');
225 if(!exp[y])
226 return MATCH;
227 while(str[x]) {
228 switch(_shexp_match(&str[x++],&exp[y])) {
229 case NOMATCH:
230 continue;
231 case ABORTED:
232 ret = ABORTED;
233 break;
234 default:
235 return MATCH;
236 }
237 break;
238 }
239 if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
240 return MATCH;
241 else
242 ret = ABORTED;
243 break;
244 case '[':
245 if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
246 ++y;
247
248 if((isalnum(exp[y])) && (exp[y+1] == '-') &&
249 (isalnum(exp[y+2])) && (exp[y+3] == ']'))
250 {
251 int start = exp[y], end = exp[y+2];
252
253 /* Droolproofing for pinheads not included */
254 if(neg ^ ((str[x] < start) || (str[x] > end))) {
255 ret = NOMATCH;
256 break;
257 }
258 y+=3;
259 }
260 else {
261 int matched;
262
263 for(matched=0;exp[y] != ']';y++)
264 matched |= (str[x] == exp[y]);
265 if(neg ^ (!matched))
266 ret = NOMATCH;
267 }
268 break;
269 case '(':
270 return handle_union(&str[x],&exp[y]);
271 break;
272 case '?':
273 break;
274 case '\\':
275 ++y;
276 default:
277 #ifdef XP_UNIX
278 if(str[x] != exp[y])
279 #else /* XP_WIN32 */
280 if(strnicmp(str + x, exp + y, 1))
281 #endif /* XP_WIN32 */
282 ret = NOMATCH;
283 break;
284 }
285 }
286 if(ret)
287 break;
288 }
289 return (ret ? ret : (str[x] ? NOMATCH : MATCH));
290 }
291
292 int _shexp_match_noicmp(const char *str, const char *exp)
293 {
294 register int x,y;
295 int ret,neg;
296
297 ret = 0;
298 for(x=0,y=0;exp[y];++y,++x) {
299 if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
300 ret = ABORTED;
301 else {
302 switch(exp[y]) {
303 case '$':
304 if( (str[x]) )
305 ret = NOMATCH;
306 else
307 --x; /* we don't want loop to increment x */
308 break;
309 case '*':
310 while(exp[++y] == '*');
311 if(!exp[y])
312 return MATCH;
313 while(str[x]) {
314 switch(_shexp_match_noicmp(&str[x++],&exp[y])) {
315 case NOMATCH:
316 continue;
317 case ABORTED:
318 ret = ABORTED;
319 break;
320 default:
321 return MATCH;
322 }
323 break;
324 }
325 if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
326 return MATCH;
327 else
328 ret = ABORTED;
329 break;
330 case '[':
331 if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
332 ++y;
333
334 if((isalnum(exp[y])) && (exp[y+1] == '-') &&
335 (isalnum(exp[y+2])) && (exp[y+3] == ']'))
336 {
337 int start = exp[y], end = exp[y+2];
338
339 /* Droolproofing for pinheads not included */
340 if(neg ^ ((str[x] < start) || (str[x] > end))) {
341 ret = NOMATCH;
342 break;
343 }
344 y+=3;
345 }
346 else {
347 int matched;
348
349 for(matched=0;exp[y] != ']';y++)
350 matched |= (str[x] == exp[y]);
351 if(neg ^ (!matched))
352 ret = NOMATCH;
353 }
354 break;
355 case '(':
356 return handle_union_noicmp(&str[x],&exp[y]);
357 break;
358 case '?':
359 break;
360 case '\\':
361 ++y;
362 default:
363 if(str[x] != exp[y])
364 ret = NOMATCH;
365 break;
366 }
367 }
368 if(ret)
369 break;
370 }
371 return (ret ? ret : (str[x] ? NOMATCH : MATCH));
372 }
373
374 NSAPI_PUBLIC int shexp_match(const char *str, const char *exp)
375 {
376 register int x;
377 char *expbase = NULL;
378
379 for(x=strlen(exp)-1;x;--x) {
380 if((exp[x] == '~') && (exp[x-1] != '\\')) {
381 /* we're done if the negative subexp matches */
382 if(_shexp_match(str,&exp[x+1]) == MATCH)
383 return 1;
384 /* we're done if the only thing in front of the subexp is '*' */
385 if (x == 1 && exp[0] == '*')
386 return 0;
387 /* create a copy so we can strip off the subexp */
388 expbase = STRDUP(exp);
389 expbase[x] = '\0';
390 exp = expbase;
391 break;
392 }
393 }
394 if(_shexp_match(str,exp) == MATCH) {
395 if (expbase)
396 FREE(expbase);
397 return 0;
398 }
399
400 if (expbase)
401 FREE(expbase);
402 return 1;
403 }
404
405 NSAPI_PUBLIC int shexp_match_noicmp(const char *str, const char *exp)
406 {
407 register int x;
408 char *expbase = NULL;
409
410 for(x=strlen(exp)-1;x;--x) {
411 if((exp[x] == '~') && (exp[x-1] != '\\')) {
412 /* we're done if the negative subexp matches */
413 if(_shexp_match_noicmp(str,&exp[x+1]) == MATCH)
414 return 1;
415 /* we're done if the only thing in front of the subexp is '*' */
416 if (x == 1 && exp[0] == '*')
417 return 0;
418 /* create a copy so we can strip off the subexp */
419 expbase = STRDUP(exp);
420 expbase[x] = '\0';
421 exp = expbase;
422 break;
423 }
424 }
425 if(_shexp_match_noicmp(str,exp) == MATCH) {
426 if (expbase)
427 FREE(expbase);
428 return 0;
429 }
430
431 if (expbase)
432 FREE(expbase);
433 return 1;
434 }
435
436 /* ------------------------------ shexp_cmp ------------------------------- */
437
438
439 NSAPI_PUBLIC int shexp_cmp(const char *str, const char *exp)
440 {
441 switch(shexp_valid(exp)) {
442 case INVALID_SXP:
443 return -1;
444 case NON_SXP:
445 #ifdef XP_UNIX
446 return (strcmp(exp,str) ? 1 : 0);
447 #else /* XP_WIN32 */
448 return (stricmp(exp,str) ? 1 : 0);
449 #endif /* XP_WIN32 */
450 default:
451 return shexp_match(str, exp);
452 }
453 }
454
455 /* ------------------------------ shexp_cmp ------------------------------- */
456
457 NSAPI_PUBLIC int shexp_noicmp(const char *str, const char *exp)
458 {
459 switch(shexp_valid(exp)) {
460 case INVALID_SXP:
461 return -1;
462 case NON_SXP:
463 return (strcmp(exp,str) ? 1 : 0);
464 default:
465 return shexp_match_noicmp(str, exp);
466 }
467 }
468
469 /* ---------------------------- shexp_casecmp ----------------------------- */
470
471
472 NSAPI_PUBLIC int shexp_casecmp(const char *str, const char *exp)
473 {
474 char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t;
475 int ret;
476
477 for(t = lstr; *t; t++)
478 if(isalpha(*t)) *t = tolower(*t);
479 for(t = lexp; *t; t++)
480 if(isalpha(*t)) *t = tolower(*t);
481
482 switch(shexp_valid(lexp)) {
483 case INVALID_SXP:
484 ret = -1;
485 break;
486 case NON_SXP:
487 ret = (strcmp(lexp, lstr) ? 1 : 0);
488 break;
489 default:
490 ret = shexp_match(lstr, lexp);
491 }
492 FREE(lstr);
493 FREE(lexp);
494 return ret;
495 }
496

mercurial