xref: /freebsd/crypto/openssh/openbsd-compat/glob.c (revision acc1a9ef8333c798c210fa94be6af4d5fe2dd794)
1462c32cbSDag-Erling Smørgrav /*	$OpenBSD: glob.c,v 1.38 2011/09/22 06:27:29 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 
614a421b63SDag-Erling Smørgrav #include "includes.h"
62*acc1a9efSDag-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>
734a421b63SDag-Erling Smørgrav #include <string.h>
744a421b63SDag-Erling Smørgrav #include <unistd.h>
754a421b63SDag-Erling Smørgrav 
764a421b63SDag-Erling Smørgrav #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
774a421b63SDag-Erling Smørgrav     !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
784a421b63SDag-Erling Smørgrav     !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
794a421b63SDag-Erling Smørgrav     defined(BROKEN_GLOB)
804a421b63SDag-Erling Smørgrav 
814a421b63SDag-Erling Smørgrav #include "charclass.h"
8283d2307dSDag-Erling Smørgrav 
8383d2307dSDag-Erling Smørgrav #define	DOLLAR		'$'
8483d2307dSDag-Erling Smørgrav #define	DOT		'.'
8583d2307dSDag-Erling Smørgrav #define	EOS		'\0'
8683d2307dSDag-Erling Smørgrav #define	LBRACKET	'['
8783d2307dSDag-Erling Smørgrav #define	NOT		'!'
8883d2307dSDag-Erling Smørgrav #define	QUESTION	'?'
8983d2307dSDag-Erling Smørgrav #define	QUOTE		'\\'
9083d2307dSDag-Erling Smørgrav #define	RANGE		'-'
9183d2307dSDag-Erling Smørgrav #define	RBRACKET	']'
9283d2307dSDag-Erling Smørgrav #define	SEP		'/'
9383d2307dSDag-Erling Smørgrav #define	STAR		'*'
9483d2307dSDag-Erling Smørgrav #define	TILDE		'~'
9583d2307dSDag-Erling Smørgrav #define	UNDERSCORE	'_'
9683d2307dSDag-Erling Smørgrav #define	LBRACE		'{'
9783d2307dSDag-Erling Smørgrav #define	RBRACE		'}'
9883d2307dSDag-Erling Smørgrav #define	SLASH		'/'
9983d2307dSDag-Erling Smørgrav #define	COMMA		','
10083d2307dSDag-Erling Smørgrav 
10183d2307dSDag-Erling Smørgrav #ifndef DEBUG
10283d2307dSDag-Erling Smørgrav 
10383d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x8000
10483d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x4000
10583d2307dSDag-Erling Smørgrav #define	M_MASK		0xffff
10683d2307dSDag-Erling Smørgrav #define	M_ASCII		0x00ff
10783d2307dSDag-Erling Smørgrav 
10883d2307dSDag-Erling Smørgrav typedef u_short Char;
10983d2307dSDag-Erling Smørgrav 
11083d2307dSDag-Erling Smørgrav #else
11183d2307dSDag-Erling Smørgrav 
11283d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x80
11383d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x40
11483d2307dSDag-Erling Smørgrav #define	M_MASK		0xff
11583d2307dSDag-Erling Smørgrav #define	M_ASCII		0x7f
11683d2307dSDag-Erling Smørgrav 
11783d2307dSDag-Erling Smørgrav typedef char Char;
11883d2307dSDag-Erling Smørgrav 
11983d2307dSDag-Erling Smørgrav #endif
12083d2307dSDag-Erling Smørgrav 
12183d2307dSDag-Erling Smørgrav 
12283d2307dSDag-Erling Smørgrav #define	CHAR(c)		((Char)((c)&M_ASCII))
12383d2307dSDag-Erling Smørgrav #define	META(c)		((Char)((c)|M_QUOTE))
12483d2307dSDag-Erling Smørgrav #define	M_ALL		META('*')
12583d2307dSDag-Erling Smørgrav #define	M_END		META(']')
12683d2307dSDag-Erling Smørgrav #define	M_NOT		META('!')
12783d2307dSDag-Erling Smørgrav #define	M_ONE		META('?')
12883d2307dSDag-Erling Smørgrav #define	M_RNG		META('-')
12983d2307dSDag-Erling Smørgrav #define	M_SET		META('[')
1304a421b63SDag-Erling Smørgrav #define	M_CLASS		META(':')
13183d2307dSDag-Erling Smørgrav #define	ismeta(c)	(((c)&M_QUOTE) != 0)
13283d2307dSDag-Erling Smørgrav 
1334a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_MALLOC	65536
1344a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_STAT		128
1354a421b63SDag-Erling Smørgrav #define	GLOB_LIMIT_READDIR	16384
1364a421b63SDag-Erling Smørgrav 
137462c32cbSDag-Erling Smørgrav /* Limit of recursion during matching attempts. */
138462c32cbSDag-Erling Smørgrav #define GLOB_LIMIT_RECUR	64
139462c32cbSDag-Erling Smørgrav 
1404a421b63SDag-Erling Smørgrav struct glob_lim {
1414a421b63SDag-Erling Smørgrav 	size_t	glim_malloc;
1424a421b63SDag-Erling Smørgrav 	size_t	glim_stat;
1434a421b63SDag-Erling Smørgrav 	size_t	glim_readdir;
1444a421b63SDag-Erling Smørgrav };
14583d2307dSDag-Erling Smørgrav 
146462c32cbSDag-Erling Smørgrav struct glob_path_stat {
147462c32cbSDag-Erling Smørgrav 	char		*gps_path;
148462c32cbSDag-Erling Smørgrav 	struct stat	*gps_stat;
149462c32cbSDag-Erling Smørgrav };
150462c32cbSDag-Erling Smørgrav 
1514b17dab0SDag-Erling Smørgrav static int	 compare(const void *, const void *);
152462c32cbSDag-Erling Smørgrav static int	 compare_gps(const void *, const void *);
1534b17dab0SDag-Erling Smørgrav static int	 g_Ctoc(const Char *, char *, u_int);
1544b17dab0SDag-Erling Smørgrav static int	 g_lstat(Char *, struct stat *, glob_t *);
1554b17dab0SDag-Erling Smørgrav static DIR	*g_opendir(Char *, glob_t *);
1564a421b63SDag-Erling Smørgrav static Char	*g_strchr(const Char *, int);
1574a421b63SDag-Erling Smørgrav static int	 g_strncmp(const Char *, const char *, size_t);
1584b17dab0SDag-Erling Smørgrav static int	 g_stat(Char *, struct stat *, glob_t *);
1594a421b63SDag-Erling Smørgrav static int	 glob0(const Char *, glob_t *, struct glob_lim *);
1604a421b63SDag-Erling Smørgrav static int	 glob1(Char *, Char *, glob_t *, struct glob_lim *);
1614b17dab0SDag-Erling Smørgrav static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
1624a421b63SDag-Erling Smørgrav 		    glob_t *, struct glob_lim *);
163d4af9e69SDag-Erling Smørgrav static int	 glob3(Char *, Char *, Char *, Char *, Char *,
1644a421b63SDag-Erling Smørgrav 		    Char *, Char *, glob_t *, struct glob_lim *);
1654a421b63SDag-Erling Smørgrav static int	 globextend(const Char *, glob_t *, struct glob_lim *,
1664a421b63SDag-Erling Smørgrav 		    struct stat *);
16783d2307dSDag-Erling Smørgrav static const Char *
1684b17dab0SDag-Erling Smørgrav 		 globtilde(const Char *, Char *, size_t, glob_t *);
1694a421b63SDag-Erling Smørgrav static int	 globexp1(const Char *, glob_t *, struct glob_lim *);
1704a421b63SDag-Erling Smørgrav static int	 globexp2(const Char *, const Char *, glob_t *,
1714a421b63SDag-Erling Smørgrav 		    struct glob_lim *);
172462c32cbSDag-Erling Smørgrav static int	 match(Char *, Char *, Char *, int);
17383d2307dSDag-Erling Smørgrav #ifdef DEBUG
1744b17dab0SDag-Erling Smørgrav static void	 qprintf(const char *, Char *);
17583d2307dSDag-Erling Smørgrav #endif
17683d2307dSDag-Erling Smørgrav 
17783d2307dSDag-Erling Smørgrav int
178021d409fSDag-Erling Smørgrav glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
179021d409fSDag-Erling Smørgrav     glob_t *pglob)
18083d2307dSDag-Erling Smørgrav {
18183d2307dSDag-Erling Smørgrav 	const u_char *patnext;
18283d2307dSDag-Erling Smørgrav 	int c;
18383d2307dSDag-Erling Smørgrav 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
1844a421b63SDag-Erling Smørgrav 	struct glob_lim limit = { 0, 0, 0 };
18583d2307dSDag-Erling Smørgrav 
186462c32cbSDag-Erling Smørgrav 	if (strnlen(pattern, PATH_MAX) == PATH_MAX)
187462c32cbSDag-Erling Smørgrav 		return(GLOB_NOMATCH);
188462c32cbSDag-Erling Smørgrav 
18983d2307dSDag-Erling Smørgrav 	patnext = (u_char *) pattern;
19083d2307dSDag-Erling Smørgrav 	if (!(flags & GLOB_APPEND)) {
19183d2307dSDag-Erling Smørgrav 		pglob->gl_pathc = 0;
19283d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
1934a421b63SDag-Erling Smørgrav 		pglob->gl_statv = NULL;
19483d2307dSDag-Erling Smørgrav 		if (!(flags & GLOB_DOOFFS))
19583d2307dSDag-Erling Smørgrav 			pglob->gl_offs = 0;
19683d2307dSDag-Erling Smørgrav 	}
19783d2307dSDag-Erling Smørgrav 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
19883d2307dSDag-Erling Smørgrav 	pglob->gl_errfunc = errfunc;
19983d2307dSDag-Erling Smørgrav 	pglob->gl_matchc = 0;
20083d2307dSDag-Erling Smørgrav 
2014a421b63SDag-Erling Smørgrav 	if (pglob->gl_offs < 0 || pglob->gl_pathc < 0 ||
2024a421b63SDag-Erling Smørgrav 	    pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
2034a421b63SDag-Erling Smørgrav 	    pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
2044a421b63SDag-Erling Smørgrav 		return GLOB_NOSPACE;
2054a421b63SDag-Erling Smørgrav 
20683d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
20783d2307dSDag-Erling Smørgrav 	bufend = bufnext + MAXPATHLEN - 1;
20883d2307dSDag-Erling Smørgrav 	if (flags & GLOB_NOESCAPE)
20983d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
21083d2307dSDag-Erling Smørgrav 			*bufnext++ = c;
21183d2307dSDag-Erling Smørgrav 	else {
21283d2307dSDag-Erling Smørgrav 		/* Protect the quoted characters. */
21383d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
21483d2307dSDag-Erling Smørgrav 			if (c == QUOTE) {
21583d2307dSDag-Erling Smørgrav 				if ((c = *patnext++) == EOS) {
21683d2307dSDag-Erling Smørgrav 					c = QUOTE;
21783d2307dSDag-Erling Smørgrav 					--patnext;
21883d2307dSDag-Erling Smørgrav 				}
21983d2307dSDag-Erling Smørgrav 				*bufnext++ = c | M_PROTECT;
22083d2307dSDag-Erling Smørgrav 			} else
22183d2307dSDag-Erling Smørgrav 				*bufnext++ = c;
22283d2307dSDag-Erling Smørgrav 	}
22383d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
22483d2307dSDag-Erling Smørgrav 
22583d2307dSDag-Erling Smørgrav 	if (flags & GLOB_BRACE)
2264a421b63SDag-Erling Smørgrav 		return globexp1(patbuf, pglob, &limit);
22783d2307dSDag-Erling Smørgrav 	else
2284a421b63SDag-Erling Smørgrav 		return glob0(patbuf, pglob, &limit);
22983d2307dSDag-Erling Smørgrav }
23083d2307dSDag-Erling Smørgrav 
23183d2307dSDag-Erling Smørgrav /*
23283d2307dSDag-Erling Smørgrav  * Expand recursively a glob {} pattern. When there is no more expansion
23383d2307dSDag-Erling Smørgrav  * invoke the standard globbing routine to glob the rest of the magic
23483d2307dSDag-Erling Smørgrav  * characters
23583d2307dSDag-Erling Smørgrav  */
23683d2307dSDag-Erling Smørgrav static int
2374a421b63SDag-Erling Smørgrav globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
23883d2307dSDag-Erling Smørgrav {
23983d2307dSDag-Erling Smørgrav 	const Char* ptr = pattern;
24083d2307dSDag-Erling Smørgrav 
24183d2307dSDag-Erling Smørgrav 	/* Protect a single {}, for find(1), like csh */
24283d2307dSDag-Erling Smørgrav 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
2434a421b63SDag-Erling Smørgrav 		return glob0(pattern, pglob, limitp);
24483d2307dSDag-Erling Smørgrav 
2454a421b63SDag-Erling Smørgrav 	if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
2464a421b63SDag-Erling Smørgrav 		return globexp2(ptr, pattern, pglob, limitp);
24783d2307dSDag-Erling Smørgrav 
2484a421b63SDag-Erling Smørgrav 	return glob0(pattern, pglob, limitp);
24983d2307dSDag-Erling Smørgrav }
25083d2307dSDag-Erling Smørgrav 
25183d2307dSDag-Erling Smørgrav 
25283d2307dSDag-Erling Smørgrav /*
25383d2307dSDag-Erling Smørgrav  * Recursive brace globbing helper. Tries to expand a single brace.
25483d2307dSDag-Erling Smørgrav  * If it succeeds then it invokes globexp1 with the new pattern.
25583d2307dSDag-Erling Smørgrav  * If it fails then it tries to glob the rest of the pattern and returns.
25683d2307dSDag-Erling Smørgrav  */
25783d2307dSDag-Erling Smørgrav static int
2584a421b63SDag-Erling Smørgrav globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
2594a421b63SDag-Erling Smørgrav     struct glob_lim *limitp)
26083d2307dSDag-Erling Smørgrav {
2614a421b63SDag-Erling Smørgrav 	int     i, rv;
26283d2307dSDag-Erling Smørgrav 	Char   *lm, *ls;
26383d2307dSDag-Erling Smørgrav 	const Char *pe, *pm, *pl;
26483d2307dSDag-Erling Smørgrav 	Char    patbuf[MAXPATHLEN];
26583d2307dSDag-Erling Smørgrav 
26683d2307dSDag-Erling Smørgrav 	/* copy part up to the brace */
26783d2307dSDag-Erling Smørgrav 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
26883d2307dSDag-Erling Smørgrav 		;
26983d2307dSDag-Erling Smørgrav 	*lm = EOS;
27083d2307dSDag-Erling Smørgrav 	ls = lm;
27183d2307dSDag-Erling Smørgrav 
27283d2307dSDag-Erling Smørgrav 	/* Find the balanced brace */
27383d2307dSDag-Erling Smørgrav 	for (i = 0, pe = ++ptr; *pe; pe++)
27483d2307dSDag-Erling Smørgrav 		if (*pe == LBRACKET) {
27583d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
27683d2307dSDag-Erling Smørgrav 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
27783d2307dSDag-Erling Smørgrav 				;
27883d2307dSDag-Erling Smørgrav 			if (*pe == EOS) {
27983d2307dSDag-Erling Smørgrav 				/*
28083d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
28183d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
28283d2307dSDag-Erling Smørgrav 				 */
28383d2307dSDag-Erling Smørgrav 				pe = pm;
28483d2307dSDag-Erling Smørgrav 			}
28583d2307dSDag-Erling Smørgrav 		} else if (*pe == LBRACE)
28683d2307dSDag-Erling Smørgrav 			i++;
28783d2307dSDag-Erling Smørgrav 		else if (*pe == RBRACE) {
28883d2307dSDag-Erling Smørgrav 			if (i == 0)
28983d2307dSDag-Erling Smørgrav 				break;
29083d2307dSDag-Erling Smørgrav 			i--;
29183d2307dSDag-Erling Smørgrav 		}
29283d2307dSDag-Erling Smørgrav 
29383d2307dSDag-Erling Smørgrav 	/* Non matching braces; just glob the pattern */
2944a421b63SDag-Erling Smørgrav 	if (i != 0 || *pe == EOS)
2954a421b63SDag-Erling Smørgrav 		return glob0(patbuf, pglob, limitp);
29683d2307dSDag-Erling Smørgrav 
29783d2307dSDag-Erling Smørgrav 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
29883d2307dSDag-Erling Smørgrav 		switch (*pm) {
29983d2307dSDag-Erling Smørgrav 		case LBRACKET:
30083d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
30183d2307dSDag-Erling Smørgrav 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
30283d2307dSDag-Erling Smørgrav 				;
30383d2307dSDag-Erling Smørgrav 			if (*pm == EOS) {
30483d2307dSDag-Erling Smørgrav 				/*
30583d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
30683d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
30783d2307dSDag-Erling Smørgrav 				 */
30883d2307dSDag-Erling Smørgrav 				pm = pl;
30983d2307dSDag-Erling Smørgrav 			}
31083d2307dSDag-Erling Smørgrav 			break;
31183d2307dSDag-Erling Smørgrav 
31283d2307dSDag-Erling Smørgrav 		case LBRACE:
31383d2307dSDag-Erling Smørgrav 			i++;
31483d2307dSDag-Erling Smørgrav 			break;
31583d2307dSDag-Erling Smørgrav 
31683d2307dSDag-Erling Smørgrav 		case RBRACE:
31783d2307dSDag-Erling Smørgrav 			if (i) {
31883d2307dSDag-Erling Smørgrav 				i--;
31983d2307dSDag-Erling Smørgrav 				break;
32083d2307dSDag-Erling Smørgrav 			}
32183d2307dSDag-Erling Smørgrav 			/* FALLTHROUGH */
32283d2307dSDag-Erling Smørgrav 		case COMMA:
32383d2307dSDag-Erling Smørgrav 			if (i && *pm == COMMA)
32483d2307dSDag-Erling Smørgrav 				break;
32583d2307dSDag-Erling Smørgrav 			else {
32683d2307dSDag-Erling Smørgrav 				/* Append the current string */
32783d2307dSDag-Erling Smørgrav 				for (lm = ls; (pl < pm); *lm++ = *pl++)
32883d2307dSDag-Erling Smørgrav 					;
32983d2307dSDag-Erling Smørgrav 
33083d2307dSDag-Erling Smørgrav 				/*
33183d2307dSDag-Erling Smørgrav 				 * Append the rest of the pattern after the
33283d2307dSDag-Erling Smørgrav 				 * closing brace
33383d2307dSDag-Erling Smørgrav 				 */
33483d2307dSDag-Erling Smørgrav 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
33583d2307dSDag-Erling Smørgrav 					;
33683d2307dSDag-Erling Smørgrav 
33783d2307dSDag-Erling Smørgrav 				/* Expand the current pattern */
33883d2307dSDag-Erling Smørgrav #ifdef DEBUG
33983d2307dSDag-Erling Smørgrav 				qprintf("globexp2:", patbuf);
34083d2307dSDag-Erling Smørgrav #endif
3414a421b63SDag-Erling Smørgrav 				rv = globexp1(patbuf, pglob, limitp);
3424a421b63SDag-Erling Smørgrav 				if (rv && rv != GLOB_NOMATCH)
3434a421b63SDag-Erling Smørgrav 					return rv;
34483d2307dSDag-Erling Smørgrav 
34583d2307dSDag-Erling Smørgrav 				/* move after the comma, to the next string */
34683d2307dSDag-Erling Smørgrav 				pl = pm + 1;
34783d2307dSDag-Erling Smørgrav 			}
34883d2307dSDag-Erling Smørgrav 			break;
34983d2307dSDag-Erling Smørgrav 
35083d2307dSDag-Erling Smørgrav 		default:
35183d2307dSDag-Erling Smørgrav 			break;
35283d2307dSDag-Erling Smørgrav 		}
35383d2307dSDag-Erling Smørgrav 	}
35483d2307dSDag-Erling Smørgrav 	return 0;
35583d2307dSDag-Erling Smørgrav }
35683d2307dSDag-Erling Smørgrav 
35783d2307dSDag-Erling Smørgrav 
35883d2307dSDag-Erling Smørgrav 
35983d2307dSDag-Erling Smørgrav /*
36083d2307dSDag-Erling Smørgrav  * expand tilde from the passwd file.
36183d2307dSDag-Erling Smørgrav  */
36283d2307dSDag-Erling Smørgrav static const Char *
363021d409fSDag-Erling Smørgrav globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
36483d2307dSDag-Erling Smørgrav {
36583d2307dSDag-Erling Smørgrav 	struct passwd *pwd;
36683d2307dSDag-Erling Smørgrav 	char *h;
36783d2307dSDag-Erling Smørgrav 	const Char *p;
36883d2307dSDag-Erling Smørgrav 	Char *b, *eb;
36983d2307dSDag-Erling Smørgrav 
37083d2307dSDag-Erling Smørgrav 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
37183d2307dSDag-Erling Smørgrav 		return pattern;
37283d2307dSDag-Erling Smørgrav 
37383d2307dSDag-Erling Smørgrav 	/* Copy up to the end of the string or / */
37483d2307dSDag-Erling Smørgrav 	eb = &patbuf[patbuf_len - 1];
37583d2307dSDag-Erling Smørgrav 	for (p = pattern + 1, h = (char *) patbuf;
37683d2307dSDag-Erling Smørgrav 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
37783d2307dSDag-Erling Smørgrav 		;
37883d2307dSDag-Erling Smørgrav 
37983d2307dSDag-Erling Smørgrav 	*h = EOS;
38083d2307dSDag-Erling Smørgrav 
38183d2307dSDag-Erling Smørgrav #if 0
38283d2307dSDag-Erling Smørgrav 	if (h == (char *)eb)
38383d2307dSDag-Erling Smørgrav 		return what;
38483d2307dSDag-Erling Smørgrav #endif
38583d2307dSDag-Erling Smørgrav 
38683d2307dSDag-Erling Smørgrav 	if (((char *) patbuf)[0] == EOS) {
38783d2307dSDag-Erling Smørgrav 		/*
38883d2307dSDag-Erling Smørgrav 		 * handle a plain ~ or ~/ by expanding $HOME
38983d2307dSDag-Erling Smørgrav 		 * first and then trying the password file
39083d2307dSDag-Erling Smørgrav 		 */
39183d2307dSDag-Erling Smørgrav #if 0
39283d2307dSDag-Erling Smørgrav 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
39383d2307dSDag-Erling Smørgrav #endif
39483d2307dSDag-Erling Smørgrav 		if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
39583d2307dSDag-Erling Smørgrav 			if ((pwd = getpwuid(getuid())) == NULL)
39683d2307dSDag-Erling Smørgrav 				return pattern;
39783d2307dSDag-Erling Smørgrav 			else
39883d2307dSDag-Erling Smørgrav 				h = pwd->pw_dir;
39983d2307dSDag-Erling Smørgrav 		}
40083d2307dSDag-Erling Smørgrav 	} else {
40183d2307dSDag-Erling Smørgrav 		/*
40283d2307dSDag-Erling Smørgrav 		 * Expand a ~user
40383d2307dSDag-Erling Smørgrav 		 */
40483d2307dSDag-Erling Smørgrav 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
40583d2307dSDag-Erling Smørgrav 			return pattern;
40683d2307dSDag-Erling Smørgrav 		else
40783d2307dSDag-Erling Smørgrav 			h = pwd->pw_dir;
40883d2307dSDag-Erling Smørgrav 	}
40983d2307dSDag-Erling Smørgrav 
41083d2307dSDag-Erling Smørgrav 	/* Copy the home directory */
41183d2307dSDag-Erling Smørgrav 	for (b = patbuf; b < eb && *h; *b++ = *h++)
41283d2307dSDag-Erling Smørgrav 		;
41383d2307dSDag-Erling Smørgrav 
41483d2307dSDag-Erling Smørgrav 	/* Append the rest of the pattern */
41583d2307dSDag-Erling Smørgrav 	while (b < eb && (*b++ = *p++) != EOS)
41683d2307dSDag-Erling Smørgrav 		;
41783d2307dSDag-Erling Smørgrav 	*b = EOS;
41883d2307dSDag-Erling Smørgrav 
41983d2307dSDag-Erling Smørgrav 	return patbuf;
42083d2307dSDag-Erling Smørgrav }
42183d2307dSDag-Erling Smørgrav 
4224a421b63SDag-Erling Smørgrav static int
4234a421b63SDag-Erling Smørgrav g_strncmp(const Char *s1, const char *s2, size_t n)
4244a421b63SDag-Erling Smørgrav {
4254a421b63SDag-Erling Smørgrav 	int rv = 0;
4264a421b63SDag-Erling Smørgrav 
4274a421b63SDag-Erling Smørgrav 	while (n--) {
4284a421b63SDag-Erling Smørgrav 		rv = *(Char *)s1 - *(const unsigned char *)s2++;
4294a421b63SDag-Erling Smørgrav 		if (rv)
4304a421b63SDag-Erling Smørgrav 			break;
4314a421b63SDag-Erling Smørgrav 		if (*s1++ == '\0')
4324a421b63SDag-Erling Smørgrav 			break;
4334a421b63SDag-Erling Smørgrav 	}
4344a421b63SDag-Erling Smørgrav 	return rv;
4354a421b63SDag-Erling Smørgrav }
4364a421b63SDag-Erling Smørgrav 
4374a421b63SDag-Erling Smørgrav static int
4384a421b63SDag-Erling Smørgrav g_charclass(const Char **patternp, Char **bufnextp)
4394a421b63SDag-Erling Smørgrav {
4404a421b63SDag-Erling Smørgrav 	const Char *pattern = *patternp + 1;
4414a421b63SDag-Erling Smørgrav 	Char *bufnext = *bufnextp;
4424a421b63SDag-Erling Smørgrav 	const Char *colon;
4434a421b63SDag-Erling Smørgrav 	struct cclass *cc;
4444a421b63SDag-Erling Smørgrav 	size_t len;
4454a421b63SDag-Erling Smørgrav 
4464a421b63SDag-Erling Smørgrav 	if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
4474a421b63SDag-Erling Smørgrav 		return 1;	/* not a character class */
4484a421b63SDag-Erling Smørgrav 
4494a421b63SDag-Erling Smørgrav 	len = (size_t)(colon - pattern);
4504a421b63SDag-Erling Smørgrav 	for (cc = cclasses; cc->name != NULL; cc++) {
4514a421b63SDag-Erling Smørgrav 		if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
4524a421b63SDag-Erling Smørgrav 			break;
4534a421b63SDag-Erling Smørgrav 	}
4544a421b63SDag-Erling Smørgrav 	if (cc->name == NULL)
4554a421b63SDag-Erling Smørgrav 		return -1;	/* invalid character class */
4564a421b63SDag-Erling Smørgrav 	*bufnext++ = M_CLASS;
4574a421b63SDag-Erling Smørgrav 	*bufnext++ = (Char)(cc - &cclasses[0]);
4584a421b63SDag-Erling Smørgrav 	*bufnextp = bufnext;
4594a421b63SDag-Erling Smørgrav 	*patternp += len + 3;
4604a421b63SDag-Erling Smørgrav 
4614a421b63SDag-Erling Smørgrav 	return 0;
4624a421b63SDag-Erling Smørgrav }
46383d2307dSDag-Erling Smørgrav 
46483d2307dSDag-Erling Smørgrav /*
46583d2307dSDag-Erling Smørgrav  * The main glob() routine: compiles the pattern (optionally processing
46683d2307dSDag-Erling Smørgrav  * quotes), calls glob1() to do the real pattern matching, and finally
46783d2307dSDag-Erling Smørgrav  * sorts the list (unless unsorted operation is requested).  Returns 0
46883d2307dSDag-Erling Smørgrav  * if things went well, nonzero if errors occurred.  It is not an error
46983d2307dSDag-Erling Smørgrav  * to find no matches.
47083d2307dSDag-Erling Smørgrav  */
47183d2307dSDag-Erling Smørgrav static int
4724a421b63SDag-Erling Smørgrav glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
47383d2307dSDag-Erling Smørgrav {
47483d2307dSDag-Erling Smørgrav 	const Char *qpatnext;
47583d2307dSDag-Erling Smørgrav 	int c, err, oldpathc;
47683d2307dSDag-Erling Smørgrav 	Char *bufnext, patbuf[MAXPATHLEN];
47783d2307dSDag-Erling Smørgrav 
47883d2307dSDag-Erling Smørgrav 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
47983d2307dSDag-Erling Smørgrav 	oldpathc = pglob->gl_pathc;
48083d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
48183d2307dSDag-Erling Smørgrav 
48283d2307dSDag-Erling Smørgrav 	/* We don't need to check for buffer overflow any more. */
48383d2307dSDag-Erling Smørgrav 	while ((c = *qpatnext++) != EOS) {
48483d2307dSDag-Erling Smørgrav 		switch (c) {
48583d2307dSDag-Erling Smørgrav 		case LBRACKET:
48683d2307dSDag-Erling Smørgrav 			c = *qpatnext;
48783d2307dSDag-Erling Smørgrav 			if (c == NOT)
48883d2307dSDag-Erling Smørgrav 				++qpatnext;
48983d2307dSDag-Erling Smørgrav 			if (*qpatnext == EOS ||
4904a421b63SDag-Erling Smørgrav 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
49183d2307dSDag-Erling Smørgrav 				*bufnext++ = LBRACKET;
49283d2307dSDag-Erling Smørgrav 				if (c == NOT)
49383d2307dSDag-Erling Smørgrav 					--qpatnext;
49483d2307dSDag-Erling Smørgrav 				break;
49583d2307dSDag-Erling Smørgrav 			}
49683d2307dSDag-Erling Smørgrav 			*bufnext++ = M_SET;
49783d2307dSDag-Erling Smørgrav 			if (c == NOT)
49883d2307dSDag-Erling Smørgrav 				*bufnext++ = M_NOT;
49983d2307dSDag-Erling Smørgrav 			c = *qpatnext++;
50083d2307dSDag-Erling Smørgrav 			do {
5014a421b63SDag-Erling Smørgrav 				if (c == LBRACKET && *qpatnext == ':') {
5024a421b63SDag-Erling Smørgrav 					do {
5034a421b63SDag-Erling Smørgrav 						err = g_charclass(&qpatnext,
5044a421b63SDag-Erling Smørgrav 						    &bufnext);
5054a421b63SDag-Erling Smørgrav 						if (err)
5064a421b63SDag-Erling Smørgrav 							break;
5074a421b63SDag-Erling Smørgrav 						c = *qpatnext++;
5084a421b63SDag-Erling Smørgrav 					} while (c == LBRACKET && *qpatnext == ':');
5094a421b63SDag-Erling Smørgrav 					if (err == -1 &&
5104a421b63SDag-Erling Smørgrav 					    !(pglob->gl_flags & GLOB_NOCHECK))
5114a421b63SDag-Erling Smørgrav 						return GLOB_NOMATCH;
5124a421b63SDag-Erling Smørgrav 					if (c == RBRACKET)
5134a421b63SDag-Erling Smørgrav 						break;
5144a421b63SDag-Erling Smørgrav 				}
51583d2307dSDag-Erling Smørgrav 				*bufnext++ = CHAR(c);
51683d2307dSDag-Erling Smørgrav 				if (*qpatnext == RANGE &&
51783d2307dSDag-Erling Smørgrav 				    (c = qpatnext[1]) != RBRACKET) {
51883d2307dSDag-Erling Smørgrav 					*bufnext++ = M_RNG;
51983d2307dSDag-Erling Smørgrav 					*bufnext++ = CHAR(c);
52083d2307dSDag-Erling Smørgrav 					qpatnext += 2;
52183d2307dSDag-Erling Smørgrav 				}
52283d2307dSDag-Erling Smørgrav 			} while ((c = *qpatnext++) != RBRACKET);
52383d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
52483d2307dSDag-Erling Smørgrav 			*bufnext++ = M_END;
52583d2307dSDag-Erling Smørgrav 			break;
52683d2307dSDag-Erling Smørgrav 		case QUESTION:
52783d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
52883d2307dSDag-Erling Smørgrav 			*bufnext++ = M_ONE;
52983d2307dSDag-Erling Smørgrav 			break;
53083d2307dSDag-Erling Smørgrav 		case STAR:
53183d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
53283d2307dSDag-Erling Smørgrav 			/* collapse adjacent stars to one,
53383d2307dSDag-Erling Smørgrav 			 * to avoid exponential behavior
53483d2307dSDag-Erling Smørgrav 			 */
53583d2307dSDag-Erling Smørgrav 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
53683d2307dSDag-Erling Smørgrav 				*bufnext++ = M_ALL;
53783d2307dSDag-Erling Smørgrav 			break;
53883d2307dSDag-Erling Smørgrav 		default:
53983d2307dSDag-Erling Smørgrav 			*bufnext++ = CHAR(c);
54083d2307dSDag-Erling Smørgrav 			break;
54183d2307dSDag-Erling Smørgrav 		}
54283d2307dSDag-Erling Smørgrav 	}
54383d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
54483d2307dSDag-Erling Smørgrav #ifdef DEBUG
54583d2307dSDag-Erling Smørgrav 	qprintf("glob0:", patbuf);
54683d2307dSDag-Erling Smørgrav #endif
54783d2307dSDag-Erling Smørgrav 
5484a421b63SDag-Erling Smørgrav 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp)) != 0)
54983d2307dSDag-Erling Smørgrav 		return(err);
55083d2307dSDag-Erling Smørgrav 
55183d2307dSDag-Erling Smørgrav 	/*
55283d2307dSDag-Erling Smørgrav 	 * If there was no match we are going to append the pattern
55383d2307dSDag-Erling Smørgrav 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
55483d2307dSDag-Erling Smørgrav 	 * and the pattern did not contain any magic characters
55583d2307dSDag-Erling Smørgrav 	 * GLOB_NOMAGIC is there just for compatibility with csh.
55683d2307dSDag-Erling Smørgrav 	 */
55783d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathc == oldpathc) {
55883d2307dSDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
55983d2307dSDag-Erling Smørgrav 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
56083d2307dSDag-Erling Smørgrav 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
5614a421b63SDag-Erling Smørgrav 			return(globextend(pattern, pglob, limitp, NULL));
56283d2307dSDag-Erling Smørgrav 		else
56383d2307dSDag-Erling Smørgrav 			return(GLOB_NOMATCH);
56483d2307dSDag-Erling Smørgrav 	}
565462c32cbSDag-Erling Smørgrav 	if (!(pglob->gl_flags & GLOB_NOSORT)) {
566462c32cbSDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
567462c32cbSDag-Erling Smørgrav 			/* Keep the paths and stat info synced during sort */
568462c32cbSDag-Erling Smørgrav 			struct glob_path_stat *path_stat;
569462c32cbSDag-Erling Smørgrav 			int i;
570462c32cbSDag-Erling Smørgrav 			int n = pglob->gl_pathc - oldpathc;
571462c32cbSDag-Erling Smørgrav 			int o = pglob->gl_offs + oldpathc;
572462c32cbSDag-Erling Smørgrav 
573462c32cbSDag-Erling Smørgrav 			if ((path_stat = calloc(n, sizeof(*path_stat))) == NULL)
574462c32cbSDag-Erling Smørgrav 				return GLOB_NOSPACE;
575462c32cbSDag-Erling Smørgrav 			for (i = 0; i < n; i++) {
576462c32cbSDag-Erling Smørgrav 				path_stat[i].gps_path = pglob->gl_pathv[o + i];
577462c32cbSDag-Erling Smørgrav 				path_stat[i].gps_stat = pglob->gl_statv[o + i];
578462c32cbSDag-Erling Smørgrav 			}
579462c32cbSDag-Erling Smørgrav 			qsort(path_stat, n, sizeof(*path_stat), compare_gps);
580462c32cbSDag-Erling Smørgrav 			for (i = 0; i < n; i++) {
581462c32cbSDag-Erling Smørgrav 				pglob->gl_pathv[o + i] = path_stat[i].gps_path;
582462c32cbSDag-Erling Smørgrav 				pglob->gl_statv[o + i] = path_stat[i].gps_stat;
583462c32cbSDag-Erling Smørgrav 			}
584462c32cbSDag-Erling Smørgrav 			free(path_stat);
585462c32cbSDag-Erling Smørgrav 		} else {
58683d2307dSDag-Erling Smørgrav 			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
587462c32cbSDag-Erling Smørgrav 			    pglob->gl_pathc - oldpathc, sizeof(char *),
588462c32cbSDag-Erling Smørgrav 			    compare);
589462c32cbSDag-Erling Smørgrav 		}
590462c32cbSDag-Erling Smørgrav 	}
59183d2307dSDag-Erling Smørgrav 	return(0);
59283d2307dSDag-Erling Smørgrav }
59383d2307dSDag-Erling Smørgrav 
59483d2307dSDag-Erling Smørgrav static int
595021d409fSDag-Erling Smørgrav compare(const void *p, const void *q)
59683d2307dSDag-Erling Smørgrav {
59783d2307dSDag-Erling Smørgrav 	return(strcmp(*(char **)p, *(char **)q));
59883d2307dSDag-Erling Smørgrav }
59983d2307dSDag-Erling Smørgrav 
60083d2307dSDag-Erling Smørgrav static int
601462c32cbSDag-Erling Smørgrav compare_gps(const void *_p, const void *_q)
602462c32cbSDag-Erling Smørgrav {
603462c32cbSDag-Erling Smørgrav 	const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
604462c32cbSDag-Erling Smørgrav 	const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
605462c32cbSDag-Erling Smørgrav 
606462c32cbSDag-Erling Smørgrav 	return(strcmp(p->gps_path, q->gps_path));
607462c32cbSDag-Erling Smørgrav }
608462c32cbSDag-Erling Smørgrav 
609462c32cbSDag-Erling Smørgrav static int
6104a421b63SDag-Erling Smørgrav glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
61183d2307dSDag-Erling Smørgrav {
61283d2307dSDag-Erling Smørgrav 	Char pathbuf[MAXPATHLEN];
61383d2307dSDag-Erling Smørgrav 
61483d2307dSDag-Erling Smørgrav 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
61583d2307dSDag-Erling Smørgrav 	if (*pattern == EOS)
61683d2307dSDag-Erling Smørgrav 		return(0);
61783d2307dSDag-Erling Smørgrav 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
61883d2307dSDag-Erling Smørgrav 	    pathbuf, pathbuf+MAXPATHLEN-1,
61983d2307dSDag-Erling Smørgrav 	    pattern, pattern_last, pglob, limitp));
62083d2307dSDag-Erling Smørgrav }
62183d2307dSDag-Erling Smørgrav 
62283d2307dSDag-Erling Smørgrav /*
62383d2307dSDag-Erling Smørgrav  * The functions glob2 and glob3 are mutually recursive; there is one level
62483d2307dSDag-Erling Smørgrav  * of recursion for each segment in the pattern that contains one or more
62583d2307dSDag-Erling Smørgrav  * meta characters.
62683d2307dSDag-Erling Smørgrav  */
62783d2307dSDag-Erling Smørgrav static int
628021d409fSDag-Erling Smørgrav glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
6294a421b63SDag-Erling Smørgrav     Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
63083d2307dSDag-Erling Smørgrav {
63183d2307dSDag-Erling Smørgrav 	struct stat sb;
63283d2307dSDag-Erling Smørgrav 	Char *p, *q;
63383d2307dSDag-Erling Smørgrav 	int anymeta;
63483d2307dSDag-Erling Smørgrav 
63583d2307dSDag-Erling Smørgrav 	/*
63683d2307dSDag-Erling Smørgrav 	 * Loop over pattern segments until end of pattern or until
63783d2307dSDag-Erling Smørgrav 	 * segment with meta character found.
63883d2307dSDag-Erling Smørgrav 	 */
63983d2307dSDag-Erling Smørgrav 	for (anymeta = 0;;) {
64083d2307dSDag-Erling Smørgrav 		if (*pattern == EOS) {		/* End of pattern? */
64183d2307dSDag-Erling Smørgrav 			*pathend = EOS;
64283d2307dSDag-Erling Smørgrav 			if (g_lstat(pathbuf, &sb, pglob))
64383d2307dSDag-Erling Smørgrav 				return(0);
64483d2307dSDag-Erling Smørgrav 
6454a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_LIMIT) &&
6464a421b63SDag-Erling Smørgrav 			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
6474a421b63SDag-Erling Smørgrav 				errno = 0;
6484a421b63SDag-Erling Smørgrav 				*pathend++ = SEP;
6494a421b63SDag-Erling Smørgrav 				*pathend = EOS;
6504a421b63SDag-Erling Smørgrav 				return(GLOB_NOSPACE);
6514a421b63SDag-Erling Smørgrav 			}
6524a421b63SDag-Erling Smørgrav 
65383d2307dSDag-Erling Smørgrav 			if (((pglob->gl_flags & GLOB_MARK) &&
65483d2307dSDag-Erling Smørgrav 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
65583d2307dSDag-Erling Smørgrav 			    (S_ISLNK(sb.st_mode) &&
65683d2307dSDag-Erling Smørgrav 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
65783d2307dSDag-Erling Smørgrav 			    S_ISDIR(sb.st_mode)))) {
65883d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
65983d2307dSDag-Erling Smørgrav 					return (1);
66083d2307dSDag-Erling Smørgrav 				*pathend++ = SEP;
66183d2307dSDag-Erling Smørgrav 				*pathend = EOS;
66283d2307dSDag-Erling Smørgrav 			}
66383d2307dSDag-Erling Smørgrav 			++pglob->gl_matchc;
6644a421b63SDag-Erling Smørgrav 			return(globextend(pathbuf, pglob, limitp, &sb));
66583d2307dSDag-Erling Smørgrav 		}
66683d2307dSDag-Erling Smørgrav 
66783d2307dSDag-Erling Smørgrav 		/* Find end of next segment, copy tentatively to pathend. */
66883d2307dSDag-Erling Smørgrav 		q = pathend;
66983d2307dSDag-Erling Smørgrav 		p = pattern;
67083d2307dSDag-Erling Smørgrav 		while (*p != EOS && *p != SEP) {
67183d2307dSDag-Erling Smørgrav 			if (ismeta(*p))
67283d2307dSDag-Erling Smørgrav 				anymeta = 1;
67383d2307dSDag-Erling Smørgrav 			if (q+1 > pathend_last)
67483d2307dSDag-Erling Smørgrav 				return (1);
67583d2307dSDag-Erling Smørgrav 			*q++ = *p++;
67683d2307dSDag-Erling Smørgrav 		}
67783d2307dSDag-Erling Smørgrav 
67883d2307dSDag-Erling Smørgrav 		if (!anymeta) {		/* No expansion, do next segment. */
67983d2307dSDag-Erling Smørgrav 			pathend = q;
68083d2307dSDag-Erling Smørgrav 			pattern = p;
68183d2307dSDag-Erling Smørgrav 			while (*pattern == SEP) {
68283d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
68383d2307dSDag-Erling Smørgrav 					return (1);
68483d2307dSDag-Erling Smørgrav 				*pathend++ = *pattern++;
68583d2307dSDag-Erling Smørgrav 			}
68683d2307dSDag-Erling Smørgrav 		} else
68783d2307dSDag-Erling Smørgrav 			/* Need expansion, recurse. */
68883d2307dSDag-Erling Smørgrav 			return(glob3(pathbuf, pathbuf_last, pathend,
689d4af9e69SDag-Erling Smørgrav 			    pathend_last, pattern, p, pattern_last,
690d4af9e69SDag-Erling Smørgrav 			    pglob, limitp));
69183d2307dSDag-Erling Smørgrav 	}
69283d2307dSDag-Erling Smørgrav 	/* NOTREACHED */
69383d2307dSDag-Erling Smørgrav }
69483d2307dSDag-Erling Smørgrav 
69583d2307dSDag-Erling Smørgrav static int
696021d409fSDag-Erling Smørgrav glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
697d4af9e69SDag-Erling Smørgrav     Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
6984a421b63SDag-Erling Smørgrav     struct glob_lim *limitp)
69983d2307dSDag-Erling Smørgrav {
700021d409fSDag-Erling Smørgrav 	struct dirent *dp;
70183d2307dSDag-Erling Smørgrav 	DIR *dirp;
70283d2307dSDag-Erling Smørgrav 	int err;
70383d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
70483d2307dSDag-Erling Smørgrav 
70583d2307dSDag-Erling Smørgrav 	/*
70683d2307dSDag-Erling Smørgrav 	 * The readdirfunc declaration can't be prototyped, because it is
70783d2307dSDag-Erling Smørgrav 	 * assigned, below, to two functions which are prototyped in glob.h
70883d2307dSDag-Erling Smørgrav 	 * and dirent.h as taking pointers to differently typed opaque
70983d2307dSDag-Erling Smørgrav 	 * structures.
71083d2307dSDag-Erling Smørgrav 	 */
711d95e11bfSDag-Erling Smørgrav 	struct dirent *(*readdirfunc)(void *);
71283d2307dSDag-Erling Smørgrav 
71383d2307dSDag-Erling Smørgrav 	if (pathend > pathend_last)
71483d2307dSDag-Erling Smørgrav 		return (1);
71583d2307dSDag-Erling Smørgrav 	*pathend = EOS;
71683d2307dSDag-Erling Smørgrav 	errno = 0;
71783d2307dSDag-Erling Smørgrav 
71883d2307dSDag-Erling Smørgrav 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
71983d2307dSDag-Erling Smørgrav 		/* TODO: don't call for ENOENT or ENOTDIR? */
72083d2307dSDag-Erling Smørgrav 		if (pglob->gl_errfunc) {
72183d2307dSDag-Erling Smørgrav 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
72283d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
72383d2307dSDag-Erling Smørgrav 			if (pglob->gl_errfunc(buf, errno) ||
72483d2307dSDag-Erling Smørgrav 			    pglob->gl_flags & GLOB_ERR)
72583d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
72683d2307dSDag-Erling Smørgrav 		}
72783d2307dSDag-Erling Smørgrav 		return(0);
72883d2307dSDag-Erling Smørgrav 	}
72983d2307dSDag-Erling Smørgrav 
73083d2307dSDag-Erling Smørgrav 	err = 0;
73183d2307dSDag-Erling Smørgrav 
73283d2307dSDag-Erling Smørgrav 	/* Search directory for matching names. */
73383d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
73483d2307dSDag-Erling Smørgrav 		readdirfunc = pglob->gl_readdir;
73583d2307dSDag-Erling Smørgrav 	else
736d95e11bfSDag-Erling Smørgrav 		readdirfunc = (struct dirent *(*)(void *))readdir;
73783d2307dSDag-Erling Smørgrav 	while ((dp = (*readdirfunc)(dirp))) {
738021d409fSDag-Erling Smørgrav 		u_char *sc;
739021d409fSDag-Erling Smørgrav 		Char *dc;
74083d2307dSDag-Erling Smørgrav 
7414a421b63SDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_LIMIT) &&
7424a421b63SDag-Erling Smørgrav 		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
7434a421b63SDag-Erling Smørgrav 			errno = 0;
7444a421b63SDag-Erling Smørgrav 			*pathend++ = SEP;
7454a421b63SDag-Erling Smørgrav 			*pathend = EOS;
746462c32cbSDag-Erling Smørgrav 			err = GLOB_NOSPACE;
747462c32cbSDag-Erling Smørgrav 			break;
7484a421b63SDag-Erling Smørgrav 		}
7494a421b63SDag-Erling Smørgrav 
75083d2307dSDag-Erling Smørgrav 		/* Initial DOT must be matched literally. */
75183d2307dSDag-Erling Smørgrav 		if (dp->d_name[0] == DOT && *pattern != DOT)
75283d2307dSDag-Erling Smørgrav 			continue;
75383d2307dSDag-Erling Smørgrav 		dc = pathend;
75483d2307dSDag-Erling Smørgrav 		sc = (u_char *) dp->d_name;
75583d2307dSDag-Erling Smørgrav 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
75683d2307dSDag-Erling Smørgrav 			;
75783d2307dSDag-Erling Smørgrav 		if (dc >= pathend_last) {
75883d2307dSDag-Erling Smørgrav 			*dc = EOS;
75983d2307dSDag-Erling Smørgrav 			err = 1;
76083d2307dSDag-Erling Smørgrav 			break;
76183d2307dSDag-Erling Smørgrav 		}
76283d2307dSDag-Erling Smørgrav 
763462c32cbSDag-Erling Smørgrav 		if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
76483d2307dSDag-Erling Smørgrav 			*pathend = EOS;
76583d2307dSDag-Erling Smørgrav 			continue;
76683d2307dSDag-Erling Smørgrav 		}
76783d2307dSDag-Erling Smørgrav 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
76883d2307dSDag-Erling Smørgrav 		    restpattern, restpattern_last, pglob, limitp);
76983d2307dSDag-Erling Smørgrav 		if (err)
77083d2307dSDag-Erling Smørgrav 			break;
77183d2307dSDag-Erling Smørgrav 	}
77283d2307dSDag-Erling Smørgrav 
77383d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
77483d2307dSDag-Erling Smørgrav 		(*pglob->gl_closedir)(dirp);
77583d2307dSDag-Erling Smørgrav 	else
77683d2307dSDag-Erling Smørgrav 		closedir(dirp);
77783d2307dSDag-Erling Smørgrav 	return(err);
77883d2307dSDag-Erling Smørgrav }
77983d2307dSDag-Erling Smørgrav 
78083d2307dSDag-Erling Smørgrav 
78183d2307dSDag-Erling Smørgrav /*
7824b17dab0SDag-Erling Smørgrav  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
78383d2307dSDag-Erling Smørgrav  * add the new item, and update gl_pathc.
78483d2307dSDag-Erling Smørgrav  *
78583d2307dSDag-Erling Smørgrav  * This assumes the BSD realloc, which only copies the block when its size
78683d2307dSDag-Erling Smørgrav  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
78783d2307dSDag-Erling Smørgrav  * behavior.
78883d2307dSDag-Erling Smørgrav  *
78983d2307dSDag-Erling Smørgrav  * Return 0 if new item added, error code if memory couldn't be allocated.
79083d2307dSDag-Erling Smørgrav  *
79183d2307dSDag-Erling Smørgrav  * Invariant of the glob_t structure:
79283d2307dSDag-Erling Smørgrav  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
79383d2307dSDag-Erling Smørgrav  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
79483d2307dSDag-Erling Smørgrav  */
79583d2307dSDag-Erling Smørgrav static int
7964a421b63SDag-Erling Smørgrav globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
7974a421b63SDag-Erling Smørgrav     struct stat *sb)
79883d2307dSDag-Erling Smørgrav {
799021d409fSDag-Erling Smørgrav 	char **pathv;
8004a421b63SDag-Erling Smørgrav 	ssize_t i;
8014a421b63SDag-Erling Smørgrav 	size_t newn, len;
8024a421b63SDag-Erling Smørgrav 	char *copy = NULL;
80383d2307dSDag-Erling Smørgrav 	const Char *p;
8044a421b63SDag-Erling Smørgrav 	struct stat **statv;
80583d2307dSDag-Erling Smørgrav 
8064a421b63SDag-Erling Smørgrav 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
8074a421b63SDag-Erling Smørgrav 	if (pglob->gl_offs >= INT_MAX ||
8084a421b63SDag-Erling Smørgrav 	    pglob->gl_pathc >= INT_MAX ||
8094a421b63SDag-Erling Smørgrav 	    newn >= INT_MAX ||
8104a421b63SDag-Erling Smørgrav 	    SIZE_MAX / sizeof(*pathv) <= newn ||
8114a421b63SDag-Erling Smørgrav 	    SIZE_MAX / sizeof(*statv) <= newn) {
8124a421b63SDag-Erling Smørgrav  nospace:
8134a421b63SDag-Erling Smørgrav 		for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
8144a421b63SDag-Erling Smørgrav 			if (pglob->gl_pathv && pglob->gl_pathv[i])
8154a421b63SDag-Erling Smørgrav 				free(pglob->gl_pathv[i]);
8164a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
8174a421b63SDag-Erling Smørgrav 			    pglob->gl_pathv && pglob->gl_pathv[i])
8184a421b63SDag-Erling Smørgrav 				free(pglob->gl_statv[i]);
8194a421b63SDag-Erling Smørgrav 		}
82083d2307dSDag-Erling Smørgrav 		if (pglob->gl_pathv) {
82183d2307dSDag-Erling Smørgrav 			free(pglob->gl_pathv);
82283d2307dSDag-Erling Smørgrav 			pglob->gl_pathv = NULL;
82383d2307dSDag-Erling Smørgrav 		}
8244a421b63SDag-Erling Smørgrav 		if (pglob->gl_statv) {
8254a421b63SDag-Erling Smørgrav 			free(pglob->gl_statv);
8264a421b63SDag-Erling Smørgrav 			pglob->gl_statv = NULL;
8274a421b63SDag-Erling Smørgrav 		}
82883d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
82983d2307dSDag-Erling Smørgrav 	}
83083d2307dSDag-Erling Smørgrav 
8314a421b63SDag-Erling Smørgrav 	pathv = realloc(pglob->gl_pathv, newn * sizeof(*pathv));
8324a421b63SDag-Erling Smørgrav 	if (pathv == NULL)
8334a421b63SDag-Erling Smørgrav 		goto nospace;
83483d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
83583d2307dSDag-Erling Smørgrav 		/* first time around -- clear initial gl_offs items */
83683d2307dSDag-Erling Smørgrav 		pathv += pglob->gl_offs;
83783d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_offs; --i >= 0; )
83883d2307dSDag-Erling Smørgrav 			*--pathv = NULL;
83983d2307dSDag-Erling Smørgrav 	}
84083d2307dSDag-Erling Smørgrav 	pglob->gl_pathv = pathv;
84183d2307dSDag-Erling Smørgrav 
8424a421b63SDag-Erling Smørgrav 	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
8434a421b63SDag-Erling Smørgrav 		statv = realloc(pglob->gl_statv, newn * sizeof(*statv));
8444a421b63SDag-Erling Smørgrav 		if (statv == NULL)
8454a421b63SDag-Erling Smørgrav 			goto nospace;
8464a421b63SDag-Erling Smørgrav 		if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
8474a421b63SDag-Erling Smørgrav 			/* first time around -- clear initial gl_offs items */
8484a421b63SDag-Erling Smørgrav 			statv += pglob->gl_offs;
8494a421b63SDag-Erling Smørgrav 			for (i = pglob->gl_offs; --i >= 0; )
8504a421b63SDag-Erling Smørgrav 				*--statv = NULL;
8514a421b63SDag-Erling Smørgrav 		}
8524a421b63SDag-Erling Smørgrav 		pglob->gl_statv = statv;
8534a421b63SDag-Erling Smørgrav 		if (sb == NULL)
8544a421b63SDag-Erling Smørgrav 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
8554a421b63SDag-Erling Smørgrav 		else {
8564a421b63SDag-Erling Smørgrav 			limitp->glim_malloc += sizeof(**statv);
8574a421b63SDag-Erling Smørgrav 			if ((pglob->gl_flags & GLOB_LIMIT) &&
8584a421b63SDag-Erling Smørgrav 			    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
8594a421b63SDag-Erling Smørgrav 				errno = 0;
8604a421b63SDag-Erling Smørgrav 				return(GLOB_NOSPACE);
8614a421b63SDag-Erling Smørgrav 			}
8624a421b63SDag-Erling Smørgrav 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
8634a421b63SDag-Erling Smørgrav 			    malloc(sizeof(**statv))) == NULL)
8644a421b63SDag-Erling Smørgrav 				goto copy_error;
8654a421b63SDag-Erling Smørgrav 			memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
8664a421b63SDag-Erling Smørgrav 			    sizeof(*sb));
8674a421b63SDag-Erling Smørgrav 		}
8684a421b63SDag-Erling Smørgrav 		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
8694a421b63SDag-Erling Smørgrav 	}
8704a421b63SDag-Erling Smørgrav 
87183d2307dSDag-Erling Smørgrav 	for (p = path; *p++;)
87283d2307dSDag-Erling Smørgrav 		;
87383d2307dSDag-Erling Smørgrav 	len = (size_t)(p - path);
8744a421b63SDag-Erling Smørgrav 	limitp->glim_malloc += len;
87583d2307dSDag-Erling Smørgrav 	if ((copy = malloc(len)) != NULL) {
87683d2307dSDag-Erling Smørgrav 		if (g_Ctoc(path, copy, len)) {
87783d2307dSDag-Erling Smørgrav 			free(copy);
87883d2307dSDag-Erling Smørgrav 			return(GLOB_NOSPACE);
87983d2307dSDag-Erling Smørgrav 		}
88083d2307dSDag-Erling Smørgrav 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
88183d2307dSDag-Erling Smørgrav 	}
88283d2307dSDag-Erling Smørgrav 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
88383d2307dSDag-Erling Smørgrav 
88483d2307dSDag-Erling Smørgrav 	if ((pglob->gl_flags & GLOB_LIMIT) &&
8854a421b63SDag-Erling Smørgrav 	    (newn * sizeof(*pathv)) + limitp->glim_malloc >
8864a421b63SDag-Erling Smørgrav 	    GLOB_LIMIT_MALLOC) {
88783d2307dSDag-Erling Smørgrav 		errno = 0;
88883d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
88983d2307dSDag-Erling Smørgrav 	}
8904a421b63SDag-Erling Smørgrav  copy_error:
89183d2307dSDag-Erling Smørgrav 	return(copy == NULL ? GLOB_NOSPACE : 0);
89283d2307dSDag-Erling Smørgrav }
89383d2307dSDag-Erling Smørgrav 
89483d2307dSDag-Erling Smørgrav 
89583d2307dSDag-Erling Smørgrav /*
89683d2307dSDag-Erling Smørgrav  * pattern matching function for filenames.  Each occurrence of the *
89783d2307dSDag-Erling Smørgrav  * pattern causes a recursion level.
89883d2307dSDag-Erling Smørgrav  */
89983d2307dSDag-Erling Smørgrav static int
900462c32cbSDag-Erling Smørgrav match(Char *name, Char *pat, Char *patend, int recur)
90183d2307dSDag-Erling Smørgrav {
90283d2307dSDag-Erling Smørgrav 	int ok, negate_range;
90383d2307dSDag-Erling Smørgrav 	Char c, k;
90483d2307dSDag-Erling Smørgrav 
905462c32cbSDag-Erling Smørgrav 	if (recur-- == 0)
906462c32cbSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
907462c32cbSDag-Erling Smørgrav 
90883d2307dSDag-Erling Smørgrav 	while (pat < patend) {
90983d2307dSDag-Erling Smørgrav 		c = *pat++;
91083d2307dSDag-Erling Smørgrav 		switch (c & M_MASK) {
91183d2307dSDag-Erling Smørgrav 		case M_ALL:
912462c32cbSDag-Erling Smørgrav 			while (pat < patend && (*pat & M_MASK) == M_ALL)
913462c32cbSDag-Erling Smørgrav 				pat++;	/* eat consecutive '*' */
91483d2307dSDag-Erling Smørgrav 			if (pat == patend)
91583d2307dSDag-Erling Smørgrav 				return(1);
916021d409fSDag-Erling Smørgrav 			do {
917462c32cbSDag-Erling Smørgrav 			    if (match(name, pat, patend, recur))
91883d2307dSDag-Erling Smørgrav 				    return(1);
919021d409fSDag-Erling Smørgrav 			} while (*name++ != EOS);
92083d2307dSDag-Erling Smørgrav 			return(0);
92183d2307dSDag-Erling Smørgrav 		case M_ONE:
92283d2307dSDag-Erling Smørgrav 			if (*name++ == EOS)
92383d2307dSDag-Erling Smørgrav 				return(0);
92483d2307dSDag-Erling Smørgrav 			break;
92583d2307dSDag-Erling Smørgrav 		case M_SET:
92683d2307dSDag-Erling Smørgrav 			ok = 0;
92783d2307dSDag-Erling Smørgrav 			if ((k = *name++) == EOS)
92883d2307dSDag-Erling Smørgrav 				return(0);
92983d2307dSDag-Erling Smørgrav 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
93083d2307dSDag-Erling Smørgrav 				++pat;
9314a421b63SDag-Erling Smørgrav 			while (((c = *pat++) & M_MASK) != M_END) {
9324a421b63SDag-Erling Smørgrav 				if ((c & M_MASK) == M_CLASS) {
9334a421b63SDag-Erling Smørgrav 					Char idx = *pat & M_MASK;
9344a421b63SDag-Erling Smørgrav 					if (idx < NCCLASSES &&
9354a421b63SDag-Erling Smørgrav 					    cclasses[idx].isctype(k))
9364a421b63SDag-Erling Smørgrav 						ok = 1;
9374a421b63SDag-Erling Smørgrav 					++pat;
9384a421b63SDag-Erling Smørgrav 				}
93983d2307dSDag-Erling Smørgrav 				if ((*pat & M_MASK) == M_RNG) {
94083d2307dSDag-Erling Smørgrav 					if (c <= k && k <= pat[1])
94183d2307dSDag-Erling Smørgrav 						ok = 1;
94283d2307dSDag-Erling Smørgrav 					pat += 2;
94383d2307dSDag-Erling Smørgrav 				} else if (c == k)
94483d2307dSDag-Erling Smørgrav 					ok = 1;
9454a421b63SDag-Erling Smørgrav 			}
94683d2307dSDag-Erling Smørgrav 			if (ok == negate_range)
94783d2307dSDag-Erling Smørgrav 				return(0);
94883d2307dSDag-Erling Smørgrav 			break;
94983d2307dSDag-Erling Smørgrav 		default:
95083d2307dSDag-Erling Smørgrav 			if (*name++ != c)
95183d2307dSDag-Erling Smørgrav 				return(0);
95283d2307dSDag-Erling Smørgrav 			break;
95383d2307dSDag-Erling Smørgrav 		}
95483d2307dSDag-Erling Smørgrav 	}
95583d2307dSDag-Erling Smørgrav 	return(*name == EOS);
95683d2307dSDag-Erling Smørgrav }
95783d2307dSDag-Erling Smørgrav 
95883d2307dSDag-Erling Smørgrav /* Free allocated data belonging to a glob_t structure. */
95983d2307dSDag-Erling Smørgrav void
960021d409fSDag-Erling Smørgrav globfree(glob_t *pglob)
96183d2307dSDag-Erling Smørgrav {
962021d409fSDag-Erling Smørgrav 	int i;
963021d409fSDag-Erling Smørgrav 	char **pp;
96483d2307dSDag-Erling Smørgrav 
96583d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv != NULL) {
96683d2307dSDag-Erling Smørgrav 		pp = pglob->gl_pathv + pglob->gl_offs;
96783d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_pathc; i--; ++pp)
96883d2307dSDag-Erling Smørgrav 			if (*pp)
96983d2307dSDag-Erling Smørgrav 				free(*pp);
97083d2307dSDag-Erling Smørgrav 		free(pglob->gl_pathv);
97183d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
97283d2307dSDag-Erling Smørgrav 	}
9734a421b63SDag-Erling Smørgrav 	if (pglob->gl_statv != NULL) {
9744a421b63SDag-Erling Smørgrav 		for (i = 0; i < pglob->gl_pathc; i++) {
9754a421b63SDag-Erling Smørgrav 			if (pglob->gl_statv[i] != NULL)
9764a421b63SDag-Erling Smørgrav 				free(pglob->gl_statv[i]);
9774a421b63SDag-Erling Smørgrav 		}
9784a421b63SDag-Erling Smørgrav 		free(pglob->gl_statv);
9794a421b63SDag-Erling Smørgrav 		pglob->gl_statv = NULL;
9804a421b63SDag-Erling Smørgrav 	}
98183d2307dSDag-Erling Smørgrav }
98283d2307dSDag-Erling Smørgrav 
98383d2307dSDag-Erling Smørgrav static DIR *
984021d409fSDag-Erling Smørgrav g_opendir(Char *str, glob_t *pglob)
98583d2307dSDag-Erling Smørgrav {
98683d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
98783d2307dSDag-Erling Smørgrav 
98883d2307dSDag-Erling Smørgrav 	if (!*str)
9894b17dab0SDag-Erling Smørgrav 		strlcpy(buf, ".", sizeof buf);
99083d2307dSDag-Erling Smørgrav 	else {
99183d2307dSDag-Erling Smørgrav 		if (g_Ctoc(str, buf, sizeof(buf)))
99283d2307dSDag-Erling Smørgrav 			return(NULL);
99383d2307dSDag-Erling Smørgrav 	}
99483d2307dSDag-Erling Smørgrav 
99583d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
99683d2307dSDag-Erling Smørgrav 		return((*pglob->gl_opendir)(buf));
99783d2307dSDag-Erling Smørgrav 
99883d2307dSDag-Erling Smørgrav 	return(opendir(buf));
99983d2307dSDag-Erling Smørgrav }
100083d2307dSDag-Erling Smørgrav 
100183d2307dSDag-Erling Smørgrav static int
1002021d409fSDag-Erling Smørgrav g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
100383d2307dSDag-Erling Smørgrav {
100483d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
100583d2307dSDag-Erling Smørgrav 
100683d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
100783d2307dSDag-Erling Smørgrav 		return(-1);
100883d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
100983d2307dSDag-Erling Smørgrav 		return((*pglob->gl_lstat)(buf, sb));
101083d2307dSDag-Erling Smørgrav 	return(lstat(buf, sb));
101183d2307dSDag-Erling Smørgrav }
101283d2307dSDag-Erling Smørgrav 
101383d2307dSDag-Erling Smørgrav static int
1014021d409fSDag-Erling Smørgrav g_stat(Char *fn, struct stat *sb, glob_t *pglob)
101583d2307dSDag-Erling Smørgrav {
101683d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
101783d2307dSDag-Erling Smørgrav 
101883d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
101983d2307dSDag-Erling Smørgrav 		return(-1);
102083d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
102183d2307dSDag-Erling Smørgrav 		return((*pglob->gl_stat)(buf, sb));
102283d2307dSDag-Erling Smørgrav 	return(stat(buf, sb));
102383d2307dSDag-Erling Smørgrav }
102483d2307dSDag-Erling Smørgrav 
102583d2307dSDag-Erling Smørgrav static Char *
10264a421b63SDag-Erling Smørgrav g_strchr(const Char *str, int ch)
102783d2307dSDag-Erling Smørgrav {
102883d2307dSDag-Erling Smørgrav 	do {
102983d2307dSDag-Erling Smørgrav 		if (*str == ch)
10304a421b63SDag-Erling Smørgrav 			return ((Char *)str);
103183d2307dSDag-Erling Smørgrav 	} while (*str++);
103283d2307dSDag-Erling Smørgrav 	return (NULL);
103383d2307dSDag-Erling Smørgrav }
103483d2307dSDag-Erling Smørgrav 
103583d2307dSDag-Erling Smørgrav static int
1036021d409fSDag-Erling Smørgrav g_Ctoc(const Char *str, char *buf, u_int len)
103783d2307dSDag-Erling Smørgrav {
103883d2307dSDag-Erling Smørgrav 
103983d2307dSDag-Erling Smørgrav 	while (len--) {
104083d2307dSDag-Erling Smørgrav 		if ((*buf++ = *str++) == EOS)
104183d2307dSDag-Erling Smørgrav 			return (0);
104283d2307dSDag-Erling Smørgrav 	}
104383d2307dSDag-Erling Smørgrav 	return (1);
104483d2307dSDag-Erling Smørgrav }
104583d2307dSDag-Erling Smørgrav 
104683d2307dSDag-Erling Smørgrav #ifdef DEBUG
104783d2307dSDag-Erling Smørgrav static void
1048021d409fSDag-Erling Smørgrav qprintf(const char *str, Char *s)
104983d2307dSDag-Erling Smørgrav {
1050021d409fSDag-Erling Smørgrav 	Char *p;
105183d2307dSDag-Erling Smørgrav 
105283d2307dSDag-Erling Smørgrav 	(void)printf("%s:\n", str);
105383d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
105483d2307dSDag-Erling Smørgrav 		(void)printf("%c", CHAR(*p));
105583d2307dSDag-Erling Smørgrav 	(void)printf("\n");
105683d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
105783d2307dSDag-Erling Smørgrav 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
105883d2307dSDag-Erling Smørgrav 	(void)printf("\n");
105983d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
106083d2307dSDag-Erling Smørgrav 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
106183d2307dSDag-Erling Smørgrav 	(void)printf("\n");
106283d2307dSDag-Erling Smørgrav }
106383d2307dSDag-Erling Smørgrav #endif
106483d2307dSDag-Erling Smørgrav 
106583d2307dSDag-Erling Smørgrav #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
10664a421b63SDag-Erling Smørgrav           !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) */
1067