xref: /csrg-svn/lib/libc/gen/glob.c (revision 50049)
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*50049Sbostic static char sccsid[] = "@(#)glob.c	5.9 (Berkeley) 06/16/91";
1340087Sbostic #endif /* LIBC_SCCS and not lint */
1440087Sbostic 
1540087Sbostic /*
1640087Sbostic  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
1740087Sbostic  * draft 9.
1840087Sbostic  *
1940087Sbostic  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
2040087Sbostic  *
2140087Sbostic  * Optional extra services, controlled by flags not defined by POSIX:
2247590Sbostic  *
2347590Sbostic  * GLOB_QUOTE:
2447590Sbostic  *	Escaping convention: \ inhibits any special meaning the following
2547590Sbostic  *	character might have (except \ at end of string is retained).
2647590Sbostic  * GLOB_MAGCHAR:
2748540Sbostic  *	Set in gl_flags if pattern contained a globbing character.
2847590Sbostic  * gl_matchc:
2947590Sbostic  *	Number of matches in the current invocation of glob.
3040087Sbostic  */
3140087Sbostic 
3248540Sbostic #include <sys/cdefs.h>
3340087Sbostic #include <sys/param.h>
3440087Sbostic #include <sys/stat.h>
3540087Sbostic #include <dirent.h>
3640087Sbostic #include <glob.h>
3740087Sbostic #include <ctype.h>
3840087Sbostic #include <errno.h>
3940087Sbostic #include <string.h>
4040087Sbostic #include <stdio.h>
4146597Sdonn #include <stdlib.h>
4240087Sbostic 
4340087Sbostic #define	DOLLAR		'$'
4440087Sbostic #define	DOT		'.'
4540087Sbostic #define	EOS		'\0'
4640087Sbostic #define	LBRACKET	'['
4740087Sbostic #define	NOT		'!'
4840087Sbostic #define	QUESTION	'?'
4940087Sbostic #define	QUOTE		'\\'
5040087Sbostic #define	RANGE		'-'
5140087Sbostic #define	RBRACKET	']'
5240087Sbostic #define	SEP		'/'
5340087Sbostic #define	STAR		'*'
5440087Sbostic #define	TILDE		'~'
5540087Sbostic #define	UNDERSCORE	'_'
5640087Sbostic 
57*50049Sbostic #define	M_QUOTE		0x8000
58*50049Sbostic #define	M_PROTECT	0x4000
5948540Sbostic #define	M_MASK		0xffff
6048540Sbostic 
61*50049Sbostic #define	META(c)		((c)|M_QUOTE)
6240087Sbostic #define	M_ALL		META('*')
6340087Sbostic #define	M_END		META(']')
6440087Sbostic #define	M_NOT		META('!')
6540087Sbostic #define	M_ONE		META('?')
6640087Sbostic #define	M_RNG		META('-')
6740087Sbostic #define	M_SET		META('[')
68*50049Sbostic #define	ismeta(c)	(((c)&M_QUOTE) != 0)
6940087Sbostic 
70*50049Sbostic typedef u_short shortchar_t;
71*50049Sbostic 
72*50049Sbostic static int glob1 __P((shortchar_t *, glob_t *));
73*50049Sbostic static int glob2 __P((shortchar_t *, shortchar_t *, shortchar_t *, glob_t *));
74*50049Sbostic static int glob3 __P((shortchar_t *,
75*50049Sbostic 	shortchar_t *, shortchar_t *, shortchar_t *, glob_t *));
76*50049Sbostic static int globextend __P((shortchar_t *, glob_t *));
77*50049Sbostic static int match __P((shortchar_t *, shortchar_t *, shortchar_t *));
78*50049Sbostic static DIR *Opendir __P((shortchar_t *));
79*50049Sbostic static int Lstat __P((shortchar_t *, struct stat *));
80*50049Sbostic static int Stat __P((shortchar_t *, struct stat *));
81*50049Sbostic static shortchar_t *Strchr __P((shortchar_t *, int));
82*50049Sbostic #ifdef DEBUG
83*50049Sbostic static void qprintf __P((shortchar_t *));
84*50049Sbostic #endif
85*50049Sbostic 
8648540Sbostic static DIR *
8748540Sbostic Opendir(str)
88*50049Sbostic 	register shortchar_t *str;
8948540Sbostic {
9048540Sbostic 	register char *dc;
9148540Sbostic 	char buf[MAXPATHLEN];
9248540Sbostic 
9348540Sbostic 	if (!*str)
9448540Sbostic 		return(opendir("."));
9548540Sbostic 	for (dc = buf; *dc++ = *str++;);
9648540Sbostic 	return(opendir(buf));
9748540Sbostic }
9848540Sbostic 
9948540Sbostic static int
10048540Sbostic Lstat(fn, sb)
101*50049Sbostic 	register shortchar_t *fn;
102*50049Sbostic 	struct stat *sb;
10348540Sbostic {
10448540Sbostic 	register char *dc;
10548540Sbostic 	char buf[MAXPATHLEN];
10648540Sbostic 
10748540Sbostic 	for (dc = buf; *dc++ = *fn++;);
10848540Sbostic 	return(lstat(buf, sb));
10948540Sbostic }
11048540Sbostic 
11148540Sbostic static int
11248540Sbostic Stat(fn, sb)
113*50049Sbostic 	register shortchar_t *fn;
114*50049Sbostic 	struct stat *sb;
11548540Sbostic {
11648540Sbostic 	register char *dc;
11748540Sbostic 	char buf[MAXPATHLEN];
11848540Sbostic 
11948540Sbostic 	for (dc = buf; *dc++ = *fn++;);
12048540Sbostic 	return(stat(buf, sb));
12148540Sbostic }
122*50049Sbostic 
123*50049Sbostic static shortchar_t *
124*50049Sbostic Strchr(str, ch)
125*50049Sbostic 	shortchar_t *str;
126*50049Sbostic 	int ch;
127*50049Sbostic {
128*50049Sbostic 	do {
129*50049Sbostic 		if (*str == ch)
130*50049Sbostic 			return (str);
131*50049Sbostic 	} while (*str++);
132*50049Sbostic 	return (NULL);
133*50049Sbostic }
134*50049Sbostic 
135*50049Sbostic #ifdef DEBUG
136*50049Sbostic static void
137*50049Sbostic qprintf(s)
138*50049Sbostic shortchar_t *s;
139*50049Sbostic {
140*50049Sbostic 	shortchar_t *p;
141*50049Sbostic 
142*50049Sbostic 	for (p = s; *p; p++)
143*50049Sbostic 		printf("%c", *p & 0xff);
144*50049Sbostic 	printf("\n");
145*50049Sbostic 	for (p = s; *p; p++)
146*50049Sbostic 		printf("%c", *p & M_PROTECT ? '"' : ' ');
147*50049Sbostic 	printf("\n");
148*50049Sbostic 	for (p = s; *p; p++)
149*50049Sbostic 		printf("%c", *p & M_META ? '_' : ' ');
150*50049Sbostic 	printf("\n");
151*50049Sbostic }
15248540Sbostic #endif
15348540Sbostic 
15448540Sbostic static int
15540087Sbostic compare(p, q)
15643531Sbostic 	void **p, **q;
15740087Sbostic {
15843531Sbostic 	return(strcmp(*(char **)p, *(char **)q));
15940087Sbostic }
16040087Sbostic 
16140087Sbostic /*
16240087Sbostic  * The main glob() routine: compiles the pattern (optionally processing
16340087Sbostic  * quotes), calls glob1() to do the real pattern matching, and finally
16440087Sbostic  * sorts the list (unless unsorted operation is requested).  Returns 0
16540087Sbostic  * if things went well, nonzero if errors occurred.  It is not an error
16640087Sbostic  * to find no matches.
16740087Sbostic  */
16840087Sbostic glob(pattern, flags, errfunc, pglob)
16946597Sdonn 	const char *pattern;
17046597Sdonn 	int flags;
17146597Sdonn 	int (*errfunc) __P((char *, int));
17240087Sbostic 	glob_t *pglob;
17340087Sbostic {
17440087Sbostic 	int err, oldpathc;
17548540Sbostic 	shortchar_t *bufnext, *bufend, *compilebuf;
17646597Sdonn 	const char *compilepat, *patnext;
17748540Sbostic 	char c;
178*50049Sbostic 	shortchar_t patbuf[MAXPATHLEN+1], *qpatnext;
17940087Sbostic 
18040087Sbostic 	patnext = pattern;
18140087Sbostic 	if (!(flags & GLOB_APPEND)) {
18240087Sbostic 		pglob->gl_pathc = 0;
18340087Sbostic 		pglob->gl_pathv = NULL;
18440087Sbostic 		if (!(flags & GLOB_DOOFFS))
18540087Sbostic 			pglob->gl_offs = 0;
18640087Sbostic 	}
18747590Sbostic 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
18840087Sbostic 	pglob->gl_errfunc = errfunc;
18940087Sbostic 	oldpathc = pglob->gl_pathc;
19047590Sbostic 	pglob->gl_matchc = 0;
19140087Sbostic 
19240087Sbostic 	bufnext = patbuf;
193*50049Sbostic 	bufend = bufnext + MAXPATHLEN;
194*50049Sbostic 	if (flags & GLOB_QUOTE) {
195*50049Sbostic 		/* Protect the quoted characters */
196*50049Sbostic 		while (bufnext < bufend && (c = *patnext++) != EOS)
197*50049Sbostic 			if (c == QUOTE) {
198*50049Sbostic 				if ((c = *patnext++) == EOS) {
199*50049Sbostic 					c = QUOTE;
200*50049Sbostic 					--patnext;
201*50049Sbostic 				}
202*50049Sbostic 				*bufnext++ = c | M_PROTECT;
203*50049Sbostic 			}
204*50049Sbostic 			else
205*50049Sbostic 				*bufnext++ = c;
206*50049Sbostic 	}
207*50049Sbostic 	else
208*50049Sbostic 	    while (bufnext < bufend && (c = *patnext++) != EOS)
209*50049Sbostic 		    *bufnext++ = c;
210*50049Sbostic 	*bufnext = EOS;
21140087Sbostic 
212*50049Sbostic 	bufnext = patbuf;
213*50049Sbostic 	qpatnext = patbuf;
21440087Sbostic 	compilebuf = bufnext;
21540087Sbostic 	compilepat = patnext;
216*50049Sbostic 	/* we don't need to check for buffer overflow any more */
217*50049Sbostic 	while ((c = *qpatnext++) != EOS) {
21840087Sbostic 		switch (c) {
21940087Sbostic 		case LBRACKET:
22047590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
221*50049Sbostic 			c = *qpatnext;
22240087Sbostic 			if (c == NOT)
223*50049Sbostic 				++qpatnext;
224*50049Sbostic 			if (*qpatnext == EOS ||
225*50049Sbostic 			    Strchr(qpatnext+1, RBRACKET) == NULL) {
22640087Sbostic 				*bufnext++ = LBRACKET;
22740087Sbostic 				if (c == NOT)
228*50049Sbostic 					--qpatnext;
22940087Sbostic 				break;
23040087Sbostic 			}
23140087Sbostic 			*bufnext++ = M_SET;
23240087Sbostic 			if (c == NOT)
23340087Sbostic 				*bufnext++ = M_NOT;
234*50049Sbostic 			c = *qpatnext++;
23540087Sbostic 			do {
23640087Sbostic 				*bufnext++ = c;
237*50049Sbostic 				if (*qpatnext == RANGE &&
238*50049Sbostic 				    (c = qpatnext[1]) != RBRACKET) {
23940087Sbostic 					*bufnext++ = M_RNG;
24040087Sbostic 					*bufnext++ = c;
241*50049Sbostic 					qpatnext += 2;
24240087Sbostic 				}
243*50049Sbostic 			} while ((c = *qpatnext++) != RBRACKET);
24440087Sbostic 			*bufnext++ = M_END;
24540087Sbostic 			break;
24640087Sbostic 		case QUESTION:
24747590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
24840087Sbostic 			*bufnext++ = M_ONE;
24940087Sbostic 			break;
25040087Sbostic 		case STAR:
25147590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
25240087Sbostic 			*bufnext++ = M_ALL;
25340087Sbostic 			break;
25440087Sbostic 		default:
25540087Sbostic 			*bufnext++ = c;
25640087Sbostic 			break;
25740087Sbostic 		}
25840087Sbostic 	}
25940087Sbostic 	*bufnext = EOS;
260*50049Sbostic #ifdef DEBUG
261*50049Sbostic 	qprintf(patbuf);
262*50049Sbostic #endif
26340087Sbostic 
26440087Sbostic 	if ((err = glob1(patbuf, pglob)) != 0)
26540087Sbostic 		return(err);
26640087Sbostic 
26740087Sbostic 	if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) {
26848540Sbostic 		if (!(flags & GLOB_QUOTE)) {
26948540Sbostic 			shortchar_t *dp = compilebuf;
27048540Sbostic 			const char *sp = compilepat;
27148540Sbostic 			while (*dp++ = (u_char)*sp++);
27248540Sbostic 		}
27340087Sbostic 		else {
27440087Sbostic 			/*
27540087Sbostic 			 * copy pattern, interpreting quotes; this is slightly
27640087Sbostic 			 * different than the interpretation of quotes above
27740087Sbostic 			 * -- which should prevail?
27840087Sbostic 			 */
27940087Sbostic 			while (*compilepat != EOS) {
28040087Sbostic 				if (*compilepat == QUOTE) {
28140087Sbostic 					if (*++compilepat == EOS)
28240087Sbostic 						--compilepat;
28340087Sbostic 				}
28448540Sbostic 				*compilebuf++ = (u_char)*compilepat++;
28540087Sbostic 			}
28640087Sbostic 			*compilebuf = EOS;
28740087Sbostic 		}
28840087Sbostic 		return(globextend(patbuf, pglob));
28948540Sbostic 	} else if (!(flags & GLOB_NOSORT))
29048540Sbostic 		qsort((char*)(pglob->gl_pathv + pglob->gl_offs + oldpathc),
29140087Sbostic 		    pglob->gl_pathc - oldpathc, sizeof(char*), compare);
29240087Sbostic 	return(0);
29340087Sbostic }
29440087Sbostic 
29540087Sbostic static
29640087Sbostic glob1(pattern, pglob)
29748540Sbostic 	shortchar_t *pattern;
29840087Sbostic 	glob_t *pglob;
29940087Sbostic {
30048540Sbostic 	shortchar_t pathbuf[MAXPATHLEN+1];
30140087Sbostic 
30240087Sbostic 	/*
303*50049Sbostic 	 * A null pathname is invalid -- POSIX 1003.1 sect. 2.4.
30448540Sbostic 	 */
30540087Sbostic 	if (*pattern == EOS)
30640087Sbostic 		return(0);
30740087Sbostic 	return(glob2(pathbuf, pathbuf, pattern, pglob));
30840087Sbostic }
30940087Sbostic 
31040087Sbostic /*
31140087Sbostic  * functions glob2 and glob3 are mutually recursive; there is one level
31240087Sbostic  * of recursion for each segment in the pattern that contains one or
31340087Sbostic  * more meta characters.
31440087Sbostic  */
31540087Sbostic static
31640087Sbostic glob2(pathbuf, pathend, pattern, pglob)
31748540Sbostic 	shortchar_t *pathbuf, *pathend, *pattern;
31840087Sbostic 	glob_t *pglob;
31940087Sbostic {
32048540Sbostic 	struct stat sbuf;
32148540Sbostic 	shortchar_t *p, *q;
32248540Sbostic 	int anymeta;
32340087Sbostic 
32440087Sbostic 	/*
32540087Sbostic 	 * loop over pattern segments until end of pattern or until
32640087Sbostic 	 * segment with meta character found.
32740087Sbostic 	 */
32848357Sbostic 	for (anymeta = 0;;) {
32940087Sbostic 		if (*pattern == EOS) {		/* end of pattern? */
33040087Sbostic 			*pathend = EOS;
33148540Sbostic 			if (Lstat(pathbuf, &sbuf))
33248357Sbostic 				return(0);
33348540Sbostic 
33448540Sbostic 			if (((pglob->gl_flags & GLOB_MARK) &&
33548540Sbostic 			    pathend[-1] != SEP) && (S_ISDIR(sbuf.st_mode)
33648540Sbostic 			    || (S_ISLNK(sbuf.st_mode) &&
33748540Sbostic 			    (Stat(pathbuf, &sbuf) == 0) &&
33848540Sbostic 			    S_ISDIR(sbuf.st_mode)))) {
33940087Sbostic 				*pathend++ = SEP;
34040087Sbostic 				*pathend = EOS;
34140087Sbostic 			}
34247590Sbostic 			++pglob->gl_matchc;
34340087Sbostic 			return(globextend(pathbuf, pglob));
34440087Sbostic 		}
34540087Sbostic 
34640087Sbostic 		/* find end of next segment, copy tentatively to pathend */
34740087Sbostic 		q = pathend;
34840087Sbostic 		p = pattern;
34940087Sbostic 		while (*p != EOS && *p != SEP) {
35040087Sbostic 			if (ismeta(*p))
35140087Sbostic 				anymeta = 1;
35240087Sbostic 			*q++ = *p++;
35340087Sbostic 		}
35440087Sbostic 
35540087Sbostic 		if (!anymeta) {		/* no expansion, do next segment */
35640087Sbostic 			pathend = q;
35740087Sbostic 			pattern = p;
35840087Sbostic 			while (*pattern == SEP)
35940087Sbostic 				*pathend++ = *pattern++;
36040087Sbostic 		} else			/* need expansion, recurse */
36140087Sbostic 			return(glob3(pathbuf, pathend, pattern, p, pglob));
36240087Sbostic 	}
36340087Sbostic 	/* NOTREACHED */
36440087Sbostic }
36540087Sbostic 
36640087Sbostic static
36740087Sbostic glob3(pathbuf, pathend, pattern, restpattern, pglob)
36848540Sbostic 	shortchar_t *pathbuf, *pathend, *pattern, *restpattern;
36940087Sbostic 	glob_t *pglob;
37040087Sbostic {
37140087Sbostic 	extern int errno;
37240087Sbostic 	DIR *dirp;
37340087Sbostic 	struct dirent *dp;
37440087Sbostic 	int len, err;
37540087Sbostic 
37640087Sbostic 	*pathend = EOS;
37740087Sbostic 	errno = 0;
37848540Sbostic 
37948540Sbostic 	if (!(dirp = Opendir(pathbuf)))
38040087Sbostic 		/* todo: don't call for ENOENT or ENOTDIR? */
38140087Sbostic 		if (pglob->gl_errfunc &&
38240087Sbostic 		    (*pglob->gl_errfunc)(pathbuf, errno) ||
38340087Sbostic 		    (pglob->gl_flags & GLOB_ERR))
38440087Sbostic 			return(GLOB_ABEND);
38540087Sbostic 		else
38640087Sbostic 			return(0);
38740087Sbostic 
38840087Sbostic 	err = 0;
38940087Sbostic 
39040087Sbostic 	/* search directory for matching names */
39140087Sbostic 	while ((dp = readdir(dirp))) {
39248540Sbostic 		register char *sc;
39348540Sbostic 		register shortchar_t *dc;
39440087Sbostic 		/* initial DOT must be matched literally */
39540087Sbostic 		if (dp->d_name[0] == DOT && *pattern != DOT)
39640087Sbostic 			continue;
39748540Sbostic 		for (sc = dp->d_name, dc = pathend;
39848540Sbostic 		     *dc++ = (u_char)*sc++;);
39948540Sbostic 		if (!match(pathend, pattern, restpattern)) {
40048540Sbostic 			*pathend = EOS;
40140087Sbostic 			continue;
40248540Sbostic 		}
40348540Sbostic 		err = glob2(pathbuf, --dc, restpattern, pglob);
40440087Sbostic 		if (err)
40540087Sbostic 			break;
40640087Sbostic 	}
40740087Sbostic 	/* todo: check error from readdir? */
40840087Sbostic 	(void)closedir(dirp);
40940087Sbostic 	return(err);
41040087Sbostic }
41140087Sbostic 
41240087Sbostic 
41340087Sbostic /*
41440087Sbostic  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
41540087Sbostic  * add the new item, and update gl_pathc.
41640087Sbostic  *
41740087Sbostic  * This assumes the BSD realloc, which only copies the block when its size
41840087Sbostic  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
41940087Sbostic  * behavior.
42040087Sbostic  *
42140087Sbostic  * Return 0 if new item added, error code if memory couldn't be allocated.
42240087Sbostic  *
42340087Sbostic  * Invariant of the glob_t structure:
42440087Sbostic  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
42540087Sbostic  *	 gl_pathv points to (gl_offs + gl_pathc + 1) items.
42640087Sbostic  */
42748540Sbostic static int
42840087Sbostic globextend(path, pglob)
42948540Sbostic 	shortchar_t *path;
43040087Sbostic 	glob_t *pglob;
43140087Sbostic {
43240087Sbostic 	register char **pathv;
43340087Sbostic 	register int i;
43448540Sbostic 	u_int newsize;
43540087Sbostic 	char *copy;
43648540Sbostic 	shortchar_t *p;
43740087Sbostic 
43840087Sbostic 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
43948540Sbostic 	pathv = (char **)realloc((char *)pglob->gl_pathv, newsize);
44040087Sbostic 	if (pathv == NULL)
44140087Sbostic 		return(GLOB_NOSPACE);
44240087Sbostic 
44340087Sbostic 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
44440087Sbostic 		/* first time around -- clear initial gl_offs items */
44540087Sbostic 		pathv += pglob->gl_offs;
44640087Sbostic 		for (i = pglob->gl_offs; --i >= 0; )
44740087Sbostic 			*--pathv = NULL;
44840087Sbostic 	}
44940087Sbostic 	pglob->gl_pathv = pathv;
45040087Sbostic 
45148540Sbostic 	for (p = path; *p++;);
45248540Sbostic 	if ((copy = malloc(p - path)) != NULL) {
453*50049Sbostic 		register char *dc;
454*50049Sbostic 		register shortchar_t *sc;
455*50049Sbostic 
456*50049Sbostic 		for (dc = copy, sc = path; *dc++ = *sc++;);
45740087Sbostic 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
45840087Sbostic 	}
45940087Sbostic 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
46040087Sbostic 	return((copy == NULL) ? GLOB_NOSPACE : 0);
46140087Sbostic }
46240087Sbostic 
46340087Sbostic 
46440087Sbostic /*
46540087Sbostic  * pattern matching function for filenames.  Each occurrence of the *
46640087Sbostic  * pattern causes a recursion level.
46740087Sbostic  */
46848540Sbostic static
46940087Sbostic match(name, pat, patend)
47048540Sbostic 	register shortchar_t *name, *pat, *patend;
47140087Sbostic {
47248540Sbostic 	int ok, negate_range;
47348540Sbostic 	shortchar_t c, k;
47440087Sbostic 
47540087Sbostic 	while (pat < patend) {
47640087Sbostic 		c = *pat++;
47748540Sbostic 		switch (c & M_MASK) {
47840087Sbostic 		case M_ALL:
47940087Sbostic 			if (pat == patend)
48040087Sbostic 				return(1);
48140087Sbostic 			for (; *name != EOS; ++name) {
48240087Sbostic 				if (match(name, pat, patend))
48340087Sbostic 					return(1);
48440087Sbostic 			}
48540087Sbostic 			return(0);
48640087Sbostic 		case M_ONE:
48740087Sbostic 			if (*name++ == EOS)
48840087Sbostic 				return(0);
48940087Sbostic 			break;
49040087Sbostic 		case M_SET:
49140087Sbostic 			ok = 0;
49240087Sbostic 			k = *name++;
49348540Sbostic 			if (negate_range = ((*pat & M_MASK) == M_NOT))
49440087Sbostic 				++pat;
49548540Sbostic 			while (((c = *pat++) & M_MASK) != M_END) {
49648540Sbostic 				if ((*pat & M_MASK) == M_RNG) {
49740087Sbostic 					if (c <= k && k <= pat[1])
49840087Sbostic 						ok = 1;
49940087Sbostic 					pat += 2;
50040087Sbostic 				}
50140087Sbostic 				else if (c == k)
50240087Sbostic 					ok = 1;
50340087Sbostic 			}
50440087Sbostic 			if (ok == negate_range)
50540087Sbostic 				return(0);
50640087Sbostic 			break;
50740087Sbostic 		default:
50840087Sbostic 			if (*name++ != c)
50940087Sbostic 				return(0);
51040087Sbostic 			break;
51140087Sbostic 		}
51240087Sbostic 	}
51340087Sbostic 	return(*name == EOS);
51440087Sbostic }
51540087Sbostic 
51640087Sbostic /* free allocated data belonging to a glob_t structure */
51740087Sbostic void
51840087Sbostic globfree(pglob)
51940087Sbostic 	glob_t *pglob;
52040087Sbostic {
52140087Sbostic 	register int i;
52240087Sbostic 	register char **pp;
52340087Sbostic 
52440087Sbostic 	if (pglob->gl_pathv != NULL) {
52540087Sbostic 		pp = pglob->gl_pathv + pglob->gl_offs;
52640087Sbostic 		for (i = pglob->gl_pathc; i--; ++pp)
52740087Sbostic 			if (*pp)
528*50049Sbostic 				free(pp);
529*50049Sbostic 		free(pglob->gl_pathv);
53040087Sbostic 	}
53140087Sbostic }
532