]>
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 #pragma clang diagnostic push
39 #pragma clang diagnostic ignored "-Wstrict-prototypes"
41 #if defined(LIBC_SCCS) && !defined(lint)
42 static char sccsid
[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
43 #endif /* LIBC_SCCS and not lint */
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
47 #include "xlocale_private.h"
50 * glob(3) -- a superset of the one defined in POSIX 1003.2.
52 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
54 * Optional extra services, controlled by flags not defined by POSIX:
57 * Escaping convention: \ inhibits any special meaning the following
58 * character might have (except \ at end of string is retained).
60 * Set in gl_flags if pattern contained a globbing character.
62 * Same as GLOB_NOCHECK, but it will only append pattern if it did
63 * not contain any magic characters. [Used in csh style globbing]
65 * Use alternately specified directory access functions.
67 * expand ~user/foo to the /home/dir/of/user/foo
69 * expand {1,2}{a,b} to 1a 1b 2a 2b
71 * Number of matches in the current invocation of glob.
75 * Some notes on multibyte character support:
76 * 1. Patterns with illegal byte sequences match nothing - even if
77 * GLOB_NOCHECK is specified.
78 * 2. Illegal byte sequences in filenames are handled by treating them as
79 * single-byte characters with a values of such bytes of the sequence
81 * 3. State-dependent encodings are not currently supported.
84 #include <sys/param.h>
99 #include <malloc_private.h>
104 * glob(3) expansion limits. Stop the expansion if any of these limits
105 * is reached. This caps the runtime in the face of DoS attacks. See
108 #define GLOB_LIMIT_BRACE 128 /* number of brace calls */
109 #define GLOB_LIMIT_PATH 1024 /* number of path elements */
110 #define GLOB_LIMIT_READDIR 16384 /* number of readdirs */
111 #define GLOB_LIMIT_STAT 128 /* number of stat system calls */
112 #define GLOB_LIMIT_STRING 65536 /* maximum total size for paths */
117 size_t l_readdir_cnt
;
124 #define LBRACKET L'['
126 #define QUESTION L'?'
129 #define RBRACKET L']'
137 #define M_QUOTE 0x8000000000ULL
138 #define M_PROTECT 0x4000000000ULL
139 #define M_MASK 0xffffffffffULL
140 #define M_CHAR 0x00ffffffffULL
142 typedef uint_fast64_t Char
;
144 #define CHAR(c) ((Char)((c)&M_CHAR))
145 #define META(c) ((Char)((c)|M_QUOTE))
146 #define UNPROT(c) ((c) & ~M_PROTECT)
147 #define M_ALL META(L'*')
148 #define M_END META(L']')
149 #define M_NOT META(L'!')
150 #define M_ONE META(L'?')
151 #define M_RNG META(L'-')
152 #define M_SET META(L'[')
153 #define ismeta(c) (((c)&M_QUOTE) != 0)
155 #define isprot(c) (((c)&M_PROTECT) != 0)
159 #define compare __gl_compare
160 #define g_Ctoc __gl_g_Ctoc
161 #define g_strchr __gl_g_strchr
162 #define globextend __gl_globextend
163 #define globtilde __gl_globtilde
164 #define match __gl_match
166 __private_extern__
int compare(const void *, const void *);
167 __private_extern__
int g_Ctoc(const Char
*, char *, size_t, locale_t
);
168 static int g_lstat(Char
*, struct stat
*, glob_t
*, locale_t
);
169 static DIR *g_opendir(Char
*, glob_t
*, locale_t
);
170 __private_extern__
const Char
*g_strchr(const Char
*, wchar_t);
172 static Char
*g_strcat(Char
*, const Char
*);
174 static int g_stat(Char
*, struct stat
*, glob_t
*, locale_t
);
175 static int glob0(const Char
*, glob_t
*, struct glob_limit
*,
176 const char *,locale_t
);
177 static int glob1(Char
*, glob_t
*, struct glob_limit
*, locale_t
);
178 static int glob2(Char
*, Char
*, Char
*, Char
*, glob_t
*,
179 struct glob_limit
*, locale_t
);
180 static int glob3(Char
*, Char
*, Char
*, Char
*, Char
*, glob_t
*,
181 struct glob_limit
*, locale_t
);
182 __private_extern__
int globextend(const Char
*, glob_t
*, struct glob_limit
*,
183 const char *, locale_t
);
184 __private_extern__
const Char
* globtilde(const Char
*, Char
*, size_t, glob_t
*,
186 static int globexp0(const Char
*, glob_t
*, struct glob_limit
*,
187 const char *, locale_t
);
188 static int globexp1(const Char
*, glob_t
*, struct glob_limit
*, locale_t
);
189 static int globexp2(const Char
*, const Char
*, glob_t
*,
190 struct glob_limit
*, locale_t
);
191 static int globfinal(glob_t
*, struct glob_limit
*, size_t,
192 const char *, locale_t
);
193 __private_extern__
int match(Char
*, Char
*, Char
*, locale_t
);
194 static int err_nomatch(glob_t
*, struct glob_limit
*, const char *, locale_t loc
);
195 static int err_aborted(glob_t
*, int, char *);
197 static void qprintf(const char *, Char
*);
201 __glob(const char *pattern
, glob_t
*pglob
)
203 struct glob_limit limit
= { 0, 0, 0, 0, 0 };
205 Char
*bufnext
, *bufend
, patbuf
[MAXPATHLEN
], prot
;
210 locale_t loc
= __current_locale();
211 int mb_cur_max
= MB_CUR_MAX_L(loc
);
214 if (!(pglob
->gl_flags
& GLOB_APPEND
)) {
216 pglob
->gl_pathv
= NULL
;
217 if (!(pglob
->gl_flags
& GLOB_DOOFFS
))
220 if (pglob
->gl_flags
& GLOB_LIMIT
) {
221 limit
.l_path_lim
= pglob
->gl_matchc
;
222 if (limit
.l_path_lim
== 0)
223 limit
.l_path_lim
= GLOB_LIMIT_PATH
;
225 pglob
->gl_matchc
= 0;
228 bufend
= bufnext
+ MAXPATHLEN
- 1;
230 if (pglob
->gl_flags
& GLOB_NOESCAPE
) {
231 memset(&mbs
, 0, sizeof(mbs
));
232 while (bufend
- bufnext
>= mb_cur_max
) {
233 clen
= mbrtowc_l(&wc
, patnext
, MB_LEN_MAX
, &mbs
, loc
);
234 if (clen
== (size_t)-1 || clen
== (size_t)-2)
235 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
236 else if (clen
== 0) {
244 /* Protect the quoted characters. */
245 memset(&mbs
, 0, sizeof(mbs
));
246 while (bufend
- bufnext
>= mb_cur_max
) {
247 if (*patnext
== '\\') {
248 if (*++patnext
== '\0') {
255 clen
= mbrtowc_l(&wc
, patnext
, MB_LEN_MAX
, &mbs
, loc
);
256 if (clen
== (size_t)-1 || clen
== (size_t)-2)
257 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
258 else if (clen
== 0) {
262 *bufnext
++ = wc
| prot
;
267 return (err_nomatch(pglob
, &limit
, pattern
, loc
));
270 if (pglob
->gl_flags
& GLOB_BRACE
)
271 return globexp0(patbuf
, pglob
, &limit
, pattern
, loc
);
273 return glob0(patbuf
, pglob
, &limit
, pattern
, loc
);
277 glob(const char *pattern
, int flags
, int (*errfunc
)(const char *, int), glob_t
*pglob
)
280 pglob
->gl_flags
= flags
& ~(GLOB_MAGCHAR
| _GLOB_ERR_BLOCK
);
281 #else /* !__BLOCKS__ */
282 pglob
->gl_flags
= flags
& ~GLOB_MAGCHAR
;
283 #endif /* __BLOCKS__ */
284 pglob
->gl_errfunc
= errfunc
;
285 return __glob(pattern
, pglob
);
290 glob_b(const char *pattern
, int flags
, int (^errblk
)(const char *, int), glob_t
*pglob
)
292 pglob
->gl_flags
= flags
& ~GLOB_MAGCHAR
;
293 pglob
->gl_flags
|= _GLOB_ERR_BLOCK
;
294 pglob
->gl_errblk
= errblk
;
295 return __glob(pattern
, pglob
);
297 #endif /* __BLOCKS__ */
300 globexp0(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
,
301 const char *origpat
, locale_t loc
) {
305 /* Protect a single {}, for find(1), like csh */
306 if (pattern
[0] == LBRACE
&& pattern
[1] == RBRACE
&& pattern
[2] == EOS
) {
307 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
308 limit
->l_brace_cnt
++ >= GLOB_LIMIT_BRACE
) {
310 return (GLOB_NOSPACE
);
312 return (glob0(pattern
, pglob
, limit
, origpat
, loc
));
315 oldpathc
= pglob
->gl_pathc
;
317 if ((rv
= globexp1(pattern
, pglob
, limit
, loc
)) != 0)
320 return (globfinal(pglob
, limit
, oldpathc
, origpat
, loc
));
324 * Expand recursively a glob {} pattern. When there is no more expansion
325 * invoke the standard globbing routine to glob the rest of the magic
329 globexp1(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
333 if ((ptr
= g_strchr(pattern
, LBRACE
)) != NULL
) {
334 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
335 limit
->l_brace_cnt
++ >= GLOB_LIMIT_BRACE
) {
337 return (GLOB_NOSPACE
);
339 return (globexp2(ptr
, pattern
, pglob
, limit
, loc
));
342 return (glob0(pattern
, pglob
, limit
, NULL
, loc
));
347 * Recursive brace globbing helper. Tries to expand a single brace.
348 * If it succeeds then it invokes globexp1 with the new pattern.
349 * If it fails then it tries to glob the rest of the pattern and returns.
352 globexp2(const Char
*ptr
, const Char
*pattern
, glob_t
*pglob
,
353 struct glob_limit
*limit
, locale_t loc
)
357 const Char
*pe
, *pm
, *pm1
, *pl
;
358 Char patbuf
[MAXPATHLEN
];
360 /* copy part up to the brace */
361 for (lm
= patbuf
, pm
= pattern
; pm
!= ptr
; *lm
++ = *pm
++)
366 /* Find the balanced brace */
367 for (i
= 0, pe
= ++ptr
; *pe
!= EOS
; pe
++)
368 if (*pe
== LBRACKET
) {
369 /* Ignore everything between [] */
370 for (pm
= pe
++; *pe
!= RBRACKET
&& *pe
!= EOS
; pe
++)
374 * We could not find a matching RBRACKET.
375 * Ignore and just look for RBRACE
380 else if (*pe
== LBRACE
)
382 else if (*pe
== RBRACE
) {
388 /* Non matching braces; just glob the pattern */
389 if (i
!= 0 || *pe
== EOS
)
390 return (glob0(pattern
, pglob
, limit
, NULL
, loc
));
392 for (i
= 0, pl
= pm
= ptr
; pm
<= pe
; pm
++)
395 /* Ignore everything between [] */
396 for (pm1
= pm
++; *pm
!= RBRACKET
&& *pm
!= EOS
; pm
++)
400 * We could not find a matching RBRACKET.
401 * Ignore and just look for RBRACE
418 if (i
&& *pm
== COMMA
)
421 /* Append the current string */
422 for (lm
= ls
; (pl
< pm
); *lm
++ = *pl
++)
425 * Append the rest of the pattern after the
428 for (pl
= pe
+ 1; (*lm
++ = *pl
++) != EOS
;)
431 /* Expand the current pattern */
433 qprintf("globexp2:", patbuf
);
435 rv
= globexp1(patbuf
, pglob
, limit
, loc
);
439 /* move after the comma, to the next string */
452 #ifndef BUILDING_VARIANT
454 * expand tilde from the passwd file.
456 __private_extern__
const Char
*
457 globtilde(const Char
*pattern
, Char
*patbuf
, size_t patbuf_len
, glob_t
*pglob
, locale_t loc
)
464 wchar_t wbuf
[MAXPATHLEN
];
465 wchar_t *wbufend
, *dc
;
470 if (*pattern
!= TILDE
|| !(pglob
->gl_flags
& GLOB_TILDE
))
474 * Copy up to the end of the string or /
476 eb
= &patbuf
[patbuf_len
- 1];
477 for (p
= pattern
+ 1, b
= patbuf
;
478 b
< eb
&& *p
!= EOS
&& UNPROT(*p
) != SEP
; *b
++ = *p
++)
481 if (*p
!= EOS
&& UNPROT(*p
) != SEP
)
487 if (patbuf
[0] == EOS
) {
489 * handle a plain ~ or ~/ by expanding $HOME first (iff
490 * we're not running setuid or setgid) and then trying
493 if (issetugid() != 0 ||
494 (h
= getenv("HOME")) == NULL
) {
495 if (((h
= getlogin()) != NULL
&&
496 (pwd
= getpwnam(h
)) != NULL
) ||
497 (pwd
= getpwuid(getuid())) != NULL
)
507 if (g_Ctoc(patbuf
, (char *)wbuf
, sizeof(wbuf
), loc
))
509 if ((pwd
= getpwnam((char *)wbuf
)) == NULL
)
515 /* Copy the home directory */
518 wbufend
= wbuf
+ MAXPATHLEN
- 1;
520 memset(&mbs
, 0, sizeof(mbs
));
521 while (dc
<= wbufend
) {
522 clen
= mbrtowc(&wc
, sc
, MB_LEN_MAX
, &mbs
);
523 if (clen
== (size_t)-1 || clen
== (size_t)-2) {
524 /* XXX See initial comment #2. */
525 wc
= (unsigned char)*sc
;
527 memset(&mbs
, 0, sizeof(mbs
));
529 if ((*dc
++ = wc
) == EOS
) {
539 for (b
= patbuf
; b
< eb
&& *dc
!= EOS
; *b
++ = *dc
++ | M_PROTECT
)
544 /* Append the rest of the pattern */
548 if ((*b
++ = *p
++) == EOS
) {
560 #endif /* BUILDING_VARIANT */
564 * The main glob() routine: compiles the pattern (optionally processing
565 * quotes), calls glob1() to do the real pattern matching, and finally
566 * sorts the list (unless unsorted operation is requested). Returns 0
567 * if things went well, nonzero if errors occurred.
570 glob0(const Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
,
571 const char *origpat
, locale_t loc
)
573 const Char
*qpatnext
;
576 Char
*bufnext
, c
, patbuf
[MAXPATHLEN
];
578 qpatnext
= globtilde(pattern
, patbuf
, MAXPATHLEN
, pglob
, loc
);
579 if (qpatnext
== NULL
) {
581 return (GLOB_NOSPACE
);
583 oldpathc
= pglob
->gl_pathc
;
586 /* We don't need to check for buffer overflow any more. */
587 while ((c
= *qpatnext
++) != EOS
) {
593 if (*qpatnext
== EOS
||
594 g_strchr(qpatnext
+1, RBRACKET
) == NULL
) {
595 *bufnext
++ = LBRACKET
;
605 *bufnext
++ = CHAR(c
);
606 if (*qpatnext
== RANGE
&&
607 (c
= qpatnext
[1]) != RBRACKET
) {
609 *bufnext
++ = CHAR(c
);
612 } while ((c
= *qpatnext
++) != RBRACKET
);
613 pglob
->gl_flags
|= GLOB_MAGCHAR
;
617 pglob
->gl_flags
|= GLOB_MAGCHAR
;
621 pglob
->gl_flags
|= GLOB_MAGCHAR
;
622 /* collapse adjacent stars to one,
623 * to ensure "**" at the end continues to match the
626 if (bufnext
== patbuf
|| bufnext
[-1] != M_ALL
)
630 *bufnext
++ = CHAR(c
);
636 qprintf("glob0:", patbuf
);
639 if ((err
= glob1(patbuf
, pglob
, limit
, loc
)) != 0)
643 return (globfinal(pglob
, limit
, oldpathc
, origpat
, loc
));
649 globfinal(glob_t
*pglob
, struct glob_limit
*limit
, size_t oldpathc
,
650 const char *origpat
, locale_t loc
) {
651 if (pglob
->gl_pathc
== oldpathc
)
652 return (err_nomatch(pglob
, limit
, origpat
, loc
));
654 if (!(pglob
->gl_flags
& GLOB_NOSORT
))
655 qsort(pglob
->gl_pathv
+ pglob
->gl_offs
+ oldpathc
,
656 pglob
->gl_pathc
- oldpathc
, sizeof(char *), compare
);
661 #ifndef BUILDING_VARIANT
662 __private_extern__
int
663 compare(const void *p
, const void *q
)
665 return(strcoll(*(char **)p
, *(char **)q
));
667 #endif /* BUILDING_VARIANT */
670 glob1(Char
*pattern
, glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
672 Char pathbuf
[MAXPATHLEN
];
674 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
677 return (glob2(pathbuf
, pathbuf
, pathbuf
+ MAXPATHLEN
- 1,
678 pattern
, pglob
, limit
, loc
));
682 * The functions glob2 and glob3 are mutually recursive; there is one level
683 * of recursion for each segment in the pattern that contains one or more
687 glob2(Char
*pathbuf
, Char
*pathend
, Char
*pathend_last
, Char
*pattern
,
688 glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
695 * Loop over pattern segments until end of pattern or until
696 * segment with meta character found.
698 for (anymeta
= 0;;) {
699 if (*pattern
== EOS
) { /* End of pattern? */
701 if (g_lstat(pathbuf
, &sb
, pglob
, loc
))
704 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
705 limit
->l_stat_cnt
++ >= GLOB_LIMIT_STAT
) {
707 return (GLOB_NOSPACE
);
709 if ((pglob
->gl_flags
& GLOB_MARK
) &&
710 UNPROT(pathend
[-1]) != SEP
&&
711 (S_ISDIR(sb
.st_mode
) ||
712 (S_ISLNK(sb
.st_mode
) &&
713 g_stat(pathbuf
, &sb
, pglob
, loc
) == 0 &&
714 S_ISDIR(sb
.st_mode
)))) {
715 if (pathend
+ 1 > pathend_last
) {
717 return (GLOB_NOSPACE
);
723 return (globextend(pathbuf
, pglob
, limit
, NULL
, loc
));
726 /* Find end of next segment, copy tentatively to pathend. */
729 while (*p
!= EOS
&& UNPROT(*p
) != SEP
) {
732 if (q
+ 1 > pathend_last
) {
734 return (GLOB_NOSPACE
);
739 if (!anymeta
) { /* No expansion, do next segment. */
742 while (UNPROT(*pattern
) == SEP
) {
743 if (pathend
+ 1 > pathend_last
) {
745 return (GLOB_NOSPACE
);
747 *pathend
++ = *pattern
++;
749 } else /* Need expansion, recurse. */
750 return(glob3(pathbuf
, pathend
, pathend_last
, pattern
,
751 p
, pglob
, limit
, loc
));
757 glob3(Char
*pathbuf
, Char
*pathend
, Char
*pathend_last
,
758 Char
*pattern
, Char
*restpattern
,
759 glob_t
*pglob
, struct glob_limit
*limit
, locale_t loc
)
763 int err
, too_long
, saverrno
, saverrno2
;
764 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
767 * The readdirfunc declaration can't be prototyped, because it is
768 * assigned, below, to two functions which are prototyped in glob.h
769 * and dirent.h as taking pointers to differently typed opaque
772 struct dirent
*(*readdirfunc
)();
774 if (pathend
> pathend_last
) {
776 return (GLOB_NOSPACE
);
779 if ((pglob
->gl_errfunc
!= NULL
|| pglob
->gl_errblk
!= NULL
) &&
780 g_Ctoc(pathbuf
, buf
, sizeof(buf
), loc
)) {
782 return (GLOB_NOSPACE
);
788 if ((dirp
= g_opendir(pathbuf
, pglob
, loc
)) == NULL
) {
789 if (errno
== ENOENT
|| errno
== ENOTDIR
)
792 err
= err_aborted(pglob
, errno
, buf
);
800 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
801 readdirfunc
= pglob
->gl_readdir
;
803 readdirfunc
= readdir
;
806 /* Search directory for matching names. */
807 while ((dp
= (*readdirfunc
)(dirp
)) != NULL
) {
814 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
815 limit
->l_readdir_cnt
++ >= GLOB_LIMIT_READDIR
) {
821 /* Initial DOT must be matched literally. */
822 if (dp
->d_name
[0] == '.' && UNPROT(*pattern
) != DOT
) {
826 memset(&mbs
, 0, sizeof(mbs
));
830 while (dc
<= pathend_last
) {
831 clen
= mbrtowc_l(&wc
, sc
, MB_LEN_MAX
, &mbs
, loc
);
832 if (clen
== (size_t)-1 || clen
== (size_t)-2) {
833 /* XXX See initial comment #2. */
834 wc
= (unsigned char)*sc
;
836 memset(&mbs
, 0, sizeof(mbs
));
838 if ((*dc
++ = wc
) == EOS
) {
844 if (too_long
&& (err
= err_aborted(pglob
, ENAMETOOLONG
,
846 errno
= ENAMETOOLONG
;
849 if (too_long
|| !match(pathend
, pattern
, restpattern
, loc
)) {
856 err
= glob2(pathbuf
, --dc
, pathend_last
, restpattern
,
864 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
865 (*pglob
->gl_closedir
)(dirp
);
873 if (dp
== NULL
&& errno
!= 0 &&
874 (err
= err_aborted(pglob
, errno
, buf
)))
883 #ifndef BUILDING_VARIANT
885 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
886 * add the new item, and update gl_pathc.
888 * This assumes the BSD realloc, which only copies the block when its size
889 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
892 * Return 0 if new item added, error code if memory couldn't be allocated.
894 * Invariant of the glob_t structure:
895 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
896 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
898 __private_extern__
int
899 globextend(const Char
*path
, glob_t
*pglob
, struct glob_limit
*limit
,
900 const char *origpat
, locale_t loc
)
907 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
908 pglob
->gl_matchc
> limit
->l_path_lim
) {
910 return (GLOB_NOSPACE
);
913 newn
= 2 + pglob
->gl_pathc
+ pglob
->gl_offs
;
914 /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
915 pathv
= reallocarray(pglob
->gl_pathv
, newn
, sizeof(*pathv
));
917 return (GLOB_NOSPACE
);
919 if (pglob
->gl_pathv
== NULL
&& pglob
->gl_offs
> 0) {
920 /* first time around -- clear initial gl_offs items */
921 pathv
+= pglob
->gl_offs
;
922 for (i
= pglob
->gl_offs
+ 1; --i
> 0; )
925 pglob
->gl_pathv
= pathv
;
928 copy
= strdup(origpat
);
930 for (p
= path
; *p
++ != EOS
;)
932 len
= MB_CUR_MAX_L(loc
) * (size_t)(p
- path
); /* XXX overallocation */
933 if ((copy
= malloc(len
)) != NULL
) {
934 if (g_Ctoc(path
, copy
, len
, loc
)) {
937 return (GLOB_NOSPACE
);
942 limit
->l_string_cnt
+= strlen(copy
) + 1;
943 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
944 limit
->l_string_cnt
>= GLOB_LIMIT_STRING
) {
947 return (GLOB_NOSPACE
);
949 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
++] = copy
;
951 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
] = NULL
;
952 return (copy
== NULL
? GLOB_NOSPACE
: 0);
956 * pattern matching function for filenames.
958 __private_extern__
int
959 match(Char
*name
, Char
*pat
, Char
*patend
, locale_t loc
)
961 int ok
, negate_range
;
962 Char c
, k
, *nextp
, *nextn
;
968 while (pat
< patend
) {
970 switch (c
& M_MASK
) {
985 if ((k
= *name
++) == EOS
)
987 negate_range
= ((*pat
& M_MASK
) == M_NOT
);
988 if (negate_range
!= 0)
990 while (((c
= *pat
++) & M_MASK
) != M_END
)
991 if ((*pat
& M_MASK
) == M_RNG
) {
992 if (loc
->__collate_load_error
?
993 CHAR(c
) <= CHAR(k
) && CHAR(k
) <= CHAR(pat
[1]) :
994 __collate_range_cmp(CHAR(c
), CHAR(k
), loc
) <= 0
995 && __collate_range_cmp(CHAR(k
), CHAR(pat
[1]), loc
) <= 0
1002 if (ok
== negate_range
)
1023 /* Free allocated data belonging to a glob_t structure. */
1025 globfree(glob_t
*pglob
)
1030 if (pglob
->gl_pathv
!= NULL
) {
1031 pp
= pglob
->gl_pathv
+ pglob
->gl_offs
;
1032 for (i
= pglob
->gl_pathc
; i
--; ++pp
)
1035 free(pglob
->gl_pathv
);
1036 pglob
->gl_pathv
= NULL
;
1039 #endif /* !BUILDING_VARIANT */
1042 g_opendir(Char
*str
, glob_t
*pglob
, locale_t loc
)
1044 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1049 if (g_Ctoc(str
, buf
, sizeof(buf
), loc
)) {
1050 errno
= ENAMETOOLONG
;
1055 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1056 return ((*pglob
->gl_opendir
)(buf
));
1058 return (opendir(buf
));
1062 g_lstat(Char
*fn
, struct stat
*sb
, glob_t
*pglob
, locale_t loc
)
1064 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1066 if (g_Ctoc(fn
, buf
, sizeof(buf
), loc
)) {
1067 errno
= ENAMETOOLONG
;
1070 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1071 return((*pglob
->gl_lstat
)(buf
, sb
));
1072 return (lstat(buf
, sb
));
1076 g_stat(Char
*fn
, struct stat
*sb
, glob_t
*pglob
, locale_t loc
)
1078 char buf
[MAXPATHLEN
+ MB_LEN_MAX
- 1];
1080 if (g_Ctoc(fn
, buf
, sizeof(buf
), loc
)) {
1081 errno
= ENAMETOOLONG
;
1084 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1085 return ((*pglob
->gl_stat
)(buf
, sb
));
1086 return (stat(buf
, sb
));
1089 #ifndef BUILDING_VARIANT
1090 __private_extern__
const Char
*
1091 g_strchr(const Char
*str
, wchar_t ch
)
1101 __private_extern__
int
1102 g_Ctoc(const Char
*str
, char *buf
, size_t len
, locale_t loc
)
1106 int mb_cur_max
= MB_CUR_MAX_L(loc
);
1108 memset(&mbs
, 0, sizeof(mbs
));
1109 while (len
>= mb_cur_max
) {
1110 clen
= wcrtomb_l(buf
, *str
, &mbs
, loc
);
1111 if (clen
== (size_t)-1) {
1112 /* XXX See initial comment #2. */
1113 *buf
= (char)CHAR(*str
);
1115 memset(&mbs
, 0, sizeof(mbs
));
1117 if (CHAR(*str
) == EOS
)
1125 #endif /* !BUILDING_VARIANT */
1128 err_nomatch(glob_t
*pglob
, struct glob_limit
*limit
, const char *origpat
, locale_t loc
) {
1130 * If there was no match we are going to append the origpat
1131 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
1132 * and the origpat did not contain any magic characters
1133 * GLOB_NOMAGIC is there just for compatibility with csh.
1135 if ((pglob
->gl_flags
& GLOB_NOCHECK
) ||
1136 ((pglob
->gl_flags
& GLOB_NOMAGIC
) &&
1137 !(pglob
->gl_flags
& GLOB_MAGCHAR
)))
1138 return (globextend(NULL
, pglob
, limit
, origpat
, loc
));
1139 return (GLOB_NOMATCH
);
1143 err_aborted(glob_t
*pglob
, int err
, char *buf
) {
1145 if (pglob
->gl_flags
& _GLOB_ERR_BLOCK
&& pglob
->gl_errblk(buf
, errno
)) {
1146 return (GLOB_ABORTED
);
1148 #endif /* __BLOCKS__ */
1149 if (pglob
->gl_errfunc
!= NULL
&& pglob
->gl_errfunc(buf
, errno
)) {
1150 return (GLOB_ABORTED
);
1151 } else if (pglob
->gl_flags
& GLOB_ERR
) {
1152 return (GLOB_ABORTED
);
1159 qprintf(const char *str
, Char
*s
)
1163 (void)printf("%s\n", str
);
1165 for (p
= s
; *p
!= EOS
; p
++)
1166 (void)printf("%c", (char)CHAR(*p
));
1168 for (p
= s
; *p
!= EOS
; p
++)
1169 (void)printf("%c", (isprot(*p
) ? '\\' : ' '));
1171 for (p
= s
; *p
!= EOS
; p
++)
1172 (void)printf("%c", (ismeta(*p
) ? '_' : ' '));
1177 #pragma clang diagnostic pop