Changeset a43fbc95 in mainline
- Timestamp:
- 2011-07-01T21:51:00Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 06cb827
- Parents:
- 6b4c64a
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/fnmatch.c
r6b4c64a ra43fbc95 33 33 */ 34 34 35 // TODO: clean this up a bit 36 37 #include "stdbool.h" 38 #include "ctype.h" 39 #include "string.h" 40 #include "stdlib.h" 41 #include "assert.h" 42 35 43 #define LIBPOSIX_INTERNAL 36 44 … … 38 46 #include "fnmatch.h" 39 47 40 #include "stdlib.h"41 #include "string.h"42 #include "ctype.h"43 44 48 #define INVALID_PATTERN -1 45 49 … … 51 55 #define COLL_ELM_INVALID -1 52 56 57 /** Get collating element matching a string. 58 * 59 * @param str 60 * @return 61 */ 53 62 static _coll_elm_t _coll_elm_get(const char* str) 54 63 { … … 59 68 } 60 69 70 /** Get collating element matching a single character. 71 * 72 * @param c 73 * @return 74 */ 61 75 static _coll_elm_t _coll_elm_char(int c) 62 76 { … … 64 78 } 65 79 66 /** 80 /** Match collating element with a beginning of a string. 67 81 * 68 82 * @param elm 69 * @param pattern83 * @param str 70 84 * @return 0 if the element doesn't match, or the number of characters matched. 71 85 */ … … 143 157 { "alnum", isalnum }, 144 158 { "alpha", isalpha }, 145 { "blank", posix_isblank },146 { "cntrl", posix_iscntrl },159 { "blank", isblank }, 160 { "cntrl", iscntrl }, 147 161 { "digit", isdigit }, 148 { "graph", posix_isgraph },162 { "graph", isgraph }, 149 163 { "lower", islower }, 150 { "print", posix_isprint },151 { "punct", posix_ispunct },164 { "print", isprint }, 165 { "punct", ispunct }, 152 166 { "space", isspace }, 153 167 { "upper", isupper }, 154 { "xdigit", posix_isxdigit }168 { "xdigit", isxdigit } 155 169 }; 156 170 … … 158 172 { 159 173 const struct _char_class *class = elem; 160 return posix_strcmp((const char *) key, class->name);174 return strcmp((const char *) key, class->name); 161 175 } 162 176 … … 164 178 { 165 179 /* Search for class in the array of supported character classes. */ 166 const struct _char_class *class = posix_bsearch(cname, _char_classes,180 const struct _char_class *class = bsearch(cname, _char_classes, 167 181 sizeof(_char_classes) / sizeof(struct _char_class), 168 182 sizeof(struct _char_class), _class_compare); … … 324 338 const bool special_period = (flags & FNM_PERIOD) != 0; 325 339 const bool noescape = (flags & FNM_NOESCAPE) != 0; 340 const bool leading_dir = (flags & FNM_LEADING_DIR) != 0; 341 326 342 const char *s = *string; 327 343 const char *p = *pattern; 328 344 329 for (; *p != '*'; p++) { 345 while (*p != '*') { 346 /* Bracket expression. */ 330 347 if (*p == '[') { 331 /* Bracket expression. */332 348 int matched = _match_bracket_expr(&p, s, flags); 333 349 if (matched == 0) { … … 335 351 return false; 336 352 } 337 if (matched == INVALID_PATTERN) { 338 /* Fall through to match [ as an ordinary 339 * character. 340 */ 341 } else { 353 if (matched != INVALID_PATTERN) { 342 354 s += matched; 343 355 continue; 344 356 } 345 } 346 357 358 assert(matched == INVALID_PATTERN); 359 /* Fall through to match [ as an ordinary character. */ 360 } 361 362 /* Wildcard match. */ 347 363 if (*p == '?') { 348 /* Wildcard match. */ 349 if (*s == '\0' || (pathname && *s == '/') || 350 (special_period && pathname && *s == '.' && 351 *(s - 1) == '/')) { 364 if (*s == '\0') { 365 /* No character to match. */ 352 366 return false; 353 367 } 368 if (pathname && *s == '/') { 369 /* Slash must be matched explicitly. */ 370 return false; 371 } 372 if (special_period && pathname && 373 *s == '.' && *(s - 1) == '/') { 374 /* Initial period must be matched explicitly. */ 375 return false; 376 } 377 378 /* None of the above, match anything else. */ 354 379 p++; 355 380 s++; … … 362 387 } 363 388 389 if (*p == '\0') { 390 /* End of pattern, must match end of string or 391 * an end of subdirectory name (optional). 392 */ 393 394 if (*s == '\0' || (leading_dir && *s == '/')) { 395 break; 396 } 397 398 return false; 399 } 400 364 401 if (*p == *s) { 365 402 /* Exact match. */ 366 if (*s == '\0') { 367 break; 368 } 403 p++; 404 s++; 369 405 continue; 370 406 } … … 374 410 } 375 411 376 /* Entire pattern matched. */ 412 /* Entire sub-pattern matched. */ 413 414 /* postconditions */ 415 assert(*p == '\0' || *p == '*'); 416 assert(*p != '\0' || *s == '\0' || (leading_dir && *s == '/')); 417 377 418 *pattern = p; 378 419 *string = s; … … 382 423 static bool _full_match(const char *pattern, const char *string, int flags) 383 424 { 425 const bool pathname = (flags & FNM_PATHNAME) != 0; 384 426 const bool special_period = (flags & FNM_PERIOD) != 0; 427 const bool leading_dir = (flags & FNM_LEADING_DIR) != 0; 385 428 386 429 if (special_period && *string == '.') { … … 402 445 while (*pattern != '\0') { 403 446 assert(*pattern == '*'); 404 405 while (*pattern == '*') { 406 pattern++; 447 pattern++; 448 449 bool matched = false; 450 451 const char *end; 452 if (pathname && special_period && 453 *string == '.' && *(string - 1) == '/') { 454 end = string; 455 } else { 456 end= strchrnul(string, pathname ? '/' : '\0'); 407 457 } 408 458 409 459 /* Try to match every possible offset. */ 410 while ( *string != '\0') {460 while (string <= end) { 411 461 if (_partial_match(&pattern, &string, flags)) { 462 matched = true; 412 463 break; 413 464 } 414 465 string++; 415 466 } 416 } 417 418 return *string == '\0'; 467 468 if (matched) { 469 continue; 470 } 471 472 return false; 473 } 474 475 return *string == '\0' || (leading_dir && *string == '/'); 476 } 477 478 static char *_casefold(const char *s) 479 { 480 char *result = strdup(s); 481 for (char *i = result; *i != '\0'; ++i) { 482 *i = tolower(*i); 483 } 484 return result; 419 485 } 420 486 … … 429 495 int posix_fnmatch(const char *pattern, const char *string, int flags) 430 496 { 497 // TODO: don't fold everything in advance, but only when needed 498 499 if ((flags & FNM_CASEFOLD) != 0) { 500 /* Just fold the entire pattern and string. */ 501 pattern = _casefold(pattern); 502 string = _casefold(string); 503 } 504 431 505 bool result = _full_match(pattern, string, flags); 506 507 if ((flags & FNM_CASEFOLD) != 0) { 508 free((char *) pattern); 509 free((char *) string); 510 } 511 432 512 return result ? 0 : FNM_NOMATCH; 433 513 } 434 514 515 // FIXME: put the testcases somewhere else 516 517 #if 0 518 519 #include <stdio.h> 520 521 void __posix_fnmatch_test() 522 { 523 int fail = 0; 524 525 #undef assert 526 #define assert(x) { if (x) printf("SUCCESS: "#x"\n"); else { printf("FAILED: "#x"\n"); fail++; } } 527 #define match(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == 0) 528 #define nomatch(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == FNM_NOMATCH) 529 530 assert(FNM_PATHNAME == FNM_FILE_NAME); 531 match("", "", 0); 532 match("*", "hello", 0); 533 match("hello", "hello", 0); 534 match("hello*", "hello", 0); 535 nomatch("hello?", "hello", 0); 536 match("*hello", "prdel hello", 0); 537 match("he[sl]lo", "hello", 0); 538 match("he[sl]lo", "heslo", 0); 539 nomatch("he[sl]lo", "heblo", 0); 540 nomatch("he[^sl]lo", "hello", 0); 541 nomatch("he[^sl]lo", "heslo", 0); 542 match("he[^sl]lo", "heblo", 0); 543 nomatch("he[!sl]lo", "hello", 0); 544 nomatch("he[!sl]lo", "heslo", 0); 545 match("he[!sl]lo", "heblo", 0); 546 match("al*[c-t]a*vis*ta", "alheimer talir jehovista", 0); 547 match("al*[c-t]a*vis*ta", "alfons had jehovista", 0); 548 match("[a-ce-z]", "a", 0); 549 match("[a-ce-z]", "c", 0); 550 nomatch("[a-ce-z]", "d", 0); 551 match("[a-ce-z]", "e", 0); 552 match("[a-ce-z]", "z", 0); 553 nomatch("[^a-ce-z]", "a", 0); 554 nomatch("[^a-ce-z]", "c", 0); 555 match("[^a-ce-z]", "d", 0); 556 nomatch("[^a-ce-z]", "e", 0); 557 nomatch("[^a-ce-z]", "z", 0); 558 match("helen??", "helenos", 0); 559 match("****booo****", "booo", 0); 560 561 match("hello[[:space:]]world", "hello world", 0); 562 nomatch("hello[[:alpha:]]world", "hello world", 0); 563 564 match("/hoooo*", "/hooooooo/hooo", 0); 565 nomatch("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME); 566 nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME); 567 match("/hoooo*/*", "/hooooooo/hooo", FNM_PATHNAME); 568 match("/hoooo*/hooo", "/hooooooo/hooo", FNM_PATHNAME); 569 match("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR); 570 nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR); 571 nomatch("/hoooo", "/hooooooo/hooo", FNM_LEADING_DIR); 572 match("/hooooooo", "/hooooooo/hooo", FNM_LEADING_DIR); 573 574 match("*", "hell", 0); 575 match("*?", "hell", 0); 576 match("?*?", "hell", 0); 577 match("?*??", "hell", 0); 578 match("??*??", "hell", 0); 579 nomatch("???*??", "hell", 0); 580 581 nomatch("", "hell", 0); 582 nomatch("?", "hell", 0); 583 nomatch("??", "hell", 0); 584 nomatch("???", "hell", 0); 585 match("????", "hell", 0); 586 587 match("*", "h.ello", FNM_PERIOD); 588 match("*", "h.ello", FNM_PATHNAME | FNM_PERIOD); 589 nomatch("*", ".hello", FNM_PERIOD); 590 match("h?ello", "h.ello", FNM_PERIOD); 591 nomatch("?hello", ".hello", FNM_PERIOD); 592 match("/home/user/.*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD); 593 match("/home/user/*", "/home/user/.hello", FNM_PERIOD); 594 nomatch("/home/user/*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD); 595 596 nomatch("HeLlO", "hello", 0); 597 match("HeLlO", "hello", FNM_CASEFOLD); 598 599 printf("Failed: %d\n", fail); 600 } 601 602 #endif 603 435 604 /** @} 436 605 */
Note:
See TracChangeset
for help on using the changeset viewer.