xref: /freebsd/crypto/openssh/openbsd-compat/glob.c (revision 83d2307d00b1f24dddf918c6651fb440d6863bf9)
183d2307dSDag-Erling Smørgrav /*
283d2307dSDag-Erling Smørgrav  * Copyright (c) 1989, 1993
383d2307dSDag-Erling Smørgrav  *	The Regents of the University of California.  All rights reserved.
483d2307dSDag-Erling Smørgrav  *
583d2307dSDag-Erling Smørgrav  * This code is derived from software contributed to Berkeley by
683d2307dSDag-Erling Smørgrav  * Guido van Rossum.
783d2307dSDag-Erling Smørgrav  *
883d2307dSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
983d2307dSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
1083d2307dSDag-Erling Smørgrav  * are met:
1183d2307dSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1283d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1383d2307dSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1483d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1583d2307dSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1683d2307dSDag-Erling Smørgrav  * 3. All advertising materials mentioning features or use of this software
1783d2307dSDag-Erling Smørgrav  *    must display the following acknowledgement:
1883d2307dSDag-Erling Smørgrav  *	This product includes software developed by the University of
1983d2307dSDag-Erling Smørgrav  *	California, Berkeley and its contributors.
2083d2307dSDag-Erling Smørgrav  * 4. Neither the name of the University nor the names of its contributors
2183d2307dSDag-Erling Smørgrav  *    may be used to endorse or promote products derived from this software
2283d2307dSDag-Erling Smørgrav  *    without specific prior written permission.
2383d2307dSDag-Erling Smørgrav  *
2483d2307dSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2583d2307dSDag-Erling Smørgrav  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2683d2307dSDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2783d2307dSDag-Erling Smørgrav  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2883d2307dSDag-Erling Smørgrav  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2983d2307dSDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3083d2307dSDag-Erling Smørgrav  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3183d2307dSDag-Erling Smørgrav  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3283d2307dSDag-Erling Smørgrav  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3383d2307dSDag-Erling Smørgrav  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3483d2307dSDag-Erling Smørgrav  * SUCH DAMAGE.
3583d2307dSDag-Erling Smørgrav  */
3683d2307dSDag-Erling Smørgrav 
3783d2307dSDag-Erling Smørgrav #include "includes.h"
3883d2307dSDag-Erling Smørgrav #include <ctype.h>
3983d2307dSDag-Erling Smørgrav 
4083d2307dSDag-Erling Smørgrav static long
4183d2307dSDag-Erling Smørgrav get_arg_max(void)
4283d2307dSDag-Erling Smørgrav {
4383d2307dSDag-Erling Smørgrav #ifdef ARG_MAX
4483d2307dSDag-Erling Smørgrav 	return(ARG_MAX);
4583d2307dSDag-Erling Smørgrav #elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
4683d2307dSDag-Erling Smørgrav 	return(sysconf(_SC_ARG_MAX));
4783d2307dSDag-Erling Smørgrav #else
4883d2307dSDag-Erling Smørgrav 	return(256); /* XXX: arbitrary */
4983d2307dSDag-Erling Smørgrav #endif
5083d2307dSDag-Erling Smørgrav }
5183d2307dSDag-Erling Smørgrav 
5283d2307dSDag-Erling Smørgrav #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
5383d2307dSDag-Erling Smørgrav     !defined(GLOB_HAS_GL_MATCHC)
5483d2307dSDag-Erling Smørgrav 
5583d2307dSDag-Erling Smørgrav #if defined(LIBC_SCCS) && !defined(lint)
5683d2307dSDag-Erling Smørgrav #if 0
5783d2307dSDag-Erling Smørgrav static char sccsid[] = "@(#)glob.c	8.3 (Berkeley) 10/13/93";
5883d2307dSDag-Erling Smørgrav #else
5983d2307dSDag-Erling Smørgrav static char rcsid[] = "$OpenBSD: glob.c,v 1.16 2001/04/05 18:36:12 deraadt Exp $";
6083d2307dSDag-Erling Smørgrav #endif
6183d2307dSDag-Erling Smørgrav #endif /* LIBC_SCCS and not lint */
6283d2307dSDag-Erling Smørgrav 
6383d2307dSDag-Erling Smørgrav /*
6483d2307dSDag-Erling Smørgrav  * glob(3) -- a superset of the one defined in POSIX 1003.2.
6583d2307dSDag-Erling Smørgrav  *
6683d2307dSDag-Erling Smørgrav  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
6783d2307dSDag-Erling Smørgrav  *
6883d2307dSDag-Erling Smørgrav  * Optional extra services, controlled by flags not defined by POSIX:
6983d2307dSDag-Erling Smørgrav  *
7083d2307dSDag-Erling Smørgrav  * GLOB_QUOTE:
7183d2307dSDag-Erling Smørgrav  *	Escaping convention: \ inhibits any special meaning the following
7283d2307dSDag-Erling Smørgrav  *	character might have (except \ at end of string is retained).
7383d2307dSDag-Erling Smørgrav  * GLOB_MAGCHAR:
7483d2307dSDag-Erling Smørgrav  *	Set in gl_flags if pattern contained a globbing character.
7583d2307dSDag-Erling Smørgrav  * GLOB_NOMAGIC:
7683d2307dSDag-Erling Smørgrav  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
7783d2307dSDag-Erling Smørgrav  *	not contain any magic characters.  [Used in csh style globbing]
7883d2307dSDag-Erling Smørgrav  * GLOB_ALTDIRFUNC:
7983d2307dSDag-Erling Smørgrav  *	Use alternately specified directory access functions.
8083d2307dSDag-Erling Smørgrav  * GLOB_TILDE:
8183d2307dSDag-Erling Smørgrav  *	expand ~user/foo to the /home/dir/of/user/foo
8283d2307dSDag-Erling Smørgrav  * GLOB_BRACE:
8383d2307dSDag-Erling Smørgrav  *	expand {1,2}{a,b} to 1a 1b 2a 2b
8483d2307dSDag-Erling Smørgrav  * gl_matchc:
8583d2307dSDag-Erling Smørgrav  *	Number of matches in the current invocation of glob.
8683d2307dSDag-Erling Smørgrav  */
8783d2307dSDag-Erling Smørgrav 
8883d2307dSDag-Erling Smørgrav 
8983d2307dSDag-Erling Smørgrav #define	DOLLAR		'$'
9083d2307dSDag-Erling Smørgrav #define	DOT		'.'
9183d2307dSDag-Erling Smørgrav #define	EOS		'\0'
9283d2307dSDag-Erling Smørgrav #define	LBRACKET	'['
9383d2307dSDag-Erling Smørgrav #define	NOT		'!'
9483d2307dSDag-Erling Smørgrav #define	QUESTION	'?'
9583d2307dSDag-Erling Smørgrav #define	QUOTE		'\\'
9683d2307dSDag-Erling Smørgrav #define	RANGE		'-'
9783d2307dSDag-Erling Smørgrav #define	RBRACKET	']'
9883d2307dSDag-Erling Smørgrav #define	SEP		'/'
9983d2307dSDag-Erling Smørgrav #define	STAR		'*'
10083d2307dSDag-Erling Smørgrav #define	TILDE		'~'
10183d2307dSDag-Erling Smørgrav #define	UNDERSCORE	'_'
10283d2307dSDag-Erling Smørgrav #define	LBRACE		'{'
10383d2307dSDag-Erling Smørgrav #define	RBRACE		'}'
10483d2307dSDag-Erling Smørgrav #define	SLASH		'/'
10583d2307dSDag-Erling Smørgrav #define	COMMA		','
10683d2307dSDag-Erling Smørgrav 
10783d2307dSDag-Erling Smørgrav #ifndef DEBUG
10883d2307dSDag-Erling Smørgrav 
10983d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x8000
11083d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x4000
11183d2307dSDag-Erling Smørgrav #define	M_MASK		0xffff
11283d2307dSDag-Erling Smørgrav #define	M_ASCII		0x00ff
11383d2307dSDag-Erling Smørgrav 
11483d2307dSDag-Erling Smørgrav typedef u_short Char;
11583d2307dSDag-Erling Smørgrav 
11683d2307dSDag-Erling Smørgrav #else
11783d2307dSDag-Erling Smørgrav 
11883d2307dSDag-Erling Smørgrav #define	M_QUOTE		0x80
11983d2307dSDag-Erling Smørgrav #define	M_PROTECT	0x40
12083d2307dSDag-Erling Smørgrav #define	M_MASK		0xff
12183d2307dSDag-Erling Smørgrav #define	M_ASCII		0x7f
12283d2307dSDag-Erling Smørgrav 
12383d2307dSDag-Erling Smørgrav typedef char Char;
12483d2307dSDag-Erling Smørgrav 
12583d2307dSDag-Erling Smørgrav #endif
12683d2307dSDag-Erling Smørgrav 
12783d2307dSDag-Erling Smørgrav 
12883d2307dSDag-Erling Smørgrav #define	CHAR(c)		((Char)((c)&M_ASCII))
12983d2307dSDag-Erling Smørgrav #define	META(c)		((Char)((c)|M_QUOTE))
13083d2307dSDag-Erling Smørgrav #define	M_ALL		META('*')
13183d2307dSDag-Erling Smørgrav #define	M_END		META(']')
13283d2307dSDag-Erling Smørgrav #define	M_NOT		META('!')
13383d2307dSDag-Erling Smørgrav #define	M_ONE		META('?')
13483d2307dSDag-Erling Smørgrav #define	M_RNG		META('-')
13583d2307dSDag-Erling Smørgrav #define	M_SET		META('[')
13683d2307dSDag-Erling Smørgrav #define	ismeta(c)	(((c)&M_QUOTE) != 0)
13783d2307dSDag-Erling Smørgrav 
13883d2307dSDag-Erling Smørgrav 
13983d2307dSDag-Erling Smørgrav static int	 compare __P((const void *, const void *));
14083d2307dSDag-Erling Smørgrav static int	 g_Ctoc __P((const Char *, char *, u_int));
14183d2307dSDag-Erling Smørgrav static int	 g_lstat __P((Char *, struct stat *, glob_t *));
14283d2307dSDag-Erling Smørgrav static DIR	*g_opendir __P((Char *, glob_t *));
14383d2307dSDag-Erling Smørgrav static Char	*g_strchr __P((Char *, int));
14483d2307dSDag-Erling Smørgrav static int	 g_stat __P((Char *, struct stat *, glob_t *));
14583d2307dSDag-Erling Smørgrav static int	 glob0 __P((const Char *, glob_t *));
14683d2307dSDag-Erling Smørgrav static int	 glob1 __P((Char *, Char *, glob_t *, size_t *));
14783d2307dSDag-Erling Smørgrav static int	 glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *,
14883d2307dSDag-Erling Smørgrav 		    glob_t *, size_t *));
14983d2307dSDag-Erling Smørgrav static int	 glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *,
15083d2307dSDag-Erling Smørgrav 		    Char *, Char *, glob_t *, size_t *));
15183d2307dSDag-Erling Smørgrav static int	 globextend __P((const Char *, glob_t *, size_t *));
15283d2307dSDag-Erling Smørgrav static const Char *
15383d2307dSDag-Erling Smørgrav 		 globtilde __P((const Char *, Char *, size_t, glob_t *));
15483d2307dSDag-Erling Smørgrav static int	 globexp1 __P((const Char *, glob_t *));
15583d2307dSDag-Erling Smørgrav static int	 globexp2 __P((const Char *, const Char *, glob_t *, int *));
15683d2307dSDag-Erling Smørgrav static int	 match __P((Char *, Char *, Char *));
15783d2307dSDag-Erling Smørgrav #ifdef DEBUG
15883d2307dSDag-Erling Smørgrav static void	 qprintf __P((const char *, Char *));
15983d2307dSDag-Erling Smørgrav #endif
16083d2307dSDag-Erling Smørgrav 
16183d2307dSDag-Erling Smørgrav int
16283d2307dSDag-Erling Smørgrav glob(pattern, flags, errfunc, pglob)
16383d2307dSDag-Erling Smørgrav 	const char *pattern;
16483d2307dSDag-Erling Smørgrav 	int flags, (*errfunc) __P((const char *, int));
16583d2307dSDag-Erling Smørgrav 	glob_t *pglob;
16683d2307dSDag-Erling Smørgrav {
16783d2307dSDag-Erling Smørgrav 	const u_char *patnext;
16883d2307dSDag-Erling Smørgrav 	int c;
16983d2307dSDag-Erling Smørgrav 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
17083d2307dSDag-Erling Smørgrav 
17183d2307dSDag-Erling Smørgrav 	patnext = (u_char *) pattern;
17283d2307dSDag-Erling Smørgrav 	if (!(flags & GLOB_APPEND)) {
17383d2307dSDag-Erling Smørgrav 		pglob->gl_pathc = 0;
17483d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
17583d2307dSDag-Erling Smørgrav 		if (!(flags & GLOB_DOOFFS))
17683d2307dSDag-Erling Smørgrav 			pglob->gl_offs = 0;
17783d2307dSDag-Erling Smørgrav 	}
17883d2307dSDag-Erling Smørgrav 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
17983d2307dSDag-Erling Smørgrav 	pglob->gl_errfunc = errfunc;
18083d2307dSDag-Erling Smørgrav 	pglob->gl_matchc = 0;
18183d2307dSDag-Erling Smørgrav 
18283d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
18383d2307dSDag-Erling Smørgrav 	bufend = bufnext + MAXPATHLEN - 1;
18483d2307dSDag-Erling Smørgrav 	if (flags & GLOB_NOESCAPE)
18583d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
18683d2307dSDag-Erling Smørgrav 			*bufnext++ = c;
18783d2307dSDag-Erling Smørgrav 	else {
18883d2307dSDag-Erling Smørgrav 		/* Protect the quoted characters. */
18983d2307dSDag-Erling Smørgrav 		while (bufnext < bufend && (c = *patnext++) != EOS)
19083d2307dSDag-Erling Smørgrav 			if (c == QUOTE) {
19183d2307dSDag-Erling Smørgrav 				if ((c = *patnext++) == EOS) {
19283d2307dSDag-Erling Smørgrav 					c = QUOTE;
19383d2307dSDag-Erling Smørgrav 					--patnext;
19483d2307dSDag-Erling Smørgrav 				}
19583d2307dSDag-Erling Smørgrav 				*bufnext++ = c | M_PROTECT;
19683d2307dSDag-Erling Smørgrav 			} else
19783d2307dSDag-Erling Smørgrav 				*bufnext++ = c;
19883d2307dSDag-Erling Smørgrav 	}
19983d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
20083d2307dSDag-Erling Smørgrav 
20183d2307dSDag-Erling Smørgrav 	if (flags & GLOB_BRACE)
20283d2307dSDag-Erling Smørgrav 		return globexp1(patbuf, pglob);
20383d2307dSDag-Erling Smørgrav 	else
20483d2307dSDag-Erling Smørgrav 		return glob0(patbuf, pglob);
20583d2307dSDag-Erling Smørgrav }
20683d2307dSDag-Erling Smørgrav 
20783d2307dSDag-Erling Smørgrav /*
20883d2307dSDag-Erling Smørgrav  * Expand recursively a glob {} pattern. When there is no more expansion
20983d2307dSDag-Erling Smørgrav  * invoke the standard globbing routine to glob the rest of the magic
21083d2307dSDag-Erling Smørgrav  * characters
21183d2307dSDag-Erling Smørgrav  */
21283d2307dSDag-Erling Smørgrav static int
21383d2307dSDag-Erling Smørgrav globexp1(pattern, pglob)
21483d2307dSDag-Erling Smørgrav 	const Char *pattern;
21583d2307dSDag-Erling Smørgrav 	glob_t *pglob;
21683d2307dSDag-Erling Smørgrav {
21783d2307dSDag-Erling Smørgrav 	const Char* ptr = pattern;
21883d2307dSDag-Erling Smørgrav 	int rv;
21983d2307dSDag-Erling Smørgrav 
22083d2307dSDag-Erling Smørgrav 	/* Protect a single {}, for find(1), like csh */
22183d2307dSDag-Erling Smørgrav 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
22283d2307dSDag-Erling Smørgrav 		return glob0(pattern, pglob);
22383d2307dSDag-Erling Smørgrav 
22483d2307dSDag-Erling Smørgrav 	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
22583d2307dSDag-Erling Smørgrav 		if (!globexp2(ptr, pattern, pglob, &rv))
22683d2307dSDag-Erling Smørgrav 			return rv;
22783d2307dSDag-Erling Smørgrav 
22883d2307dSDag-Erling Smørgrav 	return glob0(pattern, pglob);
22983d2307dSDag-Erling Smørgrav }
23083d2307dSDag-Erling Smørgrav 
23183d2307dSDag-Erling Smørgrav 
23283d2307dSDag-Erling Smørgrav /*
23383d2307dSDag-Erling Smørgrav  * Recursive brace globbing helper. Tries to expand a single brace.
23483d2307dSDag-Erling Smørgrav  * If it succeeds then it invokes globexp1 with the new pattern.
23583d2307dSDag-Erling Smørgrav  * If it fails then it tries to glob the rest of the pattern and returns.
23683d2307dSDag-Erling Smørgrav  */
23783d2307dSDag-Erling Smørgrav static int
23883d2307dSDag-Erling Smørgrav globexp2(ptr, pattern, pglob, rv)
23983d2307dSDag-Erling Smørgrav 	const Char *ptr, *pattern;
24083d2307dSDag-Erling Smørgrav 	glob_t *pglob;
24183d2307dSDag-Erling Smørgrav 	int *rv;
24283d2307dSDag-Erling Smørgrav {
24383d2307dSDag-Erling Smørgrav 	int     i;
24483d2307dSDag-Erling Smørgrav 	Char   *lm, *ls;
24583d2307dSDag-Erling Smørgrav 	const Char *pe, *pm, *pl;
24683d2307dSDag-Erling Smørgrav 	Char    patbuf[MAXPATHLEN];
24783d2307dSDag-Erling Smørgrav 
24883d2307dSDag-Erling Smørgrav 	/* copy part up to the brace */
24983d2307dSDag-Erling Smørgrav 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
25083d2307dSDag-Erling Smørgrav 		;
25183d2307dSDag-Erling Smørgrav 	*lm = EOS;
25283d2307dSDag-Erling Smørgrav 	ls = lm;
25383d2307dSDag-Erling Smørgrav 
25483d2307dSDag-Erling Smørgrav 	/* Find the balanced brace */
25583d2307dSDag-Erling Smørgrav 	for (i = 0, pe = ++ptr; *pe; pe++)
25683d2307dSDag-Erling Smørgrav 		if (*pe == LBRACKET) {
25783d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
25883d2307dSDag-Erling Smørgrav 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
25983d2307dSDag-Erling Smørgrav 				;
26083d2307dSDag-Erling Smørgrav 			if (*pe == EOS) {
26183d2307dSDag-Erling Smørgrav 				/*
26283d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
26383d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
26483d2307dSDag-Erling Smørgrav 				 */
26583d2307dSDag-Erling Smørgrav 				pe = pm;
26683d2307dSDag-Erling Smørgrav 			}
26783d2307dSDag-Erling Smørgrav 		} else if (*pe == LBRACE)
26883d2307dSDag-Erling Smørgrav 			i++;
26983d2307dSDag-Erling Smørgrav 		else if (*pe == RBRACE) {
27083d2307dSDag-Erling Smørgrav 			if (i == 0)
27183d2307dSDag-Erling Smørgrav 				break;
27283d2307dSDag-Erling Smørgrav 			i--;
27383d2307dSDag-Erling Smørgrav 		}
27483d2307dSDag-Erling Smørgrav 
27583d2307dSDag-Erling Smørgrav 	/* Non matching braces; just glob the pattern */
27683d2307dSDag-Erling Smørgrav 	if (i != 0 || *pe == EOS) {
27783d2307dSDag-Erling Smørgrav 		*rv = glob0(patbuf, pglob);
27883d2307dSDag-Erling Smørgrav 		return 0;
27983d2307dSDag-Erling Smørgrav 	}
28083d2307dSDag-Erling Smørgrav 
28183d2307dSDag-Erling Smørgrav 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
28283d2307dSDag-Erling Smørgrav 		switch (*pm) {
28383d2307dSDag-Erling Smørgrav 		case LBRACKET:
28483d2307dSDag-Erling Smørgrav 			/* Ignore everything between [] */
28583d2307dSDag-Erling Smørgrav 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
28683d2307dSDag-Erling Smørgrav 				;
28783d2307dSDag-Erling Smørgrav 			if (*pm == EOS) {
28883d2307dSDag-Erling Smørgrav 				/*
28983d2307dSDag-Erling Smørgrav 				 * We could not find a matching RBRACKET.
29083d2307dSDag-Erling Smørgrav 				 * Ignore and just look for RBRACE
29183d2307dSDag-Erling Smørgrav 				 */
29283d2307dSDag-Erling Smørgrav 				pm = pl;
29383d2307dSDag-Erling Smørgrav 			}
29483d2307dSDag-Erling Smørgrav 			break;
29583d2307dSDag-Erling Smørgrav 
29683d2307dSDag-Erling Smørgrav 		case LBRACE:
29783d2307dSDag-Erling Smørgrav 			i++;
29883d2307dSDag-Erling Smørgrav 			break;
29983d2307dSDag-Erling Smørgrav 
30083d2307dSDag-Erling Smørgrav 		case RBRACE:
30183d2307dSDag-Erling Smørgrav 			if (i) {
30283d2307dSDag-Erling Smørgrav 				i--;
30383d2307dSDag-Erling Smørgrav 				break;
30483d2307dSDag-Erling Smørgrav 			}
30583d2307dSDag-Erling Smørgrav 			/* FALLTHROUGH */
30683d2307dSDag-Erling Smørgrav 		case COMMA:
30783d2307dSDag-Erling Smørgrav 			if (i && *pm == COMMA)
30883d2307dSDag-Erling Smørgrav 				break;
30983d2307dSDag-Erling Smørgrav 			else {
31083d2307dSDag-Erling Smørgrav 				/* Append the current string */
31183d2307dSDag-Erling Smørgrav 				for (lm = ls; (pl < pm); *lm++ = *pl++)
31283d2307dSDag-Erling Smørgrav 					;
31383d2307dSDag-Erling Smørgrav 
31483d2307dSDag-Erling Smørgrav 				/*
31583d2307dSDag-Erling Smørgrav 				 * Append the rest of the pattern after the
31683d2307dSDag-Erling Smørgrav 				 * closing brace
31783d2307dSDag-Erling Smørgrav 				 */
31883d2307dSDag-Erling Smørgrav 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
31983d2307dSDag-Erling Smørgrav 					;
32083d2307dSDag-Erling Smørgrav 
32183d2307dSDag-Erling Smørgrav 				/* Expand the current pattern */
32283d2307dSDag-Erling Smørgrav #ifdef DEBUG
32383d2307dSDag-Erling Smørgrav 				qprintf("globexp2:", patbuf);
32483d2307dSDag-Erling Smørgrav #endif
32583d2307dSDag-Erling Smørgrav 				*rv = globexp1(patbuf, pglob);
32683d2307dSDag-Erling Smørgrav 
32783d2307dSDag-Erling Smørgrav 				/* move after the comma, to the next string */
32883d2307dSDag-Erling Smørgrav 				pl = pm + 1;
32983d2307dSDag-Erling Smørgrav 			}
33083d2307dSDag-Erling Smørgrav 			break;
33183d2307dSDag-Erling Smørgrav 
33283d2307dSDag-Erling Smørgrav 		default:
33383d2307dSDag-Erling Smørgrav 			break;
33483d2307dSDag-Erling Smørgrav 		}
33583d2307dSDag-Erling Smørgrav 	}
33683d2307dSDag-Erling Smørgrav 	*rv = 0;
33783d2307dSDag-Erling Smørgrav 	return 0;
33883d2307dSDag-Erling Smørgrav }
33983d2307dSDag-Erling Smørgrav 
34083d2307dSDag-Erling Smørgrav 
34183d2307dSDag-Erling Smørgrav 
34283d2307dSDag-Erling Smørgrav /*
34383d2307dSDag-Erling Smørgrav  * expand tilde from the passwd file.
34483d2307dSDag-Erling Smørgrav  */
34583d2307dSDag-Erling Smørgrav static const Char *
34683d2307dSDag-Erling Smørgrav globtilde(pattern, patbuf, patbuf_len, pglob)
34783d2307dSDag-Erling Smørgrav 	const Char *pattern;
34883d2307dSDag-Erling Smørgrav 	Char *patbuf;
34983d2307dSDag-Erling Smørgrav 	size_t patbuf_len;
35083d2307dSDag-Erling Smørgrav 	glob_t *pglob;
35183d2307dSDag-Erling Smørgrav {
35283d2307dSDag-Erling Smørgrav 	struct passwd *pwd;
35383d2307dSDag-Erling Smørgrav 	char *h;
35483d2307dSDag-Erling Smørgrav 	const Char *p;
35583d2307dSDag-Erling Smørgrav 	Char *b, *eb;
35683d2307dSDag-Erling Smørgrav 
35783d2307dSDag-Erling Smørgrav 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
35883d2307dSDag-Erling Smørgrav 		return pattern;
35983d2307dSDag-Erling Smørgrav 
36083d2307dSDag-Erling Smørgrav 	/* Copy up to the end of the string or / */
36183d2307dSDag-Erling Smørgrav 	eb = &patbuf[patbuf_len - 1];
36283d2307dSDag-Erling Smørgrav 	for (p = pattern + 1, h = (char *) patbuf;
36383d2307dSDag-Erling Smørgrav 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
36483d2307dSDag-Erling Smørgrav 		;
36583d2307dSDag-Erling Smørgrav 
36683d2307dSDag-Erling Smørgrav 	*h = EOS;
36783d2307dSDag-Erling Smørgrav 
36883d2307dSDag-Erling Smørgrav #if 0
36983d2307dSDag-Erling Smørgrav 	if (h == (char *)eb)
37083d2307dSDag-Erling Smørgrav 		return what;
37183d2307dSDag-Erling Smørgrav #endif
37283d2307dSDag-Erling Smørgrav 
37383d2307dSDag-Erling Smørgrav 	if (((char *) patbuf)[0] == EOS) {
37483d2307dSDag-Erling Smørgrav 		/*
37583d2307dSDag-Erling Smørgrav 		 * handle a plain ~ or ~/ by expanding $HOME
37683d2307dSDag-Erling Smørgrav 		 * first and then trying the password file
37783d2307dSDag-Erling Smørgrav 		 */
37883d2307dSDag-Erling Smørgrav #if 0
37983d2307dSDag-Erling Smørgrav 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
38083d2307dSDag-Erling Smørgrav #endif
38183d2307dSDag-Erling Smørgrav 		if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
38283d2307dSDag-Erling Smørgrav 			if ((pwd = getpwuid(getuid())) == NULL)
38383d2307dSDag-Erling Smørgrav 				return pattern;
38483d2307dSDag-Erling Smørgrav 			else
38583d2307dSDag-Erling Smørgrav 				h = pwd->pw_dir;
38683d2307dSDag-Erling Smørgrav 		}
38783d2307dSDag-Erling Smørgrav 	} else {
38883d2307dSDag-Erling Smørgrav 		/*
38983d2307dSDag-Erling Smørgrav 		 * Expand a ~user
39083d2307dSDag-Erling Smørgrav 		 */
39183d2307dSDag-Erling Smørgrav 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
39283d2307dSDag-Erling Smørgrav 			return pattern;
39383d2307dSDag-Erling Smørgrav 		else
39483d2307dSDag-Erling Smørgrav 			h = pwd->pw_dir;
39583d2307dSDag-Erling Smørgrav 	}
39683d2307dSDag-Erling Smørgrav 
39783d2307dSDag-Erling Smørgrav 	/* Copy the home directory */
39883d2307dSDag-Erling Smørgrav 	for (b = patbuf; b < eb && *h; *b++ = *h++)
39983d2307dSDag-Erling Smørgrav 		;
40083d2307dSDag-Erling Smørgrav 
40183d2307dSDag-Erling Smørgrav 	/* Append the rest of the pattern */
40283d2307dSDag-Erling Smørgrav 	while (b < eb && (*b++ = *p++) != EOS)
40383d2307dSDag-Erling Smørgrav 		;
40483d2307dSDag-Erling Smørgrav 	*b = EOS;
40583d2307dSDag-Erling Smørgrav 
40683d2307dSDag-Erling Smørgrav 	return patbuf;
40783d2307dSDag-Erling Smørgrav }
40883d2307dSDag-Erling Smørgrav 
40983d2307dSDag-Erling Smørgrav 
41083d2307dSDag-Erling Smørgrav /*
41183d2307dSDag-Erling Smørgrav  * The main glob() routine: compiles the pattern (optionally processing
41283d2307dSDag-Erling Smørgrav  * quotes), calls glob1() to do the real pattern matching, and finally
41383d2307dSDag-Erling Smørgrav  * sorts the list (unless unsorted operation is requested).  Returns 0
41483d2307dSDag-Erling Smørgrav  * if things went well, nonzero if errors occurred.  It is not an error
41583d2307dSDag-Erling Smørgrav  * to find no matches.
41683d2307dSDag-Erling Smørgrav  */
41783d2307dSDag-Erling Smørgrav static int
41883d2307dSDag-Erling Smørgrav glob0(pattern, pglob)
41983d2307dSDag-Erling Smørgrav 	const Char *pattern;
42083d2307dSDag-Erling Smørgrav 	glob_t *pglob;
42183d2307dSDag-Erling Smørgrav {
42283d2307dSDag-Erling Smørgrav 	const Char *qpatnext;
42383d2307dSDag-Erling Smørgrav 	int c, err, oldpathc;
42483d2307dSDag-Erling Smørgrav 	Char *bufnext, patbuf[MAXPATHLEN];
42583d2307dSDag-Erling Smørgrav 	size_t limit = 0;
42683d2307dSDag-Erling Smørgrav 
42783d2307dSDag-Erling Smørgrav 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
42883d2307dSDag-Erling Smørgrav 	oldpathc = pglob->gl_pathc;
42983d2307dSDag-Erling Smørgrav 	bufnext = patbuf;
43083d2307dSDag-Erling Smørgrav 
43183d2307dSDag-Erling Smørgrav 	/* We don't need to check for buffer overflow any more. */
43283d2307dSDag-Erling Smørgrav 	while ((c = *qpatnext++) != EOS) {
43383d2307dSDag-Erling Smørgrav 		switch (c) {
43483d2307dSDag-Erling Smørgrav 		case LBRACKET:
43583d2307dSDag-Erling Smørgrav 			c = *qpatnext;
43683d2307dSDag-Erling Smørgrav 			if (c == NOT)
43783d2307dSDag-Erling Smørgrav 				++qpatnext;
43883d2307dSDag-Erling Smørgrav 			if (*qpatnext == EOS ||
43983d2307dSDag-Erling Smørgrav 			    g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
44083d2307dSDag-Erling Smørgrav 				*bufnext++ = LBRACKET;
44183d2307dSDag-Erling Smørgrav 				if (c == NOT)
44283d2307dSDag-Erling Smørgrav 					--qpatnext;
44383d2307dSDag-Erling Smørgrav 				break;
44483d2307dSDag-Erling Smørgrav 			}
44583d2307dSDag-Erling Smørgrav 			*bufnext++ = M_SET;
44683d2307dSDag-Erling Smørgrav 			if (c == NOT)
44783d2307dSDag-Erling Smørgrav 				*bufnext++ = M_NOT;
44883d2307dSDag-Erling Smørgrav 			c = *qpatnext++;
44983d2307dSDag-Erling Smørgrav 			do {
45083d2307dSDag-Erling Smørgrav 				*bufnext++ = CHAR(c);
45183d2307dSDag-Erling Smørgrav 				if (*qpatnext == RANGE &&
45283d2307dSDag-Erling Smørgrav 				    (c = qpatnext[1]) != RBRACKET) {
45383d2307dSDag-Erling Smørgrav 					*bufnext++ = M_RNG;
45483d2307dSDag-Erling Smørgrav 					*bufnext++ = CHAR(c);
45583d2307dSDag-Erling Smørgrav 					qpatnext += 2;
45683d2307dSDag-Erling Smørgrav 				}
45783d2307dSDag-Erling Smørgrav 			} while ((c = *qpatnext++) != RBRACKET);
45883d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
45983d2307dSDag-Erling Smørgrav 			*bufnext++ = M_END;
46083d2307dSDag-Erling Smørgrav 			break;
46183d2307dSDag-Erling Smørgrav 		case QUESTION:
46283d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
46383d2307dSDag-Erling Smørgrav 			*bufnext++ = M_ONE;
46483d2307dSDag-Erling Smørgrav 			break;
46583d2307dSDag-Erling Smørgrav 		case STAR:
46683d2307dSDag-Erling Smørgrav 			pglob->gl_flags |= GLOB_MAGCHAR;
46783d2307dSDag-Erling Smørgrav 			/* collapse adjacent stars to one,
46883d2307dSDag-Erling Smørgrav 			 * to avoid exponential behavior
46983d2307dSDag-Erling Smørgrav 			 */
47083d2307dSDag-Erling Smørgrav 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
47183d2307dSDag-Erling Smørgrav 				*bufnext++ = M_ALL;
47283d2307dSDag-Erling Smørgrav 			break;
47383d2307dSDag-Erling Smørgrav 		default:
47483d2307dSDag-Erling Smørgrav 			*bufnext++ = CHAR(c);
47583d2307dSDag-Erling Smørgrav 			break;
47683d2307dSDag-Erling Smørgrav 		}
47783d2307dSDag-Erling Smørgrav 	}
47883d2307dSDag-Erling Smørgrav 	*bufnext = EOS;
47983d2307dSDag-Erling Smørgrav #ifdef DEBUG
48083d2307dSDag-Erling Smørgrav 	qprintf("glob0:", patbuf);
48183d2307dSDag-Erling Smørgrav #endif
48283d2307dSDag-Erling Smørgrav 
48383d2307dSDag-Erling Smørgrav 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
48483d2307dSDag-Erling Smørgrav 		return(err);
48583d2307dSDag-Erling Smørgrav 
48683d2307dSDag-Erling Smørgrav 	/*
48783d2307dSDag-Erling Smørgrav 	 * If there was no match we are going to append the pattern
48883d2307dSDag-Erling Smørgrav 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
48983d2307dSDag-Erling Smørgrav 	 * and the pattern did not contain any magic characters
49083d2307dSDag-Erling Smørgrav 	 * GLOB_NOMAGIC is there just for compatibility with csh.
49183d2307dSDag-Erling Smørgrav 	 */
49283d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathc == oldpathc) {
49383d2307dSDag-Erling Smørgrav 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
49483d2307dSDag-Erling Smørgrav 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
49583d2307dSDag-Erling Smørgrav 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
49683d2307dSDag-Erling Smørgrav 			return(globextend(pattern, pglob, &limit));
49783d2307dSDag-Erling Smørgrav 		else
49883d2307dSDag-Erling Smørgrav 			return(GLOB_NOMATCH);
49983d2307dSDag-Erling Smørgrav 	}
50083d2307dSDag-Erling Smørgrav 	if (!(pglob->gl_flags & GLOB_NOSORT))
50183d2307dSDag-Erling Smørgrav 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
50283d2307dSDag-Erling Smørgrav 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
50383d2307dSDag-Erling Smørgrav 	return(0);
50483d2307dSDag-Erling Smørgrav }
50583d2307dSDag-Erling Smørgrav 
50683d2307dSDag-Erling Smørgrav static int
50783d2307dSDag-Erling Smørgrav compare(p, q)
50883d2307dSDag-Erling Smørgrav 	const void *p, *q;
50983d2307dSDag-Erling Smørgrav {
51083d2307dSDag-Erling Smørgrav 	return(strcmp(*(char **)p, *(char **)q));
51183d2307dSDag-Erling Smørgrav }
51283d2307dSDag-Erling Smørgrav 
51383d2307dSDag-Erling Smørgrav static int
51483d2307dSDag-Erling Smørgrav glob1(pattern, pattern_last, pglob, limitp)
51583d2307dSDag-Erling Smørgrav 	Char *pattern, *pattern_last;
51683d2307dSDag-Erling Smørgrav 	glob_t *pglob;
51783d2307dSDag-Erling Smørgrav 	size_t *limitp;
51883d2307dSDag-Erling Smørgrav {
51983d2307dSDag-Erling Smørgrav 	Char pathbuf[MAXPATHLEN];
52083d2307dSDag-Erling Smørgrav 
52183d2307dSDag-Erling Smørgrav 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
52283d2307dSDag-Erling Smørgrav 	if (*pattern == EOS)
52383d2307dSDag-Erling Smørgrav 		return(0);
52483d2307dSDag-Erling Smørgrav 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
52583d2307dSDag-Erling Smørgrav 	    pathbuf, pathbuf+MAXPATHLEN-1,
52683d2307dSDag-Erling Smørgrav 	    pattern, pattern_last, pglob, limitp));
52783d2307dSDag-Erling Smørgrav }
52883d2307dSDag-Erling Smørgrav 
52983d2307dSDag-Erling Smørgrav /*
53083d2307dSDag-Erling Smørgrav  * The functions glob2 and glob3 are mutually recursive; there is one level
53183d2307dSDag-Erling Smørgrav  * of recursion for each segment in the pattern that contains one or more
53283d2307dSDag-Erling Smørgrav  * meta characters.
53383d2307dSDag-Erling Smørgrav  */
53483d2307dSDag-Erling Smørgrav static int
53583d2307dSDag-Erling Smørgrav glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
53683d2307dSDag-Erling Smørgrav     pattern_last, pglob, limitp)
53783d2307dSDag-Erling Smørgrav 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
53883d2307dSDag-Erling Smørgrav 	Char *pattern, *pattern_last;
53983d2307dSDag-Erling Smørgrav 	glob_t *pglob;
54083d2307dSDag-Erling Smørgrav 	size_t *limitp;
54183d2307dSDag-Erling Smørgrav {
54283d2307dSDag-Erling Smørgrav 	struct stat sb;
54383d2307dSDag-Erling Smørgrav 	Char *p, *q;
54483d2307dSDag-Erling Smørgrav 	int anymeta;
54583d2307dSDag-Erling Smørgrav 
54683d2307dSDag-Erling Smørgrav 	/*
54783d2307dSDag-Erling Smørgrav 	 * Loop over pattern segments until end of pattern or until
54883d2307dSDag-Erling Smørgrav 	 * segment with meta character found.
54983d2307dSDag-Erling Smørgrav 	 */
55083d2307dSDag-Erling Smørgrav 	for (anymeta = 0;;) {
55183d2307dSDag-Erling Smørgrav 		if (*pattern == EOS) {		/* End of pattern? */
55283d2307dSDag-Erling Smørgrav 			*pathend = EOS;
55383d2307dSDag-Erling Smørgrav 			if (g_lstat(pathbuf, &sb, pglob))
55483d2307dSDag-Erling Smørgrav 				return(0);
55583d2307dSDag-Erling Smørgrav 
55683d2307dSDag-Erling Smørgrav 			if (((pglob->gl_flags & GLOB_MARK) &&
55783d2307dSDag-Erling Smørgrav 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
55883d2307dSDag-Erling Smørgrav 			    (S_ISLNK(sb.st_mode) &&
55983d2307dSDag-Erling Smørgrav 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
56083d2307dSDag-Erling Smørgrav 			    S_ISDIR(sb.st_mode)))) {
56183d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
56283d2307dSDag-Erling Smørgrav 					return (1);
56383d2307dSDag-Erling Smørgrav 				*pathend++ = SEP;
56483d2307dSDag-Erling Smørgrav 				*pathend = EOS;
56583d2307dSDag-Erling Smørgrav 			}
56683d2307dSDag-Erling Smørgrav 			++pglob->gl_matchc;
56783d2307dSDag-Erling Smørgrav 			return(globextend(pathbuf, pglob, limitp));
56883d2307dSDag-Erling Smørgrav 		}
56983d2307dSDag-Erling Smørgrav 
57083d2307dSDag-Erling Smørgrav 		/* Find end of next segment, copy tentatively to pathend. */
57183d2307dSDag-Erling Smørgrav 		q = pathend;
57283d2307dSDag-Erling Smørgrav 		p = pattern;
57383d2307dSDag-Erling Smørgrav 		while (*p != EOS && *p != SEP) {
57483d2307dSDag-Erling Smørgrav 			if (ismeta(*p))
57583d2307dSDag-Erling Smørgrav 				anymeta = 1;
57683d2307dSDag-Erling Smørgrav 			if (q+1 > pathend_last)
57783d2307dSDag-Erling Smørgrav 				return (1);
57883d2307dSDag-Erling Smørgrav 			*q++ = *p++;
57983d2307dSDag-Erling Smørgrav 		}
58083d2307dSDag-Erling Smørgrav 
58183d2307dSDag-Erling Smørgrav 		if (!anymeta) {		/* No expansion, do next segment. */
58283d2307dSDag-Erling Smørgrav 			pathend = q;
58383d2307dSDag-Erling Smørgrav 			pattern = p;
58483d2307dSDag-Erling Smørgrav 			while (*pattern == SEP) {
58583d2307dSDag-Erling Smørgrav 				if (pathend+1 > pathend_last)
58683d2307dSDag-Erling Smørgrav 					return (1);
58783d2307dSDag-Erling Smørgrav 				*pathend++ = *pattern++;
58883d2307dSDag-Erling Smørgrav 			}
58983d2307dSDag-Erling Smørgrav 		} else
59083d2307dSDag-Erling Smørgrav 			/* Need expansion, recurse. */
59183d2307dSDag-Erling Smørgrav 			return(glob3(pathbuf, pathbuf_last, pathend,
59283d2307dSDag-Erling Smørgrav 			    pathend_last, pattern, pattern_last,
59383d2307dSDag-Erling Smørgrav 			    p, pattern_last, pglob, limitp));
59483d2307dSDag-Erling Smørgrav 	}
59583d2307dSDag-Erling Smørgrav 	/* NOTREACHED */
59683d2307dSDag-Erling Smørgrav }
59783d2307dSDag-Erling Smørgrav 
59883d2307dSDag-Erling Smørgrav static int
59983d2307dSDag-Erling Smørgrav glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
60083d2307dSDag-Erling Smørgrav     restpattern, restpattern_last, pglob, limitp)
60183d2307dSDag-Erling Smørgrav 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
60283d2307dSDag-Erling Smørgrav 	Char *pattern, *pattern_last, *restpattern, *restpattern_last;
60383d2307dSDag-Erling Smørgrav 	glob_t *pglob;
60483d2307dSDag-Erling Smørgrav 	size_t *limitp;
60583d2307dSDag-Erling Smørgrav {
60683d2307dSDag-Erling Smørgrav 	register struct dirent *dp;
60783d2307dSDag-Erling Smørgrav 	DIR *dirp;
60883d2307dSDag-Erling Smørgrav 	int err;
60983d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
61083d2307dSDag-Erling Smørgrav 
61183d2307dSDag-Erling Smørgrav 	/*
61283d2307dSDag-Erling Smørgrav 	 * The readdirfunc declaration can't be prototyped, because it is
61383d2307dSDag-Erling Smørgrav 	 * assigned, below, to two functions which are prototyped in glob.h
61483d2307dSDag-Erling Smørgrav 	 * and dirent.h as taking pointers to differently typed opaque
61583d2307dSDag-Erling Smørgrav 	 * structures.
61683d2307dSDag-Erling Smørgrav 	 */
61783d2307dSDag-Erling Smørgrav 	struct dirent *(*readdirfunc)();
61883d2307dSDag-Erling Smørgrav 
61983d2307dSDag-Erling Smørgrav 	if (pathend > pathend_last)
62083d2307dSDag-Erling Smørgrav 		return (1);
62183d2307dSDag-Erling Smørgrav 	*pathend = EOS;
62283d2307dSDag-Erling Smørgrav 	errno = 0;
62383d2307dSDag-Erling Smørgrav 
62483d2307dSDag-Erling Smørgrav 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
62583d2307dSDag-Erling Smørgrav 		/* TODO: don't call for ENOENT or ENOTDIR? */
62683d2307dSDag-Erling Smørgrav 		if (pglob->gl_errfunc) {
62783d2307dSDag-Erling Smørgrav 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
62883d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
62983d2307dSDag-Erling Smørgrav 			if (pglob->gl_errfunc(buf, errno) ||
63083d2307dSDag-Erling Smørgrav 			    pglob->gl_flags & GLOB_ERR)
63183d2307dSDag-Erling Smørgrav 				return(GLOB_ABORTED);
63283d2307dSDag-Erling Smørgrav 		}
63383d2307dSDag-Erling Smørgrav 		return(0);
63483d2307dSDag-Erling Smørgrav 	}
63583d2307dSDag-Erling Smørgrav 
63683d2307dSDag-Erling Smørgrav 	err = 0;
63783d2307dSDag-Erling Smørgrav 
63883d2307dSDag-Erling Smørgrav 	/* Search directory for matching names. */
63983d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
64083d2307dSDag-Erling Smørgrav 		readdirfunc = pglob->gl_readdir;
64183d2307dSDag-Erling Smørgrav 	else
64283d2307dSDag-Erling Smørgrav 		readdirfunc = readdir;
64383d2307dSDag-Erling Smørgrav 	while ((dp = (*readdirfunc)(dirp))) {
64483d2307dSDag-Erling Smørgrav 		register u_char *sc;
64583d2307dSDag-Erling Smørgrav 		register Char *dc;
64683d2307dSDag-Erling Smørgrav 
64783d2307dSDag-Erling Smørgrav 		/* Initial DOT must be matched literally. */
64883d2307dSDag-Erling Smørgrav 		if (dp->d_name[0] == DOT && *pattern != DOT)
64983d2307dSDag-Erling Smørgrav 			continue;
65083d2307dSDag-Erling Smørgrav 		dc = pathend;
65183d2307dSDag-Erling Smørgrav 		sc = (u_char *) dp->d_name;
65283d2307dSDag-Erling Smørgrav 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
65383d2307dSDag-Erling Smørgrav 			;
65483d2307dSDag-Erling Smørgrav 		if (dc >= pathend_last) {
65583d2307dSDag-Erling Smørgrav 			*dc = EOS;
65683d2307dSDag-Erling Smørgrav 			err = 1;
65783d2307dSDag-Erling Smørgrav 			break;
65883d2307dSDag-Erling Smørgrav 		}
65983d2307dSDag-Erling Smørgrav 
66083d2307dSDag-Erling Smørgrav 		if (!match(pathend, pattern, restpattern)) {
66183d2307dSDag-Erling Smørgrav 			*pathend = EOS;
66283d2307dSDag-Erling Smørgrav 			continue;
66383d2307dSDag-Erling Smørgrav 		}
66483d2307dSDag-Erling Smørgrav 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
66583d2307dSDag-Erling Smørgrav 		    restpattern, restpattern_last, pglob, limitp);
66683d2307dSDag-Erling Smørgrav 		if (err)
66783d2307dSDag-Erling Smørgrav 			break;
66883d2307dSDag-Erling Smørgrav 	}
66983d2307dSDag-Erling Smørgrav 
67083d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
67183d2307dSDag-Erling Smørgrav 		(*pglob->gl_closedir)(dirp);
67283d2307dSDag-Erling Smørgrav 	else
67383d2307dSDag-Erling Smørgrav 		closedir(dirp);
67483d2307dSDag-Erling Smørgrav 	return(err);
67583d2307dSDag-Erling Smørgrav }
67683d2307dSDag-Erling Smørgrav 
67783d2307dSDag-Erling Smørgrav 
67883d2307dSDag-Erling Smørgrav /*
67983d2307dSDag-Erling Smørgrav  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
68083d2307dSDag-Erling Smørgrav  * add the new item, and update gl_pathc.
68183d2307dSDag-Erling Smørgrav  *
68283d2307dSDag-Erling Smørgrav  * This assumes the BSD realloc, which only copies the block when its size
68383d2307dSDag-Erling Smørgrav  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
68483d2307dSDag-Erling Smørgrav  * behavior.
68583d2307dSDag-Erling Smørgrav  *
68683d2307dSDag-Erling Smørgrav  * Return 0 if new item added, error code if memory couldn't be allocated.
68783d2307dSDag-Erling Smørgrav  *
68883d2307dSDag-Erling Smørgrav  * Invariant of the glob_t structure:
68983d2307dSDag-Erling Smørgrav  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
69083d2307dSDag-Erling Smørgrav  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
69183d2307dSDag-Erling Smørgrav  */
69283d2307dSDag-Erling Smørgrav static int
69383d2307dSDag-Erling Smørgrav globextend(path, pglob, limitp)
69483d2307dSDag-Erling Smørgrav 	const Char *path;
69583d2307dSDag-Erling Smørgrav 	glob_t *pglob;
69683d2307dSDag-Erling Smørgrav 	size_t *limitp;
69783d2307dSDag-Erling Smørgrav {
69883d2307dSDag-Erling Smørgrav 	register char **pathv;
69983d2307dSDag-Erling Smørgrav 	register int i;
70083d2307dSDag-Erling Smørgrav 	u_int newsize, len;
70183d2307dSDag-Erling Smørgrav 	char *copy;
70283d2307dSDag-Erling Smørgrav 	const Char *p;
70383d2307dSDag-Erling Smørgrav 
70483d2307dSDag-Erling Smørgrav 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
70583d2307dSDag-Erling Smørgrav 	pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
70683d2307dSDag-Erling Smørgrav 	    malloc(newsize);
70783d2307dSDag-Erling Smørgrav 	if (pathv == NULL) {
70883d2307dSDag-Erling Smørgrav 		if (pglob->gl_pathv) {
70983d2307dSDag-Erling Smørgrav 			free(pglob->gl_pathv);
71083d2307dSDag-Erling Smørgrav 			pglob->gl_pathv = NULL;
71183d2307dSDag-Erling Smørgrav 		}
71283d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
71383d2307dSDag-Erling Smørgrav 	}
71483d2307dSDag-Erling Smørgrav 
71583d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
71683d2307dSDag-Erling Smørgrav 		/* first time around -- clear initial gl_offs items */
71783d2307dSDag-Erling Smørgrav 		pathv += pglob->gl_offs;
71883d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_offs; --i >= 0; )
71983d2307dSDag-Erling Smørgrav 			*--pathv = NULL;
72083d2307dSDag-Erling Smørgrav 	}
72183d2307dSDag-Erling Smørgrav 	pglob->gl_pathv = pathv;
72283d2307dSDag-Erling Smørgrav 
72383d2307dSDag-Erling Smørgrav 	for (p = path; *p++;)
72483d2307dSDag-Erling Smørgrav 		;
72583d2307dSDag-Erling Smørgrav 	len = (size_t)(p - path);
72683d2307dSDag-Erling Smørgrav 	*limitp += len;
72783d2307dSDag-Erling Smørgrav 	if ((copy = malloc(len)) != NULL) {
72883d2307dSDag-Erling Smørgrav 		if (g_Ctoc(path, copy, len)) {
72983d2307dSDag-Erling Smørgrav 			free(copy);
73083d2307dSDag-Erling Smørgrav 			return(GLOB_NOSPACE);
73183d2307dSDag-Erling Smørgrav 		}
73283d2307dSDag-Erling Smørgrav 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
73383d2307dSDag-Erling Smørgrav 	}
73483d2307dSDag-Erling Smørgrav 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
73583d2307dSDag-Erling Smørgrav 
73683d2307dSDag-Erling Smørgrav 	if ((pglob->gl_flags & GLOB_LIMIT) &&
73783d2307dSDag-Erling Smørgrav 	    newsize + *limitp >= (u_int) get_arg_max()) {
73883d2307dSDag-Erling Smørgrav 		errno = 0;
73983d2307dSDag-Erling Smørgrav 		return(GLOB_NOSPACE);
74083d2307dSDag-Erling Smørgrav 	}
74183d2307dSDag-Erling Smørgrav 
74283d2307dSDag-Erling Smørgrav 	return(copy == NULL ? GLOB_NOSPACE : 0);
74383d2307dSDag-Erling Smørgrav }
74483d2307dSDag-Erling Smørgrav 
74583d2307dSDag-Erling Smørgrav 
74683d2307dSDag-Erling Smørgrav /*
74783d2307dSDag-Erling Smørgrav  * pattern matching function for filenames.  Each occurrence of the *
74883d2307dSDag-Erling Smørgrav  * pattern causes a recursion level.
74983d2307dSDag-Erling Smørgrav  */
75083d2307dSDag-Erling Smørgrav static int
75183d2307dSDag-Erling Smørgrav match(name, pat, patend)
75283d2307dSDag-Erling Smørgrav 	register Char *name, *pat, *patend;
75383d2307dSDag-Erling Smørgrav {
75483d2307dSDag-Erling Smørgrav 	int ok, negate_range;
75583d2307dSDag-Erling Smørgrav 	Char c, k;
75683d2307dSDag-Erling Smørgrav 
75783d2307dSDag-Erling Smørgrav 	while (pat < patend) {
75883d2307dSDag-Erling Smørgrav 		c = *pat++;
75983d2307dSDag-Erling Smørgrav 		switch (c & M_MASK) {
76083d2307dSDag-Erling Smørgrav 		case M_ALL:
76183d2307dSDag-Erling Smørgrav 			if (pat == patend)
76283d2307dSDag-Erling Smørgrav 				return(1);
76383d2307dSDag-Erling Smørgrav 			do
76483d2307dSDag-Erling Smørgrav 			    if (match(name, pat, patend))
76583d2307dSDag-Erling Smørgrav 				    return(1);
76683d2307dSDag-Erling Smørgrav 			while (*name++ != EOS)
76783d2307dSDag-Erling Smørgrav 				;
76883d2307dSDag-Erling Smørgrav 			return(0);
76983d2307dSDag-Erling Smørgrav 		case M_ONE:
77083d2307dSDag-Erling Smørgrav 			if (*name++ == EOS)
77183d2307dSDag-Erling Smørgrav 				return(0);
77283d2307dSDag-Erling Smørgrav 			break;
77383d2307dSDag-Erling Smørgrav 		case M_SET:
77483d2307dSDag-Erling Smørgrav 			ok = 0;
77583d2307dSDag-Erling Smørgrav 			if ((k = *name++) == EOS)
77683d2307dSDag-Erling Smørgrav 				return(0);
77783d2307dSDag-Erling Smørgrav 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
77883d2307dSDag-Erling Smørgrav 				++pat;
77983d2307dSDag-Erling Smørgrav 			while (((c = *pat++) & M_MASK) != M_END)
78083d2307dSDag-Erling Smørgrav 				if ((*pat & M_MASK) == M_RNG) {
78183d2307dSDag-Erling Smørgrav 					if (c <= k && k <= pat[1])
78283d2307dSDag-Erling Smørgrav 						ok = 1;
78383d2307dSDag-Erling Smørgrav 					pat += 2;
78483d2307dSDag-Erling Smørgrav 				} else if (c == k)
78583d2307dSDag-Erling Smørgrav 					ok = 1;
78683d2307dSDag-Erling Smørgrav 			if (ok == negate_range)
78783d2307dSDag-Erling Smørgrav 				return(0);
78883d2307dSDag-Erling Smørgrav 			break;
78983d2307dSDag-Erling Smørgrav 		default:
79083d2307dSDag-Erling Smørgrav 			if (*name++ != c)
79183d2307dSDag-Erling Smørgrav 				return(0);
79283d2307dSDag-Erling Smørgrav 			break;
79383d2307dSDag-Erling Smørgrav 		}
79483d2307dSDag-Erling Smørgrav 	}
79583d2307dSDag-Erling Smørgrav 	return(*name == EOS);
79683d2307dSDag-Erling Smørgrav }
79783d2307dSDag-Erling Smørgrav 
79883d2307dSDag-Erling Smørgrav /* Free allocated data belonging to a glob_t structure. */
79983d2307dSDag-Erling Smørgrav void
80083d2307dSDag-Erling Smørgrav globfree(pglob)
80183d2307dSDag-Erling Smørgrav 	glob_t *pglob;
80283d2307dSDag-Erling Smørgrav {
80383d2307dSDag-Erling Smørgrav 	register int i;
80483d2307dSDag-Erling Smørgrav 	register char **pp;
80583d2307dSDag-Erling Smørgrav 
80683d2307dSDag-Erling Smørgrav 	if (pglob->gl_pathv != NULL) {
80783d2307dSDag-Erling Smørgrav 		pp = pglob->gl_pathv + pglob->gl_offs;
80883d2307dSDag-Erling Smørgrav 		for (i = pglob->gl_pathc; i--; ++pp)
80983d2307dSDag-Erling Smørgrav 			if (*pp)
81083d2307dSDag-Erling Smørgrav 				free(*pp);
81183d2307dSDag-Erling Smørgrav 		free(pglob->gl_pathv);
81283d2307dSDag-Erling Smørgrav 		pglob->gl_pathv = NULL;
81383d2307dSDag-Erling Smørgrav 	}
81483d2307dSDag-Erling Smørgrav }
81583d2307dSDag-Erling Smørgrav 
81683d2307dSDag-Erling Smørgrav static DIR *
81783d2307dSDag-Erling Smørgrav g_opendir(str, pglob)
81883d2307dSDag-Erling Smørgrav 	register Char *str;
81983d2307dSDag-Erling Smørgrav 	glob_t *pglob;
82083d2307dSDag-Erling Smørgrav {
82183d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
82283d2307dSDag-Erling Smørgrav 
82383d2307dSDag-Erling Smørgrav 	if (!*str)
82483d2307dSDag-Erling Smørgrav 		strcpy(buf, ".");
82583d2307dSDag-Erling Smørgrav 	else {
82683d2307dSDag-Erling Smørgrav 		if (g_Ctoc(str, buf, sizeof(buf)))
82783d2307dSDag-Erling Smørgrav 			return(NULL);
82883d2307dSDag-Erling Smørgrav 	}
82983d2307dSDag-Erling Smørgrav 
83083d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
83183d2307dSDag-Erling Smørgrav 		return((*pglob->gl_opendir)(buf));
83283d2307dSDag-Erling Smørgrav 
83383d2307dSDag-Erling Smørgrav 	return(opendir(buf));
83483d2307dSDag-Erling Smørgrav }
83583d2307dSDag-Erling Smørgrav 
83683d2307dSDag-Erling Smørgrav static int
83783d2307dSDag-Erling Smørgrav g_lstat(fn, sb, pglob)
83883d2307dSDag-Erling Smørgrav 	register Char *fn;
83983d2307dSDag-Erling Smørgrav 	struct stat *sb;
84083d2307dSDag-Erling Smørgrav 	glob_t *pglob;
84183d2307dSDag-Erling Smørgrav {
84283d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
84383d2307dSDag-Erling Smørgrav 
84483d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
84583d2307dSDag-Erling Smørgrav 		return(-1);
84683d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
84783d2307dSDag-Erling Smørgrav 		return((*pglob->gl_lstat)(buf, sb));
84883d2307dSDag-Erling Smørgrav 	return(lstat(buf, sb));
84983d2307dSDag-Erling Smørgrav }
85083d2307dSDag-Erling Smørgrav 
85183d2307dSDag-Erling Smørgrav static int
85283d2307dSDag-Erling Smørgrav g_stat(fn, sb, pglob)
85383d2307dSDag-Erling Smørgrav 	register Char *fn;
85483d2307dSDag-Erling Smørgrav 	struct stat *sb;
85583d2307dSDag-Erling Smørgrav 	glob_t *pglob;
85683d2307dSDag-Erling Smørgrav {
85783d2307dSDag-Erling Smørgrav 	char buf[MAXPATHLEN];
85883d2307dSDag-Erling Smørgrav 
85983d2307dSDag-Erling Smørgrav 	if (g_Ctoc(fn, buf, sizeof(buf)))
86083d2307dSDag-Erling Smørgrav 		return(-1);
86183d2307dSDag-Erling Smørgrav 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
86283d2307dSDag-Erling Smørgrav 		return((*pglob->gl_stat)(buf, sb));
86383d2307dSDag-Erling Smørgrav 	return(stat(buf, sb));
86483d2307dSDag-Erling Smørgrav }
86583d2307dSDag-Erling Smørgrav 
86683d2307dSDag-Erling Smørgrav static Char *
86783d2307dSDag-Erling Smørgrav g_strchr(str, ch)
86883d2307dSDag-Erling Smørgrav 	Char *str;
86983d2307dSDag-Erling Smørgrav 	int ch;
87083d2307dSDag-Erling Smørgrav {
87183d2307dSDag-Erling Smørgrav 	do {
87283d2307dSDag-Erling Smørgrav 		if (*str == ch)
87383d2307dSDag-Erling Smørgrav 			return (str);
87483d2307dSDag-Erling Smørgrav 	} while (*str++);
87583d2307dSDag-Erling Smørgrav 	return (NULL);
87683d2307dSDag-Erling Smørgrav }
87783d2307dSDag-Erling Smørgrav 
87883d2307dSDag-Erling Smørgrav static int
87983d2307dSDag-Erling Smørgrav g_Ctoc(str, buf, len)
88083d2307dSDag-Erling Smørgrav 	register const Char *str;
88183d2307dSDag-Erling Smørgrav 	char *buf;
88283d2307dSDag-Erling Smørgrav 	u_int len;
88383d2307dSDag-Erling Smørgrav {
88483d2307dSDag-Erling Smørgrav 
88583d2307dSDag-Erling Smørgrav 	while (len--) {
88683d2307dSDag-Erling Smørgrav 		if ((*buf++ = *str++) == EOS)
88783d2307dSDag-Erling Smørgrav 			return (0);
88883d2307dSDag-Erling Smørgrav 	}
88983d2307dSDag-Erling Smørgrav 	return (1);
89083d2307dSDag-Erling Smørgrav }
89183d2307dSDag-Erling Smørgrav 
89283d2307dSDag-Erling Smørgrav #ifdef DEBUG
89383d2307dSDag-Erling Smørgrav static void
89483d2307dSDag-Erling Smørgrav qprintf(str, s)
89583d2307dSDag-Erling Smørgrav 	const char *str;
89683d2307dSDag-Erling Smørgrav 	register Char *s;
89783d2307dSDag-Erling Smørgrav {
89883d2307dSDag-Erling Smørgrav 	register Char *p;
89983d2307dSDag-Erling Smørgrav 
90083d2307dSDag-Erling Smørgrav 	(void)printf("%s:\n", str);
90183d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
90283d2307dSDag-Erling Smørgrav 		(void)printf("%c", CHAR(*p));
90383d2307dSDag-Erling Smørgrav 	(void)printf("\n");
90483d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
90583d2307dSDag-Erling Smørgrav 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
90683d2307dSDag-Erling Smørgrav 	(void)printf("\n");
90783d2307dSDag-Erling Smørgrav 	for (p = s; *p; p++)
90883d2307dSDag-Erling Smørgrav 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
90983d2307dSDag-Erling Smørgrav 	(void)printf("\n");
91083d2307dSDag-Erling Smørgrav }
91183d2307dSDag-Erling Smørgrav #endif
91283d2307dSDag-Erling Smørgrav 
91383d2307dSDag-Erling Smørgrav #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
91483d2307dSDag-Erling Smørgrav           !defined(GLOB_HAS_GL_MATCHC) */
91583d2307dSDag-Erling Smørgrav 
916