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