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