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