]> git.saurik.com Git - apple/libc.git/blob - gen/glob-fbsd.c
49d0cbbf2eb1da516d206793d65d2396665c7973
[apple/libc.git] / gen / glob-fbsd.c
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 #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.22 2004/07/29 03:48:52 tjr Exp $");
42
43 #include "xlocale_private.h"
44
45 /*
46 * glob(3) -- a superset of the one defined in POSIX 1003.2.
47 *
48 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
49 *
50 * Optional extra services, controlled by flags not defined by POSIX:
51 *
52 * GLOB_QUOTE:
53 * Escaping convention: \ inhibits any special meaning the following
54 * character might have (except \ at end of string is retained).
55 * GLOB_MAGCHAR:
56 * Set in gl_flags if pattern contained a globbing character.
57 * GLOB_NOMAGIC:
58 * Same as GLOB_NOCHECK, but it will only append pattern if it did
59 * not contain any magic characters. [Used in csh style globbing]
60 * GLOB_ALTDIRFUNC:
61 * Use alternately specified directory access functions.
62 * GLOB_TILDE:
63 * expand ~user/foo to the /home/dir/of/user/foo
64 * GLOB_BRACE:
65 * expand {1,2}{a,b} to 1a 1b 2a 2b
66 * gl_matchc:
67 * Number of matches in the current invocation of glob.
68 */
69
70 /*
71 * Some notes on multibyte character support:
72 * 1. Patterns with illegal byte sequences match nothing - even if
73 * GLOB_NOCHECK is specified.
74 * 2. Illegal byte sequences in filenames are handled by treating them as
75 * single-byte characters with a value of the first byte of the sequence
76 * cast to wchar_t.
77 * 3. State-dependent encodings are not currently supported.
78 */
79
80 #include <sys/param.h>
81 #include <sys/stat.h>
82
83 #include <ctype.h>
84 #include <dirent.h>
85 #include <errno.h>
86 #include <glob.h>
87 #include <limits.h>
88 #include <pwd.h>
89 #include <stdint.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <unistd.h>
94 #include <wchar.h>
95
96 #include "collate.h"
97
98 #define DOLLAR '$'
99 #define DOT '.'
100 #define EOS '\0'
101 #define LBRACKET '['
102 #define NOT '!'
103 #define QUESTION '?'
104 #define QUOTE '\\'
105 #define RANGE '-'
106 #define RBRACKET ']'
107 #define SEP '/'
108 #define STAR '*'
109 #define TILDE '~'
110 #define UNDERSCORE '_'
111 #define LBRACE '{'
112 #define RBRACE '}'
113 #define SLASH '/'
114 #define COMMA ','
115
116 #ifndef DEBUG
117
118 #define M_QUOTE 0x8000000000ULL
119 #define M_PROTECT 0x4000000000ULL
120 #define M_MASK 0xffffffffffULL
121 #define M_CHAR 0x00ffffffffULL
122
123 typedef uint_fast64_t Char;
124
125 #else
126
127 #define M_QUOTE 0x80
128 #define M_PROTECT 0x40
129 #define M_MASK 0xff
130 #define M_CHAR 0x7f
131
132 typedef char Char;
133
134 #endif
135
136
137 #define CHAR(c) ((Char)((c)&M_CHAR))
138 #define META(c) ((Char)((c)|M_QUOTE))
139 #define M_ALL META('*')
140 #define M_END META(']')
141 #define M_NOT META('!')
142 #define M_ONE META('?')
143 #define M_RNG META('-')
144 #define M_SET META('[')
145 #define ismeta(c) (((c)&M_QUOTE) != 0)
146
147 static int g_lstat(Char *, struct stat *, glob_t *, locale_t);
148 static int g_stat(Char *, struct stat *, glob_t *, locale_t);
149
150 #define g_Ctoc __gl_g_Ctoc
151 #define glob0 __gl_glob0
152 #define glob2_32 __gl_glob0_32
153 #define glob2_64 __gl_glob0_64
154 #define glob3 __gl_glob3
155 #define globexp1 __gl_globexp1
156 #define globextend __gl_globextend
157 __private_extern__ int g_Ctoc(const Char *, char *, u_int, locale_t);
158 __private_extern__ int glob0(const Char *, glob_t *, int *, locale_t);
159 __private_extern__ int glob2_32(Char *, Char *, Char *, Char *, glob_t *, int *, locale_t);
160 __private_extern__ int glob2_64(Char *, Char *, Char *, Char *, glob_t *, int *, locale_t);
161 __private_extern__ int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *, locale_t);
162 __private_extern__ int globexp1(const Char *, glob_t *, int *, locale_t);
163 __private_extern__ int globextend(const Char *, glob_t *, int *, locale_t);
164
165 #ifndef BUILDING_VARIANT
166 #define glob2(a,b,c,d,e,f,g) (((e)->gl_flags & GLOB_INODE64) ? glob2_64((a),(b),(c),(d),(e),(f),(g)) : glob2_32((a),(b),(c),(d),(e),(f),(g)))
167
168 static int compare(const void *, const void *);
169 static DIR *g_opendir(Char *, glob_t *, locale_t);
170 static Char *g_strchr(Char *, wchar_t);
171 #ifdef notdef
172 static Char *g_strcat(Char *, const Char *);
173 #endif
174 static int glob1(Char *, glob_t *, int *, locale_t);
175 static const Char *
176 globtilde(const Char *, Char *, size_t, glob_t *);
177 static int globexp2(const Char *, const Char *, glob_t *, int *, int *, locale_t);
178 static int match(Char *, Char *, Char *, locale_t);
179 #ifdef DEBUG
180 static void qprintf(const char *, Char *);
181 #endif
182 #endif /* !BUILDING_VARIANT */
183
184 int
185 glob(pattern, flags, errfunc, pglob)
186 const char *pattern;
187 int flags, (*errfunc)(const char *, int);
188 glob_t *pglob;
189 {
190 const u_char *patnext;
191 int limit;
192 Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
193 mbstate_t mbs;
194 wchar_t wc;
195 size_t clen;
196 locale_t loc = __current_locale();
197 int mb_cur_max = MB_CUR_MAX_L(loc);
198
199 patnext = (u_char *) pattern;
200 if (!(flags & GLOB_APPEND)) {
201 pglob->gl_pathc = 0;
202 pglob->gl_pathv = NULL;
203 if (!(flags & GLOB_DOOFFS))
204 pglob->gl_offs = 0;
205 }
206 if (flags & GLOB_LIMIT) {
207 limit = pglob->gl_matchc;
208 if (limit == 0)
209 limit = ARG_MAX;
210 } else
211 limit = 0;
212 #if __DARWIN_64_BIT_INO_T
213 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
214 pglob->gl_flags |= GLOB_INODE64;
215 #else /* !__DARWIN_64_BIT_INO_T */
216 pglob->gl_flags = flags & ~(GLOB_MAGCHAR | GLOB_INODE64);
217 #endif /* __DARWIN_64_BIT_INO_T */
218 pglob->gl_errfunc = errfunc;
219 pglob->gl_matchc = 0;
220
221 bufnext = patbuf;
222 bufend = bufnext + MAXPATHLEN - 1;
223 if (flags & GLOB_NOESCAPE) {
224 memset(&mbs, 0, sizeof(mbs));
225 while (bufend - bufnext >= mb_cur_max) {
226 clen = mbrtowc_l(&wc, (const char *)patnext, MB_LEN_MAX, &mbs, loc);
227 if (clen == (size_t)-1 || clen == (size_t)-2)
228 return (GLOB_NOMATCH);
229 else if (clen == 0)
230 break;
231 *bufnext++ = wc;
232 patnext += clen;
233 }
234 } else {
235 /* Protect the quoted characters. */
236 memset(&mbs, 0, sizeof(mbs));
237 while (bufend - bufnext >= mb_cur_max) {
238 if (*patnext == QUOTE) {
239 if (*++patnext == EOS) {
240 *bufnext++ = QUOTE | M_PROTECT;
241 continue;
242 }
243 prot = M_PROTECT;
244 } else
245 prot = 0;
246 clen = mbrtowc_l(&wc, (const char *)patnext, MB_LEN_MAX, &mbs, loc);
247 if (clen == (size_t)-1 || clen == (size_t)-2)
248 return (GLOB_NOMATCH);
249 else if (clen == 0)
250 break;
251 *bufnext++ = wc | prot;
252 patnext += clen;
253 }
254 }
255 *bufnext = EOS;
256
257 if (flags & GLOB_BRACE)
258 return globexp1(patbuf, pglob, &limit, loc);
259 else
260 return glob0(patbuf, pglob, &limit, loc);
261 }
262
263 #ifndef BUILDING_VARIANT
264 /*
265 * Expand recursively a glob {} pattern. When there is no more expansion
266 * invoke the standard globbing routine to glob the rest of the magic
267 * characters
268 */
269 __private_extern__ int
270 globexp1(pattern, pglob, limit, loc)
271 const Char *pattern;
272 glob_t *pglob;
273 int *limit;
274 locale_t loc;
275 {
276 const Char* ptr = pattern;
277 int rv;
278
279 /* Protect a single {}, for find(1), like csh */
280 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
281 return glob0(pattern, pglob, limit, loc);
282
283 while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
284 if (!globexp2(ptr, pattern, pglob, &rv, limit, loc))
285 return rv;
286
287 return glob0(pattern, pglob, limit, loc);
288 }
289
290
291 /*
292 * Recursive brace globbing helper. Tries to expand a single brace.
293 * If it succeeds then it invokes globexp1 with the new pattern.
294 * If it fails then it tries to glob the rest of the pattern and returns.
295 */
296 static int
297 globexp2(ptr, pattern, pglob, rv, limit, loc)
298 const Char *ptr, *pattern;
299 glob_t *pglob;
300 int *rv, *limit;
301 locale_t loc;
302 {
303 int i;
304 Char *lm, *ls;
305 const Char *pe, *pm, *pl;
306 Char patbuf[MAXPATHLEN];
307
308 /* copy part up to the brace */
309 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
310 continue;
311 *lm = EOS;
312 ls = lm;
313
314 /* Find the balanced brace */
315 for (i = 0, pe = ++ptr; *pe; pe++)
316 if (*pe == LBRACKET) {
317 /* Ignore everything between [] */
318 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
319 continue;
320 if (*pe == EOS) {
321 /*
322 * We could not find a matching RBRACKET.
323 * Ignore and just look for RBRACE
324 */
325 pe = pm;
326 }
327 }
328 else if (*pe == LBRACE)
329 i++;
330 else if (*pe == RBRACE) {
331 if (i == 0)
332 break;
333 i--;
334 }
335
336 /* Non matching braces; just glob the pattern */
337 if (i != 0 || *pe == EOS) {
338 *rv = glob0(patbuf, pglob, limit, loc);
339 return 0;
340 }
341
342 for (i = 0, pl = pm = ptr; pm <= pe; pm++)
343 switch (*pm) {
344 case LBRACKET:
345 /* Ignore everything between [] */
346 for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
347 continue;
348 if (*pm == EOS) {
349 /*
350 * We could not find a matching RBRACKET.
351 * Ignore and just look for RBRACE
352 */
353 pm = pl;
354 }
355 break;
356
357 case LBRACE:
358 i++;
359 break;
360
361 case RBRACE:
362 if (i) {
363 i--;
364 break;
365 }
366 /* FALLTHROUGH */
367 case COMMA:
368 if (i && *pm == COMMA)
369 break;
370 else {
371 /* Append the current string */
372 for (lm = ls; (pl < pm); *lm++ = *pl++)
373 continue;
374 /*
375 * Append the rest of the pattern after the
376 * closing brace
377 */
378 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
379 continue;
380
381 /* Expand the current pattern */
382 #ifdef DEBUG
383 qprintf("globexp2:", patbuf);
384 #endif
385 *rv = globexp1(patbuf, pglob, limit, loc);
386
387 /* move after the comma, to the next string */
388 pl = pm + 1;
389 }
390 break;
391
392 default:
393 break;
394 }
395 *rv = 0;
396 return 0;
397 }
398
399
400
401 /*
402 * expand tilde from the passwd file.
403 */
404 static const Char *
405 globtilde(pattern, patbuf, patbuf_len, pglob)
406 const Char *pattern;
407 Char *patbuf;
408 size_t patbuf_len;
409 glob_t *pglob;
410 {
411 struct passwd *pwd;
412 char *h;
413 const Char *p;
414 Char *b, *eb;
415
416 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
417 return pattern;
418
419 /*
420 * Copy up to the end of the string or /
421 */
422 eb = &patbuf[patbuf_len - 1];
423 for (p = pattern + 1, h = (char *) patbuf;
424 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
425 continue;
426
427 *h = EOS;
428
429 if (((char *) patbuf)[0] == EOS) {
430 /*
431 * handle a plain ~ or ~/ by expanding $HOME first (iff
432 * we're not running setuid or setgid) and then trying
433 * the password file
434 */
435 if (issetugid() != 0 ||
436 (h = getenv("HOME")) == NULL) {
437 if (((h = getlogin()) != NULL &&
438 (pwd = getpwnam(h)) != NULL) ||
439 (pwd = getpwuid(getuid())) != NULL)
440 h = pwd->pw_dir;
441 else
442 return pattern;
443 }
444 }
445 else {
446 /*
447 * Expand a ~user
448 */
449 if ((pwd = getpwnam((char*) patbuf)) == NULL)
450 return pattern;
451 else
452 h = pwd->pw_dir;
453 }
454
455 /* Copy the home directory */
456 for (b = patbuf; b < eb && *h; *b++ = *h++)
457 continue;
458
459 /* Append the rest of the pattern */
460 while (b < eb && (*b++ = *p++) != EOS)
461 continue;
462 *b = EOS;
463
464 return patbuf;
465 }
466
467
468 /*
469 * The main glob() routine: compiles the pattern (optionally processing
470 * quotes), calls glob1() to do the real pattern matching, and finally
471 * sorts the list (unless unsorted operation is requested). Returns 0
472 * if things went well, nonzero if errors occurred.
473 */
474 __private_extern__ int
475 glob0(pattern, pglob, limit, loc)
476 const Char *pattern;
477 glob_t *pglob;
478 int *limit;
479 locale_t loc;
480 {
481 const Char *qpatnext;
482 Char c;
483 int err, oldpathc;
484 Char *bufnext, patbuf[MAXPATHLEN];
485
486 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
487 oldpathc = pglob->gl_pathc;
488 bufnext = patbuf;
489
490 /* We don't need to check for buffer overflow any more. */
491 while ((c = *qpatnext++) != EOS) {
492 if (c & M_PROTECT) {
493 *bufnext++ = CHAR(c);
494 continue;
495 } /* else */
496 switch (c) {
497 case LBRACKET:
498 c = *qpatnext;
499 if (c == NOT)
500 ++qpatnext;
501 if (*qpatnext == EOS ||
502 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
503 *bufnext++ = LBRACKET;
504 if (c == NOT)
505 --qpatnext;
506 break;
507 }
508 *bufnext++ = M_SET;
509 if (c == NOT)
510 *bufnext++ = M_NOT;
511 c = *qpatnext++;
512 do {
513 *bufnext++ = CHAR(c);
514 if (*qpatnext == RANGE &&
515 (c = qpatnext[1]) != RBRACKET) {
516 *bufnext++ = M_RNG;
517 *bufnext++ = CHAR(c);
518 qpatnext += 2;
519 }
520 } while ((c = *qpatnext++) != RBRACKET);
521 pglob->gl_flags |= GLOB_MAGCHAR;
522 *bufnext++ = M_END;
523 break;
524 case QUESTION:
525 pglob->gl_flags |= GLOB_MAGCHAR;
526 *bufnext++ = M_ONE;
527 break;
528 case STAR:
529 pglob->gl_flags |= GLOB_MAGCHAR;
530 /* collapse adjacent stars to one,
531 * to avoid exponential behavior
532 */
533 if (bufnext == patbuf || bufnext[-1] != M_ALL)
534 *bufnext++ = M_ALL;
535 break;
536 default:
537 *bufnext++ = CHAR(c);
538 break;
539 }
540 }
541 *bufnext = EOS;
542 #ifdef DEBUG
543 qprintf("glob0:", patbuf);
544 #endif
545
546 if ((err = glob1(patbuf, pglob, limit, loc)) != 0)
547 return(err);
548
549 /*
550 * If there was no match we are going to append the pattern
551 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
552 * and the pattern did not contain any magic characters
553 * GLOB_NOMAGIC is there just for compatibility with csh.
554 */
555 if (pglob->gl_pathc == oldpathc) {
556 if (((pglob->gl_flags & GLOB_NOCHECK) ||
557 ((pglob->gl_flags & GLOB_NOMAGIC) &&
558 !(pglob->gl_flags & GLOB_MAGCHAR))))
559 return(globextend(pattern, pglob, limit, loc));
560 else
561 return(GLOB_NOMATCH);
562 }
563 if (!(pglob->gl_flags & GLOB_NOSORT))
564 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
565 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
566 return(0);
567 }
568
569 static int
570 compare(p, q)
571 const void *p, *q;
572 {
573 return(strcoll(*(char **)p, *(char **)q));
574 }
575
576 static int
577 glob1(pattern, pglob, limit, loc)
578 Char *pattern;
579 glob_t *pglob;
580 int *limit;
581 locale_t loc;
582 {
583 Char pathbuf[MAXPATHLEN];
584
585 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
586 if (*pattern == EOS)
587 return(0);
588 return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
589 pattern, pglob, limit, loc));
590 }
591 #endif /* !BUILDING_VARIANT */
592
593 /*
594 * The functions glob2 and glob3 are mutually recursive; there is one level
595 * of recursion for each segment in the pattern that contains one or more
596 * meta characters.
597 */
598 __private_extern__ int
599 #if __DARWIN_64_BIT_INO_T
600 glob2_64(pathbuf, pathend, pathend_last, pattern, pglob, limit, loc)
601 #else /* !__DARWIN_64_BIT_INO_T */
602 glob2_32(pathbuf, pathend, pathend_last, pattern, pglob, limit, loc)
603 #endif /* __DARWIN_64_BIT_INO_T */
604 Char *pathbuf, *pathend, *pathend_last, *pattern;
605 glob_t *pglob;
606 int *limit;
607 locale_t loc;
608 {
609 struct stat sb;
610 Char *p, *q;
611 int anymeta;
612
613 /*
614 * Loop over pattern segments until end of pattern or until
615 * segment with meta character found.
616 */
617 for (anymeta = 0;;) {
618 if (*pattern == EOS) { /* End of pattern? */
619 *pathend = EOS;
620 if (g_lstat(pathbuf, &sb, pglob, loc))
621 return(0);
622
623 if (((pglob->gl_flags & GLOB_MARK) &&
624 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
625 || (S_ISLNK(sb.st_mode) &&
626 (g_stat(pathbuf, &sb, pglob, loc) == 0) &&
627 S_ISDIR(sb.st_mode)))) {
628 if (pathend + 1 > pathend_last)
629 return (GLOB_ABORTED);
630 *pathend++ = SEP;
631 *pathend = EOS;
632 }
633 ++pglob->gl_matchc;
634 return(globextend(pathbuf, pglob, limit, loc));
635 }
636
637 /* Find end of next segment, copy tentatively to pathend. */
638 q = pathend;
639 p = pattern;
640 while (*p != EOS && *p != SEP) {
641 if (ismeta(*p))
642 anymeta = 1;
643 if (q + 1 > pathend_last)
644 return (GLOB_ABORTED);
645 *q++ = *p++;
646 }
647
648 if (!anymeta) { /* No expansion, do next segment. */
649 pathend = q;
650 pattern = p;
651 while (*pattern == SEP) {
652 if (pathend + 1 > pathend_last)
653 return (GLOB_ABORTED);
654 *pathend++ = *pattern++;
655 }
656 } else /* Need expansion, recurse. */
657 return(glob3(pathbuf, pathend, pathend_last, pattern, p,
658 pglob, limit, loc));
659 }
660 /* NOTREACHED */
661 }
662
663 #ifndef BUILDING_VARIANT
664 __private_extern__ int
665 glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit, loc)
666 Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
667 glob_t *pglob;
668 int *limit;
669 locale_t loc;
670 {
671 struct dirent *dp;
672 DIR *dirp;
673 int err;
674 char buf[MAXPATHLEN];
675
676 /*
677 * The readdirfunc declaration can't be prototyped, because it is
678 * assigned, below, to two functions which are prototyped in glob.h
679 * and dirent.h as taking pointers to differently typed opaque
680 * structures.
681 */
682 struct dirent *(*readdirfunc)();
683
684 if (pathend > pathend_last)
685 return (GLOB_ABORTED);
686 *pathend = EOS;
687 errno = 0;
688
689 if ((dirp = g_opendir(pathbuf, pglob, loc)) == NULL) {
690 /* TODO: don't call for ENOENT or ENOTDIR? */
691 if (pglob->gl_errfunc) {
692 if (g_Ctoc(pathbuf, buf, sizeof(buf), loc))
693 return (GLOB_ABORTED);
694 if (pglob->gl_errfunc(buf, errno))
695 return (GLOB_ABORTED);
696 }
697 if (pglob->gl_flags & GLOB_ERR)
698 return (GLOB_ABORTED);
699 return(0);
700 }
701
702 err = 0;
703
704 /* Search directory for matching names. */
705 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
706 readdirfunc = pglob->gl_readdir;
707 else
708 readdirfunc = readdir;
709 while ((dp = (*readdirfunc)(dirp))) {
710 u_char *sc;
711 Char *dc;
712 wchar_t wc;
713 size_t clen;
714 mbstate_t mbs;
715
716 /* Initial DOT must be matched literally. */
717 if (dp->d_name[0] == DOT && *pattern != DOT)
718 continue;
719 memset(&mbs, 0, sizeof(mbs));
720 dc = pathend;
721 sc = (u_char *) dp->d_name;
722 while (dc < pathend_last) {
723 clen = mbrtowc_l(&wc, (const char *)sc, MB_LEN_MAX, &mbs, loc);
724 if (clen == (size_t)-1 || clen == (size_t)-2) {
725 wc = *sc;
726 clen = 1;
727 memset(&mbs, 0, sizeof(mbs));
728 }
729 if ((*dc++ = wc) == EOS)
730 break;
731 sc += clen;
732 }
733 if (!match(pathend, pattern, restpattern, loc)) {
734 *pathend = EOS;
735 continue;
736 }
737 err = glob2(pathbuf, --dc, pathend_last, restpattern,
738 pglob, limit, loc);
739 if (err)
740 break;
741 }
742
743 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
744 (*pglob->gl_closedir)(dirp);
745 else
746 closedir(dirp);
747 return(err);
748 }
749
750
751 /*
752 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
753 * add the new item, and update gl_pathc.
754 *
755 * This assumes the BSD realloc, which only copies the block when its size
756 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
757 * behavior.
758 *
759 * Return 0 if new item added, error code if memory couldn't be allocated.
760 *
761 * Invariant of the glob_t structure:
762 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
763 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
764 */
765 __private_extern__ int
766 globextend(path, pglob, limit, loc)
767 const Char *path;
768 glob_t *pglob;
769 int *limit;
770 locale_t loc;
771 {
772 char **pathv;
773 int i;
774 u_int newsize, len;
775 char *copy;
776 const Char *p;
777
778 if (*limit && pglob->gl_pathc > *limit) {
779 errno = 0;
780 return (GLOB_NOSPACE);
781 }
782
783 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
784 pathv = pglob->gl_pathv ?
785 realloc((char *)pglob->gl_pathv, newsize) :
786 malloc(newsize);
787 if (pathv == NULL) {
788 if (pglob->gl_pathv) {
789 free(pglob->gl_pathv);
790 pglob->gl_pathv = NULL;
791 }
792 return(GLOB_NOSPACE);
793 }
794
795 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
796 /* first time around -- clear initial gl_offs items */
797 pathv += pglob->gl_offs;
798 for (i = pglob->gl_offs; --i >= 0; )
799 *--pathv = NULL;
800 }
801 pglob->gl_pathv = pathv;
802
803 for (p = path; *p++;)
804 continue;
805 len = MB_CUR_MAX_L(loc) * (size_t)(p - path); /* XXX overallocation */
806 if ((copy = malloc(len)) != NULL) {
807 if (g_Ctoc(path, copy, len, loc)) {
808 free(copy);
809 return (GLOB_NOSPACE);
810 }
811 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
812 }
813 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
814 return(copy == NULL ? GLOB_NOSPACE : 0);
815 }
816
817 /*
818 * pattern matching function for filenames. Each occurrence of the *
819 * pattern causes a recursion level.
820 */
821 static int
822 match(name, pat, patend, loc)
823 Char *name, *pat, *patend;
824 locale_t loc;
825 {
826 int ok, negate_range;
827 Char c, k;
828
829 while (pat < patend) {
830 c = *pat++;
831 switch (c & M_MASK) {
832 case M_ALL:
833 if (pat == patend)
834 return(1);
835 do
836 if (match(name, pat, patend, loc))
837 return(1);
838 while (*name++ != EOS);
839 return(0);
840 case M_ONE:
841 if (*name++ == EOS)
842 return(0);
843 break;
844 case M_SET:
845 ok = 0;
846 if ((k = *name++) == EOS)
847 return(0);
848 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
849 ++pat;
850 while (((c = *pat++) & M_MASK) != M_END)
851 if ((*pat & M_MASK) == M_RNG) {
852 if (loc->__collate_load_error ?
853 CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
854 __collate_range_cmp(CHAR(c), CHAR(k), loc) <= 0
855 && __collate_range_cmp(CHAR(k), CHAR(pat[1]), loc) <= 0
856 )
857 ok = 1;
858 pat += 2;
859 } else if (c == k)
860 ok = 1;
861 if (ok == negate_range)
862 return(0);
863 break;
864 default:
865 if (*name++ != c)
866 return(0);
867 break;
868 }
869 }
870 return(*name == EOS);
871 }
872
873 /* Free allocated data belonging to a glob_t structure. */
874 void
875 globfree(pglob)
876 glob_t *pglob;
877 {
878 int i;
879 char **pp;
880
881 if (pglob->gl_pathv != NULL) {
882 pp = pglob->gl_pathv + pglob->gl_offs;
883 for (i = pglob->gl_pathc; i--; ++pp)
884 if (*pp)
885 free(*pp);
886 free(pglob->gl_pathv);
887 pglob->gl_pathv = NULL;
888 }
889 }
890
891 static DIR *
892 g_opendir(str, pglob, loc)
893 Char *str;
894 glob_t *pglob;
895 locale_t loc;
896 {
897 char buf[MAXPATHLEN];
898
899 if (!*str)
900 strcpy(buf, ".");
901 else {
902 if (g_Ctoc(str, buf, sizeof(buf), loc))
903 return (NULL);
904 }
905
906 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
907 return((*pglob->gl_opendir)(buf));
908
909 return(opendir(buf));
910 }
911 #endif /* !BUILDING_VARIANT */
912
913 static int
914 g_lstat(fn, sb, pglob, loc)
915 Char *fn;
916 struct stat *sb;
917 glob_t *pglob;
918 locale_t loc;
919 {
920 char buf[MAXPATHLEN];
921
922 if (g_Ctoc(fn, buf, sizeof(buf), loc)) {
923 errno = ENAMETOOLONG;
924 return (-1);
925 }
926 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
927 return((*pglob->gl_lstat)(buf, sb));
928 return(lstat(buf, sb));
929 }
930
931 static int
932 g_stat(fn, sb, pglob, loc)
933 Char *fn;
934 struct stat *sb;
935 glob_t *pglob;
936 locale_t loc;
937 {
938 char buf[MAXPATHLEN];
939
940 if (g_Ctoc(fn, buf, sizeof(buf), loc)) {
941 errno = ENAMETOOLONG;
942 return (-1);
943 }
944 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
945 return((*pglob->gl_stat)(buf, sb));
946 return(stat(buf, sb));
947 }
948
949 #ifndef BUILDING_VARIANT
950 static Char *
951 g_strchr(str, ch)
952 Char *str;
953 wchar_t ch;
954 {
955 do {
956 if (*str == ch)
957 return (str);
958 } while (*str++);
959 return (NULL);
960 }
961
962 __private_extern__ int
963 g_Ctoc(str, buf, len, loc)
964 const Char *str;
965 char *buf;
966 u_int len;
967 locale_t loc;
968 {
969 mbstate_t mbs;
970 size_t clen;
971 int mb_cur_max = MB_CUR_MAX_L(loc);
972
973 memset(&mbs, 0, sizeof(mbs));
974 while (len >= mb_cur_max) {
975 clen = wcrtomb_l(buf, *str, &mbs, loc);
976 if (clen == (size_t)-1)
977 return (1);
978 if (*str == L'\0')
979 return (0);
980 str++;
981 buf += clen;
982 len -= clen;
983 }
984 return (1);
985 }
986
987 #ifdef DEBUG
988 static void
989 qprintf(str, s)
990 const char *str;
991 Char *s;
992 {
993 Char *p;
994
995 (void)printf("%s:\n", str);
996 for (p = s; *p; p++)
997 (void)printf("%c", CHAR(*p));
998 (void)printf("\n");
999 for (p = s; *p; p++)
1000 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1001 (void)printf("\n");
1002 for (p = s; *p; p++)
1003 (void)printf("%c", ismeta(*p) ? '_' : ' ');
1004 (void)printf("\n");
1005 }
1006 #endif
1007 #endif /* !BUILDING_VARIANT */