1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Guido van Rossum. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 /* 38 * glob(3) -- a superset of the one defined in POSIX 1003.2. 39 * 40 * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 41 * 42 * Optional extra services, controlled by flags not defined by POSIX: 43 * 44 * GLOB_QUOTE: 45 * Escaping convention: \ inhibits any special meaning the following 46 * character might have (except \ at end of string is retained). 47 * GLOB_MAGCHAR: 48 * Set in gl_flags if pattern contained a globbing character. 49 * GLOB_NOMAGIC: 50 * Same as GLOB_NOCHECK, but it will only append pattern if it did 51 * not contain any magic characters. [Used in csh style globbing] 52 * GLOB_ALTDIRFUNC: 53 * Use alternately specified directory access functions. 54 * GLOB_TILDE: 55 * expand ~user/foo to the /home/dir/of/user/foo 56 * GLOB_BRACE: 57 * expand {1,2}{a,b} to 1a 1b 2a 2b 58 * gl_matchc: 59 * Number of matches in the current invocation of glob. 60 */ 61 62 #include <sys/param.h> 63 #include <sys/stat.h> 64 65 #include <ctype.h> 66 #include <dirent.h> 67 #include <errno.h> 68 #include <glob.h> 69 #include <pwd.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <unistd.h> 74 75 //#include "collate.h" 76 77 #define DOLLAR '$' 78 #define DOT '.' 79 #define EOS '\0' 80 #define LBRACKET '[' 81 #define NOT '!' 82 #define QUESTION '?' 83 #define QUOTE '\\' 84 #define RANGE '-' 85 #define RBRACKET ']' 86 #define SEP '/' 87 #define STAR '*' 88 #define TILDE '~' 89 #define UNDERSCORE '_' 90 #define LBRACE '{' 91 #define RBRACE '}' 92 #define SLASH '/' 93 #define COMMA ',' 94 95 #ifndef DEBUG 96 97 #define M_QUOTE 0x8000 98 #define M_PROTECT 0x4000 99 #define M_MASK 0xffff 100 #define M_ASCII 0x00ff 101 102 typedef u_short Char; 103 104 #else 105 106 #define M_QUOTE 0x80 107 #define M_PROTECT 0x40 108 #define M_MASK 0xff 109 #define M_ASCII 0x7f 110 111 typedef char Char; 112 113 #endif 114 115 116 #define CHAR(c) ((Char)((c)&M_ASCII)) 117 #define META(c) ((Char)((c)|M_QUOTE)) 118 #define M_ALL META('*') 119 #define M_END META(']') 120 #define M_NOT META('!') 121 #define M_ONE META('?') 122 #define M_RNG META('-') 123 #define M_SET META('[') 124 #define ismeta(c) (((c)&M_QUOTE) != 0) 125 126 127 static int compare(const void *, const void *); 128 static int g_Ctoc(const Char *, char *, u_int); 129 static int g_lstat(Char *, struct stat *, glob_t *); 130 static DIR *g_opendir(Char *, glob_t *); 131 static Char *g_strchr(Char *, int); 132 #ifdef notdef 133 static Char *g_strcat(Char *, const Char *); 134 #endif 135 static int g_stat(Char *, struct stat *, glob_t *); 136 static int glob0(const Char *, glob_t *, int *); 137 static int glob1(Char *, glob_t *, int *); 138 static int glob2(Char *, Char *, Char *, Char *, glob_t *, int *); 139 static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *); 140 static int globextend(const Char *, glob_t *, int *); 141 static const Char * 142 globtilde(const Char *, Char *, size_t, glob_t *); 143 static int globexp1(const Char *, glob_t *, int *); 144 static int globexp2(const Char *, const Char *, glob_t *, int *, int *); 145 static int match(Char *, Char *, Char *); 146 #ifdef DEBUG 147 static void qprintf(const char *, Char *); 148 #endif 149 150 151 int 152 glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) 153 { 154 const u_char *patnext; 155 int c, limit; 156 Char *bufnext, *bufend, patbuf[MAXPATHLEN]; 157 158 patnext = (u_char *) pattern; 159 if (!(flags & GLOB_APPEND)) { 160 pglob->gl_pathc = 0; 161 pglob->gl_pathv = NULL; 162 if (!(flags & GLOB_DOOFFS)) 163 pglob->gl_offs = 0; 164 } 165 if (flags & GLOB_LIMIT) { 166 limit = pglob->gl_matchc; 167 if (limit == 0) 168 limit = ARG_MAX; 169 } else 170 limit = 0; 171 172 pglob->gl_flags = flags & ~GLOB_MAGCHAR; 173 pglob->gl_errfunc = errfunc; 174 pglob->gl_matchc = 0; 175 176 bufnext = patbuf; 177 bufend = bufnext + MAXPATHLEN - 1; 178 if (flags & GLOB_NOESCAPE) { 179 while (bufnext < bufend && (c = *patnext++) != EOS) 180 *bufnext++ = c; 181 } else { 182 /* Protect the quoted characters. */ 183 while (bufnext < bufend && (c = *patnext++) != EOS) 184 if (c == QUOTE) { 185 if ((c = *patnext++) == EOS) { 186 c = QUOTE; 187 --patnext; 188 } 189 *bufnext++ = c | M_PROTECT; 190 } 191 else 192 *bufnext++ = c; 193 } 194 *bufnext = EOS; 195 196 if (flags & GLOB_BRACE) 197 return globexp1(patbuf, pglob, &limit); 198 199 return glob0(patbuf, pglob, &limit); 200 } 201 202 203 /* 204 * Expand recursively a glob {} pattern. When there is no more expansion 205 * invoke the standard globbing routine to glob the rest of the magic 206 * characters 207 */ 208 209 static int 210 globexp1(const Char *pattern, glob_t *pglob, int *limit) 211 { 212 const Char* ptr = pattern; 213 int rv; 214 215 /* Protect a single {}, for find(1), like csh */ 216 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) 217 return glob0(pattern, pglob, limit); 218 219 while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) 220 if (!globexp2(ptr, pattern, pglob, &rv, limit)) 221 return rv; 222 223 return glob0(pattern, pglob, limit); 224 } 225 226 227 /* 228 * Recursive brace globbing helper. Tries to expand a single brace. 229 * If it succeeds then it invokes globexp1 with the new pattern. 230 * If it fails then it tries to glob the rest of the pattern and returns. 231 */ 232 233 static int 234 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, int *limit) 235 { 236 int i; 237 Char *lm, *ls; 238 const Char *pe, *pm, *pl; 239 Char patbuf[MAXPATHLEN]; 240 241 /* copy part up to the brace */ 242 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 243 continue; 244 *lm = EOS; 245 ls = lm; 246 247 /* Find the balanced brace */ 248 for (i = 0, pe = ++ptr; *pe; pe++) { 249 if (*pe == LBRACKET) { 250 /* Ignore everything between [] */ 251 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) 252 continue; 253 if (*pe == EOS) { 254 /* 255 * We could not find a matching RBRACKET. 256 * Ignore and just look for RBRACE 257 */ 258 pe = pm; 259 } 260 } 261 else if (*pe == LBRACE) 262 i++; 263 else if (*pe == RBRACE) { 264 if (i == 0) 265 break; 266 i--; 267 } 268 } 269 270 /* Non matching braces; just glob the pattern */ 271 if (i != 0 || *pe == EOS) { 272 *rv = glob0(patbuf, pglob, limit); 273 return 0; 274 } 275 276 for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 277 switch (*pm) { 278 case LBRACKET: 279 /* Ignore everything between [] */ 280 for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) 281 continue; 282 if (*pm == EOS) { 283 /* 284 * We could not find a matching RBRACKET. 285 * Ignore and just look for RBRACE 286 */ 287 pm = pl; 288 } 289 break; 290 291 case LBRACE: 292 i++; 293 break; 294 295 case RBRACE: 296 if (i) { 297 i--; 298 break; 299 } 300 /* FALLTHROUGH */ 301 case COMMA: 302 if (i && *pm == COMMA) 303 break; 304 else { 305 /* Append the current string */ 306 for (lm = ls; (pl < pm); *lm++ = *pl++) 307 continue; 308 /* 309 * Append the rest of the pattern after the 310 * closing brace 311 */ 312 for (pl = pe + 1; (*lm++ = *pl++) != EOS;) 313 continue; 314 315 /* Expand the current pattern */ 316 #ifdef DEBUG 317 qprintf("globexp2:", patbuf); 318 #endif 319 *rv = globexp1(patbuf, pglob, limit); 320 321 /* move after the comma, to the next string */ 322 pl = pm + 1; 323 } 324 break; 325 326 default: 327 break; 328 } 329 } 330 331 *rv = 0; 332 return 0; 333 } 334 335 336 /* 337 * expand tilde from the passwd file. 338 */ 339 340 static const Char * 341 globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) 342 { 343 struct passwd *pwd; 344 char *h; 345 const Char *p; 346 Char *b, *eb; 347 348 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) 349 return pattern; 350 351 /* 352 * Copy up to the end of the string or / 353 */ 354 eb = &patbuf[patbuf_len - 1]; 355 for (p = pattern + 1, h = (char *) patbuf; 356 h < (char *)eb && *p && *p != SLASH; *h++ = *p++) 357 continue; 358 359 *h = EOS; 360 361 if (((char *) patbuf)[0] == EOS) { 362 /* 363 * handle a plain ~ or ~/ by expanding $HOME first (iff 364 * we're not running setuid or setgid) and then trying 365 * the password file 366 */ 367 if ( 368 //#ifndef __NETBSD_SYSCALLS 369 // issetugid() != 0 || 370 //#endif 371 (h = getenv("HOME")) == NULL) { 372 if (((h = getlogin()) != NULL && 373 (pwd = getpwnam(h)) != NULL) || 374 (pwd = getpwuid(getuid())) != NULL) 375 h = pwd->pw_dir; 376 else 377 return pattern; 378 } 379 } 380 else { 381 /* 382 * Expand a ~user 383 */ 384 if ((pwd = getpwnam((char*) patbuf)) == NULL) 385 return pattern; 386 else 387 h = pwd->pw_dir; 388 } 389 390 /* Copy the home directory */ 391 for (b = patbuf; b < eb && *h; *b++ = *h++) 392 continue; 393 394 /* Append the rest of the pattern */ 395 while (b < eb && (*b++ = *p++) != EOS) 396 continue; 397 *b = EOS; 398 399 return patbuf; 400 } 401 402 403 /* 404 * The main glob() routine: compiles the pattern (optionally processing 405 * quotes), calls glob1() to do the real pattern matching, and finally 406 * sorts the list (unless unsorted operation is requested). Returns 0 407 * if things went well, nonzero if errors occurred. 408 */ 409 410 static int 411 glob0(const Char *pattern, glob_t *pglob, int *limit) 412 { 413 const Char *qpatnext; 414 int c, err, oldpathc; 415 Char *bufnext, patbuf[MAXPATHLEN]; 416 417 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); 418 oldpathc = pglob->gl_pathc; 419 bufnext = patbuf; 420 421 /* We don't need to check for buffer overflow any more. */ 422 while ((c = *qpatnext++) != EOS) { 423 switch (c) { 424 case LBRACKET: 425 c = *qpatnext; 426 if (c == NOT) 427 ++qpatnext; 428 if (*qpatnext == EOS || 429 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { 430 *bufnext++ = LBRACKET; 431 if (c == NOT) 432 --qpatnext; 433 break; 434 } 435 *bufnext++ = M_SET; 436 if (c == NOT) 437 *bufnext++ = M_NOT; 438 c = *qpatnext++; 439 do { 440 *bufnext++ = CHAR(c); 441 if (*qpatnext == RANGE && 442 (c = qpatnext[1]) != RBRACKET) { 443 *bufnext++ = M_RNG; 444 *bufnext++ = CHAR(c); 445 qpatnext += 2; 446 } 447 } while ((c = *qpatnext++) != RBRACKET); 448 pglob->gl_flags |= GLOB_MAGCHAR; 449 *bufnext++ = M_END; 450 break; 451 case QUESTION: 452 pglob->gl_flags |= GLOB_MAGCHAR; 453 *bufnext++ = M_ONE; 454 break; 455 case STAR: 456 pglob->gl_flags |= GLOB_MAGCHAR; 457 /* collapse adjacent stars to one, 458 * to avoid exponential behavior 459 */ 460 if (bufnext == patbuf || bufnext[-1] != M_ALL) 461 *bufnext++ = M_ALL; 462 break; 463 default: 464 *bufnext++ = CHAR(c); 465 break; 466 } 467 } 468 *bufnext = EOS; 469 #ifdef DEBUG 470 qprintf("glob0:", patbuf); 471 #endif 472 473 if ((err = glob1(patbuf, pglob, limit)) != 0) 474 return(err); 475 476 /* 477 * If there was no match we are going to append the pattern 478 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 479 * and the pattern did not contain any magic characters 480 * GLOB_NOMAGIC is there just for compatibility with csh. 481 */ 482 if (pglob->gl_pathc == oldpathc) { 483 if (((pglob->gl_flags & GLOB_NOCHECK) || 484 ((pglob->gl_flags & GLOB_NOMAGIC) && 485 !(pglob->gl_flags & GLOB_MAGCHAR)))) 486 return globextend(pattern, pglob, limit); 487 else 488 return GLOB_NOMATCH; 489 } 490 if (!(pglob->gl_flags & GLOB_NOSORT)) 491 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 492 pglob->gl_pathc - oldpathc, sizeof(char *), compare); 493 return 0; 494 } 495 496 497 static int 498 compare(const void *p, const void *q) 499 { 500 return strcmp(*(char **)p, *(char **)q); 501 } 502 503 504 static int 505 glob1(Char *pattern, glob_t *pglob, int *limit) 506 { 507 Char pathbuf[MAXPATHLEN]; 508 509 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 510 if (*pattern == EOS) 511 return 0; 512 513 return glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, 514 pattern, pglob, limit); 515 } 516 517 518 /* 519 * The functions glob2 and glob3 are mutually recursive; there is one level 520 * of recursion for each segment in the pattern that contains one or more 521 * meta characters. 522 */ 523 524 static int 525 glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, glob_t *pglob, int *limit) 526 { 527 struct stat sb; 528 Char *p, *q; 529 int anymeta; 530 531 /* 532 * Loop over pattern segments until end of pattern or until 533 * segment with meta character found. 534 */ 535 for (anymeta = 0;;) { 536 if (*pattern == EOS) { /* End of pattern? */ 537 *pathend = EOS; 538 if (g_lstat(pathbuf, &sb, pglob)) 539 return(0); 540 541 if (((pglob->gl_flags & GLOB_MARK) && 542 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) 543 || (S_ISLNK(sb.st_mode) && 544 (g_stat(pathbuf, &sb, pglob) == 0) && 545 S_ISDIR(sb.st_mode)))) { 546 if (pathend + 1 > pathend_last) 547 return GLOB_ABORTED; 548 *pathend++ = SEP; 549 *pathend = EOS; 550 } 551 ++pglob->gl_matchc; 552 return globextend(pathbuf, pglob, limit); 553 } 554 555 /* Find end of next segment, copy tentatively to pathend. */ 556 q = pathend; 557 p = pattern; 558 while (*p != EOS && *p != SEP) { 559 if (ismeta(*p)) 560 anymeta = 1; 561 if (q + 1 > pathend_last) 562 return GLOB_ABORTED; 563 *q++ = *p++; 564 } 565 566 if (!anymeta) { /* No expansion, do next segment. */ 567 pathend = q; 568 pattern = p; 569 while (*pattern == SEP) { 570 if (pathend + 1 > pathend_last) 571 return GLOB_ABORTED; 572 *pathend++ = *pattern++; 573 } 574 } else /* Need expansion, recurse. */ 575 return glob3(pathbuf, pathend, pathend_last, pattern, p, pglob, limit); 576 } 577 /* NOTREACHED */ 578 } 579 580 581 static int 582 glob3(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, Char *restpattern, 583 glob_t *pglob, int *limit) 584 { 585 struct dirent *dp; 586 DIR *dirp; 587 int err; 588 char buf[MAXPATHLEN]; 589 590 /* 591 * The readdirfunc declaration can't be prototyped, because it is 592 * assigned, below, to two functions which are prototyped in glob.h 593 * and dirent.h as taking pointers to differently typed opaque 594 * structures. 595 */ 596 struct dirent *(*readdirfunc)(); 597 598 if (pathend > pathend_last) 599 return GLOB_ABORTED; 600 *pathend = EOS; 601 errno = 0; 602 603 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 604 /* TODO: don't call for ENOENT or ENOTDIR? */ 605 if (pglob->gl_errfunc) { 606 if (g_Ctoc(pathbuf, buf, sizeof(buf))) 607 return GLOB_ABORTED; 608 if (pglob->gl_errfunc(buf, errno) || 609 pglob->gl_flags & GLOB_ERR) 610 return GLOB_ABORTED; 611 } 612 return 0; 613 } 614 615 err = 0; 616 617 /* Search directory for matching names. */ 618 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 619 readdirfunc = pglob->gl_readdir; 620 else 621 readdirfunc = readdir; 622 623 while ((dp = (*readdirfunc)(dirp))) { 624 u_char *sc; 625 Char *dc; 626 627 /* Initial DOT must be matched literally. */ 628 if (dp->d_name[0] == DOT && *pattern != DOT) 629 continue; 630 dc = pathend; 631 sc = (u_char *) dp->d_name; 632 while (dc < pathend_last && (*dc++ = *sc++) != EOS) 633 ; 634 if (!match(pathend, pattern, restpattern)) { 635 *pathend = EOS; 636 continue; 637 } 638 err = glob2(pathbuf, --dc, pathend_last, restpattern, 639 pglob, limit); 640 if (err) 641 break; 642 } 643 644 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 645 (*pglob->gl_closedir)(dirp); 646 else 647 closedir(dirp); 648 649 return err; 650 } 651 652 653 /* 654 * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 655 * add the new item, and update gl_pathc. 656 * 657 * This assumes the BSD realloc, which only copies the block when its size 658 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 659 * behavior. 660 * 661 * Return 0 if new item added, error code if memory couldn't be allocated. 662 * 663 * Invariant of the glob_t structure: 664 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 665 * gl_pathv points to (gl_offs + gl_pathc + 1) items. 666 */ 667 668 static int 669 globextend(const Char *path, glob_t *pglob, int *limit) 670 { 671 char **pathv; 672 int i; 673 u_int newsize, len; 674 char *copy; 675 const Char *p; 676 677 if (*limit && pglob->gl_pathc > *limit) { 678 errno = 0; 679 return GLOB_NOSPACE; 680 } 681 682 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 683 pathv = pglob->gl_pathv ? 684 realloc((char *)pglob->gl_pathv, newsize) : 685 malloc(newsize); 686 if (pathv == NULL) { 687 if (pglob->gl_pathv) { 688 free(pglob->gl_pathv); 689 pglob->gl_pathv = NULL; 690 } 691 return GLOB_NOSPACE; 692 } 693 694 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 695 /* first time around -- clear initial gl_offs items */ 696 pathv += pglob->gl_offs; 697 for (i = pglob->gl_offs; --i >= 0; ) 698 *--pathv = NULL; 699 } 700 pglob->gl_pathv = pathv; 701 702 for (p = path; *p++;) 703 continue; 704 len = (size_t)(p - path); 705 if ((copy = malloc(len)) != NULL) { 706 if (g_Ctoc(path, copy, len)) { 707 free(copy); 708 return GLOB_NOSPACE; 709 } 710 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 711 } 712 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 713 return copy == NULL ? GLOB_NOSPACE : 0; 714 } 715 716 717 /* 718 * pattern matching function for filenames. Each occurrence of the * 719 * pattern causes a recursion level. 720 */ 721 722 static int 723 match(Char *name, Char *pat, Char *patend) 724 { 725 int ok, negate_range; 726 Char c, k; 727 728 while (pat < patend) { 729 c = *pat++; 730 switch (c & M_MASK) { 731 case M_ALL: 732 if (pat == patend) 733 return 1; 734 do 735 if (match(name, pat, patend)) 736 return 1; 737 while (*name++ != EOS); 738 return 0; 739 case M_ONE: 740 if (*name++ == EOS) 741 return 0; 742 break; 743 case M_SET: 744 ok = 0; 745 if ((k = *name++) == EOS) 746 return 0; 747 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) 748 ++pat; 749 while (((c = *pat++) & M_MASK) != M_END) 750 if ((*pat & M_MASK) == M_RNG) { 751 // ToDo: collate stuff disabled 752 if ( 753 // __collate_load_error ? 754 CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) 755 // : __collate_range_cmp(CHAR(c), CHAR(k)) <= 0 756 // && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0 757 ) 758 ok = 1; 759 pat += 2; 760 } else if (c == k) 761 ok = 1; 762 if (ok == negate_range) 763 return 0; 764 break; 765 default: 766 if (*name++ != c) 767 return 0; 768 break; 769 } 770 } 771 return *name == EOS; 772 } 773 774 775 /* Free allocated data belonging to a glob_t structure. */ 776 777 void 778 globfree(glob_t *pglob) 779 { 780 int i; 781 char **pp; 782 783 if (pglob->gl_pathv != NULL) { 784 pp = pglob->gl_pathv + pglob->gl_offs; 785 for (i = pglob->gl_pathc; i--; ++pp) 786 if (*pp) 787 free(*pp); 788 free(pglob->gl_pathv); 789 pglob->gl_pathv = NULL; 790 } 791 } 792 793 794 static DIR * 795 g_opendir(Char *str, glob_t *pglob) 796 { 797 char buf[MAXPATHLEN]; 798 799 if (!*str) 800 strcpy(buf, "."); 801 else { 802 if (g_Ctoc(str, buf, sizeof(buf))) 803 return NULL; 804 } 805 806 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 807 return (*pglob->gl_opendir)(buf); 808 809 return opendir(buf); 810 } 811 812 813 static int 814 g_lstat(Char *fn, struct stat *sb, glob_t *pglob) 815 { 816 char buf[MAXPATHLEN]; 817 818 if (g_Ctoc(fn, buf, sizeof(buf))) { 819 errno = ENAMETOOLONG; 820 return -1; 821 } 822 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 823 return (*pglob->gl_lstat)(buf, sb); 824 825 return lstat(buf, sb); 826 } 827 828 829 static int 830 g_stat(Char *fn, struct stat *sb, glob_t *pglob) 831 { 832 char buf[MAXPATHLEN]; 833 834 if (g_Ctoc(fn, buf, sizeof(buf))) { 835 errno = ENAMETOOLONG; 836 return -1; 837 } 838 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 839 return (*pglob->gl_stat)(buf, sb); 840 841 return stat(buf, sb); 842 } 843 844 845 static Char * 846 g_strchr(Char *str, int ch) 847 { 848 do { 849 if (*str == ch) 850 return str; 851 } while (*str++); 852 853 return NULL; 854 } 855 856 857 static int 858 g_Ctoc(const Char *str, char *buf, u_int len) 859 { 860 861 while (len--) { 862 if ((*buf++ = *str++) == '\0') 863 return 0; 864 } 865 return 1; 866 } 867 868 869 #ifdef DEBUG 870 static void 871 qprintf(const char *str, Char *s) 872 { 873 Char *p; 874 875 printf("%s:\n", str); 876 for (p = s; *p; p++) 877 printf("%c", CHAR(*p)); 878 printf("\n"); 879 for (p = s; *p; p++) 880 printf("%c", *p & M_PROTECT ? '"' : ' '); 881 printf("\n"); 882 for (p = s; *p; p++) 883 printf("%c", ismeta(*p) ? '_' : ' '); 884 printf("\n"); 885 } 886 #endif 887