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

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