xref: /freebsd/contrib/tcsh/glob.c (revision 19d2e3de755b7c9ca2f5c90b5902fc8f214b2490)
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.
1629301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
17c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien  *    without specific prior written permission.
19c80476e4SDavid E. O'Brien  *
20c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien  */
32c80476e4SDavid E. O'Brien #if defined(LIBC_SCCS) && !defined(lint)
33c80476e4SDavid E. O'Brien static char sccsid[] = "@(#)glob.c	5.12 (Berkeley) 6/24/91";
34c80476e4SDavid E. O'Brien #endif /* LIBC_SCCS and not lint */
35c80476e4SDavid E. O'Brien /*
36c80476e4SDavid E. O'Brien  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
37c80476e4SDavid E. O'Brien  * draft 9.
38c80476e4SDavid E. O'Brien  *
39c80476e4SDavid E. O'Brien  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
40c80476e4SDavid E. O'Brien  *
41c80476e4SDavid E. O'Brien  * Optional extra services, controlled by flags not defined by POSIX:
42c80476e4SDavid E. O'Brien  *
43c80476e4SDavid E. O'Brien  * GLOB_QUOTE:
44c80476e4SDavid E. O'Brien  *	Escaping convention: \ inhibits any special meaning the following
45c80476e4SDavid E. O'Brien  *	character might have (except \ at end of string is retained).
46c80476e4SDavid E. O'Brien  * GLOB_MAGCHAR:
47c80476e4SDavid E. O'Brien  *	Set in gl_flags if pattern contained a globbing character.
48c80476e4SDavid E. O'Brien  * GLOB_ALTNOT:
49c80476e4SDavid E. O'Brien  *	Use ^ instead of ! for "not".
50c80476e4SDavid E. O'Brien  * gl_matchc:
51c80476e4SDavid E. O'Brien  *	Number of matches in the current invocation of glob.
52c80476e4SDavid E. O'Brien  */
53c80476e4SDavid E. O'Brien 
543b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
55c80476e4SDavid E. O'Brien 	#pragma warning(disable:4244)
563b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
57c80476e4SDavid E. O'Brien 
58c80476e4SDavid E. O'Brien #define Char __Char
59c80476e4SDavid E. O'Brien #include "sh.h"
6023338178SMark Peek #include "glob.h"
6123338178SMark Peek 
62*19d2e3deSDmitry Chagin #ifndef HAVE_MBLEN
63*19d2e3deSDmitry Chagin #undef mblen
64*19d2e3deSDmitry Chagin #define mblen(_s,_n)	mbrlen((_s),(_n),NULL)
65*19d2e3deSDmitry Chagin #endif
66*19d2e3deSDmitry Chagin 
67c80476e4SDavid E. O'Brien #undef Char
68c80476e4SDavid E. O'Brien #undef QUOTE
69c80476e4SDavid E. O'Brien #undef TILDE
70c80476e4SDavid E. O'Brien #undef META
71c80476e4SDavid E. O'Brien #undef ismeta
72c80476e4SDavid E. O'Brien #undef Strchr
73c80476e4SDavid E. O'Brien 
74c80476e4SDavid E. O'Brien #ifndef S_ISDIR
75c80476e4SDavid E. O'Brien #define S_ISDIR(a)	(((a) & S_IFMT) == S_IFDIR)
76c80476e4SDavid E. O'Brien #endif
77c80476e4SDavid E. O'Brien 
78c80476e4SDavid E. O'Brien #if !defined(S_ISLNK) && defined(S_IFLNK)
79c80476e4SDavid E. O'Brien #define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
80c80476e4SDavid E. O'Brien #endif
81c80476e4SDavid E. O'Brien 
82c80476e4SDavid E. O'Brien #if !defined(S_ISLNK) && !defined(lstat)
83c80476e4SDavid E. O'Brien #define lstat stat
84c80476e4SDavid E. O'Brien #endif
85c80476e4SDavid E. O'Brien 
86c80476e4SDavid E. O'Brien typedef unsigned short Char;
87c80476e4SDavid E. O'Brien 
8845e5710bSMark Peek static	int	 glob1 		(Char *, glob_t *, int);
8945e5710bSMark Peek static	int	 glob2		(struct strbuf *, const Char *, glob_t *, int);
9045e5710bSMark Peek static	int	 glob3		(struct strbuf *, const Char *, const Char *,
919ccc37e3SMark Peek 				 const Char *, glob_t *, int);
9245e5710bSMark Peek static	void	 globextend	(const char *, glob_t *);
9345e5710bSMark Peek static	int	 match		(const char *, const Char *, const Char *,
9445e5710bSMark Peek 				 int);
9545e5710bSMark Peek static	int	 compare	(const void *, const void *);
9645e5710bSMark Peek static 	DIR	*Opendir	(const char *);
97c80476e4SDavid E. O'Brien #ifdef S_IFLNK
9845e5710bSMark Peek static	int	 Lstat		(const char *, struct stat *);
99c80476e4SDavid E. O'Brien #endif
10045e5710bSMark Peek static	int	 Stat		(const char *, struct stat *sb);
10145e5710bSMark Peek static 	Char 	*Strchr		(Char *, int);
102c80476e4SDavid E. O'Brien #ifdef DEBUG
10345e5710bSMark Peek static	void	 qprintf	(const Char *);
104c80476e4SDavid E. O'Brien #endif
105c80476e4SDavid E. O'Brien 
106c80476e4SDavid E. O'Brien #define	DOLLAR		'$'
107c80476e4SDavid E. O'Brien #define	DOT		'.'
108c80476e4SDavid E. O'Brien #define	EOS		'\0'
109c80476e4SDavid E. O'Brien #define	LBRACKET	'['
110c80476e4SDavid E. O'Brien #define	NOT		'!'
111c80476e4SDavid E. O'Brien #define ALTNOT		'^'
112c80476e4SDavid E. O'Brien #define	QUESTION	'?'
113c80476e4SDavid E. O'Brien #define	QUOTE		'\\'
114c80476e4SDavid E. O'Brien #define	RANGE		'-'
115c80476e4SDavid E. O'Brien #define	RBRACKET	']'
116c80476e4SDavid E. O'Brien #define	SEP		'/'
117c80476e4SDavid E. O'Brien #define	STAR		'*'
118c80476e4SDavid E. O'Brien #define	TILDE		'~'
119c80476e4SDavid E. O'Brien #define	UNDERSCORE	'_'
120c80476e4SDavid E. O'Brien 
121c80476e4SDavid E. O'Brien #define	M_META		0x8000
122c80476e4SDavid E. O'Brien #define M_PROTECT	0x4000
123c80476e4SDavid E. O'Brien #define	M_MASK		0xffff
124c80476e4SDavid E. O'Brien #define	M_ASCII		0x00ff
125c80476e4SDavid E. O'Brien 
12645e5710bSMark Peek #define	LCHAR(c)	((c)&M_ASCII)
127c80476e4SDavid E. O'Brien #define	META(c)		((c)|M_META)
128c80476e4SDavid E. O'Brien #define	M_ALL		META('*')
129c80476e4SDavid E. O'Brien #define	M_END		META(']')
130c80476e4SDavid E. O'Brien #define	M_NOT		META('!')
131c80476e4SDavid E. O'Brien #define	M_ALTNOT	META('^')
132c80476e4SDavid E. O'Brien #define	M_ONE		META('?')
133c80476e4SDavid E. O'Brien #define	M_RNG		META('-')
134c80476e4SDavid E. O'Brien #define	M_SET		META('[')
135c80476e4SDavid E. O'Brien #define	ismeta(c)	(((c)&M_META) != 0)
136c80476e4SDavid E. O'Brien 
137c80476e4SDavid E. O'Brien int
13845e5710bSMark Peek globcharcoll(__Char c1, __Char c2, int cs)
139c80476e4SDavid E. O'Brien {
14045e5710bSMark Peek #if defined(NLS) && defined(LC_COLLATE) && defined(HAVE_STRCOLL)
14145e5710bSMark Peek # if defined(WIDE_STRINGS)
14223338178SMark Peek     wchar_t s1[2], s2[2];
14323338178SMark Peek 
14423338178SMark Peek     if (c1 == c2)
14523338178SMark Peek 	return (0);
14623338178SMark Peek     if (cs) {
14723338178SMark Peek 	c1 = towlower(c1);
14823338178SMark Peek 	c2 = towlower(c2);
14923338178SMark Peek     } else {
1502219fc0fSAndrey A. Chernov #ifndef __FreeBSD__
15123338178SMark Peek 	/* This should not be here, but I'll rather leave it in than engage in
15223338178SMark Peek 	   a LC_COLLATE flamewar about a shell I don't use... */
15323338178SMark Peek 	if (iswlower(c1) && iswupper(c2))
15423338178SMark Peek 	    return (1);
15523338178SMark Peek 	if (iswupper(c1) && iswlower(c2))
15623338178SMark Peek 	    return (-1);
1572219fc0fSAndrey A. Chernov #endif
15823338178SMark Peek     }
15923338178SMark Peek     s1[0] = c1;
16023338178SMark Peek     s2[0] = c2;
16123338178SMark Peek     s1[1] = s2[1] = '\0';
16223338178SMark Peek     return wcscoll(s1, s2);
16345e5710bSMark Peek # else /* not WIDE_STRINGS */
164c80476e4SDavid E. O'Brien     char s1[2], s2[2];
165c80476e4SDavid E. O'Brien 
166c80476e4SDavid E. O'Brien     if (c1 == c2)
167c80476e4SDavid E. O'Brien 	return (0);
1688e66bd9eSDavid E. O'Brien     /*
1698e66bd9eSDavid E. O'Brien      * From kevin lyda <kevin@suberic.net>:
1708e66bd9eSDavid E. O'Brien      * strcoll does not guarantee case sorting, so we pre-process now:
1718e66bd9eSDavid E. O'Brien      */
172b2d5d167SMark Peek     if (cs) {
173b2d5d167SMark Peek 	c1 = islower(c1) ? c1 : tolower(c1);
174b2d5d167SMark Peek 	c2 = islower(c2) ? c2 : tolower(c2);
175b2d5d167SMark Peek     } else {
1768e66bd9eSDavid E. O'Brien 	if (islower(c1) && isupper(c2))
1778e66bd9eSDavid E. O'Brien 	    return (1);
17823338178SMark Peek 	if (isupper(c1) && islower(c2))
17923338178SMark Peek 	    return (-1);
180b2d5d167SMark Peek     }
181c80476e4SDavid E. O'Brien     s1[0] = c1;
182c80476e4SDavid E. O'Brien     s2[0] = c2;
183c80476e4SDavid E. O'Brien     s1[1] = s2[1] = '\0';
184c80476e4SDavid E. O'Brien     return strcoll(s1, s2);
18523338178SMark Peek # endif
186c80476e4SDavid E. O'Brien #else
187c80476e4SDavid E. O'Brien     return (c1 - c2);
188c80476e4SDavid E. O'Brien #endif
189c80476e4SDavid E. O'Brien }
190c80476e4SDavid E. O'Brien 
191c80476e4SDavid E. O'Brien /*
192c80476e4SDavid E. O'Brien  * Need to dodge two kernel bugs:
193c80476e4SDavid E. O'Brien  * opendir("") != opendir(".")
194c80476e4SDavid E. O'Brien  * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
195c80476e4SDavid E. O'Brien  *            POSIX specifies that they should be ignored in directories.
196c80476e4SDavid E. O'Brien  */
197c80476e4SDavid E. O'Brien 
198c80476e4SDavid E. O'Brien static DIR *
19945e5710bSMark Peek Opendir(const char *str)
200c80476e4SDavid E. O'Brien {
201c80476e4SDavid E. O'Brien #if defined(hpux) || defined(__hpux)
202c80476e4SDavid E. O'Brien     struct stat st;
203c80476e4SDavid E. O'Brien #endif
204c80476e4SDavid E. O'Brien 
205c80476e4SDavid E. O'Brien     if (!*str)
206c80476e4SDavid E. O'Brien 	return (opendir("."));
207c80476e4SDavid E. O'Brien #if defined(hpux) || defined(__hpux)
208c80476e4SDavid E. O'Brien     /*
209c80476e4SDavid E. O'Brien      * Opendir on some device files hangs, so avoid it
210c80476e4SDavid E. O'Brien      */
21145e5710bSMark Peek     if (stat(str, &st) == -1 || !S_ISDIR(st.st_mode))
212c80476e4SDavid E. O'Brien 	return NULL;
213c80476e4SDavid E. O'Brien #endif
21445e5710bSMark Peek     return opendir(str);
215c80476e4SDavid E. O'Brien }
216c80476e4SDavid E. O'Brien 
217c80476e4SDavid E. O'Brien #ifdef S_IFLNK
218c80476e4SDavid E. O'Brien static int
21945e5710bSMark Peek Lstat(const char *fn, struct stat *sb)
220c80476e4SDavid E. O'Brien {
221c80476e4SDavid E. O'Brien     int st;
222c80476e4SDavid E. O'Brien 
22345e5710bSMark Peek     st = lstat(fn, sb);
22445e5710bSMark Peek # ifdef NAMEI_BUG
22545e5710bSMark Peek     if (*fn != 0 && strend(fn)[-1] == '/' && !S_ISDIR(sb->st_mode))
22645e5710bSMark Peek 	st = -1;
227c80476e4SDavid E. O'Brien # endif	/* NAMEI_BUG */
22845e5710bSMark Peek     return st;
229c80476e4SDavid E. O'Brien }
230c80476e4SDavid E. O'Brien #else
231c80476e4SDavid E. O'Brien #define Lstat Stat
232c80476e4SDavid E. O'Brien #endif /* S_IFLNK */
233c80476e4SDavid E. O'Brien 
234c80476e4SDavid E. O'Brien static int
23545e5710bSMark Peek Stat(const char *fn, struct stat *sb)
236c80476e4SDavid E. O'Brien {
237c80476e4SDavid E. O'Brien     int st;
238c80476e4SDavid E. O'Brien 
23945e5710bSMark Peek     st = stat(fn, sb);
24045e5710bSMark Peek #ifdef NAMEI_BUG
24145e5710bSMark Peek     if (*fn != 0 && strend(fn)[-1] == '/' && !S_ISDIR(sb->st_mode))
24245e5710bSMark Peek 	st = -1;
243c80476e4SDavid E. O'Brien #endif /* NAMEI_BUG */
24445e5710bSMark Peek     return st;
245c80476e4SDavid E. O'Brien }
246c80476e4SDavid E. O'Brien 
247c80476e4SDavid E. O'Brien static Char *
24845e5710bSMark Peek Strchr(Char *str, int ch)
249c80476e4SDavid E. O'Brien {
250c80476e4SDavid E. O'Brien     do
251c80476e4SDavid E. O'Brien 	if (*str == ch)
252c80476e4SDavid E. O'Brien 	    return (str);
253c80476e4SDavid E. O'Brien     while (*str++);
254c80476e4SDavid E. O'Brien     return (NULL);
255c80476e4SDavid E. O'Brien }
256c80476e4SDavid E. O'Brien 
257c80476e4SDavid E. O'Brien #ifdef DEBUG
258c80476e4SDavid E. O'Brien static void
25945e5710bSMark Peek qprintf(const Char *s)
260c80476e4SDavid E. O'Brien {
26145e5710bSMark Peek     const Char *p;
262c80476e4SDavid E. O'Brien 
263c80476e4SDavid E. O'Brien     for (p = s; *p; p++)
264c80476e4SDavid E. O'Brien 	printf("%c", *p & 0xff);
265c80476e4SDavid E. O'Brien     printf("\n");
266c80476e4SDavid E. O'Brien     for (p = s; *p; p++)
267c80476e4SDavid E. O'Brien 	printf("%c", *p & M_PROTECT ? '"' : ' ');
268c80476e4SDavid E. O'Brien     printf("\n");
269c80476e4SDavid E. O'Brien     for (p = s; *p; p++)
270c80476e4SDavid E. O'Brien 	printf("%c", *p & M_META ? '_' : ' ');
271c80476e4SDavid E. O'Brien     printf("\n");
272c80476e4SDavid E. O'Brien }
273c80476e4SDavid E. O'Brien #endif /* DEBUG */
274c80476e4SDavid E. O'Brien 
275c80476e4SDavid E. O'Brien static int
27645e5710bSMark Peek compare(const void *p, const void *q)
277c80476e4SDavid E. O'Brien {
27845e5710bSMark Peek #if defined(NLS) && defined(HAVE_STRCOLL)
27945e5710bSMark Peek     return (strcoll(*(char *const *) p, *(char *const *) q));
280c80476e4SDavid E. O'Brien #else
28145e5710bSMark Peek     return (strcmp(*(char *const *) p, *(char *const *) q));
28245e5710bSMark Peek #endif /* NLS && HAVE_STRCOLL */
283c80476e4SDavid E. O'Brien }
284c80476e4SDavid E. O'Brien 
285c80476e4SDavid E. O'Brien /*
286c80476e4SDavid E. O'Brien  * The main glob() routine: compiles the pattern (optionally processing
287c80476e4SDavid E. O'Brien  * quotes), calls glob1() to do the real pattern matching, and finally
288c80476e4SDavid E. O'Brien  * sorts the list (unless unsorted operation is requested).  Returns 0
289c80476e4SDavid E. O'Brien  * if things went well, nonzero if errors occurred.  It is not an error
290c80476e4SDavid E. O'Brien  * to find no matches.
291c80476e4SDavid E. O'Brien  */
292c80476e4SDavid E. O'Brien int
29345e5710bSMark Peek glob(const char *pattern, int flags, int (*errfunc) (const char *, int),
29445e5710bSMark Peek      glob_t *pglob)
295c80476e4SDavid E. O'Brien {
296c80476e4SDavid E. O'Brien     int     err, oldpathc;
29745e5710bSMark Peek     Char *bufnext, m_not;
29845e5710bSMark Peek     const unsigned char *patnext;
299c80476e4SDavid E. O'Brien     int     c, not;
30045e5710bSMark Peek     Char *qpatnext, *patbuf;
301c80476e4SDavid E. O'Brien     int     no_match;
302c80476e4SDavid E. O'Brien 
30323338178SMark Peek     patnext = (const unsigned char *) pattern;
304c80476e4SDavid E. O'Brien     if (!(flags & GLOB_APPEND)) {
305c80476e4SDavid E. O'Brien 	pglob->gl_pathc = 0;
306c80476e4SDavid E. O'Brien 	pglob->gl_pathv = NULL;
307c80476e4SDavid E. O'Brien 	if (!(flags & GLOB_DOOFFS))
308c80476e4SDavid E. O'Brien 	    pglob->gl_offs = 0;
309c80476e4SDavid E. O'Brien     }
310c80476e4SDavid E. O'Brien     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
311c80476e4SDavid E. O'Brien     pglob->gl_errfunc = errfunc;
312c80476e4SDavid E. O'Brien     oldpathc = pglob->gl_pathc;
313c80476e4SDavid E. O'Brien     pglob->gl_matchc = 0;
314c80476e4SDavid E. O'Brien 
315c80476e4SDavid E. O'Brien     if (pglob->gl_flags & GLOB_ALTNOT) {
316c80476e4SDavid E. O'Brien 	not = ALTNOT;
317c80476e4SDavid E. O'Brien 	m_not = M_ALTNOT;
318c80476e4SDavid E. O'Brien     }
319c80476e4SDavid E. O'Brien     else {
320c80476e4SDavid E. O'Brien 	not = NOT;
321c80476e4SDavid E. O'Brien 	m_not = M_NOT;
322c80476e4SDavid E. O'Brien     }
323c80476e4SDavid E. O'Brien 
32445e5710bSMark Peek     patbuf = xmalloc((strlen(pattern) + 1) * sizeof(*patbuf));
325c80476e4SDavid E. O'Brien     bufnext = patbuf;
326c80476e4SDavid E. O'Brien 
327c80476e4SDavid E. O'Brien     no_match = *patnext == not;
328c80476e4SDavid E. O'Brien     if (no_match)
329c80476e4SDavid E. O'Brien 	patnext++;
330c80476e4SDavid E. O'Brien 
331c80476e4SDavid E. O'Brien     if (flags & GLOB_QUOTE) {
332c80476e4SDavid E. O'Brien 	/* Protect the quoted characters */
33345e5710bSMark Peek 	while ((c = *patnext++) != EOS) {
33423338178SMark Peek #ifdef WIDE_STRINGS
33523338178SMark Peek 	    int len;
33623338178SMark Peek 
33723338178SMark Peek 	    len = mblen((const char *)(patnext - 1), MB_LEN_MAX);
33823338178SMark Peek 	    if (len == -1)
3399ccc37e3SMark Peek 		TCSH_IGNORE(mblen(NULL, 0));
340a15e6f9aSMark Peek 	    else if (len > 1) {
3418e66bd9eSDavid E. O'Brien 		*bufnext++ = (Char) c;
34223338178SMark Peek 		while (--len != 0)
34323338178SMark Peek 		    *bufnext++ = (Char) (*patnext++ | M_PROTECT);
34423338178SMark Peek 	    } else
34523338178SMark Peek #endif /* WIDE_STRINGS */
346c80476e4SDavid E. O'Brien 	    if (c == QUOTE) {
347c80476e4SDavid E. O'Brien 		if ((c = *patnext++) == EOS) {
348c80476e4SDavid E. O'Brien 		    c = QUOTE;
349c80476e4SDavid E. O'Brien 		    --patnext;
350c80476e4SDavid E. O'Brien 		}
351c80476e4SDavid E. O'Brien 		*bufnext++ = (Char) (c | M_PROTECT);
352c80476e4SDavid E. O'Brien 	    }
353c80476e4SDavid E. O'Brien 	    else
354c80476e4SDavid E. O'Brien 		*bufnext++ = (Char) c;
355c80476e4SDavid E. O'Brien 	}
35623338178SMark Peek     }
357c80476e4SDavid E. O'Brien     else
35845e5710bSMark Peek 	while ((c = *patnext++) != EOS)
359c80476e4SDavid E. O'Brien 	    *bufnext++ = (Char) c;
360c80476e4SDavid E. O'Brien     *bufnext = EOS;
361c80476e4SDavid E. O'Brien 
362c80476e4SDavid E. O'Brien     bufnext = patbuf;
363c80476e4SDavid E. O'Brien     qpatnext = patbuf;
364c80476e4SDavid E. O'Brien     while ((c = *qpatnext++) != EOS) {
365c80476e4SDavid E. O'Brien 	switch (c) {
366c80476e4SDavid E. O'Brien 	case LBRACKET:
367c80476e4SDavid E. O'Brien 	    c = *qpatnext;
368c80476e4SDavid E. O'Brien 	    if (c == not)
369c80476e4SDavid E. O'Brien 		++qpatnext;
370c80476e4SDavid E. O'Brien 	    if (*qpatnext == EOS ||
371c80476e4SDavid E. O'Brien 		Strchr(qpatnext + 1, RBRACKET) == NULL) {
372c80476e4SDavid E. O'Brien 		*bufnext++ = LBRACKET;
373c80476e4SDavid E. O'Brien 		if (c == not)
374c80476e4SDavid E. O'Brien 		    --qpatnext;
375c80476e4SDavid E. O'Brien 		break;
376c80476e4SDavid E. O'Brien 	    }
377c80476e4SDavid E. O'Brien 	    pglob->gl_flags |= GLOB_MAGCHAR;
378c80476e4SDavid E. O'Brien 	    *bufnext++ = M_SET;
379c80476e4SDavid E. O'Brien 	    if (c == not)
380c80476e4SDavid E. O'Brien 		*bufnext++ = m_not;
381c80476e4SDavid E. O'Brien 	    c = *qpatnext++;
382c80476e4SDavid E. O'Brien 	    do {
38345e5710bSMark Peek 		*bufnext++ = LCHAR(c);
384c80476e4SDavid E. O'Brien 		if (*qpatnext == RANGE &&
385c80476e4SDavid E. O'Brien 		    (c = qpatnext[1]) != RBRACKET) {
386c80476e4SDavid E. O'Brien 		    *bufnext++ = M_RNG;
38745e5710bSMark Peek 		    *bufnext++ = LCHAR(c);
388c80476e4SDavid E. O'Brien 		    qpatnext += 2;
389c80476e4SDavid E. O'Brien 		}
390c80476e4SDavid E. O'Brien 	    } while ((c = *qpatnext++) != RBRACKET);
391c80476e4SDavid E. O'Brien 	    *bufnext++ = M_END;
392c80476e4SDavid E. O'Brien 	    break;
393c80476e4SDavid E. O'Brien 	case QUESTION:
394c80476e4SDavid E. O'Brien 	    pglob->gl_flags |= GLOB_MAGCHAR;
395c80476e4SDavid E. O'Brien 	    *bufnext++ = M_ONE;
396c80476e4SDavid E. O'Brien 	    break;
397c80476e4SDavid E. O'Brien 	case STAR:
398c80476e4SDavid E. O'Brien 	    pglob->gl_flags |= GLOB_MAGCHAR;
3999ccc37e3SMark Peek 	    /* collapse adjacent stars to one [or three if globstar],
4009ccc37e3SMark Peek 	     * to avoid exponential behavior
401c80476e4SDavid E. O'Brien 	     */
4029ccc37e3SMark Peek 	    if (bufnext == patbuf || bufnext[-1] != M_ALL ||
4039ccc37e3SMark Peek 	       ((flags & GLOB_STAR) != 0 &&
4049ccc37e3SMark Peek 		 (bufnext - 1 == patbuf || bufnext[-2] != M_ALL ||
4059ccc37e3SMark Peek 		 bufnext - 2 == patbuf || bufnext[-3] != M_ALL)))
406c80476e4SDavid E. O'Brien 		*bufnext++ = M_ALL;
407c80476e4SDavid E. O'Brien 	    break;
408c80476e4SDavid E. O'Brien 	default:
40945e5710bSMark Peek 	    *bufnext++ = LCHAR(c);
410c80476e4SDavid E. O'Brien 	    break;
411c80476e4SDavid E. O'Brien 	}
412c80476e4SDavid E. O'Brien     }
413c80476e4SDavid E. O'Brien     *bufnext = EOS;
414c80476e4SDavid E. O'Brien #ifdef DEBUG
415c80476e4SDavid E. O'Brien     qprintf(patbuf);
416c80476e4SDavid E. O'Brien #endif
417c80476e4SDavid E. O'Brien 
41845e5710bSMark Peek     if ((err = glob1(patbuf, pglob, no_match)) != 0) {
41945e5710bSMark Peek 	xfree(patbuf);
420c80476e4SDavid E. O'Brien 	return (err);
42145e5710bSMark Peek     }
422c80476e4SDavid E. O'Brien 
423c80476e4SDavid E. O'Brien     /*
424c80476e4SDavid E. O'Brien      * If there was no match we are going to append the pattern
425c80476e4SDavid E. O'Brien      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
426c80476e4SDavid E. O'Brien      * and the pattern did not contain any magic characters
427c80476e4SDavid E. O'Brien      * GLOB_NOMAGIC is there just for compatibility with csh.
428c80476e4SDavid E. O'Brien      */
429c80476e4SDavid E. O'Brien     if (pglob->gl_pathc == oldpathc &&
430c80476e4SDavid E. O'Brien 	((flags & GLOB_NOCHECK) ||
431c80476e4SDavid E. O'Brien 	 ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
43245e5710bSMark Peek 	if (!(flags & GLOB_QUOTE))
43345e5710bSMark Peek 	    globextend(pattern, pglob);
434c80476e4SDavid E. O'Brien 	else {
43545e5710bSMark Peek 	    char *copy, *dest;
43645e5710bSMark Peek 	    const char *src;
43745e5710bSMark Peek 
43845e5710bSMark Peek 	    /* copy pattern, interpreting quotes */
43945e5710bSMark Peek 	    copy = xmalloc(strlen(pattern) + 1);
44045e5710bSMark Peek 	    dest = copy;
44145e5710bSMark Peek 	    src = pattern;
44245e5710bSMark Peek 	    while (*src != EOS) {
443*19d2e3deSDmitry Chagin 		/* Don't interpret quotes. The spec does not say we should do */
44445e5710bSMark Peek 		if (*src == QUOTE) {
44545e5710bSMark Peek 		    if (*++src == EOS)
44645e5710bSMark Peek 			--src;
447c80476e4SDavid E. O'Brien 		}
44845e5710bSMark Peek 		*dest++ = *src++;
449c80476e4SDavid E. O'Brien 	    }
45045e5710bSMark Peek 	    *dest = EOS;
45145e5710bSMark Peek 	    globextend(copy, pglob);
45245e5710bSMark Peek 	    xfree(copy);
453c80476e4SDavid E. O'Brien 	}
45445e5710bSMark Peek 	xfree(patbuf);
45545e5710bSMark Peek 	return 0;
456c80476e4SDavid E. O'Brien     }
4578e66bd9eSDavid E. O'Brien     else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc))
45845e5710bSMark Peek 	qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
45945e5710bSMark Peek 	      pglob->gl_pathc - oldpathc, sizeof(char *), compare);
46045e5710bSMark Peek     xfree(patbuf);
461c80476e4SDavid E. O'Brien     return (0);
462c80476e4SDavid E. O'Brien }
463c80476e4SDavid E. O'Brien 
464c80476e4SDavid E. O'Brien static int
46545e5710bSMark Peek glob1(Char *pattern, glob_t *pglob, int no_match)
466c80476e4SDavid E. O'Brien {
46745e5710bSMark Peek     struct strbuf pathbuf = strbuf_INIT;
46845e5710bSMark Peek     int err;
469c80476e4SDavid E. O'Brien 
470c80476e4SDavid E. O'Brien     /*
471c80476e4SDavid E. O'Brien      * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
472c80476e4SDavid E. O'Brien      */
473c80476e4SDavid E. O'Brien     if (*pattern == EOS)
474c80476e4SDavid E. O'Brien 	return (0);
47545e5710bSMark Peek     err = glob2(&pathbuf, pattern, pglob, no_match);
47645e5710bSMark Peek     xfree(pathbuf.s);
47745e5710bSMark Peek     return err;
478c80476e4SDavid E. O'Brien }
479c80476e4SDavid E. O'Brien 
480c80476e4SDavid E. O'Brien /*
481c80476e4SDavid E. O'Brien  * functions glob2 and glob3 are mutually recursive; there is one level
482c80476e4SDavid E. O'Brien  * of recursion for each segment in the pattern that contains one or
483c80476e4SDavid E. O'Brien  * more meta characters.
484c80476e4SDavid E. O'Brien  */
485c80476e4SDavid E. O'Brien static int
48645e5710bSMark Peek glob2(struct strbuf *pathbuf, const Char *pattern, glob_t *pglob, int no_match)
487c80476e4SDavid E. O'Brien {
488c80476e4SDavid E. O'Brien     struct stat sbuf;
489c80476e4SDavid E. O'Brien     int anymeta;
49045e5710bSMark Peek     const Char *p;
49145e5710bSMark Peek     size_t orig_len;
492c80476e4SDavid E. O'Brien 
493c80476e4SDavid E. O'Brien     /*
494c80476e4SDavid E. O'Brien      * loop over pattern segments until end of pattern or until segment with
495c80476e4SDavid E. O'Brien      * meta character found.
496c80476e4SDavid E. O'Brien      */
497c80476e4SDavid E. O'Brien     anymeta = 0;
498c80476e4SDavid E. O'Brien     for (;;) {
499c80476e4SDavid E. O'Brien 	if (*pattern == EOS) {	/* end of pattern? */
50045e5710bSMark Peek 	    strbuf_terminate(pathbuf);
501c80476e4SDavid E. O'Brien 
50245e5710bSMark Peek 	    if (Lstat(pathbuf->s, &sbuf))
503c80476e4SDavid E. O'Brien 		return (0);
504c80476e4SDavid E. O'Brien 
505c80476e4SDavid E. O'Brien 	    if (((pglob->gl_flags & GLOB_MARK) &&
50645e5710bSMark Peek 		 pathbuf->s[pathbuf->len - 1] != SEP) &&
507c80476e4SDavid E. O'Brien 		(S_ISDIR(sbuf.st_mode)
508c80476e4SDavid E. O'Brien #ifdef S_IFLNK
509c80476e4SDavid E. O'Brien 		 || (S_ISLNK(sbuf.st_mode) &&
51045e5710bSMark Peek 		     (Stat(pathbuf->s, &sbuf) == 0) &&
511c80476e4SDavid E. O'Brien 		     S_ISDIR(sbuf.st_mode))
512c80476e4SDavid E. O'Brien #endif
513c80476e4SDavid E. O'Brien 		 )) {
51445e5710bSMark Peek 		strbuf_append1(pathbuf, SEP);
51545e5710bSMark Peek 		strbuf_terminate(pathbuf);
516c80476e4SDavid E. O'Brien 	    }
517c80476e4SDavid E. O'Brien 	    ++pglob->gl_matchc;
51845e5710bSMark Peek 	    globextend(pathbuf->s, pglob);
51945e5710bSMark Peek 	    return 0;
520c80476e4SDavid E. O'Brien 	}
521c80476e4SDavid E. O'Brien 
52245e5710bSMark Peek 	/* find end of next segment, tentatively copy to pathbuf */
523c80476e4SDavid E. O'Brien 	p = pattern;
52445e5710bSMark Peek 	orig_len = pathbuf->len;
525c80476e4SDavid E. O'Brien 	while (*p != EOS && *p != SEP) {
526c80476e4SDavid E. O'Brien 	    if (ismeta(*p))
527c80476e4SDavid E. O'Brien 		anymeta = 1;
52845e5710bSMark Peek 	    strbuf_append1(pathbuf, *p++);
529c80476e4SDavid E. O'Brien 	}
530c80476e4SDavid E. O'Brien 
531c80476e4SDavid E. O'Brien 	if (!anymeta) {		/* no expansion, do next segment */
532c80476e4SDavid E. O'Brien 	    pattern = p;
533c80476e4SDavid E. O'Brien 	    while (*pattern == SEP)
53445e5710bSMark Peek 		strbuf_append1(pathbuf, *pattern++);
535c80476e4SDavid E. O'Brien 	}
53645e5710bSMark Peek 	else {			/* need expansion, recurse */
53745e5710bSMark Peek 	    pathbuf->len = orig_len;
5389ccc37e3SMark Peek 	    return (glob3(pathbuf, pattern, p, pattern, pglob, no_match));
53945e5710bSMark Peek 	}
540c80476e4SDavid E. O'Brien     }
541c80476e4SDavid E. O'Brien     /* NOTREACHED */
542c80476e4SDavid E. O'Brien }
543c80476e4SDavid E. O'Brien 
5449ccc37e3SMark Peek static size_t
5459ccc37e3SMark Peek One_Char_mbtowc(__Char *pwc, const Char *s, size_t n)
5469ccc37e3SMark Peek {
5479ccc37e3SMark Peek #ifdef WIDE_STRINGS
5489ccc37e3SMark Peek     char buf[MB_LEN_MAX], *p;
5499ccc37e3SMark Peek 
5509ccc37e3SMark Peek     if (n > MB_LEN_MAX)
5519ccc37e3SMark Peek 	n = MB_LEN_MAX;
5529ccc37e3SMark Peek     p = buf;
5539ccc37e3SMark Peek     while (p < buf + n && (*p++ = LCHAR(*s++)) != 0)
5549ccc37e3SMark Peek 	;
5559ccc37e3SMark Peek     return one_mbtowc(pwc, buf, n);
5569ccc37e3SMark Peek #else
5579ccc37e3SMark Peek     *pwc = *s & CHAR;
5589ccc37e3SMark Peek     return 1;
5599ccc37e3SMark Peek #endif
5609ccc37e3SMark Peek }
561c80476e4SDavid E. O'Brien 
562c80476e4SDavid E. O'Brien static int
56345e5710bSMark Peek glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern,
5649ccc37e3SMark Peek       const Char *pglobstar, glob_t *pglob, int no_match)
565c80476e4SDavid E. O'Brien {
566c80476e4SDavid E. O'Brien     DIR    *dirp;
567c80476e4SDavid E. O'Brien     struct dirent *dp;
5689ccc37e3SMark Peek     struct stat sbuf;
569c80476e4SDavid E. O'Brien     int     err;
570c80476e4SDavid E. O'Brien     Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
57145e5710bSMark Peek     size_t orig_len;
5729ccc37e3SMark Peek     int globstar = 0;
5739ccc37e3SMark Peek     int chase_symlinks = 0;
5749ccc37e3SMark Peek     const Char *termstar = NULL;
575c80476e4SDavid E. O'Brien 
57645e5710bSMark Peek     strbuf_terminate(pathbuf);
5779ccc37e3SMark Peek     orig_len = pathbuf->len;
5789ccc37e3SMark Peek     errno = err = 0;
5799ccc37e3SMark Peek 
5809ccc37e3SMark Peek     while (pglobstar < restpattern) {
5819ccc37e3SMark Peek 	__Char wc;
5829ccc37e3SMark Peek 	size_t width = One_Char_mbtowc(&wc, pglobstar, MB_LEN_MAX);
5839ccc37e3SMark Peek 	if ((pglobstar[0] & M_MASK) == M_ALL &&
5849ccc37e3SMark Peek 	    (pglobstar[width] & M_MASK) == M_ALL) {
5859ccc37e3SMark Peek 	    globstar = 1;
5869ccc37e3SMark Peek 	    chase_symlinks = (pglobstar[2 * width] & M_MASK) == M_ALL;
5879ccc37e3SMark Peek 	    termstar = pglobstar + (2 + chase_symlinks) * width;
5889ccc37e3SMark Peek 	    break;
5899ccc37e3SMark Peek 	}
5909ccc37e3SMark Peek         pglobstar += width;
5919ccc37e3SMark Peek     }
5929ccc37e3SMark Peek 
5939ccc37e3SMark Peek     if (globstar) {
5949ccc37e3SMark Peek 	err = pglobstar==pattern && termstar==restpattern ?
5959ccc37e3SMark Peek 		*restpattern == EOS ?
5969ccc37e3SMark Peek 		glob2(pathbuf, restpattern - 1, pglob, no_match) :
5979ccc37e3SMark Peek 		glob2(pathbuf, restpattern + 1, pglob, no_match) :
5989ccc37e3SMark Peek 		glob3(pathbuf, pattern, restpattern, termstar, pglob, no_match);
5999ccc37e3SMark Peek 	if (err)
6009ccc37e3SMark Peek 	    return err;
6019ccc37e3SMark Peek 	pathbuf->len = orig_len;
6029ccc37e3SMark Peek 	strbuf_terminate(pathbuf);
6039ccc37e3SMark Peek     }
6049ccc37e3SMark Peek 
6059ccc37e3SMark Peek     if (*pathbuf->s && (Lstat(pathbuf->s, &sbuf) || !S_ISDIR(sbuf.st_mode)
6069ccc37e3SMark Peek #ifdef S_IFLINK
6079ccc37e3SMark Peek 	     && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode))
6089ccc37e3SMark Peek #endif
6099ccc37e3SMark Peek 	))
6109ccc37e3SMark Peek 	return 0;
611c80476e4SDavid E. O'Brien 
61245e5710bSMark Peek     if (!(dirp = Opendir(pathbuf->s))) {
613c80476e4SDavid E. O'Brien 	/* todo: don't call for ENOENT or ENOTDIR? */
61445e5710bSMark Peek 	if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf->s, errno)) ||
615c80476e4SDavid E. O'Brien 	    (pglob->gl_flags & GLOB_ERR))
616c80476e4SDavid E. O'Brien 	    return (GLOB_ABEND);
617c80476e4SDavid E. O'Brien 	else
618c80476e4SDavid E. O'Brien 	    return (0);
619c80476e4SDavid E. O'Brien     }
620c80476e4SDavid E. O'Brien 
621c80476e4SDavid E. O'Brien     /* search directory for matching names */
622c80476e4SDavid E. O'Brien     while ((dp = readdir(dirp)) != NULL) {
623c80476e4SDavid E. O'Brien 	/* initial DOT must be matched literally */
624c80476e4SDavid E. O'Brien 	if (dp->d_name[0] == DOT && *pattern != DOT)
6259ccc37e3SMark Peek 	    if (!(pglob->gl_flags & GLOB_DOT) || !dp->d_name[1] ||
6269ccc37e3SMark Peek 		(dp->d_name[1] == DOT && !dp->d_name[2]))
6279ccc37e3SMark Peek 		continue; /*unless globdot and not . or .. */
62845e5710bSMark Peek 	pathbuf->len = orig_len;
62945e5710bSMark Peek 	strbuf_append(pathbuf, dp->d_name);
63045e5710bSMark Peek 	strbuf_terminate(pathbuf);
6319ccc37e3SMark Peek 
6329ccc37e3SMark Peek 	if (globstar) {
6339ccc37e3SMark Peek #ifdef S_IFLNK
6349ccc37e3SMark Peek 	    if (!chase_symlinks &&
6359ccc37e3SMark Peek 		(Lstat(pathbuf->s, &sbuf) || S_ISLNK(sbuf.st_mode)))
636c80476e4SDavid E. O'Brien 		    continue;
6379ccc37e3SMark Peek #endif
6389ccc37e3SMark Peek 	    if (match(pathbuf->s + orig_len, pattern, termstar,
6399ccc37e3SMark Peek 		(int)m_not) == no_match)
6409ccc37e3SMark Peek 		    continue;
6419ccc37e3SMark Peek 	    strbuf_append1(pathbuf, SEP);
6429ccc37e3SMark Peek 	    strbuf_terminate(pathbuf);
6439ccc37e3SMark Peek 	    if ((err = glob2(pathbuf, pglobstar, pglob, no_match)) != 0)
644c80476e4SDavid E. O'Brien 		break;
6459ccc37e3SMark Peek 	} else {
6469ccc37e3SMark Peek 	    if (match(pathbuf->s + orig_len, pattern, restpattern,
6479ccc37e3SMark Peek 		(int) m_not) == no_match)
6489ccc37e3SMark Peek 		continue;
6499ccc37e3SMark Peek 	    if ((err = glob2(pathbuf, restpattern, pglob, no_match)) != 0)
6509ccc37e3SMark Peek 		break;
6519ccc37e3SMark Peek 	}
652c80476e4SDavid E. O'Brien     }
653c80476e4SDavid E. O'Brien     /* todo: check error from readdir? */
65445e5710bSMark Peek     closedir(dirp);
655c80476e4SDavid E. O'Brien     return (err);
656c80476e4SDavid E. O'Brien }
657c80476e4SDavid E. O'Brien 
658c80476e4SDavid E. O'Brien 
659c80476e4SDavid E. O'Brien /*
660c80476e4SDavid E. O'Brien  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
661c80476e4SDavid E. O'Brien  * add the new item, and update gl_pathc.
662c80476e4SDavid E. O'Brien  *
663c80476e4SDavid E. O'Brien  * This assumes the BSD realloc, which only copies the block when its size
664c80476e4SDavid E. O'Brien  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
665c80476e4SDavid E. O'Brien  * behavior.
666c80476e4SDavid E. O'Brien  *
667c80476e4SDavid E. O'Brien  * Return 0 if new item added, error code if memory couldn't be allocated.
668c80476e4SDavid E. O'Brien  *
669c80476e4SDavid E. O'Brien  * Invariant of the glob_t structure:
670c80476e4SDavid E. O'Brien  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
671c80476e4SDavid E. O'Brien  *	 gl_pathv points to (gl_offs + gl_pathc + 1) items.
672c80476e4SDavid E. O'Brien  */
67345e5710bSMark Peek static void
67445e5710bSMark Peek globextend(const char *path, glob_t *pglob)
675c80476e4SDavid E. O'Brien {
67623338178SMark Peek     char **pathv;
67723338178SMark Peek     int i;
67845e5710bSMark Peek     size_t newsize;
679c80476e4SDavid E. O'Brien 
680c80476e4SDavid E. O'Brien     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
68145e5710bSMark Peek     pathv = xrealloc(pglob->gl_pathv, newsize);
682c80476e4SDavid E. O'Brien 
683c80476e4SDavid E. O'Brien     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
684c80476e4SDavid E. O'Brien 	/* first time around -- clear initial gl_offs items */
685c80476e4SDavid E. O'Brien 	pathv += pglob->gl_offs;
686c80476e4SDavid E. O'Brien 	for (i = pglob->gl_offs; --i >= 0;)
687c80476e4SDavid E. O'Brien 	    *--pathv = NULL;
688c80476e4SDavid E. O'Brien     }
689c80476e4SDavid E. O'Brien     pglob->gl_pathv = pathv;
690c80476e4SDavid E. O'Brien 
69145e5710bSMark Peek     pathv[pglob->gl_offs + pglob->gl_pathc++] = strsave(path);
692c80476e4SDavid E. O'Brien     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
693c80476e4SDavid E. O'Brien }
694c80476e4SDavid E. O'Brien 
695c80476e4SDavid E. O'Brien /*
696c80476e4SDavid E. O'Brien  * pattern matching function for filenames.  Each occurrence of the *
697c80476e4SDavid E. O'Brien  * pattern causes a recursion level.
698c80476e4SDavid E. O'Brien  */
699c80476e4SDavid E. O'Brien static  int
70045e5710bSMark Peek match(const char *name, const Char *pat, const Char *patend, int m_not)
701c80476e4SDavid E. O'Brien {
702c80476e4SDavid E. O'Brien     int ok, negate_range;
70345e5710bSMark Peek     Char c;
704c80476e4SDavid E. O'Brien 
705c80476e4SDavid E. O'Brien     while (pat < patend) {
70623338178SMark Peek 	size_t lwk;
70745e5710bSMark Peek 	__Char wc, wk;
70823338178SMark Peek 
70923338178SMark Peek 	c = *pat; /* Only for M_MASK bits */
71045e5710bSMark Peek 	pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX);
71145e5710bSMark Peek 	lwk = one_mbtowc(&wk, name, MB_LEN_MAX);
712c80476e4SDavid E. O'Brien 	switch (c & M_MASK) {
713c80476e4SDavid E. O'Brien 	case M_ALL:
7149ccc37e3SMark Peek 	    while (pat < patend && (*pat & M_MASK) == M_ALL)  /* eat consecutive '*' */
7159ccc37e3SMark Peek 		pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX);
716c80476e4SDavid E. O'Brien 	    if (pat == patend)
717c80476e4SDavid E. O'Brien 	        return (1);
7189ccc37e3SMark Peek 	    while (!match(name, pat, patend, m_not)) {
71923338178SMark Peek 		if (*name == EOS)
7209ccc37e3SMark Peek 		    return (0);
72123338178SMark Peek 		name += lwk;
72245e5710bSMark Peek 		lwk = one_mbtowc(&wk, name, MB_LEN_MAX);
72323338178SMark Peek 	    }
7249ccc37e3SMark Peek 	    return (1);
725c80476e4SDavid E. O'Brien 	case M_ONE:
72623338178SMark Peek 	    if (*name == EOS)
727c80476e4SDavid E. O'Brien 		return (0);
72823338178SMark Peek 	    name += lwk;
729c80476e4SDavid E. O'Brien 	    break;
730c80476e4SDavid E. O'Brien 	case M_SET:
731c80476e4SDavid E. O'Brien 	    ok = 0;
73223338178SMark Peek 	    if (*name == EOS)
733c80476e4SDavid E. O'Brien 		return (0);
73423338178SMark Peek 	    name += lwk;
735c80476e4SDavid E. O'Brien 	    if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
736c80476e4SDavid E. O'Brien 		++pat;
73723338178SMark Peek 	    while ((*pat & M_MASK) != M_END) {
73845e5710bSMark Peek 		pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX);
739c80476e4SDavid E. O'Brien 		if ((*pat & M_MASK) == M_RNG) {
74045e5710bSMark Peek 		    __Char wc2;
74123338178SMark Peek 
74223338178SMark Peek 		    pat++;
74345e5710bSMark Peek 		    pat += One_Char_mbtowc(&wc2, pat, MB_LEN_MAX);
74423338178SMark Peek 		    if (globcharcoll(wc, wk, 0) <= 0 &&
74523338178SMark Peek 			globcharcoll(wk, wc2, 0) <= 0)
746c80476e4SDavid E. O'Brien 			ok = 1;
74723338178SMark Peek 		} else if (wc == wk)
748c80476e4SDavid E. O'Brien 		    ok = 1;
749c80476e4SDavid E. O'Brien 	    }
75045e5710bSMark Peek 	    pat += One_Char_mbtowc(&wc, pat, MB_LEN_MAX);
751c80476e4SDavid E. O'Brien 	    if (ok == negate_range)
752c80476e4SDavid E. O'Brien 		return (0);
753c80476e4SDavid E. O'Brien 	    break;
754c80476e4SDavid E. O'Brien 	default:
7559ccc37e3SMark Peek 	    if (*name == EOS || samecase(wk) != samecase(wc))
756c80476e4SDavid E. O'Brien 		return (0);
7579ccc37e3SMark Peek 	    name += lwk;
758c80476e4SDavid E. O'Brien 	    break;
759c80476e4SDavid E. O'Brien 	}
760c80476e4SDavid E. O'Brien     }
761c80476e4SDavid E. O'Brien     return (*name == EOS);
762c80476e4SDavid E. O'Brien }
763c80476e4SDavid E. O'Brien 
764c80476e4SDavid E. O'Brien /* free allocated data belonging to a glob_t structure */
765c80476e4SDavid E. O'Brien void
76645e5710bSMark Peek globfree(glob_t *pglob)
767c80476e4SDavid E. O'Brien {
76823338178SMark Peek     int i;
76923338178SMark Peek     char **pp;
770c80476e4SDavid E. O'Brien 
771c80476e4SDavid E. O'Brien     if (pglob->gl_pathv != NULL) {
772c80476e4SDavid E. O'Brien 	pp = pglob->gl_pathv + pglob->gl_offs;
773c80476e4SDavid E. O'Brien 	for (i = pglob->gl_pathc; i--; ++pp)
774c80476e4SDavid E. O'Brien 	    if (*pp)
77545e5710bSMark Peek 		xfree(*pp), *pp = NULL;
77645e5710bSMark Peek 	xfree(pglob->gl_pathv), pglob->gl_pathv = NULL;
777c80476e4SDavid E. O'Brien     }
778c80476e4SDavid E. O'Brien }
779