root/win32/glob.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. glob
  2. globexp1
  3. globexp2
  4. globtilde
  5. glob0
  6. compare
  7. glob1
  8. glob2
  9. glob3
  10. globextend
  11. match
  12. globfree
  13. g_opendir
  14. g_lstat
  15. g_stat
  16. g_strchr
  17. g_Ctoc
  18. qprintf

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

/* [<][>][^][v][top][bottom][index][help] */