1*19261079SEd Maste /* $OpenBSD: glob.c,v 1.49 2020/04/21 08:25:22 dtucker Exp $ */
283d2307dSDag-Erling Smørgrav /*
383d2307dSDag-Erling Smørgrav * Copyright (c) 1989, 1993
483d2307dSDag-Erling Smørgrav * The Regents of the University of California. All rights reserved.
583d2307dSDag-Erling Smørgrav *
683d2307dSDag-Erling Smørgrav * This code is derived from software contributed to Berkeley by
783d2307dSDag-Erling Smørgrav * Guido van Rossum.
883d2307dSDag-Erling Smørgrav *
983d2307dSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
1083d2307dSDag-Erling Smørgrav * modification, are permitted provided that the following conditions
1183d2307dSDag-Erling Smørgrav * are met:
1283d2307dSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright
1383d2307dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer.
1483d2307dSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright
1583d2307dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the
1683d2307dSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution.
17d95e11bfSDag-Erling Smørgrav * 3. Neither the name of the University nor the names of its contributors
1883d2307dSDag-Erling Smørgrav * may be used to endorse or promote products derived from this software
1983d2307dSDag-Erling Smørgrav * without specific prior written permission.
2083d2307dSDag-Erling Smørgrav *
2183d2307dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2283d2307dSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2383d2307dSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2483d2307dSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2583d2307dSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2683d2307dSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2783d2307dSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2883d2307dSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2983d2307dSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3083d2307dSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3183d2307dSDag-Erling Smørgrav * SUCH DAMAGE.
3283d2307dSDag-Erling Smørgrav */
3383d2307dSDag-Erling Smørgrav
34021d409fSDag-Erling Smørgrav /* OPENBSD ORIGINAL: lib/libc/gen/glob.c */
35021d409fSDag-Erling Smørgrav
3683d2307dSDag-Erling Smørgrav /*
3783d2307dSDag-Erling Smørgrav * glob(3) -- a superset of the one defined in POSIX 1003.2.
3883d2307dSDag-Erling Smørgrav *
3983d2307dSDag-Erling Smørgrav * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
4083d2307dSDag-Erling Smørgrav *
4183d2307dSDag-Erling Smørgrav * Optional extra services, controlled by flags not defined by POSIX:
4283d2307dSDag-Erling Smørgrav *
4383d2307dSDag-Erling Smørgrav * GLOB_QUOTE:
4483d2307dSDag-Erling Smørgrav * Escaping convention: \ inhibits any special meaning the following
4583d2307dSDag-Erling Smørgrav * character might have (except \ at end of string is retained).
4683d2307dSDag-Erling Smørgrav * GLOB_MAGCHAR:
4783d2307dSDag-Erling Smørgrav * Set in gl_flags if pattern contained a globbing character.
4883d2307dSDag-Erling Smørgrav * GLOB_NOMAGIC:
4983d2307dSDag-Erling Smørgrav * Same as GLOB_NOCHECK, but it will only append pattern if it did
5083d2307dSDag-Erling Smørgrav * not contain any magic characters. [Used in csh style globbing]
5183d2307dSDag-Erling Smørgrav * GLOB_ALTDIRFUNC:
5283d2307dSDag-Erling Smørgrav * Use alternately specified directory access functions.
5383d2307dSDag-Erling Smørgrav * GLOB_TILDE:
5483d2307dSDag-Erling Smørgrav * expand ~user/foo to the /home/dir/of/user/foo
5583d2307dSDag-Erling Smørgrav * GLOB_BRACE:
5683d2307dSDag-Erling Smørgrav * expand {1,2}{a,b} to 1a 1b 2a 2b
5783d2307dSDag-Erling Smørgrav * gl_matchc:
5883d2307dSDag-Erling Smørgrav * Number of matches in the current invocation of glob.
5983d2307dSDag-Erling Smørgrav */
6083d2307dSDag-Erling Smørgrav
614a421b63SDag-Erling Smørgrav #include "includes.h"
62acc1a9efSDag-Erling Smørgrav #include "glob.h"
634a421b63SDag-Erling Smørgrav
644a421b63SDag-Erling Smørgrav #include <sys/types.h>
654a421b63SDag-Erling Smørgrav #include <sys/stat.h>
664a421b63SDag-Erling Smørgrav
674a421b63SDag-Erling Smørgrav #include <dirent.h>
684a421b63SDag-Erling Smørgrav #include <ctype.h>
694a421b63SDag-Erling Smørgrav #include <errno.h>
70462c32cbSDag-Erling Smørgrav #include <limits.h>
714a421b63SDag-Erling Smørgrav #include <pwd.h>
724a421b63SDag-Erling Smørgrav #include <stdlib.h>
73*19261079SEd Maste #ifdef HAVE_STDINT_H
74*19261079SEd Maste #include <stdint.h>
75*19261079SEd Maste #endif
764a421b63SDag-Erling Smørgrav #include <string.h>
774a421b63SDag-Erling Smørgrav #include <unistd.h>
784a421b63SDag-Erling Smørgrav
794a421b63SDag-Erling Smørgrav #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
804a421b63SDag-Erling Smørgrav !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
814a421b63SDag-Erling Smørgrav !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
824a421b63SDag-Erling Smørgrav defined(BROKEN_GLOB)
834a421b63SDag-Erling Smørgrav
844a421b63SDag-Erling Smørgrav #include "charclass.h"
8583d2307dSDag-Erling Smørgrav
86*19261079SEd Maste #ifdef TILDE
87*19261079SEd Maste # undef TILDE
88*19261079SEd Maste #endif
89*19261079SEd Maste
9083d2307dSDag-Erling Smørgrav #define DOLLAR '$'
9183d2307dSDag-Erling Smørgrav #define DOT '.'
9283d2307dSDag-Erling Smørgrav #define EOS '\0'
9383d2307dSDag-Erling Smørgrav #define LBRACKET '['
9483d2307dSDag-Erling Smørgrav #define NOT '!'
9583d2307dSDag-Erling Smørgrav #define QUESTION '?'
9683d2307dSDag-Erling Smørgrav #define QUOTE '\\'
9783d2307dSDag-Erling Smørgrav #define RANGE '-'
9883d2307dSDag-Erling Smørgrav #define RBRACKET ']'
9983d2307dSDag-Erling Smørgrav #define SEP '/'
10083d2307dSDag-Erling Smørgrav #define STAR '*'
10183d2307dSDag-Erling Smørgrav #define TILDE '~'
10283d2307dSDag-Erling Smørgrav #define UNDERSCORE '_'
10383d2307dSDag-Erling Smørgrav #define LBRACE '{'
10483d2307dSDag-Erling Smørgrav #define RBRACE '}'
10583d2307dSDag-Erling Smørgrav #define SLASH '/'
10683d2307dSDag-Erling Smørgrav #define COMMA ','
10783d2307dSDag-Erling Smørgrav
10883d2307dSDag-Erling Smørgrav #ifndef DEBUG
10983d2307dSDag-Erling Smørgrav
11083d2307dSDag-Erling Smørgrav #define M_QUOTE 0x8000
11183d2307dSDag-Erling Smørgrav #define M_PROTECT 0x4000
11283d2307dSDag-Erling Smørgrav #define M_MASK 0xffff
11383d2307dSDag-Erling Smørgrav #define M_ASCII 0x00ff
11483d2307dSDag-Erling Smørgrav
11583d2307dSDag-Erling Smørgrav typedef u_short Char;
11683d2307dSDag-Erling Smørgrav
11783d2307dSDag-Erling Smørgrav #else
11883d2307dSDag-Erling Smørgrav
11983d2307dSDag-Erling Smørgrav #define M_QUOTE 0x80
12083d2307dSDag-Erling Smørgrav #define M_PROTECT 0x40
12183d2307dSDag-Erling Smørgrav #define M_MASK 0xff
12283d2307dSDag-Erling Smørgrav #define M_ASCII 0x7f
12383d2307dSDag-Erling Smørgrav
12483d2307dSDag-Erling Smørgrav typedef char Char;
12583d2307dSDag-Erling Smørgrav
12683d2307dSDag-Erling Smørgrav #endif
12783d2307dSDag-Erling Smørgrav
12883d2307dSDag-Erling Smørgrav
12983d2307dSDag-Erling Smørgrav #define CHAR(c) ((Char)((c)&M_ASCII))
13083d2307dSDag-Erling Smørgrav #define META(c) ((Char)((c)|M_QUOTE))
13183d2307dSDag-Erling Smørgrav #define M_ALL META('*')
13283d2307dSDag-Erling Smørgrav #define M_END META(']')
13383d2307dSDag-Erling Smørgrav #define M_NOT META('!')
13483d2307dSDag-Erling Smørgrav #define M_ONE META('?')
13583d2307dSDag-Erling Smørgrav #define M_RNG META('-')
13683d2307dSDag-Erling Smørgrav #define M_SET META('[')
1374a421b63SDag-Erling Smørgrav #define M_CLASS META(':')
13883d2307dSDag-Erling Smørgrav #define ismeta(c) (((c)&M_QUOTE) != 0)
13983d2307dSDag-Erling Smørgrav
1404a421b63SDag-Erling Smørgrav #define GLOB_LIMIT_MALLOC 65536
141*19261079SEd Maste #define GLOB_LIMIT_STAT 2048
1424a421b63SDag-Erling Smørgrav #define GLOB_LIMIT_READDIR 16384
1434a421b63SDag-Erling Smørgrav
1444a421b63SDag-Erling Smørgrav struct glob_lim {
1454a421b63SDag-Erling Smørgrav size_t glim_malloc;
1464a421b63SDag-Erling Smørgrav size_t glim_stat;
1474a421b63SDag-Erling Smørgrav size_t glim_readdir;
1484a421b63SDag-Erling Smørgrav };
14983d2307dSDag-Erling Smørgrav
150462c32cbSDag-Erling Smørgrav struct glob_path_stat {
151462c32cbSDag-Erling Smørgrav char *gps_path;
152462c32cbSDag-Erling Smørgrav struct stat *gps_stat;
153462c32cbSDag-Erling Smørgrav };
154462c32cbSDag-Erling Smørgrav
1554b17dab0SDag-Erling Smørgrav static int compare(const void *, const void *);
156462c32cbSDag-Erling Smørgrav static int compare_gps(const void *, const void *);
157*19261079SEd Maste static int g_Ctoc(const Char *, char *, size_t);
1584b17dab0SDag-Erling Smørgrav static int g_lstat(Char *, struct stat *, glob_t *);
1594b17dab0SDag-Erling Smørgrav static DIR *g_opendir(Char *, glob_t *);
1604a421b63SDag-Erling Smørgrav static Char *g_strchr(const Char *, int);
1614a421b63SDag-Erling Smørgrav static int g_strncmp(const Char *, const char *, size_t);
1624b17dab0SDag-Erling Smørgrav static int g_stat(Char *, struct stat *, glob_t *);
1634a421b63SDag-Erling Smørgrav static int glob0(const Char *, glob_t *, struct glob_lim *);
1644a421b63SDag-Erling Smørgrav static int glob1(Char *, Char *, glob_t *, struct glob_lim *);
1654b17dab0SDag-Erling Smørgrav static int glob2(Char *, Char *, Char *, Char *, Char *, Char *,
1664a421b63SDag-Erling Smørgrav glob_t *, struct glob_lim *);
167d4af9e69SDag-Erling Smørgrav static int glob3(Char *, Char *, Char *, Char *, Char *,
1684a421b63SDag-Erling Smørgrav Char *, Char *, glob_t *, struct glob_lim *);
1694a421b63SDag-Erling Smørgrav static int globextend(const Char *, glob_t *, struct glob_lim *,
1704a421b63SDag-Erling Smørgrav struct stat *);
17183d2307dSDag-Erling Smørgrav static const Char *
1724b17dab0SDag-Erling Smørgrav globtilde(const Char *, Char *, size_t, glob_t *);
1734a421b63SDag-Erling Smørgrav static int globexp1(const Char *, glob_t *, struct glob_lim *);
1744a421b63SDag-Erling Smørgrav static int globexp2(const Char *, const Char *, glob_t *,
1754a421b63SDag-Erling Smørgrav struct glob_lim *);
176*19261079SEd Maste static int match(Char *, Char *, Char *);
17783d2307dSDag-Erling Smørgrav #ifdef DEBUG
1784b17dab0SDag-Erling Smørgrav static void qprintf(const char *, Char *);
17983d2307dSDag-Erling Smørgrav #endif
18083d2307dSDag-Erling Smørgrav
18183d2307dSDag-Erling Smørgrav int
glob(const char * pattern,int flags,int (* errfunc)(const char *,int),glob_t * pglob)182021d409fSDag-Erling Smørgrav glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
183021d409fSDag-Erling Smørgrav glob_t *pglob)
18483d2307dSDag-Erling Smørgrav {
18583d2307dSDag-Erling Smørgrav const u_char *patnext;
18683d2307dSDag-Erling Smørgrav int c;
187*19261079SEd Maste Char *bufnext, *bufend, patbuf[PATH_MAX];
1884a421b63SDag-Erling Smørgrav struct glob_lim limit = { 0, 0, 0 };
18983d2307dSDag-Erling Smørgrav
19083d2307dSDag-Erling Smørgrav patnext = (u_char *) pattern;
19183d2307dSDag-Erling Smørgrav if (!(flags & GLOB_APPEND)) {
19283d2307dSDag-Erling Smørgrav pglob->gl_pathc = 0;
19383d2307dSDag-Erling Smørgrav pglob->gl_pathv = NULL;
1944a421b63SDag-Erling Smørgrav pglob->gl_statv = NULL;
19583d2307dSDag-Erling Smørgrav if (!(flags & GLOB_DOOFFS))
19683d2307dSDag-Erling Smørgrav pglob->gl_offs = 0;
19783d2307dSDag-Erling Smørgrav }
19883d2307dSDag-Erling Smørgrav pglob->gl_flags = flags & ~GLOB_MAGCHAR;
19983d2307dSDag-Erling Smørgrav pglob->gl_errfunc = errfunc;
20083d2307dSDag-Erling Smørgrav pglob->gl_matchc = 0;
20183d2307dSDag-Erling Smørgrav
202*19261079SEd Maste if (strnlen(pattern, PATH_MAX) == PATH_MAX)
203*19261079SEd Maste return(GLOB_NOMATCH);
204*19261079SEd Maste
205*19261079SEd Maste if (pglob->gl_offs >= SSIZE_MAX || pglob->gl_pathc >= SSIZE_MAX ||
206*19261079SEd Maste pglob->gl_pathc >= SSIZE_MAX - pglob->gl_offs - 1)
2074a421b63SDag-Erling Smørgrav return GLOB_NOSPACE;
2084a421b63SDag-Erling Smørgrav
20983d2307dSDag-Erling Smørgrav bufnext = patbuf;
210*19261079SEd Maste bufend = bufnext + PATH_MAX - 1;
21183d2307dSDag-Erling Smørgrav if (flags & GLOB_NOESCAPE)
21283d2307dSDag-Erling Smørgrav while (bufnext < bufend && (c = *patnext++) != EOS)
21383d2307dSDag-Erling Smørgrav *bufnext++ = c;
21483d2307dSDag-Erling Smørgrav else {
21583d2307dSDag-Erling Smørgrav /* Protect the quoted characters. */
21683d2307dSDag-Erling Smørgrav while (bufnext < bufend && (c = *patnext++) != EOS)
21783d2307dSDag-Erling Smørgrav if (c == QUOTE) {
21883d2307dSDag-Erling Smørgrav if ((c = *patnext++) == EOS) {
21983d2307dSDag-Erling Smørgrav c = QUOTE;
22083d2307dSDag-Erling Smørgrav --patnext;
22183d2307dSDag-Erling Smørgrav }
22283d2307dSDag-Erling Smørgrav *bufnext++ = c | M_PROTECT;
22383d2307dSDag-Erling Smørgrav } else
22483d2307dSDag-Erling Smørgrav *bufnext++ = c;
22583d2307dSDag-Erling Smørgrav }
22683d2307dSDag-Erling Smørgrav *bufnext = EOS;
22783d2307dSDag-Erling Smørgrav
22883d2307dSDag-Erling Smørgrav if (flags & GLOB_BRACE)
2294a421b63SDag-Erling Smørgrav return globexp1(patbuf, pglob, &limit);
23083d2307dSDag-Erling Smørgrav else
2314a421b63SDag-Erling Smørgrav return glob0(patbuf, pglob, &limit);
23283d2307dSDag-Erling Smørgrav }
23383d2307dSDag-Erling Smørgrav
23483d2307dSDag-Erling Smørgrav /*
23583d2307dSDag-Erling Smørgrav * Expand recursively a glob {} pattern. When there is no more expansion
23683d2307dSDag-Erling Smørgrav * invoke the standard globbing routine to glob the rest of the magic
23783d2307dSDag-Erling Smørgrav * characters
23883d2307dSDag-Erling Smørgrav */
23983d2307dSDag-Erling Smørgrav static int
globexp1(const Char * pattern,glob_t * pglob,struct glob_lim * limitp)2404a421b63SDag-Erling Smørgrav globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
24183d2307dSDag-Erling Smørgrav {
24283d2307dSDag-Erling Smørgrav const Char* ptr = pattern;
24383d2307dSDag-Erling Smørgrav
24483d2307dSDag-Erling Smørgrav /* Protect a single {}, for find(1), like csh */
24583d2307dSDag-Erling Smørgrav if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
2464a421b63SDag-Erling Smørgrav return glob0(pattern, pglob, limitp);
24783d2307dSDag-Erling Smørgrav
2484a421b63SDag-Erling Smørgrav if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
2494a421b63SDag-Erling Smørgrav return globexp2(ptr, pattern, pglob, limitp);
25083d2307dSDag-Erling Smørgrav
2514a421b63SDag-Erling Smørgrav return glob0(pattern, pglob, limitp);
25283d2307dSDag-Erling Smørgrav }
25383d2307dSDag-Erling Smørgrav
25483d2307dSDag-Erling Smørgrav
25583d2307dSDag-Erling Smørgrav /*
25683d2307dSDag-Erling Smørgrav * Recursive brace globbing helper. Tries to expand a single brace.
25783d2307dSDag-Erling Smørgrav * If it succeeds then it invokes globexp1 with the new pattern.
25883d2307dSDag-Erling Smørgrav * If it fails then it tries to glob the rest of the pattern and returns.
25983d2307dSDag-Erling Smørgrav */
26083d2307dSDag-Erling Smørgrav static int
globexp2(const Char * ptr,const Char * pattern,glob_t * pglob,struct glob_lim * limitp)2614a421b63SDag-Erling Smørgrav globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
2624a421b63SDag-Erling Smørgrav struct glob_lim *limitp)
26383d2307dSDag-Erling Smørgrav {
2644a421b63SDag-Erling Smørgrav int i, rv;
26583d2307dSDag-Erling Smørgrav Char *lm, *ls;
26683d2307dSDag-Erling Smørgrav const Char *pe, *pm, *pl;
267*19261079SEd Maste Char patbuf[PATH_MAX];
26883d2307dSDag-Erling Smørgrav
26983d2307dSDag-Erling Smørgrav /* copy part up to the brace */
27083d2307dSDag-Erling Smørgrav for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
27183d2307dSDag-Erling Smørgrav ;
27283d2307dSDag-Erling Smørgrav *lm = EOS;
27383d2307dSDag-Erling Smørgrav ls = lm;
27483d2307dSDag-Erling Smørgrav
27583d2307dSDag-Erling Smørgrav /* Find the balanced brace */
27683d2307dSDag-Erling Smørgrav for (i = 0, pe = ++ptr; *pe; pe++)
27783d2307dSDag-Erling Smørgrav if (*pe == LBRACKET) {
27883d2307dSDag-Erling Smørgrav /* Ignore everything between [] */
27983d2307dSDag-Erling Smørgrav for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
28083d2307dSDag-Erling Smørgrav ;
28183d2307dSDag-Erling Smørgrav if (*pe == EOS) {
28283d2307dSDag-Erling Smørgrav /*
28383d2307dSDag-Erling Smørgrav * We could not find a matching RBRACKET.
28483d2307dSDag-Erling Smørgrav * Ignore and just look for RBRACE
28583d2307dSDag-Erling Smørgrav */
28683d2307dSDag-Erling Smørgrav pe = pm;
28783d2307dSDag-Erling Smørgrav }
28883d2307dSDag-Erling Smørgrav } else if (*pe == LBRACE)
28983d2307dSDag-Erling Smørgrav i++;
29083d2307dSDag-Erling Smørgrav else if (*pe == RBRACE) {
29183d2307dSDag-Erling Smørgrav if (i == 0)
29283d2307dSDag-Erling Smørgrav break;
29383d2307dSDag-Erling Smørgrav i--;
29483d2307dSDag-Erling Smørgrav }
29583d2307dSDag-Erling Smørgrav
29683d2307dSDag-Erling Smørgrav /* Non matching braces; just glob the pattern */
2974a421b63SDag-Erling Smørgrav if (i != 0 || *pe == EOS)
2984a421b63SDag-Erling Smørgrav return glob0(patbuf, pglob, limitp);
29983d2307dSDag-Erling Smørgrav
30083d2307dSDag-Erling Smørgrav for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
30183d2307dSDag-Erling Smørgrav switch (*pm) {
30283d2307dSDag-Erling Smørgrav case LBRACKET:
30383d2307dSDag-Erling Smørgrav /* Ignore everything between [] */
30483d2307dSDag-Erling Smørgrav for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
30583d2307dSDag-Erling Smørgrav ;
30683d2307dSDag-Erling Smørgrav if (*pm == EOS) {
30783d2307dSDag-Erling Smørgrav /*
30883d2307dSDag-Erling Smørgrav * We could not find a matching RBRACKET.
30983d2307dSDag-Erling Smørgrav * Ignore and just look for RBRACE
31083d2307dSDag-Erling Smørgrav */
31183d2307dSDag-Erling Smørgrav pm = pl;
31283d2307dSDag-Erling Smørgrav }
31383d2307dSDag-Erling Smørgrav break;
31483d2307dSDag-Erling Smørgrav
31583d2307dSDag-Erling Smørgrav case LBRACE:
31683d2307dSDag-Erling Smørgrav i++;
31783d2307dSDag-Erling Smørgrav break;
31883d2307dSDag-Erling Smørgrav
31983d2307dSDag-Erling Smørgrav case RBRACE:
32083d2307dSDag-Erling Smørgrav if (i) {
32183d2307dSDag-Erling Smørgrav i--;
32283d2307dSDag-Erling Smørgrav break;
32383d2307dSDag-Erling Smørgrav }
32483d2307dSDag-Erling Smørgrav /* FALLTHROUGH */
32583d2307dSDag-Erling Smørgrav case COMMA:
32683d2307dSDag-Erling Smørgrav if (i && *pm == COMMA)
32783d2307dSDag-Erling Smørgrav break;
32883d2307dSDag-Erling Smørgrav else {
32983d2307dSDag-Erling Smørgrav /* Append the current string */
33083d2307dSDag-Erling Smørgrav for (lm = ls; (pl < pm); *lm++ = *pl++)
33183d2307dSDag-Erling Smørgrav ;
33283d2307dSDag-Erling Smørgrav
33383d2307dSDag-Erling Smørgrav /*
33483d2307dSDag-Erling Smørgrav * Append the rest of the pattern after the
33583d2307dSDag-Erling Smørgrav * closing brace
33683d2307dSDag-Erling Smørgrav */
33783d2307dSDag-Erling Smørgrav for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
33883d2307dSDag-Erling Smørgrav ;
33983d2307dSDag-Erling Smørgrav
34083d2307dSDag-Erling Smørgrav /* Expand the current pattern */
34183d2307dSDag-Erling Smørgrav #ifdef DEBUG
34283d2307dSDag-Erling Smørgrav qprintf("globexp2:", patbuf);
34383d2307dSDag-Erling Smørgrav #endif
3444a421b63SDag-Erling Smørgrav rv = globexp1(patbuf, pglob, limitp);
3454a421b63SDag-Erling Smørgrav if (rv && rv != GLOB_NOMATCH)
3464a421b63SDag-Erling Smørgrav return rv;
34783d2307dSDag-Erling Smørgrav
34883d2307dSDag-Erling Smørgrav /* move after the comma, to the next string */
34983d2307dSDag-Erling Smørgrav pl = pm + 1;
35083d2307dSDag-Erling Smørgrav }
35183d2307dSDag-Erling Smørgrav break;
35283d2307dSDag-Erling Smørgrav
35383d2307dSDag-Erling Smørgrav default:
35483d2307dSDag-Erling Smørgrav break;
35583d2307dSDag-Erling Smørgrav }
35683d2307dSDag-Erling Smørgrav }
35783d2307dSDag-Erling Smørgrav return 0;
35883d2307dSDag-Erling Smørgrav }
35983d2307dSDag-Erling Smørgrav
36083d2307dSDag-Erling Smørgrav
36183d2307dSDag-Erling Smørgrav
36283d2307dSDag-Erling Smørgrav /*
36383d2307dSDag-Erling Smørgrav * expand tilde from the passwd file.
36483d2307dSDag-Erling Smørgrav */
36583d2307dSDag-Erling Smørgrav static const Char *
globtilde(const Char * pattern,Char * patbuf,size_t patbuf_len,glob_t * pglob)366021d409fSDag-Erling Smørgrav globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
36783d2307dSDag-Erling Smørgrav {
36883d2307dSDag-Erling Smørgrav struct passwd *pwd;
36983d2307dSDag-Erling Smørgrav char *h;
37083d2307dSDag-Erling Smørgrav const Char *p;
37183d2307dSDag-Erling Smørgrav Char *b, *eb;
37283d2307dSDag-Erling Smørgrav
37383d2307dSDag-Erling Smørgrav if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
37483d2307dSDag-Erling Smørgrav return pattern;
37583d2307dSDag-Erling Smørgrav
37683d2307dSDag-Erling Smørgrav /* Copy up to the end of the string or / */
37783d2307dSDag-Erling Smørgrav eb = &patbuf[patbuf_len - 1];
37883d2307dSDag-Erling Smørgrav for (p = pattern + 1, h = (char *) patbuf;
37983d2307dSDag-Erling Smørgrav h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
38083d2307dSDag-Erling Smørgrav ;
38183d2307dSDag-Erling Smørgrav
38283d2307dSDag-Erling Smørgrav *h = EOS;
38383d2307dSDag-Erling Smørgrav
38483d2307dSDag-Erling Smørgrav #if 0
38583d2307dSDag-Erling Smørgrav if (h == (char *)eb)
38683d2307dSDag-Erling Smørgrav return what;
38783d2307dSDag-Erling Smørgrav #endif
38883d2307dSDag-Erling Smørgrav
38983d2307dSDag-Erling Smørgrav if (((char *) patbuf)[0] == EOS) {
39083d2307dSDag-Erling Smørgrav /*
39183d2307dSDag-Erling Smørgrav * handle a plain ~ or ~/ by expanding $HOME
39283d2307dSDag-Erling Smørgrav * first and then trying the password file
39383d2307dSDag-Erling Smørgrav */
39483d2307dSDag-Erling Smørgrav #if 0
39583d2307dSDag-Erling Smørgrav if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
39683d2307dSDag-Erling Smørgrav #endif
39783d2307dSDag-Erling Smørgrav if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
39883d2307dSDag-Erling Smørgrav if ((pwd = getpwuid(getuid())) == NULL)
39983d2307dSDag-Erling Smørgrav return pattern;
40083d2307dSDag-Erling Smørgrav else
40183d2307dSDag-Erling Smørgrav h = pwd->pw_dir;
40283d2307dSDag-Erling Smørgrav }
40383d2307dSDag-Erling Smørgrav } else {
40483d2307dSDag-Erling Smørgrav /*
40583d2307dSDag-Erling Smørgrav * Expand a ~user
40683d2307dSDag-Erling Smørgrav */
40783d2307dSDag-Erling Smørgrav if ((pwd = getpwnam((char*) patbuf)) == NULL)
40883d2307dSDag-Erling Smørgrav return pattern;
40983d2307dSDag-Erling Smørgrav else
41083d2307dSDag-Erling Smørgrav h = pwd->pw_dir;
41183d2307dSDag-Erling Smørgrav }
41283d2307dSDag-Erling Smørgrav
41383d2307dSDag-Erling Smørgrav /* Copy the home directory */
41483d2307dSDag-Erling Smørgrav for (b = patbuf; b < eb && *h; *b++ = *h++)
41583d2307dSDag-Erling Smørgrav ;
41683d2307dSDag-Erling Smørgrav
41783d2307dSDag-Erling Smørgrav /* Append the rest of the pattern */
41883d2307dSDag-Erling Smørgrav while (b < eb && (*b++ = *p++) != EOS)
41983d2307dSDag-Erling Smørgrav ;
42083d2307dSDag-Erling Smørgrav *b = EOS;
42183d2307dSDag-Erling Smørgrav
42283d2307dSDag-Erling Smørgrav return patbuf;
42383d2307dSDag-Erling Smørgrav }
42483d2307dSDag-Erling Smørgrav
4254a421b63SDag-Erling Smørgrav static int
4264a421b63SDag-Erling Smørgrav g_strncmp(const Char *s1, const char *s2, size_t n)
4274a421b63SDag-Erling Smørgrav {
4284a421b63SDag-Erling Smørgrav int rv = 0;
4294a421b63SDag-Erling Smørgrav
4304a421b63SDag-Erling Smørgrav while (n--) {
4314a421b63SDag-Erling Smørgrav rv = *(Char *)s1 - *(const unsigned char *)s2++;
4324a421b63SDag-Erling Smørgrav if (rv)
4334a421b63SDag-Erling Smørgrav break;
4344a421b63SDag-Erling Smørgrav if (*s1++ == '\0')
4354a421b63SDag-Erling Smørgrav break;
4364a421b63SDag-Erling Smørgrav }
4374a421b63SDag-Erling Smørgrav return rv;
4384a421b63SDag-Erling Smørgrav }
4394a421b63SDag-Erling Smørgrav
4404a421b63SDag-Erling Smørgrav static int
4414a421b63SDag-Erling Smørgrav g_charclass(const Char **patternp, Char **bufnextp)
4424a421b63SDag-Erling Smørgrav {
4434a421b63SDag-Erling Smørgrav const Char *pattern = *patternp + 1;
4444a421b63SDag-Erling Smørgrav Char *bufnext = *bufnextp;
4454a421b63SDag-Erling Smørgrav const Char *colon;
4464a421b63SDag-Erling Smørgrav struct cclass *cc;
4474a421b63SDag-Erling Smørgrav size_t len;
4484a421b63SDag-Erling Smørgrav
4494a421b63SDag-Erling Smørgrav if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
4504a421b63SDag-Erling Smørgrav return 1; /* not a character class */
4514a421b63SDag-Erling Smørgrav
4524a421b63SDag-Erling Smørgrav len = (size_t)(colon - pattern);
4534a421b63SDag-Erling Smørgrav for (cc = cclasses; cc->name != NULL; cc++) {
4544a421b63SDag-Erling Smørgrav if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
4554a421b63SDag-Erling Smørgrav break;
4564a421b63SDag-Erling Smørgrav }
4574a421b63SDag-Erling Smørgrav if (cc->name == NULL)
4584a421b63SDag-Erling Smørgrav return -1; /* invalid character class */
4594a421b63SDag-Erling Smørgrav *bufnext++ = M_CLASS;
4604a421b63SDag-Erling Smørgrav *bufnext++ = (Char)(cc - &cclasses[0]);
4614a421b63SDag-Erling Smørgrav *bufnextp = bufnext;
4624a421b63SDag-Erling Smørgrav *patternp += len + 3;
4634a421b63SDag-Erling Smørgrav
4644a421b63SDag-Erling Smørgrav return 0;
4654a421b63SDag-Erling Smørgrav }
46683d2307dSDag-Erling Smørgrav
46783d2307dSDag-Erling Smørgrav /*
46883d2307dSDag-Erling Smørgrav * The main glob() routine: compiles the pattern (optionally processing
46983d2307dSDag-Erling Smørgrav * quotes), calls glob1() to do the real pattern matching, and finally
47083d2307dSDag-Erling Smørgrav * sorts the list (unless unsorted operation is requested). Returns 0
47183d2307dSDag-Erling Smørgrav * if things went well, nonzero if errors occurred. It is not an error
47283d2307dSDag-Erling Smørgrav * to find no matches.
47383d2307dSDag-Erling Smørgrav */
47483d2307dSDag-Erling Smørgrav static int
4754a421b63SDag-Erling Smørgrav glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
47683d2307dSDag-Erling Smørgrav {
47783d2307dSDag-Erling Smørgrav const Char *qpatnext;
478*19261079SEd Maste int c, err;
479*19261079SEd Maste size_t oldpathc;
480*19261079SEd Maste Char *bufnext, patbuf[PATH_MAX];
48183d2307dSDag-Erling Smørgrav
482*19261079SEd Maste qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
48383d2307dSDag-Erling Smørgrav oldpathc = pglob->gl_pathc;
48483d2307dSDag-Erling Smørgrav bufnext = patbuf;
48583d2307dSDag-Erling Smørgrav
48683d2307dSDag-Erling Smørgrav /* We don't need to check for buffer overflow any more. */
48783d2307dSDag-Erling Smørgrav while ((c = *qpatnext++) != EOS) {
48883d2307dSDag-Erling Smørgrav switch (c) {
48983d2307dSDag-Erling Smørgrav case LBRACKET:
49083d2307dSDag-Erling Smørgrav c = *qpatnext;
49183d2307dSDag-Erling Smørgrav if (c == NOT)
49283d2307dSDag-Erling Smørgrav ++qpatnext;
49383d2307dSDag-Erling Smørgrav if (*qpatnext == EOS ||
4944a421b63SDag-Erling Smørgrav g_strchr(qpatnext+1, RBRACKET) == NULL) {
49583d2307dSDag-Erling Smørgrav *bufnext++ = LBRACKET;
49683d2307dSDag-Erling Smørgrav if (c == NOT)
49783d2307dSDag-Erling Smørgrav --qpatnext;
49883d2307dSDag-Erling Smørgrav break;
49983d2307dSDag-Erling Smørgrav }
50083d2307dSDag-Erling Smørgrav *bufnext++ = M_SET;
50183d2307dSDag-Erling Smørgrav if (c == NOT)
50283d2307dSDag-Erling Smørgrav *bufnext++ = M_NOT;
50383d2307dSDag-Erling Smørgrav c = *qpatnext++;
50483d2307dSDag-Erling Smørgrav do {
5054a421b63SDag-Erling Smørgrav if (c == LBRACKET && *qpatnext == ':') {
5064a421b63SDag-Erling Smørgrav do {
5074a421b63SDag-Erling Smørgrav err = g_charclass(&qpatnext,
5084a421b63SDag-Erling Smørgrav &bufnext);
5094a421b63SDag-Erling Smørgrav if (err)
5104a421b63SDag-Erling Smørgrav break;
5114a421b63SDag-Erling Smørgrav c = *qpatnext++;
5124a421b63SDag-Erling Smørgrav } while (c == LBRACKET && *qpatnext == ':');
5134a421b63SDag-Erling Smørgrav if (err == -1 &&
5144a421b63SDag-Erling Smørgrav !(pglob->gl_flags & GLOB_NOCHECK))
5154a421b63SDag-Erling Smørgrav return GLOB_NOMATCH;
5164a421b63SDag-Erling Smørgrav if (c == RBRACKET)
5174a421b63SDag-Erling Smørgrav break;
5184a421b63SDag-Erling Smørgrav }
51983d2307dSDag-Erling Smørgrav *bufnext++ = CHAR(c);
52083d2307dSDag-Erling Smørgrav if (*qpatnext == RANGE &&
52183d2307dSDag-Erling Smørgrav (c = qpatnext[1]) != RBRACKET) {
52283d2307dSDag-Erling Smørgrav *bufnext++ = M_RNG;
52383d2307dSDag-Erling Smørgrav *bufnext++ = CHAR(c);
52483d2307dSDag-Erling Smørgrav qpatnext += 2;
52583d2307dSDag-Erling Smørgrav }
52683d2307dSDag-Erling Smørgrav } while ((c = *qpatnext++) != RBRACKET);
52783d2307dSDag-Erling Smørgrav pglob->gl_flags |= GLOB_MAGCHAR;
52883d2307dSDag-Erling Smørgrav *bufnext++ = M_END;
52983d2307dSDag-Erling Smørgrav break;
53083d2307dSDag-Erling Smørgrav case QUESTION:
53183d2307dSDag-Erling Smørgrav pglob->gl_flags |= GLOB_MAGCHAR;
53283d2307dSDag-Erling Smørgrav *bufnext++ = M_ONE;
53383d2307dSDag-Erling Smørgrav break;
53483d2307dSDag-Erling Smørgrav case STAR:
53583d2307dSDag-Erling Smørgrav pglob->gl_flags |= GLOB_MAGCHAR;
53683d2307dSDag-Erling Smørgrav /* collapse adjacent stars to one,
53783d2307dSDag-Erling Smørgrav * to avoid exponential behavior
53883d2307dSDag-Erling Smørgrav */
53983d2307dSDag-Erling Smørgrav if (bufnext == patbuf || bufnext[-1] != M_ALL)
54083d2307dSDag-Erling Smørgrav *bufnext++ = M_ALL;
54183d2307dSDag-Erling Smørgrav break;
54283d2307dSDag-Erling Smørgrav default:
54383d2307dSDag-Erling Smørgrav *bufnext++ = CHAR(c);
54483d2307dSDag-Erling Smørgrav break;
54583d2307dSDag-Erling Smørgrav }
54683d2307dSDag-Erling Smørgrav }
54783d2307dSDag-Erling Smørgrav *bufnext = EOS;
54883d2307dSDag-Erling Smørgrav #ifdef DEBUG
54983d2307dSDag-Erling Smørgrav qprintf("glob0:", patbuf);
55083d2307dSDag-Erling Smørgrav #endif
55183d2307dSDag-Erling Smørgrav
552*19261079SEd Maste if ((err = glob1(patbuf, patbuf+PATH_MAX-1, pglob, limitp)) != 0)
55383d2307dSDag-Erling Smørgrav return(err);
55483d2307dSDag-Erling Smørgrav
55583d2307dSDag-Erling Smørgrav /*
55683d2307dSDag-Erling Smørgrav * If there was no match we are going to append the pattern
55783d2307dSDag-Erling Smørgrav * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
55883d2307dSDag-Erling Smørgrav * and the pattern did not contain any magic characters
55983d2307dSDag-Erling Smørgrav * GLOB_NOMAGIC is there just for compatibility with csh.
56083d2307dSDag-Erling Smørgrav */
56183d2307dSDag-Erling Smørgrav if (pglob->gl_pathc == oldpathc) {
56283d2307dSDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_NOCHECK) ||
56383d2307dSDag-Erling Smørgrav ((pglob->gl_flags & GLOB_NOMAGIC) &&
56483d2307dSDag-Erling Smørgrav !(pglob->gl_flags & GLOB_MAGCHAR)))
5654a421b63SDag-Erling Smørgrav return(globextend(pattern, pglob, limitp, NULL));
56683d2307dSDag-Erling Smørgrav else
56783d2307dSDag-Erling Smørgrav return(GLOB_NOMATCH);
56883d2307dSDag-Erling Smørgrav }
569462c32cbSDag-Erling Smørgrav if (!(pglob->gl_flags & GLOB_NOSORT)) {
570462c32cbSDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
571462c32cbSDag-Erling Smørgrav /* Keep the paths and stat info synced during sort */
572462c32cbSDag-Erling Smørgrav struct glob_path_stat *path_stat;
573*19261079SEd Maste size_t i;
574*19261079SEd Maste size_t n = pglob->gl_pathc - oldpathc;
575*19261079SEd Maste size_t o = pglob->gl_offs + oldpathc;
576462c32cbSDag-Erling Smørgrav
577462c32cbSDag-Erling Smørgrav if ((path_stat = calloc(n, sizeof(*path_stat))) == NULL)
578462c32cbSDag-Erling Smørgrav return GLOB_NOSPACE;
579462c32cbSDag-Erling Smørgrav for (i = 0; i < n; i++) {
580462c32cbSDag-Erling Smørgrav path_stat[i].gps_path = pglob->gl_pathv[o + i];
581462c32cbSDag-Erling Smørgrav path_stat[i].gps_stat = pglob->gl_statv[o + i];
582462c32cbSDag-Erling Smørgrav }
583462c32cbSDag-Erling Smørgrav qsort(path_stat, n, sizeof(*path_stat), compare_gps);
584462c32cbSDag-Erling Smørgrav for (i = 0; i < n; i++) {
585462c32cbSDag-Erling Smørgrav pglob->gl_pathv[o + i] = path_stat[i].gps_path;
586462c32cbSDag-Erling Smørgrav pglob->gl_statv[o + i] = path_stat[i].gps_stat;
587462c32cbSDag-Erling Smørgrav }
588462c32cbSDag-Erling Smørgrav free(path_stat);
589462c32cbSDag-Erling Smørgrav } else {
59083d2307dSDag-Erling Smørgrav qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
591462c32cbSDag-Erling Smørgrav pglob->gl_pathc - oldpathc, sizeof(char *),
592462c32cbSDag-Erling Smørgrav compare);
593462c32cbSDag-Erling Smørgrav }
594462c32cbSDag-Erling Smørgrav }
59583d2307dSDag-Erling Smørgrav return(0);
59683d2307dSDag-Erling Smørgrav }
59783d2307dSDag-Erling Smørgrav
59883d2307dSDag-Erling Smørgrav static int
599021d409fSDag-Erling Smørgrav compare(const void *p, const void *q)
60083d2307dSDag-Erling Smørgrav {
60183d2307dSDag-Erling Smørgrav return(strcmp(*(char **)p, *(char **)q));
60283d2307dSDag-Erling Smørgrav }
60383d2307dSDag-Erling Smørgrav
60483d2307dSDag-Erling Smørgrav static int
605462c32cbSDag-Erling Smørgrav compare_gps(const void *_p, const void *_q)
606462c32cbSDag-Erling Smørgrav {
607462c32cbSDag-Erling Smørgrav const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
608462c32cbSDag-Erling Smørgrav const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
609462c32cbSDag-Erling Smørgrav
610462c32cbSDag-Erling Smørgrav return(strcmp(p->gps_path, q->gps_path));
611462c32cbSDag-Erling Smørgrav }
612462c32cbSDag-Erling Smørgrav
613462c32cbSDag-Erling Smørgrav static int
6144a421b63SDag-Erling Smørgrav glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
61583d2307dSDag-Erling Smørgrav {
616*19261079SEd Maste Char pathbuf[PATH_MAX];
61783d2307dSDag-Erling Smørgrav
61883d2307dSDag-Erling Smørgrav /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
61983d2307dSDag-Erling Smørgrav if (*pattern == EOS)
62083d2307dSDag-Erling Smørgrav return(0);
621*19261079SEd Maste return(glob2(pathbuf, pathbuf+PATH_MAX-1,
622*19261079SEd Maste pathbuf, pathbuf+PATH_MAX-1,
62383d2307dSDag-Erling Smørgrav pattern, pattern_last, pglob, limitp));
62483d2307dSDag-Erling Smørgrav }
62583d2307dSDag-Erling Smørgrav
62683d2307dSDag-Erling Smørgrav /*
62783d2307dSDag-Erling Smørgrav * The functions glob2 and glob3 are mutually recursive; there is one level
62883d2307dSDag-Erling Smørgrav * of recursion for each segment in the pattern that contains one or more
62983d2307dSDag-Erling Smørgrav * meta characters.
63083d2307dSDag-Erling Smørgrav */
63183d2307dSDag-Erling Smørgrav static int
632021d409fSDag-Erling Smørgrav glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
6334a421b63SDag-Erling Smørgrav Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
63483d2307dSDag-Erling Smørgrav {
63583d2307dSDag-Erling Smørgrav struct stat sb;
63683d2307dSDag-Erling Smørgrav Char *p, *q;
63783d2307dSDag-Erling Smørgrav int anymeta;
63883d2307dSDag-Erling Smørgrav
63983d2307dSDag-Erling Smørgrav /*
64083d2307dSDag-Erling Smørgrav * Loop over pattern segments until end of pattern or until
64183d2307dSDag-Erling Smørgrav * segment with meta character found.
64283d2307dSDag-Erling Smørgrav */
64383d2307dSDag-Erling Smørgrav for (anymeta = 0;;) {
64483d2307dSDag-Erling Smørgrav if (*pattern == EOS) { /* End of pattern? */
64583d2307dSDag-Erling Smørgrav *pathend = EOS;
64683d2307dSDag-Erling Smørgrav
6474a421b63SDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_LIMIT) &&
6484a421b63SDag-Erling Smørgrav limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
6494a421b63SDag-Erling Smørgrav errno = 0;
6504a421b63SDag-Erling Smørgrav *pathend++ = SEP;
6514a421b63SDag-Erling Smørgrav *pathend = EOS;
6524a421b63SDag-Erling Smørgrav return(GLOB_NOSPACE);
6534a421b63SDag-Erling Smørgrav }
654*19261079SEd Maste if (g_lstat(pathbuf, &sb, pglob))
655*19261079SEd Maste return(0);
6564a421b63SDag-Erling Smørgrav
65783d2307dSDag-Erling Smørgrav if (((pglob->gl_flags & GLOB_MARK) &&
65883d2307dSDag-Erling Smørgrav pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
65983d2307dSDag-Erling Smørgrav (S_ISLNK(sb.st_mode) &&
66083d2307dSDag-Erling Smørgrav (g_stat(pathbuf, &sb, pglob) == 0) &&
66183d2307dSDag-Erling Smørgrav S_ISDIR(sb.st_mode)))) {
66283d2307dSDag-Erling Smørgrav if (pathend+1 > pathend_last)
66383d2307dSDag-Erling Smørgrav return (1);
66483d2307dSDag-Erling Smørgrav *pathend++ = SEP;
66583d2307dSDag-Erling Smørgrav *pathend = EOS;
66683d2307dSDag-Erling Smørgrav }
66783d2307dSDag-Erling Smørgrav ++pglob->gl_matchc;
6684a421b63SDag-Erling Smørgrav return(globextend(pathbuf, pglob, limitp, &sb));
66983d2307dSDag-Erling Smørgrav }
67083d2307dSDag-Erling Smørgrav
67183d2307dSDag-Erling Smørgrav /* Find end of next segment, copy tentatively to pathend. */
67283d2307dSDag-Erling Smørgrav q = pathend;
67383d2307dSDag-Erling Smørgrav p = pattern;
67483d2307dSDag-Erling Smørgrav while (*p != EOS && *p != SEP) {
67583d2307dSDag-Erling Smørgrav if (ismeta(*p))
67683d2307dSDag-Erling Smørgrav anymeta = 1;
67783d2307dSDag-Erling Smørgrav if (q+1 > pathend_last)
67883d2307dSDag-Erling Smørgrav return (1);
67983d2307dSDag-Erling Smørgrav *q++ = *p++;
68083d2307dSDag-Erling Smørgrav }
68183d2307dSDag-Erling Smørgrav
68283d2307dSDag-Erling Smørgrav if (!anymeta) { /* No expansion, do next segment. */
68383d2307dSDag-Erling Smørgrav pathend = q;
68483d2307dSDag-Erling Smørgrav pattern = p;
68583d2307dSDag-Erling Smørgrav while (*pattern == SEP) {
68683d2307dSDag-Erling Smørgrav if (pathend+1 > pathend_last)
68783d2307dSDag-Erling Smørgrav return (1);
68883d2307dSDag-Erling Smørgrav *pathend++ = *pattern++;
68983d2307dSDag-Erling Smørgrav }
69083d2307dSDag-Erling Smørgrav } else
69183d2307dSDag-Erling Smørgrav /* Need expansion, recurse. */
69283d2307dSDag-Erling Smørgrav return(glob3(pathbuf, pathbuf_last, pathend,
693d4af9e69SDag-Erling Smørgrav pathend_last, pattern, p, pattern_last,
694d4af9e69SDag-Erling Smørgrav pglob, limitp));
69583d2307dSDag-Erling Smørgrav }
69683d2307dSDag-Erling Smørgrav /* NOTREACHED */
69783d2307dSDag-Erling Smørgrav }
69883d2307dSDag-Erling Smørgrav
69983d2307dSDag-Erling Smørgrav static int
700021d409fSDag-Erling Smørgrav glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
701d4af9e69SDag-Erling Smørgrav Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
7024a421b63SDag-Erling Smørgrav struct glob_lim *limitp)
70383d2307dSDag-Erling Smørgrav {
704021d409fSDag-Erling Smørgrav struct dirent *dp;
70583d2307dSDag-Erling Smørgrav DIR *dirp;
70683d2307dSDag-Erling Smørgrav int err;
707*19261079SEd Maste char buf[PATH_MAX];
70883d2307dSDag-Erling Smørgrav
70983d2307dSDag-Erling Smørgrav /*
71083d2307dSDag-Erling Smørgrav * The readdirfunc declaration can't be prototyped, because it is
71183d2307dSDag-Erling Smørgrav * assigned, below, to two functions which are prototyped in glob.h
71283d2307dSDag-Erling Smørgrav * and dirent.h as taking pointers to differently typed opaque
71383d2307dSDag-Erling Smørgrav * structures.
71483d2307dSDag-Erling Smørgrav */
715d95e11bfSDag-Erling Smørgrav struct dirent *(*readdirfunc)(void *);
71683d2307dSDag-Erling Smørgrav
71783d2307dSDag-Erling Smørgrav if (pathend > pathend_last)
71883d2307dSDag-Erling Smørgrav return (1);
71983d2307dSDag-Erling Smørgrav *pathend = EOS;
72083d2307dSDag-Erling Smørgrav errno = 0;
72183d2307dSDag-Erling Smørgrav
72283d2307dSDag-Erling Smørgrav if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
72383d2307dSDag-Erling Smørgrav /* TODO: don't call for ENOENT or ENOTDIR? */
72483d2307dSDag-Erling Smørgrav if (pglob->gl_errfunc) {
72583d2307dSDag-Erling Smørgrav if (g_Ctoc(pathbuf, buf, sizeof(buf)))
72683d2307dSDag-Erling Smørgrav return(GLOB_ABORTED);
72783d2307dSDag-Erling Smørgrav if (pglob->gl_errfunc(buf, errno) ||
72883d2307dSDag-Erling Smørgrav pglob->gl_flags & GLOB_ERR)
72983d2307dSDag-Erling Smørgrav return(GLOB_ABORTED);
73083d2307dSDag-Erling Smørgrav }
73183d2307dSDag-Erling Smørgrav return(0);
73283d2307dSDag-Erling Smørgrav }
73383d2307dSDag-Erling Smørgrav
73483d2307dSDag-Erling Smørgrav err = 0;
73583d2307dSDag-Erling Smørgrav
73683d2307dSDag-Erling Smørgrav /* Search directory for matching names. */
73783d2307dSDag-Erling Smørgrav if (pglob->gl_flags & GLOB_ALTDIRFUNC)
73883d2307dSDag-Erling Smørgrav readdirfunc = pglob->gl_readdir;
73983d2307dSDag-Erling Smørgrav else
740d95e11bfSDag-Erling Smørgrav readdirfunc = (struct dirent *(*)(void *))readdir;
74183d2307dSDag-Erling Smørgrav while ((dp = (*readdirfunc)(dirp))) {
742021d409fSDag-Erling Smørgrav u_char *sc;
743021d409fSDag-Erling Smørgrav Char *dc;
74483d2307dSDag-Erling Smørgrav
7454a421b63SDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_LIMIT) &&
7464a421b63SDag-Erling Smørgrav limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
7474a421b63SDag-Erling Smørgrav errno = 0;
7484a421b63SDag-Erling Smørgrav *pathend++ = SEP;
7494a421b63SDag-Erling Smørgrav *pathend = EOS;
750462c32cbSDag-Erling Smørgrav err = GLOB_NOSPACE;
751462c32cbSDag-Erling Smørgrav break;
7524a421b63SDag-Erling Smørgrav }
7534a421b63SDag-Erling Smørgrav
75483d2307dSDag-Erling Smørgrav /* Initial DOT must be matched literally. */
75583d2307dSDag-Erling Smørgrav if (dp->d_name[0] == DOT && *pattern != DOT)
75683d2307dSDag-Erling Smørgrav continue;
75783d2307dSDag-Erling Smørgrav dc = pathend;
75883d2307dSDag-Erling Smørgrav sc = (u_char *) dp->d_name;
75983d2307dSDag-Erling Smørgrav while (dc < pathend_last && (*dc++ = *sc++) != EOS)
76083d2307dSDag-Erling Smørgrav ;
76183d2307dSDag-Erling Smørgrav if (dc >= pathend_last) {
76283d2307dSDag-Erling Smørgrav *dc = EOS;
76383d2307dSDag-Erling Smørgrav err = 1;
76483d2307dSDag-Erling Smørgrav break;
76583d2307dSDag-Erling Smørgrav }
76683d2307dSDag-Erling Smørgrav
767*19261079SEd Maste if (!match(pathend, pattern, restpattern)) {
76883d2307dSDag-Erling Smørgrav *pathend = EOS;
76983d2307dSDag-Erling Smørgrav continue;
77083d2307dSDag-Erling Smørgrav }
77183d2307dSDag-Erling Smørgrav err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
77283d2307dSDag-Erling Smørgrav restpattern, restpattern_last, pglob, limitp);
77383d2307dSDag-Erling Smørgrav if (err)
77483d2307dSDag-Erling Smørgrav break;
77583d2307dSDag-Erling Smørgrav }
77683d2307dSDag-Erling Smørgrav
77783d2307dSDag-Erling Smørgrav if (pglob->gl_flags & GLOB_ALTDIRFUNC)
77883d2307dSDag-Erling Smørgrav (*pglob->gl_closedir)(dirp);
77983d2307dSDag-Erling Smørgrav else
78083d2307dSDag-Erling Smørgrav closedir(dirp);
78183d2307dSDag-Erling Smørgrav return(err);
78283d2307dSDag-Erling Smørgrav }
78383d2307dSDag-Erling Smørgrav
78483d2307dSDag-Erling Smørgrav
78583d2307dSDag-Erling Smørgrav /*
7864b17dab0SDag-Erling Smørgrav * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
78783d2307dSDag-Erling Smørgrav * add the new item, and update gl_pathc.
78883d2307dSDag-Erling Smørgrav *
78983d2307dSDag-Erling Smørgrav * This assumes the BSD realloc, which only copies the block when its size
79083d2307dSDag-Erling Smørgrav * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
79183d2307dSDag-Erling Smørgrav * behavior.
79283d2307dSDag-Erling Smørgrav *
79383d2307dSDag-Erling Smørgrav * Return 0 if new item added, error code if memory couldn't be allocated.
79483d2307dSDag-Erling Smørgrav *
79583d2307dSDag-Erling Smørgrav * Invariant of the glob_t structure:
79683d2307dSDag-Erling Smørgrav * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
79783d2307dSDag-Erling Smørgrav * gl_pathv points to (gl_offs + gl_pathc + 1) items.
79883d2307dSDag-Erling Smørgrav */
79983d2307dSDag-Erling Smørgrav static int
8004a421b63SDag-Erling Smørgrav globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
8014a421b63SDag-Erling Smørgrav struct stat *sb)
80283d2307dSDag-Erling Smørgrav {
803021d409fSDag-Erling Smørgrav char **pathv;
804*19261079SEd Maste size_t i, newn, len;
8054a421b63SDag-Erling Smørgrav char *copy = NULL;
80683d2307dSDag-Erling Smørgrav const Char *p;
8074a421b63SDag-Erling Smørgrav struct stat **statv;
80883d2307dSDag-Erling Smørgrav
8094a421b63SDag-Erling Smørgrav newn = 2 + pglob->gl_pathc + pglob->gl_offs;
810*19261079SEd Maste if (pglob->gl_offs >= SSIZE_MAX ||
811*19261079SEd Maste pglob->gl_pathc >= SSIZE_MAX ||
812*19261079SEd Maste newn >= SSIZE_MAX ||
8134a421b63SDag-Erling Smørgrav SIZE_MAX / sizeof(*pathv) <= newn ||
8144a421b63SDag-Erling Smørgrav SIZE_MAX / sizeof(*statv) <= newn) {
8154a421b63SDag-Erling Smørgrav nospace:
816*19261079SEd Maste for (i = pglob->gl_offs; i < newn - 2; i++) {
8174a421b63SDag-Erling Smørgrav if (pglob->gl_pathv && pglob->gl_pathv[i])
8184a421b63SDag-Erling Smørgrav free(pglob->gl_pathv[i]);
8194a421b63SDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
8204a421b63SDag-Erling Smørgrav pglob->gl_pathv && pglob->gl_pathv[i])
8214a421b63SDag-Erling Smørgrav free(pglob->gl_statv[i]);
8224a421b63SDag-Erling Smørgrav }
82383d2307dSDag-Erling Smørgrav free(pglob->gl_pathv);
82483d2307dSDag-Erling Smørgrav pglob->gl_pathv = NULL;
8254a421b63SDag-Erling Smørgrav free(pglob->gl_statv);
8264a421b63SDag-Erling Smørgrav pglob->gl_statv = NULL;
82783d2307dSDag-Erling Smørgrav return(GLOB_NOSPACE);
82883d2307dSDag-Erling Smørgrav }
82983d2307dSDag-Erling Smørgrav
830*19261079SEd Maste pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
8314a421b63SDag-Erling Smørgrav if (pathv == NULL)
8324a421b63SDag-Erling Smørgrav goto nospace;
83383d2307dSDag-Erling Smørgrav if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
83483d2307dSDag-Erling Smørgrav /* first time around -- clear initial gl_offs items */
83583d2307dSDag-Erling Smørgrav pathv += pglob->gl_offs;
836*19261079SEd Maste for (i = pglob->gl_offs; i > 0; i--)
83783d2307dSDag-Erling Smørgrav *--pathv = NULL;
83883d2307dSDag-Erling Smørgrav }
83983d2307dSDag-Erling Smørgrav pglob->gl_pathv = pathv;
84083d2307dSDag-Erling Smørgrav
8414a421b63SDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
842*19261079SEd Maste statv = reallocarray(pglob->gl_statv, newn, sizeof(*statv));
8434a421b63SDag-Erling Smørgrav if (statv == NULL)
8444a421b63SDag-Erling Smørgrav goto nospace;
8454a421b63SDag-Erling Smørgrav if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
8464a421b63SDag-Erling Smørgrav /* first time around -- clear initial gl_offs items */
8474a421b63SDag-Erling Smørgrav statv += pglob->gl_offs;
848*19261079SEd Maste for (i = pglob->gl_offs; i > 0; i--)
8494a421b63SDag-Erling Smørgrav *--statv = NULL;
8504a421b63SDag-Erling Smørgrav }
8514a421b63SDag-Erling Smørgrav pglob->gl_statv = statv;
8524a421b63SDag-Erling Smørgrav if (sb == NULL)
8534a421b63SDag-Erling Smørgrav statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
8544a421b63SDag-Erling Smørgrav else {
8554a421b63SDag-Erling Smørgrav limitp->glim_malloc += sizeof(**statv);
8564a421b63SDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_LIMIT) &&
8574a421b63SDag-Erling Smørgrav limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
8584a421b63SDag-Erling Smørgrav errno = 0;
8594a421b63SDag-Erling Smørgrav return(GLOB_NOSPACE);
8604a421b63SDag-Erling Smørgrav }
8614a421b63SDag-Erling Smørgrav if ((statv[pglob->gl_offs + pglob->gl_pathc] =
8624a421b63SDag-Erling Smørgrav malloc(sizeof(**statv))) == NULL)
8634a421b63SDag-Erling Smørgrav goto copy_error;
8644a421b63SDag-Erling Smørgrav memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
8654a421b63SDag-Erling Smørgrav sizeof(*sb));
8664a421b63SDag-Erling Smørgrav }
8674a421b63SDag-Erling Smørgrav statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
8684a421b63SDag-Erling Smørgrav }
8694a421b63SDag-Erling Smørgrav
87083d2307dSDag-Erling Smørgrav for (p = path; *p++;)
87183d2307dSDag-Erling Smørgrav ;
87283d2307dSDag-Erling Smørgrav len = (size_t)(p - path);
8734a421b63SDag-Erling Smørgrav limitp->glim_malloc += len;
87483d2307dSDag-Erling Smørgrav if ((copy = malloc(len)) != NULL) {
87583d2307dSDag-Erling Smørgrav if (g_Ctoc(path, copy, len)) {
87683d2307dSDag-Erling Smørgrav free(copy);
87783d2307dSDag-Erling Smørgrav return(GLOB_NOSPACE);
87883d2307dSDag-Erling Smørgrav }
87983d2307dSDag-Erling Smørgrav pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
88083d2307dSDag-Erling Smørgrav }
88183d2307dSDag-Erling Smørgrav pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
88283d2307dSDag-Erling Smørgrav
88383d2307dSDag-Erling Smørgrav if ((pglob->gl_flags & GLOB_LIMIT) &&
8844a421b63SDag-Erling Smørgrav (newn * sizeof(*pathv)) + limitp->glim_malloc >
8854a421b63SDag-Erling Smørgrav GLOB_LIMIT_MALLOC) {
88683d2307dSDag-Erling Smørgrav errno = 0;
88783d2307dSDag-Erling Smørgrav return(GLOB_NOSPACE);
88883d2307dSDag-Erling Smørgrav }
8894a421b63SDag-Erling Smørgrav copy_error:
89083d2307dSDag-Erling Smørgrav return(copy == NULL ? GLOB_NOSPACE : 0);
89183d2307dSDag-Erling Smørgrav }
89283d2307dSDag-Erling Smørgrav
89383d2307dSDag-Erling Smørgrav
89483d2307dSDag-Erling Smørgrav /*
89583d2307dSDag-Erling Smørgrav * pattern matching function for filenames. Each occurrence of the *
896*19261079SEd Maste * pattern causes an iteration.
897*19261079SEd Maste *
898*19261079SEd Maste * Note, this function differs from the original as per the discussion
899*19261079SEd Maste * here: https://research.swtch.com/glob
900*19261079SEd Maste *
901*19261079SEd Maste * Basically we removed the recursion and made it use the algorithm
902*19261079SEd Maste * from Russ Cox to not go quadratic on cases like a file called
903*19261079SEd Maste * ("a" x 100) . "x" matched against a pattern like "a*a*a*a*a*a*a*y".
90483d2307dSDag-Erling Smørgrav */
90583d2307dSDag-Erling Smørgrav static int
906*19261079SEd Maste match(Char *name, Char *pat, Char *patend)
90783d2307dSDag-Erling Smørgrav {
90883d2307dSDag-Erling Smørgrav int ok, negate_range;
90983d2307dSDag-Erling Smørgrav Char c, k;
910*19261079SEd Maste Char *nextp = NULL;
911*19261079SEd Maste Char *nextn = NULL;
91283d2307dSDag-Erling Smørgrav
913*19261079SEd Maste loop:
91483d2307dSDag-Erling Smørgrav while (pat < patend) {
91583d2307dSDag-Erling Smørgrav c = *pat++;
91683d2307dSDag-Erling Smørgrav switch (c & M_MASK) {
91783d2307dSDag-Erling Smørgrav case M_ALL:
918462c32cbSDag-Erling Smørgrav while (pat < patend && (*pat & M_MASK) == M_ALL)
919462c32cbSDag-Erling Smørgrav pat++; /* eat consecutive '*' */
92083d2307dSDag-Erling Smørgrav if (pat == patend)
92183d2307dSDag-Erling Smørgrav return(1);
922*19261079SEd Maste if (*name == EOS)
92383d2307dSDag-Erling Smørgrav return(0);
924*19261079SEd Maste nextn = name + 1;
925*19261079SEd Maste nextp = pat - 1;
926*19261079SEd Maste break;
92783d2307dSDag-Erling Smørgrav case M_ONE:
92883d2307dSDag-Erling Smørgrav if (*name++ == EOS)
929*19261079SEd Maste goto fail;
93083d2307dSDag-Erling Smørgrav break;
93183d2307dSDag-Erling Smørgrav case M_SET:
93283d2307dSDag-Erling Smørgrav ok = 0;
93383d2307dSDag-Erling Smørgrav if ((k = *name++) == EOS)
934*19261079SEd Maste goto fail;
93583d2307dSDag-Erling Smørgrav if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
93683d2307dSDag-Erling Smørgrav ++pat;
9374a421b63SDag-Erling Smørgrav while (((c = *pat++) & M_MASK) != M_END) {
9384a421b63SDag-Erling Smørgrav if ((c & M_MASK) == M_CLASS) {
9394a421b63SDag-Erling Smørgrav Char idx = *pat & M_MASK;
9404a421b63SDag-Erling Smørgrav if (idx < NCCLASSES &&
9414a421b63SDag-Erling Smørgrav cclasses[idx].isctype(k))
9424a421b63SDag-Erling Smørgrav ok = 1;
9434a421b63SDag-Erling Smørgrav ++pat;
9444a421b63SDag-Erling Smørgrav }
94583d2307dSDag-Erling Smørgrav if ((*pat & M_MASK) == M_RNG) {
94683d2307dSDag-Erling Smørgrav if (c <= k && k <= pat[1])
94783d2307dSDag-Erling Smørgrav ok = 1;
94883d2307dSDag-Erling Smørgrav pat += 2;
94983d2307dSDag-Erling Smørgrav } else if (c == k)
95083d2307dSDag-Erling Smørgrav ok = 1;
9514a421b63SDag-Erling Smørgrav }
95283d2307dSDag-Erling Smørgrav if (ok == negate_range)
953*19261079SEd Maste goto fail;
95483d2307dSDag-Erling Smørgrav break;
95583d2307dSDag-Erling Smørgrav default:
95683d2307dSDag-Erling Smørgrav if (*name++ != c)
957*19261079SEd Maste goto fail;
95883d2307dSDag-Erling Smørgrav break;
95983d2307dSDag-Erling Smørgrav }
96083d2307dSDag-Erling Smørgrav }
961*19261079SEd Maste if (*name == EOS)
962*19261079SEd Maste return(1);
963*19261079SEd Maste
964*19261079SEd Maste fail:
965*19261079SEd Maste if (nextn) {
966*19261079SEd Maste pat = nextp;
967*19261079SEd Maste name = nextn;
968*19261079SEd Maste goto loop;
969*19261079SEd Maste }
970*19261079SEd Maste return(0);
97183d2307dSDag-Erling Smørgrav }
97283d2307dSDag-Erling Smørgrav
97383d2307dSDag-Erling Smørgrav /* Free allocated data belonging to a glob_t structure. */
97483d2307dSDag-Erling Smørgrav void
975021d409fSDag-Erling Smørgrav globfree(glob_t *pglob)
97683d2307dSDag-Erling Smørgrav {
977*19261079SEd Maste size_t i;
978021d409fSDag-Erling Smørgrav char **pp;
97983d2307dSDag-Erling Smørgrav
98083d2307dSDag-Erling Smørgrav if (pglob->gl_pathv != NULL) {
98183d2307dSDag-Erling Smørgrav pp = pglob->gl_pathv + pglob->gl_offs;
98283d2307dSDag-Erling Smørgrav for (i = pglob->gl_pathc; i--; ++pp)
98383d2307dSDag-Erling Smørgrav free(*pp);
98483d2307dSDag-Erling Smørgrav free(pglob->gl_pathv);
98583d2307dSDag-Erling Smørgrav pglob->gl_pathv = NULL;
98683d2307dSDag-Erling Smørgrav }
9874a421b63SDag-Erling Smørgrav if (pglob->gl_statv != NULL) {
9884a421b63SDag-Erling Smørgrav for (i = 0; i < pglob->gl_pathc; i++) {
9894a421b63SDag-Erling Smørgrav free(pglob->gl_statv[i]);
9904a421b63SDag-Erling Smørgrav }
9914a421b63SDag-Erling Smørgrav free(pglob->gl_statv);
9924a421b63SDag-Erling Smørgrav pglob->gl_statv = NULL;
9934a421b63SDag-Erling Smørgrav }
99483d2307dSDag-Erling Smørgrav }
99583d2307dSDag-Erling Smørgrav
99683d2307dSDag-Erling Smørgrav static DIR *
997021d409fSDag-Erling Smørgrav g_opendir(Char *str, glob_t *pglob)
99883d2307dSDag-Erling Smørgrav {
999*19261079SEd Maste char buf[PATH_MAX];
100083d2307dSDag-Erling Smørgrav
100183d2307dSDag-Erling Smørgrav if (!*str)
10024b17dab0SDag-Erling Smørgrav strlcpy(buf, ".", sizeof buf);
100383d2307dSDag-Erling Smørgrav else {
100483d2307dSDag-Erling Smørgrav if (g_Ctoc(str, buf, sizeof(buf)))
100583d2307dSDag-Erling Smørgrav return(NULL);
100683d2307dSDag-Erling Smørgrav }
100783d2307dSDag-Erling Smørgrav
100883d2307dSDag-Erling Smørgrav if (pglob->gl_flags & GLOB_ALTDIRFUNC)
100983d2307dSDag-Erling Smørgrav return((*pglob->gl_opendir)(buf));
101083d2307dSDag-Erling Smørgrav
101183d2307dSDag-Erling Smørgrav return(opendir(buf));
101283d2307dSDag-Erling Smørgrav }
101383d2307dSDag-Erling Smørgrav
101483d2307dSDag-Erling Smørgrav static int
1015021d409fSDag-Erling Smørgrav g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
101683d2307dSDag-Erling Smørgrav {
1017*19261079SEd Maste char buf[PATH_MAX];
101883d2307dSDag-Erling Smørgrav
101983d2307dSDag-Erling Smørgrav if (g_Ctoc(fn, buf, sizeof(buf)))
102083d2307dSDag-Erling Smørgrav return(-1);
102183d2307dSDag-Erling Smørgrav if (pglob->gl_flags & GLOB_ALTDIRFUNC)
102283d2307dSDag-Erling Smørgrav return((*pglob->gl_lstat)(buf, sb));
102383d2307dSDag-Erling Smørgrav return(lstat(buf, sb));
102483d2307dSDag-Erling Smørgrav }
102583d2307dSDag-Erling Smørgrav
102683d2307dSDag-Erling Smørgrav static int
1027021d409fSDag-Erling Smørgrav g_stat(Char *fn, struct stat *sb, glob_t *pglob)
102883d2307dSDag-Erling Smørgrav {
1029*19261079SEd Maste char buf[PATH_MAX];
103083d2307dSDag-Erling Smørgrav
103183d2307dSDag-Erling Smørgrav if (g_Ctoc(fn, buf, sizeof(buf)))
103283d2307dSDag-Erling Smørgrav return(-1);
103383d2307dSDag-Erling Smørgrav if (pglob->gl_flags & GLOB_ALTDIRFUNC)
103483d2307dSDag-Erling Smørgrav return((*pglob->gl_stat)(buf, sb));
103583d2307dSDag-Erling Smørgrav return(stat(buf, sb));
103683d2307dSDag-Erling Smørgrav }
103783d2307dSDag-Erling Smørgrav
103883d2307dSDag-Erling Smørgrav static Char *
10394a421b63SDag-Erling Smørgrav g_strchr(const Char *str, int ch)
104083d2307dSDag-Erling Smørgrav {
104183d2307dSDag-Erling Smørgrav do {
104283d2307dSDag-Erling Smørgrav if (*str == ch)
10434a421b63SDag-Erling Smørgrav return ((Char *)str);
104483d2307dSDag-Erling Smørgrav } while (*str++);
104583d2307dSDag-Erling Smørgrav return (NULL);
104683d2307dSDag-Erling Smørgrav }
104783d2307dSDag-Erling Smørgrav
104883d2307dSDag-Erling Smørgrav static int
1049*19261079SEd Maste g_Ctoc(const Char *str, char *buf, size_t len)
105083d2307dSDag-Erling Smørgrav {
105183d2307dSDag-Erling Smørgrav
105283d2307dSDag-Erling Smørgrav while (len--) {
105383d2307dSDag-Erling Smørgrav if ((*buf++ = *str++) == EOS)
105483d2307dSDag-Erling Smørgrav return (0);
105583d2307dSDag-Erling Smørgrav }
105683d2307dSDag-Erling Smørgrav return (1);
105783d2307dSDag-Erling Smørgrav }
105883d2307dSDag-Erling Smørgrav
105983d2307dSDag-Erling Smørgrav #ifdef DEBUG
106083d2307dSDag-Erling Smørgrav static void
1061021d409fSDag-Erling Smørgrav qprintf(const char *str, Char *s)
106283d2307dSDag-Erling Smørgrav {
1063021d409fSDag-Erling Smørgrav Char *p;
106483d2307dSDag-Erling Smørgrav
106583d2307dSDag-Erling Smørgrav (void)printf("%s:\n", str);
106683d2307dSDag-Erling Smørgrav for (p = s; *p; p++)
106783d2307dSDag-Erling Smørgrav (void)printf("%c", CHAR(*p));
106883d2307dSDag-Erling Smørgrav (void)printf("\n");
106983d2307dSDag-Erling Smørgrav for (p = s; *p; p++)
107083d2307dSDag-Erling Smørgrav (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
107183d2307dSDag-Erling Smørgrav (void)printf("\n");
107283d2307dSDag-Erling Smørgrav for (p = s; *p; p++)
107383d2307dSDag-Erling Smørgrav (void)printf("%c", ismeta(*p) ? '_' : ' ');
107483d2307dSDag-Erling Smørgrav (void)printf("\n");
107583d2307dSDag-Erling Smørgrav }
107683d2307dSDag-Erling Smørgrav #endif
107783d2307dSDag-Erling Smørgrav
107883d2307dSDag-Erling Smørgrav #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
10794a421b63SDag-Erling Smørgrav !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) */
1080