xref: /freebsd/contrib/tcsh/glob.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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 #if defined(LIBC_SCCS) && !defined(lint)
37 static char sccsid[] = "@(#)glob.c	5.12 (Berkeley) 6/24/91";
38 #endif /* LIBC_SCCS and not lint */
39 /*
40  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
41  * draft 9.
42  *
43  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
44  *
45  * Optional extra services, controlled by flags not defined by POSIX:
46  *
47  * GLOB_QUOTE:
48  *	Escaping convention: \ inhibits any special meaning the following
49  *	character might have (except \ at end of string is retained).
50  * GLOB_MAGCHAR:
51  *	Set in gl_flags if pattern contained a globbing character.
52  * GLOB_ALTNOT:
53  *	Use ^ instead of ! for "not".
54  * gl_matchc:
55  *	Number of matches in the current invocation of glob.
56  */
57 
58 #ifdef notdef
59 #include <sys/types.h>
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #include <dirent.h>
63 #include <ctype.h>
64 typedef void * ptr_t;
65 #endif
66 #ifdef WINNT_NATIVE
67 	#pragma warning(disable:4244)
68 #endif /* WINNT_NATIVE */
69 
70 #define Char __Char
71 #include "sh.h"
72 #undef Char
73 #undef QUOTE
74 #undef TILDE
75 #undef META
76 #undef CHAR
77 #undef ismeta
78 #undef Strchr
79 
80 #include "glob.h"
81 
82 #ifndef S_ISDIR
83 #define S_ISDIR(a)	(((a) & S_IFMT) == S_IFDIR)
84 #endif
85 
86 #if !defined(S_ISLNK) && defined(S_IFLNK)
87 #define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
88 #endif
89 
90 #if !defined(S_ISLNK) && !defined(lstat)
91 #define lstat stat
92 #endif
93 
94 typedef unsigned short Char;
95 
96 static	int	 glob1 		__P((Char *, glob_t *, int));
97 static	int	 glob2		__P((Char *, Char *, Char *, glob_t *, int));
98 static	int	 glob3		__P((Char *, Char *, Char *, Char *,
99 				     glob_t *, int));
100 static	int	 globextend	__P((Char *, glob_t *));
101 static	int	 match		__P((Char *, Char *, Char *, int));
102 #ifndef __clipper__
103 static	int	 compare	__P((const ptr_t, const ptr_t));
104 #endif
105 static 	DIR	*Opendir	__P((Char *));
106 #ifdef S_IFLNK
107 static	int	 Lstat		__P((Char *, struct stat *));
108 #endif
109 static	int	 Stat		__P((Char *, struct stat *sb));
110 static 	Char 	*Strchr		__P((Char *, int));
111 #ifdef DEBUG
112 static	void	 qprintf	__P((Char *));
113 #endif
114 
115 #define	DOLLAR		'$'
116 #define	DOT		'.'
117 #define	EOS		'\0'
118 #define	LBRACKET	'['
119 #define	NOT		'!'
120 #define ALTNOT		'^'
121 #define	QUESTION	'?'
122 #define	QUOTE		'\\'
123 #define	RANGE		'-'
124 #define	RBRACKET	']'
125 #define	SEP		'/'
126 #define	STAR		'*'
127 #define	TILDE		'~'
128 #define	UNDERSCORE	'_'
129 
130 #define	M_META		0x8000
131 #define M_PROTECT	0x4000
132 #define	M_MASK		0xffff
133 #define	M_ASCII		0x00ff
134 
135 #define	CHAR(c)		((c)&M_ASCII)
136 #define	META(c)		((c)|M_META)
137 #define	M_ALL		META('*')
138 #define	M_END		META(']')
139 #define	M_NOT		META('!')
140 #define	M_ALTNOT	META('^')
141 #define	M_ONE		META('?')
142 #define	M_RNG		META('-')
143 #define	M_SET		META('[')
144 #define	ismeta(c)	(((c)&M_META) != 0)
145 
146 #ifndef BUFSIZE
147 #define GLOBBUFLEN	MAXPATHLEN
148 #else
149 #define GLOBBUFLEN	BUFSIZE
150 #endif
151 
152 int
153 globcharcoll(c1, c2)
154     int c1, c2;
155 {
156 #if defined(NLS) && defined(LC_COLLATE) && !defined(NOSTRCOLL)
157     char s1[2], s2[2];
158 
159     if (c1 == c2)
160 	return (0);
161     /*
162      * From kevin lyda <kevin@suberic.net>:
163      * strcoll does not guarantee case sorting, so we pre-process now:
164      */
165     if (islower(c1) && isupper(c2))
166 	return (1);
167     s1[0] = c1;
168     s2[0] = c2;
169     s1[1] = s2[1] = '\0';
170     return strcoll(s1, s2);
171 #else
172     return (c1 - c2);
173 #endif
174 }
175 
176 /*
177  * Need to dodge two kernel bugs:
178  * opendir("") != opendir(".")
179  * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
180  *            POSIX specifies that they should be ignored in directories.
181  */
182 
183 static DIR *
184 Opendir(str)
185     register Char *str;
186 {
187     char    buf[GLOBBUFLEN];
188     register char *dc = buf;
189 #if defined(hpux) || defined(__hpux)
190     struct stat st;
191 #endif
192 
193     if (!*str)
194 	return (opendir("."));
195     while ((*dc++ = *str++) != '\0')
196 	continue;
197 #if defined(hpux) || defined(__hpux)
198     /*
199      * Opendir on some device files hangs, so avoid it
200      */
201     if (stat(buf, &st) == -1 || !S_ISDIR(st.st_mode))
202 	return NULL;
203 #endif
204     return (opendir(buf));
205 }
206 
207 #ifdef S_IFLNK
208 static int
209 Lstat(fn, sb)
210     register Char *fn;
211     struct stat *sb;
212 {
213     char    buf[GLOBBUFLEN];
214     register char *dc = buf;
215 
216     while ((*dc++ = *fn++) != '\0')
217 	continue;
218 # ifdef NAMEI_BUG
219     {
220 	int     st;
221 
222 	st = lstat(buf, sb);
223 	if (*buf)
224 	    dc--;
225 	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
226     }
227 # else
228     return (lstat(buf, sb));
229 # endif	/* NAMEI_BUG */
230 }
231 #else
232 #define Lstat Stat
233 #endif /* S_IFLNK */
234 
235 static int
236 Stat(fn, sb)
237     register Char *fn;
238     struct stat *sb;
239 {
240     char    buf[GLOBBUFLEN];
241     register char *dc = buf;
242 
243     while ((*dc++ = *fn++) != '\0')
244 	continue;
245 #ifdef NAMEI_BUG
246     {
247 	int     st;
248 
249 	st = stat(buf, sb);
250 	if (*buf)
251 	    dc--;
252 	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
253     }
254 #else
255     return (stat(buf, sb));
256 #endif /* NAMEI_BUG */
257 }
258 
259 static Char *
260 Strchr(str, ch)
261     Char *str;
262     int ch;
263 {
264     do
265 	if (*str == ch)
266 	    return (str);
267     while (*str++);
268     return (NULL);
269 }
270 
271 #ifdef DEBUG
272 static void
273 qprintf(s)
274 Char *s;
275 {
276     Char *p;
277 
278     for (p = s; *p; p++)
279 	printf("%c", *p & 0xff);
280     printf("\n");
281     for (p = s; *p; p++)
282 	printf("%c", *p & M_PROTECT ? '"' : ' ');
283     printf("\n");
284     for (p = s; *p; p++)
285 	printf("%c", *p & M_META ? '_' : ' ');
286     printf("\n");
287 }
288 #endif /* DEBUG */
289 
290 static int
291 compare(p, q)
292     const ptr_t  p, q;
293 {
294 #if defined(NLS) && !defined(NOSTRCOLL)
295     errno = 0;  /* strcoll sets errno, another brain-damage */
296 
297     return (strcoll(*(char **) p, *(char **) q));
298 #else
299     return (strcmp(*(char **) p, *(char **) q));
300 #endif /* NLS && !NOSTRCOLL */
301 }
302 
303 /*
304  * The main glob() routine: compiles the pattern (optionally processing
305  * quotes), calls glob1() to do the real pattern matching, and finally
306  * sorts the list (unless unsorted operation is requested).  Returns 0
307  * if things went well, nonzero if errors occurred.  It is not an error
308  * to find no matches.
309  */
310 int
311 glob(pattern, flags, errfunc, pglob)
312     const char *pattern;
313     int     flags;
314     int     (*errfunc) __P((const char *, int));
315     glob_t *pglob;
316 {
317     int     err, oldpathc;
318     Char *bufnext, *bufend, *compilebuf, m_not;
319     const unsigned char *compilepat, *patnext;
320     int     c, not;
321     Char patbuf[GLOBBUFLEN + 1], *qpatnext;
322     int     no_match;
323 
324     patnext = (unsigned char *) pattern;
325     if (!(flags & GLOB_APPEND)) {
326 	pglob->gl_pathc = 0;
327 	pglob->gl_pathv = NULL;
328 	if (!(flags & GLOB_DOOFFS))
329 	    pglob->gl_offs = 0;
330     }
331     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
332     pglob->gl_errfunc = errfunc;
333     oldpathc = pglob->gl_pathc;
334     pglob->gl_matchc = 0;
335 
336     if (pglob->gl_flags & GLOB_ALTNOT) {
337 	not = ALTNOT;
338 	m_not = M_ALTNOT;
339     }
340     else {
341 	not = NOT;
342 	m_not = M_NOT;
343     }
344 
345     bufnext = patbuf;
346     bufend = bufnext + GLOBBUFLEN;
347     compilebuf = bufnext;
348     compilepat = patnext;
349 
350     no_match = *patnext == not;
351     if (no_match)
352 	patnext++;
353 
354     if (flags & GLOB_QUOTE) {
355 	/* Protect the quoted characters */
356 	while (bufnext < bufend && (c = *patnext++) != EOS)
357 #ifdef DSPMBYTE
358 	    if (Ismbyte1(c) && *patnext != EOS)
359 	    {
360 	      *bufnext++ = (Char) c;
361 	      *bufnext++ = (Char) *patnext++;
362 	    }
363 	    else
364 #endif /* DSPMBYTE */
365 	    if (c == QUOTE) {
366 		if ((c = *patnext++) == EOS) {
367 		    c = QUOTE;
368 		    --patnext;
369 		}
370 		*bufnext++ = (Char) (c | M_PROTECT);
371 	    }
372 	    else
373 		*bufnext++ = (Char) c;
374     }
375     else
376 	while (bufnext < bufend && (c = *patnext++) != EOS)
377 	    *bufnext++ = (Char) c;
378     *bufnext = EOS;
379 
380     bufnext = patbuf;
381     qpatnext = patbuf;
382     /* we don't need to check for buffer overflow any more */
383     while ((c = *qpatnext++) != EOS) {
384 #ifdef DSPMBYTE
385 	if (Ismbyte1(c) && *qpatnext != EOS)
386 	{
387 	  *bufnext++ = CHAR(c);
388 	  *bufnext++ = CHAR(*qpatnext++);
389 	}
390 	else
391 #endif /* DSPMBYTE */
392 	switch (c) {
393 	case LBRACKET:
394 	    c = *qpatnext;
395 	    if (c == not)
396 		++qpatnext;
397 	    if (*qpatnext == EOS ||
398 		Strchr(qpatnext + 1, RBRACKET) == NULL) {
399 		*bufnext++ = LBRACKET;
400 		if (c == not)
401 		    --qpatnext;
402 		break;
403 	    }
404 	    pglob->gl_flags |= GLOB_MAGCHAR;
405 	    *bufnext++ = M_SET;
406 	    if (c == not)
407 		*bufnext++ = m_not;
408 	    c = *qpatnext++;
409 	    do {
410 		*bufnext++ = CHAR(c);
411 		if (*qpatnext == RANGE &&
412 		    (c = qpatnext[1]) != RBRACKET) {
413 		    *bufnext++ = M_RNG;
414 		    *bufnext++ = CHAR(c);
415 		    qpatnext += 2;
416 		}
417 	    } while ((c = *qpatnext++) != RBRACKET);
418 	    *bufnext++ = M_END;
419 	    break;
420 	case QUESTION:
421 	    pglob->gl_flags |= GLOB_MAGCHAR;
422 	    *bufnext++ = M_ONE;
423 	    break;
424 	case STAR:
425 	    pglob->gl_flags |= GLOB_MAGCHAR;
426 	    /* collapse adjacent stars to one, to avoid
427 	     * exponential behavior
428 	     */
429 	    if (bufnext == patbuf || bufnext[-1] != M_ALL)
430 		*bufnext++ = M_ALL;
431 	    break;
432 	default:
433 	    *bufnext++ = CHAR(c);
434 	    break;
435 	}
436     }
437     *bufnext = EOS;
438 #ifdef DEBUG
439     qprintf(patbuf);
440 #endif
441 
442     if ((err = glob1(patbuf, pglob, no_match)) != 0)
443 	return (err);
444 
445     /*
446      * If there was no match we are going to append the pattern
447      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
448      * and the pattern did not contain any magic characters
449      * GLOB_NOMAGIC is there just for compatibility with csh.
450      */
451     if (pglob->gl_pathc == oldpathc &&
452 	((flags & GLOB_NOCHECK) ||
453 	 ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
454 	if (!(flags & GLOB_QUOTE)) {
455 	    Char *dp = compilebuf;
456 	    const unsigned char *sp = compilepat;
457 
458 	    while ((*dp++ = *sp++) != '\0')
459 		continue;
460 	}
461 	else {
462 	    /*
463 	     * copy pattern, interpreting quotes; this is slightly different
464 	     * than the interpretation of quotes above -- which should prevail?
465 	     */
466 	    while (*compilepat != EOS) {
467 		if (*compilepat == QUOTE) {
468 		    if (*++compilepat == EOS)
469 			--compilepat;
470 		}
471 		*compilebuf++ = (unsigned char) *compilepat++;
472 	    }
473 	    *compilebuf = EOS;
474 	}
475 	return (globextend(patbuf, pglob));
476     }
477     else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc))
478 	qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
479 	      pglob->gl_pathc - oldpathc, sizeof(char *),
480 	      (int (*) __P((const void *, const void *))) compare);
481     return (0);
482 }
483 
484 static int
485 glob1(pattern, pglob, no_match)
486     Char *pattern;
487     glob_t *pglob;
488     int     no_match;
489 {
490     Char pathbuf[GLOBBUFLEN + 1];
491 
492     /*
493      * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
494      */
495     if (*pattern == EOS)
496 	return (0);
497     return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
498 }
499 
500 /*
501  * functions glob2 and glob3 are mutually recursive; there is one level
502  * of recursion for each segment in the pattern that contains one or
503  * more meta characters.
504  */
505 static int
506 glob2(pathbuf, pathend, pattern, pglob, no_match)
507     Char *pathbuf, *pathend, *pattern;
508     glob_t *pglob;
509     int     no_match;
510 {
511     struct stat sbuf;
512     int anymeta;
513     Char *p, *q;
514 
515     /*
516      * loop over pattern segments until end of pattern or until segment with
517      * meta character found.
518      */
519     anymeta = 0;
520     for (;;) {
521 	if (*pattern == EOS) {	/* end of pattern? */
522 	    *pathend = EOS;
523 
524 	    if (Lstat(pathbuf, &sbuf))
525 		return (0);
526 
527 	    if (((pglob->gl_flags & GLOB_MARK) &&
528 		 pathend[-1] != SEP) &&
529 		(S_ISDIR(sbuf.st_mode)
530 #ifdef S_IFLNK
531 		 || (S_ISLNK(sbuf.st_mode) &&
532 		     (Stat(pathbuf, &sbuf) == 0) &&
533 		     S_ISDIR(sbuf.st_mode))
534 #endif
535 		 )) {
536 		*pathend++ = SEP;
537 		*pathend = EOS;
538 	    }
539 	    ++pglob->gl_matchc;
540 	    return (globextend(pathbuf, pglob));
541 	}
542 
543 	/* find end of next segment, copy tentatively to pathend */
544 	q = pathend;
545 	p = pattern;
546 	while (*p != EOS && *p != SEP) {
547 	    if (ismeta(*p))
548 		anymeta = 1;
549 	    *q++ = *p++;
550 	}
551 
552 	if (!anymeta) {		/* no expansion, do next segment */
553 	    pathend = q;
554 	    pattern = p;
555 	    while (*pattern == SEP)
556 		*pathend++ = *pattern++;
557 	}
558 	else			/* need expansion, recurse */
559 	    return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
560     }
561     /* NOTREACHED */
562 }
563 
564 
565 static int
566 glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
567     Char *pathbuf, *pathend, *pattern, *restpattern;
568     glob_t *pglob;
569     int     no_match;
570 {
571     DIR    *dirp;
572     struct dirent *dp;
573     int     err;
574     Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
575     char cpathbuf[GLOBBUFLEN], *ptr;;
576 
577     *pathend = EOS;
578     errno = 0;
579 
580     if (!(dirp = Opendir(pathbuf))) {
581 	/* todo: don't call for ENOENT or ENOTDIR? */
582 	for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;)
583 	    continue;
584 	if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) ||
585 	    (pglob->gl_flags & GLOB_ERR))
586 	    return (GLOB_ABEND);
587 	else
588 	    return (0);
589     }
590 
591     err = 0;
592 
593     /* search directory for matching names */
594     while ((dp = readdir(dirp)) != NULL) {
595 	register unsigned char *sc;
596 	register Char *dc;
597 
598 	/* initial DOT must be matched literally */
599 	if (dp->d_name[0] == DOT && *pattern != DOT)
600 	    continue;
601 	for (sc = (unsigned char *) dp->d_name, dc = pathend;
602 	     (*dc++ = *sc++) != '\0';)
603 	    continue;
604 	if (match(pathend, pattern, restpattern, (int) m_not) == no_match) {
605 	    *pathend = EOS;
606 	    continue;
607 	}
608 	err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
609 	if (err)
610 	    break;
611     }
612     /* todo: check error from readdir? */
613     (void) closedir(dirp);
614     return (err);
615 }
616 
617 
618 /*
619  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
620  * add the new item, and update gl_pathc.
621  *
622  * This assumes the BSD realloc, which only copies the block when its size
623  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
624  * behavior.
625  *
626  * Return 0 if new item added, error code if memory couldn't be allocated.
627  *
628  * Invariant of the glob_t structure:
629  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
630  *	 gl_pathv points to (gl_offs + gl_pathc + 1) items.
631  */
632 static int
633 globextend(path, pglob)
634     Char *path;
635     glob_t *pglob;
636 {
637     register char **pathv;
638     register int i;
639     unsigned int newsize;
640     char   *copy;
641     Char *p;
642 
643     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
644     pathv = (char **) (pglob->gl_pathv ?
645 		       xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) :
646 		       xmalloc((size_t) newsize));
647     if (pathv == NULL)
648 	return (GLOB_NOSPACE);
649 
650     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
651 	/* first time around -- clear initial gl_offs items */
652 	pathv += pglob->gl_offs;
653 	for (i = pglob->gl_offs; --i >= 0;)
654 	    *--pathv = NULL;
655     }
656     pglob->gl_pathv = pathv;
657 
658     for (p = path; *p++;)
659 	continue;
660     if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) {
661 	register char *dc = copy;
662 	register Char *sc = path;
663 
664 	while ((*dc++ = *sc++) != '\0')
665 	    continue;
666 	pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
667     }
668     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
669     return ((copy == NULL) ? GLOB_NOSPACE : 0);
670 }
671 
672 
673 /*
674  * pattern matching function for filenames.  Each occurrence of the *
675  * pattern causes a recursion level.
676  */
677 static  int
678 match(name, pat, patend, m_not)
679     register Char *name, *pat, *patend;
680     int m_not;
681 {
682     int ok, negate_range;
683     Char c, k;
684 
685     while (pat < patend) {
686 	c = *pat++;
687 	switch (c & M_MASK) {
688 	case M_ALL:
689 	    if (pat == patend)
690 		return (1);
691 	    do
692 		if (match(name, pat, patend, m_not))
693 		    return (1);
694 	    while (*name++ != EOS);
695 	    return (0);
696 	case M_ONE:
697 	    if (*name++ == EOS)
698 		return (0);
699 	    break;
700 	case M_SET:
701 	    ok = 0;
702 	    if ((k = *name++) == EOS)
703 		return (0);
704 	    if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
705 		++pat;
706 	    while (((c = *pat++) & M_MASK) != M_END) {
707 		if ((*pat & M_MASK) == M_RNG) {
708 		    if (globcharcoll(CHAR(c), CHAR(k)) <= 0 &&
709 			globcharcoll(CHAR(k), CHAR(pat[1])) <= 0)
710 			ok = 1;
711 		    pat += 2;
712 		}
713 		else if (c == k)
714 		    ok = 1;
715 	    }
716 	    if (ok == negate_range)
717 		return (0);
718 	    break;
719 	default:
720 	    k = *name++;
721 	    if (samecase(k) != samecase(c))
722 		return (0);
723 	    break;
724 	}
725     }
726     return (*name == EOS);
727 }
728 
729 /* free allocated data belonging to a glob_t structure */
730 void
731 globfree(pglob)
732     glob_t *pglob;
733 {
734     register int i;
735     register char **pp;
736 
737     if (pglob->gl_pathv != NULL) {
738 	pp = pglob->gl_pathv + pglob->gl_offs;
739 	for (i = pglob->gl_pathc; i--; ++pp)
740 	    if (*pp)
741 		xfree((ptr_t) *pp), *pp = NULL;
742 	xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
743     }
744 }
745