glob.c revision 24158
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 */
401573Srgrimes
411573Srgrimes/*
421573Srgrimes * glob(3) -- a superset of the one defined in POSIX 1003.2.
431573Srgrimes *
441573Srgrimes * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
451573Srgrimes *
461573Srgrimes * Optional extra services, controlled by flags not defined by POSIX:
471573Srgrimes *
481573Srgrimes * GLOB_QUOTE:
491573Srgrimes *	Escaping convention: \ inhibits any special meaning the following
501573Srgrimes *	character might have (except \ at end of string is retained).
511573Srgrimes * GLOB_MAGCHAR:
521573Srgrimes *	Set in gl_flags if pattern contained a globbing character.
531573Srgrimes * GLOB_NOMAGIC:
541573Srgrimes *	Same as GLOB_NOCHECK, but it will only append pattern if it did
551573Srgrimes *	not contain any magic characters.  [Used in csh style globbing]
561573Srgrimes * GLOB_ALTDIRFUNC:
571573Srgrimes *	Use alternately specified directory access functions.
581573Srgrimes * GLOB_TILDE:
591573Srgrimes *	expand ~user/foo to the /home/dir/of/user/foo
601573Srgrimes * GLOB_BRACE:
618870Srgrimes *	expand {1,2}{a,b} to 1a 1b 2a 2b
621573Srgrimes * gl_matchc:
631573Srgrimes *	Number of matches in the current invocation of glob.
641573Srgrimes */
651573Srgrimes
661573Srgrimes#include <sys/param.h>
671573Srgrimes#include <sys/stat.h>
681573Srgrimes
691573Srgrimes#include <ctype.h>
701573Srgrimes#include <dirent.h>
711573Srgrimes#include <errno.h>
721573Srgrimes#include <glob.h>
731573Srgrimes#include <pwd.h>
741573Srgrimes#include <stdio.h>
751573Srgrimes#include <stdlib.h>
761573Srgrimes#include <string.h>
771573Srgrimes#include <unistd.h>
781573Srgrimes
7919276Sache#include "collate.h"
8019276Sache
811573Srgrimes#define	DOLLAR		'$'
821573Srgrimes#define	DOT		'.'
831573Srgrimes#define	EOS		'\0'
841573Srgrimes#define	LBRACKET	'['
851573Srgrimes#define	NOT		'!'
861573Srgrimes#define	QUESTION	'?'
871573Srgrimes#define	QUOTE		'\\'
881573Srgrimes#define	RANGE		'-'
891573Srgrimes#define	RBRACKET	']'
901573Srgrimes#define	SEP		'/'
911573Srgrimes#define	STAR		'*'
921573Srgrimes#define	TILDE		'~'
931573Srgrimes#define	UNDERSCORE	'_'
941573Srgrimes#define	LBRACE		'{'
951573Srgrimes#define	RBRACE		'}'
961573Srgrimes#define	SLASH		'/'
971573Srgrimes#define	COMMA		','
981573Srgrimes
991573Srgrimes#ifndef DEBUG
1001573Srgrimes
1011573Srgrimes#define	M_QUOTE		0x8000
1021573Srgrimes#define	M_PROTECT	0x4000
1031573Srgrimes#define	M_MASK		0xffff
1041573Srgrimes#define	M_ASCII		0x00ff
1051573Srgrimes
1061573Srgrimestypedef u_short Char;
1071573Srgrimes
1081573Srgrimes#else
1091573Srgrimes
1101573Srgrimes#define	M_QUOTE		0x80
1111573Srgrimes#define	M_PROTECT	0x40
1121573Srgrimes#define	M_MASK		0xff
1131573Srgrimes#define	M_ASCII		0x7f
1141573Srgrimes
1151573Srgrimestypedef char Char;
1161573Srgrimes
1171573Srgrimes#endif
1181573Srgrimes
1191573Srgrimes
1201573Srgrimes#define	CHAR(c)		((Char)((c)&M_ASCII))
1211573Srgrimes#define	META(c)		((Char)((c)|M_QUOTE))
1221573Srgrimes#define	M_ALL		META('*')
1231573Srgrimes#define	M_END		META(']')
1241573Srgrimes#define	M_NOT		META('!')
1251573Srgrimes#define	M_ONE		META('?')
1261573Srgrimes#define	M_RNG		META('-')
1271573Srgrimes#define	M_SET		META('[')
1281573Srgrimes#define	ismeta(c)	(((c)&M_QUOTE) != 0)
1291573Srgrimes
1301573Srgrimes
1311573Srgrimesstatic int	 compare __P((const void *, const void *));
1321573Srgrimesstatic void	 g_Ctoc __P((const Char *, char *));
1331573Srgrimesstatic int	 g_lstat __P((Char *, struct stat *, glob_t *));
1341573Srgrimesstatic DIR	*g_opendir __P((Char *, glob_t *));
1351573Srgrimesstatic Char	*g_strchr __P((Char *, int));
1361573Srgrimes#ifdef notdef
1371573Srgrimesstatic Char	*g_strcat __P((Char *, const Char *));
1381573Srgrimes#endif
1391573Srgrimesstatic int	 g_stat __P((Char *, struct stat *, glob_t *));
1401573Srgrimesstatic int	 glob0 __P((const Char *, glob_t *));
1411573Srgrimesstatic int	 glob1 __P((Char *, glob_t *));
1421573Srgrimesstatic int	 glob2 __P((Char *, Char *, Char *, glob_t *));
1431573Srgrimesstatic int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
1441573Srgrimesstatic int	 globextend __P((const Char *, glob_t *));
14524158Simpstatic const Char *	 globtilde __P((const Char *, Char *, size_t, glob_t *));
1461573Srgrimesstatic int	 globexp1 __P((const Char *, glob_t *));
1471573Srgrimesstatic int	 globexp2 __P((const Char *, const Char *, glob_t *, int *));
1481573Srgrimesstatic int	 match __P((Char *, Char *, Char *));
1491573Srgrimes#ifdef DEBUG
1501573Srgrimesstatic void	 qprintf __P((const char *, Char *));
1511573Srgrimes#endif
1521573Srgrimes
1531573Srgrimesint
1541573Srgrimesglob(pattern, flags, errfunc, pglob)
1551573Srgrimes	const char *pattern;
1561573Srgrimes	int flags, (*errfunc) __P((const char *, int));
1571573Srgrimes	glob_t *pglob;
1581573Srgrimes{
1591573Srgrimes	const u_char *patnext;
1601573Srgrimes	int c;
1611573Srgrimes	Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
1621573Srgrimes
1631573Srgrimes	patnext = (u_char *) pattern;
1641573Srgrimes	if (!(flags & GLOB_APPEND)) {
1651573Srgrimes		pglob->gl_pathc = 0;
1661573Srgrimes		pglob->gl_pathv = NULL;
1671573Srgrimes		if (!(flags & GLOB_DOOFFS))
1681573Srgrimes			pglob->gl_offs = 0;
1691573Srgrimes	}
1701573Srgrimes	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
1711573Srgrimes	pglob->gl_errfunc = errfunc;
1721573Srgrimes	pglob->gl_matchc = 0;
1731573Srgrimes
1741573Srgrimes	bufnext = patbuf;
1751573Srgrimes	bufend = bufnext + MAXPATHLEN;
1761573Srgrimes	if (flags & GLOB_QUOTE) {
1771573Srgrimes		/* Protect the quoted characters. */
1788870Srgrimes		while (bufnext < bufend && (c = *patnext++) != EOS)
1791573Srgrimes			if (c == QUOTE) {
1801573Srgrimes				if ((c = *patnext++) == EOS) {
1811573Srgrimes					c = QUOTE;
1821573Srgrimes					--patnext;
1831573Srgrimes				}
1841573Srgrimes				*bufnext++ = c | M_PROTECT;
1851573Srgrimes			}
1861573Srgrimes			else
1871573Srgrimes				*bufnext++ = c;
1881573Srgrimes	}
1898870Srgrimes	else
1908870Srgrimes	    while (bufnext < bufend && (c = *patnext++) != EOS)
1911573Srgrimes		    *bufnext++ = c;
1921573Srgrimes	*bufnext = EOS;
1931573Srgrimes
1941573Srgrimes	if (flags & GLOB_BRACE)
1951573Srgrimes	    return globexp1(patbuf, pglob);
1961573Srgrimes	else
1971573Srgrimes	    return glob0(patbuf, pglob);
1981573Srgrimes}
1991573Srgrimes
2001573Srgrimes/*
2011573Srgrimes * Expand recursively a glob {} pattern. When there is no more expansion
2021573Srgrimes * invoke the standard globbing routine to glob the rest of the magic
2031573Srgrimes * characters
2041573Srgrimes */
2051573Srgrimesstatic int globexp1(pattern, pglob)
2061573Srgrimes	const Char *pattern;
2071573Srgrimes	glob_t *pglob;
2081573Srgrimes{
2091573Srgrimes	const Char* ptr = pattern;
2101573Srgrimes	int rv;
2111573Srgrimes
2121573Srgrimes	/* Protect a single {}, for find(1), like csh */
2131573Srgrimes	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
2141573Srgrimes		return glob0(pattern, pglob);
2151573Srgrimes
2161573Srgrimes	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
2171573Srgrimes		if (!globexp2(ptr, pattern, pglob, &rv))
2181573Srgrimes			return rv;
2191573Srgrimes
2201573Srgrimes	return glob0(pattern, pglob);
2211573Srgrimes}
2221573Srgrimes
2231573Srgrimes
2241573Srgrimes/*
2251573Srgrimes * Recursive brace globbing helper. Tries to expand a single brace.
2261573Srgrimes * If it succeeds then it invokes globexp1 with the new pattern.
2271573Srgrimes * If it fails then it tries to glob the rest of the pattern and returns.
2281573Srgrimes */
2291573Srgrimesstatic int globexp2(ptr, pattern, pglob, rv)
2301573Srgrimes	const Char *ptr, *pattern;
2311573Srgrimes	glob_t *pglob;
2321573Srgrimes	int *rv;
2331573Srgrimes{
2341573Srgrimes	int     i;
2351573Srgrimes	Char   *lm, *ls;
2361573Srgrimes	const Char *pe, *pm, *pl;
2371573Srgrimes	Char    patbuf[MAXPATHLEN + 1];
2381573Srgrimes
2391573Srgrimes	/* copy part up to the brace */
2401573Srgrimes	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
2411573Srgrimes		continue;
2421573Srgrimes	ls = lm;
2431573Srgrimes
2441573Srgrimes	/* Find the balanced brace */
2451573Srgrimes	for (i = 0, pe = ++ptr; *pe; pe++)
2461573Srgrimes		if (*pe == LBRACKET) {
2471573Srgrimes			/* Ignore everything between [] */
2481573Srgrimes			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
2491573Srgrimes				continue;
2501573Srgrimes			if (*pe == EOS) {
2518870Srgrimes				/*
2521573Srgrimes				 * We could not find a matching RBRACKET.
2531573Srgrimes				 * Ignore and just look for RBRACE
2541573Srgrimes				 */
2551573Srgrimes				pe = pm;
2561573Srgrimes			}
2571573Srgrimes		}
2581573Srgrimes		else if (*pe == LBRACE)
2591573Srgrimes			i++;
2601573Srgrimes		else if (*pe == RBRACE) {
2611573Srgrimes			if (i == 0)
2621573Srgrimes				break;
2631573Srgrimes			i--;
2641573Srgrimes		}
2651573Srgrimes
2661573Srgrimes	/* Non matching braces; just glob the pattern */
2671573Srgrimes	if (i != 0 || *pe == EOS) {
2681573Srgrimes		*rv = glob0(patbuf, pglob);
2691573Srgrimes		return 0;
2701573Srgrimes	}
2711573Srgrimes
2721573Srgrimes	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
2731573Srgrimes		switch (*pm) {
2741573Srgrimes		case LBRACKET:
2751573Srgrimes			/* Ignore everything between [] */
2761573Srgrimes			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
2771573Srgrimes				continue;
2781573Srgrimes			if (*pm == EOS) {
2798870Srgrimes				/*
2801573Srgrimes				 * We could not find a matching RBRACKET.
2811573Srgrimes				 * Ignore and just look for RBRACE
2821573Srgrimes				 */
2831573Srgrimes				pm = pl;
2841573Srgrimes			}
2851573Srgrimes			break;
2861573Srgrimes
2871573Srgrimes		case LBRACE:
2881573Srgrimes			i++;
2891573Srgrimes			break;
2901573Srgrimes
2911573Srgrimes		case RBRACE:
2921573Srgrimes			if (i) {
2931573Srgrimes			    i--;
2941573Srgrimes			    break;
2951573Srgrimes			}
2961573Srgrimes			/* FALLTHROUGH */
2971573Srgrimes		case COMMA:
2981573Srgrimes			if (i && *pm == COMMA)
2991573Srgrimes				break;
3001573Srgrimes			else {
3011573Srgrimes				/* Append the current string */
3021573Srgrimes				for (lm = ls; (pl < pm); *lm++ = *pl++)
3031573Srgrimes					continue;
3048870Srgrimes				/*
3051573Srgrimes				 * Append the rest of the pattern after the
3061573Srgrimes				 * closing brace
3071573Srgrimes				 */
3081573Srgrimes				for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
3091573Srgrimes					continue;
3101573Srgrimes
3111573Srgrimes				/* Expand the current pattern */
3121573Srgrimes#ifdef DEBUG
3131573Srgrimes				qprintf("globexp2:", patbuf);
3141573Srgrimes#endif
3151573Srgrimes				*rv = globexp1(patbuf, pglob);
3161573Srgrimes
3171573Srgrimes				/* move after the comma, to the next string */
3181573Srgrimes				pl = pm + 1;
3191573Srgrimes			}
3201573Srgrimes			break;
3211573Srgrimes
3221573Srgrimes		default:
3231573Srgrimes			break;
3241573Srgrimes		}
3251573Srgrimes	*rv = 0;
3261573Srgrimes	return 0;
3271573Srgrimes}
3281573Srgrimes
3291573Srgrimes
3301573Srgrimes
3311573Srgrimes/*
3321573Srgrimes * expand tilde from the passwd file.
3331573Srgrimes */
3341573Srgrimesstatic const Char *
33524158Simpglobtilde(pattern, patbuf, patbuf_len, pglob)
3361573Srgrimes	const Char *pattern;
3371573Srgrimes	Char *patbuf;
33824158Simp	size_t patbuf_len;
3391573Srgrimes	glob_t *pglob;
3401573Srgrimes{
3411573Srgrimes	struct passwd *pwd;
3421573Srgrimes	char *h;
3431573Srgrimes	const Char *p;
34424158Simp	Char *b, *eb;
3451573Srgrimes
3461573Srgrimes	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
3471573Srgrimes		return pattern;
3481573Srgrimes
34924158Simp	/*
35024158Simp	 * Copy up to the end of the string or /
35124158Simp	 */
35224158Simp	eb = &patbuf[patbuf_len - 1];
35324158Simp	for (p = pattern + 1, h = (char *) patbuf;
35424158Simp	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
3551573Srgrimes		continue;
3561573Srgrimes
3571573Srgrimes	*h = EOS;
3581573Srgrimes
3591573Srgrimes	if (((char *) patbuf)[0] == EOS) {
3608870Srgrimes		/*
3618870Srgrimes		 * handle a plain ~ or ~/ by expanding $HOME
3621573Srgrimes		 * first and then trying the password file
3631573Srgrimes		 */
3641573Srgrimes		if ((h = getenv("HOME")) == NULL) {
3651573Srgrimes			if ((pwd = getpwuid(getuid())) == NULL)
3661573Srgrimes				return pattern;
3671573Srgrimes			else
3681573Srgrimes				h = pwd->pw_dir;
3691573Srgrimes		}
3701573Srgrimes	}
3711573Srgrimes	else {
3721573Srgrimes		/*
3731573Srgrimes		 * Expand a ~user
3741573Srgrimes		 */
3751573Srgrimes		if ((pwd = getpwnam((char*) patbuf)) == NULL)
3761573Srgrimes			return pattern;
3771573Srgrimes		else
3781573Srgrimes			h = pwd->pw_dir;
3791573Srgrimes	}
3801573Srgrimes
3811573Srgrimes	/* Copy the home directory */
38224158Simp	for (b = patbuf; b < eb && *h; *b++ = *h++)
3831573Srgrimes		continue;
3848870Srgrimes
3851573Srgrimes	/* Append the rest of the pattern */
38624158Simp	while (b < eb && (*b++ = *p++) != EOS)
3871573Srgrimes		continue;
38824158Simp	*b = EOS;
3891573Srgrimes
3901573Srgrimes	return patbuf;
3911573Srgrimes}
3921573Srgrimes
3938870Srgrimes
3941573Srgrimes/*
3951573Srgrimes * The main glob() routine: compiles the pattern (optionally processing
3961573Srgrimes * quotes), calls glob1() to do the real pattern matching, and finally
3971573Srgrimes * sorts the list (unless unsorted operation is requested).  Returns 0
3981573Srgrimes * if things went well, nonzero if errors occurred.  It is not an error
3991573Srgrimes * to find no matches.
4001573Srgrimes */
4011573Srgrimesstatic int
4021573Srgrimesglob0(pattern, pglob)
4031573Srgrimes	const Char *pattern;
4041573Srgrimes	glob_t *pglob;
4051573Srgrimes{
4061573Srgrimes	const Char *qpatnext;
4071573Srgrimes	int c, err, oldpathc;
4081573Srgrimes	Char *bufnext, patbuf[MAXPATHLEN+1];
4091573Srgrimes
41024158Simp	qpatnext = globtilde(pattern, patbuf, sizeof(patbuf) / sizeof(Char),
41124158Simp	    pglob);
4121573Srgrimes	oldpathc = pglob->gl_pathc;
4131573Srgrimes	bufnext = patbuf;
4141573Srgrimes
4151573Srgrimes	/* We don't need to check for buffer overflow any more. */
4161573Srgrimes	while ((c = *qpatnext++) != EOS) {
4171573Srgrimes		switch (c) {
4181573Srgrimes		case LBRACKET:
4191573Srgrimes			c = *qpatnext;
4201573Srgrimes			if (c == NOT)
4211573Srgrimes				++qpatnext;
4221573Srgrimes			if (*qpatnext == EOS ||
4231573Srgrimes			    g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
4241573Srgrimes				*bufnext++ = LBRACKET;
4251573Srgrimes				if (c == NOT)
4261573Srgrimes					--qpatnext;
4271573Srgrimes				break;
4281573Srgrimes			}
4291573Srgrimes			*bufnext++ = M_SET;
4301573Srgrimes			if (c == NOT)
4311573Srgrimes				*bufnext++ = M_NOT;
4321573Srgrimes			c = *qpatnext++;
4331573Srgrimes			do {
4341573Srgrimes				*bufnext++ = CHAR(c);
4351573Srgrimes				if (*qpatnext == RANGE &&
4361573Srgrimes				    (c = qpatnext[1]) != RBRACKET) {
4371573Srgrimes					*bufnext++ = M_RNG;
4381573Srgrimes					*bufnext++ = CHAR(c);
4391573Srgrimes					qpatnext += 2;
4401573Srgrimes				}
4411573Srgrimes			} while ((c = *qpatnext++) != RBRACKET);
4421573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4431573Srgrimes			*bufnext++ = M_END;
4441573Srgrimes			break;
4451573Srgrimes		case QUESTION:
4461573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4471573Srgrimes			*bufnext++ = M_ONE;
4481573Srgrimes			break;
4491573Srgrimes		case STAR:
4501573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
4518870Srgrimes			/* collapse adjacent stars to one,
4521573Srgrimes			 * to avoid exponential behavior
4531573Srgrimes			 */
4541573Srgrimes			if (bufnext == patbuf || bufnext[-1] != M_ALL)
4551573Srgrimes			    *bufnext++ = M_ALL;
4561573Srgrimes			break;
4571573Srgrimes		default:
4581573Srgrimes			*bufnext++ = CHAR(c);
4591573Srgrimes			break;
4601573Srgrimes		}
4611573Srgrimes	}
4621573Srgrimes	*bufnext = EOS;
4631573Srgrimes#ifdef DEBUG
4641573Srgrimes	qprintf("glob0:", patbuf);
4651573Srgrimes#endif
4661573Srgrimes
4671573Srgrimes	if ((err = glob1(patbuf, pglob)) != 0)
4681573Srgrimes		return(err);
4691573Srgrimes
4701573Srgrimes	/*
4718870Srgrimes	 * If there was no match we are going to append the pattern
4721573Srgrimes	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
4731573Srgrimes	 * and the pattern did not contain any magic characters
4741573Srgrimes	 * GLOB_NOMAGIC is there just for compatibility with csh.
4751573Srgrimes	 */
4768870Srgrimes	if (pglob->gl_pathc == oldpathc &&
4778870Srgrimes	    ((pglob->gl_flags & GLOB_NOCHECK) ||
4781573Srgrimes	      ((pglob->gl_flags & GLOB_NOMAGIC) &&
4791573Srgrimes	       !(pglob->gl_flags & GLOB_MAGCHAR))))
4801573Srgrimes		return(globextend(pattern, pglob));
4818870Srgrimes	else if (!(pglob->gl_flags & GLOB_NOSORT))
4821573Srgrimes		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
4831573Srgrimes		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
4841573Srgrimes	return(0);
4851573Srgrimes}
4861573Srgrimes
4871573Srgrimesstatic int
4881573Srgrimescompare(p, q)
4891573Srgrimes	const void *p, *q;
4901573Srgrimes{
4911573Srgrimes	return(strcmp(*(char **)p, *(char **)q));
4921573Srgrimes}
4931573Srgrimes
4941573Srgrimesstatic int
4951573Srgrimesglob1(pattern, pglob)
4961573Srgrimes	Char *pattern;
4971573Srgrimes	glob_t *pglob;
4981573Srgrimes{
4991573Srgrimes	Char pathbuf[MAXPATHLEN+1];
5001573Srgrimes
5011573Srgrimes	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
5021573Srgrimes	if (*pattern == EOS)
5031573Srgrimes		return(0);
5041573Srgrimes	return(glob2(pathbuf, pathbuf, pattern, pglob));
5051573Srgrimes}
5061573Srgrimes
5071573Srgrimes/*
5081573Srgrimes * The functions glob2 and glob3 are mutually recursive; there is one level
5091573Srgrimes * of recursion for each segment in the pattern that contains one or more
5101573Srgrimes * meta characters.
5111573Srgrimes */
5121573Srgrimesstatic int
5131573Srgrimesglob2(pathbuf, pathend, pattern, pglob)
5141573Srgrimes	Char *pathbuf, *pathend, *pattern;
5151573Srgrimes	glob_t *pglob;
5161573Srgrimes{
5171573Srgrimes	struct stat sb;
5181573Srgrimes	Char *p, *q;
5191573Srgrimes	int anymeta;
5201573Srgrimes
5211573Srgrimes	/*
5221573Srgrimes	 * Loop over pattern segments until end of pattern or until
5231573Srgrimes	 * segment with meta character found.
5241573Srgrimes	 */
5251573Srgrimes	for (anymeta = 0;;) {
5261573Srgrimes		if (*pattern == EOS) {		/* End of pattern? */
5271573Srgrimes			*pathend = EOS;
5281573Srgrimes			if (g_lstat(pathbuf, &sb, pglob))
5291573Srgrimes				return(0);
5308870Srgrimes
5311573Srgrimes			if (((pglob->gl_flags & GLOB_MARK) &&
5321573Srgrimes			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
5331573Srgrimes			    || (S_ISLNK(sb.st_mode) &&
5341573Srgrimes			    (g_stat(pathbuf, &sb, pglob) == 0) &&
5351573Srgrimes			    S_ISDIR(sb.st_mode)))) {
5361573Srgrimes				*pathend++ = SEP;
5371573Srgrimes				*pathend = EOS;
5381573Srgrimes			}
5391573Srgrimes			++pglob->gl_matchc;
5401573Srgrimes			return(globextend(pathbuf, pglob));
5411573Srgrimes		}
5421573Srgrimes
5431573Srgrimes		/* Find end of next segment, copy tentatively to pathend. */
5441573Srgrimes		q = pathend;
5451573Srgrimes		p = pattern;
5461573Srgrimes		while (*p != EOS && *p != SEP) {
5471573Srgrimes			if (ismeta(*p))
5481573Srgrimes				anymeta = 1;
5491573Srgrimes			*q++ = *p++;
5501573Srgrimes		}
5511573Srgrimes
5521573Srgrimes		if (!anymeta) {		/* No expansion, do next segment. */
5531573Srgrimes			pathend = q;
5541573Srgrimes			pattern = p;
5551573Srgrimes			while (*pattern == SEP)
5561573Srgrimes				*pathend++ = *pattern++;
5571573Srgrimes		} else			/* Need expansion, recurse. */
5581573Srgrimes			return(glob3(pathbuf, pathend, pattern, p, pglob));
5591573Srgrimes	}
5601573Srgrimes	/* NOTREACHED */
5611573Srgrimes}
5621573Srgrimes
5631573Srgrimesstatic int
5641573Srgrimesglob3(pathbuf, pathend, pattern, restpattern, pglob)
5651573Srgrimes	Char *pathbuf, *pathend, *pattern, *restpattern;
5661573Srgrimes	glob_t *pglob;
5671573Srgrimes{
5681573Srgrimes	register struct dirent *dp;
5691573Srgrimes	DIR *dirp;
5701573Srgrimes	int err;
5711573Srgrimes	char buf[MAXPATHLEN];
5721573Srgrimes
5731573Srgrimes	/*
5741573Srgrimes	 * The readdirfunc declaration can't be prototyped, because it is
5751573Srgrimes	 * assigned, below, to two functions which are prototyped in glob.h
5761573Srgrimes	 * and dirent.h as taking pointers to differently typed opaque
5771573Srgrimes	 * structures.
5781573Srgrimes	 */
5791573Srgrimes	struct dirent *(*readdirfunc)();
5801573Srgrimes
5811573Srgrimes	*pathend = EOS;
5821573Srgrimes	errno = 0;
5838870Srgrimes
5841573Srgrimes	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
5851573Srgrimes		/* TODO: don't call for ENOENT or ENOTDIR? */
5861573Srgrimes		if (pglob->gl_errfunc) {
5871573Srgrimes			g_Ctoc(pathbuf, buf);
5881573Srgrimes			if (pglob->gl_errfunc(buf, errno) ||
5891573Srgrimes			    pglob->gl_flags & GLOB_ERR)
5901573Srgrimes				return (GLOB_ABEND);
5911573Srgrimes		}
5921573Srgrimes		return(0);
5931573Srgrimes	}
5941573Srgrimes
5951573Srgrimes	err = 0;
5961573Srgrimes
5971573Srgrimes	/* Search directory for matching names. */
5981573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
5991573Srgrimes		readdirfunc = pglob->gl_readdir;
6001573Srgrimes	else
6011573Srgrimes		readdirfunc = readdir;
6021573Srgrimes	while ((dp = (*readdirfunc)(dirp))) {
6031573Srgrimes		register u_char *sc;
6041573Srgrimes		register Char *dc;
6051573Srgrimes
6061573Srgrimes		/* Initial DOT must be matched literally. */
6071573Srgrimes		if (dp->d_name[0] == DOT && *pattern != DOT)
6081573Srgrimes			continue;
6098870Srgrimes		for (sc = (u_char *) dp->d_name, dc = pathend;
6101573Srgrimes		     (*dc++ = *sc++) != EOS;)
6111573Srgrimes			continue;
6121573Srgrimes		if (!match(pathend, pattern, restpattern)) {
6131573Srgrimes			*pathend = EOS;
6141573Srgrimes			continue;
6151573Srgrimes		}
6161573Srgrimes		err = glob2(pathbuf, --dc, restpattern, pglob);
6171573Srgrimes		if (err)
6181573Srgrimes			break;
6191573Srgrimes	}
6201573Srgrimes
6211573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
6221573Srgrimes		(*pglob->gl_closedir)(dirp);
6231573Srgrimes	else
6241573Srgrimes		closedir(dirp);
6251573Srgrimes	return(err);
6261573Srgrimes}
6271573Srgrimes
6281573Srgrimes
6291573Srgrimes/*
6301573Srgrimes * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
6311573Srgrimes * add the new item, and update gl_pathc.
6321573Srgrimes *
6331573Srgrimes * This assumes the BSD realloc, which only copies the block when its size
6341573Srgrimes * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
6351573Srgrimes * behavior.
6361573Srgrimes *
6371573Srgrimes * Return 0 if new item added, error code if memory couldn't be allocated.
6381573Srgrimes *
6391573Srgrimes * Invariant of the glob_t structure:
6401573Srgrimes *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
6411573Srgrimes *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
6421573Srgrimes */
6431573Srgrimesstatic int
6441573Srgrimesglobextend(path, pglob)
6451573Srgrimes	const Char *path;
6461573Srgrimes	glob_t *pglob;
6471573Srgrimes{
6481573Srgrimes	register char **pathv;
6491573Srgrimes	register int i;
6501573Srgrimes	u_int newsize;
6511573Srgrimes	char *copy;
6521573Srgrimes	const Char *p;
6531573Srgrimes
6541573Srgrimes	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
6558870Srgrimes	pathv = pglob->gl_pathv ?
6561573Srgrimes		    realloc((char *)pglob->gl_pathv, newsize) :
6571573Srgrimes		    malloc(newsize);
6581573Srgrimes	if (pathv == NULL)
6591573Srgrimes		return(GLOB_NOSPACE);
6601573Srgrimes
6611573Srgrimes	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
6621573Srgrimes		/* first time around -- clear initial gl_offs items */
6631573Srgrimes		pathv += pglob->gl_offs;
6641573Srgrimes		for (i = pglob->gl_offs; --i >= 0; )
6651573Srgrimes			*--pathv = NULL;
6661573Srgrimes	}
6671573Srgrimes	pglob->gl_pathv = pathv;
6681573Srgrimes
6691573Srgrimes	for (p = path; *p++;)
6701573Srgrimes		continue;
6711573Srgrimes	if ((copy = malloc(p - path)) != NULL) {
6721573Srgrimes		g_Ctoc(path, copy);
6731573Srgrimes		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
6741573Srgrimes	}
6751573Srgrimes	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
6761573Srgrimes	return(copy == NULL ? GLOB_NOSPACE : 0);
6771573Srgrimes}
6781573Srgrimes
6791573Srgrimes/*
6801573Srgrimes * pattern matching function for filenames.  Each occurrence of the *
6811573Srgrimes * pattern causes a recursion level.
6821573Srgrimes */
6831573Srgrimesstatic int
6841573Srgrimesmatch(name, pat, patend)
6851573Srgrimes	register Char *name, *pat, *patend;
6861573Srgrimes{
6871573Srgrimes	int ok, negate_range;
6881573Srgrimes	Char c, k;
6891573Srgrimes
6901573Srgrimes	while (pat < patend) {
6911573Srgrimes		c = *pat++;
6921573Srgrimes		switch (c & M_MASK) {
6931573Srgrimes		case M_ALL:
6941573Srgrimes			if (pat == patend)
6951573Srgrimes				return(1);
6968870Srgrimes			do
6971573Srgrimes			    if (match(name, pat, patend))
6981573Srgrimes				    return(1);
6991573Srgrimes			while (*name++ != EOS);
7001573Srgrimes			return(0);
7011573Srgrimes		case M_ONE:
7021573Srgrimes			if (*name++ == EOS)
7031573Srgrimes				return(0);
7041573Srgrimes			break;
7051573Srgrimes		case M_SET:
7061573Srgrimes			ok = 0;
7071573Srgrimes			if ((k = *name++) == EOS)
7081573Srgrimes				return(0);
7091573Srgrimes			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
7101573Srgrimes				++pat;
7111573Srgrimes			while (((c = *pat++) & M_MASK) != M_END)
7121573Srgrimes				if ((*pat & M_MASK) == M_RNG) {
71319276Sache					if (   __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
71419276Sache					    && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
71517528Sache					   )
7161573Srgrimes						ok = 1;
7171573Srgrimes					pat += 2;
7181573Srgrimes				} else if (c == k)
7191573Srgrimes					ok = 1;
7201573Srgrimes			if (ok == negate_range)
7211573Srgrimes				return(0);
7221573Srgrimes			break;
7231573Srgrimes		default:
7241573Srgrimes			if (*name++ != c)
7251573Srgrimes				return(0);
7261573Srgrimes			break;
7271573Srgrimes		}
7281573Srgrimes	}
7291573Srgrimes	return(*name == EOS);
7301573Srgrimes}
7311573Srgrimes
7321573Srgrimes/* Free allocated data belonging to a glob_t structure. */
7331573Srgrimesvoid
7341573Srgrimesglobfree(pglob)
7351573Srgrimes	glob_t *pglob;
7361573Srgrimes{
7371573Srgrimes	register int i;
7381573Srgrimes	register char **pp;
7391573Srgrimes
7401573Srgrimes	if (pglob->gl_pathv != NULL) {
7411573Srgrimes		pp = pglob->gl_pathv + pglob->gl_offs;
7421573Srgrimes		for (i = pglob->gl_pathc; i--; ++pp)
7431573Srgrimes			if (*pp)
7441573Srgrimes				free(*pp);
7451573Srgrimes		free(pglob->gl_pathv);
7461573Srgrimes	}
7471573Srgrimes}
7481573Srgrimes
7491573Srgrimesstatic DIR *
7501573Srgrimesg_opendir(str, pglob)
7511573Srgrimes	register Char *str;
7521573Srgrimes	glob_t *pglob;
7531573Srgrimes{
7541573Srgrimes	char buf[MAXPATHLEN];
7551573Srgrimes
7561573Srgrimes	if (!*str)
7571573Srgrimes		strcpy(buf, ".");
7581573Srgrimes	else
7591573Srgrimes		g_Ctoc(str, buf);
7601573Srgrimes
7611573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
7621573Srgrimes		return((*pglob->gl_opendir)(buf));
7631573Srgrimes
7641573Srgrimes	return(opendir(buf));
7651573Srgrimes}
7661573Srgrimes
7671573Srgrimesstatic int
7681573Srgrimesg_lstat(fn, sb, pglob)
7691573Srgrimes	register Char *fn;
7701573Srgrimes	struct stat *sb;
7711573Srgrimes	glob_t *pglob;
7721573Srgrimes{
7731573Srgrimes	char buf[MAXPATHLEN];
7741573Srgrimes
7751573Srgrimes	g_Ctoc(fn, buf);
7761573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
7771573Srgrimes		return((*pglob->gl_lstat)(buf, sb));
7781573Srgrimes	return(lstat(buf, sb));
7791573Srgrimes}
7801573Srgrimes
7811573Srgrimesstatic int
7821573Srgrimesg_stat(fn, sb, pglob)
7831573Srgrimes	register Char *fn;
7841573Srgrimes	struct stat *sb;
7851573Srgrimes	glob_t *pglob;
7861573Srgrimes{
7871573Srgrimes	char buf[MAXPATHLEN];
7881573Srgrimes
7891573Srgrimes	g_Ctoc(fn, buf);
7901573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
7911573Srgrimes		return((*pglob->gl_stat)(buf, sb));
7921573Srgrimes	return(stat(buf, sb));
7931573Srgrimes}
7941573Srgrimes
7951573Srgrimesstatic Char *
7961573Srgrimesg_strchr(str, ch)
7971573Srgrimes	Char *str;
7981573Srgrimes	int ch;
7991573Srgrimes{
8001573Srgrimes	do {
8011573Srgrimes		if (*str == ch)
8021573Srgrimes			return (str);
8031573Srgrimes	} while (*str++);
8041573Srgrimes	return (NULL);
8051573Srgrimes}
8061573Srgrimes
8071573Srgrimes#ifdef notdef
8081573Srgrimesstatic Char *
8091573Srgrimesg_strcat(dst, src)
8101573Srgrimes	Char *dst;
8111573Srgrimes	const Char* src;
8121573Srgrimes{
8131573Srgrimes	Char *sdst = dst;
8141573Srgrimes
8151573Srgrimes	while (*dst++)
8161573Srgrimes		continue;
8171573Srgrimes	--dst;
8181573Srgrimes	while((*dst++ = *src++) != EOS)
8191573Srgrimes	    continue;
8201573Srgrimes
8211573Srgrimes	return (sdst);
8221573Srgrimes}
8231573Srgrimes#endif
8241573Srgrimes
8251573Srgrimesstatic void
8261573Srgrimesg_Ctoc(str, buf)
8271573Srgrimes	register const Char *str;
8281573Srgrimes	char *buf;
8291573Srgrimes{
8301573Srgrimes	register char *dc;
8311573Srgrimes
8321573Srgrimes	for (dc = buf; (*dc++ = *str++) != EOS;)
8331573Srgrimes		continue;
8341573Srgrimes}
8351573Srgrimes
8361573Srgrimes#ifdef DEBUG
8378870Srgrimesstatic void
8381573Srgrimesqprintf(str, s)
8391573Srgrimes	const char *str;
8401573Srgrimes	register Char *s;
8411573Srgrimes{
8421573Srgrimes	register Char *p;
8431573Srgrimes
8441573Srgrimes	(void)printf("%s:\n", str);
8451573Srgrimes	for (p = s; *p; p++)
8461573Srgrimes		(void)printf("%c", CHAR(*p));
8471573Srgrimes	(void)printf("\n");
8481573Srgrimes	for (p = s; *p; p++)
8491573Srgrimes		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
8501573Srgrimes	(void)printf("\n");
8511573Srgrimes	for (p = s; *p; p++)
8521573Srgrimes		(void)printf("%c", ismeta(*p) ? '_' : ' ');
8531573Srgrimes	(void)printf("\n");
8541573Srgrimes}
8551573Srgrimes#endif
856