]>
git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/glob.c
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
8 * Copyright (c) 2011 The FreeBSD Foundation
10 * Portions of this software were developed by David Chisnall
11 * under sponsorship from the FreeBSD Foundation.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #if defined(LIBC_SCCS) && !defined(lint)
39 static char sccsid
[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
40 #endif /* LIBC_SCCS and not lint */
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
44 #include "xlocale_private.h"
47 * glob(3) -- a superset of the one defined in POSIX 1003.2.
49 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
51 * Optional extra services, controlled by flags not defined by POSIX:
54 * Escaping convention: \ inhibits any special meaning the following
55 * character might have (except \ at end of string is retained).
57 * Set in gl_flags if pattern contained a globbing character.
59 * Same as GLOB_NOCHECK, but it will only append pattern if it did
60 * not contain any magic characters. [Used in csh style globbing]
62 * Use alternately specified directory access functions.
64 * expand ~user/foo to the /home/dir/of/user/foo
66 * expand {1,2}{a,b} to 1a 1b 2a 2b
68 * Number of matches in the current invocation of glob.
72 * Some notes on multibyte character support:
73 * 1. Patterns with illegal byte sequences match nothing - even if
74 * GLOB_NOCHECK is specified.
75 * 2. Illegal byte sequences in filenames are handled by treating them as
76 * single-byte characters with a values of such bytes of the sequence
78 * 3. State-dependent encodings are not currently supported.
81 #include <sys/param.h>
96 #include <malloc_private.h>
101 * glob(3) expansion limits. Stop the expansion if any of these limits
102 * is reached. This caps the runtime in the face of DoS attacks. See
105 #define GLOB_LIMIT_BRACE 128 /* number of brace calls */
106 #define GLOB_LIMIT_PATH 1024 /* number of path elements */
107 #define GLOB_LIMIT_READDIR 16384 /* number of readdirs */
108 #define GLOB_LIMIT_STAT 128 /* number of stat system calls */
109 #define GLOB_LIMIT_STRING 65536 /* maximum total size for paths */
114 size_t l_readdir_cnt
;
121 #define LBRACKET L'['
123 #define QUESTION L'?'
126 #define RBRACKET L']'
134 #define M_QUOTE 0x8000000000ULL
135 #define M_PROTECT 0x4000000000ULL
136 #define M_MASK 0xffffffffffULL
137 #define M_CHAR 0x00ffffffffULL
139 typedef uint_fast64_t Char
;
141 #define CHAR(c) ((Char)((c)&M_CHAR))
142 #define META(c) ((Char)((c)|M_QUOTE))
143 #define UNPROT(c) ((c) & ~M_PROTECT)
144 #define M_ALL META(L'*')
145 #define M_END META(L']')
146 #define M_NOT META(L'!')
147 #define M_ONE META(L'?')
148 #define M_RNG META(L'-')
149 #define M_SET META(L'[')
150 #define ismeta(c) (((c)&M_QUOTE) != 0)
152 #define isprot(c) (((c)&M_PROTECT) != 0)
156 #define compare __gl_compare
157 #define g_Ctoc __gl_g_Ctoc
158 #define g_strchr __gl_g_strchr
159 #define globextend __gl_globextend
160 #define globtilde __gl_globtilde
161 #define match __gl_match
163 __private_extern__
int compare(const void *, const void *);
164 __private_extern__
int g_Ctoc(const Char
*, char *, size_t, locale_t
);
165 static int g_lstat(Char
*, struct stat
*, glob_t
*, locale_t
);
166 static DIR *g_opendir(Char
*, glob_t
*, locale_t
);
167 __private_extern__
const Char
*g_strchr(const Char
*, wchar_t);
169 static Char
*g_strcat(Char
*, const Char
*);
171 static int g_stat(Char
*, struct stat
*, glob_t
*, locale_t
);
172 static int glob0(const Char
*, glob_t
*, struct glob_limit
*,
173 const char *,locale_t
);
174 static int glob1(Char
*, glob_t
*, struct glob_limit
*, locale_t
);
175 static int glob2(Char
*, Char
*, Char
*, Char
*, glob_t
*,
176 struct glob_limit
*, locale_t
);
177 static int glob3(Char
*, Char
*, Char
*, Char
*, Char
*, glob_t
*,
178 struct glob_limit
*, locale_t
);
179 __private_extern__
int globextend(const Char
*, glob_t
*, struct glob_limit
*,
180 const char *, locale_t
);
181 __private_extern__
const Char
* globtilde(const Char
*, Char
*, size_t, glob_t
*,
183 static int globexp0(const Char
*, glob_t
*, struct glob_limit
*,
184 const char *, locale_t
);
185 static int globexp1(const Char
*, glob_t
*, struct glob_limit
*, locale_t
);
186 static int globexp2(const Char
*, const Char
*, glob_t
*,
187 struct glob_limit
*, locale_t
);
188 static int globfinal(glob_t
*, struct glob_limit
*, size_t,
189 const char *, locale_t
);
190 __private_extern__
int match(Char
*, Char
*, Char
*, locale_t
);
191 static int err_nomatch(glob_t
*, struct glob_limit
*, const char *, locale_t loc
);
192 static int err_aborted(glob_t
*, int, char *);
194 static void qprintf(const char *, Char
*);
198 __glob(const char *pattern
, glob_t
*pglob
)
200 struct glob_limit limit
= { 0, 0, 0, 0, 0 };
202 Char
*bufnext
, *bufend
, patbuf
[MAXPATHLEN
], prot
;
207 locale_t loc
= __current_locale();
208 int mb_cur_max
= MB_CUR_MAX_L(loc
);
211 if (!(pglob
->gl_flags
& GLOB_APPEND
)) {
213 pglob
->gl_pathv
= NULL
;
214 if (!(pglob
->gl_flags
& GLOB_DOOFFS
))
217 if (pglob
->gl_flags
& GLOB_LIMIT
) {
218 limit
.l_path_lim
= pglob
->gl_matchc
;
219 if (limit
.l_path_lim
== 0)
220 limit
.l_path_lim
= GLOB_LIMIT_PATH
;
222 pglob
->gl_matchc
= 0;
225 bufend
= bufnext
+ MAXPATHLEN
- 1;
227 if (pglob
->gl_flags
& GLOB_NOESCAPE
) {
228 memset(&mbs
, 0, sizeof(mbs
));
229 while (bufend
- bufnext
>= mb_cur_max
) {
230 clen
= mbrtowc_l(&wc
, patnext
, MB_LEN_MAX
, &mbs
, loc
);
231 if (clen
== (size_t)-1 || clen
== (size_t)-2)
232 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
233 else if (clen
== 0) {
241 /* Protect the quoted characters. */
242 memset(&mbs
, 0, sizeof(mbs
));
243 while (bufend
- bufnext
>= mb_cur_max
) {
244 if (*patnext
== '\\') {
245 if (*++patnext
== '\0') {
252 clen
= mbrtowc_l(&wc
, patnext
, MB_LEN_MAX
, &mbs
, loc
);
253 if (clen
== (size_t)-1 || clen
== (size_t)-2)
254 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
255 else if (clen
== 0) {
259 *bufnext
++ = wc
| prot
;
264 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
267 if (pglob
->gl_flags
& GLOB_BRACE
)
268 return globexp0(patbuf
, pglob
, &limit
, pattern
, loc
);
270 return glob0(patbuf
, pglob
, &limit
, pattern
, loc
);
274 glob(const char *pattern
, int flags
, int (*errfunc
)(const char *, int), glob_t
*pglob
)
277 pglob
->gl_flags
= flags
& ~(GLOB_MAGCHAR
| _GLOB_ERR_BLOCK
);
278 #else /* !__BLOCKS__ */
279 pglob
->gl_flags
= flags
& ~GLOB_MAGCHAR
;
280 #endif /* __BLOCKS__ */
281 pglob
->gl_errfunc
= errfunc
;
282 return __glob(pattern
, pglob
);
287 glob_b(const char *pattern
, int flags
, int (^errblk
)(const char *, int), glob_t
*pglob
)
289 pglob
->gl_flags
= flags
& ~GLOB_MAGCHAR
;
290 pglob
->gl_flags
|= _GLOB_ERR_BLOCK
;
291 pglob
->gl_errblk
= errblk
;
292 return __glob(pattern
, pglob
);
294 #endif /* __BLOCKS__ */
297 globexp0(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
,
298 const char *origpat
, locale_t loc
) {
302 /* Protect a single {}, for find(1), like csh */
303 if (pattern
[0] == LBRACE
&& pattern
[1] == RBRACE
&& pattern
[2] == EOS
) {
304 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
305 limit
->l_brace_cnt
++ >= GLOB_LIMIT_BRACE
) {
307 return (GLOB_NOSPACE
);
309 return (glob0(pattern
, pglob
, limit
, origpat
, loc
));
312 oldpathc
= pglob
->gl_pathc
;
314 if ((rv
= globexp1(pattern
, pglob
, limit
, loc
)) != 0)
317 return (globfinal(pglob
, limit
, oldpathc
, origpat
, loc
));
321 * Expand recursively a glob {} pattern. When there is no more expansion
322 * invoke the standard globbing routine to glob the rest of the magic
326 globexp1(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
330 if ((ptr
= g_strchr(pattern
, LBRACE
)) != NULL
) {
331 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
332 limit
->l_brace_cnt
++ >= GLOB_LIMIT_BRACE
) {
334 return (GLOB_NOSPACE
);
336 return (globexp2(ptr
, pattern
, pglob
, limit
, loc
));
339 return (glob0(pattern
, pglob
, limit
, NULL
, loc
));
344 * Recursive brace globbing helper. Tries to expand a single brace.
345 * If it succeeds then it invokes globexp1 with the new pattern.
346 * If it fails then it tries to glob the rest of the pattern and returns.
349 globexp2(const Char
*ptr
, const Char
*pattern
, glob_t
*pglob
,
350 struct glob_limit
*limit
, locale_t loc
)
354 const Char
*pe
, *pm
, *pm1
, *pl
;
355 Char patbuf
[MAXPATHLEN
];
357 /* copy part up to the brace */
358 for (lm
= patbuf
, pm
= pattern
; pm
!= ptr
; *lm
++ = *pm
++)
363 /* Find the balanced brace */
364 for (i
= 0, pe
= ++ptr
; *pe
!= EOS
; pe
++)
365 if (*pe
== LBRACKET
) {
366 /* Ignore everything between [] */
367 for (pm
= pe
++; *pe
!= RBRACKET
&& *pe
!= EOS
; pe
++)
371 * We could not find a matching RBRACKET.
372 * Ignore and just look for RBRACE
377 else if (*pe
== LBRACE
)
379 else if (*pe
== RBRACE
) {
385 /* Non matching braces; just glob the pattern */
386 if (i
!= 0 || *pe
== EOS
)
387 return (glob0(pattern
, pglob
, limit
, NULL
, loc
));
389 for (i
= 0, pl
= pm
= ptr
; pm
<= pe
; pm
++)
392 /* Ignore everything between [] */
393 for (pm1
= pm
++; *pm
!= RBRACKET
&& *pm
!= EOS
; pm
++)
397 * We could not find a matching RBRACKET.
398 * Ignore and just look for RBRACE
415 if (i
&& *pm
== COMMA
)
418 /* Append the current string */
419 for (lm
= ls
; (pl
< pm
); *lm
++ = *pl
++)
422 * Append the rest of the pattern after the
425 for (pl
= pe
+ 1; (*lm
++ = *pl
++) != EOS
;)
428 /* Expand the current pattern */
430 qprintf("globexp2:", patbuf
);
432 rv
= globexp1(patbuf
, pglob
, limit
, loc
);
436 /* move after the comma, to the next string */
449 #ifndef BUILDING_VARIANT
451 * expand tilde from the passwd file.
453 __private_extern__
const Char
*
454 globtilde(const Char
*pattern
, Char
*patbuf
, size_t patbuf_len
, glob_t
*pglob
, locale_t loc
)
461 wchar_t wbuf
[MAXPATHLEN
];
462 wchar_t *wbufend
, *dc
;
467 if (*pattern
!= TILDE
|| !(pglob
->gl_flags
& GLOB_TILDE
))
471 * Copy up to the end of the string or /
473 eb
= &patbuf
[patbuf_len
- 1];
474 for (p
= pattern
+ 1, b
= patbuf
;
475 b
< eb
&& *p
!= EOS
&& UNPROT(*p
) != SEP
; *b
++ = *p
++)
478 if (*p
!= EOS
&& UNPROT(*p
) != SEP
)
484 if (patbuf
[0] == EOS
) {
486 * handle a plain ~ or ~/ by expanding $HOME first (iff
487 * we're not running setuid or setgid) and then trying
490 if (issetugid() != 0 ||
491 (h
= getenv("HOME")) == NULL
) {
492 if (((h
= getlogin()) != NULL
&&
493 (pwd
= getpwnam(h
)) != NULL
) ||
494 (pwd
= getpwuid(getuid())) != NULL
)
504 if (g_Ctoc(patbuf
, (char *)wbuf
, sizeof(wbuf
), loc
))
506 if ((pwd
= getpwnam((char *)wbuf
)) == NULL
)
512 /* Copy the home directory */
515 wbufend
= wbuf
+ MAXPATHLEN
- 1;
517 memset(&mbs
, 0, sizeof(mbs
));
518 while (dc
<= wbufend
) {
519 clen
= mbrtowc(&wc
, sc
, MB_LEN_MAX
, &mbs
);
520 if (clen
== (size_t)-1 || clen
== (size_t)-2) {
521 /* XXX See initial comment #2. */
522 wc
= (unsigned char)*sc
;
524 memset(&mbs
, 0, sizeof(mbs
));
526 if ((*dc
++ = wc
) == EOS
) {
536 for (b
= patbuf
; b
< eb
&& *dc
!= EOS
; *b
++ = *dc
++ | M_PROTECT
)
541 /* Append the rest of the pattern */
545 if ((*b
++ = *p
++) == EOS
) {
557 #endif /* BUILDING_VARIANT */
561 * The main glob() routine: compiles the pattern (optionally processing
562 * quotes), calls glob1() to do the real pattern matching, and finally
563 * sorts the list (unless unsorted operation is requested). Returns 0
564 * if things went well, nonzero if errors occurred.
567 glob0(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
,
568 const char *origpat
, locale_t loc
)
570 const Char
*qpatnext
;
573 Char
*bufnext
, c
, patbuf
[MAXPATHLEN
];
575 qpatnext
= globtilde(pattern
, patbuf
, MAXPATHLEN
, pglob
, loc
);
576 if (qpatnext
== NULL
) {
578 return (GLOB_NOSPACE
);
580 oldpathc
= pglob
->gl_pathc
;
583 /* We don't need to check for buffer overflow any more. */
584 while ((c
= *qpatnext
++) != EOS
) {
590 if (*qpatnext
== EOS
||
591 g_strchr(qpatnext
+1, RBRACKET
) == NULL
) {
592 *bufnext
++ = LBRACKET
;
602 *bufnext
++ = CHAR(c
);
603 if (*qpatnext
== RANGE
&&
604 (c
= qpatnext
[1]) != RBRACKET
) {
606 *bufnext
++ = CHAR(c
);
609 } while ((c
= *qpatnext
++) != RBRACKET
);
610 pglob
->gl_flags
|= GLOB_MAGCHAR
;
614 pglob
->gl_flags
|= GLOB_MAGCHAR
;
618 pglob
->gl_flags
|= GLOB_MAGCHAR
;
619 /* collapse adjacent stars to one,
620 * to ensure "**" at the end continues to match the
623 if (bufnext
== patbuf
|| bufnext
[-1] != M_ALL
)
627 *bufnext
++ = CHAR(c
);
633 qprintf("glob0:", patbuf
);
636 if ((err
= glob1(patbuf
, pglob
, limit
, loc
)) != 0)
640 return (globfinal(pglob
, limit
, oldpathc
, origpat
, loc
));
646 globfinal(glob_t
*pglob
, struct glob_limit
*limit
, size_t oldpathc
,
647 const char *origpat
, locale_t loc
) {
648 if (pglob
->gl_pathc
== oldpathc
)
649 return (err_nomatch(pglob
, limit
, origpat
, loc
));
651 if (!(pglob
->gl_flags
& GLOB_NOSORT
))
652 qsort(pglob
->gl_pathv
+ pglob
->gl_offs
+ oldpathc
,
653 pglob
->gl_pathc
- oldpathc
, sizeof(char *), compare
);
658 #ifndef BUILDING_VARIANT
659 __private_extern__
int
660 compare(const void *p
, const void *q
)
662 return(strcoll(*(char **)p
, *(char **)q
));
664 #endif /* BUILDING_VARIANT */
667 glob1(Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
669 Char pathbuf
[MAXPATHLEN
];
671 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
674 return (glob2(pathbuf
, pathbuf
, pathbuf
+ MAXPATHLEN
- 1,
675 pattern
, pglob
, limit
, loc
));
679 * The functions glob2 and glob3 are mutually recursive; there is one level
680 * of recursion for each segment in the pattern that contains one or more
684 glob2(Char
*pathbuf
, Char
*pathend
, Char
*pathend_last
, Char
*pattern
,
685 glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
692 * Loop over pattern segments until end of pattern or until
693 * segment with meta character found.
695 for (anymeta
= 0;;) {
696 if (*pattern
== EOS
) { /* End of pattern? */
698 if (g_lstat(pathbuf
, &sb
, pglob
, loc
))
701 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
702 limit
->l_stat_cnt
++ >= GLOB_LIMIT_STAT
) {
704 return (GLOB_NOSPACE
);
706 if ((pglob
->gl_flags
& GLOB_MARK
) &&
707 UNPROT(pathend
[-1]) != SEP
&&
708 (S_ISDIR(sb
.st_mode
) ||
709 (S_ISLNK(sb
.st_mode
) &&
710 g_stat(pathbuf
, &sb
, pglob
, loc
) == 0 &&
711 S_ISDIR(sb
.st_mode
)))) {
712 if (pathend
+ 1 > pathend_last
) {
714 return (GLOB_NOSPACE
);
720 return (globextend(pathbuf
, pglob
, limit
, NULL
, loc
));
723 /* Find end of next segment, copy tentatively to pathend. */
726 while (*p
!= EOS
&& UNPROT(*p
) != SEP
) {
729 if (q
+ 1 > pathend_last
) {
731 return (GLOB_NOSPACE
);
736 if (!anymeta
) { /* No expansion, do next segment. */
739 while (UNPROT(*pattern
) == SEP
) {
740 if (pathend
+ 1 > pathend_last
) {
742 return (GLOB_NOSPACE
);
744 *pathend
++ = *pattern
++;
746 } else /* Need expansion, recurse. */
747 return(glob3(pathbuf
, pathend
, pathend_last
, pattern
,
748 p
, pglob
, limit
, loc
));
754 glob3(Char
*pathbuf
, Char
*pathend
, Char
*pathend_last
,
755 Char
*pattern
, Char
*restpattern
,
756 glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
760 int err
, too_long
, saverrno
, saverrno2
;
761 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
764 * The readdirfunc declaration can't be prototyped, because it is
765 * assigned, below, to two functions which are prototyped in glob.h
766 * and dirent.h as taking pointers to differently typed opaque
769 struct dirent
*(*readdirfunc
)();
771 if (pathend
> pathend_last
) {
773 return (GLOB_NOSPACE
);
776 if ((pglob
->gl_errfunc
!= NULL
|| pglob
->gl_errblk
!= NULL
) &&
777 g_Ctoc(pathbuf
, buf
, sizeof(buf
), loc
)) {
779 return (GLOB_NOSPACE
);
785 if ((dirp
= g_opendir(pathbuf
, pglob
, loc
)) == NULL
) {
786 if (errno
== ENOENT
|| errno
== ENOTDIR
)
789 err
= err_aborted(pglob
, errno
, buf
);
797 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
798 readdirfunc
= pglob
->gl_readdir
;
800 readdirfunc
= readdir
;
803 /* Search directory for matching names. */
804 while ((dp
= (*readdirfunc
)(dirp
)) != NULL
) {
811 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
812 limit
->l_readdir_cnt
++ >= GLOB_LIMIT_READDIR
) {
818 /* Initial DOT must be matched literally. */
819 if (dp
->d_name
[0] == '.' && UNPROT(*pattern
) != DOT
) {
823 memset(&mbs
, 0, sizeof(mbs
));
827 while (dc
<= pathend_last
) {
828 clen
= mbrtowc_l(&wc
, sc
, MB_LEN_MAX
, &mbs
, loc
);
829 if (clen
== (size_t)-1 || clen
== (size_t)-2) {
830 /* XXX See initial comment #2. */
831 wc
= (unsigned char)*sc
;
833 memset(&mbs
, 0, sizeof(mbs
));
835 if ((*dc
++ = wc
) == EOS
) {
841 if (too_long
&& (err
= err_aborted(pglob
, ENAMETOOLONG
,
843 errno
= ENAMETOOLONG
;
846 if (too_long
|| !match(pathend
, pattern
, restpattern
, loc
)) {
853 err
= glob2(pathbuf
, --dc
, pathend_last
, restpattern
,
861 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
862 (*pglob
->gl_closedir
)(dirp
);
870 if (dp
== NULL
&& errno
!= 0 &&
871 (err
= err_aborted(pglob
, errno
, buf
)))
880 #ifndef BUILDING_VARIANT
882 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
883 * add the new item, and update gl_pathc.
885 * This assumes the BSD realloc, which only copies the block when its size
886 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
889 * Return 0 if new item added, error code if memory couldn't be allocated.
891 * Invariant of the glob_t structure:
892 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
893 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
895 __private_extern__
int
896 globextend(const Char
*path
, glob_t
*pglob
, struct glob_limit
*limit
,
897 const char *origpat
, locale_t loc
)
904 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
905 pglob
->gl_matchc
> limit
->l_path_lim
) {
907 return (GLOB_NOSPACE
);
910 newn
= 2 + pglob
->gl_pathc
+ pglob
->gl_offs
;
911 /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
912 pathv
= reallocarray(pglob
->gl_pathv
, newn
, sizeof(*pathv
));
914 return (GLOB_NOSPACE
);
916 if (pglob
->gl_pathv
== NULL
&& pglob
->gl_offs
> 0) {
917 /* first time around -- clear initial gl_offs items */
918 pathv
+= pglob
->gl_offs
;
919 for (i
= pglob
->gl_offs
+ 1; --i
> 0; )
922 pglob
->gl_pathv
= pathv
;
925 copy
= strdup(origpat
);
927 for (p
= path
; *p
++ != EOS
;)
929 len
= MB_CUR_MAX_L(loc
) * (size_t)(p
- path
); /* XXX overallocation */
930 if ((copy
= malloc(len
)) != NULL
) {
931 if (g_Ctoc(path
, copy
, len
, loc
)) {
934 return (GLOB_NOSPACE
);
939 limit
->l_string_cnt
+= strlen(copy
) + 1;
940 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
941 limit
->l_string_cnt
>= GLOB_LIMIT_STRING
) {
944 return (GLOB_NOSPACE
);
946 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
++] = copy
;
948 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
] = NULL
;
949 return (copy
== NULL
? GLOB_NOSPACE
: 0);
953 * pattern matching function for filenames.
955 __private_extern__
int
956 match(Char
*name
, Char
*pat
, Char
*patend
, locale_t loc
)
958 int ok
, negate_range
;
959 Char c
, k
, *nextp
, *nextn
;
965 while (pat
< patend
) {
967 switch (c
& M_MASK
) {
982 if ((k
= *name
++) == EOS
)
984 negate_range
= ((*pat
& M_MASK
) == M_NOT
);
985 if (negate_range
!= 0)
987 while (((c
= *pat
++) & M_MASK
) != M_END
)
988 if ((*pat
& M_MASK
) == M_RNG
) {
989 if (loc
->__collate_load_error
?
990 CHAR(c
) <= CHAR(k
) && CHAR(k
) <= CHAR(pat
[1]) :
991 __collate_range_cmp(CHAR(c
), CHAR(k
), loc
) <= 0
992 && __collate_range_cmp(CHAR(k
), CHAR(pat
[1]), loc
) <= 0
999 if (ok
== negate_range
)
1020 /* Free allocated data belonging to a glob_t structure. */
1022 globfree(glob_t
*pglob
)
1027 if (pglob
->gl_pathv
!= NULL
) {
1028 pp
= pglob
->gl_pathv
+ pglob
->gl_offs
;
1029 for (i
= pglob
->gl_pathc
; i
--; ++pp
)
1032 free(pglob
->gl_pathv
);
1033 pglob
->gl_pathv
= NULL
;
1036 #endif /* !BUILDING_VARIANT */
1039 g_opendir(Char
*str
, glob_t
*pglob
, locale_t loc
)
1041 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1046 if (g_Ctoc(str
, buf
, sizeof(buf
), loc
)) {
1047 errno
= ENAMETOOLONG
;
1052 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1053 return ((*pglob
->gl_opendir
)(buf
));
1055 return (opendir(buf
));
1059 g_lstat(Char
*fn
, struct stat
*sb
, glob_t
*pglob
, locale_t loc
)
1061 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1063 if (g_Ctoc(fn
, buf
, sizeof(buf
), loc
)) {
1064 errno
= ENAMETOOLONG
;
1067 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1068 return((*pglob
->gl_lstat
)(buf
, sb
));
1069 return (lstat(buf
, sb
));
1073 g_stat(Char
*fn
, struct stat
*sb
, glob_t
*pglob
, locale_t loc
)
1075 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1077 if (g_Ctoc(fn
, buf
, sizeof(buf
), loc
)) {
1078 errno
= ENAMETOOLONG
;
1081 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1082 return ((*pglob
->gl_stat
)(buf
, sb
));
1083 return (stat(buf
, sb
));
1086 #ifndef BUILDING_VARIANT
1087 __private_extern__
const Char
*
1088 g_strchr(const Char
*str
, wchar_t ch
)
1098 __private_extern__
int
1099 g_Ctoc(const Char
*str
, char *buf
, size_t len
, locale_t loc
)
1103 int mb_cur_max
= MB_CUR_MAX_L(loc
);
1105 memset(&mbs
, 0, sizeof(mbs
));
1106 while (len
>= mb_cur_max
) {
1107 clen
= wcrtomb_l(buf
, *str
, &mbs
, loc
);
1108 if (clen
== (size_t)-1) {
1109 /* XXX See initial comment #2. */
1110 *buf
= (char)CHAR(*str
);
1112 memset(&mbs
, 0, sizeof(mbs
));
1114 if (CHAR(*str
) == EOS
)
1122 #endif /* !BUILDING_VARIANT */
1125 err_nomatch(glob_t
*pglob
, struct glob_limit
*limit
, const char *origpat
, locale_t loc
) {
1127 * If there was no match we are going to append the origpat
1128 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
1129 * and the origpat did not contain any magic characters
1130 * GLOB_NOMAGIC is there just for compatibility with csh.
1132 if ((pglob
->gl_flags
& GLOB_NOCHECK
) ||
1133 ((pglob
->gl_flags
& GLOB_NOMAGIC
) &&
1134 !(pglob
->gl_flags
& GLOB_MAGCHAR
)))
1135 return (globextend(NULL
, pglob
, limit
, origpat
, loc
));
1136 return (GLOB_NOMATCH
);
1140 err_aborted(glob_t
*pglob
, int err
, char *buf
) {
1142 if (pglob
->gl_flags
& _GLOB_ERR_BLOCK
&& pglob
->gl_errblk(buf
, errno
)) {
1143 return (GLOB_ABORTED
);
1145 #endif /* __BLOCKS__ */
1146 if (pglob
->gl_errfunc
!= NULL
&& pglob
->gl_errfunc(buf
, errno
)) {
1147 return (GLOB_ABORTED
);
1148 } else if (pglob
->gl_flags
& GLOB_ERR
) {
1149 return (GLOB_ABORTED
);
1156 qprintf(const char *str
, Char
*s
)
1160 (void)printf("%s\n", str
);
1162 for (p
= s
; *p
!= EOS
; p
++)
1163 (void)printf("%c", (char)CHAR(*p
));
1165 for (p
= s
; *p
!= EOS
; p
++)
1166 (void)printf("%c", (isprot(*p
) ? '\\' : ' '));
1168 for (p
= s
; *p
!= EOS
; p
++)
1169 (void)printf("%c", (ismeta(*p
) ? '_' : ' '));