UNIXworkcode

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 497