Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 925 lines (829 sloc) 21.244 kB
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 #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
4e3d4e4 - Let's be consistent with these..
foobar authored
75 #include "php.h"
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 ']'
c7441b2 Fixed bug #21597 (made glob() understand windows paths)
Edin Kadribasic authored
100 #define SEP DEFAULT_SLASH
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 *,
196e45a @pierrejoye - ws
pierrejoye authored
149 glob_t *, size_t *);
5446942 Added glob() support for windows.
Edin Kadribasic authored
150 static int glob3(Char *, Char *, Char *, Char *, Char *, Char *,
196e45a @pierrejoye - ws
pierrejoye authored
151 Char *, Char *, glob_t *, size_t *);
5446942 Added glob() support for windows.
Edin Kadribasic authored
152 static int globextend(const Char *, glob_t *, size_t *);
196e45a @pierrejoye - ws
pierrejoye authored
153 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
5446942 Added glob() support for windows.
Edin Kadribasic authored
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
0a636b4 @pierrejoye - expose glob and globfree on wi ndows, can be used by shared ext (co…
pierrejoye authored
161 PHPAPI int
5446942 Added glob() support for windows.
Edin Kadribasic authored
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
c7441b2 Fixed bug #21597 (made glob() understand windows paths)
Edin Kadribasic authored
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
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 {
dc34d34 Simplify the code base as this getpwd() was used only once
Dmitry Stogov authored
359 #ifndef PHP_WIN32
5446942 Added glob() support for windows.
Edin Kadribasic authored
360 struct passwd *pwd;
dc34d34 Simplify the code base as this getpwd() was used only once
Dmitry Stogov authored
361 #endif
5446942 Added glob() support for windows.
Edin Kadribasic authored
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;
196e45a @pierrejoye - ws
pierrejoye authored
372 h < (char *)eb && *p && *p != SLASH; *h++ = (char) *p++)
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 */
dc34d34 Simplify the code base as this getpwd() was used only once
Dmitry Stogov authored
401 #ifndef PHP_WIN32
9143760 Removed some leftover debugging code.
Edin Kadribasic authored
402 if ((pwd = getpwnam((char*) patbuf)) == NULL)
5446942 Added glob() support for windows.
Edin Kadribasic authored
403 return pattern;
404 else
405 h = pwd->pw_dir;
dc34d34 Simplify the code base as this getpwd() was used only once
Dmitry Stogov authored
406 #else
407 return pattern;
408 #endif
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 ||
196e45a @pierrejoye - ws
pierrejoye authored
453 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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 &&
196e45a @pierrejoye - ws
pierrejoye authored
466 (c = qpatnext[1]) != RBRACKET) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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) ||
196e45a @pierrejoye - ws
pierrejoye authored
508 ((pglob->gl_flags & GLOB_NOMAGIC) &&
509 !(pglob->gl_flags & GLOB_MAGCHAR)))
5446942 Added glob() support for windows.
Edin Kadribasic authored
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,
da4d4ce @pierrejoye - silent warning
pierrejoye authored
516 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
5446942 Added glob() support for windows.
Edin Kadribasic authored
517 return(0);
518 }
519
520 static int
0655d34 @KalleZ Fixed compiler warning
KalleZ authored
521 compare(const void *p, const void *q)
5446942 Added glob() support for windows.
Edin Kadribasic authored
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,
196e45a @pierrejoye - ws
pierrejoye authored
538 pathbuf, pathbuf+MAXPATHLEN-1,
539 pattern, pattern_last, pglob, limitp));
5446942 Added glob() support for windows.
Edin Kadribasic authored
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,
196e45a @pierrejoye - ws
pierrejoye authored
549 pattern_last, pglob, limitp)
5446942 Added glob() support for windows.
Edin Kadribasic authored
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) &&
196e45a @pierrejoye - ws
pierrejoye authored
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)))) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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;
c7441b2 Fixed bug #21597 (made glob() understand windows paths)
Edin Kadribasic authored
586 while (*p != EOS && !IS_SLASH(*p)) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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;
c7441b2 Fixed bug #21597 (made glob() understand windows paths)
Edin Kadribasic authored
597 while (IS_SLASH(*pattern)) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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,
196e45a @pierrejoye - ws
pierrejoye authored
605 pathend_last, pattern, pattern_last,
606 p, pattern_last, pglob, limitp));
5446942 Added glob() support for windows.
Edin Kadribasic authored
607 }
608 /* NOTREACHED */
609 }
610
611 static int
612 glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
196e45a @pierrejoye - ws
pierrejoye authored
613 restpattern, restpattern_last, pglob, limitp)
5446942 Added glob() support for windows.
Edin Kadribasic authored
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) ||
196e45a @pierrejoye - ws
pierrejoye authored
643 pglob->gl_flags & GLOB_ERR)
5446942 Added glob() support for windows.
Edin Kadribasic authored
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,
196e45a @pierrejoye - ws
pierrejoye authored
678 restpattern, restpattern_last, pglob, limitp);
5446942 Added glob() support for windows.
Edin Kadribasic authored
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) :
196e45a @pierrejoye - ws
pierrejoye authored
719 malloc(newsize);
5446942 Added glob() support for windows.
Edin Kadribasic authored
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) &&
196e45a @pierrejoye - ws
pierrejoye authored
750 newsize + *limitp >= ARG_MAX) {
5446942 Added glob() support for windows.
Edin Kadribasic authored
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
196e45a @pierrejoye - ws
pierrejoye authored
777 if (match(name, pat, patend))
778 return(1);
5446942 Added glob() support for windows.
Edin Kadribasic authored
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. */
0a636b4 @pierrejoye - expose glob and globfree on wi ndows, can be used by shared ext (co…
pierrejoye authored
812 PHPAPI void
5446942 Added glob() support for windows.
Edin Kadribasic authored
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)
9d04bf5 Sync with openbsd glob.c 1.19
Edin Kadribasic authored
837 strlcpy(buf, ".", sizeof buf);
5446942 Added glob() support for windows.
Edin Kadribasic authored
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));
8a18e0b @pierrejoye - use php_sys_lstat
pierrejoye authored
861 return(php_sys_lstat(buf, sb));
5446942 Added glob() support for windows.
Edin Kadribasic authored
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));
e5e0899 @pierrejoye - use php_sys_sat
pierrejoye authored
876 return(php_sys_stat(buf, sb));
5446942 Added glob() support for windows.
Edin Kadribasic authored
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
Something went wrong with that request. Please try again.