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