Back to index

php5  5.3.10
glob.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1989, 1993
00003  *     The Regents of the University of California.  All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Guido van Rossum.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *     This product includes software developed by the University of
00019  *     California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 /* $Id: glob.c 303317 2010-09-13 11:17:40Z pajoye $ */
00038 
00039 /*
00040  * glob(3) -- a superset of the one defined in POSIX 1003.2.
00041  *
00042  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
00043  *
00044  * Optional extra services, controlled by flags not defined by POSIX:
00045  *
00046  * GLOB_QUOTE:
00047  *     Escaping convention: \ inhibits any special meaning the following
00048  *     character might have (except \ at end of string is retained).
00049  * GLOB_MAGCHAR:
00050  *     Set in gl_flags if pattern contained a globbing character.
00051  * GLOB_NOMAGIC:
00052  *     Same as GLOB_NOCHECK, but it will only append pattern if it did
00053  *     not contain any magic characters.  [Used in csh style globbing]
00054  * GLOB_ALTDIRFUNC:
00055  *     Use alternately specified directory access functions.
00056  * GLOB_TILDE:
00057  *     expand ~user/foo to the /home/dir/of/user/foo
00058  * GLOB_BRACE:
00059  *     expand {1,2}{a,b} to 1a 1b 2a 2b
00060  * gl_matchc:
00061  *     Number of matches in the current invocation of glob.
00062  */
00063 #ifdef PHP_WIN32
00064 #define _POSIX_
00065 #include <limits.h>
00066 #undef _POSIX_
00067 #ifndef S_ISDIR
00068 #define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR)
00069 #endif
00070 #ifndef S_ISLNK
00071 #define S_ISLNK(m) (0)
00072 #endif
00073 #endif
00074 
00075 #include "php.h"
00076 #include <sys/stat.h>
00077 
00078 #include <ctype.h>
00079 #ifndef PHP_WIN32
00080 #include <sys/param.h>
00081 #include <dirent.h>
00082 #include <pwd.h>
00083 #include <unistd.h>
00084 #endif
00085 #include <errno.h>
00086 #include "glob.h"
00087 #include <stdio.h>
00088 #include <stdlib.h>
00089 #include <string.h>
00090 
00091 #define       DOLLAR        '$'
00092 #define       DOT           '.'
00093 #define       EOS           '\0'
00094 #define       LBRACKET      '['
00095 #define       NOT           '!'
00096 #define       QUESTION      '?'
00097 #define       QUOTE         '\\'
00098 #define       RANGE         '-'
00099 #define       RBRACKET      ']'
00100 #define       SEP           DEFAULT_SLASH
00101 #define       STAR          '*'
00102 #define       TILDE         '~'
00103 #define       UNDERSCORE    '_'
00104 #define       LBRACE        '{'
00105 #define       RBRACE        '}'
00106 #define       SLASH         '/'
00107 #define       COMMA         ','
00108 
00109 #ifndef DEBUG
00110 
00111 #define       M_QUOTE              0x8000
00112 #define       M_PROTECT     0x4000
00113 #define       M_MASK        0xffff
00114 #define       M_ASCII              0x00ff
00115 
00116 typedef u_short Char;
00117 
00118 #else
00119 
00120 #define       M_QUOTE              0x80
00121 #define       M_PROTECT     0x40
00122 #define       M_MASK        0xff
00123 #define       M_ASCII              0x7f
00124 
00125 typedef char Char;
00126 
00127 #endif
00128 
00129 
00130 #define       CHAR(c)              ((Char)((c)&M_ASCII))
00131 #define       META(c)              ((Char)((c)|M_QUOTE))
00132 #define       M_ALL         META('*')
00133 #define       M_END         META(']')
00134 #define       M_NOT         META('!')
00135 #define       M_ONE         META('?')
00136 #define       M_RNG         META('-')
00137 #define       M_SET         META('[')
00138 #define       ismeta(c)     (((c)&M_QUOTE) != 0)
00139 
00140 static int     compare(const void *, const void *);
00141 static int     g_Ctoc(const Char *, char *, u_int);
00142 static int     g_lstat(Char *, struct stat *, glob_t *);
00143 static DIR    *g_opendir(Char *, glob_t *);
00144 static Char   *g_strchr(Char *, int);
00145 static int     g_stat(Char *, struct stat *, glob_t *);
00146 static int     glob0(const Char *, glob_t *);
00147 static int     glob1(Char *, Char *, glob_t *, size_t *);
00148 static int     glob2(Char *, Char *, Char *, Char *, Char *, Char *,
00149                             glob_t *, size_t *);
00150 static int     glob3(Char *, Char *, Char *, Char *, Char *, Char *,
00151                             Char *, Char *, glob_t *, size_t *);
00152 static int     globextend(const Char *, glob_t *, size_t *);
00153 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
00154 static int     globexp1(const Char *, glob_t *);
00155 static int     globexp2(const Char *, const Char *, glob_t *, int *);
00156 static int     match(Char *, Char *, Char *);
00157 #ifdef DEBUG
00158 static void    qprintf(const char *, Char *);
00159 #endif
00160 
00161 PHPAPI int
00162 glob(pattern, flags, errfunc, pglob)
00163        const char *pattern;
00164        int flags, (*errfunc)(const char *, int);
00165        glob_t *pglob;
00166 {
00167        const u_char *patnext;
00168        int c;
00169        Char *bufnext, *bufend, patbuf[MAXPATHLEN];
00170 
00171 #ifdef PHP_WIN32
00172        /* Force skipping escape sequences on windows
00173         * due to the ambiguity with path backslashes
00174         */
00175        flags |= GLOB_NOESCAPE;
00176 #endif
00177 
00178        patnext = (u_char *) pattern;
00179        if (!(flags & GLOB_APPEND)) {
00180               pglob->gl_pathc = 0;
00181               pglob->gl_pathv = NULL;
00182               if (!(flags & GLOB_DOOFFS))
00183                      pglob->gl_offs = 0;
00184        }
00185        pglob->gl_flags = flags & ~GLOB_MAGCHAR;
00186        pglob->gl_errfunc = errfunc;
00187        pglob->gl_matchc = 0;
00188 
00189        bufnext = patbuf;
00190        bufend = bufnext + MAXPATHLEN - 1;
00191        if (flags & GLOB_NOESCAPE)
00192               while (bufnext < bufend && (c = *patnext++) != EOS)
00193                      *bufnext++ = c;
00194        else {
00195               /* Protect the quoted characters. */
00196               while (bufnext < bufend && (c = *patnext++) != EOS)
00197                      if (c == QUOTE) {
00198                             if ((c = *patnext++) == EOS) {
00199                                    c = QUOTE;
00200                                    --patnext;
00201                             }
00202                             *bufnext++ = c | M_PROTECT;
00203                      } else
00204                             *bufnext++ = c;
00205        }
00206        *bufnext = EOS;
00207 
00208        if (flags & GLOB_BRACE)
00209               return globexp1(patbuf, pglob);
00210        else
00211               return glob0(patbuf, pglob);
00212 }
00213 
00214 /*
00215  * Expand recursively a glob {} pattern. When there is no more expansion
00216  * invoke the standard globbing routine to glob the rest of the magic
00217  * characters
00218  */
00219 static int
00220 globexp1(pattern, pglob)
00221        const Char *pattern;
00222        glob_t *pglob;
00223 {
00224        const Char* ptr = pattern;
00225        int rv;
00226 
00227        /* Protect a single {}, for find(1), like csh */
00228        if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
00229               return glob0(pattern, pglob);
00230 
00231        while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
00232               if (!globexp2(ptr, pattern, pglob, &rv))
00233                      return rv;
00234 
00235        return glob0(pattern, pglob);
00236 }
00237 
00238 
00239 /*
00240  * Recursive brace globbing helper. Tries to expand a single brace.
00241  * If it succeeds then it invokes globexp1 with the new pattern.
00242  * If it fails then it tries to glob the rest of the pattern and returns.
00243  */
00244 static int
00245 globexp2(ptr, pattern, pglob, rv)
00246        const Char *ptr, *pattern;
00247        glob_t *pglob;
00248        int *rv;
00249 {
00250        int     i;
00251        Char   *lm, *ls;
00252        const Char *pe, *pm, *pl;
00253        Char    patbuf[MAXPATHLEN];
00254 
00255        /* copy part up to the brace */
00256        for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
00257               ;
00258        *lm = EOS;
00259        ls = lm;
00260 
00261        /* Find the balanced brace */
00262        for (i = 0, pe = ++ptr; *pe; pe++)
00263               if (*pe == LBRACKET) {
00264                      /* Ignore everything between [] */
00265                      for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
00266                             ;
00267                      if (*pe == EOS) {
00268                             /*
00269                              * We could not find a matching RBRACKET.
00270                              * Ignore and just look for RBRACE
00271                              */
00272                             pe = pm;
00273                      }
00274               } else if (*pe == LBRACE)
00275                      i++;
00276               else if (*pe == RBRACE) {
00277                      if (i == 0)
00278                             break;
00279                      i--;
00280               }
00281 
00282        /* Non matching braces; just glob the pattern */
00283        if (i != 0 || *pe == EOS) {
00284               *rv = glob0(patbuf, pglob);
00285               return 0;
00286        }
00287 
00288        for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
00289               switch (*pm) {
00290               case LBRACKET:
00291                      /* Ignore everything between [] */
00292                      for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
00293                             ;
00294                      if (*pm == EOS) {
00295                             /*
00296                              * We could not find a matching RBRACKET.
00297                              * Ignore and just look for RBRACE
00298                              */
00299                             pm = pl;
00300                      }
00301                      break;
00302 
00303               case LBRACE:
00304                      i++;
00305                      break;
00306 
00307               case RBRACE:
00308                      if (i) {
00309                             i--;
00310                             break;
00311                      }
00312                      /* FALLTHROUGH */
00313               case COMMA:
00314                      if (i && *pm == COMMA)
00315                             break;
00316                      else {
00317                             /* Append the current string */
00318                             for (lm = ls; (pl < pm); *lm++ = *pl++)
00319                                    ;
00320 
00321                             /*
00322                              * Append the rest of the pattern after the
00323                              * closing brace
00324                              */
00325                             for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
00326                                    ;
00327 
00328                             /* Expand the current pattern */
00329 #ifdef DEBUG
00330                             qprintf("globexp2:", patbuf);
00331 #endif
00332                             *rv = globexp1(patbuf, pglob);
00333 
00334                             /* move after the comma, to the next string */
00335                             pl = pm + 1;
00336                      }
00337                      break;
00338 
00339               default:
00340                      break;
00341               }
00342        }
00343        *rv = 0;
00344        return 0;
00345 }
00346 
00347 
00348 
00349 /*
00350  * expand tilde from the passwd file.
00351  */
00352 static const Char *
00353 globtilde(pattern, patbuf, patbuf_len, pglob)
00354        const Char *pattern;
00355        Char *patbuf;
00356        size_t patbuf_len;
00357        glob_t *pglob;
00358 {
00359 #ifndef PHP_WIN32
00360        struct passwd *pwd;
00361 #endif
00362        char *h;
00363        const Char *p;
00364        Char *b, *eb;
00365 
00366        if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
00367               return pattern;
00368 
00369        /* Copy up to the end of the string or / */
00370        eb = &patbuf[patbuf_len - 1];
00371        for (p = pattern + 1, h = (char *) patbuf;
00372               h < (char *)eb && *p && *p != SLASH; *h++ = (char) *p++)
00373               ;
00374 
00375        *h = EOS;
00376 
00377 #if 0
00378        if (h == (char *)eb)
00379               return what;
00380 #endif
00381 
00382        if (((char *) patbuf)[0] == EOS) {
00383               /*
00384                * handle a plain ~ or ~/ by expanding $HOME
00385                * first and then trying the password file
00386                */
00387               if ((h = getenv("HOME")) == NULL) {
00388 #ifndef PHP_WIN32
00389                      if ((pwd = getpwuid(getuid())) == NULL)
00390                             return pattern;
00391                      else
00392                             h = pwd->pw_dir;
00393 #else
00394                      return pattern;
00395 #endif
00396               }
00397        } else {
00398               /*
00399                * Expand a ~user
00400                */
00401 #ifndef PHP_WIN32
00402               if ((pwd = getpwnam((char*) patbuf)) == NULL)
00403                      return pattern;
00404               else
00405                      h = pwd->pw_dir;
00406 #else
00407               return pattern;
00408 #endif
00409        }
00410 
00411        /* Copy the home directory */
00412        for (b = patbuf; b < eb && *h; *b++ = *h++)
00413               ;
00414 
00415        /* Append the rest of the pattern */
00416        while (b < eb && (*b++ = *p++) != EOS)
00417               ;
00418        *b = EOS;
00419 
00420        return patbuf;
00421 }
00422 
00423 
00424 /*
00425  * The main glob() routine: compiles the pattern (optionally processing
00426  * quotes), calls glob1() to do the real pattern matching, and finally
00427  * sorts the list (unless unsorted operation is requested).  Returns 0
00428  * if things went well, nonzero if errors occurred.  It is not an error
00429  * to find no matches.
00430  */
00431 static int
00432 glob0(pattern, pglob)
00433        const Char *pattern;
00434        glob_t *pglob;
00435 {
00436        const Char *qpatnext;
00437        int c, err, oldpathc;
00438        Char *bufnext, patbuf[MAXPATHLEN];
00439        size_t limit = 0;
00440 
00441        qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
00442        oldpathc = pglob->gl_pathc;
00443        bufnext = patbuf;
00444 
00445        /* We don't need to check for buffer overflow any more. */
00446        while ((c = *qpatnext++) != EOS) {
00447               switch (c) {
00448               case LBRACKET:
00449                      c = *qpatnext;
00450                      if (c == NOT)
00451                             ++qpatnext;
00452                      if (*qpatnext == EOS ||
00453                             g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
00454                             *bufnext++ = LBRACKET;
00455                             if (c == NOT)
00456                                    --qpatnext;
00457                             break;
00458                      }
00459                      *bufnext++ = M_SET;
00460                      if (c == NOT)
00461                             *bufnext++ = M_NOT;
00462                      c = *qpatnext++;
00463                      do {
00464                             *bufnext++ = CHAR(c);
00465                             if (*qpatnext == RANGE &&
00466                                    (c = qpatnext[1]) != RBRACKET) {
00467                                    *bufnext++ = M_RNG;
00468                                    *bufnext++ = CHAR(c);
00469                                    qpatnext += 2;
00470                             }
00471                      } while ((c = *qpatnext++) != RBRACKET);
00472                      pglob->gl_flags |= GLOB_MAGCHAR;
00473                      *bufnext++ = M_END;
00474                      break;
00475               case QUESTION:
00476                      pglob->gl_flags |= GLOB_MAGCHAR;
00477                      *bufnext++ = M_ONE;
00478                      break;
00479               case STAR:
00480                      pglob->gl_flags |= GLOB_MAGCHAR;
00481                      /* collapse adjacent stars to one,
00482                       * to avoid exponential behavior
00483                       */
00484                      if (bufnext == patbuf || bufnext[-1] != M_ALL)
00485                             *bufnext++ = M_ALL;
00486                      break;
00487               default:
00488                      *bufnext++ = CHAR(c);
00489                      break;
00490               }
00491        }
00492        *bufnext = EOS;
00493 #ifdef DEBUG
00494        qprintf("glob0:", patbuf);
00495 #endif
00496 
00497        if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
00498               return(err);
00499 
00500        /*
00501         * If there was no match we are going to append the pattern
00502         * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
00503         * and the pattern did not contain any magic characters
00504         * GLOB_NOMAGIC is there just for compatibility with csh.
00505         */
00506        if (pglob->gl_pathc == oldpathc) {
00507               if ((pglob->gl_flags & GLOB_NOCHECK) ||
00508                      ((pglob->gl_flags & GLOB_NOMAGIC) &&
00509                      !(pglob->gl_flags & GLOB_MAGCHAR)))
00510                      return(globextend(pattern, pglob, &limit));
00511               else
00512                      return(GLOB_NOMATCH);
00513        }
00514        if (!(pglob->gl_flags & GLOB_NOSORT))
00515               qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
00516                      pglob->gl_pathc - oldpathc, sizeof(char *), compare);
00517        return(0);
00518 }
00519 
00520 static int
00521 compare(const void *p, const void *q)
00522 {
00523        return(strcmp(*(char **)p, *(char **)q));
00524 }
00525 
00526 static int
00527 glob1(pattern, pattern_last, pglob, limitp)
00528        Char *pattern, *pattern_last;
00529        glob_t *pglob;
00530        size_t *limitp;
00531 {
00532        Char pathbuf[MAXPATHLEN];
00533 
00534        /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
00535        if (*pattern == EOS)
00536               return(0);
00537        return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
00538               pathbuf, pathbuf+MAXPATHLEN-1,
00539               pattern, pattern_last, pglob, limitp));
00540 }
00541 
00542 /*
00543  * The functions glob2 and glob3 are mutually recursive; there is one level
00544  * of recursion for each segment in the pattern that contains one or more
00545  * meta characters.
00546  */
00547 static int
00548 glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
00549               pattern_last, pglob, limitp)
00550        Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
00551        Char *pattern, *pattern_last;
00552        glob_t *pglob;
00553        size_t *limitp;
00554 {
00555        struct stat sb;
00556        Char *p, *q;
00557        int anymeta;
00558 
00559        /*
00560         * Loop over pattern segments until end of pattern or until
00561         * segment with meta character found.
00562         */
00563        for (anymeta = 0;;) {
00564               if (*pattern == EOS) {             /* End of pattern? */
00565                      *pathend = EOS;
00566                      if (g_lstat(pathbuf, &sb, pglob))
00567                             return(0);
00568 
00569                      if (((pglob->gl_flags & GLOB_MARK) &&
00570                             !IS_SLASH(pathend[-1])) && (S_ISDIR(sb.st_mode) ||
00571                             (S_ISLNK(sb.st_mode) &&
00572                             (g_stat(pathbuf, &sb, pglob) == 0) &&
00573                             S_ISDIR(sb.st_mode)))) {
00574                             if (pathend+1 > pathend_last)
00575                                    return (1);
00576                             *pathend++ = SEP;
00577                             *pathend = EOS;
00578                      }
00579                      ++pglob->gl_matchc;
00580                      return(globextend(pathbuf, pglob, limitp));
00581               }
00582 
00583               /* Find end of next segment, copy tentatively to pathend. */
00584               q = pathend;
00585               p = pattern;
00586               while (*p != EOS && !IS_SLASH(*p)) {
00587                      if (ismeta(*p))
00588                             anymeta = 1;
00589                      if (q+1 > pathend_last)
00590                             return (1);
00591                      *q++ = *p++;
00592               }
00593 
00594               if (!anymeta) {             /* No expansion, do next segment. */
00595                      pathend = q;
00596                      pattern = p;
00597                      while (IS_SLASH(*pattern)) {
00598                             if (pathend+1 > pathend_last)
00599                                    return (1);
00600                             *pathend++ = *pattern++;
00601                      }
00602               } else
00603                      /* Need expansion, recurse. */
00604                      return(glob3(pathbuf, pathbuf_last, pathend,
00605                             pathend_last, pattern, pattern_last,
00606                             p, pattern_last, pglob, limitp));
00607        }
00608        /* NOTREACHED */
00609 }
00610 
00611 static int
00612 glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
00613        restpattern, restpattern_last, pglob, limitp)
00614        Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
00615        Char *pattern, *pattern_last, *restpattern, *restpattern_last;
00616        glob_t *pglob;
00617        size_t *limitp;
00618 {
00619        register struct dirent *dp;
00620        DIR *dirp;
00621        int err;
00622        char buf[MAXPATHLEN];
00623 
00624        /*
00625         * The readdirfunc declaration can't be prototyped, because it is
00626         * assigned, below, to two functions which are prototyped in glob.h
00627         * and dirent.h as taking pointers to differently typed opaque
00628         * structures.
00629         */
00630        struct dirent *(*readdirfunc)();
00631 
00632        if (pathend > pathend_last)
00633               return (1);
00634        *pathend = EOS;
00635        errno = 0;
00636 
00637        if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
00638               /* TODO: don't call for ENOENT or ENOTDIR? */
00639               if (pglob->gl_errfunc) {
00640                      if (g_Ctoc(pathbuf, buf, sizeof(buf)))
00641                             return(GLOB_ABORTED);
00642                      if (pglob->gl_errfunc(buf, errno) ||
00643                             pglob->gl_flags & GLOB_ERR)
00644                             return(GLOB_ABORTED);
00645               }
00646               return(0);
00647        }
00648 
00649        err = 0;
00650 
00651        /* Search directory for matching names. */
00652        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
00653               readdirfunc = pglob->gl_readdir;
00654        else
00655               readdirfunc = readdir;
00656        while ((dp = (*readdirfunc)(dirp))) {
00657               register u_char *sc;
00658               register Char *dc;
00659 
00660               /* Initial DOT must be matched literally. */
00661               if (dp->d_name[0] == DOT && *pattern != DOT)
00662                      continue;
00663               dc = pathend;
00664               sc = (u_char *) dp->d_name;
00665               while (dc < pathend_last && (*dc++ = *sc++) != EOS)
00666                      ;
00667               if (dc >= pathend_last) {
00668                      *dc = EOS;
00669                      err = 1;
00670                      break;
00671               }
00672 
00673               if (!match(pathend, pattern, restpattern)) {
00674                      *pathend = EOS;
00675                      continue;
00676               }
00677               err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
00678                      restpattern, restpattern_last, pglob, limitp);
00679               if (err)
00680                      break;
00681        }
00682 
00683        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
00684               (*pglob->gl_closedir)(dirp);
00685        else
00686               closedir(dirp);
00687        return(err);
00688 }
00689 
00690 
00691 /*
00692  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
00693  * add the new item, and update gl_pathc.
00694  *
00695  * This assumes the BSD realloc, which only copies the block when its size
00696  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
00697  * behavior.
00698  *
00699  * Return 0 if new item added, error code if memory couldn't be allocated.
00700  *
00701  * Invariant of the glob_t structure:
00702  *     Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
00703  *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
00704  */
00705 static int
00706 globextend(path, pglob, limitp)
00707        const Char *path;
00708        glob_t *pglob;
00709        size_t *limitp;
00710 {
00711        register char **pathv;
00712        register int i;
00713        u_int newsize, len;
00714        char *copy;
00715        const Char *p;
00716 
00717        newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
00718        pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
00719               malloc(newsize);
00720        if (pathv == NULL) {
00721               if (pglob->gl_pathv) {
00722                      free(pglob->gl_pathv);
00723                      pglob->gl_pathv = NULL;
00724               }
00725               return(GLOB_NOSPACE);
00726        }
00727 
00728        if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
00729               /* first time around -- clear initial gl_offs items */
00730               pathv += pglob->gl_offs;
00731               for (i = pglob->gl_offs; --i >= 0; )
00732                      *--pathv = NULL;
00733        }
00734        pglob->gl_pathv = pathv;
00735 
00736        for (p = path; *p++;)
00737               ;
00738        len = (size_t)(p - path);
00739        *limitp += len;
00740        if ((copy = malloc(len)) != NULL) {
00741               if (g_Ctoc(path, copy, len)) {
00742                      free(copy);
00743                      return(GLOB_NOSPACE);
00744               }
00745               pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
00746        }
00747        pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
00748 
00749        if ((pglob->gl_flags & GLOB_LIMIT) &&
00750               newsize + *limitp >= ARG_MAX) {
00751               errno = 0;
00752               return(GLOB_NOSPACE);
00753        }
00754 
00755        return(copy == NULL ? GLOB_NOSPACE : 0);
00756 }
00757 
00758 
00759 /*
00760  * pattern matching function for filenames.  Each occurrence of the *
00761  * pattern causes a recursion level.
00762  */
00763 static int
00764 match(name, pat, patend)
00765        register Char *name, *pat, *patend;
00766 {
00767        int ok, negate_range;
00768        Char c, k;
00769 
00770        while (pat < patend) {
00771               c = *pat++;
00772               switch (c & M_MASK) {
00773               case M_ALL:
00774                      if (pat == patend)
00775                             return(1);
00776                      do
00777                             if (match(name, pat, patend))
00778                                    return(1);
00779                      while (*name++ != EOS)
00780                             ;
00781                      return(0);
00782               case M_ONE:
00783                      if (*name++ == EOS)
00784                             return(0);
00785                      break;
00786               case M_SET:
00787                      ok = 0;
00788                      if ((k = *name++) == EOS)
00789                             return(0);
00790                      if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
00791                             ++pat;
00792                      while (((c = *pat++) & M_MASK) != M_END)
00793                             if ((*pat & M_MASK) == M_RNG) {
00794                                    if (c <= k && k <= pat[1])
00795                                           ok = 1;
00796                                    pat += 2;
00797                             } else if (c == k)
00798                                    ok = 1;
00799                      if (ok == negate_range)
00800                             return(0);
00801                      break;
00802               default:
00803                      if (*name++ != c)
00804                             return(0);
00805                      break;
00806               }
00807        }
00808        return(*name == EOS);
00809 }
00810 
00811 /* Free allocated data belonging to a glob_t structure. */
00812 PHPAPI void
00813 globfree(pglob)
00814        glob_t *pglob;
00815 {
00816        register int i;
00817        register char **pp;
00818 
00819        if (pglob->gl_pathv != NULL) {
00820               pp = pglob->gl_pathv + pglob->gl_offs;
00821               for (i = pglob->gl_pathc; i--; ++pp)
00822                      if (*pp)
00823                             free(*pp);
00824               free(pglob->gl_pathv);
00825               pglob->gl_pathv = NULL;
00826        }
00827 }
00828 
00829 static DIR *
00830 g_opendir(str, pglob)
00831        register Char *str;
00832        glob_t *pglob;
00833 {
00834        char buf[MAXPATHLEN];
00835 
00836        if (!*str)
00837               strlcpy(buf, ".", sizeof buf);
00838        else {
00839               if (g_Ctoc(str, buf, sizeof(buf)))
00840                      return(NULL);
00841        }
00842 
00843        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
00844               return((*pglob->gl_opendir)(buf));
00845 
00846        return(opendir(buf));
00847 }
00848 
00849 static int
00850 g_lstat(fn, sb, pglob)
00851        register Char *fn;
00852        struct stat *sb;
00853        glob_t *pglob;
00854 {
00855        char buf[MAXPATHLEN];
00856 
00857        if (g_Ctoc(fn, buf, sizeof(buf)))
00858               return(-1);
00859        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
00860               return((*pglob->gl_lstat)(buf, sb));
00861        return(php_sys_lstat(buf, sb));
00862 }
00863 
00864 static int
00865 g_stat(fn, sb, pglob)
00866        register Char *fn;
00867        struct stat *sb;
00868        glob_t *pglob;
00869 {
00870        char buf[MAXPATHLEN];
00871 
00872        if (g_Ctoc(fn, buf, sizeof(buf)))
00873               return(-1);
00874        if (pglob->gl_flags & GLOB_ALTDIRFUNC)
00875               return((*pglob->gl_stat)(buf, sb));
00876        return(php_sys_stat(buf, sb));
00877 }
00878 
00879 static Char *
00880 g_strchr(str, ch)
00881        Char *str;
00882        int ch;
00883 {
00884        do {
00885               if (*str == ch)
00886                      return (str);
00887        } while (*str++);
00888        return (NULL);
00889 }
00890 
00891 static int
00892 g_Ctoc(str, buf, len)
00893        register const Char *str;
00894        char *buf;
00895        u_int len;
00896 {
00897 
00898        while (len--) {
00899               if ((*buf++ = (char) *str++) == EOS)
00900                      return (0);
00901        }
00902        return (1);
00903 }
00904 
00905 #ifdef DEBUG
00906 static void
00907 qprintf(str, s)
00908        const char *str;
00909        register Char *s;
00910 {
00911        register Char *p;
00912 
00913        (void)printf("%s:\n", str);
00914        for (p = s; *p; p++)
00915               (void)printf("%c", CHAR(*p));
00916        (void)printf("\n");
00917        for (p = s; *p; p++)
00918               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
00919        (void)printf("\n");
00920        for (p = s; *p; p++)
00921               (void)printf("%c", ismeta(*p) ? '_' : ' ');
00922        (void)printf("\n");
00923 }
00924 #endif