xref: /freebsd/crypto/openssh/openbsd-compat/glob.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
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