Cygwin: (mostly) drop NT4 and Samba < 3.0 support
[newlib-cygwin.git] / winsup / cygwin / glob.cc
blob90ec473aea55d6831df97fd62117aa76da514d97
1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #ifdef __CYGWIN__
34 #include "winsup.h"
35 #endif
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
39 #endif /* LIBC_SCCS and not lint */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Exp $");
44 * glob(3) -- a superset of the one defined in POSIX 1003.2.
46 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
48 * Optional extra services, controlled by flags not defined by POSIX:
50 * GLOB_QUOTE:
51 * Escaping convention: \ inhibits any special meaning the following
52 * character might have (except \ at end of string is retained).
53 * GLOB_MAGCHAR:
54 * Set in gl_flags if pattern contained a globbing character.
55 * GLOB_NOMAGIC:
56 * Same as GLOB_NOCHECK, but it will only append pattern if it did
57 * not contain any magic characters. [Used in csh style globbing]
58 * GLOB_ALTDIRFUNC:
59 * Use alternately specified directory access functions.
60 * GLOB_TILDE:
61 * expand ~user/foo to the /home/dir/of/user/foo
62 * GLOB_BRACE:
63 * expand {1,2}{a,b} to 1a 1b 2a 2b
64 * gl_matchc:
65 * Number of matches in the current invocation of glob.
69 * Some notes on multibyte character support:
70 * 1. Patterns with illegal byte sequences match nothing - even if
71 * GLOB_NOCHECK is specified.
72 * 2. Illegal byte sequences in filenames are handled by treating them as
73 * single-byte characters with a value of the first byte of the sequence
74 * cast to wint_t.
75 * 3. State-dependent encodings are not currently supported.
78 #include <sys/param.h>
79 #include <sys/stat.h>
81 #include <ctype.h>
82 #include <dirent.h>
83 #include <errno.h>
84 #include <glob.h>
85 #include <limits.h>
86 #include <pwd.h>
87 #include <stdint.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <unistd.h>
92 #include <wchar.h>
93 #include <wctype.h>
95 #include "collate.h"
97 #ifdef __CYGWIN__
98 #define Cchar(c) (ignore_case_with_glob ? towlower (c) : (c))
99 #endif
101 #undef MAXPATHLEN
102 #define MAXPATHLEN 8192
104 #define DOLLAR '$'
105 #define DOT '.'
106 #define COLON ':'
107 #define EQUALS '='
108 #define EOS '\0'
109 #define LBRACKET '['
110 #define NOT '!'
111 #define QUESTION '?'
112 #define QUOTE '\\'
113 #define RANGE '-'
114 #define RBRACKET ']'
115 #define SEP '/'
116 #define STAR '*'
117 #define TILDE '~'
118 #define UNDERSCORE '_'
119 #define LBRACE '{'
120 #define RBRACE '}'
121 #define SLASH '/'
122 #define COMMA ','
124 #ifndef DEBUG
126 #define M_QUOTE 0x40000000U
127 #define M_PROTECT 0x20000000U
128 #define M_MASK 0x70ffffffU
129 #define M_COLL_MASK 0x700000ffU
130 #define M_CHAR 0x00ffffffU
132 typedef wint_t Char;
134 #else
136 #define M_QUOTE 0x80
137 #define M_PROTECT 0x40
138 #define M_MASK 0xff
139 #define M_CHAR 0x7f
141 typedef char Char;
143 #endif
146 #define CHAR(c) ((Char)((c)&M_CHAR))
147 #define META(c) ((Char)((c)|M_QUOTE))
148 #define M_ALL META('*')
149 #define M_END META(']')
150 #define M_NOT META('!')
151 #define M_ONE META('?')
152 #define M_RNG META('-')
153 #define M_SET META('[')
154 #define M_NAMED META(':')
155 #define M_EQUIV META('=')
156 #define M_COLL(_ccnt) META('.' | ((_ccnt) << 8))
157 #define M_COLL_P(_c) (((_c) & M_COLL_MASK) == META('.'))
158 #define M_COLL_CNT(_c) (((_c) & ~M_COLL_MASK) >> 8)
159 #define ismeta(c) (((c)&M_QUOTE) != 0)
161 static int compare(const void *, const void *);
162 static int g_Ctoc(const Char *, char *, size_t);
163 static int g_lstat(Char *, struct stat *, glob_t *);
164 static DIR *g_opendir(Char *, glob_t *);
165 static const Char *g_strchr(const Char *, wint_t);
166 #ifdef notdef
167 static Char *g_strcat(Char *, const Char *);
168 #endif
169 static int g_stat(Char *, struct stat *, glob_t *);
170 static int glob0(const Char *, glob_t *, size_t *);
171 static int glob1(Char *, glob_t *, size_t *);
172 static int glob2(Char *, Char *, Char *, Char *, glob_t *, size_t *);
173 static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, size_t *);
174 static int globextend(const Char *, glob_t *, size_t *);
175 static const Char *
176 globtilde(const Char *, Char *, size_t, glob_t *);
177 static int globexp1(const Char *, glob_t *, size_t *);
178 static int globexp2(const Char *, const Char *, glob_t *, int *, size_t *);
179 static int match(Char *, Char *, Char *);
180 #ifdef DEBUG
181 static void qprintf(const char *, Char *);
182 #endif
184 /* Return value is either EOS, COLON, DOT, EQUALS, or LBRACKET if no class
185 expression found. */
186 static inline Char
187 check_classes_expr(const Char *&cptr, wint_t *classbuf = NULL,
188 size_t classbufsize = 0)
190 const Char *ctype = NULL;
192 if (*cptr == LBRACKET &&
193 (cptr[1] == COLON || cptr[1] == DOT || cptr[1] == EQUALS)) {
194 ctype = ++cptr;
195 while (*++cptr != EOS &&
196 (*cptr != *ctype || cptr[1] != RBRACKET))
198 if (*cptr == EOS)
199 return EOS;
200 if (classbuf) {
201 const Char *class_p = ctype + 1;
202 size_t clen = cptr - class_p;
204 if (clen < classbufsize)
205 *wcipncpy (classbuf, class_p, clen) = '\0';
206 else
207 ctype = NULL;
209 cptr++; /* Advance cptr to closing RBRACKET of class expr */
211 return ctype ? *ctype : LBRACKET;
215 glob(const char *__restrict pattern, int flags, int (*errfunc)(const char *, int), glob_t *__restrict pglob)
217 const char *patnext;
218 size_t limit;
219 Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
220 mbstate_t mbs;
221 wint_t wc;
222 size_t clen;
224 patnext = pattern;
225 if (!(flags & GLOB_APPEND)) {
226 pglob->gl_pathc = 0;
227 pglob->gl_pathv = NULL;
228 if (!(flags & GLOB_DOOFFS))
229 pglob->gl_offs = 0;
231 if (flags & GLOB_LIMIT) {
232 limit = pglob->gl_matchc;
233 if (limit == 0)
234 limit = ARG_MAX;
235 } else
236 limit = 0;
237 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
238 pglob->gl_errfunc = errfunc;
239 pglob->gl_matchc = 0;
241 bufnext = patbuf;
242 bufend = bufnext + MAXPATHLEN - 1;
243 if (flags & GLOB_NOESCAPE) {
244 memset(&mbs, 0, sizeof(mbs));
245 while (bufend - bufnext >= MB_CUR_MAX) {
246 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
247 if (clen == (size_t)-1 || clen == (size_t)-2)
248 return (GLOB_NOMATCH);
249 else if (clen == 0)
250 break;
251 *bufnext++ = wc;
252 patnext += clen;
254 } else {
255 /* Protect the quoted characters. */
256 memset(&mbs, 0, sizeof(mbs));
257 while (bufend - bufnext >= MB_CUR_MAX) {
258 if (*patnext == QUOTE) {
259 if (*++patnext == EOS) {
260 *bufnext++ = QUOTE | M_PROTECT;
261 continue;
263 prot = M_PROTECT;
264 } else
265 prot = 0;
266 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
267 if (clen == (size_t)-1 || clen == (size_t)-2)
268 return (GLOB_NOMATCH);
269 else if (clen == 0)
270 break;
271 *bufnext++ = wc | prot;
272 patnext += clen;
275 *bufnext = EOS;
277 if (flags & GLOB_BRACE)
278 return globexp1(patbuf, pglob, &limit);
279 else
280 return glob0(patbuf, pglob, &limit);
284 * Expand recursively a glob {} pattern. When there is no more expansion
285 * invoke the standard globbing routine to glob the rest of the magic
286 * characters
288 static int
289 globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
291 const Char* ptr = pattern;
292 int rv;
294 /* Protect a single {}, for find(1), like csh */
295 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
296 return glob0(pattern, pglob, limit);
298 while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
299 if (!globexp2(ptr, pattern, pglob, &rv, limit))
300 return rv;
302 return glob0(pattern, pglob, limit);
307 * Recursive brace globbing helper. Tries to expand a single brace.
308 * If it succeeds then it invokes globexp1 with the new pattern.
309 * If it fails then it tries to glob the rest of the pattern and returns.
311 static int
312 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, size_t *limit)
314 int i;
315 Char *lm, *ls;
316 const Char *pe, *pm, *pm1, *pl;
317 Char patbuf[MAXPATHLEN];
319 /* copy part up to the brace */
320 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
321 continue;
322 *lm = EOS;
323 ls = lm;
325 /* Find the balanced brace */
326 for (i = 0, pe = ++ptr; *pe; pe++)
327 if (*pe == LBRACKET) {
328 /* Ignore everything between [] */
329 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) {
330 if (check_classes_expr (pe) == EOS)
331 break;
333 if (*pe == EOS) {
335 * We could not find a matching RBRACKET.
336 * Ignore and just look for RBRACE
338 pe = pm;
341 else if (*pe == LBRACE)
342 i++;
343 else if (*pe == RBRACE) {
344 if (i == 0)
345 break;
346 i--;
349 /* Non matching braces; just glob the pattern */
350 if (i != 0 || *pe == EOS) {
351 *rv = glob0(patbuf, pglob, limit);
352 return 0;
355 for (i = 0, pl = pm = ptr; pm <= pe; pm++)
356 switch (*pm) {
357 case LBRACKET:
358 /* Ignore everything between [] */
359 for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) {
360 if (check_classes_expr (pm) == EOS)
361 break;
363 if (*pm == EOS) {
365 * We could not find a matching RBRACKET.
366 * Ignore and just look for RBRACE
368 pm = pm1;
370 break;
372 case LBRACE:
373 i++;
374 break;
376 case RBRACE:
377 if (i) {
378 i--;
379 break;
381 fallthrough;
382 case COMMA:
383 if (i && *pm == COMMA)
384 break;
385 else {
386 /* Append the current string */
387 for (lm = ls; (pl < pm); *lm++ = *pl++)
388 continue;
390 * Append the rest of the pattern after the
391 * closing brace
393 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
394 continue;
396 /* Expand the current pattern */
397 #ifdef DEBUG
398 qprintf("globexp2:", patbuf);
399 #endif
400 *rv = globexp1(patbuf, pglob, limit);
402 /* move after the comma, to the next string */
403 pl = pm + 1;
405 break;
407 default:
408 break;
410 *rv = 0;
411 return 0;
417 * expand tilde from the passwd file.
419 static const Char *
420 globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
422 struct passwd *pwd;
423 char *h;
424 const Char *p;
425 Char *b, *eb;
427 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
428 return pattern;
431 * Copy up to the end of the string or /
433 eb = &patbuf[patbuf_len - 1];
434 for (p = pattern + 1, h = (char *) patbuf;
435 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
436 continue;
438 *h = EOS;
440 if (((char *) patbuf)[0] == EOS) {
442 * handle a plain ~ or ~/ by expanding $HOME first (iff
443 * we're not running setuid or setgid) and then trying
444 * the password file
446 if (issetugid() != 0 ||
447 (h = getenv("HOME")) == NULL) {
448 if (((h = getlogin()) != NULL &&
449 (pwd = getpwnam(h)) != NULL) ||
450 (pwd = getpwuid(getuid())) != NULL)
451 h = pwd->pw_dir;
452 else
453 return pattern;
456 else {
458 * Expand a ~user
460 if ((pwd = getpwnam((char*) patbuf)) == NULL)
461 return pattern;
462 else
463 h = pwd->pw_dir;
466 /* Copy the home directory */
467 for (b = patbuf; b < eb && *h; *b++ = *h++)
468 continue;
470 /* Append the rest of the pattern */
471 while (b < eb && (*b++ = *p++) != EOS)
472 continue;
473 *b = EOS;
475 return patbuf;
479 * The main glob() routine: compiles the pattern (optionally processing
480 * quotes), calls glob1() to do the real pattern matching, and finally
481 * sorts the list (unless unsorted operation is requested). Returns 0
482 * if things went well, nonzero if errors occurred.
484 static int
485 glob0(const Char *pattern, glob_t *pglob, size_t *limit)
487 const Char *qpatnext, *qpatrbsrch;
488 int err;
489 size_t oldpathc;
490 Char *bufnext, c, patbuf[MAXPATHLEN];
492 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
493 oldpathc = pglob->gl_pathc;
494 bufnext = patbuf;
496 /* We don't need to check for buffer overflow any more. */
497 while ((c = *qpatnext++) != EOS) {
498 switch (c) {
499 case LBRACKET:
500 c = *qpatnext;
501 if (c == NOT)
502 ++qpatnext;
503 for (qpatrbsrch = qpatnext;
504 *qpatrbsrch != RBRACKET && *qpatrbsrch != EOS;
505 ++qpatrbsrch) {
506 if (check_classes_expr (qpatrbsrch) == EOS)
507 break;
509 if (*qpatrbsrch == EOS) {
510 *bufnext++ = LBRACKET;
511 if (c == NOT)
512 --qpatnext;
513 break;
515 *bufnext++ = M_SET;
516 if (c == NOT)
517 *bufnext++ = M_NOT;
518 c = *qpatnext++;
519 do {
520 wint_t wclass[64];
521 Char ctype;
523 ctype = check_classes_expr(--qpatnext, wclass,
524 64);
525 ++qpatnext;
526 if (ctype == COLON) {
527 wctype_t type;
528 char cclass[64];
530 /* No worries, char classes are
531 ASCII-only anyway */
532 wcitoascii (cclass, wclass);
533 if ((type = wctype (cclass))) {
534 *bufnext++ = M_NAMED;
535 *bufnext++ = CHAR (type);
537 continue;
539 if (ctype == EQUALS) {
540 if (wclass[0] && !wclass[1]) {
541 *bufnext++ = M_EQUIV;
542 *bufnext++ = CHAR (wclass[0]);
544 continue;
546 if (ctype == DOT &&
547 is_unicode_coll_elem (wclass)) {
548 *bufnext++ =
549 M_COLL (wcilen (wclass));
550 wint_t *wcp = wclass;
551 while ((*bufnext++ = *wcp++))
553 --bufnext; /* drop NUL */
554 } else
555 *bufnext++ = CHAR(c);
556 if (*qpatnext == RANGE &&
557 (c = qpatnext[1]) != RBRACKET) {
558 *bufnext++ = M_RNG;
560 ctype = check_classes_expr(++qpatnext,
561 wclass, 64);
562 if (ctype == DOT &&
563 is_unicode_coll_elem (wclass)) {
564 *bufnext++ =
565 M_COLL (wcilen (wclass));
566 wint_t *wcp = wclass;
567 while ((*bufnext++ = *wcp++))
569 --bufnext; /* drop NUL */
570 } else
571 *bufnext++ = CHAR(c);
572 ++qpatnext;
574 } while ((c = *qpatnext++) != RBRACKET);
575 pglob->gl_flags |= GLOB_MAGCHAR;
576 *bufnext++ = M_END;
577 break;
578 case QUESTION:
579 pglob->gl_flags |= GLOB_MAGCHAR;
580 *bufnext++ = M_ONE;
581 break;
582 case STAR:
583 pglob->gl_flags |= GLOB_MAGCHAR;
584 /* collapse adjacent stars to one,
585 * to avoid exponential behavior
587 if (bufnext == patbuf || bufnext[-1] != M_ALL)
588 *bufnext++ = M_ALL;
589 break;
590 default:
591 *bufnext++ = CHAR(c);
592 break;
595 *bufnext = EOS;
596 #ifdef DEBUG
597 qprintf("glob0:", patbuf);
598 #endif
600 if ((err = glob1(patbuf, pglob, limit)) != 0)
601 return(err);
604 * If there was no match we are going to append the pattern
605 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
606 * and the pattern did not contain any magic characters
607 * GLOB_NOMAGIC is there just for compatibility with csh.
609 if (pglob->gl_pathc == oldpathc) {
610 if (((pglob->gl_flags & GLOB_NOCHECK) ||
611 ((pglob->gl_flags & GLOB_NOMAGIC) &&
612 !(pglob->gl_flags & GLOB_MAGCHAR))))
613 return(globextend(pattern, pglob, limit));
614 else
615 return(GLOB_NOMATCH);
617 if (!(pglob->gl_flags & GLOB_NOSORT))
618 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
619 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
620 return(0);
623 static int
624 compare(const void *p, const void *q)
626 return(strcoll(*(char **)p, *(char **)q));
629 static int
630 glob1(Char *pattern, glob_t *pglob, size_t *limit)
632 Char pathbuf[MAXPATHLEN];
634 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
635 if (*pattern == EOS)
636 return(0);
637 return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
638 pattern, pglob, limit));
642 * The functions glob2 and glob3 are mutually recursive; there is one level
643 * of recursion for each segment in the pattern that contains one or more
644 * meta characters.
646 static int
647 glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
648 glob_t *pglob, size_t *limit)
650 struct stat sb;
651 Char *p, *q;
652 int anymeta;
655 * Loop over pattern segments until end of pattern or until
656 * segment with meta character found.
658 for (anymeta = 0;;) {
659 if (*pattern == EOS) { /* End of pattern? */
660 *pathend = EOS;
661 if (g_lstat(pathbuf, &sb, pglob))
662 return(0);
664 if (((pglob->gl_flags & GLOB_MARK) &&
665 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
666 || (S_ISLNK(sb.st_mode) &&
667 (g_stat(pathbuf, &sb, pglob) == 0) &&
668 S_ISDIR(sb.st_mode)))) {
669 if (pathend + 1 > pathend_last)
670 return (GLOB_ABORTED);
671 *pathend++ = SEP;
672 *pathend = EOS;
674 ++pglob->gl_matchc;
675 return(globextend(pathbuf, pglob, limit));
678 /* Find end of next segment, copy tentatively to pathend. */
679 q = pathend;
680 p = pattern;
681 while (*p != EOS && *p != SEP) {
682 if (ismeta(*p))
683 anymeta = 1;
684 if (q + 1 > pathend_last)
685 return (GLOB_ABORTED);
686 *q++ = *p++;
689 if (!anymeta) { /* No expansion, do next segment. */
690 pathend = q;
691 pattern = p;
692 while (*pattern == SEP) {
693 if (pathend + 1 > pathend_last)
694 return (GLOB_ABORTED);
695 *pathend++ = *pattern++;
697 } else /* Need expansion, recurse. */
698 return(glob3(pathbuf, pathend, pathend_last, pattern, p,
699 pglob, limit));
701 /* NOTREACHED */
704 static int
705 glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
706 Char *pattern, Char *restpattern,
707 glob_t *pglob, size_t *limit)
709 struct dirent *dp;
710 DIR *dirp;
711 int err;
712 char buf[MAXPATHLEN];
715 * The readdirfunc declaration can't be prototyped, because it is
716 * assigned, below, to two functions which are prototyped in glob.h
717 * and dirent.h as taking pointers to differently typed opaque
718 * structures.
719 * CYGWIN: Needs prototype and subsequently wild casting to avoid
720 * compiler error.
722 struct dirent *(*readdirfunc)(void *);
724 if (pathend > pathend_last)
725 return (GLOB_ABORTED);
726 *pathend = EOS;
727 errno = 0;
729 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
730 /* TODO: don't call for ENOENT or ENOTDIR? */
731 if (pglob->gl_errfunc) {
732 if (g_Ctoc(pathbuf, buf, sizeof(buf)))
733 return (GLOB_ABORTED);
734 if (pglob->gl_errfunc(buf, errno) ||
735 pglob->gl_flags & GLOB_ERR)
736 return (GLOB_ABORTED);
738 return(0);
741 err = 0;
743 /* Search directory for matching names. */
744 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
745 readdirfunc = pglob->gl_readdir;
746 else
747 readdirfunc = (dirent*(*)(void*)) readdir;
748 while ((dp = (*readdirfunc)(dirp))) {
749 char *sc;
750 Char *dc;
751 wint_t wc;
752 size_t clen;
753 mbstate_t mbs;
755 /* Initial DOT must be matched literally. */
756 if (dp->d_name[0] == DOT && *pattern != DOT)
757 continue;
758 memset(&mbs, 0, sizeof(mbs));
759 dc = pathend;
760 sc = dp->d_name;
761 while (dc < pathend_last) {
762 clen = mbrtowi(&wc, sc, MB_LEN_MAX, &mbs);
763 if (clen == (size_t)-1 || clen == (size_t)-2) {
764 wc = *sc;
765 clen = 1;
766 memset(&mbs, 0, sizeof(mbs));
768 if ((*dc++ = wc) == EOS)
769 break;
770 sc += clen;
772 if (!match(pathend, pattern, restpattern)) {
773 *pathend = EOS;
774 continue;
776 err = glob2(pathbuf, --dc, pathend_last, restpattern,
777 pglob, limit);
778 if (err)
779 break;
782 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
783 (*pglob->gl_closedir)(dirp);
784 else
785 closedir(dirp);
786 return(err);
791 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
792 * add the new item, and update gl_pathc.
794 * This assumes the BSD realloc, which only copies the block when its size
795 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
796 * behavior.
798 * Return 0 if new item added, error code if memory couldn't be allocated.
800 * Invariant of the glob_t structure:
801 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
802 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
804 static int
805 globextend(const Char *path, glob_t *pglob, size_t *limit)
807 char **pathv;
808 size_t i, newsize, len;
809 char *copy;
810 const Char *p;
812 if (*limit && pglob->gl_pathc > *limit) {
813 errno = 0;
814 return (GLOB_NOSPACE);
817 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
818 pathv = pglob->gl_pathv ?
819 (char **) realloc((char *)pglob->gl_pathv, newsize) :
820 (char **) malloc(newsize);
821 if (pathv == NULL) {
822 if (pglob->gl_pathv) {
823 free(pglob->gl_pathv);
824 pglob->gl_pathv = NULL;
826 return(GLOB_NOSPACE);
829 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
830 /* first time around -- clear initial gl_offs items */
831 pathv += pglob->gl_offs;
832 for (i = pglob->gl_offs + 1; --i > 0; )
833 *--pathv = NULL;
835 pglob->gl_pathv = pathv;
837 for (p = path; *p++;)
838 continue;
839 len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
840 if ((copy = (char *) malloc(len)) != NULL) {
841 if (g_Ctoc(path, copy, len)) {
842 free(copy);
843 return (GLOB_NOSPACE);
845 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
847 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
848 return(copy == NULL ? GLOB_NOSPACE : 0);
852 * pattern matching function for filenames. Each occurrence of the *
853 * pattern causes a recursion level.
855 static int
856 match(Char *name, Char *pat, Char *patend)
858 int ok, negate_range;
859 Char *c, *k;
860 size_t k_len;
862 while (pat < patend) {
863 c = pat++;
864 switch (*c & M_MASK) {
865 case M_ALL:
866 if (pat == patend)
867 return(1);
869 if (match(name, pat, patend))
870 return(1);
871 while (*name++ != EOS);
872 return(0);
873 case M_ONE:
874 if (*name++ == EOS)
875 return(0);
876 break;
877 case M_SET:
878 ok = 0;
879 if (*(k = name) == EOS)
880 return(0);
881 k_len = next_unicode_char (k);
882 name += k_len;
883 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
884 ++pat;
885 while ((*(c = pat++) & M_MASK) != M_END) {
886 size_t len1 = 1, len2 = 1;
888 if ((*c & M_MASK) == M_NAMED) {
889 if (iswctype (*k, *pat++))
890 ok = 1;
891 continue;
893 if ((*c & M_MASK) == M_EQUIV) {
894 if (is_unicode_equiv (*k, *pat++))
895 ok = 1;
896 continue;
898 if (M_COLL_P(*c)) {
899 len1 = M_COLL_CNT(*c);
900 ++c;
901 pat += len1;
903 if ((*pat & M_MASK) == M_RNG) {
904 if (M_COLL_P(pat[1]))
905 len2 = M_COLL_CNT(*++pat);
906 #ifdef __CYGWIN__
907 if ((!__get_current_collate_locale ()->win_locale[0]) ?
908 #else
909 if (__collate_load_error ?
910 #endif
911 *c <= *k && *k <= pat[1] :
912 __wscollate_range_cmp(c, k, len1, k_len) <= 0
913 && __wscollate_range_cmp(k, pat + 1, k_len, len2) <= 0
915 ok = 1;
916 pat += len2 + 1;
917 } else if (len1 == k_len &&
918 wcincmp (c, k, len1) == 0)
919 ok = 1;
921 if (ok == negate_range)
922 return(0);
923 break;
924 default:
925 if (Cchar(*name++) != Cchar(*c))
926 return(0);
927 break;
930 return(*name == EOS);
933 /* Free allocated data belonging to a glob_t structure. */
934 void
935 globfree(glob_t *pglob)
937 size_t i;
938 char **pp;
940 if (pglob->gl_pathv != NULL) {
941 pp = pglob->gl_pathv + pglob->gl_offs;
942 for (i = pglob->gl_pathc; i--; ++pp)
943 if (*pp)
944 free(*pp);
945 free(pglob->gl_pathv);
946 pglob->gl_pathv = NULL;
950 static DIR *
951 g_opendir(Char *str, glob_t *pglob)
953 char buf[MAXPATHLEN];
955 if (!*str)
956 strcpy(buf, ".");
957 else {
958 if (g_Ctoc(str, buf, sizeof(buf)))
959 return (NULL);
962 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
963 return (DIR *) ((*pglob->gl_opendir)((const char *) buf));
965 return(opendir(buf));
968 #define CYGWIN_gl_stat(sfptr) ((*pglob->sfptr) (buf, sb))
970 static int
971 g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
973 char buf[MAXPATHLEN];
975 if (g_Ctoc(fn, buf, sizeof(buf))) {
976 errno = ENAMETOOLONG;
977 return (-1);
979 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
980 return CYGWIN_gl_stat (gl_lstat);
981 return(lstat(buf, sb));
984 static int
985 g_stat(Char *fn, struct stat *sb, glob_t *pglob)
987 char buf[MAXPATHLEN];
989 if (g_Ctoc(fn, buf, sizeof(buf))) {
990 errno = ENAMETOOLONG;
991 return (-1);
993 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
994 return CYGWIN_gl_stat (gl_stat);
995 return(stat(buf, sb));
998 static const Char *
999 g_strchr(const Char *str, wint_t ch)
1002 do {
1003 if (*str == ch)
1004 return (str);
1005 } while (*str++);
1006 return (NULL);
1009 static int
1010 g_Ctoc(const Char *str, char *buf, size_t len)
1012 mbstate_t mbs;
1013 size_t clen;
1015 memset(&mbs, 0, sizeof(mbs));
1016 while (len >= (size_t) MB_CUR_MAX) {
1017 clen = wirtomb(buf, CHAR (*str), &mbs);
1018 if (clen == (size_t)-1)
1019 return (1);
1020 if (*str == L'\0')
1021 return (0);
1022 str++;
1023 buf += clen;
1024 len -= clen;
1026 return (1);
1029 #ifdef DEBUG
1030 static void
1031 qprintf(const char *str, Char *s)
1033 Char *p;
1035 (void)printf("%s:\n", str);
1036 for (p = s; *p; p++)
1037 (void)printf("%c", CHAR(*p));
1038 (void)printf("\n");
1039 for (p = s; *p; p++)
1040 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1041 (void)printf("\n");
1042 for (p = s; *p; p++)
1043 (void)printf("%c", ismeta(*p) ? '_' : ' ');
1044 (void)printf("\n");
1046 #endif