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