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