xref: /freebsd/crypto/openssh/openbsd-compat/glob.c (revision 4a421b6336e5e0c2ff27024c30fe32c6f71dcf3d)
1*4a421b63SDag-Erling Smørgrav /*	$OpenBSD: glob.c,v 1.35 2011/01/12 01:53:14 djm 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 
61*4a421b63SDag-Erling Smørgrav #include "includes.h"
62*4a421b63SDag-Erling Smørgrav 
63*4a421b63SDag-Erling Smørgrav #include <sys/types.h>
64*4a421b63SDag-Erling Smørgrav #include <sys/stat.h>
65*4a421b63SDag-Erling Smørgrav 
66*4a421b63SDag-Erling Smørgrav #include <dirent.h>
67*4a421b63SDag-Erling Smørgrav #include <ctype.h>
68*4a421b63SDag-Erling Smørgrav #include <errno.h>
69*4a421b63SDag-Erling Smørgrav #include <pwd.h>
70*4a421b63SDag-Erling Smørgrav #include <stdlib.h>
71*4a421b63SDag-Erling Smørgrav #include <string.h>
72*4a421b63SDag-Erling Smørgrav #include <unistd.h>
73*4a421b63SDag-Erling Smørgrav 
74*4a421b63SDag-Erling Smørgrav #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
75*4a421b63SDag-Erling Smørgrav     !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
76*4a421b63SDag-Erling Smørgrav     !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
77*4a421b63SDag-Erling Smørgrav     defined(BROKEN_GLOB)
78*4a421b63SDag-Erling Smørgrav 
79*4a421b63SDag-Erling Smørgrav #include "charclass.h"
8083d2307dSDag-Erling Smørgrav 
8183d2307dSDag-Erling Smørgrav #define	DOLLAR		'$'
8283d2307dSDag-Erling Smørgrav #define	DOT		'.'
8383d2307dSDag-Erling Smørgrav #define	EOS		'\0'
8483d2307dSDag-Erling Smørgrav #define	LBRACKET	'['
8583d2307dSDag-Erling Smørgrav #define	NOT		'!'
8683d2307dSDag-Erling Smørgrav #define	QUESTION	'?'
8783d2307dSDag-Erling Smørgrav #define	QUOTE		'\\'
8883d2307dSDag-Erling Smørgrav #define	RANGE		'-'
8983d2307dSDag-Erling Smørgrav #define	RBRACKET	']'
9083d2307dSDag-Erling Smørgrav #define	SEP		'/'
9183d2307dSDag-Erling Smørgrav #define	STAR		'*'
9283d2307dSDag-Erling Smørgrav #define	TILDE		'~'
9383d2307dSDag-Erling Smørgrav #define	UNDERSCORE	'_'
9483d2307dSDag-Erling Smørgrav #define	LBRACE		'{'
9583d2307dSDag-Erling Smørgrav #define	RBRACE		'}'
9683d2307dSDag-Erling Smørgrav #define	SLASH		'/'
9783d2307dSDag-Erling Smørgrav #define	COMMA		','
9883d2307dSDag-Erling Smørgrav 
9983d2307dSDag-Erling Smørgrav #ifndef DEBUG
10083d2307dSDag-Erling Smørgrav 
10183d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x8000
10283d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x4000
10383d2307dSDag-Erling Smørgrav #define	M_MASK		0xffff
10483d2307dSDag-Erling Smørgrav #define	M_ASCII		0x00ff
10583d2307dSDag-Erling Smørgrav 
10683d2307dSDag-Erling Smørgrav typedef u_short Char;
10783d2307dSDag-Erling Smørgrav 
10883d2307dSDag-Erling Smørgrav #else
10983d2307dSDag-Erling Smørgrav 
11083d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x80
11183d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x40
11283d2307dSDag-Erling Smørgrav #define	M_MASK		0xff
11383d2307dSDag-Erling Smørgrav #define	M_ASCII		0x7f
11483d2307dSDag-Erling Smørgrav 
11583d2307dSDag-Erling Smørgrav typedef char Char;
11683d2307dSDag-Erling Smørgrav 
11783d2307dSDag-Erling Smørgrav #endif
11883d2307dSDag-Erling Smørgrav 
11983d2307dSDag-Erling Smørgrav 
12083d2307dSDag-Erling Smørgrav #define	CHAR(c)		((Char)((c)&M_ASCII))
12183d2307dSDag-Erling Smørgrav #define	META(c)		((Char)((c)|M_QUOTE))
12283d2307dSDag-Erling Smørgrav #define	M_ALL		META('*')
12383d2307dSDag-Erling Smørgrav #define	M_END		META(']')
12483d2307dSDag-Erling Smørgrav #define	M_NOT		META('!')
12583d2307dSDag-Erling Smørgrav #define	M_ONE		META('?')
12683d2307dSDag-Erling Smørgrav #define	M_RNG		META('-')
12783d2307dSDag-Erling Smørgrav #define	M_SET		META('[')
128*4a421b63SDag-Erling Smørgrav #define	M_CLASS		META(':')
12983d2307dSDag-Erling Smørgrav #define	ismeta(c)	(((c)&M_QUOTE) != 0)
13083d2307dSDag-Erling Smørgrav 
131*4a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_MALLOC	65536
132*4a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_STAT		128
133*4a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_READDIR	16384
134*4a421b63SDag-Erling Smørgrav 
135*4a421b63SDag-Erling Smørgrav struct glob_lim {
136*4a421b63SDag-Erling Smørgrav 	size_t	glim_malloc;
137*4a421b63SDag-Erling Smørgrav 	size_t	glim_stat;
138*4a421b63SDag-Erling Smørgrav 	size_t	glim_readdir;
139*4a421b63SDag-Erling Smørgrav };
14083d2307dSDag-Erling Smørgrav 
1414b17dab0SDag-Erling Smørgrav static int	 compare(const void *, const void *);
1424b17dab0SDag-Erling Smørgrav static int	 g_Ctoc(const Char *, char *, u_int);
1434b17dab0SDag-Erling Smørgrav static int	 g_lstat(Char *, struct stat *, glob_t *);
1444b17dab0SDag-Erling Smørgrav static DIR	*g_opendir(Char *, glob_t *);
145*4a421b63SDag-Erling Smørgrav static Char	*g_strchr(const Char *, int);
146*4a421b63SDag-Erling Smørgrav static int	 g_strncmp(const Char *, const char *, size_t);
1474b17dab0SDag-Erling Smørgrav static int	 g_stat(Char *, struct stat *, glob_t *);
148*4a421b63SDag-Erling Smørgrav static int	 glob0(const Char *, glob_t *, struct glob_lim *);
149*4a421b63SDag-Erling Smørgrav static int	 glob1(Char *, Char *, glob_t *, struct glob_lim *);
1504b17dab0SDag-Erling Smørgrav static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
151*4a421b63SDag-Erling Smørgrav 		    glob_t *, struct glob_lim *);
152d4af9e69SDag-Erling Smørgrav static int	 glob3(Char *, Char *, Char *, Char *, Char *,
153*4a421b63SDag-Erling Smørgrav 		    Char *, Char *, glob_t *, struct glob_lim *);
154*4a421b63SDag-Erling Smørgrav static int	 globextend(const Char *, glob_t *, struct glob_lim *,
155*4a421b63SDag-Erling Smørgrav 		    struct stat *);
15683d2307dSDag-Erling Smørgrav static const Char *
1574b17dab0SDag-Erling Smørgrav 		 globtilde(const Char *, Char *, size_t, glob_t *);
158*4a421b63SDag-Erling Smørgrav static int	 globexp1(const Char *, glob_t *, struct glob_lim *);
159*4a421b63SDag-Erling Smørgrav static int	 globexp2(const Char *, const Char *, glob_t *,
160*4a421b63SDag-Erling Smørgrav 		    struct glob_lim *);
1614b17dab0SDag-Erling Smørgrav static int	 match(Char *, Char *, Char *);
16283d2307dSDag-Erling Smørgrav #ifdef DEBUG
1634b17dab0SDag-Erling Smørgrav static void	 qprintf(const char *, Char *);
16483d2307dSDag-Erling Smørgrav #endif
16583d2307dSDag-Erling Smørgrav 
16683d2307dSDag-Erling Smørgrav int
167021d409fSDag-Erling Smørgrav glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
168021d409fSDag-Erling Smørgrav     glob_t *pglob)
16983d2307dSDag-Erling Smørgrav {
17083d2307dSDag-Erling Smørgrav 	const u_char *patnext;
17183d2307dSDag-Erling Smørgrav 	int c;
17283d2307dSDag-Erling Smørgrav 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
173*4a421b63SDag-Erling Smørgrav 	struct glob_lim limit = { 0, 0, 0 };
17483d2307dSDag-Erling Smørgrav 
17583d2307dSDag-Erling Smørgrav 	patnext = (u_char *) pattern;
17683d2307dSDag-Erling Smørgrav 	if (!(flags & GLOB_APPEND)) {
17783d2307dSDag-Erling Smørgrav 		pglob->gl_pathc = 0;
17883d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
179*4a421b63SDag-Erling Smørgrav 		pglob->gl_statv = NULL;
18083d2307dSDag-Erling Smørgrav 		if (!(flags & GLOB_DOOFFS))
18183d2307dSDag-Erling Smørgrav 			pglob->gl_offs = 0;
18283d2307dSDag-Erling Smørgrav 	}
18383d2307dSDag-Erling Smørgrav 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
18483d2307dSDag-Erling Smørgrav 	pglob->gl_errfunc = errfunc;
18583d2307dSDag-Erling Smørgrav 	pglob->gl_matchc = 0;
18683d2307dSDag-Erling Smørgrav 
187*4a421b63SDag-Erling Smørgrav 	if (pglob->gl_offs < 0 || pglob->gl_pathc < 0 ||
188*4a421b63SDag-Erling Smørgrav 	    pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
189*4a421b63SDag-Erling Smørgrav 	    pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
190*4a421b63SDag-Erling Smørgrav 		return GLOB_NOSPACE;
191*4a421b63SDag-Erling Smørgrav 
19283d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
19383d2307dSDag-Erling Smørgrav 	bufend = bufnext + MAXPATHLEN - 1;
19483d2307dSDag-Erling Smørgrav 	if (flags & GLOB_NOESCAPE)
19583d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
19683d2307dSDag-Erling Smørgrav 			*bufnext++ = c;
19783d2307dSDag-Erling Smørgrav 	else {
19883d2307dSDag-Erling Smørgrav 		/* Protect the quoted characters. */
19983d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
20083d2307dSDag-Erling Smørgrav 			if (c == QUOTE) {
20183d2307dSDag-Erling Smørgrav 				if ((c = *patnext++) == EOS) {
20283d2307dSDag-Erling Smørgrav 					c = QUOTE;
20383d2307dSDag-Erling Smørgrav 					--patnext;
20483d2307dSDag-Erling Smørgrav 				}
20583d2307dSDag-Erling Smørgrav 				*bufnext++ = c | M_PROTECT;
20683d2307dSDag-Erling Smørgrav 			} else
20783d2307dSDag-Erling Smørgrav 				*bufnext++ = c;
20883d2307dSDag-Erling Smørgrav 	}
20983d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
21083d2307dSDag-Erling Smørgrav 
21183d2307dSDag-Erling Smørgrav 	if (flags & GLOB_BRACE)
212*4a421b63SDag-Erling Smørgrav 		return globexp1(patbuf, pglob, &limit);
21383d2307dSDag-Erling Smørgrav 	else
214*4a421b63SDag-Erling Smørgrav 		return glob0(patbuf, pglob, &limit);
21583d2307dSDag-Erling Smørgrav }
21683d2307dSDag-Erling Smørgrav 
21783d2307dSDag-Erling Smørgrav /*
21883d2307dSDag-Erling Smørgrav  * Expand recursively a glob {} pattern. When there is no more expansion
21983d2307dSDag-Erling Smørgrav  * invoke the standard globbing routine to glob the rest of the magic
22083d2307dSDag-Erling Smørgrav  * characters
22183d2307dSDag-Erling Smørgrav  */
22283d2307dSDag-Erling Smørgrav static int
223*4a421b63SDag-Erling Smørgrav globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
22483d2307dSDag-Erling Smørgrav {
22583d2307dSDag-Erling Smørgrav 	const Char* ptr = pattern;
22683d2307dSDag-Erling Smørgrav 
22783d2307dSDag-Erling Smørgrav 	/* Protect a single {}, for find(1), like csh */
22883d2307dSDag-Erling Smørgrav 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
229*4a421b63SDag-Erling Smørgrav 		return glob0(pattern, pglob, limitp);
23083d2307dSDag-Erling Smørgrav 
231*4a421b63SDag-Erling Smørgrav 	if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
232*4a421b63SDag-Erling Smørgrav 		return globexp2(ptr, pattern, pglob, limitp);
23383d2307dSDag-Erling Smørgrav 
234*4a421b63SDag-Erling Smørgrav 	return glob0(pattern, pglob, limitp);
23583d2307dSDag-Erling Smørgrav }
23683d2307dSDag-Erling Smørgrav 
23783d2307dSDag-Erling Smørgrav 
23883d2307dSDag-Erling Smørgrav /*
23983d2307dSDag-Erling Smørgrav  * Recursive brace globbing helper. Tries to expand a single brace.
24083d2307dSDag-Erling Smørgrav  * If it succeeds then it invokes globexp1 with the new pattern.
24183d2307dSDag-Erling Smørgrav  * If it fails then it tries to glob the rest of the pattern and returns.
24283d2307dSDag-Erling Smørgrav  */
24383d2307dSDag-Erling Smørgrav static int
244*4a421b63SDag-Erling Smørgrav globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
245*4a421b63SDag-Erling Smørgrav     struct glob_lim *limitp)
24683d2307dSDag-Erling Smørgrav {
247*4a421b63SDag-Erling Smørgrav 	int     i, rv;
24883d2307dSDag-Erling Smørgrav 	Char   *lm, *ls;
24983d2307dSDag-Erling Smørgrav 	const Char *pe, *pm, *pl;
25083d2307dSDag-Erling Smørgrav 	Char    patbuf[MAXPATHLEN];
25183d2307dSDag-Erling Smørgrav 
25283d2307dSDag-Erling Smørgrav 	/* copy part up to the brace */
25383d2307dSDag-Erling Smørgrav 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
25483d2307dSDag-Erling Smørgrav 		;
25583d2307dSDag-Erling Smørgrav 	*lm = EOS;
25683d2307dSDag-Erling Smørgrav 	ls = lm;
25783d2307dSDag-Erling Smørgrav 
25883d2307dSDag-Erling Smørgrav 	/* Find the balanced brace */
25983d2307dSDag-Erling Smørgrav 	for (i = 0, pe = ++ptr; *pe; pe++)
26083d2307dSDag-Erling Smørgrav 		if (*pe == LBRACKET) {
26183d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
26283d2307dSDag-Erling Smørgrav 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
26383d2307dSDag-Erling Smørgrav 				;
26483d2307dSDag-Erling Smørgrav 			if (*pe == EOS) {
26583d2307dSDag-Erling Smørgrav 				/*
26683d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
26783d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
26883d2307dSDag-Erling Smørgrav 				 */
26983d2307dSDag-Erling Smørgrav 				pe = pm;
27083d2307dSDag-Erling Smørgrav 			}
27183d2307dSDag-Erling Smørgrav 		} else if (*pe == LBRACE)
27283d2307dSDag-Erling Smørgrav 			i++;
27383d2307dSDag-Erling Smørgrav 		else if (*pe == RBRACE) {
27483d2307dSDag-Erling Smørgrav 			if (i == 0)
27583d2307dSDag-Erling Smørgrav 				break;
27683d2307dSDag-Erling Smørgrav 			i--;
27783d2307dSDag-Erling Smørgrav 		}
27883d2307dSDag-Erling Smørgrav 
27983d2307dSDag-Erling Smørgrav 	/* Non matching braces; just glob the pattern */
280*4a421b63SDag-Erling Smørgrav 	if (i != 0 || *pe == EOS)
281*4a421b63SDag-Erling Smørgrav 		return glob0(patbuf, pglob, limitp);
28283d2307dSDag-Erling Smørgrav 
28383d2307dSDag-Erling Smørgrav 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
28483d2307dSDag-Erling Smørgrav 		switch (*pm) {
28583d2307dSDag-Erling Smørgrav 		case LBRACKET:
28683d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
28783d2307dSDag-Erling Smørgrav 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
28883d2307dSDag-Erling Smørgrav 				;
28983d2307dSDag-Erling Smørgrav 			if (*pm == EOS) {
29083d2307dSDag-Erling Smørgrav 				/*
29183d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
29283d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
29383d2307dSDag-Erling Smørgrav 				 */
29483d2307dSDag-Erling Smørgrav 				pm = pl;
29583d2307dSDag-Erling Smørgrav 			}
29683d2307dSDag-Erling Smørgrav 			break;
29783d2307dSDag-Erling Smørgrav 
29883d2307dSDag-Erling Smørgrav 		case LBRACE:
29983d2307dSDag-Erling Smørgrav 			i++;
30083d2307dSDag-Erling Smørgrav 			break;
30183d2307dSDag-Erling Smørgrav 
30283d2307dSDag-Erling Smørgrav 		case RBRACE:
30383d2307dSDag-Erling Smørgrav 			if (i) {
30483d2307dSDag-Erling Smørgrav 				i--;
30583d2307dSDag-Erling Smørgrav 				break;
30683d2307dSDag-Erling Smørgrav 			}
30783d2307dSDag-Erling Smørgrav 			/* FALLTHROUGH */
30883d2307dSDag-Erling Smørgrav 		case COMMA:
30983d2307dSDag-Erling Smørgrav 			if (i && *pm == COMMA)
31083d2307dSDag-Erling Smørgrav 				break;
31183d2307dSDag-Erling Smørgrav 			else {
31283d2307dSDag-Erling Smørgrav 				/* Append the current string */
31383d2307dSDag-Erling Smørgrav 				for (lm = ls; (pl < pm); *lm++ = *pl++)
31483d2307dSDag-Erling Smørgrav 					;
31583d2307dSDag-Erling Smørgrav 
31683d2307dSDag-Erling Smørgrav 				/*
31783d2307dSDag-Erling Smørgrav 				 * Append the rest of the pattern after the
31883d2307dSDag-Erling Smørgrav 				 * closing brace
31983d2307dSDag-Erling Smørgrav 				 */
32083d2307dSDag-Erling Smørgrav 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
32183d2307dSDag-Erling Smørgrav 					;
32283d2307dSDag-Erling Smørgrav 
32383d2307dSDag-Erling Smørgrav 				/* Expand the current pattern */
32483d2307dSDag-Erling Smørgrav #ifdef DEBUG
32583d2307dSDag-Erling Smørgrav 				qprintf("globexp2:", patbuf);
32683d2307dSDag-Erling Smørgrav #endif
327*4a421b63SDag-Erling Smørgrav 				rv = globexp1(patbuf, pglob, limitp);
328*4a421b63SDag-Erling Smørgrav 				if (rv && rv != GLOB_NOMATCH)
329*4a421b63SDag-Erling Smørgrav 					return rv;
33083d2307dSDag-Erling Smørgrav 
33183d2307dSDag-Erling Smørgrav 				/* move after the comma, to the next string */
33283d2307dSDag-Erling Smørgrav 				pl = pm + 1;
33383d2307dSDag-Erling Smørgrav 			}
33483d2307dSDag-Erling Smørgrav 			break;
33583d2307dSDag-Erling Smørgrav 
33683d2307dSDag-Erling Smørgrav 		default:
33783d2307dSDag-Erling Smørgrav 			break;
33883d2307dSDag-Erling Smørgrav 		}
33983d2307dSDag-Erling Smørgrav 	}
34083d2307dSDag-Erling Smørgrav 	return 0;
34183d2307dSDag-Erling Smørgrav }
34283d2307dSDag-Erling Smørgrav 
34383d2307dSDag-Erling Smørgrav 
34483d2307dSDag-Erling Smørgrav 
34583d2307dSDag-Erling Smørgrav /*
34683d2307dSDag-Erling Smørgrav  * expand tilde from the passwd file.
34783d2307dSDag-Erling Smørgrav  */
34883d2307dSDag-Erling Smørgrav static const Char *
349021d409fSDag-Erling Smørgrav globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
35083d2307dSDag-Erling Smørgrav {
35183d2307dSDag-Erling Smørgrav 	struct passwd *pwd;
35283d2307dSDag-Erling Smørgrav 	char *h;
35383d2307dSDag-Erling Smørgrav 	const Char *p;
35483d2307dSDag-Erling Smørgrav 	Char *b, *eb;
35583d2307dSDag-Erling Smørgrav 
35683d2307dSDag-Erling Smørgrav 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
35783d2307dSDag-Erling Smørgrav 		return pattern;
35883d2307dSDag-Erling Smørgrav 
35983d2307dSDag-Erling Smørgrav 	/* Copy up to the end of the string or / */
36083d2307dSDag-Erling Smørgrav 	eb = &patbuf[patbuf_len - 1];
36183d2307dSDag-Erling Smørgrav 	for (p = pattern + 1, h = (char *) patbuf;
36283d2307dSDag-Erling Smørgrav 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
36383d2307dSDag-Erling Smørgrav 		;
36483d2307dSDag-Erling Smørgrav 
36583d2307dSDag-Erling Smørgrav 	*h = EOS;
36683d2307dSDag-Erling Smørgrav 
36783d2307dSDag-Erling Smørgrav #if 0
36883d2307dSDag-Erling Smørgrav 	if (h == (char *)eb)
36983d2307dSDag-Erling Smørgrav 		return what;
37083d2307dSDag-Erling Smørgrav #endif
37183d2307dSDag-Erling Smørgrav 
37283d2307dSDag-Erling Smørgrav 	if (((char *) patbuf)[0] == EOS) {
37383d2307dSDag-Erling Smørgrav 		/*
37483d2307dSDag-Erling Smørgrav 		 * handle a plain ~ or ~/ by expanding $HOME
37583d2307dSDag-Erling Smørgrav 		 * first and then trying the password file
37683d2307dSDag-Erling Smørgrav 		 */
37783d2307dSDag-Erling Smørgrav #if 0
37883d2307dSDag-Erling Smørgrav 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
37983d2307dSDag-Erling Smørgrav #endif
38083d2307dSDag-Erling Smørgrav 		if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
38183d2307dSDag-Erling Smørgrav 			if ((pwd = getpwuid(getuid())) == NULL)
38283d2307dSDag-Erling Smørgrav 				return pattern;
38383d2307dSDag-Erling Smørgrav 			else
38483d2307dSDag-Erling Smørgrav 				h = pwd->pw_dir;
38583d2307dSDag-Erling Smørgrav 		}
38683d2307dSDag-Erling Smørgrav 	} else {
38783d2307dSDag-Erling Smørgrav 		/*
38883d2307dSDag-Erling Smørgrav 		 * Expand a ~user
38983d2307dSDag-Erling Smørgrav 		 */
39083d2307dSDag-Erling Smørgrav 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
39183d2307dSDag-Erling Smørgrav 			return pattern;
39283d2307dSDag-Erling Smørgrav 		else
39383d2307dSDag-Erling Smørgrav 			h = pwd->pw_dir;
39483d2307dSDag-Erling Smørgrav 	}
39583d2307dSDag-Erling Smørgrav 
39683d2307dSDag-Erling Smørgrav 	/* Copy the home directory */
39783d2307dSDag-Erling Smørgrav 	for (b = patbuf; b < eb && *h; *b++ = *h++)
39883d2307dSDag-Erling Smørgrav 		;
39983d2307dSDag-Erling Smørgrav 
40083d2307dSDag-Erling Smørgrav 	/* Append the rest of the pattern */
40183d2307dSDag-Erling Smørgrav 	while (b < eb && (*b++ = *p++) != EOS)
40283d2307dSDag-Erling Smørgrav 		;
40383d2307dSDag-Erling Smørgrav 	*b = EOS;
40483d2307dSDag-Erling Smørgrav 
40583d2307dSDag-Erling Smørgrav 	return patbuf;
40683d2307dSDag-Erling Smørgrav }
40783d2307dSDag-Erling Smørgrav 
408*4a421b63SDag-Erling Smørgrav static int
409*4a421b63SDag-Erling Smørgrav g_strncmp(const Char *s1, const char *s2, size_t n)
410*4a421b63SDag-Erling Smørgrav {
411*4a421b63SDag-Erling Smørgrav 	int rv = 0;
412*4a421b63SDag-Erling Smørgrav 
413*4a421b63SDag-Erling Smørgrav 	while (n--) {
414*4a421b63SDag-Erling Smørgrav 		rv = *(Char *)s1 - *(const unsigned char *)s2++;
415*4a421b63SDag-Erling Smørgrav 		if (rv)
416*4a421b63SDag-Erling Smørgrav 			break;
417*4a421b63SDag-Erling Smørgrav 		if (*s1++ == '\0')
418*4a421b63SDag-Erling Smørgrav 			break;
419*4a421b63SDag-Erling Smørgrav 	}
420*4a421b63SDag-Erling Smørgrav 	return rv;
421*4a421b63SDag-Erling Smørgrav }
422*4a421b63SDag-Erling Smørgrav 
423*4a421b63SDag-Erling Smørgrav static int
424*4a421b63SDag-Erling Smørgrav g_charclass(const Char **patternp, Char **bufnextp)
425*4a421b63SDag-Erling Smørgrav {
426*4a421b63SDag-Erling Smørgrav 	const Char *pattern = *patternp + 1;
427*4a421b63SDag-Erling Smørgrav 	Char *bufnext = *bufnextp;
428*4a421b63SDag-Erling Smørgrav 	const Char *colon;
429*4a421b63SDag-Erling Smørgrav 	struct cclass *cc;
430*4a421b63SDag-Erling Smørgrav 	size_t len;
431*4a421b63SDag-Erling Smørgrav 
432*4a421b63SDag-Erling Smørgrav 	if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
433*4a421b63SDag-Erling Smørgrav 		return 1;	/* not a character class */
434*4a421b63SDag-Erling Smørgrav 
435*4a421b63SDag-Erling Smørgrav 	len = (size_t)(colon - pattern);
436*4a421b63SDag-Erling Smørgrav 	for (cc = cclasses; cc->name != NULL; cc++) {
437*4a421b63SDag-Erling Smørgrav 		if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
438*4a421b63SDag-Erling Smørgrav 			break;
439*4a421b63SDag-Erling Smørgrav 	}
440*4a421b63SDag-Erling Smørgrav 	if (cc->name == NULL)
441*4a421b63SDag-Erling Smørgrav 		return -1;	/* invalid character class */
442*4a421b63SDag-Erling Smørgrav 	*bufnext++ = M_CLASS;
443*4a421b63SDag-Erling Smørgrav 	*bufnext++ = (Char)(cc - &cclasses[0]);
444*4a421b63SDag-Erling Smørgrav 	*bufnextp = bufnext;
445*4a421b63SDag-Erling Smørgrav 	*patternp += len + 3;
446*4a421b63SDag-Erling Smørgrav 
447*4a421b63SDag-Erling Smørgrav 	return 0;
448*4a421b63SDag-Erling Smørgrav }
44983d2307dSDag-Erling Smørgrav 
45083d2307dSDag-Erling Smørgrav /*
45183d2307dSDag-Erling Smørgrav  * The main glob() routine: compiles the pattern (optionally processing
45283d2307dSDag-Erling Smørgrav  * quotes), calls glob1() to do the real pattern matching, and finally
45383d2307dSDag-Erling Smørgrav  * sorts the list (unless unsorted operation is requested).  Returns 0
45483d2307dSDag-Erling Smørgrav  * if things went well, nonzero if errors occurred.  It is not an error
45583d2307dSDag-Erling Smørgrav  * to find no matches.
45683d2307dSDag-Erling Smørgrav  */
45783d2307dSDag-Erling Smørgrav static int
458*4a421b63SDag-Erling Smørgrav glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
45983d2307dSDag-Erling Smørgrav {
46083d2307dSDag-Erling Smørgrav 	const Char *qpatnext;
46183d2307dSDag-Erling Smørgrav 	int c, err, oldpathc;
46283d2307dSDag-Erling Smørgrav 	Char *bufnext, patbuf[MAXPATHLEN];
46383d2307dSDag-Erling Smørgrav 
46483d2307dSDag-Erling Smørgrav 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
46583d2307dSDag-Erling Smørgrav 	oldpathc = pglob->gl_pathc;
46683d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
46783d2307dSDag-Erling Smørgrav 
46883d2307dSDag-Erling Smørgrav 	/* We don't need to check for buffer overflow any more. */
46983d2307dSDag-Erling Smørgrav 	while ((c = *qpatnext++) != EOS) {
47083d2307dSDag-Erling Smørgrav 		switch (c) {
47183d2307dSDag-Erling Smørgrav 		case LBRACKET:
47283d2307dSDag-Erling Smørgrav 			c = *qpatnext;
47383d2307dSDag-Erling Smørgrav 			if (c == NOT)
47483d2307dSDag-Erling Smørgrav 				++qpatnext;
47583d2307dSDag-Erling Smørgrav 			if (*qpatnext == EOS ||
476*4a421b63SDag-Erling Smørgrav 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
47783d2307dSDag-Erling Smørgrav 				*bufnext++ = LBRACKET;
47883d2307dSDag-Erling Smørgrav 				if (c == NOT)
47983d2307dSDag-Erling Smørgrav 					--qpatnext;
48083d2307dSDag-Erling Smørgrav 				break;
48183d2307dSDag-Erling Smørgrav 			}
48283d2307dSDag-Erling Smørgrav 			*bufnext++ = M_SET;
48383d2307dSDag-Erling Smørgrav 			if (c == NOT)
48483d2307dSDag-Erling Smørgrav 				*bufnext++ = M_NOT;
48583d2307dSDag-Erling Smørgrav 			c = *qpatnext++;
48683d2307dSDag-Erling Smørgrav 			do {
487*4a421b63SDag-Erling Smørgrav 				if (c == LBRACKET && *qpatnext == ':') {
488*4a421b63SDag-Erling Smørgrav 					do {
489*4a421b63SDag-Erling Smørgrav 						err = g_charclass(&qpatnext,
490*4a421b63SDag-Erling Smørgrav 						    &bufnext);
491*4a421b63SDag-Erling Smørgrav 						if (err)
492*4a421b63SDag-Erling Smørgrav 							break;
493*4a421b63SDag-Erling Smørgrav 						c = *qpatnext++;
494*4a421b63SDag-Erling Smørgrav 					} while (c == LBRACKET && *qpatnext == ':');
495*4a421b63SDag-Erling Smørgrav 					if (err == -1 &&
496*4a421b63SDag-Erling Smørgrav 					    !(pglob->gl_flags & GLOB_NOCHECK))
497*4a421b63SDag-Erling Smørgrav 						return GLOB_NOMATCH;
498*4a421b63SDag-Erling Smørgrav 					if (c == RBRACKET)
499*4a421b63SDag-Erling Smørgrav 						break;
500*4a421b63SDag-Erling Smørgrav 				}
50183d2307dSDag-Erling Smørgrav 				*bufnext++ = CHAR(c);
50283d2307dSDag-Erling Smørgrav 				if (*qpatnext == RANGE &&
50383d2307dSDag-Erling Smørgrav 				    (c = qpatnext[1]) != RBRACKET) {
50483d2307dSDag-Erling Smørgrav 					*bufnext++ = M_RNG;
50583d2307dSDag-Erling Smørgrav 					*bufnext++ = CHAR(c);
50683d2307dSDag-Erling Smørgrav 					qpatnext += 2;
50783d2307dSDag-Erling Smørgrav 				}
50883d2307dSDag-Erling Smørgrav 			} while ((c = *qpatnext++) != RBRACKET);
50983d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
51083d2307dSDag-Erling Smørgrav 			*bufnext++ = M_END;
51183d2307dSDag-Erling Smørgrav 			break;
51283d2307dSDag-Erling Smørgrav 		case QUESTION:
51383d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
51483d2307dSDag-Erling Smørgrav 			*bufnext++ = M_ONE;
51583d2307dSDag-Erling Smørgrav 			break;
51683d2307dSDag-Erling Smørgrav 		case STAR:
51783d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
51883d2307dSDag-Erling Smørgrav 			/* collapse adjacent stars to one,
51983d2307dSDag-Erling Smørgrav 			 * to avoid exponential behavior
52083d2307dSDag-Erling Smørgrav 			 */
52183d2307dSDag-Erling Smørgrav 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
52283d2307dSDag-Erling Smørgrav 				*bufnext++ = M_ALL;
52383d2307dSDag-Erling Smørgrav 			break;
52483d2307dSDag-Erling Smørgrav 		default:
52583d2307dSDag-Erling Smørgrav 			*bufnext++ = CHAR(c);
52683d2307dSDag-Erling Smørgrav 			break;
52783d2307dSDag-Erling Smørgrav 		}
52883d2307dSDag-Erling Smørgrav 	}
52983d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
53083d2307dSDag-Erling Smørgrav #ifdef DEBUG
53183d2307dSDag-Erling Smørgrav 	qprintf("glob0:", patbuf);
53283d2307dSDag-Erling Smørgrav #endif
53383d2307dSDag-Erling Smørgrav 
534*4a421b63SDag-Erling Smørgrav 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp)) != 0)
53583d2307dSDag-Erling Smørgrav 		return(err);
53683d2307dSDag-Erling Smørgrav 
53783d2307dSDag-Erling Smørgrav 	/*
53883d2307dSDag-Erling Smørgrav 	 * If there was no match we are going to append the pattern
53983d2307dSDag-Erling Smørgrav 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
54083d2307dSDag-Erling Smørgrav 	 * and the pattern did not contain any magic characters
54183d2307dSDag-Erling Smørgrav 	 * GLOB_NOMAGIC is there just for compatibility with csh.
54283d2307dSDag-Erling Smørgrav 	 */
54383d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathc == oldpathc) {
54483d2307dSDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
54583d2307dSDag-Erling Smørgrav 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
54683d2307dSDag-Erling Smørgrav 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
547*4a421b63SDag-Erling Smørgrav 			return(globextend(pattern, pglob, limitp, NULL));
54883d2307dSDag-Erling Smørgrav 		else
54983d2307dSDag-Erling Smørgrav 			return(GLOB_NOMATCH);
55083d2307dSDag-Erling Smørgrav 	}
55183d2307dSDag-Erling Smørgrav 	if (!(pglob->gl_flags & GLOB_NOSORT))
55283d2307dSDag-Erling Smørgrav 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
55383d2307dSDag-Erling Smørgrav 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
55483d2307dSDag-Erling Smørgrav 	return(0);
55583d2307dSDag-Erling Smørgrav }
55683d2307dSDag-Erling Smørgrav 
55783d2307dSDag-Erling Smørgrav static int
558021d409fSDag-Erling Smørgrav compare(const void *p, const void *q)
55983d2307dSDag-Erling Smørgrav {
56083d2307dSDag-Erling Smørgrav 	return(strcmp(*(char **)p, *(char **)q));
56183d2307dSDag-Erling Smørgrav }
56283d2307dSDag-Erling Smørgrav 
56383d2307dSDag-Erling Smørgrav static int
564*4a421b63SDag-Erling Smørgrav glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
56583d2307dSDag-Erling Smørgrav {
56683d2307dSDag-Erling Smørgrav 	Char pathbuf[MAXPATHLEN];
56783d2307dSDag-Erling Smørgrav 
56883d2307dSDag-Erling Smørgrav 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
56983d2307dSDag-Erling Smørgrav 	if (*pattern == EOS)
57083d2307dSDag-Erling Smørgrav 		return(0);
57183d2307dSDag-Erling Smørgrav 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
57283d2307dSDag-Erling Smørgrav 	    pathbuf, pathbuf+MAXPATHLEN-1,
57383d2307dSDag-Erling Smørgrav 	    pattern, pattern_last, pglob, limitp));
57483d2307dSDag-Erling Smørgrav }
57583d2307dSDag-Erling Smørgrav 
57683d2307dSDag-Erling Smørgrav /*
57783d2307dSDag-Erling Smørgrav  * The functions glob2 and glob3 are mutually recursive; there is one level
57883d2307dSDag-Erling Smørgrav  * of recursion for each segment in the pattern that contains one or more
57983d2307dSDag-Erling Smørgrav  * meta characters.
58083d2307dSDag-Erling Smørgrav  */
58183d2307dSDag-Erling Smørgrav static int
582021d409fSDag-Erling Smørgrav glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
583*4a421b63SDag-Erling Smørgrav     Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
58483d2307dSDag-Erling Smørgrav {
58583d2307dSDag-Erling Smørgrav 	struct stat sb;
58683d2307dSDag-Erling Smørgrav 	Char *p, *q;
58783d2307dSDag-Erling Smørgrav 	int anymeta;
58883d2307dSDag-Erling Smørgrav 
58983d2307dSDag-Erling Smørgrav 	/*
59083d2307dSDag-Erling Smørgrav 	 * Loop over pattern segments until end of pattern or until
59183d2307dSDag-Erling Smørgrav 	 * segment with meta character found.
59283d2307dSDag-Erling Smørgrav 	 */
59383d2307dSDag-Erling Smørgrav 	for (anymeta = 0;;) {
59483d2307dSDag-Erling Smørgrav 		if (*pattern == EOS) {		/* End of pattern? */
59583d2307dSDag-Erling Smørgrav 			*pathend = EOS;
59683d2307dSDag-Erling Smørgrav 			if (g_lstat(pathbuf, &sb, pglob))
59783d2307dSDag-Erling Smørgrav 				return(0);
59883d2307dSDag-Erling Smørgrav 
599*4a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_LIMIT) &&
600*4a421b63SDag-Erling Smørgrav 			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
601*4a421b63SDag-Erling Smørgrav 				errno = 0;
602*4a421b63SDag-Erling Smørgrav 				*pathend++ = SEP;
603*4a421b63SDag-Erling Smørgrav 				*pathend = EOS;
604*4a421b63SDag-Erling Smørgrav 				return(GLOB_NOSPACE);
605*4a421b63SDag-Erling Smørgrav 			}
606*4a421b63SDag-Erling Smørgrav 
60783d2307dSDag-Erling Smørgrav 			if (((pglob->gl_flags & GLOB_MARK) &&
60883d2307dSDag-Erling Smørgrav 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
60983d2307dSDag-Erling Smørgrav 			    (S_ISLNK(sb.st_mode) &&
61083d2307dSDag-Erling Smørgrav 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
61183d2307dSDag-Erling Smørgrav 			    S_ISDIR(sb.st_mode)))) {
61283d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
61383d2307dSDag-Erling Smørgrav 					return (1);
61483d2307dSDag-Erling Smørgrav 				*pathend++ = SEP;
61583d2307dSDag-Erling Smørgrav 				*pathend = EOS;
61683d2307dSDag-Erling Smørgrav 			}
61783d2307dSDag-Erling Smørgrav 			++pglob->gl_matchc;
618*4a421b63SDag-Erling Smørgrav 			return(globextend(pathbuf, pglob, limitp, &sb));
61983d2307dSDag-Erling Smørgrav 		}
62083d2307dSDag-Erling Smørgrav 
62183d2307dSDag-Erling Smørgrav 		/* Find end of next segment, copy tentatively to pathend. */
62283d2307dSDag-Erling Smørgrav 		q = pathend;
62383d2307dSDag-Erling Smørgrav 		p = pattern;
62483d2307dSDag-Erling Smørgrav 		while (*p != EOS && *p != SEP) {
62583d2307dSDag-Erling Smørgrav 			if (ismeta(*p))
62683d2307dSDag-Erling Smørgrav 				anymeta = 1;
62783d2307dSDag-Erling Smørgrav 			if (q+1 > pathend_last)
62883d2307dSDag-Erling Smørgrav 				return (1);
62983d2307dSDag-Erling Smørgrav 			*q++ = *p++;
63083d2307dSDag-Erling Smørgrav 		}
63183d2307dSDag-Erling Smørgrav 
63283d2307dSDag-Erling Smørgrav 		if (!anymeta) {		/* No expansion, do next segment. */
63383d2307dSDag-Erling Smørgrav 			pathend = q;
63483d2307dSDag-Erling Smørgrav 			pattern = p;
63583d2307dSDag-Erling Smørgrav 			while (*pattern == SEP) {
63683d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
63783d2307dSDag-Erling Smørgrav 					return (1);
63883d2307dSDag-Erling Smørgrav 				*pathend++ = *pattern++;
63983d2307dSDag-Erling Smørgrav 			}
64083d2307dSDag-Erling Smørgrav 		} else
64183d2307dSDag-Erling Smørgrav 			/* Need expansion, recurse. */
64283d2307dSDag-Erling Smørgrav 			return(glob3(pathbuf, pathbuf_last, pathend,
643d4af9e69SDag-Erling Smørgrav 			    pathend_last, pattern, p, pattern_last,
644d4af9e69SDag-Erling Smørgrav 			    pglob, limitp));
64583d2307dSDag-Erling Smørgrav 	}
64683d2307dSDag-Erling Smørgrav 	/* NOTREACHED */
64783d2307dSDag-Erling Smørgrav }
64883d2307dSDag-Erling Smørgrav 
64983d2307dSDag-Erling Smørgrav static int
650021d409fSDag-Erling Smørgrav glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
651d4af9e69SDag-Erling Smørgrav     Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
652*4a421b63SDag-Erling Smørgrav     struct glob_lim *limitp)
65383d2307dSDag-Erling Smørgrav {
654021d409fSDag-Erling Smørgrav 	struct dirent *dp;
65583d2307dSDag-Erling Smørgrav 	DIR *dirp;
65683d2307dSDag-Erling Smørgrav 	int err;
65783d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
65883d2307dSDag-Erling Smørgrav 
65983d2307dSDag-Erling Smørgrav 	/*
66083d2307dSDag-Erling Smørgrav 	 * The readdirfunc declaration can't be prototyped, because it is
66183d2307dSDag-Erling Smørgrav 	 * assigned, below, to two functions which are prototyped in glob.h
66283d2307dSDag-Erling Smørgrav 	 * and dirent.h as taking pointers to differently typed opaque
66383d2307dSDag-Erling Smørgrav 	 * structures.
66483d2307dSDag-Erling Smørgrav 	 */
665d95e11bfSDag-Erling Smørgrav 	struct dirent *(*readdirfunc)(void *);
66683d2307dSDag-Erling Smørgrav 
66783d2307dSDag-Erling Smørgrav 	if (pathend > pathend_last)
66883d2307dSDag-Erling Smørgrav 		return (1);
66983d2307dSDag-Erling Smørgrav 	*pathend = EOS;
67083d2307dSDag-Erling Smørgrav 	errno = 0;
67183d2307dSDag-Erling Smørgrav 
67283d2307dSDag-Erling Smørgrav 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
67383d2307dSDag-Erling Smørgrav 		/* TODO: don't call for ENOENT or ENOTDIR? */
67483d2307dSDag-Erling Smørgrav 		if (pglob->gl_errfunc) {
67583d2307dSDag-Erling Smørgrav 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
67683d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
67783d2307dSDag-Erling Smørgrav 			if (pglob->gl_errfunc(buf, errno) ||
67883d2307dSDag-Erling Smørgrav 			    pglob->gl_flags & GLOB_ERR)
67983d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
68083d2307dSDag-Erling Smørgrav 		}
68183d2307dSDag-Erling Smørgrav 		return(0);
68283d2307dSDag-Erling Smørgrav 	}
68383d2307dSDag-Erling Smørgrav 
68483d2307dSDag-Erling Smørgrav 	err = 0;
68583d2307dSDag-Erling Smørgrav 
68683d2307dSDag-Erling Smørgrav 	/* Search directory for matching names. */
68783d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
68883d2307dSDag-Erling Smørgrav 		readdirfunc = pglob->gl_readdir;
68983d2307dSDag-Erling Smørgrav 	else
690d95e11bfSDag-Erling Smørgrav 		readdirfunc = (struct dirent *(*)(void *))readdir;
69183d2307dSDag-Erling Smørgrav 	while ((dp = (*readdirfunc)(dirp))) {
692021d409fSDag-Erling Smørgrav 		u_char *sc;
693021d409fSDag-Erling Smørgrav 		Char *dc;
69483d2307dSDag-Erling Smørgrav 
695*4a421b63SDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_LIMIT) &&
696*4a421b63SDag-Erling Smørgrav 		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
697*4a421b63SDag-Erling Smørgrav 			errno = 0;
698*4a421b63SDag-Erling Smørgrav 			*pathend++ = SEP;
699*4a421b63SDag-Erling Smørgrav 			*pathend = EOS;
700*4a421b63SDag-Erling Smørgrav 			return(GLOB_NOSPACE);
701*4a421b63SDag-Erling Smørgrav 		}
702*4a421b63SDag-Erling Smørgrav 
70383d2307dSDag-Erling Smørgrav 		/* Initial DOT must be matched literally. */
70483d2307dSDag-Erling Smørgrav 		if (dp->d_name[0] == DOT && *pattern != DOT)
70583d2307dSDag-Erling Smørgrav 			continue;
70683d2307dSDag-Erling Smørgrav 		dc = pathend;
70783d2307dSDag-Erling Smørgrav 		sc = (u_char *) dp->d_name;
70883d2307dSDag-Erling Smørgrav 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
70983d2307dSDag-Erling Smørgrav 			;
71083d2307dSDag-Erling Smørgrav 		if (dc >= pathend_last) {
71183d2307dSDag-Erling Smørgrav 			*dc = EOS;
71283d2307dSDag-Erling Smørgrav 			err = 1;
71383d2307dSDag-Erling Smørgrav 			break;
71483d2307dSDag-Erling Smørgrav 		}
71583d2307dSDag-Erling Smørgrav 
71683d2307dSDag-Erling Smørgrav 		if (!match(pathend, pattern, restpattern)) {
71783d2307dSDag-Erling Smørgrav 			*pathend = EOS;
71883d2307dSDag-Erling Smørgrav 			continue;
71983d2307dSDag-Erling Smørgrav 		}
72083d2307dSDag-Erling Smørgrav 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
72183d2307dSDag-Erling Smørgrav 		    restpattern, restpattern_last, pglob, limitp);
72283d2307dSDag-Erling Smørgrav 		if (err)
72383d2307dSDag-Erling Smørgrav 			break;
72483d2307dSDag-Erling Smørgrav 	}
72583d2307dSDag-Erling Smørgrav 
72683d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
72783d2307dSDag-Erling Smørgrav 		(*pglob->gl_closedir)(dirp);
72883d2307dSDag-Erling Smørgrav 	else
72983d2307dSDag-Erling Smørgrav 		closedir(dirp);
73083d2307dSDag-Erling Smørgrav 	return(err);
73183d2307dSDag-Erling Smørgrav }
73283d2307dSDag-Erling Smørgrav 
73383d2307dSDag-Erling Smørgrav 
73483d2307dSDag-Erling Smørgrav /*
7354b17dab0SDag-Erling Smørgrav  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
73683d2307dSDag-Erling Smørgrav  * add the new item, and update gl_pathc.
73783d2307dSDag-Erling Smørgrav  *
73883d2307dSDag-Erling Smørgrav  * This assumes the BSD realloc, which only copies the block when its size
73983d2307dSDag-Erling Smørgrav  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
74083d2307dSDag-Erling Smørgrav  * behavior.
74183d2307dSDag-Erling Smørgrav  *
74283d2307dSDag-Erling Smørgrav  * Return 0 if new item added, error code if memory couldn't be allocated.
74383d2307dSDag-Erling Smørgrav  *
74483d2307dSDag-Erling Smørgrav  * Invariant of the glob_t structure:
74583d2307dSDag-Erling Smørgrav  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
74683d2307dSDag-Erling Smørgrav  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
74783d2307dSDag-Erling Smørgrav  */
74883d2307dSDag-Erling Smørgrav static int
749*4a421b63SDag-Erling Smørgrav globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
750*4a421b63SDag-Erling Smørgrav     struct stat *sb)
75183d2307dSDag-Erling Smørgrav {
752021d409fSDag-Erling Smørgrav 	char **pathv;
753*4a421b63SDag-Erling Smørgrav 	ssize_t i;
754*4a421b63SDag-Erling Smørgrav 	size_t newn, len;
755*4a421b63SDag-Erling Smørgrav 	char *copy = NULL;
75683d2307dSDag-Erling Smørgrav 	const Char *p;
757*4a421b63SDag-Erling Smørgrav 	struct stat **statv;
75883d2307dSDag-Erling Smørgrav 
759*4a421b63SDag-Erling Smørgrav 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
760*4a421b63SDag-Erling Smørgrav 	if (pglob->gl_offs >= INT_MAX ||
761*4a421b63SDag-Erling Smørgrav 	    pglob->gl_pathc >= INT_MAX ||
762*4a421b63SDag-Erling Smørgrav 	    newn >= INT_MAX ||
763*4a421b63SDag-Erling Smørgrav 	    SIZE_MAX / sizeof(*pathv) <= newn ||
764*4a421b63SDag-Erling Smørgrav 	    SIZE_MAX / sizeof(*statv) <= newn) {
765*4a421b63SDag-Erling Smørgrav  nospace:
766*4a421b63SDag-Erling Smørgrav 		for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
767*4a421b63SDag-Erling Smørgrav 			if (pglob->gl_pathv && pglob->gl_pathv[i])
768*4a421b63SDag-Erling Smørgrav 				free(pglob->gl_pathv[i]);
769*4a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
770*4a421b63SDag-Erling Smørgrav 			    pglob->gl_pathv && pglob->gl_pathv[i])
771*4a421b63SDag-Erling Smørgrav 				free(pglob->gl_statv[i]);
772*4a421b63SDag-Erling Smørgrav 		}
77383d2307dSDag-Erling Smørgrav 		if (pglob->gl_pathv) {
77483d2307dSDag-Erling Smørgrav 			free(pglob->gl_pathv);
77583d2307dSDag-Erling Smørgrav 			pglob->gl_pathv = NULL;
77683d2307dSDag-Erling Smørgrav 		}
777*4a421b63SDag-Erling Smørgrav 		if (pglob->gl_statv) {
778*4a421b63SDag-Erling Smørgrav 			free(pglob->gl_statv);
779*4a421b63SDag-Erling Smørgrav 			pglob->gl_statv = NULL;
780*4a421b63SDag-Erling Smørgrav 		}
78183d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
78283d2307dSDag-Erling Smørgrav 	}
78383d2307dSDag-Erling Smørgrav 
784*4a421b63SDag-Erling Smørgrav 	pathv = realloc(pglob->gl_pathv, newn * sizeof(*pathv));
785*4a421b63SDag-Erling Smørgrav 	if (pathv == NULL)
786*4a421b63SDag-Erling Smørgrav 		goto nospace;
78783d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
78883d2307dSDag-Erling Smørgrav 		/* first time around -- clear initial gl_offs items */
78983d2307dSDag-Erling Smørgrav 		pathv += pglob->gl_offs;
79083d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_offs; --i >= 0; )
79183d2307dSDag-Erling Smørgrav 			*--pathv = NULL;
79283d2307dSDag-Erling Smørgrav 	}
79383d2307dSDag-Erling Smørgrav 	pglob->gl_pathv = pathv;
79483d2307dSDag-Erling Smørgrav 
795*4a421b63SDag-Erling Smørgrav 	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
796*4a421b63SDag-Erling Smørgrav 		statv = realloc(pglob->gl_statv, newn * sizeof(*statv));
797*4a421b63SDag-Erling Smørgrav 		if (statv == NULL)
798*4a421b63SDag-Erling Smørgrav 			goto nospace;
799*4a421b63SDag-Erling Smørgrav 		if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
800*4a421b63SDag-Erling Smørgrav 			/* first time around -- clear initial gl_offs items */
801*4a421b63SDag-Erling Smørgrav 			statv += pglob->gl_offs;
802*4a421b63SDag-Erling Smørgrav 			for (i = pglob->gl_offs; --i >= 0; )
803*4a421b63SDag-Erling Smørgrav 				*--statv = NULL;
804*4a421b63SDag-Erling Smørgrav 		}
805*4a421b63SDag-Erling Smørgrav 		pglob->gl_statv = statv;
806*4a421b63SDag-Erling Smørgrav 		if (sb == NULL)
807*4a421b63SDag-Erling Smørgrav 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
808*4a421b63SDag-Erling Smørgrav 		else {
809*4a421b63SDag-Erling Smørgrav 			limitp->glim_malloc += sizeof(**statv);
810*4a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_LIMIT) &&
811*4a421b63SDag-Erling Smørgrav 			    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
812*4a421b63SDag-Erling Smørgrav 				errno = 0;
813*4a421b63SDag-Erling Smørgrav 				return(GLOB_NOSPACE);
814*4a421b63SDag-Erling Smørgrav 			}
815*4a421b63SDag-Erling Smørgrav 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
816*4a421b63SDag-Erling Smørgrav 			    malloc(sizeof(**statv))) == NULL)
817*4a421b63SDag-Erling Smørgrav 				goto copy_error;
818*4a421b63SDag-Erling Smørgrav 			memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
819*4a421b63SDag-Erling Smørgrav 			    sizeof(*sb));
820*4a421b63SDag-Erling Smørgrav 		}
821*4a421b63SDag-Erling Smørgrav 		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
822*4a421b63SDag-Erling Smørgrav 	}
823*4a421b63SDag-Erling Smørgrav 
82483d2307dSDag-Erling Smørgrav 	for (p = path; *p++;)
82583d2307dSDag-Erling Smørgrav 		;
82683d2307dSDag-Erling Smørgrav 	len = (size_t)(p - path);
827*4a421b63SDag-Erling Smørgrav 	limitp->glim_malloc += len;
82883d2307dSDag-Erling Smørgrav 	if ((copy = malloc(len)) != NULL) {
82983d2307dSDag-Erling Smørgrav 		if (g_Ctoc(path, copy, len)) {
83083d2307dSDag-Erling Smørgrav 			free(copy);
83183d2307dSDag-Erling Smørgrav 			return(GLOB_NOSPACE);
83283d2307dSDag-Erling Smørgrav 		}
83383d2307dSDag-Erling Smørgrav 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
83483d2307dSDag-Erling Smørgrav 	}
83583d2307dSDag-Erling Smørgrav 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
83683d2307dSDag-Erling Smørgrav 
83783d2307dSDag-Erling Smørgrav 	if ((pglob->gl_flags & GLOB_LIMIT) &&
838*4a421b63SDag-Erling Smørgrav 	    (newn * sizeof(*pathv)) + limitp->glim_malloc >
839*4a421b63SDag-Erling Smørgrav 	    GLOB_LIMIT_MALLOC) {
84083d2307dSDag-Erling Smørgrav 		errno = 0;
84183d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
84283d2307dSDag-Erling Smørgrav 	}
843*4a421b63SDag-Erling Smørgrav  copy_error:
84483d2307dSDag-Erling Smørgrav 	return(copy == NULL ? GLOB_NOSPACE : 0);
84583d2307dSDag-Erling Smørgrav }
84683d2307dSDag-Erling Smørgrav 
84783d2307dSDag-Erling Smørgrav 
84883d2307dSDag-Erling Smørgrav /*
84983d2307dSDag-Erling Smørgrav  * pattern matching function for filenames.  Each occurrence of the *
85083d2307dSDag-Erling Smørgrav  * pattern causes a recursion level.
85183d2307dSDag-Erling Smørgrav  */
85283d2307dSDag-Erling Smørgrav static int
853021d409fSDag-Erling Smørgrav match(Char *name, Char *pat, Char *patend)
85483d2307dSDag-Erling Smørgrav {
85583d2307dSDag-Erling Smørgrav 	int ok, negate_range;
85683d2307dSDag-Erling Smørgrav 	Char c, k;
85783d2307dSDag-Erling Smørgrav 
85883d2307dSDag-Erling Smørgrav 	while (pat < patend) {
85983d2307dSDag-Erling Smørgrav 		c = *pat++;
86083d2307dSDag-Erling Smørgrav 		switch (c & M_MASK) {
86183d2307dSDag-Erling Smørgrav 		case M_ALL:
86283d2307dSDag-Erling Smørgrav 			if (pat == patend)
86383d2307dSDag-Erling Smørgrav 				return(1);
864021d409fSDag-Erling Smørgrav 			do {
86583d2307dSDag-Erling Smørgrav 			    if (match(name, pat, patend))
86683d2307dSDag-Erling Smørgrav 				    return(1);
867021d409fSDag-Erling Smørgrav 			} while (*name++ != EOS);
86883d2307dSDag-Erling Smørgrav 			return(0);
86983d2307dSDag-Erling Smørgrav 		case M_ONE:
87083d2307dSDag-Erling Smørgrav 			if (*name++ == EOS)
87183d2307dSDag-Erling Smørgrav 				return(0);
87283d2307dSDag-Erling Smørgrav 			break;
87383d2307dSDag-Erling Smørgrav 		case M_SET:
87483d2307dSDag-Erling Smørgrav 			ok = 0;
87583d2307dSDag-Erling Smørgrav 			if ((k = *name++) == EOS)
87683d2307dSDag-Erling Smørgrav 				return(0);
87783d2307dSDag-Erling Smørgrav 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
87883d2307dSDag-Erling Smørgrav 				++pat;
879*4a421b63SDag-Erling Smørgrav 			while (((c = *pat++) & M_MASK) != M_END) {
880*4a421b63SDag-Erling Smørgrav 				if ((c & M_MASK) == M_CLASS) {
881*4a421b63SDag-Erling Smørgrav 					Char idx = *pat & M_MASK;
882*4a421b63SDag-Erling Smørgrav 					if (idx < NCCLASSES &&
883*4a421b63SDag-Erling Smørgrav 					    cclasses[idx].isctype(k))
884*4a421b63SDag-Erling Smørgrav 						ok = 1;
885*4a421b63SDag-Erling Smørgrav 					++pat;
886*4a421b63SDag-Erling Smørgrav 				}
88783d2307dSDag-Erling Smørgrav 				if ((*pat & M_MASK) == M_RNG) {
88883d2307dSDag-Erling Smørgrav 					if (c <= k && k <= pat[1])
88983d2307dSDag-Erling Smørgrav 						ok = 1;
89083d2307dSDag-Erling Smørgrav 					pat += 2;
89183d2307dSDag-Erling Smørgrav 				} else if (c == k)
89283d2307dSDag-Erling Smørgrav 					ok = 1;
893*4a421b63SDag-Erling Smørgrav 			}
89483d2307dSDag-Erling Smørgrav 			if (ok == negate_range)
89583d2307dSDag-Erling Smørgrav 				return(0);
89683d2307dSDag-Erling Smørgrav 			break;
89783d2307dSDag-Erling Smørgrav 		default:
89883d2307dSDag-Erling Smørgrav 			if (*name++ != c)
89983d2307dSDag-Erling Smørgrav 				return(0);
90083d2307dSDag-Erling Smørgrav 			break;
90183d2307dSDag-Erling Smørgrav 		}
90283d2307dSDag-Erling Smørgrav 	}
90383d2307dSDag-Erling Smørgrav 	return(*name == EOS);
90483d2307dSDag-Erling Smørgrav }
90583d2307dSDag-Erling Smørgrav 
90683d2307dSDag-Erling Smørgrav /* Free allocated data belonging to a glob_t structure. */
90783d2307dSDag-Erling Smørgrav void
908021d409fSDag-Erling Smørgrav globfree(glob_t *pglob)
90983d2307dSDag-Erling Smørgrav {
910021d409fSDag-Erling Smørgrav 	int i;
911021d409fSDag-Erling Smørgrav 	char **pp;
91283d2307dSDag-Erling Smørgrav 
91383d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv != NULL) {
91483d2307dSDag-Erling Smørgrav 		pp = pglob->gl_pathv + pglob->gl_offs;
91583d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_pathc; i--; ++pp)
91683d2307dSDag-Erling Smørgrav 			if (*pp)
91783d2307dSDag-Erling Smørgrav 				free(*pp);
91883d2307dSDag-Erling Smørgrav 		free(pglob->gl_pathv);
91983d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
92083d2307dSDag-Erling Smørgrav 	}
921*4a421b63SDag-Erling Smørgrav 	if (pglob->gl_statv != NULL) {
922*4a421b63SDag-Erling Smørgrav 		for (i = 0; i < pglob->gl_pathc; i++) {
923*4a421b63SDag-Erling Smørgrav 			if (pglob->gl_statv[i] != NULL)
924*4a421b63SDag-Erling Smørgrav 				free(pglob->gl_statv[i]);
925*4a421b63SDag-Erling Smørgrav 		}
926*4a421b63SDag-Erling Smørgrav 		free(pglob->gl_statv);
927*4a421b63SDag-Erling Smørgrav 		pglob->gl_statv = NULL;
928*4a421b63SDag-Erling Smørgrav 	}
92983d2307dSDag-Erling Smørgrav }
93083d2307dSDag-Erling Smørgrav 
93183d2307dSDag-Erling Smørgrav static DIR *
932021d409fSDag-Erling Smørgrav g_opendir(Char *str, glob_t *pglob)
93383d2307dSDag-Erling Smørgrav {
93483d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
93583d2307dSDag-Erling Smørgrav 
93683d2307dSDag-Erling Smørgrav 	if (!*str)
9374b17dab0SDag-Erling Smørgrav 		strlcpy(buf, ".", sizeof buf);
93883d2307dSDag-Erling Smørgrav 	else {
93983d2307dSDag-Erling Smørgrav 		if (g_Ctoc(str, buf, sizeof(buf)))
94083d2307dSDag-Erling Smørgrav 			return(NULL);
94183d2307dSDag-Erling Smørgrav 	}
94283d2307dSDag-Erling Smørgrav 
94383d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
94483d2307dSDag-Erling Smørgrav 		return((*pglob->gl_opendir)(buf));
94583d2307dSDag-Erling Smørgrav 
94683d2307dSDag-Erling Smørgrav 	return(opendir(buf));
94783d2307dSDag-Erling Smørgrav }
94883d2307dSDag-Erling Smørgrav 
94983d2307dSDag-Erling Smørgrav static int
950021d409fSDag-Erling Smørgrav g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
95183d2307dSDag-Erling Smørgrav {
95283d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
95383d2307dSDag-Erling Smørgrav 
95483d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
95583d2307dSDag-Erling Smørgrav 		return(-1);
95683d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
95783d2307dSDag-Erling Smørgrav 		return((*pglob->gl_lstat)(buf, sb));
95883d2307dSDag-Erling Smørgrav 	return(lstat(buf, sb));
95983d2307dSDag-Erling Smørgrav }
96083d2307dSDag-Erling Smørgrav 
96183d2307dSDag-Erling Smørgrav static int
962021d409fSDag-Erling Smørgrav g_stat(Char *fn, struct stat *sb, glob_t *pglob)
96383d2307dSDag-Erling Smørgrav {
96483d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
96583d2307dSDag-Erling Smørgrav 
96683d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
96783d2307dSDag-Erling Smørgrav 		return(-1);
96883d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
96983d2307dSDag-Erling Smørgrav 		return((*pglob->gl_stat)(buf, sb));
97083d2307dSDag-Erling Smørgrav 	return(stat(buf, sb));
97183d2307dSDag-Erling Smørgrav }
97283d2307dSDag-Erling Smørgrav 
97383d2307dSDag-Erling Smørgrav static Char *
974*4a421b63SDag-Erling Smørgrav g_strchr(const Char *str, int ch)
97583d2307dSDag-Erling Smørgrav {
97683d2307dSDag-Erling Smørgrav 	do {
97783d2307dSDag-Erling Smørgrav 		if (*str == ch)
978*4a421b63SDag-Erling Smørgrav 			return ((Char *)str);
97983d2307dSDag-Erling Smørgrav 	} while (*str++);
98083d2307dSDag-Erling Smørgrav 	return (NULL);
98183d2307dSDag-Erling Smørgrav }
98283d2307dSDag-Erling Smørgrav 
98383d2307dSDag-Erling Smørgrav static int
984021d409fSDag-Erling Smørgrav g_Ctoc(const Char *str, char *buf, u_int len)
98583d2307dSDag-Erling Smørgrav {
98683d2307dSDag-Erling Smørgrav 
98783d2307dSDag-Erling Smørgrav 	while (len--) {
98883d2307dSDag-Erling Smørgrav 		if ((*buf++ = *str++) == EOS)
98983d2307dSDag-Erling Smørgrav 			return (0);
99083d2307dSDag-Erling Smørgrav 	}
99183d2307dSDag-Erling Smørgrav 	return (1);
99283d2307dSDag-Erling Smørgrav }
99383d2307dSDag-Erling Smørgrav 
99483d2307dSDag-Erling Smørgrav #ifdef DEBUG
99583d2307dSDag-Erling Smørgrav static void
996021d409fSDag-Erling Smørgrav qprintf(const char *str, Char *s)
99783d2307dSDag-Erling Smørgrav {
998021d409fSDag-Erling Smørgrav 	Char *p;
99983d2307dSDag-Erling Smørgrav 
100083d2307dSDag-Erling Smørgrav 	(void)printf("%s:\n", str);
100183d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
100283d2307dSDag-Erling Smørgrav 		(void)printf("%c", CHAR(*p));
100383d2307dSDag-Erling Smørgrav 	(void)printf("\n");
100483d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
100583d2307dSDag-Erling Smørgrav 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
100683d2307dSDag-Erling Smørgrav 	(void)printf("\n");
100783d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
100883d2307dSDag-Erling Smørgrav 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
100983d2307dSDag-Erling Smørgrav 	(void)printf("\n");
101083d2307dSDag-Erling Smørgrav }
101183d2307dSDag-Erling Smørgrav #endif
101283d2307dSDag-Erling Smørgrav 
101383d2307dSDag-Erling Smørgrav #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
1014*4a421b63SDag-Erling Smørgrav           !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) */
1015