glob.c revision 74307
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $FreeBSD: head/lib/libc/gen/glob.c 74307 2001-03-15 18:50:32Z jlemon $
37 */
38
39#if defined(LIBC_SCCS) && !defined(lint)
40static char sccsid[] = "@(#)glob.c	8.3 (Berkeley) 10/13/93";
41#endif /* LIBC_SCCS and not lint */
42
43/*
44 * glob(3) -- a superset of the one defined in POSIX 1003.2.
45 *
46 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
47 *
48 * Optional extra services, controlled by flags not defined by POSIX:
49 *
50 * GLOB_QUOTE:
51 *	Escaping convention: \ inhibits any special meaning the following
52 *	character might have (except \ at end of string is retained).
53 * GLOB_MAGCHAR:
54 *	Set in gl_flags if pattern contained a globbing character.
55 * GLOB_NOMAGIC:
56 *	Same as GLOB_NOCHECK, but it will only append pattern if it did
57 *	not contain any magic characters.  [Used in csh style globbing]
58 * GLOB_ALTDIRFUNC:
59 *	Use alternately specified directory access functions.
60 * GLOB_TILDE:
61 *	expand ~user/foo to the /home/dir/of/user/foo
62 * GLOB_BRACE:
63 *	expand {1,2}{a,b} to 1a 1b 2a 2b
64 * gl_matchc:
65 *	Number of matches in the current invocation of glob.
66 */
67
68#include <sys/param.h>
69#include <sys/stat.h>
70
71#include <ctype.h>
72#include <dirent.h>
73#include <errno.h>
74#include <glob.h>
75#include <pwd.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <unistd.h>
80
81#include "collate.h"
82
83#define MAX_GLOBENTRIES	10000		/* limit number of entries */
84
85#define	DOLLAR		'$'
86#define	DOT		'.'
87#define	EOS		'\0'
88#define	LBRACKET	'['
89#define	NOT		'!'
90#define	QUESTION	'?'
91#define	QUOTE		'\\'
92#define	RANGE		'-'
93#define	RBRACKET	']'
94#define	SEP		'/'
95#define	STAR		'*'
96#define	TILDE		'~'
97#define	UNDERSCORE	'_'
98#define	LBRACE		'{'
99#define	RBRACE		'}'
100#define	SLASH		'/'
101#define	COMMA		','
102
103#ifndef DEBUG
104
105#define	M_QUOTE		0x8000
106#define	M_PROTECT	0x4000
107#define	M_MASK		0xffff
108#define	M_ASCII		0x00ff
109
110typedef u_short Char;
111
112#else
113
114#define	M_QUOTE		0x80
115#define	M_PROTECT	0x40
116#define	M_MASK		0xff
117#define	M_ASCII		0x7f
118
119typedef char Char;
120
121#endif
122
123
124#define	CHAR(c)		((Char)((c)&M_ASCII))
125#define	META(c)		((Char)((c)|M_QUOTE))
126#define	M_ALL		META('*')
127#define	M_END		META(']')
128#define	M_NOT		META('!')
129#define	M_ONE		META('?')
130#define	M_RNG		META('-')
131#define	M_SET		META('[')
132#define	ismeta(c)	(((c)&M_QUOTE) != 0)
133
134
135static int	 compare __P((const void *, const void *));
136static void	 g_Ctoc __P((const Char *, char *));
137static int	 g_lstat __P((Char *, struct stat *, glob_t *));
138static DIR	*g_opendir __P((Char *, glob_t *));
139static Char	*g_strchr __P((Char *, int));
140#ifdef notdef
141static Char	*g_strcat __P((Char *, const Char *));
142#endif
143static int	 g_stat __P((Char *, struct stat *, glob_t *));
144static int	 glob0 __P((const Char *, glob_t *));
145static int	 glob1 __P((Char *, glob_t *));
146static int	 glob2 __P((Char *, Char *, Char *, glob_t *));
147static int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
148static int	 globextend __P((const Char *, glob_t *));
149static const Char *	 globtilde __P((const Char *, Char *, size_t, glob_t *));
150static int	 globexp1 __P((const Char *, glob_t *));
151static int	 globexp2 __P((const Char *, const Char *, glob_t *, int *));
152static int	 match __P((Char *, Char *, Char *));
153#ifdef DEBUG
154static void	 qprintf __P((const char *, Char *));
155#endif
156
157int
158glob(pattern, flags, errfunc, pglob)
159	const char *pattern;
160	int flags, (*errfunc) __P((const char *, int));
161	glob_t *pglob;
162{
163	const u_char *patnext;
164	int c;
165	Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
166
167	patnext = (u_char *) pattern;
168	if (!(flags & GLOB_APPEND)) {
169		pglob->gl_pathc = 0;
170		pglob->gl_pathv = NULL;
171		if (!(flags & GLOB_DOOFFS))
172			pglob->gl_offs = 0;
173	}
174	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
175	pglob->gl_errfunc = errfunc;
176	pglob->gl_matchc = 0;
177
178	bufnext = patbuf;
179	bufend = bufnext + MAXPATHLEN;
180	if (flags & GLOB_QUOTE) {
181		/* Protect the quoted characters. */
182		while (bufnext < bufend && (c = *patnext++) != EOS)
183			if (c == QUOTE) {
184				if ((c = *patnext++) == EOS) {
185					c = QUOTE;
186					--patnext;
187				}
188				*bufnext++ = c | M_PROTECT;
189			}
190			else
191				*bufnext++ = c;
192	}
193	else
194	    while (bufnext < bufend && (c = *patnext++) != EOS)
195		    *bufnext++ = c;
196	*bufnext = EOS;
197
198	if (flags & GLOB_BRACE)
199	    return globexp1(patbuf, pglob);
200	else
201	    return glob0(patbuf, pglob);
202}
203
204/*
205 * Expand recursively a glob {} pattern. When there is no more expansion
206 * invoke the standard globbing routine to glob the rest of the magic
207 * characters
208 */
209static int globexp1(pattern, pglob)
210	const Char *pattern;
211	glob_t *pglob;
212{
213	const Char* ptr = pattern;
214	int rv;
215
216	/* Protect a single {}, for find(1), like csh */
217	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
218		return glob0(pattern, pglob);
219
220	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
221		if (!globexp2(ptr, pattern, pglob, &rv))
222			return rv;
223
224	return glob0(pattern, pglob);
225}
226
227
228/*
229 * Recursive brace globbing helper. Tries to expand a single brace.
230 * If it succeeds then it invokes globexp1 with the new pattern.
231 * If it fails then it tries to glob the rest of the pattern and returns.
232 */
233static int globexp2(ptr, pattern, pglob, rv)
234	const Char *ptr, *pattern;
235	glob_t *pglob;
236	int *rv;
237{
238	int     i;
239	Char   *lm, *ls;
240	const Char *pe, *pm, *pl;
241	Char    patbuf[MAXPATHLEN + 1];
242
243	/* copy part up to the brace */
244	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
245		continue;
246	ls = lm;
247
248	/* Find the balanced brace */
249	for (i = 0, pe = ++ptr; *pe; pe++)
250		if (*pe == LBRACKET) {
251			/* Ignore everything between [] */
252			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
253				continue;
254			if (*pe == EOS) {
255				/*
256				 * We could not find a matching RBRACKET.
257				 * Ignore and just look for RBRACE
258				 */
259				pe = pm;
260			}
261		}
262		else if (*pe == LBRACE)
263			i++;
264		else if (*pe == RBRACE) {
265			if (i == 0)
266				break;
267			i--;
268		}
269
270	/* Non matching braces; just glob the pattern */
271	if (i != 0 || *pe == EOS) {
272		*rv = glob0(patbuf, pglob);
273		return 0;
274	}
275
276	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
277		switch (*pm) {
278		case LBRACKET:
279			/* Ignore everything between [] */
280			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
281				continue;
282			if (*pm == EOS) {
283				/*
284				 * We could not find a matching RBRACKET.
285				 * Ignore and just look for RBRACE
286				 */
287				pm = pl;
288			}
289			break;
290
291		case LBRACE:
292			i++;
293			break;
294
295		case RBRACE:
296			if (i) {
297			    i--;
298			    break;
299			}
300			/* FALLTHROUGH */
301		case COMMA:
302			if (i && *pm == COMMA)
303				break;
304			else {
305				/* Append the current string */
306				for (lm = ls; (pl < pm); *lm++ = *pl++)
307					continue;
308				/*
309				 * Append the rest of the pattern after the
310				 * closing brace
311				 */
312				for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
313					continue;
314
315				/* Expand the current pattern */
316#ifdef DEBUG
317				qprintf("globexp2:", patbuf);
318#endif
319				*rv = globexp1(patbuf, pglob);
320
321				/* move after the comma, to the next string */
322				pl = pm + 1;
323			}
324			break;
325
326		default:
327			break;
328		}
329	*rv = 0;
330	return 0;
331}
332
333
334
335/*
336 * expand tilde from the passwd file.
337 */
338static const Char *
339globtilde(pattern, patbuf, patbuf_len, pglob)
340	const Char *pattern;
341	Char *patbuf;
342	size_t patbuf_len;
343	glob_t *pglob;
344{
345	struct passwd *pwd;
346	char *h;
347	const Char *p;
348	Char *b, *eb;
349
350	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
351		return pattern;
352
353	/*
354	 * Copy up to the end of the string or /
355	 */
356	eb = &patbuf[patbuf_len - 1];
357	for (p = pattern + 1, h = (char *) patbuf;
358	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
359		continue;
360
361	*h = EOS;
362
363	if (((char *) patbuf)[0] == EOS) {
364		/*
365		 * handle a plain ~ or ~/ by expanding $HOME first (iff
366		 * we're not running setuid or setgid) and then trying
367		 * the password file
368		 */
369		if (
370#ifndef	__NETBSD_SYSCALLS
371		    issetugid() != 0 ||
372#endif
373		    (h = getenv("HOME")) == NULL) {
374			if (((h = getlogin()) != NULL &&
375			     (pwd = getpwnam(h)) != NULL) ||
376			    (pwd = getpwuid(getuid())) != NULL)
377				h = pwd->pw_dir;
378			else
379				return pattern;
380		}
381	}
382	else {
383		/*
384		 * Expand a ~user
385		 */
386		if ((pwd = getpwnam((char*) patbuf)) == NULL)
387			return pattern;
388		else
389			h = pwd->pw_dir;
390	}
391
392	/* Copy the home directory */
393	for (b = patbuf; b < eb && *h; *b++ = *h++)
394		continue;
395
396	/* Append the rest of the pattern */
397	while (b < eb && (*b++ = *p++) != EOS)
398		continue;
399	*b = EOS;
400
401	return patbuf;
402}
403
404
405/*
406 * The main glob() routine: compiles the pattern (optionally processing
407 * quotes), calls glob1() to do the real pattern matching, and finally
408 * sorts the list (unless unsorted operation is requested).  Returns 0
409 * if things went well, nonzero if errors occurred.  It is not an error
410 * to find no matches.
411 */
412static int
413glob0(pattern, pglob)
414	const Char *pattern;
415	glob_t *pglob;
416{
417	const Char *qpatnext;
418	int c, err, oldpathc;
419	Char *bufnext, patbuf[MAXPATHLEN+1];
420
421	qpatnext = globtilde(pattern, patbuf, sizeof(patbuf) / sizeof(Char),
422	    pglob);
423	oldpathc = pglob->gl_pathc;
424	bufnext = patbuf;
425
426	/* We don't need to check for buffer overflow any more. */
427	while ((c = *qpatnext++) != EOS) {
428		switch (c) {
429		case LBRACKET:
430			c = *qpatnext;
431			if (c == NOT)
432				++qpatnext;
433			if (*qpatnext == EOS ||
434			    g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
435				*bufnext++ = LBRACKET;
436				if (c == NOT)
437					--qpatnext;
438				break;
439			}
440			*bufnext++ = M_SET;
441			if (c == NOT)
442				*bufnext++ = M_NOT;
443			c = *qpatnext++;
444			do {
445				*bufnext++ = CHAR(c);
446				if (*qpatnext == RANGE &&
447				    (c = qpatnext[1]) != RBRACKET) {
448					*bufnext++ = M_RNG;
449					*bufnext++ = CHAR(c);
450					qpatnext += 2;
451				}
452			} while ((c = *qpatnext++) != RBRACKET);
453			pglob->gl_flags |= GLOB_MAGCHAR;
454			*bufnext++ = M_END;
455			break;
456		case QUESTION:
457			pglob->gl_flags |= GLOB_MAGCHAR;
458			*bufnext++ = M_ONE;
459			break;
460		case STAR:
461			pglob->gl_flags |= GLOB_MAGCHAR;
462			/* collapse adjacent stars to one,
463			 * to avoid exponential behavior
464			 */
465			if (bufnext == patbuf || bufnext[-1] != M_ALL)
466			    *bufnext++ = M_ALL;
467			break;
468		default:
469			*bufnext++ = CHAR(c);
470			break;
471		}
472	}
473	*bufnext = EOS;
474#ifdef DEBUG
475	qprintf("glob0:", patbuf);
476#endif
477
478	if ((err = glob1(patbuf, pglob)) != 0)
479		return(err);
480
481	/*
482	 * If there was no match we are going to append the pattern
483	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
484	 * and the pattern did not contain any magic characters
485	 * GLOB_NOMAGIC is there just for compatibility with csh.
486	 */
487	if (pglob->gl_pathc == oldpathc &&
488	    ((pglob->gl_flags & GLOB_NOCHECK) ||
489	      ((pglob->gl_flags & GLOB_NOMAGIC) &&
490	       !(pglob->gl_flags & GLOB_MAGCHAR))))
491		return(globextend(pattern, pglob));
492	else if (!(pglob->gl_flags & GLOB_NOSORT))
493		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
494		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
495	return(0);
496}
497
498static int
499compare(p, q)
500	const void *p, *q;
501{
502	return(strcmp(*(char **)p, *(char **)q));
503}
504
505static int
506glob1(pattern, pglob)
507	Char *pattern;
508	glob_t *pglob;
509{
510	Char pathbuf[MAXPATHLEN+1];
511
512	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
513	if (*pattern == EOS)
514		return(0);
515	return(glob2(pathbuf, pathbuf, pattern, pglob));
516}
517
518/*
519 * The functions glob2 and glob3 are mutually recursive; there is one level
520 * of recursion for each segment in the pattern that contains one or more
521 * meta characters.
522 */
523static int
524glob2(pathbuf, pathend, pattern, pglob)
525	Char *pathbuf, *pathend, *pattern;
526	glob_t *pglob;
527{
528	struct stat sb;
529	Char *p, *q;
530	int anymeta;
531
532	/*
533	 * Loop over pattern segments until end of pattern or until
534	 * segment with meta character found.
535	 */
536	for (anymeta = 0;;) {
537		if (*pattern == EOS) {		/* End of pattern? */
538			*pathend = EOS;
539			if (g_lstat(pathbuf, &sb, pglob))
540				return(0);
541
542			if (((pglob->gl_flags & GLOB_MARK) &&
543			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
544			    || (S_ISLNK(sb.st_mode) &&
545			    (g_stat(pathbuf, &sb, pglob) == 0) &&
546			    S_ISDIR(sb.st_mode)))) {
547				*pathend++ = SEP;
548				*pathend = EOS;
549			}
550			++pglob->gl_matchc;
551			return(globextend(pathbuf, pglob));
552		}
553
554		/* Find end of next segment, copy tentatively to pathend. */
555		q = pathend;
556		p = pattern;
557		while (*p != EOS && *p != SEP) {
558			if (ismeta(*p))
559				anymeta = 1;
560			*q++ = *p++;
561		}
562
563		if (!anymeta) {		/* No expansion, do next segment. */
564			pathend = q;
565			pattern = p;
566			while (*pattern == SEP)
567				*pathend++ = *pattern++;
568		} else			/* Need expansion, recurse. */
569			return(glob3(pathbuf, pathend, pattern, p, pglob));
570	}
571	/* NOTREACHED */
572}
573
574static int
575glob3(pathbuf, pathend, pattern, restpattern, pglob)
576	Char *pathbuf, *pathend, *pattern, *restpattern;
577	glob_t *pglob;
578{
579	register struct dirent *dp;
580	DIR *dirp;
581	int err;
582	char buf[MAXPATHLEN];
583
584	/*
585	 * The readdirfunc declaration can't be prototyped, because it is
586	 * assigned, below, to two functions which are prototyped in glob.h
587	 * and dirent.h as taking pointers to differently typed opaque
588	 * structures.
589	 */
590	struct dirent *(*readdirfunc)();
591
592	*pathend = EOS;
593	errno = 0;
594
595	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
596		/* TODO: don't call for ENOENT or ENOTDIR? */
597		if (pglob->gl_errfunc) {
598			g_Ctoc(pathbuf, buf);
599			if (pglob->gl_errfunc(buf, errno) ||
600			    pglob->gl_flags & GLOB_ERR)
601				return (GLOB_ABEND);
602		}
603		return(0);
604	}
605
606	err = 0;
607
608	/* Search directory for matching names. */
609	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
610		readdirfunc = pglob->gl_readdir;
611	else
612		readdirfunc = readdir;
613	while ((dp = (*readdirfunc)(dirp))) {
614		register u_char *sc;
615		register Char *dc;
616
617		/* Initial DOT must be matched literally. */
618		if (dp->d_name[0] == DOT && *pattern != DOT)
619			continue;
620		for (sc = (u_char *) dp->d_name, dc = pathend;
621		     (*dc++ = *sc++) != EOS;)
622			continue;
623		if (!match(pathend, pattern, restpattern)) {
624			*pathend = EOS;
625			continue;
626		}
627		err = glob2(pathbuf, --dc, restpattern, pglob);
628		if (err)
629			break;
630	}
631
632	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
633		(*pglob->gl_closedir)(dirp);
634	else
635		closedir(dirp);
636	return(err);
637}
638
639
640/*
641 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
642 * add the new item, and update gl_pathc.
643 *
644 * This assumes the BSD realloc, which only copies the block when its size
645 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
646 * behavior.
647 *
648 * Return 0 if new item added, error code if memory couldn't be allocated.
649 *
650 * Invariant of the glob_t structure:
651 *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
652 *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
653 */
654static int
655globextend(path, pglob)
656	const Char *path;
657	glob_t *pglob;
658{
659	register char **pathv;
660	register int i;
661	u_int newsize;
662	char *copy;
663	const Char *p;
664
665	if (pglob->gl_pathc > MAX_GLOBENTRIES)
666		return (GLOB_ABEND);
667
668	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
669	pathv = pglob->gl_pathv ?
670		    realloc((char *)pglob->gl_pathv, newsize) :
671		    malloc(newsize);
672	if (pathv == NULL)
673		return(GLOB_NOSPACE);
674
675	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
676		/* first time around -- clear initial gl_offs items */
677		pathv += pglob->gl_offs;
678		for (i = pglob->gl_offs; --i >= 0; )
679			*--pathv = NULL;
680	}
681	pglob->gl_pathv = pathv;
682
683	for (p = path; *p++;)
684		continue;
685	if ((copy = malloc(p - path)) != NULL) {
686		g_Ctoc(path, copy);
687		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
688	}
689	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
690	return(copy == NULL ? GLOB_NOSPACE : 0);
691}
692
693/*
694 * pattern matching function for filenames.  Each occurrence of the *
695 * pattern causes a recursion level.
696 */
697static int
698match(name, pat, patend)
699	register Char *name, *pat, *patend;
700{
701	int ok, negate_range;
702	Char c, k;
703
704	while (pat < patend) {
705		c = *pat++;
706		switch (c & M_MASK) {
707		case M_ALL:
708			if (pat == patend)
709				return(1);
710			do
711			    if (match(name, pat, patend))
712				    return(1);
713			while (*name++ != EOS);
714			return(0);
715		case M_ONE:
716			if (*name++ == EOS)
717				return(0);
718			break;
719		case M_SET:
720			ok = 0;
721			if ((k = *name++) == EOS)
722				return(0);
723			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
724				++pat;
725			while (((c = *pat++) & M_MASK) != M_END)
726				if ((*pat & M_MASK) == M_RNG) {
727					if (__collate_load_error ?
728					    CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
729					       __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
730					    && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
731					   )
732						ok = 1;
733					pat += 2;
734				} else if (c == k)
735					ok = 1;
736			if (ok == negate_range)
737				return(0);
738			break;
739		default:
740			if (*name++ != c)
741				return(0);
742			break;
743		}
744	}
745	return(*name == EOS);
746}
747
748/* Free allocated data belonging to a glob_t structure. */
749void
750globfree(pglob)
751	glob_t *pglob;
752{
753	register int i;
754	register char **pp;
755
756	if (pglob->gl_pathv != NULL) {
757		pp = pglob->gl_pathv + pglob->gl_offs;
758		for (i = pglob->gl_pathc; i--; ++pp)
759			if (*pp)
760				free(*pp);
761		free(pglob->gl_pathv);
762	}
763}
764
765static DIR *
766g_opendir(str, pglob)
767	register Char *str;
768	glob_t *pglob;
769{
770	char buf[MAXPATHLEN];
771
772	if (!*str)
773		strcpy(buf, ".");
774	else
775		g_Ctoc(str, buf);
776
777	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
778		return((*pglob->gl_opendir)(buf));
779
780	return(opendir(buf));
781}
782
783static int
784g_lstat(fn, sb, pglob)
785	register Char *fn;
786	struct stat *sb;
787	glob_t *pglob;
788{
789	char buf[MAXPATHLEN];
790
791	g_Ctoc(fn, buf);
792	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
793		return((*pglob->gl_lstat)(buf, sb));
794	return(lstat(buf, sb));
795}
796
797static int
798g_stat(fn, sb, pglob)
799	register Char *fn;
800	struct stat *sb;
801	glob_t *pglob;
802{
803	char buf[MAXPATHLEN];
804
805	g_Ctoc(fn, buf);
806	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
807		return((*pglob->gl_stat)(buf, sb));
808	return(stat(buf, sb));
809}
810
811static Char *
812g_strchr(str, ch)
813	Char *str;
814	int ch;
815{
816	do {
817		if (*str == ch)
818			return (str);
819	} while (*str++);
820	return (NULL);
821}
822
823#ifdef notdef
824static Char *
825g_strcat(dst, src)
826	Char *dst;
827	const Char* src;
828{
829	Char *sdst = dst;
830
831	while (*dst++)
832		continue;
833	--dst;
834	while((*dst++ = *src++) != EOS)
835	    continue;
836
837	return (sdst);
838}
839#endif
840
841static void
842g_Ctoc(str, buf)
843	register const Char *str;
844	char *buf;
845{
846	register char *dc;
847
848	for (dc = buf; (*dc++ = *str++) != EOS;)
849		continue;
850}
851
852#ifdef DEBUG
853static void
854qprintf(str, s)
855	const char *str;
856	register Char *s;
857{
858	register Char *p;
859
860	(void)printf("%s:\n", str);
861	for (p = s; *p; p++)
862		(void)printf("%c", CHAR(*p));
863	(void)printf("\n");
864	for (p = s; *p; p++)
865		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
866	(void)printf("\n");
867	for (p = s; *p; p++)
868		(void)printf("%c", ismeta(*p) ? '_' : ' ');
869	(void)printf("\n");
870}
871#endif
872