]> git.saurik.com Git - apple/libc.git/blame - gen/glob-fbsd.c
Libc-498.tar.gz
[apple/libc.git] / gen / glob-fbsd.c
CommitLineData
224c7076
A
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)
38static 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
123typedef 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
132typedef 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
147static int g_lstat(Char *, struct stat *, glob_t *, locale_t);
148static 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
168static int compare(const void *, const void *);
169static DIR *g_opendir(Char *, glob_t *, locale_t);
170static Char *g_strchr(Char *, wchar_t);
171#ifdef notdef
172static Char *g_strcat(Char *, const Char *);
173#endif
174static int glob1(Char *, glob_t *, int *, locale_t);
175static const Char *
176 globtilde(const Char *, Char *, size_t, glob_t *);
177static int globexp2(const Char *, const Char *, glob_t *, int *, int *, locale_t);
178static int match(Char *, Char *, Char *, locale_t);
179#ifdef DEBUG
180static void qprintf(const char *, Char *);
181#endif
182#endif /* !BUILDING_VARIANT */
183
184int
185glob(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
270globexp1(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 */
296static int
297globexp2(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 */
404static const Char *
405globtilde(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
475glob0(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
569static int
570compare(p, q)
571 const void *p, *q;
572{
573 return(strcoll(*(char **)p, *(char **)q));
574}
575
576static int
577glob1(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
600glob2_64(pathbuf, pathend, pathend_last, pattern, pglob, limit, loc)
601#else /* !__DARWIN_64_BIT_INO_T */
602glob2_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
665glob3(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
766globextend(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 */
821static int
822match(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. */
874void
875globfree(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
891static DIR *
892g_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
913static int
914g_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
931static int
932g_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
950static Char *
951g_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
963g_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
988static void
989qprintf(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 */