glob.c revision 121667
11573Srgrimes/*
21573Srgrimes * Copyright (c) 1989, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Guido van Rossum.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
351573Srgrimes */
361573Srgrimes
371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
381573Srgrimesstatic char sccsid[] = "@(#)glob.c	8.3 (Berkeley) 10/13/93";
391573Srgrimes#endif /* LIBC_SCCS and not lint */
4090045Sobrien#include <sys/cdefs.h>
4190045Sobrien__FBSDID("$FreeBSD: head/lib/libc/gen/glob.c 121667 2003-10-29 10:45:01Z tjr $");
421573Srgrimes
431573Srgrimes/*
441573Srgrimes * glob(3) -- a superset of the one defined in POSIX 1003.2.
451573Srgrimes *
461573Srgrimes * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
471573Srgrimes *
481573Srgrimes * Optional extra services, controlled by flags not defined by POSIX:
491573Srgrimes *
501573Srgrimes * GLOB_QUOTE:
511573Srgrimes *	Escaping convention: \ inhibits any special meaning the following
521573Srgrimes *	character might have (except \ at end of string is retained).
531573Srgrimes * GLOB_MAGCHAR:
541573Srgrimes *	Set in gl_flags if pattern contained a globbing character.
551573Srgrimes * GLOB_NOMAGIC:
561573Srgrimes *	Same as GLOB_NOCHECK, but it will only append pattern if it did
571573Srgrimes *	not contain any magic characters.  [Used in csh style globbing]
581573Srgrimes * GLOB_ALTDIRFUNC:
591573Srgrimes *	Use alternately specified directory access functions.
601573Srgrimes * GLOB_TILDE:
611573Srgrimes *	expand ~user/foo to the /home/dir/of/user/foo
621573Srgrimes * GLOB_BRACE:
638870Srgrimes *	expand {1,2}{a,b} to 1a 1b 2a 2b
641573Srgrimes * gl_matchc:
651573Srgrimes *	Number of matches in the current invocation of glob.
661573Srgrimes */
671573Srgrimes
681573Srgrimes#include <sys/param.h>
691573Srgrimes#include <sys/stat.h>
701573Srgrimes
711573Srgrimes#include <ctype.h>
721573Srgrimes#include <dirent.h>
731573Srgrimes#include <errno.h>
741573Srgrimes#include <glob.h>
751573Srgrimes#include <pwd.h>
761573Srgrimes#include <stdio.h>
771573Srgrimes#include <stdlib.h>
781573Srgrimes#include <string.h>
791573Srgrimes#include <unistd.h>
801573Srgrimes
8119276Sache#include "collate.h"
8219276Sache
831573Srgrimes#define	DOLLAR		'$'
841573Srgrimes#define	DOT		'.'
851573Srgrimes#define	EOS		'\0'
861573Srgrimes#define	LBRACKET	'['
871573Srgrimes#define	NOT		'!'
881573Srgrimes#define	QUESTION	'?'
891573Srgrimes#define	QUOTE		'\\'
901573Srgrimes#define	RANGE		'-'
911573Srgrimes#define	RBRACKET	']'
921573Srgrimes#define	SEP		'/'
931573Srgrimes#define	STAR		'*'
941573Srgrimes#define	TILDE		'~'
951573Srgrimes#define	UNDERSCORE	'_'
961573Srgrimes#define	LBRACE		'{'
971573Srgrimes#define	RBRACE		'}'
981573Srgrimes#define	SLASH		'/'
991573Srgrimes#define	COMMA		','
1001573Srgrimes
1011573Srgrimes#ifndef DEBUG
1021573Srgrimes
1031573Srgrimes#define	M_QUOTE		0x8000
1041573Srgrimes#define	M_PROTECT	0x4000
1051573Srgrimes#define	M_MASK		0xffff
1061573Srgrimes#define	M_ASCII		0x00ff
1071573Srgrimes
1081573Srgrimestypedef u_short Char;
1091573Srgrimes
1101573Srgrimes#else
1111573Srgrimes
1121573Srgrimes#define	M_QUOTE		0x80
1131573Srgrimes#define	M_PROTECT	0x40
1141573Srgrimes#define	M_MASK		0xff
1151573Srgrimes#define	M_ASCII		0x7f
1161573Srgrimes
1171573Srgrimestypedef char Char;
1181573Srgrimes
1191573Srgrimes#endif
1201573Srgrimes
1211573Srgrimes
1221573Srgrimes#define	CHAR(c)		((Char)((c)&M_ASCII))
1231573Srgrimes#define	META(c)		((Char)((c)|M_QUOTE))
1241573Srgrimes#define	M_ALL		META('*')
1251573Srgrimes#define	M_END		META(']')
1261573Srgrimes#define	M_NOT		META('!')
1271573Srgrimes#define	M_ONE		META('?')
1281573Srgrimes#define	M_RNG		META('-')
1291573Srgrimes#define	M_SET		META('[')
1301573Srgrimes#define	ismeta(c)	(((c)&M_QUOTE) != 0)
1311573Srgrimes
1321573Srgrimes
13390045Sobrienstatic int	 compare(const void *, const void *);
13490045Sobrienstatic int	 g_Ctoc(const Char *, char *, u_int);
13590045Sobrienstatic int	 g_lstat(Char *, struct stat *, glob_t *);
13690045Sobrienstatic DIR	*g_opendir(Char *, glob_t *);
13790045Sobrienstatic Char	*g_strchr(Char *, int);
1381573Srgrimes#ifdef notdef
13990045Sobrienstatic Char	*g_strcat(Char *, const Char *);
1401573Srgrimes#endif
14190045Sobrienstatic int	 g_stat(Char *, struct stat *, glob_t *);
14290045Sobrienstatic int	 glob0(const Char *, glob_t *, int *);
14390045Sobrienstatic int	 glob1(Char *, glob_t *, int *);
14490045Sobrienstatic int	 glob2(Char *, Char *, Char *, Char *, glob_t *, int *);
14590045Sobrienstatic int	 glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *);
14690045Sobrienstatic int	 globextend(const Char *, glob_t *, int *);
14774963Speterstatic const Char *
14890045Sobrien		 globtilde(const Char *, Char *, size_t, glob_t *);
14990045Sobrienstatic int	 globexp1(const Char *, glob_t *, int *);
15090045Sobrienstatic int	 globexp2(const Char *, const Char *, glob_t *, int *, int *);
15190045Sobrienstatic int	 match(Char *, Char *, Char *);
1521573Srgrimes#ifdef DEBUG
15390045Sobrienstatic void	 qprintf(const char *, Char *);
1541573Srgrimes#endif
1551573Srgrimes
1561573Srgrimesint
1571573Srgrimesglob(pattern, flags, errfunc, pglob)
1581573Srgrimes	const char *pattern;
15990045Sobrien	int flags, (*errfunc)(const char *, int);
1601573Srgrimes	glob_t *pglob;
1611573Srgrimes{
1621573Srgrimes	const u_char *patnext;
16374469Sjlemon	int c, limit;
16474963Speter	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
1651573Srgrimes
1661573Srgrimes	patnext = (u_char *) pattern;
1671573Srgrimes	if (!(flags & GLOB_APPEND)) {
1681573Srgrimes		pglob->gl_pathc = 0;
1691573Srgrimes		pglob->gl_pathv = NULL;
1701573Srgrimes		if (!(flags & GLOB_DOOFFS))
1711573Srgrimes			pglob->gl_offs = 0;
1721573Srgrimes	}
17380525Smikeh	if (flags & GLOB_LIMIT) {
17474469Sjlemon		limit = pglob->gl_matchc;
17580525Smikeh		if (limit == 0)
17680525Smikeh			limit = ARG_MAX;
17780525Smikeh	} else
17874469Sjlemon		limit = 0;
1791573Srgrimes	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
1801573Srgrimes	pglob->gl_errfunc = errfunc;
1811573Srgrimes	pglob->gl_matchc = 0;
1821573Srgrimes
1831573Srgrimes	bufnext = patbuf;
18474963Speter	bufend = bufnext + MAXPATHLEN - 1;
185100217Smikeh	if (flags & GLOB_NOESCAPE)
186100217Smikeh	    while (bufnext < bufend && (c = *patnext++) != EOS)
187100217Smikeh		    *bufnext++ = c;
188100217Smikeh	else {
1891573Srgrimes		/* Protect the quoted characters. */
1908870Srgrimes		while (bufnext < bufend && (c = *patnext++) != EOS)
1911573Srgrimes			if (c == QUOTE) {
1921573Srgrimes				if ((c = *patnext++) == EOS) {
1931573Srgrimes					c = QUOTE;
1941573Srgrimes					--patnext;
1951573Srgrimes				}
1961573Srgrimes				*bufnext++ = c | M_PROTECT;
1971573Srgrimes			}
1981573Srgrimes			else
1991573Srgrimes				*bufnext++ = c;
2001573Srgrimes	}
2011573Srgrimes	*bufnext = EOS;
2021573Srgrimes
2031573Srgrimes	if (flags & GLOB_BRACE)
20474469Sjlemon	    return globexp1(patbuf, pglob, &limit);
2051573Srgrimes	else
20674469Sjlemon	    return glob0(patbuf, pglob, &limit);
2071573Srgrimes}
2081573Srgrimes
2091573Srgrimes/*
2101573Srgrimes * Expand recursively a glob {} pattern. When there is no more expansion
2111573Srgrimes * invoke the standard globbing routine to glob the rest of the magic
2121573Srgrimes * characters
2131573Srgrimes */
21474963Speterstatic int
21574963Speterglobexp1(pattern, pglob, limit)
2161573Srgrimes	const Char *pattern;
2171573Srgrimes	glob_t *pglob;
21874469Sjlemon	int *limit;
2191573Srgrimes{
2201573Srgrimes	const Char* ptr = pattern;
2211573Srgrimes	int rv;
2221573Srgrimes
2231573Srgrimes	/* Protect a single {}, for find(1), like csh */
2241573Srgrimes	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
22574469Sjlemon		return glob0(pattern, pglob, limit);
2261573Srgrimes
2271573Srgrimes	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
22874469Sjlemon		if (!globexp2(ptr, pattern, pglob, &rv, limit))
2291573Srgrimes			return rv;
2301573Srgrimes
23174469Sjlemon	return glob0(pattern, pglob, limit);
2321573Srgrimes}
2331573Srgrimes
2341573Srgrimes
2351573Srgrimes/*
2361573Srgrimes * Recursive brace globbing helper. Tries to expand a single brace.
2371573Srgrimes * If it succeeds then it invokes globexp1 with the new pattern.
2381573Srgrimes * If it fails then it tries to glob the rest of the pattern and returns.
2391573Srgrimes */
24074963Speterstatic int
24174963Speterglobexp2(ptr, pattern, pglob, rv, limit)
2421573Srgrimes	const Char *ptr, *pattern;
2431573Srgrimes	glob_t *pglob;
24474469Sjlemon	int *rv, *limit;
2451573Srgrimes{
2461573Srgrimes	int     i;
2471573Srgrimes	Char   *lm, *ls;
2481573Srgrimes	const Char *pe, *pm, *pl;
24974963Speter	Char    patbuf[MAXPATHLEN];
2501573Srgrimes
2511573Srgrimes	/* copy part up to the brace */
2521573Srgrimes	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
2531573Srgrimes		continue;
25474963Speter	*lm = EOS;
2551573Srgrimes	ls = lm;
2561573Srgrimes
2571573Srgrimes	/* Find the balanced brace */
2581573Srgrimes	for (i = 0, pe = ++ptr; *pe; pe++)
2591573Srgrimes		if (*pe == LBRACKET) {
2601573Srgrimes			/* Ignore everything between [] */
2611573Srgrimes			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
2621573Srgrimes				continue;
2631573Srgrimes			if (*pe == EOS) {
2648870Srgrimes				/*
2651573Srgrimes				 * We could not find a matching RBRACKET.
2661573Srgrimes				 * Ignore and just look for RBRACE
2671573Srgrimes				 */
2681573Srgrimes				pe = pm;
2691573Srgrimes			}
2701573Srgrimes		}
2711573Srgrimes		else if (*pe == LBRACE)
2721573Srgrimes			i++;
2731573Srgrimes		else if (*pe == RBRACE) {
2741573Srgrimes			if (i == 0)
2751573Srgrimes				break;
2761573Srgrimes			i--;
2771573Srgrimes		}
2781573Srgrimes
2791573Srgrimes	/* Non matching braces; just glob the pattern */
2801573Srgrimes	if (i != 0 || *pe == EOS) {
28174469Sjlemon		*rv = glob0(patbuf, pglob, limit);
2821573Srgrimes		return 0;
2831573Srgrimes	}
2841573Srgrimes
2851573Srgrimes	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
2861573Srgrimes		switch (*pm) {
2871573Srgrimes		case LBRACKET:
2881573Srgrimes			/* Ignore everything between [] */
2891573Srgrimes			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
2901573Srgrimes				continue;
2911573Srgrimes			if (*pm == EOS) {
2928870Srgrimes				/*
2931573Srgrimes				 * We could not find a matching RBRACKET.
2941573Srgrimes				 * Ignore and just look for RBRACE
2951573Srgrimes				 */
2961573Srgrimes				pm = pl;
2971573Srgrimes			}
2981573Srgrimes			break;
2991573Srgrimes
3001573Srgrimes		case LBRACE:
3011573Srgrimes			i++;
3021573Srgrimes			break;
3031573Srgrimes
3041573Srgrimes		case RBRACE:
3051573Srgrimes			if (i) {
3061573Srgrimes			    i--;
3071573Srgrimes			    break;
3081573Srgrimes			}
3091573Srgrimes			/* FALLTHROUGH */
3101573Srgrimes		case COMMA:
3111573Srgrimes			if (i && *pm == COMMA)
3121573Srgrimes				break;
3131573Srgrimes			else {
3141573Srgrimes				/* Append the current string */
3151573Srgrimes				for (lm = ls; (pl < pm); *lm++ = *pl++)
3161573Srgrimes					continue;
3178870Srgrimes				/*
3181573Srgrimes				 * Append the rest of the pattern after the
3191573Srgrimes				 * closing brace
3201573Srgrimes				 */
3211573Srgrimes				for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
3221573Srgrimes					continue;
3231573Srgrimes
3241573Srgrimes				/* Expand the current pattern */
3251573Srgrimes#ifdef DEBUG
3261573Srgrimes				qprintf("globexp2:", patbuf);
3271573Srgrimes#endif
32874469Sjlemon				*rv = globexp1(patbuf, pglob, limit);
3291573Srgrimes
3301573Srgrimes				/* move after the comma, to the next string */
3311573Srgrimes				pl = pm + 1;
3321573Srgrimes			}
3331573Srgrimes			break;
3341573Srgrimes
3351573Srgrimes		default:
3361573Srgrimes			break;
3371573Srgrimes		}
3381573Srgrimes	*rv = 0;
3391573Srgrimes	return 0;
3401573Srgrimes}
3411573Srgrimes
3421573Srgrimes
3431573Srgrimes
3441573Srgrimes/*
3451573Srgrimes * expand tilde from the passwd file.
3461573Srgrimes */
3471573Srgrimesstatic const Char *
34824158Simpglobtilde(pattern, patbuf, patbuf_len, pglob)
3491573Srgrimes	const Char *pattern;
3501573Srgrimes	Char *patbuf;
35124158Simp	size_t patbuf_len;
3521573Srgrimes	glob_t *pglob;
3531573Srgrimes{
3541573Srgrimes	struct passwd *pwd;
3551573Srgrimes	char *h;
3561573Srgrimes	const Char *p;
35724158Simp	Char *b, *eb;
3581573Srgrimes
3591573Srgrimes	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
3601573Srgrimes		return pattern;
3611573Srgrimes
36224158Simp	/*
36324158Simp	 * Copy up to the end of the string or /
36424158Simp	 */
36524158Simp	eb = &patbuf[patbuf_len - 1];
36624158Simp	for (p = pattern + 1, h = (char *) patbuf;
36724158Simp	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
3681573Srgrimes		continue;
3691573Srgrimes
3701573Srgrimes	*h = EOS;
3711573Srgrimes
3721573Srgrimes	if (((char *) patbuf)[0] == EOS) {
3738870Srgrimes		/*
37428820Simp		 * handle a plain ~ or ~/ by expanding $HOME first (iff
37528820Simp		 * we're not running setuid or setgid) and then trying
37628820Simp		 * the password file
3771573Srgrimes		 */
378121667Stjr		if (issetugid() != 0 ||
37933664Sjb		    (h = getenv("HOME")) == NULL) {
38028836Sache			if (((h = getlogin()) != NULL &&
38128836Sache			     (pwd = getpwnam(h)) != NULL) ||
38228836Sache			    (pwd = getpwuid(getuid())) != NULL)
38328836Sache				h = pwd->pw_dir;
38428836Sache			else
3851573Srgrimes				return pattern;
3861573Srgrimes		}
3871573Srgrimes	}
3881573Srgrimes	else {
3891573Srgrimes		/*
3901573Srgrimes		 * Expand a ~user
3911573Srgrimes		 */
3921573Srgrimes		if ((pwd = getpwnam((char*) patbuf)) == NULL)
3931573Srgrimes			return pattern;
3941573Srgrimes		else
3951573Srgrimes			h = pwd->pw_dir;
3961573Srgrimes	}
3971573Srgrimes
3981573Srgrimes	/* Copy the home directory */
39924158Simp	for (b = patbuf; b < eb && *h; *b++ = *h++)
4001573Srgrimes		continue;
4018870Srgrimes
4021573Srgrimes	/* Append the rest of the pattern */
40324158Simp	while (b < eb && (*b++ = *p++) != EOS)
4041573Srgrimes		continue;
40524158Simp	*b = EOS;
4061573Srgrimes
4071573Srgrimes	return patbuf;
4081573Srgrimes}
4091573Srgrimes
4108870Srgrimes
4111573Srgrimes/*
4121573Srgrimes * The main glob() routine: compiles the pattern (optionally processing
4131573Srgrimes * quotes), calls glob1() to do the real pattern matching, and finally
4141573Srgrimes * sorts the list (unless unsorted operation is requested).  Returns 0
415100217Smikeh * if things went well, nonzero if errors occurred.
4161573Srgrimes */
4171573Srgrimesstatic int
41874469Sjlemonglob0(pattern, pglob, limit)
4191573Srgrimes	const Char *pattern;
4201573Srgrimes	glob_t *pglob;
42174469Sjlemon	int *limit;
4221573Srgrimes{
4231573Srgrimes	const Char *qpatnext;
4241573Srgrimes	int c, err, oldpathc;
42574963Speter	Char *bufnext, patbuf[MAXPATHLEN];
4261573Srgrimes
42774963Speter	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
4281573Srgrimes	oldpathc = pglob->gl_pathc;
4291573Srgrimes	bufnext = patbuf;
4301573Srgrimes
4311573Srgrimes	/* We don't need to check for buffer overflow any more. */
4321573Srgrimes	while ((c = *qpatnext++) != EOS) {
4331573Srgrimes		switch (c) {
4341573Srgrimes		case LBRACKET:
4351573Srgrimes			c = *qpatnext;
4361573Srgrimes			if (c == NOT)
4371573Srgrimes				++qpatnext;
4381573Srgrimes			if (*qpatnext == EOS ||
4391573Srgrimes			    g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
4401573Srgrimes				*bufnext++ = LBRACKET;
4411573Srgrimes				if (c == NOT)
4421573Srgrimes					--qpatnext;
4431573Srgrimes				break;
4441573Srgrimes			}
4451573Srgrimes			*bufnext++ = M_SET;
4461573Srgrimes			if (c == NOT)
4471573Srgrimes				*bufnext++ = M_NOT;
4481573Srgrimes			c = *qpatnext++;
4491573Srgrimes			do {
4501573Srgrimes				*bufnext++ = CHAR(c);
4511573Srgrimes				if (*qpatnext == RANGE &&
4521573Srgrimes				    (c = qpatnext[1]) != RBRACKET) {
4531573Srgrimes					*bufnext++ = M_RNG;
4541573Srgrimes					*bufnext++ = CHAR(c);
4551573Srgrimes					qpatnext += 2;
4561573Srgrimes				}
4571573Srgrimes			} while ((c = *qpatnext++) != RBRACKET);
4581573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4591573Srgrimes			*bufnext++ = M_END;
4601573Srgrimes			break;
4611573Srgrimes		case QUESTION:
4621573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4631573Srgrimes			*bufnext++ = M_ONE;
4641573Srgrimes			break;
4651573Srgrimes		case STAR:
4661573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4678870Srgrimes			/* collapse adjacent stars to one,
4681573Srgrimes			 * to avoid exponential behavior
4691573Srgrimes			 */
4701573Srgrimes			if (bufnext == patbuf || bufnext[-1] != M_ALL)
4711573Srgrimes			    *bufnext++ = M_ALL;
4721573Srgrimes			break;
4731573Srgrimes		default:
4741573Srgrimes			*bufnext++ = CHAR(c);
4751573Srgrimes			break;
4761573Srgrimes		}
4771573Srgrimes	}
4781573Srgrimes	*bufnext = EOS;
4791573Srgrimes#ifdef DEBUG
4801573Srgrimes	qprintf("glob0:", patbuf);
4811573Srgrimes#endif
4821573Srgrimes
48374469Sjlemon	if ((err = glob1(patbuf, pglob, limit)) != 0)
4841573Srgrimes		return(err);
4851573Srgrimes
4861573Srgrimes	/*
4878870Srgrimes	 * If there was no match we are going to append the pattern
4881573Srgrimes	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
4891573Srgrimes	 * and the pattern did not contain any magic characters
4901573Srgrimes	 * GLOB_NOMAGIC is there just for compatibility with csh.
4911573Srgrimes	 */
492100217Smikeh	if (pglob->gl_pathc == oldpathc) {
493100217Smikeh		if (((pglob->gl_flags & GLOB_NOCHECK) ||
494100217Smikeh		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
495100217Smikeh			!(pglob->gl_flags & GLOB_MAGCHAR))))
496100217Smikeh			return(globextend(pattern, pglob, limit));
497100217Smikeh		else
498100217Smikeh			return(GLOB_NOMATCH);
499100217Smikeh	}
500100217Smikeh	if (!(pglob->gl_flags & GLOB_NOSORT))
5011573Srgrimes		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
5021573Srgrimes		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
5031573Srgrimes	return(0);
5041573Srgrimes}
5051573Srgrimes
5061573Srgrimesstatic int
5071573Srgrimescompare(p, q)
5081573Srgrimes	const void *p, *q;
5091573Srgrimes{
5101573Srgrimes	return(strcmp(*(char **)p, *(char **)q));
5111573Srgrimes}
5121573Srgrimes
5131573Srgrimesstatic int
51474469Sjlemonglob1(pattern, pglob, limit)
5151573Srgrimes	Char *pattern;
5161573Srgrimes	glob_t *pglob;
51774469Sjlemon	int *limit;
5181573Srgrimes{
51974963Speter	Char pathbuf[MAXPATHLEN];
5201573Srgrimes
5211573Srgrimes	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
5221573Srgrimes	if (*pattern == EOS)
5231573Srgrimes		return(0);
52474963Speter	return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
52574963Speter	    pattern, pglob, limit));
5261573Srgrimes}
5271573Srgrimes
5281573Srgrimes/*
5291573Srgrimes * The functions glob2 and glob3 are mutually recursive; there is one level
5301573Srgrimes * of recursion for each segment in the pattern that contains one or more
5311573Srgrimes * meta characters.
5321573Srgrimes */
5331573Srgrimesstatic int
53474963Speterglob2(pathbuf, pathend, pathend_last, pattern, pglob, limit)
53574963Speter	Char *pathbuf, *pathend, *pathend_last, *pattern;
5361573Srgrimes	glob_t *pglob;
53774469Sjlemon	int *limit;
5381573Srgrimes{
5391573Srgrimes	struct stat sb;
5401573Srgrimes	Char *p, *q;
5411573Srgrimes	int anymeta;
5421573Srgrimes
5431573Srgrimes	/*
5441573Srgrimes	 * Loop over pattern segments until end of pattern or until
5451573Srgrimes	 * segment with meta character found.
5461573Srgrimes	 */
5471573Srgrimes	for (anymeta = 0;;) {
5481573Srgrimes		if (*pattern == EOS) {		/* End of pattern? */
5491573Srgrimes			*pathend = EOS;
5501573Srgrimes			if (g_lstat(pathbuf, &sb, pglob))
5511573Srgrimes				return(0);
5528870Srgrimes
5531573Srgrimes			if (((pglob->gl_flags & GLOB_MARK) &&
5541573Srgrimes			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
5551573Srgrimes			    || (S_ISLNK(sb.st_mode) &&
5561573Srgrimes			    (g_stat(pathbuf, &sb, pglob) == 0) &&
5571573Srgrimes			    S_ISDIR(sb.st_mode)))) {
55874963Speter				if (pathend + 1 > pathend_last)
559100217Smikeh					return (GLOB_ABORTED);
5601573Srgrimes				*pathend++ = SEP;
5611573Srgrimes				*pathend = EOS;
5621573Srgrimes			}
5631573Srgrimes			++pglob->gl_matchc;
56474469Sjlemon			return(globextend(pathbuf, pglob, limit));
5651573Srgrimes		}
5661573Srgrimes
5671573Srgrimes		/* Find end of next segment, copy tentatively to pathend. */
5681573Srgrimes		q = pathend;
5691573Srgrimes		p = pattern;
5701573Srgrimes		while (*p != EOS && *p != SEP) {
5711573Srgrimes			if (ismeta(*p))
5721573Srgrimes				anymeta = 1;
57374963Speter			if (q + 1 > pathend_last)
574100217Smikeh				return (GLOB_ABORTED);
5751573Srgrimes			*q++ = *p++;
5761573Srgrimes		}
5771573Srgrimes
5781573Srgrimes		if (!anymeta) {		/* No expansion, do next segment. */
5791573Srgrimes			pathend = q;
5801573Srgrimes			pattern = p;
58174963Speter			while (*pattern == SEP) {
58274963Speter				if (pathend + 1 > pathend_last)
583100217Smikeh					return (GLOB_ABORTED);
5841573Srgrimes				*pathend++ = *pattern++;
58574963Speter			}
5861573Srgrimes		} else			/* Need expansion, recurse. */
58774963Speter			return(glob3(pathbuf, pathend, pathend_last, pattern, p,
58874963Speter			    pglob, limit));
5891573Srgrimes	}
5901573Srgrimes	/* NOTREACHED */
5911573Srgrimes}
5921573Srgrimes
5931573Srgrimesstatic int
59474963Speterglob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
59574963Speter	Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
5961573Srgrimes	glob_t *pglob;
59774469Sjlemon	int *limit;
5981573Srgrimes{
59990045Sobrien	struct dirent *dp;
6001573Srgrimes	DIR *dirp;
6011573Srgrimes	int err;
6021573Srgrimes	char buf[MAXPATHLEN];
6031573Srgrimes
6041573Srgrimes	/*
6051573Srgrimes	 * The readdirfunc declaration can't be prototyped, because it is
6061573Srgrimes	 * assigned, below, to two functions which are prototyped in glob.h
6071573Srgrimes	 * and dirent.h as taking pointers to differently typed opaque
6081573Srgrimes	 * structures.
6091573Srgrimes	 */
6101573Srgrimes	struct dirent *(*readdirfunc)();
6111573Srgrimes
61274963Speter	if (pathend > pathend_last)
613100217Smikeh		return (GLOB_ABORTED);
6141573Srgrimes	*pathend = EOS;
6151573Srgrimes	errno = 0;
6168870Srgrimes
6171573Srgrimes	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
6181573Srgrimes		/* TODO: don't call for ENOENT or ENOTDIR? */
6191573Srgrimes		if (pglob->gl_errfunc) {
62074921Speter			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
621100217Smikeh				return (GLOB_ABORTED);
6221573Srgrimes			if (pglob->gl_errfunc(buf, errno) ||
6231573Srgrimes			    pglob->gl_flags & GLOB_ERR)
624100217Smikeh				return (GLOB_ABORTED);
6251573Srgrimes		}
6261573Srgrimes		return(0);
6271573Srgrimes	}
6281573Srgrimes
6291573Srgrimes	err = 0;
6301573Srgrimes
6311573Srgrimes	/* Search directory for matching names. */
6321573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
6331573Srgrimes		readdirfunc = pglob->gl_readdir;
6341573Srgrimes	else
6351573Srgrimes		readdirfunc = readdir;
6361573Srgrimes	while ((dp = (*readdirfunc)(dirp))) {
63790045Sobrien		u_char *sc;
63890045Sobrien		Char *dc;
6391573Srgrimes
6401573Srgrimes		/* Initial DOT must be matched literally. */
6411573Srgrimes		if (dp->d_name[0] == DOT && *pattern != DOT)
6421573Srgrimes			continue;
64374963Speter		dc = pathend;
64474963Speter		sc = (u_char *) dp->d_name;
64574963Speter		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
64674963Speter			;
6471573Srgrimes		if (!match(pathend, pattern, restpattern)) {
6481573Srgrimes			*pathend = EOS;
6491573Srgrimes			continue;
6501573Srgrimes		}
65174963Speter		err = glob2(pathbuf, --dc, pathend_last, restpattern,
65274963Speter		    pglob, limit);
6531573Srgrimes		if (err)
6541573Srgrimes			break;
6551573Srgrimes	}
6561573Srgrimes
6571573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
6581573Srgrimes		(*pglob->gl_closedir)(dirp);
6591573Srgrimes	else
6601573Srgrimes		closedir(dirp);
6611573Srgrimes	return(err);
6621573Srgrimes}
6631573Srgrimes
6641573Srgrimes
6651573Srgrimes/*
6661573Srgrimes * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
6671573Srgrimes * add the new item, and update gl_pathc.
6681573Srgrimes *
6691573Srgrimes * This assumes the BSD realloc, which only copies the block when its size
6701573Srgrimes * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
6711573Srgrimes * behavior.
6721573Srgrimes *
6731573Srgrimes * Return 0 if new item added, error code if memory couldn't be allocated.
6741573Srgrimes *
6751573Srgrimes * Invariant of the glob_t structure:
6761573Srgrimes *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
6771573Srgrimes *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
6781573Srgrimes */
6791573Srgrimesstatic int
68074469Sjlemonglobextend(path, pglob, limit)
6811573Srgrimes	const Char *path;
6821573Srgrimes	glob_t *pglob;
68374469Sjlemon	int *limit;
6841573Srgrimes{
68590045Sobrien	char **pathv;
68690045Sobrien	int i;
68774918Speter	u_int newsize, len;
6881573Srgrimes	char *copy;
6891573Srgrimes	const Char *p;
6901573Srgrimes
69180525Smikeh	if (*limit && pglob->gl_pathc > *limit) {
69280525Smikeh		errno = 0;
69380525Smikeh		return (GLOB_NOSPACE);
69480525Smikeh	}
69574307Sjlemon
6961573Srgrimes	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
6978870Srgrimes	pathv = pglob->gl_pathv ?
6981573Srgrimes		    realloc((char *)pglob->gl_pathv, newsize) :
6991573Srgrimes		    malloc(newsize);
70074918Speter	if (pathv == NULL) {
70174918Speter		if (pglob->gl_pathv) {
70274918Speter			free(pglob->gl_pathv);
70374918Speter			pglob->gl_pathv = NULL;
70474918Speter		}
7051573Srgrimes		return(GLOB_NOSPACE);
70674918Speter	}
7071573Srgrimes
7081573Srgrimes	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
7091573Srgrimes		/* first time around -- clear initial gl_offs items */
7101573Srgrimes		pathv += pglob->gl_offs;
7111573Srgrimes		for (i = pglob->gl_offs; --i >= 0; )
7121573Srgrimes			*--pathv = NULL;
7131573Srgrimes	}
7141573Srgrimes	pglob->gl_pathv = pathv;
7151573Srgrimes
7161573Srgrimes	for (p = path; *p++;)
7171573Srgrimes		continue;
71874918Speter	len = (size_t)(p - path);
71974921Speter	if ((copy = malloc(len)) != NULL) {
72074921Speter		if (g_Ctoc(path, copy, len)) {
72174918Speter			free(copy);
72274918Speter			return (GLOB_NOSPACE);
72374918Speter		}
7241573Srgrimes		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
7251573Srgrimes	}
7261573Srgrimes	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
7271573Srgrimes	return(copy == NULL ? GLOB_NOSPACE : 0);
7281573Srgrimes}
7291573Srgrimes
7301573Srgrimes/*
7311573Srgrimes * pattern matching function for filenames.  Each occurrence of the *
7321573Srgrimes * pattern causes a recursion level.
7331573Srgrimes */
7341573Srgrimesstatic int
7351573Srgrimesmatch(name, pat, patend)
73690045Sobrien	Char *name, *pat, *patend;
7371573Srgrimes{
7381573Srgrimes	int ok, negate_range;
7391573Srgrimes	Char c, k;
7401573Srgrimes
7411573Srgrimes	while (pat < patend) {
7421573Srgrimes		c = *pat++;
7431573Srgrimes		switch (c & M_MASK) {
7441573Srgrimes		case M_ALL:
7451573Srgrimes			if (pat == patend)
7461573Srgrimes				return(1);
7478870Srgrimes			do
7481573Srgrimes			    if (match(name, pat, patend))
7491573Srgrimes				    return(1);
7501573Srgrimes			while (*name++ != EOS);
7511573Srgrimes			return(0);
7521573Srgrimes		case M_ONE:
7531573Srgrimes			if (*name++ == EOS)
7541573Srgrimes				return(0);
7551573Srgrimes			break;
7561573Srgrimes		case M_SET:
7571573Srgrimes			ok = 0;
7581573Srgrimes			if ((k = *name++) == EOS)
7591573Srgrimes				return(0);
7601573Srgrimes			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
7611573Srgrimes				++pat;
7621573Srgrimes			while (((c = *pat++) & M_MASK) != M_END)
7631573Srgrimes				if ((*pat & M_MASK) == M_RNG) {
76424633Sache					if (__collate_load_error ?
76524633Sache					    CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
76624633Sache					       __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
76719276Sache					    && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
76817528Sache					   )
7691573Srgrimes						ok = 1;
7701573Srgrimes					pat += 2;
7711573Srgrimes				} else if (c == k)
7721573Srgrimes					ok = 1;
7731573Srgrimes			if (ok == negate_range)
7741573Srgrimes				return(0);
7751573Srgrimes			break;
7761573Srgrimes		default:
7771573Srgrimes			if (*name++ != c)
7781573Srgrimes				return(0);
7791573Srgrimes			break;
7801573Srgrimes		}
7811573Srgrimes	}
7821573Srgrimes	return(*name == EOS);
7831573Srgrimes}
7841573Srgrimes
7851573Srgrimes/* Free allocated data belonging to a glob_t structure. */
7861573Srgrimesvoid
7871573Srgrimesglobfree(pglob)
7881573Srgrimes	glob_t *pglob;
7891573Srgrimes{
79090045Sobrien	int i;
79190045Sobrien	char **pp;
7921573Srgrimes
7931573Srgrimes	if (pglob->gl_pathv != NULL) {
7941573Srgrimes		pp = pglob->gl_pathv + pglob->gl_offs;
7951573Srgrimes		for (i = pglob->gl_pathc; i--; ++pp)
7961573Srgrimes			if (*pp)
7971573Srgrimes				free(*pp);
7981573Srgrimes		free(pglob->gl_pathv);
79974918Speter		pglob->gl_pathv = NULL;
8001573Srgrimes	}
8011573Srgrimes}
8021573Srgrimes
8031573Srgrimesstatic DIR *
8041573Srgrimesg_opendir(str, pglob)
80590045Sobrien	Char *str;
8061573Srgrimes	glob_t *pglob;
8071573Srgrimes{
8081573Srgrimes	char buf[MAXPATHLEN];
8091573Srgrimes
8101573Srgrimes	if (!*str)
8111573Srgrimes		strcpy(buf, ".");
81274918Speter	else {
81374921Speter		if (g_Ctoc(str, buf, sizeof(buf)))
81474918Speter			return (NULL);
81574918Speter	}
8161573Srgrimes
8171573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
8181573Srgrimes		return((*pglob->gl_opendir)(buf));
8191573Srgrimes
8201573Srgrimes	return(opendir(buf));
8211573Srgrimes}
8221573Srgrimes
8231573Srgrimesstatic int
8241573Srgrimesg_lstat(fn, sb, pglob)
82590045Sobrien	Char *fn;
8261573Srgrimes	struct stat *sb;
8271573Srgrimes	glob_t *pglob;
8281573Srgrimes{
8291573Srgrimes	char buf[MAXPATHLEN];
8301573Srgrimes
83174921Speter	if (g_Ctoc(fn, buf, sizeof(buf))) {
83274918Speter		errno = ENAMETOOLONG;
83374918Speter		return (-1);
83474918Speter	}
8351573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
8361573Srgrimes		return((*pglob->gl_lstat)(buf, sb));
8371573Srgrimes	return(lstat(buf, sb));
8381573Srgrimes}
8391573Srgrimes
8401573Srgrimesstatic int
8411573Srgrimesg_stat(fn, sb, pglob)
84290045Sobrien	Char *fn;
8431573Srgrimes	struct stat *sb;
8441573Srgrimes	glob_t *pglob;
8451573Srgrimes{
8461573Srgrimes	char buf[MAXPATHLEN];
8471573Srgrimes
84874921Speter	if (g_Ctoc(fn, buf, sizeof(buf))) {
84974918Speter		errno = ENAMETOOLONG;
85074918Speter		return (-1);
85174918Speter	}
8521573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
8531573Srgrimes		return((*pglob->gl_stat)(buf, sb));
8541573Srgrimes	return(stat(buf, sb));
8551573Srgrimes}
8561573Srgrimes
8571573Srgrimesstatic Char *
8581573Srgrimesg_strchr(str, ch)
8591573Srgrimes	Char *str;
8601573Srgrimes	int ch;
8611573Srgrimes{
8621573Srgrimes	do {
8631573Srgrimes		if (*str == ch)
8641573Srgrimes			return (str);
8651573Srgrimes	} while (*str++);
8661573Srgrimes	return (NULL);
8671573Srgrimes}
8681573Srgrimes
86974918Speterstatic int
87074921Speterg_Ctoc(str, buf, len)
87174921Speter	const Char *str;
87274921Speter	char *buf;
87374921Speter	u_int len;
8741573Srgrimes{
8751573Srgrimes
87674921Speter	while (len--) {
87774921Speter		if ((*buf++ = *str++) == '\0')
87874921Speter			return (0);
87974921Speter	}
88074921Speter	return (1);
8811573Srgrimes}
8821573Srgrimes
8831573Srgrimes#ifdef DEBUG
8848870Srgrimesstatic void
8851573Srgrimesqprintf(str, s)
8861573Srgrimes	const char *str;
88790045Sobrien	Char *s;
8881573Srgrimes{
88990045Sobrien	Char *p;
8901573Srgrimes
8911573Srgrimes	(void)printf("%s:\n", str);
8921573Srgrimes	for (p = s; *p; p++)
8931573Srgrimes		(void)printf("%c", CHAR(*p));
8941573Srgrimes	(void)printf("\n");
8951573Srgrimes	for (p = s; *p; p++)
8961573Srgrimes		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
8971573Srgrimes	(void)printf("\n");
8981573Srgrimes	for (p = s; *p; p++)
8991573Srgrimes		(void)printf("%c", ismeta(*p) ? '_' : ' ');
9001573Srgrimes	(void)printf("\n");
9011573Srgrimes}
9021573Srgrimes#endif
903