xref: /csrg-svn/lib/libc/gen/glob.c (revision 57006)
140087Sbostic /*
240087Sbostic  * Copyright (c) 1989 The Regents of the University of California.
340087Sbostic  * All rights reserved.
440087Sbostic  *
540087Sbostic  * This code is derived from software contributed to Berkeley by
640087Sbostic  * Guido van Rossum.
740087Sbostic  *
842625Sbostic  * %sccs.include.redist.c%
940087Sbostic  */
1040087Sbostic 
1140087Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*57006Sbostic static char sccsid[] = "@(#)glob.c	5.18 (Berkeley) 12/04/92";
1340087Sbostic #endif /* LIBC_SCCS and not lint */
1440087Sbostic 
1540087Sbostic /*
1650050Sbostic  * glob(3) -- a superset of the one defined in POSIX 1003.2.
1740087Sbostic  *
1840087Sbostic  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
1940087Sbostic  *
2040087Sbostic  * Optional extra services, controlled by flags not defined by POSIX:
2147590Sbostic  *
2247590Sbostic  * GLOB_QUOTE:
2347590Sbostic  *	Escaping convention: \ inhibits any special meaning the following
2447590Sbostic  *	character might have (except \ at end of string is retained).
2547590Sbostic  * GLOB_MAGCHAR:
2648540Sbostic  *	Set in gl_flags if pattern contained a globbing character.
2750420Sbostic  * GLOB_NOMAGIC:
2850420Sbostic  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
2950420Sbostic  *	not contain any magic characters.  [Used in csh style globbing]
3056942Smckusick  * GLOB_ALTDIRFUNC:
3156942Smckusick  *	Use alternately specified directory access functions.
3247590Sbostic  * gl_matchc:
3347590Sbostic  *	Number of matches in the current invocation of glob.
3440087Sbostic  */
3540087Sbostic 
3640087Sbostic #include <sys/param.h>
3740087Sbostic #include <sys/stat.h>
3840087Sbostic #include <dirent.h>
3940087Sbostic #include <glob.h>
4040087Sbostic #include <ctype.h>
4140087Sbostic #include <errno.h>
4240087Sbostic #include <string.h>
4340087Sbostic #include <stdio.h>
4446597Sdonn #include <stdlib.h>
4540087Sbostic 
4640087Sbostic #define	DOLLAR		'$'
4740087Sbostic #define	DOT		'.'
4840087Sbostic #define	EOS		'\0'
4940087Sbostic #define	LBRACKET	'['
5040087Sbostic #define	NOT		'!'
5140087Sbostic #define	QUESTION	'?'
5240087Sbostic #define	QUOTE		'\\'
5340087Sbostic #define	RANGE		'-'
5440087Sbostic #define	RBRACKET	']'
5540087Sbostic #define	SEP		'/'
5640087Sbostic #define	STAR		'*'
5740087Sbostic #define	TILDE		'~'
5840087Sbostic #define	UNDERSCORE	'_'
5940087Sbostic 
6050049Sbostic #define	M_QUOTE		0x8000
6150049Sbostic #define	M_PROTECT	0x4000
6248540Sbostic #define	M_MASK		0xffff
6350121Sbostic #define	M_ASCII		0x00ff
6448540Sbostic 
6550121Sbostic #define	CHAR(c)		((c)&M_ASCII)
6650049Sbostic #define	META(c)		((c)|M_QUOTE)
6740087Sbostic #define	M_ALL		META('*')
6840087Sbostic #define	M_END		META(']')
6940087Sbostic #define	M_NOT		META('!')
7040087Sbostic #define	M_ONE		META('?')
7140087Sbostic #define	M_RNG		META('-')
7240087Sbostic #define	M_SET		META('[')
7350049Sbostic #define	ismeta(c)	(((c)&M_QUOTE) != 0)
7440087Sbostic 
7550050Sbostic typedef u_short Char;
7650049Sbostic 
7750050Sbostic static int	 compare __P((const void *, const void *));
7850050Sbostic static void	 g_Ctoc __P((Char *, char *));
7956942Smckusick static int	 g_lstat __P((Char *, struct stat *, glob_t *));
8056942Smckusick static DIR	*g_opendir __P((Char *, glob_t *));
8150050Sbostic static Char	*g_strchr __P((Char *, int));
8256942Smckusick static int	 g_stat __P((Char *, struct stat *, glob_t *));
8350050Sbostic static int	 glob1 __P((Char *, glob_t *));
8450050Sbostic static int	 glob2 __P((Char *, Char *, Char *, glob_t *));
8550050Sbostic static int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
8650050Sbostic static int	 globextend __P((Char *, glob_t *));
8750050Sbostic static int	 match __P((Char *, Char *, Char *));
8850049Sbostic #ifdef DEBUG
8950050Sbostic static void	 qprintf __P((Char *));
9050049Sbostic #endif
9150049Sbostic 
9240087Sbostic /*
9340087Sbostic  * The main glob() routine: compiles the pattern (optionally processing
9440087Sbostic  * quotes), calls glob1() to do the real pattern matching, and finally
9540087Sbostic  * sorts the list (unless unsorted operation is requested).  Returns 0
9640087Sbostic  * if things went well, nonzero if errors occurred.  It is not an error
9740087Sbostic  * to find no matches.
9840087Sbostic  */
9940087Sbostic glob(pattern, flags, errfunc, pglob)
10046597Sdonn 	const char *pattern;
10150050Sbostic 	int flags, (*errfunc) __P((char *, int));
10240087Sbostic 	glob_t *pglob;
10340087Sbostic {
10450121Sbostic 	const u_char *compilepat, *patnext;
10550117Sbostic 	int c, err, oldpathc;
10650050Sbostic 	Char *bufnext, *bufend, *compilebuf, *qpatnext, patbuf[MAXPATHLEN+1];
10740087Sbostic 
10850121Sbostic 	patnext = (u_char *) pattern;
10940087Sbostic 	if (!(flags & GLOB_APPEND)) {
11040087Sbostic 		pglob->gl_pathc = 0;
11140087Sbostic 		pglob->gl_pathv = NULL;
11240087Sbostic 		if (!(flags & GLOB_DOOFFS))
11340087Sbostic 			pglob->gl_offs = 0;
11440087Sbostic 	}
11547590Sbostic 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
11640087Sbostic 	pglob->gl_errfunc = errfunc;
11740087Sbostic 	oldpathc = pglob->gl_pathc;
11847590Sbostic 	pglob->gl_matchc = 0;
11940087Sbostic 
12040087Sbostic 	bufnext = patbuf;
12150049Sbostic 	bufend = bufnext + MAXPATHLEN;
12250050Sbostic 	compilebuf = bufnext;
12350050Sbostic 	compilepat = patnext;
12450049Sbostic 	if (flags & GLOB_QUOTE) {
12550050Sbostic 		/* Protect the quoted characters. */
12650049Sbostic 		while (bufnext < bufend && (c = *patnext++) != EOS)
12750049Sbostic 			if (c == QUOTE) {
12850049Sbostic 				if ((c = *patnext++) == EOS) {
12950049Sbostic 					c = QUOTE;
13050049Sbostic 					--patnext;
13150049Sbostic 				}
13250049Sbostic 				*bufnext++ = c | M_PROTECT;
13350049Sbostic 			}
13450049Sbostic 			else
13550049Sbostic 				*bufnext++ = c;
13650049Sbostic 	}
13750049Sbostic 	else
13850049Sbostic 	    while (bufnext < bufend && (c = *patnext++) != EOS)
13950049Sbostic 		    *bufnext++ = c;
14050049Sbostic 	*bufnext = EOS;
14140087Sbostic 
14250049Sbostic 	bufnext = patbuf;
14350049Sbostic 	qpatnext = patbuf;
14450050Sbostic 	/* We don't need to check for buffer overflow any more. */
14550049Sbostic 	while ((c = *qpatnext++) != EOS) {
14640087Sbostic 		switch (c) {
14740087Sbostic 		case LBRACKET:
14850049Sbostic 			c = *qpatnext;
14940087Sbostic 			if (c == NOT)
15050049Sbostic 				++qpatnext;
15150049Sbostic 			if (*qpatnext == EOS ||
15250050Sbostic 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
15340087Sbostic 				*bufnext++ = LBRACKET;
15440087Sbostic 				if (c == NOT)
15550049Sbostic 					--qpatnext;
15640087Sbostic 				break;
15740087Sbostic 			}
15840087Sbostic 			*bufnext++ = M_SET;
15940087Sbostic 			if (c == NOT)
16040087Sbostic 				*bufnext++ = M_NOT;
16150049Sbostic 			c = *qpatnext++;
16240087Sbostic 			do {
16350121Sbostic 				*bufnext++ = CHAR(c);
16450049Sbostic 				if (*qpatnext == RANGE &&
16550049Sbostic 				    (c = qpatnext[1]) != RBRACKET) {
16640087Sbostic 					*bufnext++ = M_RNG;
16750121Sbostic 					*bufnext++ = CHAR(c);
16850049Sbostic 					qpatnext += 2;
16940087Sbostic 				}
17050049Sbostic 			} while ((c = *qpatnext++) != RBRACKET);
17150420Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
17240087Sbostic 			*bufnext++ = M_END;
17340087Sbostic 			break;
17440087Sbostic 		case QUESTION:
17547590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
17640087Sbostic 			*bufnext++ = M_ONE;
17740087Sbostic 			break;
17840087Sbostic 		case STAR:
17947590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
18056373Sbostic 			/* collapse adjacent stars to one,
18156373Sbostic 			 * to avoid exponential behavior
18256373Sbostic 			 */
18356373Sbostic 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
18456373Sbostic 			    *bufnext++ = M_ALL;
18540087Sbostic 			break;
18640087Sbostic 		default:
18750121Sbostic 			*bufnext++ = CHAR(c);
18840087Sbostic 			break;
18940087Sbostic 		}
19040087Sbostic 	}
19140087Sbostic 	*bufnext = EOS;
19250049Sbostic #ifdef DEBUG
19350049Sbostic 	qprintf(patbuf);
19450049Sbostic #endif
19540087Sbostic 
19640087Sbostic 	if ((err = glob1(patbuf, pglob)) != 0)
19740087Sbostic 		return(err);
19840087Sbostic 
19950420Sbostic 	/*
20050420Sbostic 	 * If there was no match we are going to append the pattern
20150420Sbostic 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
20250420Sbostic 	 * and the pattern did not contain any magic characters
20350420Sbostic 	 * GLOB_NOMAGIC is there just for compatibility with csh.
20450420Sbostic 	 */
20550420Sbostic 	if (pglob->gl_pathc == oldpathc &&
20650420Sbostic 	    ((flags & GLOB_NOCHECK) ||
20750420Sbostic 	     ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
20848540Sbostic 		if (!(flags & GLOB_QUOTE)) {
20950050Sbostic 			Char *dp = compilebuf;
21050121Sbostic 			const u_char *sp = compilepat;
21150121Sbostic 			while (*dp++ = *sp++);
21248540Sbostic 		}
21340087Sbostic 		else {
21440087Sbostic 			/*
21550050Sbostic 			 * Copy pattern, interpreting quotes; this is slightly
21640087Sbostic 			 * different than the interpretation of quotes above
21740087Sbostic 			 * -- which should prevail?
21840087Sbostic 			 */
21940087Sbostic 			while (*compilepat != EOS) {
22040087Sbostic 				if (*compilepat == QUOTE) {
22140087Sbostic 					if (*++compilepat == EOS)
22240087Sbostic 						--compilepat;
22340087Sbostic 				}
22448540Sbostic 				*compilebuf++ = (u_char)*compilepat++;
22540087Sbostic 			}
22640087Sbostic 			*compilebuf = EOS;
22740087Sbostic 		}
22840087Sbostic 		return(globextend(patbuf, pglob));
22948540Sbostic 	} else if (!(flags & GLOB_NOSORT))
23050050Sbostic 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
23150050Sbostic 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
23240087Sbostic 	return(0);
23340087Sbostic }
23440087Sbostic 
23550050Sbostic static int
23650050Sbostic compare(p, q)
23750050Sbostic 	const void *p, *q;
23850050Sbostic {
23950050Sbostic 	return(strcmp(*(char **)p, *(char **)q));
24050050Sbostic }
24150050Sbostic 
24240087Sbostic static
24340087Sbostic glob1(pattern, pglob)
24450050Sbostic 	Char *pattern;
24540087Sbostic 	glob_t *pglob;
24640087Sbostic {
24750050Sbostic 	Char pathbuf[MAXPATHLEN+1];
24840087Sbostic 
24950050Sbostic 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
25040087Sbostic 	if (*pattern == EOS)
25140087Sbostic 		return(0);
25240087Sbostic 	return(glob2(pathbuf, pathbuf, pattern, pglob));
25340087Sbostic }
25440087Sbostic 
25540087Sbostic /*
25650050Sbostic  * The functions glob2 and glob3 are mutually recursive; there is one level
25750050Sbostic  * of recursion for each segment in the pattern that contains one or more
25850050Sbostic  * meta characters.
25940087Sbostic  */
26040087Sbostic static
26140087Sbostic glob2(pathbuf, pathend, pattern, pglob)
26250050Sbostic 	Char *pathbuf, *pathend, *pattern;
26340087Sbostic 	glob_t *pglob;
26440087Sbostic {
26550050Sbostic 	struct stat sb;
26650050Sbostic 	Char *p, *q;
26748540Sbostic 	int anymeta;
26840087Sbostic 
26940087Sbostic 	/*
27050050Sbostic 	 * Loop over pattern segments until end of pattern or until
27140087Sbostic 	 * segment with meta character found.
27240087Sbostic 	 */
27348357Sbostic 	for (anymeta = 0;;) {
27450050Sbostic 		if (*pattern == EOS) {		/* End of pattern? */
27540087Sbostic 			*pathend = EOS;
27656942Smckusick 			if (g_lstat(pathbuf, &sb, pglob))
27748357Sbostic 				return(0);
27848540Sbostic 
27948540Sbostic 			if (((pglob->gl_flags & GLOB_MARK) &&
28050050Sbostic 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
28150050Sbostic 			    || (S_ISLNK(sb.st_mode) &&
28256942Smckusick 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
28350050Sbostic 			    S_ISDIR(sb.st_mode)))) {
28440087Sbostic 				*pathend++ = SEP;
28540087Sbostic 				*pathend = EOS;
28640087Sbostic 			}
28747590Sbostic 			++pglob->gl_matchc;
28840087Sbostic 			return(globextend(pathbuf, pglob));
28940087Sbostic 		}
29040087Sbostic 
29150050Sbostic 		/* Find end of next segment, copy tentatively to pathend. */
29240087Sbostic 		q = pathend;
29340087Sbostic 		p = pattern;
29440087Sbostic 		while (*p != EOS && *p != SEP) {
29540087Sbostic 			if (ismeta(*p))
29640087Sbostic 				anymeta = 1;
29740087Sbostic 			*q++ = *p++;
29840087Sbostic 		}
29940087Sbostic 
30050050Sbostic 		if (!anymeta) {		/* No expansion, do next segment. */
30140087Sbostic 			pathend = q;
30240087Sbostic 			pattern = p;
30340087Sbostic 			while (*pattern == SEP)
30440087Sbostic 				*pathend++ = *pattern++;
30550050Sbostic 		} else			/* Need expansion, recurse. */
30640087Sbostic 			return(glob3(pathbuf, pathend, pattern, p, pglob));
30740087Sbostic 	}
30840087Sbostic 	/* NOTREACHED */
30940087Sbostic }
31040087Sbostic 
31140087Sbostic static
31240087Sbostic glob3(pathbuf, pathend, pattern, restpattern, pglob)
31350050Sbostic 	Char *pathbuf, *pathend, *pattern, *restpattern;
31440087Sbostic 	glob_t *pglob;
31540087Sbostic {
31650050Sbostic 	register struct dirent *dp;
31756942Smckusick 	struct dirent *(*readdirfunc)();
31840087Sbostic 	DIR *dirp;
31940087Sbostic 	int len, err;
320*57006Sbostic 	char buf[MAXPATHLEN];
32140087Sbostic 
32240087Sbostic 	*pathend = EOS;
32340087Sbostic 	errno = 0;
32448540Sbostic 
325*57006Sbostic 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
32650050Sbostic 		/* TODO: don't call for ENOENT or ENOTDIR? */
327*57006Sbostic 		if (pglob->gl_errfunc) {
328*57006Sbostic 			g_Ctoc(pathbuf, buf);
329*57006Sbostic 			if (pglob->gl_errfunc(buf, errno) ||
330*57006Sbostic 			    pglob->gl_flags & GLOB_ERR)
331*57006Sbostic 				return (GLOB_ABEND);
332*57006Sbostic 		}
333*57006Sbostic 		return(0);
334*57006Sbostic 	}
33540087Sbostic 
33640087Sbostic 	err = 0;
33740087Sbostic 
33850050Sbostic 	/* Search directory for matching names. */
33956942Smckusick 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
34056942Smckusick 		readdirfunc = pglob->gl_readdir;
34156942Smckusick 	else
34256942Smckusick 		readdirfunc = readdir;
34356942Smckusick 	while ((dp = (*readdirfunc)(dirp))) {
34450121Sbostic 		register u_char *sc;
34550050Sbostic 		register Char *dc;
34650050Sbostic 
34750050Sbostic 		/* Initial DOT must be matched literally. */
34840087Sbostic 		if (dp->d_name[0] == DOT && *pattern != DOT)
34940087Sbostic 			continue;
35050121Sbostic 		for (sc = (u_char *) dp->d_name, dc = pathend;
35150121Sbostic 		     *dc++ = *sc++;);
35248540Sbostic 		if (!match(pathend, pattern, restpattern)) {
35348540Sbostic 			*pathend = EOS;
35440087Sbostic 			continue;
35548540Sbostic 		}
35648540Sbostic 		err = glob2(pathbuf, --dc, restpattern, pglob);
35740087Sbostic 		if (err)
35840087Sbostic 			break;
35940087Sbostic 	}
36050050Sbostic 
36156942Smckusick 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
36256942Smckusick 		(*pglob->gl_closedir)(dirp);
36356942Smckusick 	else
36456942Smckusick 		closedir(dirp);
36540087Sbostic 	return(err);
36640087Sbostic }
36740087Sbostic 
36840087Sbostic 
36940087Sbostic /*
37040087Sbostic  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
37140087Sbostic  * add the new item, and update gl_pathc.
37240087Sbostic  *
37340087Sbostic  * This assumes the BSD realloc, which only copies the block when its size
37440087Sbostic  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
37540087Sbostic  * behavior.
37640087Sbostic  *
37740087Sbostic  * Return 0 if new item added, error code if memory couldn't be allocated.
37840087Sbostic  *
37940087Sbostic  * Invariant of the glob_t structure:
38040087Sbostic  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
38150050Sbostic  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
38240087Sbostic  */
38348540Sbostic static int
38440087Sbostic globextend(path, pglob)
38550050Sbostic 	Char *path;
38640087Sbostic 	glob_t *pglob;
38740087Sbostic {
38840087Sbostic 	register char **pathv;
38940087Sbostic 	register int i;
39048540Sbostic 	u_int newsize;
39140087Sbostic 	char *copy;
39250050Sbostic 	Char *p;
39340087Sbostic 
39440087Sbostic 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
39548540Sbostic 	pathv = (char **)realloc((char *)pglob->gl_pathv, newsize);
39640087Sbostic 	if (pathv == NULL)
39740087Sbostic 		return(GLOB_NOSPACE);
39840087Sbostic 
39940087Sbostic 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
40040087Sbostic 		/* first time around -- clear initial gl_offs items */
40140087Sbostic 		pathv += pglob->gl_offs;
40240087Sbostic 		for (i = pglob->gl_offs; --i >= 0; )
40340087Sbostic 			*--pathv = NULL;
40440087Sbostic 	}
40540087Sbostic 	pglob->gl_pathv = pathv;
40640087Sbostic 
40748540Sbostic 	for (p = path; *p++;);
40848540Sbostic 	if ((copy = malloc(p - path)) != NULL) {
40950050Sbostic 		g_Ctoc(path, copy);
41040087Sbostic 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
41140087Sbostic 	}
41240087Sbostic 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
41350050Sbostic 	return(copy == NULL ? GLOB_NOSPACE : 0);
41440087Sbostic }
41540087Sbostic 
41640087Sbostic 
41740087Sbostic /*
41840087Sbostic  * pattern matching function for filenames.  Each occurrence of the *
41940087Sbostic  * pattern causes a recursion level.
42040087Sbostic  */
42148540Sbostic static
42240087Sbostic match(name, pat, patend)
42350050Sbostic 	register Char *name, *pat, *patend;
42440087Sbostic {
42548540Sbostic 	int ok, negate_range;
42650050Sbostic 	Char c, k;
42740087Sbostic 
42840087Sbostic 	while (pat < patend) {
42940087Sbostic 		c = *pat++;
43048540Sbostic 		switch (c & M_MASK) {
43140087Sbostic 		case M_ALL:
43240087Sbostic 			if (pat == patend)
43340087Sbostic 				return(1);
43456373Sbostic 			do
43556373Sbostic 			    if (match(name, pat, patend))
43656373Sbostic 				    return(1);
43756373Sbostic 			while (*name++ != EOS);
43840087Sbostic 			return(0);
43940087Sbostic 		case M_ONE:
44040087Sbostic 			if (*name++ == EOS)
44140087Sbostic 				return(0);
44240087Sbostic 			break;
44340087Sbostic 		case M_SET:
44440087Sbostic 			ok = 0;
44552339Sbostic 			if ((k = *name++) == EOS)
44652339Sbostic 				return(0);
44748540Sbostic 			if (negate_range = ((*pat & M_MASK) == M_NOT))
44840087Sbostic 				++pat;
44950050Sbostic 			while (((c = *pat++) & M_MASK) != M_END)
45048540Sbostic 				if ((*pat & M_MASK) == M_RNG) {
45140087Sbostic 					if (c <= k && k <= pat[1])
45240087Sbostic 						ok = 1;
45340087Sbostic 					pat += 2;
45450050Sbostic 				} else if (c == k)
45540087Sbostic 					ok = 1;
45640087Sbostic 			if (ok == negate_range)
45740087Sbostic 				return(0);
45840087Sbostic 			break;
45940087Sbostic 		default:
46040087Sbostic 			if (*name++ != c)
46140087Sbostic 				return(0);
46240087Sbostic 			break;
46340087Sbostic 		}
46440087Sbostic 	}
46540087Sbostic 	return(*name == EOS);
46640087Sbostic }
46740087Sbostic 
46850050Sbostic /* Free allocated data belonging to a glob_t structure. */
46940087Sbostic void
47040087Sbostic globfree(pglob)
47140087Sbostic 	glob_t *pglob;
47240087Sbostic {
47340087Sbostic 	register int i;
47440087Sbostic 	register char **pp;
47540087Sbostic 
47640087Sbostic 	if (pglob->gl_pathv != NULL) {
47740087Sbostic 		pp = pglob->gl_pathv + pglob->gl_offs;
47840087Sbostic 		for (i = pglob->gl_pathc; i--; ++pp)
47940087Sbostic 			if (*pp)
48050050Sbostic 				free(*pp);
48150049Sbostic 		free(pglob->gl_pathv);
48240087Sbostic 	}
48340087Sbostic }
48450050Sbostic 
48550050Sbostic static DIR *
48656942Smckusick g_opendir(str, pglob)
48750050Sbostic 	register Char *str;
48856942Smckusick 	glob_t *pglob;
48950050Sbostic {
49050050Sbostic 	char buf[MAXPATHLEN];
49156942Smckusick 	char *dirname;
49250050Sbostic 
49350050Sbostic 	if (!*str)
49456942Smckusick 		strcpy(buf, ".");
49556942Smckusick 	else
49656942Smckusick 		g_Ctoc(str, buf);
49756942Smckusick 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
49856942Smckusick 		return((*pglob->gl_opendir)(buf));
49950050Sbostic 	return(opendir(buf));
50050050Sbostic }
50150050Sbostic 
50250050Sbostic static int
50356942Smckusick g_lstat(fn, sb, pglob)
50450050Sbostic 	register Char *fn;
50550050Sbostic 	struct stat *sb;
50656942Smckusick 	glob_t *pglob;
50750050Sbostic {
50850050Sbostic 	char buf[MAXPATHLEN];
50950050Sbostic 
51050050Sbostic 	g_Ctoc(fn, buf);
51156942Smckusick 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
51256942Smckusick 		return((*pglob->gl_lstat)(buf, sb));
51350050Sbostic 	return(lstat(buf, sb));
51450050Sbostic }
51550050Sbostic 
51650050Sbostic static int
51756942Smckusick g_stat(fn, sb, pglob)
51850050Sbostic 	register Char *fn;
51950050Sbostic 	struct stat *sb;
52056942Smckusick 	glob_t *pglob;
52150050Sbostic {
52250050Sbostic 	char buf[MAXPATHLEN];
52350050Sbostic 
52450050Sbostic 	g_Ctoc(fn, buf);
52556942Smckusick 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
52656942Smckusick 		return((*pglob->gl_stat)(buf, sb));
52750050Sbostic 	return(stat(buf, sb));
52850050Sbostic }
52950050Sbostic 
53050050Sbostic static Char *
53150050Sbostic g_strchr(str, ch)
53250050Sbostic 	Char *str;
53350050Sbostic 	int ch;
53450050Sbostic {
53550050Sbostic 	do {
53650050Sbostic 		if (*str == ch)
53750050Sbostic 			return (str);
53850050Sbostic 	} while (*str++);
53950050Sbostic 	return (NULL);
54050050Sbostic }
54150050Sbostic 
54250050Sbostic static void
54350050Sbostic g_Ctoc(str, buf)
54450050Sbostic 	register Char *str;
54550050Sbostic 	char *buf;
54650050Sbostic {
54750050Sbostic 	register char *dc;
54850050Sbostic 
54950050Sbostic 	for (dc = buf; *dc++ = *str++;);
55050050Sbostic }
55150050Sbostic 
55250050Sbostic #ifdef DEBUG
55350050Sbostic static void
55450050Sbostic qprintf(s)
55550050Sbostic 	register Char *s;
55650050Sbostic {
55750050Sbostic 	register Char *p;
55850050Sbostic 
55950050Sbostic 	for (p = s; *p; p++)
560*57006Sbostic 		(void)printf("%c", CHAR(*p));
56150050Sbostic 	(void)printf("\n");
56250050Sbostic 	for (p = s; *p; p++)
56350050Sbostic 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
56450050Sbostic 	(void)printf("\n");
56550050Sbostic 	for (p = s; *p; p++)
566*57006Sbostic 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
56750050Sbostic 	(void)printf("\n");
56850050Sbostic }
56950050Sbostic #endif
570