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. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #if defined(LIBC_SCCS) && !defined(lint) 34 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; 35 /* most changes between the version above and the one below have been ported: 36 static char sscsid[]= "$OpenBSD: glob.c,v 1.8.10.1 2001/04/10 jason Exp $"; 37 */ 38 #endif /* LIBC_SCCS and not lint */ 39 40 /* 41 * glob(3) -- a superset of the one defined in POSIX 1003.2. 42 * 43 * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 44 * 45 * Optional extra services, controlled by flags not defined by POSIX: 46 * 47 * GLOB_QUOTE: 48 * Escaping convention: \ inhibits any special meaning the following 49 * character might have (except \ at end of string is retained). 50 * GLOB_MAGCHAR: 51 * Set in gl_flags if pattern contained a globbing character. 52 * GLOB_NOMAGIC: 53 * Same as GLOB_NOCHECK, but it will only append pattern if it did 54 * not contain any magic characters. [Used in csh style globbing] 55 * GLOB_ALTDIRFUNC: 56 * Use alternately specified directory access functions. 57 * GLOB_TILDE: 58 * expand ~user/foo to the /home/dir/of/user/foo 59 * GLOB_BRACE: 60 * expand {1,2}{a,b} to 1a 1b 2a 2b 61 * gl_matchc: 62 * Number of matches in the current invocation of glob. 63 * GLOB_ALPHASORT: 64 * sort alphabetically like csh (case doesn't matter) instead of in ASCII 65 * order 66 */ 67 68 #include <EXTERN.h> 69 #include <perl.h> 70 #include <XSUB.h> 71 72 #include "bsd_glob.h" 73 #ifdef I_PWD 74 # include <pwd.h> 75 #else 76 #if defined(HAS_PASSWD) && !defined(VMS) 77 struct passwd *getpwnam(char *); 78 struct passwd *getpwuid(Uid_t); 79 #endif 80 #endif 81 82 #ifndef MAXPATHLEN 83 # ifdef PATH_MAX 84 # define MAXPATHLEN PATH_MAX 85 # ifdef MACOS_TRADITIONAL 86 # define MAXPATHLEN 255 87 # else 88 # define MAXPATHLEN 1024 89 # endif 90 # endif 91 #endif 92 93 #ifdef I_LIMITS 94 #include <limits.h> 95 #endif 96 97 #ifndef ARG_MAX 98 # ifdef MACOS_TRADITIONAL 99 # define ARG_MAX 65536 /* Mac OS is actually unlimited */ 100 # else 101 # ifdef _SC_ARG_MAX 102 # define ARG_MAX (sysconf(_SC_ARG_MAX)) 103 # else 104 # ifdef _POSIX_ARG_MAX 105 # define ARG_MAX _POSIX_ARG_MAX 106 # else 107 # ifdef WIN32 108 # define ARG_MAX 14500 /* from VC's limits.h */ 109 # else 110 # define ARG_MAX 4096 /* from POSIX, be conservative */ 111 # endif 112 # endif 113 # endif 114 # endif 115 #endif 116 117 #define BG_DOLLAR '$' 118 #define BG_DOT '.' 119 #define BG_EOS '\0' 120 #define BG_LBRACKET '[' 121 #define BG_NOT '!' 122 #define BG_QUESTION '?' 123 #define BG_QUOTE '\\' 124 #define BG_RANGE '-' 125 #define BG_RBRACKET ']' 126 #ifdef MACOS_TRADITIONAL 127 # define BG_SEP ':' 128 #else 129 # define BG_SEP '/' 130 #endif 131 #ifdef DOSISH 132 #define BG_SEP2 '\\' 133 #endif 134 #define BG_STAR '*' 135 #define BG_TILDE '~' 136 #define BG_UNDERSCORE '_' 137 #define BG_LBRACE '{' 138 #define BG_RBRACE '}' 139 #define BG_SLASH '/' 140 #define BG_COMMA ',' 141 142 #ifndef GLOB_DEBUG 143 144 #define M_QUOTE 0x8000 145 #define M_PROTECT 0x4000 146 #define M_MASK 0xffff 147 #define M_ASCII 0x00ff 148 149 typedef U16 Char; 150 151 #else 152 153 #define M_QUOTE 0x80 154 #define M_PROTECT 0x40 155 #define M_MASK 0xff 156 #define M_ASCII 0x7f 157 158 typedef U8 Char; 159 160 #endif /* !GLOB_DEBUG */ 161 162 163 #define CHAR(c) ((Char)((c)&M_ASCII)) 164 #define META(c) ((Char)((c)|M_QUOTE)) 165 #define M_ALL META('*') 166 #define M_END META(']') 167 #define M_NOT META('!') 168 #define M_ONE META('?') 169 #define M_RNG META('-') 170 #define M_SET META('[') 171 #define ismeta(c) (((c)&M_QUOTE) != 0) 172 173 174 static int compare(const void *, const void *); 175 static int ci_compare(const void *, const void *); 176 static int g_Ctoc(const Char *, char *, STRLEN); 177 static int g_lstat(Char *, Stat_t *, glob_t *); 178 static DIR *g_opendir(Char *, glob_t *); 179 static Char *g_strchr(Char *, int); 180 static int g_stat(Char *, Stat_t *, glob_t *); 181 static int glob0(const Char *, glob_t *); 182 static int glob1(Char *, Char *, glob_t *, size_t *); 183 static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, 184 glob_t *, size_t *); 185 static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, 186 Char *, Char *, glob_t *, size_t *); 187 static int globextend(const Char *, glob_t *, size_t *); 188 static const Char * 189 globtilde(const Char *, Char *, size_t, glob_t *); 190 static int globexp1(const Char *, glob_t *); 191 static int globexp2(const Char *, const Char *, glob_t *, int *); 192 static int match(Char *, Char *, Char *, int); 193 #ifdef GLOB_DEBUG 194 static void qprintf(const char *, Char *); 195 #endif /* GLOB_DEBUG */ 196 197 #ifdef PERL_IMPLICIT_CONTEXT 198 static Direntry_t * my_readdir(DIR*); 199 200 static Direntry_t * 201 my_readdir(DIR *d) 202 { 203 #ifndef NETWARE 204 return PerlDir_read(d); 205 #else 206 return (DIR *)PerlDir_read(d); 207 #endif 208 } 209 #else 210 211 /* ReliantUNIX (OS formerly known as SINIX) defines readdir 212 * in LFS-mode to be a 64-bit version of readdir. */ 213 214 # ifdef sinix 215 static Direntry_t * my_readdir(DIR*); 216 217 static Direntry_t * 218 my_readdir(DIR *d) 219 { 220 return readdir(d); 221 } 222 # else 223 224 # define my_readdir readdir 225 226 # endif 227 228 #endif 229 230 #ifdef MACOS_TRADITIONAL 231 #include <Files.h> 232 #include <Types.h> 233 #include <string.h> 234 235 #define NO_UPDIR_ERR 1 /* updir resolving failed */ 236 237 static Boolean g_matchVol; /* global variable */ 238 static short updir(char *path); 239 static short resolve_updirs(char *new_pattern); 240 static void remove_trColon(char *path); 241 static short glob_mark_Mac(Char *pathbuf, Char *pathend, Char *pathend_last); 242 static OSErr GetVolInfo(short volume, Boolean indexed, FSSpec *spec); 243 static void name_f_FSSpec(StrFileName volname, FSSpec *spec); 244 245 #endif 246 247 int 248 bsd_glob(const char *pattern, int flags, 249 int (*errfunc)(const char *, int), glob_t *pglob) 250 { 251 const U8 *patnext; 252 int c; 253 Char *bufnext, *bufend, patbuf[MAXPATHLEN]; 254 255 #ifdef MACOS_TRADITIONAL 256 char *new_pat, *p, *np; 257 int err; 258 size_t len; 259 #endif 260 261 #ifndef MACOS_TRADITIONAL 262 patnext = (U8 *) pattern; 263 #endif 264 /* TODO: GLOB_APPEND / GLOB_DOOFFS aren't supported yet */ 265 #if 0 266 if (!(flags & GLOB_APPEND)) { 267 pglob->gl_pathc = 0; 268 pglob->gl_pathv = NULL; 269 if (!(flags & GLOB_DOOFFS)) 270 pglob->gl_offs = 0; 271 } 272 #else 273 pglob->gl_pathc = 0; 274 pglob->gl_pathv = NULL; 275 pglob->gl_offs = 0; 276 #endif 277 pglob->gl_flags = flags & ~GLOB_MAGCHAR; 278 pglob->gl_errfunc = errfunc; 279 pglob->gl_matchc = 0; 280 281 bufnext = patbuf; 282 bufend = bufnext + MAXPATHLEN - 1; 283 #ifdef DOSISH 284 /* Nasty hack to treat patterns like "C:*" correctly. In this 285 * case, the * should match any file in the current directory 286 * on the C: drive. However, the glob code does not treat the 287 * colon specially, so it looks for files beginning "C:" in 288 * the current directory. To fix this, change the pattern to 289 * add an explicit "./" at the start (just after the drive 290 * letter and colon - ie change to "C:./"). 291 */ 292 if (isalpha(pattern[0]) && pattern[1] == ':' && 293 pattern[2] != BG_SEP && pattern[2] != BG_SEP2 && 294 bufend - bufnext > 4) { 295 *bufnext++ = pattern[0]; 296 *bufnext++ = ':'; 297 *bufnext++ = '.'; 298 *bufnext++ = BG_SEP; 299 patnext += 2; 300 } 301 #endif 302 303 #ifdef MACOS_TRADITIONAL 304 /* Check if we need to match a volume name (e.g. '*HD:*') */ 305 g_matchVol = false; 306 p = (char *) pattern; 307 if (*p != BG_SEP) { 308 p++; 309 while (*p != BG_EOS) { 310 if (*p == BG_SEP) { 311 g_matchVol = true; 312 break; 313 } 314 p++; 315 } 316 } 317 318 /* Transform the pattern: 319 * (a) Resolve updirs, e.g. 320 * '*:t*p::' -> '*:' 321 * ':a*:tmp::::' -> '::' 322 * ':base::t*p:::' -> '::' 323 * '*HD::' -> return 0 (error, quit silently) 324 * 325 * (b) Remove a single trailing ':', unless it's a "match volume only" 326 * pattern like '*HD:'; e.g. 327 * '*:tmp:' -> '*:tmp' but 328 * '*HD:' -> '*HD:' 329 * (If we don't do that, even filenames will have a trailing ':' in 330 * the result.) 331 */ 332 333 /* We operate on a copy of the pattern */ 334 len = strlen(pattern); 335 Newx(new_pat, len + 1, char); 336 if (new_pat == NULL) 337 return (GLOB_NOSPACE); 338 339 p = (char *) pattern; 340 np = new_pat; 341 while (*np++ = *p++) ; 342 343 /* Resolve updirs ... */ 344 err = resolve_updirs(new_pat); 345 if (err) { 346 Safefree(new_pat); 347 /* The pattern is incorrect: tried to move 348 up above the volume root, see above. 349 We quit silently. */ 350 return 0; 351 } 352 /* remove trailing colon ... */ 353 remove_trColon(new_pat); 354 patnext = (U8 *) new_pat; 355 356 #endif /* MACOS_TRADITIONAL */ 357 358 if (flags & GLOB_QUOTE) { 359 /* Protect the quoted characters. */ 360 while (bufnext < bufend && (c = *patnext++) != BG_EOS) 361 if (c == BG_QUOTE) { 362 #ifdef DOSISH 363 /* To avoid backslashitis on Win32, 364 * we only treat \ as a quoting character 365 * if it precedes one of the 366 * metacharacters []-{}~\ 367 */ 368 if ((c = *patnext++) != '[' && c != ']' && 369 c != '-' && c != '{' && c != '}' && 370 c != '~' && c != '\\') { 371 #else 372 if ((c = *patnext++) == BG_EOS) { 373 #endif 374 c = BG_QUOTE; 375 --patnext; 376 } 377 *bufnext++ = c | M_PROTECT; 378 } else 379 *bufnext++ = c; 380 } else 381 while (bufnext < bufend && (c = *patnext++) != BG_EOS) 382 *bufnext++ = c; 383 *bufnext = BG_EOS; 384 385 #ifdef MACOS_TRADITIONAL 386 if (flags & GLOB_BRACE) 387 err = globexp1(patbuf, pglob); 388 else 389 err = glob0(patbuf, pglob); 390 Safefree(new_pat); 391 return err; 392 #else 393 if (flags & GLOB_BRACE) 394 return globexp1(patbuf, pglob); 395 else 396 return glob0(patbuf, pglob); 397 #endif 398 } 399 400 /* 401 * Expand recursively a glob {} pattern. When there is no more expansion 402 * invoke the standard globbing routine to glob the rest of the magic 403 * characters 404 */ 405 static int 406 globexp1(const Char *pattern, glob_t *pglob) 407 { 408 const Char* ptr = pattern; 409 int rv; 410 411 /* Protect a single {}, for find(1), like csh */ 412 if (pattern[0] == BG_LBRACE && pattern[1] == BG_RBRACE && pattern[2] == BG_EOS) 413 return glob0(pattern, pglob); 414 415 while ((ptr = (const Char *) g_strchr((Char *) ptr, BG_LBRACE)) != NULL) 416 if (!globexp2(ptr, pattern, pglob, &rv)) 417 return rv; 418 419 return glob0(pattern, pglob); 420 } 421 422 423 /* 424 * Recursive brace globbing helper. Tries to expand a single brace. 425 * If it succeeds then it invokes globexp1 with the new pattern. 426 * If it fails then it tries to glob the rest of the pattern and returns. 427 */ 428 static int 429 globexp2(const Char *ptr, const Char *pattern, 430 glob_t *pglob, int *rv) 431 { 432 int i; 433 Char *lm, *ls; 434 const Char *pe, *pm, *pm1, *pl; 435 Char patbuf[MAXPATHLEN]; 436 437 /* copy part up to the brace */ 438 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 439 ; 440 *lm = BG_EOS; 441 ls = lm; 442 443 /* Find the balanced brace */ 444 for (i = 0, pe = ++ptr; *pe; pe++) 445 if (*pe == BG_LBRACKET) { 446 /* Ignore everything between [] */ 447 for (pm = pe++; *pe != BG_RBRACKET && *pe != BG_EOS; pe++) 448 ; 449 if (*pe == BG_EOS) { 450 /* 451 * We could not find a matching BG_RBRACKET. 452 * Ignore and just look for BG_RBRACE 453 */ 454 pe = pm; 455 } 456 } else if (*pe == BG_LBRACE) 457 i++; 458 else if (*pe == BG_RBRACE) { 459 if (i == 0) 460 break; 461 i--; 462 } 463 464 /* Non matching braces; just glob the pattern */ 465 if (i != 0 || *pe == BG_EOS) { 466 *rv = glob0(patbuf, pglob); 467 return 0; 468 } 469 470 for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 471 switch (*pm) { 472 case BG_LBRACKET: 473 /* Ignore everything between [] */ 474 for (pm1 = pm++; *pm != BG_RBRACKET && *pm != BG_EOS; pm++) 475 ; 476 if (*pm == BG_EOS) { 477 /* 478 * We could not find a matching BG_RBRACKET. 479 * Ignore and just look for BG_RBRACE 480 */ 481 pm = pm1; 482 } 483 break; 484 485 case BG_LBRACE: 486 i++; 487 break; 488 489 case BG_RBRACE: 490 if (i) { 491 i--; 492 break; 493 } 494 /* FALLTHROUGH */ 495 case BG_COMMA: 496 if (i && *pm == BG_COMMA) 497 break; 498 else { 499 /* Append the current string */ 500 for (lm = ls; (pl < pm); *lm++ = *pl++) 501 ; 502 503 /* 504 * Append the rest of the pattern after the 505 * closing brace 506 */ 507 for (pl = pe + 1; (*lm++ = *pl++) != BG_EOS; ) 508 ; 509 510 /* Expand the current pattern */ 511 #ifdef GLOB_DEBUG 512 qprintf("globexp2:", patbuf); 513 #endif /* GLOB_DEBUG */ 514 *rv = globexp1(patbuf, pglob); 515 516 /* move after the comma, to the next string */ 517 pl = pm + 1; 518 } 519 break; 520 521 default: 522 break; 523 } 524 } 525 *rv = 0; 526 return 0; 527 } 528 529 530 531 /* 532 * expand tilde from the passwd file. 533 */ 534 static const Char * 535 globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) 536 { 537 char *h; 538 const Char *p; 539 Char *b, *eb; 540 541 if (*pattern != BG_TILDE || !(pglob->gl_flags & GLOB_TILDE)) 542 return pattern; 543 544 /* Copy up to the end of the string or / */ 545 eb = &patbuf[patbuf_len - 1]; 546 for (p = pattern + 1, h = (char *) patbuf; 547 h < (char*)eb && *p && *p != BG_SLASH; *h++ = (char)*p++) 548 ; 549 550 *h = BG_EOS; 551 552 #if 0 553 if (h == (char *)eb) 554 return what; 555 #endif 556 557 if (((char *) patbuf)[0] == BG_EOS) { 558 /* 559 * handle a plain ~ or ~/ by expanding $HOME 560 * first and then trying the password file 561 */ 562 if ((h = getenv("HOME")) == NULL) { 563 #ifdef HAS_PASSWD 564 struct passwd *pwd; 565 if ((pwd = getpwuid(getuid())) == NULL) 566 return pattern; 567 else 568 h = pwd->pw_dir; 569 #else 570 return pattern; 571 #endif 572 } 573 } else { 574 /* 575 * Expand a ~user 576 */ 577 #ifdef HAS_PASSWD 578 struct passwd *pwd; 579 if ((pwd = getpwnam((char*) patbuf)) == NULL) 580 return pattern; 581 else 582 h = pwd->pw_dir; 583 #else 584 return pattern; 585 #endif 586 } 587 588 /* Copy the home directory */ 589 for (b = patbuf; b < eb && *h; *b++ = *h++) 590 ; 591 592 /* Append the rest of the pattern */ 593 while (b < eb && (*b++ = *p++) != BG_EOS) 594 ; 595 *b = BG_EOS; 596 597 return patbuf; 598 } 599 600 601 /* 602 * The main glob() routine: compiles the pattern (optionally processing 603 * quotes), calls glob1() to do the real pattern matching, and finally 604 * sorts the list (unless unsorted operation is requested). Returns 0 605 * if things went well, nonzero if errors occurred. It is not an error 606 * to find no matches. 607 */ 608 static int 609 glob0(const Char *pattern, glob_t *pglob) 610 { 611 const Char *qpat, *qpatnext; 612 int c, err, oldflags, oldpathc; 613 Char *bufnext, patbuf[MAXPATHLEN]; 614 size_t limit = 0; 615 616 #ifdef MACOS_TRADITIONAL 617 if ( (*pattern == BG_TILDE) && (pglob->gl_flags & GLOB_TILDE) ) { 618 return(globextend(pattern, pglob, &limit)); 619 } 620 #endif 621 622 qpat = globtilde(pattern, patbuf, MAXPATHLEN, pglob); 623 qpatnext = qpat; 624 oldflags = pglob->gl_flags; 625 oldpathc = pglob->gl_pathc; 626 bufnext = patbuf; 627 628 /* We don't need to check for buffer overflow any more. */ 629 while ((c = *qpatnext++) != BG_EOS) { 630 switch (c) { 631 case BG_LBRACKET: 632 c = *qpatnext; 633 if (c == BG_NOT) 634 ++qpatnext; 635 if (*qpatnext == BG_EOS || 636 g_strchr((Char *) qpatnext+1, BG_RBRACKET) == NULL) { 637 *bufnext++ = BG_LBRACKET; 638 if (c == BG_NOT) 639 --qpatnext; 640 break; 641 } 642 *bufnext++ = M_SET; 643 if (c == BG_NOT) 644 *bufnext++ = M_NOT; 645 c = *qpatnext++; 646 do { 647 *bufnext++ = CHAR(c); 648 if (*qpatnext == BG_RANGE && 649 (c = qpatnext[1]) != BG_RBRACKET) { 650 *bufnext++ = M_RNG; 651 *bufnext++ = CHAR(c); 652 qpatnext += 2; 653 } 654 } while ((c = *qpatnext++) != BG_RBRACKET); 655 pglob->gl_flags |= GLOB_MAGCHAR; 656 *bufnext++ = M_END; 657 break; 658 case BG_QUESTION: 659 pglob->gl_flags |= GLOB_MAGCHAR; 660 *bufnext++ = M_ONE; 661 break; 662 case BG_STAR: 663 pglob->gl_flags |= GLOB_MAGCHAR; 664 /* collapse adjacent stars to one, 665 * to avoid exponential behavior 666 */ 667 if (bufnext == patbuf || bufnext[-1] != M_ALL) 668 *bufnext++ = M_ALL; 669 break; 670 default: 671 *bufnext++ = CHAR(c); 672 break; 673 } 674 } 675 *bufnext = BG_EOS; 676 #ifdef GLOB_DEBUG 677 qprintf("glob0:", patbuf); 678 #endif /* GLOB_DEBUG */ 679 680 if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0) { 681 pglob->gl_flags = oldflags; 682 return(err); 683 } 684 685 /* 686 * If there was no match we are going to append the pattern 687 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 688 * and the pattern did not contain any magic characters 689 * GLOB_NOMAGIC is there just for compatibility with csh. 690 */ 691 if (pglob->gl_pathc == oldpathc && 692 ((pglob->gl_flags & GLOB_NOCHECK) || 693 ((pglob->gl_flags & GLOB_NOMAGIC) && 694 !(pglob->gl_flags & GLOB_MAGCHAR)))) 695 { 696 #ifdef GLOB_DEBUG 697 printf("calling globextend from glob0\n"); 698 #endif /* GLOB_DEBUG */ 699 pglob->gl_flags = oldflags; 700 return(globextend(qpat, pglob, &limit)); 701 } 702 else if (!(pglob->gl_flags & GLOB_NOSORT)) 703 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 704 pglob->gl_pathc - oldpathc, sizeof(char *), 705 (pglob->gl_flags & (GLOB_ALPHASORT|GLOB_NOCASE)) 706 ? ci_compare : compare); 707 pglob->gl_flags = oldflags; 708 return(0); 709 } 710 711 static int 712 ci_compare(const void *p, const void *q) 713 { 714 const char *pp = *(const char **)p; 715 const char *qq = *(const char **)q; 716 int ci; 717 while (*pp && *qq) { 718 if (toLOWER(*pp) != toLOWER(*qq)) 719 break; 720 ++pp; 721 ++qq; 722 } 723 ci = toLOWER(*pp) - toLOWER(*qq); 724 if (ci == 0) 725 return compare(p, q); 726 return ci; 727 } 728 729 static int 730 compare(const void *p, const void *q) 731 { 732 return(strcmp(*(char **)p, *(char **)q)); 733 } 734 735 static int 736 glob1(Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp) 737 { 738 Char pathbuf[MAXPATHLEN]; 739 740 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 741 if (*pattern == BG_EOS) 742 return(0); 743 return(glob2(pathbuf, pathbuf+MAXPATHLEN-1, 744 pathbuf, pathbuf+MAXPATHLEN-1, 745 pattern, pattern_last, pglob, limitp)); 746 } 747 748 /* 749 * The functions glob2 and glob3 are mutually recursive; there is one level 750 * of recursion for each segment in the pattern that contains one or more 751 * meta characters. 752 */ 753 static int 754 glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, 755 Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp) 756 { 757 Stat_t sb; 758 Char *p, *q; 759 int anymeta; 760 761 /* 762 * Loop over pattern segments until end of pattern or until 763 * segment with meta character found. 764 */ 765 for (anymeta = 0;;) { 766 if (*pattern == BG_EOS) { /* End of pattern? */ 767 *pathend = BG_EOS; 768 if (g_lstat(pathbuf, &sb, pglob)) 769 return(0); 770 771 if (((pglob->gl_flags & GLOB_MARK) && 772 pathend[-1] != BG_SEP 773 #ifdef DOSISH 774 && pathend[-1] != BG_SEP2 775 #endif 776 ) && (S_ISDIR(sb.st_mode) || 777 (S_ISLNK(sb.st_mode) && 778 (g_stat(pathbuf, &sb, pglob) == 0) && 779 S_ISDIR(sb.st_mode)))) { 780 #ifdef MACOS_TRADITIONAL 781 short err; 782 err = glob_mark_Mac(pathbuf, pathend, pathend_last); 783 if (err) 784 return (err); 785 #else 786 if (pathend+1 > pathend_last) 787 return (1); 788 *pathend++ = BG_SEP; 789 *pathend = BG_EOS; 790 #endif 791 } 792 ++pglob->gl_matchc; 793 #ifdef GLOB_DEBUG 794 printf("calling globextend from glob2\n"); 795 #endif /* GLOB_DEBUG */ 796 return(globextend(pathbuf, pglob, limitp)); 797 } 798 799 /* Find end of next segment, copy tentatively to pathend. */ 800 q = pathend; 801 p = pattern; 802 while (*p != BG_EOS && *p != BG_SEP 803 #ifdef DOSISH 804 && *p != BG_SEP2 805 #endif 806 ) { 807 if (ismeta(*p)) 808 anymeta = 1; 809 if (q+1 > pathend_last) 810 return (1); 811 *q++ = *p++; 812 } 813 814 if (!anymeta) { /* No expansion, do next segment. */ 815 pathend = q; 816 pattern = p; 817 while (*pattern == BG_SEP 818 #ifdef DOSISH 819 || *pattern == BG_SEP2 820 #endif 821 ) { 822 if (pathend+1 > pathend_last) 823 return (1); 824 *pathend++ = *pattern++; 825 } 826 } else 827 /* Need expansion, recurse. */ 828 return(glob3(pathbuf, pathbuf_last, pathend, 829 pathend_last, pattern, pattern_last, 830 p, pattern_last, pglob, limitp)); 831 } 832 /* NOTREACHED */ 833 } 834 835 static int 836 glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, 837 Char *pattern, Char *pattern_last, 838 Char *restpattern, Char *restpattern_last, glob_t *pglob, size_t *limitp) 839 { 840 register Direntry_t *dp; 841 DIR *dirp; 842 int err; 843 int nocase; 844 char buf[MAXPATHLEN]; 845 846 /* 847 * The readdirfunc declaration can't be prototyped, because it is 848 * assigned, below, to two functions which are prototyped in glob.h 849 * and dirent.h as taking pointers to differently typed opaque 850 * structures. 851 */ 852 Direntry_t *(*readdirfunc)(DIR*); 853 854 if (pathend > pathend_last) 855 return (1); 856 *pathend = BG_EOS; 857 errno = 0; 858 859 #ifdef VMS 860 { 861 Char *q = pathend; 862 if (q - pathbuf > 5) { 863 q -= 5; 864 if (q[0] == '.' && 865 tolower(q[1]) == 'd' && tolower(q[2]) == 'i' && 866 tolower(q[3]) == 'r' && q[4] == '/') 867 { 868 q[0] = '/'; 869 q[1] = BG_EOS; 870 pathend = q+1; 871 } 872 } 873 } 874 #endif 875 876 #ifdef MACOS_TRADITIONAL 877 if ((!*pathbuf) && (g_matchVol)) { 878 FSSpec spec; 879 short index; 880 StrFileName vol_name; /* unsigned char[64] on MacOS */ 881 882 err = 0; 883 nocase = ((pglob->gl_flags & GLOB_NOCASE) != 0); 884 885 /* Get and match a list of volume names */ 886 for (index = 0; !GetVolInfo(index+1, true, &spec); ++index) { 887 register U8 *sc; 888 register Char *dc; 889 890 name_f_FSSpec(vol_name, &spec); 891 892 /* Initial BG_DOT must be matched literally. */ 893 if (*vol_name == BG_DOT && *pattern != BG_DOT) 894 continue; 895 dc = pathend; 896 sc = (U8 *) vol_name; 897 while (dc < pathend_last && (*dc++ = *sc++) != BG_EOS) 898 ; 899 if (dc >= pathend_last) { 900 *dc = BG_EOS; 901 err = 1; 902 break; 903 } 904 905 if (!match(pathend, pattern, restpattern, nocase)) { 906 *pathend = BG_EOS; 907 continue; 908 } 909 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, 910 restpattern, restpattern_last, pglob, limitp); 911 if (err) 912 break; 913 } 914 return(err); 915 916 } else { /* open dir */ 917 #endif /* MACOS_TRADITIONAL */ 918 919 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 920 /* TODO: don't call for ENOENT or ENOTDIR? */ 921 if (pglob->gl_errfunc) { 922 if (g_Ctoc(pathbuf, buf, sizeof(buf))) 923 return (GLOB_ABEND); 924 if (pglob->gl_errfunc(buf, errno) || 925 (pglob->gl_flags & GLOB_ERR)) 926 return (GLOB_ABEND); 927 } 928 return(0); 929 } 930 931 err = 0; 932 nocase = ((pglob->gl_flags & GLOB_NOCASE) != 0); 933 934 /* Search directory for matching names. */ 935 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 936 readdirfunc = (Direntry_t *(*)(DIR *))pglob->gl_readdir; 937 else 938 readdirfunc = (Direntry_t *(*)(DIR *))my_readdir; 939 while ((dp = (*readdirfunc)(dirp))) { 940 register U8 *sc; 941 register Char *dc; 942 943 /* Initial BG_DOT must be matched literally. */ 944 if (dp->d_name[0] == BG_DOT && *pattern != BG_DOT) 945 continue; 946 dc = pathend; 947 sc = (U8 *) dp->d_name; 948 while (dc < pathend_last && (*dc++ = *sc++) != BG_EOS) 949 ; 950 if (dc >= pathend_last) { 951 *dc = BG_EOS; 952 err = 1; 953 break; 954 } 955 956 if (!match(pathend, pattern, restpattern, nocase)) { 957 *pathend = BG_EOS; 958 continue; 959 } 960 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, 961 restpattern, restpattern_last, pglob, limitp); 962 if (err) 963 break; 964 } 965 966 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 967 (*pglob->gl_closedir)(dirp); 968 else 969 PerlDir_close(dirp); 970 return(err); 971 972 #ifdef MACOS_TRADITIONAL 973 } 974 #endif 975 } 976 977 978 /* 979 * Extend the gl_pathv member of a glob_t structure to accomodate a new item, 980 * add the new item, and update gl_pathc. 981 * 982 * This assumes the BSD realloc, which only copies the block when its size 983 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 984 * behavior. 985 * 986 * Return 0 if new item added, error code if memory couldn't be allocated. 987 * 988 * Invariant of the glob_t structure: 989 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 990 * gl_pathv points to (gl_offs + gl_pathc + 1) items. 991 */ 992 static int 993 globextend(const Char *path, glob_t *pglob, size_t *limitp) 994 { 995 register char **pathv; 996 register int i; 997 STRLEN newsize, len; 998 char *copy; 999 const Char *p; 1000 1001 #ifdef GLOB_DEBUG 1002 printf("Adding "); 1003 for (p = path; *p; p++) 1004 (void)printf("%c", CHAR(*p)); 1005 printf("\n"); 1006 #endif /* GLOB_DEBUG */ 1007 1008 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 1009 if (pglob->gl_pathv) 1010 pathv = Renew(pglob->gl_pathv,newsize,char*); 1011 else 1012 Newx(pathv,newsize,char*); 1013 if (pathv == NULL) { 1014 if (pglob->gl_pathv) { 1015 Safefree(pglob->gl_pathv); 1016 pglob->gl_pathv = NULL; 1017 } 1018 return(GLOB_NOSPACE); 1019 } 1020 1021 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 1022 /* first time around -- clear initial gl_offs items */ 1023 pathv += pglob->gl_offs; 1024 for (i = pglob->gl_offs; --i >= 0; ) 1025 *--pathv = NULL; 1026 } 1027 pglob->gl_pathv = pathv; 1028 1029 for (p = path; *p++;) 1030 ; 1031 len = (STRLEN)(p - path); 1032 *limitp += len; 1033 Newx(copy, p-path, char); 1034 if (copy != NULL) { 1035 if (g_Ctoc(path, copy, len)) { 1036 Safefree(copy); 1037 return(GLOB_NOSPACE); 1038 } 1039 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 1040 } 1041 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 1042 1043 if ((pglob->gl_flags & GLOB_LIMIT) && 1044 newsize + *limitp >= ARG_MAX) { 1045 errno = 0; 1046 return(GLOB_NOSPACE); 1047 } 1048 1049 return(copy == NULL ? GLOB_NOSPACE : 0); 1050 } 1051 1052 1053 /* 1054 * pattern matching function for filenames. Each occurrence of the * 1055 * pattern causes a recursion level. 1056 */ 1057 static int 1058 match(register Char *name, register Char *pat, register Char *patend, int nocase) 1059 { 1060 int ok, negate_range; 1061 Char c, k; 1062 1063 while (pat < patend) { 1064 c = *pat++; 1065 switch (c & M_MASK) { 1066 case M_ALL: 1067 if (pat == patend) 1068 return(1); 1069 do 1070 if (match(name, pat, patend, nocase)) 1071 return(1); 1072 while (*name++ != BG_EOS) 1073 ; 1074 return(0); 1075 case M_ONE: 1076 if (*name++ == BG_EOS) 1077 return(0); 1078 break; 1079 case M_SET: 1080 ok = 0; 1081 if ((k = *name++) == BG_EOS) 1082 return(0); 1083 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != BG_EOS) 1084 ++pat; 1085 while (((c = *pat++) & M_MASK) != M_END) 1086 if ((*pat & M_MASK) == M_RNG) { 1087 if (nocase) { 1088 if (tolower(c) <= tolower(k) && tolower(k) <= tolower(pat[1])) 1089 ok = 1; 1090 } else { 1091 if (c <= k && k <= pat[1]) 1092 ok = 1; 1093 } 1094 pat += 2; 1095 } else if (nocase ? (tolower(c) == tolower(k)) : (c == k)) 1096 ok = 1; 1097 if (ok == negate_range) 1098 return(0); 1099 break; 1100 default: 1101 k = *name++; 1102 if (nocase ? (tolower(k) != tolower(c)) : (k != c)) 1103 return(0); 1104 break; 1105 } 1106 } 1107 return(*name == BG_EOS); 1108 } 1109 1110 /* Free allocated data belonging to a glob_t structure. */ 1111 void 1112 bsd_globfree(glob_t *pglob) 1113 { 1114 register int i; 1115 register char **pp; 1116 1117 if (pglob->gl_pathv != NULL) { 1118 pp = pglob->gl_pathv + pglob->gl_offs; 1119 for (i = pglob->gl_pathc; i--; ++pp) 1120 if (*pp) 1121 Safefree(*pp); 1122 Safefree(pglob->gl_pathv); 1123 pglob->gl_pathv = NULL; 1124 } 1125 } 1126 1127 static DIR * 1128 g_opendir(register Char *str, glob_t *pglob) 1129 { 1130 char buf[MAXPATHLEN]; 1131 1132 if (!*str) { 1133 #ifdef MACOS_TRADITIONAL 1134 my_strlcpy(buf, ":", sizeof(buf)); 1135 #else 1136 my_strlcpy(buf, ".", sizeof(buf)); 1137 #endif 1138 } else { 1139 if (g_Ctoc(str, buf, sizeof(buf))) 1140 return(NULL); 1141 } 1142 1143 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1144 return((DIR*)(*pglob->gl_opendir)(buf)); 1145 1146 return(PerlDir_open(buf)); 1147 } 1148 1149 static int 1150 g_lstat(register Char *fn, Stat_t *sb, glob_t *pglob) 1151 { 1152 char buf[MAXPATHLEN]; 1153 1154 if (g_Ctoc(fn, buf, sizeof(buf))) 1155 return(-1); 1156 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1157 return((*pglob->gl_lstat)(buf, sb)); 1158 #ifdef HAS_LSTAT 1159 return(PerlLIO_lstat(buf, sb)); 1160 #else 1161 return(PerlLIO_stat(buf, sb)); 1162 #endif /* HAS_LSTAT */ 1163 } 1164 1165 static int 1166 g_stat(register Char *fn, Stat_t *sb, glob_t *pglob) 1167 { 1168 char buf[MAXPATHLEN]; 1169 1170 if (g_Ctoc(fn, buf, sizeof(buf))) 1171 return(-1); 1172 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 1173 return((*pglob->gl_stat)(buf, sb)); 1174 return(PerlLIO_stat(buf, sb)); 1175 } 1176 1177 static Char * 1178 g_strchr(Char *str, int ch) 1179 { 1180 do { 1181 if (*str == ch) 1182 return (str); 1183 } while (*str++); 1184 return (NULL); 1185 } 1186 1187 static int 1188 g_Ctoc(register const Char *str, char *buf, STRLEN len) 1189 { 1190 while (len--) { 1191 if ((*buf++ = (char)*str++) == BG_EOS) 1192 return (0); 1193 } 1194 return (1); 1195 } 1196 1197 #ifdef GLOB_DEBUG 1198 static void 1199 qprintf(const char *str, register Char *s) 1200 { 1201 register Char *p; 1202 1203 (void)printf("%s:\n", str); 1204 for (p = s; *p; p++) 1205 (void)printf("%c", CHAR(*p)); 1206 (void)printf("\n"); 1207 for (p = s; *p; p++) 1208 (void)printf("%c", *p & M_PROTECT ? '"' : ' '); 1209 (void)printf("\n"); 1210 for (p = s; *p; p++) 1211 (void)printf("%c", ismeta(*p) ? '_' : ' '); 1212 (void)printf("\n"); 1213 } 1214 #endif /* GLOB_DEBUG */ 1215 1216 1217 #ifdef MACOS_TRADITIONAL 1218 1219 /* Replace the last occurrence of the pattern ":[^:]+::", e.g. ":lib::", 1220 with a single ':', if possible. It is not an error, if the pattern 1221 doesn't match (we return -1), but if there are two consecutive colons 1222 '::', there must be a preceding ':[^:]+'. Hence, a volume path like 1223 "HD::" is considered to be an error (we return 1), that is, it can't 1224 be resolved. We return 0 on success. 1225 */ 1226 1227 static short 1228 updir(char *path) 1229 { 1230 char *pb, *pe, *lastchar; 1231 char *bgn_mark, *end_mark; 1232 char *f, *m, *b; /* front, middle, back */ 1233 size_t len; 1234 1235 len = strlen(path); 1236 lastchar = path + (len-1); 1237 b = lastchar; 1238 m = lastchar-1; 1239 f = lastchar-2; 1240 1241 /* find a '[^:]::' (e.g. b::) pattern ... */ 1242 while ( !( (*f != BG_SEP) && (*m == BG_SEP) && (*b == BG_SEP) ) 1243 && (f >= path)) { 1244 f--; 1245 m--; 1246 b--; 1247 } 1248 1249 if (f < path) { /* no (more) match */ 1250 return -1; 1251 } 1252 1253 end_mark = b; 1254 1255 /* ... and now find its preceding colon ':' */ 1256 while ((*f != BG_SEP) && (f >= path)) { 1257 f--; 1258 } 1259 if (f < path) { 1260 /* No preceding colon found, must be a 1261 volume path. We can't move up the 1262 tree and that's an error */ 1263 return 1; 1264 } 1265 bgn_mark = f; 1266 1267 /* Shrink path, i.e. exclude all characters between 1268 bgn_mark and end_mark */ 1269 1270 pb = bgn_mark; 1271 pe = end_mark; 1272 while (*pb++ = *pe++) ; 1273 return 0; 1274 } 1275 1276 1277 /* Resolve all updirs in pattern. */ 1278 1279 static short 1280 resolve_updirs(char *new_pattern) 1281 { 1282 short err; 1283 1284 do { 1285 err = updir(new_pattern); 1286 } while (!err); 1287 if (err == 1) { 1288 return NO_UPDIR_ERR; 1289 } 1290 return 0; 1291 } 1292 1293 1294 /* Remove a trailing colon from the path, but only if it's 1295 not a volume path (e.g. HD:) and not a path consisting 1296 solely of colons. */ 1297 1298 static void 1299 remove_trColon(char *path) 1300 { 1301 char *lastchar, *lc; 1302 1303 /* if path matches the pattern /:[^:]+:$/, we can 1304 remove the trailing ':' */ 1305 1306 lc = lastchar = path + (strlen(path) - 1); 1307 if (*lastchar == BG_SEP) { 1308 /* there's a trailing ':', there must be at least 1309 one preceding char != ':' and a preceding ':' */ 1310 lc--; 1311 if ((*lc != BG_SEP) && (lc >= path)) { 1312 lc--; 1313 } else { 1314 return; 1315 } 1316 while ((*lc != BG_SEP) && (lc >= path)) { 1317 lc--; 1318 } 1319 if (lc >= path) { 1320 /* ... there's a preceding ':', we remove 1321 the trailing colon */ 1322 *lastchar = BG_EOS; 1323 } 1324 } 1325 } 1326 1327 1328 /* With the GLOB_MARK flag on, we append a colon, if pathbuf 1329 is a directory. If the directory name contains no colons, 1330 e.g. 'lib', we can't simply append a ':', since this (e.g. 1331 'lib:') is not a valid (relative) path on Mac OS. Instead, 1332 we add a leading _and_ trailing ':'. */ 1333 1334 static short 1335 glob_mark_Mac(Char *pathbuf, Char *pathend, Char *pathend_last) 1336 { 1337 Char *p, *pe; 1338 Boolean is_file = true; 1339 1340 /* check if pathbuf contains a ':', 1341 i.e. is not a file name */ 1342 p = pathbuf; 1343 while (*p != BG_EOS) { 1344 if (*p == BG_SEP) { 1345 is_file = false; 1346 break; 1347 } 1348 p++; 1349 } 1350 1351 if (is_file) { 1352 if (pathend+2 > pathend_last) { 1353 return (1); 1354 } 1355 /* right shift one char */ 1356 pe = p = pathend; 1357 p--; 1358 pathend++; 1359 while (p >= pathbuf) { 1360 *pe-- = *p--; 1361 } 1362 /* first char becomes a colon */ 1363 *pathbuf = BG_SEP; 1364 /* append a colon */ 1365 *pathend++ = BG_SEP; 1366 *pathend = BG_EOS; 1367 1368 } else { 1369 if (pathend+1 > pathend_last) { 1370 return (1); 1371 } 1372 *pathend++ = BG_SEP; 1373 *pathend = BG_EOS; 1374 } 1375 return 0; 1376 } 1377 1378 1379 /* Return a FSSpec record for the specified volume 1380 (borrowed from MacPerl.xs). */ 1381 1382 static OSErr 1383 GetVolInfo(short volume, Boolean indexed, FSSpec* spec) 1384 { 1385 OSErr err; /* OSErr: 16-bit integer */ 1386 HParamBlockRec pb; 1387 1388 pb.volumeParam.ioNamePtr = spec->name; 1389 pb.volumeParam.ioVRefNum = indexed ? 0 : volume; 1390 pb.volumeParam.ioVolIndex = indexed ? volume : 0; 1391 1392 if (err = PBHGetVInfoSync(&pb)) 1393 return err; 1394 1395 spec->vRefNum = pb.volumeParam.ioVRefNum; 1396 spec->parID = 1; 1397 1398 return noErr; /* 0 */ 1399 } 1400 1401 /* Extract a C name from a FSSpec. Note that there are 1402 no leading or trailing colons. */ 1403 1404 static void 1405 name_f_FSSpec(StrFileName name, FSSpec *spec) 1406 { 1407 unsigned char *nc; 1408 const short len = spec->name[0]; 1409 short i; 1410 1411 /* FSSpec.name is a Pascal string, 1412 convert it to C ... */ 1413 nc = name; 1414 for (i=1; i<=len; i++) { 1415 *nc++ = spec->name[i]; 1416 } 1417 *nc = BG_EOS; 1418 } 1419 1420 #endif /* MACOS_TRADITIONAL */ 1421