xref: /titanic_51/usr/src/lib/libc/port/regex/glob.c (revision 33e8313d921ed710d7c5957cea98e220a663a1d5)
17c478bd9Sstevel@tonic-gate /*
2a5229c74SGary Mills  * Copyright (c) 2013 Gary Mills
3a5229c74SGary Mills  */
4a5229c74SGary Mills /*	$OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
5a5229c74SGary Mills /*
6a5229c74SGary Mills  * Copyright (c) 1989, 1993
7a5229c74SGary Mills  *	The Regents of the University of California.  All rights reserved.
87c478bd9Sstevel@tonic-gate  *
9a5229c74SGary Mills  * This code is derived from software contributed to Berkeley by
10a5229c74SGary Mills  * Guido van Rossum.
117c478bd9Sstevel@tonic-gate  *
12a5229c74SGary Mills  * Redistribution and use in source and binary forms, with or without
13a5229c74SGary Mills  * modification, are permitted provided that the following conditions
14a5229c74SGary Mills  * are met:
15a5229c74SGary Mills  * 1. Redistributions of source code must retain the above copyright
16a5229c74SGary Mills  *    notice, this list of conditions and the following disclaimer.
17a5229c74SGary Mills  * 2. Redistributions in binary form must reproduce the above copyright
18a5229c74SGary Mills  *    notice, this list of conditions and the following disclaimer in the
19a5229c74SGary Mills  *    documentation and/or other materials provided with the distribution.
20a5229c74SGary Mills  * 3. Neither the name of the University nor the names of its contributors
21a5229c74SGary Mills  *    may be used to endorse or promote products derived from this software
22a5229c74SGary Mills  *    without specific prior written permission.
237c478bd9Sstevel@tonic-gate  *
24a5229c74SGary Mills  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25a5229c74SGary Mills  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26a5229c74SGary Mills  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27a5229c74SGary Mills  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28a5229c74SGary Mills  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29a5229c74SGary Mills  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30a5229c74SGary Mills  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31a5229c74SGary Mills  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32a5229c74SGary Mills  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33a5229c74SGary Mills  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34a5229c74SGary Mills  * SUCH DAMAGE.
357c478bd9Sstevel@tonic-gate  */
36e8031f0aSraf 
377c478bd9Sstevel@tonic-gate /*
38a5229c74SGary Mills  * glob(3) -- a superset of the one defined in POSIX 1003.2.
39a5229c74SGary Mills  *
40a5229c74SGary Mills  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
41a5229c74SGary Mills  *
42a5229c74SGary Mills  * Optional extra services, controlled by flags not defined by POSIX:
43a5229c74SGary Mills  *
44a5229c74SGary Mills  * GLOB_QUOTE:
45a5229c74SGary Mills  *	Escaping convention: \ inhibits any special meaning the following
46a5229c74SGary Mills  *	character might have (except \ at end of string is retained).
47a5229c74SGary Mills  * GLOB_MAGCHAR:
48a5229c74SGary Mills  *	Set in gl_flags if pattern contained a globbing character.
49a5229c74SGary Mills  * GLOB_NOMAGIC:
50a5229c74SGary Mills  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
51a5229c74SGary Mills  *	not contain any magic characters.  [Used in csh style globbing]
52a5229c74SGary Mills  * GLOB_ALTDIRFUNC:
53a5229c74SGary Mills  *	Use alternately specified directory access functions.
54a5229c74SGary Mills  * GLOB_TILDE:
55a5229c74SGary Mills  *	expand ~user/foo to the /home/dir/of/user/foo
56a5229c74SGary Mills  * GLOB_BRACE:
57a5229c74SGary Mills  *	expand {1,2}{a,b} to 1a 1b 2a 2b
58a5229c74SGary Mills  * gl_matchc:
59a5229c74SGary Mills  *	Number of matches in the current invocation of glob.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627257d1b4Sraf #include "lint.h"
63a5229c74SGary Mills 
64a5229c74SGary Mills #include <sys/param.h>
65a5229c74SGary Mills #include <sys/stat.h>
66a5229c74SGary Mills 
67a5229c74SGary Mills #include <ctype.h>
68a5229c74SGary Mills #include <dirent.h>
69a5229c74SGary Mills #include <errno.h>
70a5229c74SGary Mills #include <glob.h>
717c478bd9Sstevel@tonic-gate #include <limits.h>
72a5229c74SGary Mills #include <pwd.h>
73a5229c74SGary Mills #include <stdio.h>
747c478bd9Sstevel@tonic-gate #include <stdlib.h>
757c478bd9Sstevel@tonic-gate #include <string.h>
76a5229c74SGary Mills #include <unistd.h>
77a5229c74SGary Mills #include <wchar.h>
78a5229c74SGary Mills #include <wctype.h>
797c478bd9Sstevel@tonic-gate 
80a5229c74SGary Mills /*
81a5229c74SGary Mills  * This is the legacy glob_t prior to illumos enhancement 1097,
82a5229c74SGary Mills  * used when old programs call the old libc glob functions.
83a5229c74SGary Mills  * (New programs call the _glob_ext, _globfree_ext functions.)
84a5229c74SGary Mills  * This struct should be considered "carved in stone".
85a5229c74SGary Mills  */
86a5229c74SGary Mills typedef	struct	old_glob	{
87a5229c74SGary Mills 	size_t	gl_pathc;		/* Count of paths matched by pattern */
88a5229c74SGary Mills 	char	**gl_pathv;		/* List of matched pathnames */
89a5229c74SGary Mills 	size_t	gl_offs;		/* # of slots reserved in gl_pathv */
90a5229c74SGary Mills 	/* following are internal to the implementation */
91a5229c74SGary Mills 	char	**gl_pathp;		/* gl_pathv + gl_offs */
92a5229c74SGary Mills 	int	gl_pathn;		/* # of elements allocated */
93a5229c74SGary Mills }	old_glob_t;
94a5229c74SGary Mills 
95a5229c74SGary Mills /*
96a5229c74SGary Mills  * For old programs, the external names need to be the old names:
97a5229c74SGary Mills  * glob() and globfree() .  We've redefined those already to
98a5229c74SGary Mills  *  _glob_ext() and _globfree_ext() .  Now redefine old_glob()
99a5229c74SGary Mills  * and old_globfree() to glob() and globfree() .
100a5229c74SGary Mills  */
101a5229c74SGary Mills #ifdef __PRAGMA_REDEFINE_EXTNAME
102a5229c74SGary Mills #pragma	redefine_extname	old_glob	glob
103a5229c74SGary Mills #pragma	redefine_extname	old_globfree	globfree
104a5229c74SGary Mills #endif /* __PRAGMA_REDEFINE_EXTNAME */
105a5229c74SGary Mills extern int old_glob(const char *, int, int (*)(const char *, int),
106a5229c74SGary Mills     old_glob_t *);
107a5229c74SGary Mills extern void old_globfree(old_glob_t *);
108a5229c74SGary Mills 
109*33e8313dSRobert Mustacchi /*
110*33e8313dSRobert Mustacchi  * The various extensions to glob(3C) allow for stat and dirent structures to
111*33e8313dSRobert Mustacchi  * show up whose size may change in a largefile environment. If libc defines
112*33e8313dSRobert Mustacchi  * _FILE_OFFSET_BITS to be 64 that is the key to indicate that we're building
113*33e8313dSRobert Mustacchi  * the LFS version of this file. As such, we rename the public functions here,
114*33e8313dSRobert Mustacchi  * _glob_ext() and _globfree_ext() to have a 64 suffix. When building the LFS
115*33e8313dSRobert Mustacchi  * version, we do not include the old versions.
116*33e8313dSRobert Mustacchi  */
117*33e8313dSRobert Mustacchi #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
118*33e8313dSRobert Mustacchi #define	_glob_ext	_glob_ext64
119*33e8313dSRobert Mustacchi #define	_globfree_ext	_globfree_ext64
120*33e8313dSRobert Mustacchi #endif	/* !_LP64 && _FILE_OFFSET_BITS == 64 */
121*33e8313dSRobert Mustacchi 
122a5229c74SGary Mills #define	DOLLAR		'$'
123a5229c74SGary Mills #define	DOT		'.'
124a5229c74SGary Mills #define	EOS		'\0'
125a5229c74SGary Mills #define	LBRACKET	'['
126a5229c74SGary Mills #define	NOT		'!'
127a5229c74SGary Mills #define	QUESTION	'?'
128a5229c74SGary Mills #define	QUOTE		'\\'
129a5229c74SGary Mills #define	RANGE		'-'
130a5229c74SGary Mills #define	RBRACKET	']'
131a5229c74SGary Mills #define	SEP		'/'
132a5229c74SGary Mills #define	STAR		'*'
133a5229c74SGary Mills #define	TILDE		'~'
134a5229c74SGary Mills #define	UNDERSCORE	'_'
135a5229c74SGary Mills #define	LBRACE		'{'
136a5229c74SGary Mills #define	RBRACE		'}'
137a5229c74SGary Mills #define	SLASH		'/'
138a5229c74SGary Mills #define	COMMA		','
139a5229c74SGary Mills #define	COLON		':'
140a5229c74SGary Mills 
141a5229c74SGary Mills #define	M_QUOTE		0x800000
142a5229c74SGary Mills #define	M_PROTECT	0x400000
143a5229c74SGary Mills 
144a5229c74SGary Mills typedef struct wcat {
145a5229c74SGary Mills 	wchar_t w_wc;
146a5229c74SGary Mills 	uint_t w_at;
147a5229c74SGary Mills } wcat_t;
148a5229c74SGary Mills 
149a5229c74SGary Mills #define	M_ALL		'*'	/* Plus M_QUOTE */
150a5229c74SGary Mills #define	M_END		']'	/* Plus M_QUOTE */
151a5229c74SGary Mills #define	M_NOT		'!'	/* Plus M_QUOTE */
152a5229c74SGary Mills #define	M_ONE		'?'	/* Plus M_QUOTE */
153a5229c74SGary Mills #define	M_RNG		'-'	/* Plus M_QUOTE */
154a5229c74SGary Mills #define	M_SET		'['	/* Plus M_QUOTE */
155a5229c74SGary Mills #define	M_CLASS		':'	/* Plus M_QUOTE */
156a5229c74SGary Mills #define	ismeta(c)	(((c).w_at&M_QUOTE) != 0)
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate #define	INITIAL			8	/* initial pathv allocation */
1597c478bd9Sstevel@tonic-gate 
160a5229c74SGary Mills #define	GLOB_LIMIT_MALLOC	65536
161a5229c74SGary Mills #define	GLOB_LIMIT_STAT		2048
162a5229c74SGary Mills #define	GLOB_LIMIT_READDIR	16384
163a5229c74SGary Mills 
164a5229c74SGary Mills /* Limit of recursion during matching attempts. */
165a5229c74SGary Mills #define	GLOB_LIMIT_RECUR	64
166a5229c74SGary Mills 
167a5229c74SGary Mills struct glob_lim {
168a5229c74SGary Mills 	size_t	glim_malloc;
169a5229c74SGary Mills 	size_t	glim_stat;
170a5229c74SGary Mills 	size_t	glim_readdir;
171a5229c74SGary Mills };
172a5229c74SGary Mills 
173a5229c74SGary Mills struct glob_path_stat {
174a5229c74SGary Mills 	char		*gps_path;
175a5229c74SGary Mills 	struct stat	*gps_stat;
176a5229c74SGary Mills };
177a5229c74SGary Mills 
178a5229c74SGary Mills static int	 compare(const void *, const void *);
179a5229c74SGary Mills static int	 compare_gps(const void *, const void *);
180a5229c74SGary Mills static int	 g_Ctoc(const wcat_t *, char *, uint_t);
181a5229c74SGary Mills static int	 g_lstat(wcat_t *, struct stat *, glob_t *);
182a5229c74SGary Mills static DIR	*g_opendir(wcat_t *, glob_t *);
183a5229c74SGary Mills static wcat_t	*g_strchr(const wcat_t *, wchar_t);
184a5229c74SGary Mills static int	 g_stat(wcat_t *, struct stat *, glob_t *);
185a5229c74SGary Mills static int	 glob0(const wcat_t *, glob_t *, struct glob_lim *,
186a5229c74SGary Mills 			int (*)(const char *, int));
187a5229c74SGary Mills static int	 glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
188a5229c74SGary Mills 			int (*)(const char *, int));
189a5229c74SGary Mills static int	 glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
190a5229c74SGary Mills 			wcat_t *, glob_t *, struct glob_lim *,
191a5229c74SGary Mills 			int (*)(const char *, int));
192a5229c74SGary Mills static int	 glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
193a5229c74SGary Mills 			wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
194a5229c74SGary Mills 			int (*)(const char *, int));
195a5229c74SGary Mills static int	 globextend(const wcat_t *, glob_t *, struct glob_lim *,
196a5229c74SGary Mills 		    struct stat *);
197a5229c74SGary Mills static
198a5229c74SGary Mills const wcat_t	*globtilde(const wcat_t *, wcat_t *, size_t, glob_t *);
199a5229c74SGary Mills static int	 globexp1(const wcat_t *, glob_t *, struct glob_lim *,
200a5229c74SGary Mills 		    int (*)(const char *, int));
201a5229c74SGary Mills static int	 globexp2(const wcat_t *, const wcat_t *, glob_t *,
202a5229c74SGary Mills 		    struct glob_lim *, int (*)(const char *, int));
203a5229c74SGary Mills static int	 match(wcat_t *, wcat_t *, wcat_t *, int);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
206a5229c74SGary Mills  * Extended glob() function, selected by #pragma redefine_extname
207a5229c74SGary Mills  * in glob.h with the external name _glob_ext() .
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate int
210a5229c74SGary Mills _glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int),
211a5229c74SGary Mills     glob_t *pglob)
2127c478bd9Sstevel@tonic-gate {
213a5229c74SGary Mills 	const char *patnext;
214a5229c74SGary Mills 	int n;
215a5229c74SGary Mills 	size_t patlen;
216a5229c74SGary Mills 	wchar_t c;
217a5229c74SGary Mills 	wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN];
218a5229c74SGary Mills 	struct glob_lim limit = { 0, 0, 0 };
2197c478bd9Sstevel@tonic-gate 
220a5229c74SGary Mills 	if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
221a5229c74SGary Mills 		return (GLOB_NOMATCH);
2227c478bd9Sstevel@tonic-gate 
223a5229c74SGary Mills 	patnext = pattern;
2247c478bd9Sstevel@tonic-gate 	if (!(flags & GLOB_APPEND)) {
225a5229c74SGary Mills 		pglob->gl_pathc = 0;
226a5229c74SGary Mills 		pglob->gl_pathn = 0;
227a5229c74SGary Mills 		pglob->gl_pathv = NULL;
228a5229c74SGary Mills 		if ((flags & GLOB_KEEPSTAT) != 0)
229a5229c74SGary Mills 			pglob->gl_statv = NULL;
230a5229c74SGary Mills 		if (!(flags & GLOB_DOOFFS))
231a5229c74SGary Mills 			pglob->gl_offs = 0;
232a5229c74SGary Mills 	}
233a5229c74SGary Mills 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
234a5229c74SGary Mills 	pglob->gl_matchc = 0;
2357c478bd9Sstevel@tonic-gate 
236a5229c74SGary Mills 	if (pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
237a5229c74SGary Mills 	    pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
2387c478bd9Sstevel@tonic-gate 		return (GLOB_NOSPACE);
2397c478bd9Sstevel@tonic-gate 
240a5229c74SGary Mills 	bufnext = patbuf;
241a5229c74SGary Mills 	bufend = bufnext + MAXPATHLEN - 1;
242a5229c74SGary Mills 	patlen += 1;
243a5229c74SGary Mills 	if (flags & GLOB_NOESCAPE) {
244a5229c74SGary Mills 		while (bufnext < bufend) {
245a5229c74SGary Mills 			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
246a5229c74SGary Mills 				patnext += n;
247a5229c74SGary Mills 				patlen -= n;
248a5229c74SGary Mills 				bufnext->w_at = 0;
249a5229c74SGary Mills 				(bufnext++)->w_wc = c;
250a5229c74SGary Mills 			} else if (n == 0) {
251a5229c74SGary Mills 				break;
252a5229c74SGary Mills 			} else {
253a5229c74SGary Mills 				return (GLOB_NOMATCH);
254a5229c74SGary Mills 			}
255a5229c74SGary Mills 		}
256a5229c74SGary Mills 	} else {
257a5229c74SGary Mills 		/* Protect the quoted characters. */
258a5229c74SGary Mills 		while (bufnext < bufend) {
259a5229c74SGary Mills 			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
260a5229c74SGary Mills 				patnext += n;
261a5229c74SGary Mills 				patlen -= n;
262a5229c74SGary Mills 				if (c == QUOTE) {
263a5229c74SGary Mills 					n = mbtowc(&c, patnext, patlen);
264a5229c74SGary Mills 					if (n < 0)
265a5229c74SGary Mills 						return (GLOB_NOMATCH);
266a5229c74SGary Mills 					if (n > 0) {
267a5229c74SGary Mills 						patnext += n;
268a5229c74SGary Mills 						patlen -= n;
269a5229c74SGary Mills 					}
270a5229c74SGary Mills 					if (n == 0)
271a5229c74SGary Mills 						c = QUOTE;
272a5229c74SGary Mills 					bufnext->w_at = M_PROTECT;
273a5229c74SGary Mills 					(bufnext++)->w_wc = c;
274a5229c74SGary Mills 				} else {
275a5229c74SGary Mills 					bufnext->w_at = 0;
276a5229c74SGary Mills 					(bufnext++)->w_wc = c;
277a5229c74SGary Mills 				}
278a5229c74SGary Mills 			} else if (n == 0) {
279a5229c74SGary Mills 				break;
280a5229c74SGary Mills 			} else {
281a5229c74SGary Mills 				return (GLOB_NOMATCH);
282a5229c74SGary Mills 			}
283a5229c74SGary Mills 		}
284a5229c74SGary Mills 	}
285a5229c74SGary Mills 	bufnext->w_at = 0;
286a5229c74SGary Mills 	bufnext->w_wc = EOS;
287a5229c74SGary Mills 
288a5229c74SGary Mills 	if (flags & GLOB_BRACE)
289a5229c74SGary Mills 		return (globexp1(patbuf, pglob, &limit, errfunc));
290a5229c74SGary Mills 	else
291a5229c74SGary Mills 		return (glob0(patbuf, pglob, &limit, errfunc));
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate /*
295a5229c74SGary Mills  * Expand recursively a glob {} pattern. When there is no more expansion
296a5229c74SGary Mills  * invoke the standard globbing routine to glob the rest of the magic
297a5229c74SGary Mills  * characters
2987c478bd9Sstevel@tonic-gate  */
299a5229c74SGary Mills static int
300a5229c74SGary Mills globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
301a5229c74SGary Mills     int (*errfunc)(const char *, int))
302a5229c74SGary Mills {
303a5229c74SGary Mills 	const wcat_t *ptr = pattern;
304a5229c74SGary Mills 
305a5229c74SGary Mills 	/* Protect a single {}, for find(1), like csh */
306a5229c74SGary Mills 	if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE &&
307a5229c74SGary Mills 	    pattern[2].w_wc == EOS)
308a5229c74SGary Mills 		return (glob0(pattern, pglob, limitp, errfunc));
309a5229c74SGary Mills 
310a5229c74SGary Mills 	if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
311a5229c74SGary Mills 		return (globexp2(ptr, pattern, pglob, limitp, errfunc));
312a5229c74SGary Mills 
313a5229c74SGary Mills 	return (glob0(pattern, pglob, limitp, errfunc));
314a5229c74SGary Mills }
315a5229c74SGary Mills 
316a5229c74SGary Mills 
317a5229c74SGary Mills /*
318a5229c74SGary Mills  * Recursive brace globbing helper. Tries to expand a single brace.
319a5229c74SGary Mills  * If it succeeds then it invokes globexp1 with the new pattern.
320a5229c74SGary Mills  * If it fails then it tries to glob the rest of the pattern and returns.
321a5229c74SGary Mills  */
322a5229c74SGary Mills static int
323a5229c74SGary Mills globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
324a5229c74SGary Mills     struct glob_lim *limitp, int (*errfunc)(const char *, int))
325a5229c74SGary Mills {
326a5229c74SGary Mills 	int	i, rv;
327a5229c74SGary Mills 	wcat_t   *lm, *ls;
328a5229c74SGary Mills 	const wcat_t *pe, *pm, *pl;
329a5229c74SGary Mills 	wcat_t    patbuf[MAXPATHLEN];
330a5229c74SGary Mills 
331a5229c74SGary Mills 	/* copy part up to the brace */
332a5229c74SGary Mills 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
333a5229c74SGary Mills 		;
334a5229c74SGary Mills 	lm->w_at = 0;
335a5229c74SGary Mills 	lm->w_wc = EOS;
336a5229c74SGary Mills 	ls = lm;
337a5229c74SGary Mills 
338a5229c74SGary Mills 	/* Find the balanced brace */
339a5229c74SGary Mills 	for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++)
340a5229c74SGary Mills 		if (pe->w_wc == LBRACKET) {
341a5229c74SGary Mills 			/* Ignore everything between [] */
342a5229c74SGary Mills 			for (pm = pe++; pe->w_wc != RBRACKET &&
343a5229c74SGary Mills 			    pe->w_wc != EOS; pe++)
344a5229c74SGary Mills 				;
345a5229c74SGary Mills 			if (pe->w_wc == EOS) {
346a5229c74SGary Mills 				/*
347a5229c74SGary Mills 				 * We could not find a matching RBRACKET.
348a5229c74SGary Mills 				 * Ignore and just look for RBRACE
349a5229c74SGary Mills 				 */
350a5229c74SGary Mills 				pe = pm;
351a5229c74SGary Mills 			}
352a5229c74SGary Mills 		} else if (pe->w_wc == LBRACE) {
353a5229c74SGary Mills 			i++;
354a5229c74SGary Mills 		} else if (pe->w_wc == RBRACE) {
355a5229c74SGary Mills 			if (i == 0)
356a5229c74SGary Mills 				break;
357a5229c74SGary Mills 			i--;
358a5229c74SGary Mills 		}
359a5229c74SGary Mills 
360a5229c74SGary Mills 	/* Non matching braces; just glob the pattern */
361a5229c74SGary Mills 	if (i != 0 || pe->w_wc == EOS)
362a5229c74SGary Mills 		return (glob0(patbuf, pglob, limitp, errfunc));
363a5229c74SGary Mills 
364a5229c74SGary Mills 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
365a5229c74SGary Mills 		switch (pm->w_wc) {
366a5229c74SGary Mills 		case LBRACKET:
367a5229c74SGary Mills 			/* Ignore everything between [] */
368a5229c74SGary Mills 			for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
369a5229c74SGary Mills 			    pm++)
370a5229c74SGary Mills 				;
371a5229c74SGary Mills 			if (pm->w_wc == EOS) {
372a5229c74SGary Mills 				/*
373a5229c74SGary Mills 				 * We could not find a matching RBRACKET.
374a5229c74SGary Mills 				 * Ignore and just look for RBRACE
375a5229c74SGary Mills 				 */
376a5229c74SGary Mills 				pm = pl;
377a5229c74SGary Mills 			}
378a5229c74SGary Mills 			break;
379a5229c74SGary Mills 
380a5229c74SGary Mills 		case LBRACE:
381a5229c74SGary Mills 			i++;
382a5229c74SGary Mills 			break;
383a5229c74SGary Mills 
384a5229c74SGary Mills 		case RBRACE:
385a5229c74SGary Mills 			if (i) {
386a5229c74SGary Mills 				i--;
387a5229c74SGary Mills 				break;
388a5229c74SGary Mills 			}
389a5229c74SGary Mills 			/* FALLTHROUGH */
390a5229c74SGary Mills 		case COMMA:
391a5229c74SGary Mills 			if (i && pm->w_wc == COMMA)
392a5229c74SGary Mills 				break;
393a5229c74SGary Mills 			else {
394a5229c74SGary Mills 				/* Append the current string */
395a5229c74SGary Mills 				for (lm = ls; (pl < pm); *lm++ = *pl++)
396a5229c74SGary Mills 					;
397a5229c74SGary Mills 
398a5229c74SGary Mills 				/*
399a5229c74SGary Mills 				 * Append the rest of the pattern after the
400a5229c74SGary Mills 				 * closing brace
401a5229c74SGary Mills 				 */
402a5229c74SGary Mills 				for (pl = pe + 1;
403a5229c74SGary Mills 				    (*lm++ = *pl++).w_wc != EOS; /* */)
404a5229c74SGary Mills 					;
405a5229c74SGary Mills 
406a5229c74SGary Mills 				/* Expand the current pattern */
407a5229c74SGary Mills 				rv = globexp1(patbuf, pglob, limitp, errfunc);
408a5229c74SGary Mills 				if (rv && rv != GLOB_NOMATCH)
409a5229c74SGary Mills 					return (rv);
410a5229c74SGary Mills 
411a5229c74SGary Mills 				/* move after the comma, to the next string */
412a5229c74SGary Mills 				pl = pm + 1;
413a5229c74SGary Mills 			}
414a5229c74SGary Mills 			break;
415a5229c74SGary Mills 
416a5229c74SGary Mills 		default:
417a5229c74SGary Mills 			break;
418a5229c74SGary Mills 		}
419a5229c74SGary Mills 	}
420a5229c74SGary Mills 	return (0);
421a5229c74SGary Mills }
422a5229c74SGary Mills 
423a5229c74SGary Mills 
424a5229c74SGary Mills 
425a5229c74SGary Mills /*
426a5229c74SGary Mills  * expand tilde from the passwd file.
427a5229c74SGary Mills  */
428a5229c74SGary Mills static const wcat_t *
429a5229c74SGary Mills globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
430a5229c74SGary Mills     glob_t *pglob)
431a5229c74SGary Mills {
432a5229c74SGary Mills 	struct passwd *pwd;
433a5229c74SGary Mills 	char *h;
434a5229c74SGary Mills 	const wcat_t *p;
435a5229c74SGary Mills 	wcat_t *b, *eb, *q;
436a5229c74SGary Mills 	int n;
437a5229c74SGary Mills 	size_t lenh;
438a5229c74SGary Mills 	wchar_t c;
439a5229c74SGary Mills 
440a5229c74SGary Mills 	if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
441a5229c74SGary Mills 		return (pattern);
442a5229c74SGary Mills 
443a5229c74SGary Mills 	/* Copy up to the end of the string or / */
444a5229c74SGary Mills 	eb = &patbuf[patbuf_len - 1];
445a5229c74SGary Mills 	for (p = pattern + 1, q = patbuf;
446a5229c74SGary Mills 	    q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++)
447a5229c74SGary Mills 		;
448a5229c74SGary Mills 
449a5229c74SGary Mills 	q->w_at = 0;
450a5229c74SGary Mills 	q->w_wc = EOS;
451a5229c74SGary Mills 
452a5229c74SGary Mills 	/* What to do if patbuf is full? */
453a5229c74SGary Mills 
454a5229c74SGary Mills 	if (patbuf[0].w_wc == EOS) {
455a5229c74SGary Mills 		/*
456a5229c74SGary Mills 		 * handle a plain ~ or ~/ by expanding $HOME
457a5229c74SGary Mills 		 * first and then trying the password file
458a5229c74SGary Mills 		 */
459a5229c74SGary Mills 		if (issetugid() != 0)
460a5229c74SGary Mills 			return (pattern);
461a5229c74SGary Mills 		if ((h = getenv("HOME")) == NULL) {
462a5229c74SGary Mills 			if ((pwd = getpwuid(getuid())) == NULL)
463a5229c74SGary Mills 				return (pattern);
464a5229c74SGary Mills 			else
465a5229c74SGary Mills 				h = pwd->pw_dir;
466a5229c74SGary Mills 		}
467a5229c74SGary Mills 	} else {
468a5229c74SGary Mills 		/*
469a5229c74SGary Mills 		 * Expand a ~user
470a5229c74SGary Mills 		 */
471a5229c74SGary Mills 		if ((pwd = getpwnam((char *)patbuf)) == NULL)
472a5229c74SGary Mills 			return (pattern);
473a5229c74SGary Mills 		else
474a5229c74SGary Mills 			h = pwd->pw_dir;
475a5229c74SGary Mills 	}
476a5229c74SGary Mills 
477a5229c74SGary Mills 	/* Copy the home directory */
478a5229c74SGary Mills 	lenh = strlen(h) + 1;
479a5229c74SGary Mills 	for (b = patbuf; b < eb && *h != EOS; b++) {
480a5229c74SGary Mills 		if ((n = mbtowc(&c, h, lenh)) > 0) {
481a5229c74SGary Mills 			h += n;
482a5229c74SGary Mills 			lenh -= n;
483a5229c74SGary Mills 			b->w_at = 0;
484a5229c74SGary Mills 			b->w_wc = c;
485a5229c74SGary Mills 		} else if (n < 0) {
486a5229c74SGary Mills 			return (pattern);
487a5229c74SGary Mills 		} else {
488a5229c74SGary Mills 			break;
489a5229c74SGary Mills 		}
490a5229c74SGary Mills 	}
491a5229c74SGary Mills 
492a5229c74SGary Mills 	/* Append the rest of the pattern */
493a5229c74SGary Mills 	while (b < eb && (*b++ = *p++).w_wc != EOS)
494a5229c74SGary Mills 		;
495a5229c74SGary Mills 	b->w_at = 0;
496a5229c74SGary Mills 	b->w_wc = EOS;
497a5229c74SGary Mills 
498a5229c74SGary Mills 	return (patbuf);
499a5229c74SGary Mills }
500a5229c74SGary Mills 
501a5229c74SGary Mills static int
502a5229c74SGary Mills g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
503a5229c74SGary Mills {
504a5229c74SGary Mills 	const wcat_t *pattern = *patternp + 1;
505a5229c74SGary Mills 	wcat_t *bufnext = *bufnextp;
506a5229c74SGary Mills 	const wcat_t *colon;
507a5229c74SGary Mills 	char cbuf[MB_LEN_MAX + 32];
508a5229c74SGary Mills 	wctype_t cc;
509a5229c74SGary Mills 	size_t len;
510a5229c74SGary Mills 
511a5229c74SGary Mills 	if ((colon = g_strchr(pattern, COLON)) == NULL ||
512a5229c74SGary Mills 	    colon[1].w_wc != RBRACKET)
513a5229c74SGary Mills 		return (1);	/* not a character class */
514a5229c74SGary Mills 
515a5229c74SGary Mills 	len = (size_t)(colon - pattern);
516a5229c74SGary Mills 	if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
517a5229c74SGary Mills 		return (-1);	/* invalid character class */
518a5229c74SGary Mills 	{
519a5229c74SGary Mills 		wchar_t w;
520a5229c74SGary Mills 		const wcat_t *s1 = pattern;
521a5229c74SGary Mills 		char *s2 = cbuf;
522a5229c74SGary Mills 		size_t n = len;
523a5229c74SGary Mills 
524a5229c74SGary Mills 		/* Copy the string. */
525a5229c74SGary Mills 		while (n > 0) {
526a5229c74SGary Mills 			w = (s1++)->w_wc;
527a5229c74SGary Mills 			/* Character class names must be ASCII. */
528a5229c74SGary Mills 			if (iswascii(w)) {
529a5229c74SGary Mills 				n--;
530a5229c74SGary Mills 				*s2++ = w;
531a5229c74SGary Mills 			} else {
532a5229c74SGary Mills 				return (-1);	/* invalid character class */
533a5229c74SGary Mills 			}
534a5229c74SGary Mills 		}
535a5229c74SGary Mills 		*s2 = EOS;
536a5229c74SGary Mills 	}
537a5229c74SGary Mills 	if ((cc = wctype(cbuf)) == 0)
538a5229c74SGary Mills 		return (-1);	/* invalid character class */
539a5229c74SGary Mills 	bufnext->w_at = M_QUOTE;
540a5229c74SGary Mills 	(bufnext++)->w_wc = M_CLASS;
541a5229c74SGary Mills 	bufnext->w_at = 0;
542a5229c74SGary Mills 	(bufnext++)->w_wc = cc;
543a5229c74SGary Mills 	*bufnextp = bufnext;
544a5229c74SGary Mills 	*patternp += len + 3;
545a5229c74SGary Mills 
546a5229c74SGary Mills 	return (0);
547a5229c74SGary Mills }
548a5229c74SGary Mills 
549a5229c74SGary Mills /*
550a5229c74SGary Mills  * The main glob() routine: compiles the pattern (optionally processing
551a5229c74SGary Mills  * quotes), calls glob1() to do the real pattern matching, and finally
552a5229c74SGary Mills  * sorts the list (unless unsorted operation is requested).  Returns 0
553a5229c74SGary Mills  * if things went well, nonzero if errors occurred.  It is not an error
554a5229c74SGary Mills  * to find no matches.
555a5229c74SGary Mills  */
556a5229c74SGary Mills static int
557a5229c74SGary Mills glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
558a5229c74SGary Mills     int (*errfunc)(const char *, int))
559a5229c74SGary Mills {
560a5229c74SGary Mills 	const wcat_t *qpatnext;
561a5229c74SGary Mills 	int err, oldpathc;
562a5229c74SGary Mills 	wchar_t c;
563a5229c74SGary Mills 	int a;
564a5229c74SGary Mills 	wcat_t *bufnext, patbuf[MAXPATHLEN];
565a5229c74SGary Mills 
566a5229c74SGary Mills 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
567a5229c74SGary Mills 	oldpathc = pglob->gl_pathc;
568a5229c74SGary Mills 	bufnext = patbuf;
569a5229c74SGary Mills 
570a5229c74SGary Mills 	/*
571a5229c74SGary Mills 	 * We don't need to check for buffer overflow any more.
572a5229c74SGary Mills 	 * The pattern has already been copied to an internal buffer.
573a5229c74SGary Mills 	 */
574a5229c74SGary Mills 	while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
575a5229c74SGary Mills 		switch (c) {
576a5229c74SGary Mills 		case LBRACKET:
577a5229c74SGary Mills 			if (a != 0) {
578a5229c74SGary Mills 				bufnext->w_at = a;
579a5229c74SGary Mills 				(bufnext++)->w_wc = c;
580a5229c74SGary Mills 				break;
581a5229c74SGary Mills 			}
582a5229c74SGary Mills 			a = qpatnext->w_at;
583a5229c74SGary Mills 			c = qpatnext->w_wc;
584a5229c74SGary Mills 			if (a == 0 && c == NOT)
585a5229c74SGary Mills 				++qpatnext;
586a5229c74SGary Mills 			if (qpatnext->w_wc == EOS ||
587a5229c74SGary Mills 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
588a5229c74SGary Mills 				bufnext->w_at = 0;
589a5229c74SGary Mills 				(bufnext++)->w_wc = LBRACKET;
590a5229c74SGary Mills 				if (a == 0 && c == NOT)
591a5229c74SGary Mills 					--qpatnext;
592a5229c74SGary Mills 				break;
593a5229c74SGary Mills 			}
594a5229c74SGary Mills 			bufnext->w_at = M_QUOTE;
595a5229c74SGary Mills 			(bufnext++)->w_wc = M_SET;
596a5229c74SGary Mills 			if (a == 0 && c == NOT) {
597a5229c74SGary Mills 				bufnext->w_at = M_QUOTE;
598a5229c74SGary Mills 				(bufnext++)->w_wc = M_NOT;
599a5229c74SGary Mills 			}
600a5229c74SGary Mills 			a = qpatnext->w_at;
601a5229c74SGary Mills 			c = (qpatnext++)->w_wc;
602a5229c74SGary Mills 			do {
603a5229c74SGary Mills 				if (a == 0 && c == LBRACKET &&
604a5229c74SGary Mills 				    qpatnext->w_wc == COLON) {
605a5229c74SGary Mills 					do {
606a5229c74SGary Mills 						err = g_charclass(&qpatnext,
607a5229c74SGary Mills 						    &bufnext);
608a5229c74SGary Mills 						if (err)
609a5229c74SGary Mills 							break;
610a5229c74SGary Mills 						a = qpatnext->w_at;
611a5229c74SGary Mills 						c = (qpatnext++)->w_wc;
612a5229c74SGary Mills 					} while (a == 0 && c == LBRACKET &&
613a5229c74SGary Mills 					    qpatnext->w_wc == COLON);
614a5229c74SGary Mills 					if (err == -1 &&
615a5229c74SGary Mills 					    !(pglob->gl_flags & GLOB_NOCHECK))
616a5229c74SGary Mills 						return (GLOB_NOMATCH);
617a5229c74SGary Mills 					if (a == 0 && c == RBRACKET)
618a5229c74SGary Mills 						break;
619a5229c74SGary Mills 				}
620a5229c74SGary Mills 				bufnext->w_at = a;
621a5229c74SGary Mills 				(bufnext++)->w_wc = c;
622a5229c74SGary Mills 				if (qpatnext->w_at == 0 &&
623a5229c74SGary Mills 				    qpatnext->w_wc == RANGE) {
624a5229c74SGary Mills 					a = qpatnext[1].w_at;
625a5229c74SGary Mills 					c = qpatnext[1].w_wc;
626a5229c74SGary Mills 					if (qpatnext[1].w_at != 0 ||
627a5229c74SGary Mills 					    qpatnext[1].w_wc != RBRACKET) {
628a5229c74SGary Mills 						bufnext->w_at = M_QUOTE;
629a5229c74SGary Mills 						(bufnext++)->w_wc = M_RNG;
630a5229c74SGary Mills 						bufnext->w_at = a;
631a5229c74SGary Mills 						(bufnext++)->w_wc = c;
632a5229c74SGary Mills 						qpatnext += 2;
633a5229c74SGary Mills 					}
634a5229c74SGary Mills 				}
635a5229c74SGary Mills 				a = qpatnext->w_at;
636a5229c74SGary Mills 				c = (qpatnext++)->w_wc;
637a5229c74SGary Mills 			} while (a != 0 || c != RBRACKET);
638a5229c74SGary Mills 			pglob->gl_flags |= GLOB_MAGCHAR;
639a5229c74SGary Mills 			bufnext->w_at = M_QUOTE;
640a5229c74SGary Mills 			(bufnext++)->w_wc = M_END;
641a5229c74SGary Mills 			break;
642a5229c74SGary Mills 		case QUESTION:
643a5229c74SGary Mills 			if (a != 0) {
644a5229c74SGary Mills 				bufnext->w_at = a;
645a5229c74SGary Mills 				(bufnext++)->w_wc = c;
646a5229c74SGary Mills 				break;
647a5229c74SGary Mills 			}
648a5229c74SGary Mills 			pglob->gl_flags |= GLOB_MAGCHAR;
649a5229c74SGary Mills 			bufnext->w_at = M_QUOTE;
650a5229c74SGary Mills 			(bufnext++)->w_wc = M_ONE;
651a5229c74SGary Mills 			break;
652a5229c74SGary Mills 		case STAR:
653a5229c74SGary Mills 			if (a != 0) {
654a5229c74SGary Mills 				bufnext->w_at = a;
655a5229c74SGary Mills 				(bufnext++)->w_wc = c;
656a5229c74SGary Mills 				break;
657a5229c74SGary Mills 			}
658a5229c74SGary Mills 			pglob->gl_flags |= GLOB_MAGCHAR;
659a5229c74SGary Mills 			/*
660a5229c74SGary Mills 			 * collapse adjacent stars to one,
661a5229c74SGary Mills 			 * to avoid exponential behavior
662a5229c74SGary Mills 			 */
663a5229c74SGary Mills 			if (bufnext == patbuf ||
664a5229c74SGary Mills 			    bufnext[-1].w_at != M_QUOTE ||
665a5229c74SGary Mills 			    bufnext[-1].w_wc != M_ALL) {
666a5229c74SGary Mills 				bufnext->w_at = M_QUOTE;
667a5229c74SGary Mills 				(bufnext++)->w_wc = M_ALL;
668a5229c74SGary Mills 			}
669a5229c74SGary Mills 			break;
670a5229c74SGary Mills 		default:
671a5229c74SGary Mills 			bufnext->w_at = a;
672a5229c74SGary Mills 			(bufnext++)->w_wc = c;
673a5229c74SGary Mills 			break;
674a5229c74SGary Mills 		}
675a5229c74SGary Mills 	}
676a5229c74SGary Mills 	bufnext->w_at = 0;
677a5229c74SGary Mills 	bufnext->w_wc = EOS;
678a5229c74SGary Mills 
679a5229c74SGary Mills 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc))
680a5229c74SGary Mills 	    != 0)
681a5229c74SGary Mills 		return (err);
682a5229c74SGary Mills 
683a5229c74SGary Mills 	/*
684a5229c74SGary Mills 	 * If there was no match we are going to append the pattern
685a5229c74SGary Mills 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
686a5229c74SGary Mills 	 * and the pattern did not contain any magic characters
687a5229c74SGary Mills 	 * GLOB_NOMAGIC is there just for compatibility with csh.
688a5229c74SGary Mills 	 */
689a5229c74SGary Mills 	if (pglob->gl_pathc == oldpathc) {
690a5229c74SGary Mills 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
691a5229c74SGary Mills 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
692a5229c74SGary Mills 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
693a5229c74SGary Mills 			return (globextend(pattern, pglob, limitp, NULL));
694a5229c74SGary Mills 		else
695a5229c74SGary Mills 			return (GLOB_NOMATCH);
696a5229c74SGary Mills 	}
697a5229c74SGary Mills 	if (!(pglob->gl_flags & GLOB_NOSORT)) {
698a5229c74SGary Mills 		if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
699a5229c74SGary Mills 			/* Keep the paths and stat info synced during sort */
700a5229c74SGary Mills 			struct glob_path_stat *path_stat;
701a5229c74SGary Mills 			int i;
702a5229c74SGary Mills 			int n = pglob->gl_pathc - oldpathc;
703a5229c74SGary Mills 			int o = pglob->gl_offs + oldpathc;
704a5229c74SGary Mills 
705a5229c74SGary Mills 			if ((path_stat = calloc(n, sizeof (*path_stat))) ==
706a5229c74SGary Mills 			    NULL)
707a5229c74SGary Mills 				return (GLOB_NOSPACE);
708a5229c74SGary Mills 			for (i = 0; i < n; i++) {
709a5229c74SGary Mills 				path_stat[i].gps_path = pglob->gl_pathv[o + i];
710a5229c74SGary Mills 				path_stat[i].gps_stat = pglob->gl_statv[o + i];
711a5229c74SGary Mills 			}
712a5229c74SGary Mills 			qsort(path_stat, n, sizeof (*path_stat), compare_gps);
713a5229c74SGary Mills 			for (i = 0; i < n; i++) {
714a5229c74SGary Mills 				pglob->gl_pathv[o + i] = path_stat[i].gps_path;
715a5229c74SGary Mills 				pglob->gl_statv[o + i] = path_stat[i].gps_stat;
716a5229c74SGary Mills 			}
717a5229c74SGary Mills 			free(path_stat);
718a5229c74SGary Mills 		} else {
719a5229c74SGary Mills 			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
720a5229c74SGary Mills 			    pglob->gl_pathc - oldpathc, sizeof (char *),
721a5229c74SGary Mills 			    compare);
722a5229c74SGary Mills 		}
723a5229c74SGary Mills 	}
724a5229c74SGary Mills 	return (0);
725a5229c74SGary Mills }
726a5229c74SGary Mills 
727a5229c74SGary Mills static int
728a5229c74SGary Mills compare(const void *p, const void *q)
729a5229c74SGary Mills {
730a5229c74SGary Mills 	return (strcmp(*(char **)p, *(char **)q));
731a5229c74SGary Mills }
732a5229c74SGary Mills 
733a5229c74SGary Mills static int
734a5229c74SGary Mills compare_gps(const void *_p, const void *_q)
735a5229c74SGary Mills {
736a5229c74SGary Mills 	const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
737a5229c74SGary Mills 	const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
738a5229c74SGary Mills 
739a5229c74SGary Mills 	return (strcmp(p->gps_path, q->gps_path));
740a5229c74SGary Mills }
741a5229c74SGary Mills 
742a5229c74SGary Mills static int
743a5229c74SGary Mills glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
744a5229c74SGary Mills     struct glob_lim *limitp, int (*errfunc)(const char *, int))
745a5229c74SGary Mills {
746a5229c74SGary Mills 	wcat_t pathbuf[MAXPATHLEN];
747a5229c74SGary Mills 
748a5229c74SGary Mills 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
749a5229c74SGary Mills 	if (pattern->w_wc == EOS)
750a5229c74SGary Mills 		return (0);
751a5229c74SGary Mills 	return (glob2(pathbuf, pathbuf+MAXPATHLEN-1,
752a5229c74SGary Mills 	    pathbuf, pathbuf+MAXPATHLEN-1,
753a5229c74SGary Mills 	    pattern, pattern_last, pglob, limitp, errfunc));
754a5229c74SGary Mills }
755a5229c74SGary Mills 
756a5229c74SGary Mills /*
757a5229c74SGary Mills  * The functions glob2 and glob3 are mutually recursive; there is one level
758a5229c74SGary Mills  * of recursion for each segment in the pattern that contains one or more
759a5229c74SGary Mills  * meta characters.
760a5229c74SGary Mills  */
761a5229c74SGary Mills static int
762a5229c74SGary Mills glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
763a5229c74SGary Mills     wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last,
764a5229c74SGary Mills     glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int))
765a5229c74SGary Mills {
766a5229c74SGary Mills 	struct stat sb;
767a5229c74SGary Mills 	wcat_t *p, *q;
768a5229c74SGary Mills 	int anymeta;
769a5229c74SGary Mills 
770a5229c74SGary Mills 	/*
771a5229c74SGary Mills 	 * Loop over pattern segments until end of pattern or until
772a5229c74SGary Mills 	 * segment with meta character found.
773a5229c74SGary Mills 	 */
774a5229c74SGary Mills 	for (anymeta = 0; ; ) {
775a5229c74SGary Mills 		if (pattern->w_wc == EOS) {		/* End of pattern? */
776a5229c74SGary Mills 			pathend->w_at = 0;
777a5229c74SGary Mills 			pathend->w_wc = EOS;
778a5229c74SGary Mills 
779a5229c74SGary Mills 			if ((pglob->gl_flags & GLOB_LIMIT) &&
780a5229c74SGary Mills 			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
781a5229c74SGary Mills 				errno = 0;
782a5229c74SGary Mills 				pathend->w_at = 0;
783a5229c74SGary Mills 				(pathend++)->w_wc = SEP;
784a5229c74SGary Mills 				pathend->w_at = 0;
785a5229c74SGary Mills 				pathend->w_wc = EOS;
786a5229c74SGary Mills 				return (GLOB_NOSPACE);
787a5229c74SGary Mills 			}
788a5229c74SGary Mills 			if (g_lstat(pathbuf, &sb, pglob))
789a5229c74SGary Mills 				return (0);
790a5229c74SGary Mills 
791a5229c74SGary Mills 			if (((pglob->gl_flags & GLOB_MARK) &&
792a5229c74SGary Mills 			    (pathend[-1].w_at != 0 ||
793a5229c74SGary Mills 			    pathend[-1].w_wc != SEP)) &&
794a5229c74SGary Mills 			    (S_ISDIR(sb.st_mode) ||
795a5229c74SGary Mills 			    (S_ISLNK(sb.st_mode) &&
796a5229c74SGary Mills 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
797a5229c74SGary Mills 			    S_ISDIR(sb.st_mode)))) {
798a5229c74SGary Mills 				if (pathend+1 > pathend_last)
799a5229c74SGary Mills 					return (GLOB_NOSPACE);
800a5229c74SGary Mills 				pathend->w_at = 0;
801a5229c74SGary Mills 				(pathend++)->w_wc = SEP;
802a5229c74SGary Mills 				pathend->w_at = 0;
803a5229c74SGary Mills 				pathend->w_wc = EOS;
804a5229c74SGary Mills 			}
805a5229c74SGary Mills 			++pglob->gl_matchc;
806a5229c74SGary Mills 			return (globextend(pathbuf, pglob, limitp, &sb));
807a5229c74SGary Mills 		}
808a5229c74SGary Mills 
809a5229c74SGary Mills 		/* Find end of next segment, copy tentatively to pathend. */
810a5229c74SGary Mills 		q = pathend;
811a5229c74SGary Mills 		p = pattern;
812a5229c74SGary Mills 		while (p->w_wc != EOS && p->w_wc != SEP) {
813a5229c74SGary Mills 			if (ismeta(*p))
814a5229c74SGary Mills 				anymeta = 1;
815a5229c74SGary Mills 			if (q+1 > pathend_last)
816a5229c74SGary Mills 				return (GLOB_NOSPACE);
817a5229c74SGary Mills 			*q++ = *p++;
818a5229c74SGary Mills 		}
819a5229c74SGary Mills 
820a5229c74SGary Mills 		if (!anymeta) {		/* No expansion, do next segment. */
821a5229c74SGary Mills 			pathend = q;
822a5229c74SGary Mills 			pattern = p;
823a5229c74SGary Mills 			while (pattern->w_wc == SEP) {
824a5229c74SGary Mills 				if (pathend+1 > pathend_last)
825a5229c74SGary Mills 					return (GLOB_NOSPACE);
826a5229c74SGary Mills 				*pathend++ = *pattern++;
827a5229c74SGary Mills 			}
828a5229c74SGary Mills 		} else  {
829a5229c74SGary Mills 			/* Need expansion, recurse. */
830a5229c74SGary Mills 			return (glob3(pathbuf, pathbuf_last, pathend,
831a5229c74SGary Mills 			    pathend_last, pattern, p, pattern_last,
832a5229c74SGary Mills 			    pglob, limitp, errfunc));
833a5229c74SGary Mills 		}
834a5229c74SGary Mills 	}
835a5229c74SGary Mills 	/* NOTREACHED */
836a5229c74SGary Mills }
837a5229c74SGary Mills 
838a5229c74SGary Mills static int
839a5229c74SGary Mills glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
840a5229c74SGary Mills     wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern,
841a5229c74SGary Mills     wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp,
842a5229c74SGary Mills     int (*errfunc)(const char *, int))
843a5229c74SGary Mills {
844a5229c74SGary Mills 	struct dirent *dp;
845a5229c74SGary Mills 	DIR *dirp;
846a5229c74SGary Mills 	int err;
847a5229c74SGary Mills 	char buf[MAXPATHLEN];
848a5229c74SGary Mills 
849a5229c74SGary Mills 	/*
850a5229c74SGary Mills 	 * The readdirfunc declaration can't be prototyped, because it is
851a5229c74SGary Mills 	 * assigned, below, to two functions which are prototyped in glob.h
852a5229c74SGary Mills 	 * and dirent.h as taking pointers to differently typed opaque
853a5229c74SGary Mills 	 * structures.
854a5229c74SGary Mills 	 */
855a5229c74SGary Mills 	struct dirent *(*readdirfunc)(void *);
856a5229c74SGary Mills 
857a5229c74SGary Mills 	if (pathend > pathend_last)
858a5229c74SGary Mills 		return (GLOB_NOSPACE);
859a5229c74SGary Mills 	pathend->w_at = 0;
860a5229c74SGary Mills 	pathend->w_wc = EOS;
861a5229c74SGary Mills 	errno = 0;
862a5229c74SGary Mills 
863a5229c74SGary Mills 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
864a5229c74SGary Mills 		/* TODO: don't call for ENOENT or ENOTDIR? */
865a5229c74SGary Mills 		if (errfunc) {
866a5229c74SGary Mills 			if (g_Ctoc(pathbuf, buf, sizeof (buf)))
867a5229c74SGary Mills 				return (GLOB_ABORTED);
868a5229c74SGary Mills 			if (errfunc(buf, errno) ||
869a5229c74SGary Mills 			    pglob->gl_flags & GLOB_ERR)
8707c478bd9Sstevel@tonic-gate 				return (GLOB_ABORTED);
8717c478bd9Sstevel@tonic-gate 		}
872a5229c74SGary Mills 		return (0);
873a5229c74SGary Mills 	}
8747c478bd9Sstevel@tonic-gate 
875a5229c74SGary Mills 	err = 0;
876a5229c74SGary Mills 
877a5229c74SGary Mills 	/* Search directory for matching names. */
878a5229c74SGary Mills 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
879a5229c74SGary Mills 		readdirfunc = pglob->gl_readdir;
8807c478bd9Sstevel@tonic-gate 	else
881a5229c74SGary Mills 		readdirfunc = (struct dirent *(*)(void *))readdir;
882a5229c74SGary Mills 	while ((dp = (*readdirfunc)(dirp))) {
883a5229c74SGary Mills 		char *sc;
884a5229c74SGary Mills 		wcat_t *dc;
885a5229c74SGary Mills 		int n;
886a5229c74SGary Mills 		int lensc;
887a5229c74SGary Mills 		wchar_t w;
888a5229c74SGary Mills 
889a5229c74SGary Mills 		if ((pglob->gl_flags & GLOB_LIMIT) &&
890a5229c74SGary Mills 		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
891a5229c74SGary Mills 			errno = 0;
892a5229c74SGary Mills 			pathend->w_at = 0;
893a5229c74SGary Mills 			(pathend++)->w_wc = SEP;
894a5229c74SGary Mills 			pathend->w_at = 0;
895a5229c74SGary Mills 			pathend->w_wc = EOS;
896a5229c74SGary Mills 			err = GLOB_NOSPACE;
897a5229c74SGary Mills 			break;
8987c478bd9Sstevel@tonic-gate 		}
899a5229c74SGary Mills 
900a5229c74SGary Mills 		/* Initial DOT must be matched literally. */
901a5229c74SGary Mills 		if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
902a5229c74SGary Mills 			continue;
903a5229c74SGary Mills 		dc = pathend;
904a5229c74SGary Mills 		sc = dp->d_name;
905a5229c74SGary Mills 		lensc = strlen(sc) + 1;
906a5229c74SGary Mills 		while (dc < pathend_last) {
907a5229c74SGary Mills 			if ((n = mbtowc(&w, sc, lensc)) <= 0) {
908a5229c74SGary Mills 				sc += 1;
909a5229c74SGary Mills 				lensc -= 1;
910a5229c74SGary Mills 				dc->w_at = 0;
911a5229c74SGary Mills 				dc->w_wc = EOS;
912a5229c74SGary Mills 			} else {
913a5229c74SGary Mills 				sc += n;
914a5229c74SGary Mills 				lensc -= n;
915a5229c74SGary Mills 				dc->w_at = 0;
916a5229c74SGary Mills 				dc->w_wc = w;
917a5229c74SGary Mills 			}
918a5229c74SGary Mills 			dc++;
919a5229c74SGary Mills 			if (n <= 0)
920a5229c74SGary Mills 				break;
921a5229c74SGary Mills 		}
922a5229c74SGary Mills 		if (dc >= pathend_last) {
923a5229c74SGary Mills 			dc->w_at = 0;
924a5229c74SGary Mills 			dc->w_wc = EOS;
925a5229c74SGary Mills 			err = GLOB_NOSPACE;
926a5229c74SGary Mills 			break;
927a5229c74SGary Mills 		}
928a5229c74SGary Mills 		if (n < 0) {
929a5229c74SGary Mills 			err = GLOB_NOMATCH;
930a5229c74SGary Mills 			break;
931a5229c74SGary Mills 		}
932a5229c74SGary Mills 
933a5229c74SGary Mills 		if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
934a5229c74SGary Mills 			pathend->w_at = 0;
935a5229c74SGary Mills 			pathend->w_wc = EOS;
936a5229c74SGary Mills 			continue;
937a5229c74SGary Mills 		}
938a5229c74SGary Mills 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
939a5229c74SGary Mills 		    restpattern, restpattern_last, pglob, limitp,
940a5229c74SGary Mills 		    errfunc);
941a5229c74SGary Mills 		if (err)
942a5229c74SGary Mills 			break;
943a5229c74SGary Mills 	}
944a5229c74SGary Mills 
945a5229c74SGary Mills 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
946a5229c74SGary Mills 		(*pglob->gl_closedir)(dirp);
947a5229c74SGary Mills 	else
948a5229c74SGary Mills 		(void) closedir(dirp);
949a5229c74SGary Mills 	return (err);
950a5229c74SGary Mills }
951a5229c74SGary Mills 
952a5229c74SGary Mills 
953a5229c74SGary Mills /*
954a5229c74SGary Mills  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
955a5229c74SGary Mills  * add the new item, and update gl_pathc.  Avoids excessive reallocation
956a5229c74SGary Mills  * by doubling the number of elements each time.  Uses gl_pathn to contain
957a5229c74SGary Mills  * the number.
958a5229c74SGary Mills  *
959a5229c74SGary Mills  * Return 0 if new item added, error code if memory couldn't be allocated.
960a5229c74SGary Mills  *
961a5229c74SGary Mills  * Invariant of the glob_t structure:
962a5229c74SGary Mills  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
963a5229c74SGary Mills  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
964a5229c74SGary Mills  */
965a5229c74SGary Mills static int
966a5229c74SGary Mills globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
967a5229c74SGary Mills     struct stat *sb)
968a5229c74SGary Mills {
969a5229c74SGary Mills 	char **pathv;
970a5229c74SGary Mills 	ssize_t i;
971a5229c74SGary Mills 	size_t allocn, newn, len;
972a5229c74SGary Mills 	char *copy = NULL;
973a5229c74SGary Mills 	const wcat_t *p;
974a5229c74SGary Mills 	struct stat **statv;
975a5229c74SGary Mills 	char junk[MB_LEN_MAX];
976a5229c74SGary Mills 	int n;
977a5229c74SGary Mills 
978a5229c74SGary Mills 	allocn = pglob->gl_pathn;
979a5229c74SGary Mills 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
980a5229c74SGary Mills 
981a5229c74SGary Mills 	if (newn <= allocn) {
982a5229c74SGary Mills 		pathv = pglob->gl_pathv;
983a5229c74SGary Mills 		if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0)
984a5229c74SGary Mills 			statv = pglob->gl_statv;
985a5229c74SGary Mills 	} else {
986a5229c74SGary Mills 		if (allocn == 0)
987a5229c74SGary Mills 			allocn = pglob->gl_offs + INITIAL;
988a5229c74SGary Mills 		allocn *= 2;
989a5229c74SGary Mills 		if (pglob->gl_offs >= INT_MAX ||
990a5229c74SGary Mills 		    pglob->gl_pathc >= INT_MAX ||
991a5229c74SGary Mills 		    allocn >= INT_MAX ||
992a5229c74SGary Mills 		    SIZE_MAX / sizeof (*pathv) <= allocn ||
993a5229c74SGary Mills 		    SIZE_MAX / sizeof (*statv) <= allocn) {
994a5229c74SGary Mills 		nospace:
995a5229c74SGary Mills 			for (i = pglob->gl_offs; i < (ssize_t)(newn - 2);
996a5229c74SGary Mills 			    i++) {
997a5229c74SGary Mills 				if (pglob->gl_pathv && pglob->gl_pathv[i])
998a5229c74SGary Mills 					free(pglob->gl_pathv[i]);
999a5229c74SGary Mills 				if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1000a5229c74SGary Mills 				    pglob->gl_statv && pglob->gl_statv[i])
1001a5229c74SGary Mills 					free(pglob->gl_statv[i]);
1002a5229c74SGary Mills 			}
1003a5229c74SGary Mills 			if (pglob->gl_pathv) {
1004a5229c74SGary Mills 				free(pglob->gl_pathv);
1005a5229c74SGary Mills 				pglob->gl_pathv = NULL;
1006a5229c74SGary Mills 			}
1007a5229c74SGary Mills 			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1008a5229c74SGary Mills 			    pglob->gl_statv) {
1009a5229c74SGary Mills 				free(pglob->gl_statv);
1010a5229c74SGary Mills 				pglob->gl_statv = NULL;
1011a5229c74SGary Mills 			}
1012a5229c74SGary Mills 			return (GLOB_NOSPACE);
1013a5229c74SGary Mills 		}
1014a5229c74SGary Mills 		limitp->glim_malloc += allocn * sizeof (*pathv);
1015a5229c74SGary Mills 		pathv = realloc(pglob->gl_pathv, allocn * sizeof (*pathv));
1016a5229c74SGary Mills 		if (pathv == NULL)
1017a5229c74SGary Mills 			goto nospace;
1018a5229c74SGary Mills 		if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1019a5229c74SGary Mills 			limitp->glim_malloc += allocn * sizeof (*statv);
1020a5229c74SGary Mills 			statv = realloc(pglob->gl_statv,
1021a5229c74SGary Mills 			    allocn * sizeof (*statv));
1022a5229c74SGary Mills 			if (statv == NULL)
1023a5229c74SGary Mills 				goto nospace;
1024a5229c74SGary Mills 		}
1025a5229c74SGary Mills 	}
1026a5229c74SGary Mills 	pglob->gl_pathn = allocn;
1027a5229c74SGary Mills 
1028a5229c74SGary Mills 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
1029a5229c74SGary Mills 		/* first time around -- clear initial gl_offs items */
1030a5229c74SGary Mills 		pathv += pglob->gl_offs;
1031a5229c74SGary Mills 		for (i = pglob->gl_offs; --i >= 0; )
1032a5229c74SGary Mills 			*--pathv = NULL;
1033a5229c74SGary Mills 	}
1034a5229c74SGary Mills 	pglob->gl_pathv = pathv;
1035a5229c74SGary Mills 
1036a5229c74SGary Mills 	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1037a5229c74SGary Mills 		if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
1038a5229c74SGary Mills 			/* first time around -- clear initial gl_offs items */
1039a5229c74SGary Mills 			statv += pglob->gl_offs;
1040a5229c74SGary Mills 			for (i = pglob->gl_offs; --i >= 0; )
1041a5229c74SGary Mills 				*--statv = NULL;
1042a5229c74SGary Mills 		}
1043a5229c74SGary Mills 		pglob->gl_statv = statv;
1044a5229c74SGary Mills 		if (sb == NULL)
1045a5229c74SGary Mills 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1046a5229c74SGary Mills 		else {
1047a5229c74SGary Mills 			limitp->glim_malloc += sizeof (**statv);
1048a5229c74SGary Mills 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
1049a5229c74SGary Mills 			    malloc(sizeof (**statv))) == NULL)
1050a5229c74SGary Mills 				goto copy_error;
1051a5229c74SGary Mills 			(void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc],
1052a5229c74SGary Mills 			    sb, sizeof (*sb));
1053a5229c74SGary Mills 		}
1054a5229c74SGary Mills 		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
1055a5229c74SGary Mills 	}
1056a5229c74SGary Mills 
1057a5229c74SGary Mills 	len = MB_LEN_MAX;
1058a5229c74SGary Mills 	p = path;
1059a5229c74SGary Mills 	while ((n = wctomb(junk, p->w_wc)) > 0) {
1060a5229c74SGary Mills 		len += n;
1061a5229c74SGary Mills 		if ((p++)->w_wc == EOS)
1062a5229c74SGary Mills 			break;
1063a5229c74SGary Mills 	}
1064a5229c74SGary Mills 	if (n < 0)
1065a5229c74SGary Mills 		return (GLOB_NOMATCH);
1066a5229c74SGary Mills 
1067a5229c74SGary Mills 	limitp->glim_malloc += len;
1068a5229c74SGary Mills 	if ((copy = malloc(len)) != NULL) {
1069a5229c74SGary Mills 		if (g_Ctoc(path, copy, len)) {
1070a5229c74SGary Mills 			free(copy);
1071a5229c74SGary Mills 			return (GLOB_NOSPACE);
1072a5229c74SGary Mills 		}
1073a5229c74SGary Mills 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1074a5229c74SGary Mills 	}
1075a5229c74SGary Mills 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1076a5229c74SGary Mills 
1077a5229c74SGary Mills 	if ((pglob->gl_flags & GLOB_LIMIT) &&
1078a5229c74SGary Mills 	    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
1079a5229c74SGary Mills 		errno = 0;
1080a5229c74SGary Mills 		return (GLOB_NOSPACE);
1081a5229c74SGary Mills 	}
1082a5229c74SGary Mills 	copy_error:
1083a5229c74SGary Mills 	return (copy == NULL ? GLOB_NOSPACE : 0);
1084a5229c74SGary Mills }
1085a5229c74SGary Mills 
1086a5229c74SGary Mills 
1087a5229c74SGary Mills /*
1088a5229c74SGary Mills  * pattern matching function for filenames.  Each occurrence of the *
1089a5229c74SGary Mills  * pattern causes a recursion level.
1090a5229c74SGary Mills  */
1091a5229c74SGary Mills static int
1092a5229c74SGary Mills match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur)
1093a5229c74SGary Mills {
1094a5229c74SGary Mills 	int ok, negate_range;
1095a5229c74SGary Mills 	wcat_t c, k;
1096a5229c74SGary Mills 
1097a5229c74SGary Mills 	if (recur-- == 0)
1098a5229c74SGary Mills 		return (1);
1099a5229c74SGary Mills 
1100a5229c74SGary Mills 	while (pat < patend) {
1101a5229c74SGary Mills 		c = *pat++;
1102a5229c74SGary Mills 		switch (c.w_wc) {
1103a5229c74SGary Mills 		case M_ALL:
1104a5229c74SGary Mills 			if (c.w_at != M_QUOTE) {
1105a5229c74SGary Mills 				k = *name++;
1106a5229c74SGary Mills 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1107a5229c74SGary Mills 					return (0);
1108a5229c74SGary Mills 				break;
1109a5229c74SGary Mills 			}
1110a5229c74SGary Mills 			while (pat < patend && pat->w_at == M_QUOTE &&
1111a5229c74SGary Mills 			    pat->w_wc == M_ALL)
1112a5229c74SGary Mills 				pat++;	/* eat consecutive '*' */
1113a5229c74SGary Mills 			if (pat == patend)
1114a5229c74SGary Mills 				return (1);
1115a5229c74SGary Mills 			do {
1116a5229c74SGary Mills 				if (match(name, pat, patend, recur))
1117a5229c74SGary Mills 					return (1);
1118a5229c74SGary Mills 			} while ((name++)->w_wc != EOS);
1119a5229c74SGary Mills 			return (0);
1120a5229c74SGary Mills 		case M_ONE:
1121a5229c74SGary Mills 			if (c.w_at != M_QUOTE) {
1122a5229c74SGary Mills 				k = *name++;
1123a5229c74SGary Mills 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1124a5229c74SGary Mills 					return (0);
1125a5229c74SGary Mills 				break;
1126a5229c74SGary Mills 			}
1127a5229c74SGary Mills 			if ((name++)->w_wc == EOS)
1128a5229c74SGary Mills 				return (0);
1129a5229c74SGary Mills 			break;
1130a5229c74SGary Mills 		case M_SET:
1131a5229c74SGary Mills 			if (c.w_at != M_QUOTE) {
1132a5229c74SGary Mills 				k = *name++;
1133a5229c74SGary Mills 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1134a5229c74SGary Mills 					return (0);
1135a5229c74SGary Mills 				break;
1136a5229c74SGary Mills 			}
1137a5229c74SGary Mills 			ok = 0;
1138a5229c74SGary Mills 			if ((k = *name++).w_wc == EOS)
1139a5229c74SGary Mills 				return (0);
1140a5229c74SGary Mills 			if ((negate_range = (pat->w_at == M_QUOTE &&
1141a5229c74SGary Mills 			    pat->w_wc == M_NOT)) != 0)
1142a5229c74SGary Mills 				++pat;
1143a5229c74SGary Mills 			while (((c = *pat++).w_at != M_QUOTE) ||
1144a5229c74SGary Mills 			    c.w_wc != M_END) {
1145a5229c74SGary Mills 				if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
1146a5229c74SGary Mills 					wcat_t cc;
1147a5229c74SGary Mills 
1148a5229c74SGary Mills 					cc.w_at = pat->w_at;
1149a5229c74SGary Mills 					cc.w_wc = pat->w_wc;
1150a5229c74SGary Mills 					if (iswctype(k.w_wc, cc.w_wc))
1151a5229c74SGary Mills 						ok = 1;
1152a5229c74SGary Mills 					++pat;
1153a5229c74SGary Mills 				}
1154a5229c74SGary Mills 				if (pat->w_at == M_QUOTE &&
1155a5229c74SGary Mills 				    pat->w_wc == M_RNG) {
1156a5229c74SGary Mills 					if (c.w_wc <= k.w_wc &&
1157a5229c74SGary Mills 					    k.w_wc <= pat[1].w_wc)
1158a5229c74SGary Mills 						ok = 1;
1159a5229c74SGary Mills 					pat += 2;
1160a5229c74SGary Mills 				} else if (c.w_wc == k.w_wc)
1161a5229c74SGary Mills 					ok = 1;
1162a5229c74SGary Mills 			}
1163a5229c74SGary Mills 			if (ok == negate_range)
1164a5229c74SGary Mills 				return (0);
1165a5229c74SGary Mills 			break;
1166a5229c74SGary Mills 		default:
1167a5229c74SGary Mills 			k = *name++;
1168a5229c74SGary Mills 			if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1169a5229c74SGary Mills 				return (0);
1170a5229c74SGary Mills 			break;
1171a5229c74SGary Mills 		}
1172a5229c74SGary Mills 	}
1173a5229c74SGary Mills 	return (name->w_wc == EOS);
1174a5229c74SGary Mills }
1175a5229c74SGary Mills 
1176a5229c74SGary Mills /*
1177a5229c74SGary Mills  * Extended globfree() function, selected by #pragma redefine_extname
1178a5229c74SGary Mills  * in glob.h with the external name _globfree_ext() .
1179a5229c74SGary Mills  */
1180a5229c74SGary Mills void
1181a5229c74SGary Mills _globfree_ext(glob_t *pglob)
1182a5229c74SGary Mills {
1183a5229c74SGary Mills 	int i;
1184a5229c74SGary Mills 	char **pp;
1185a5229c74SGary Mills 
1186a5229c74SGary Mills 	if (pglob->gl_pathv != NULL) {
1187a5229c74SGary Mills 		pp = pglob->gl_pathv + pglob->gl_offs;
1188a5229c74SGary Mills 		for (i = pglob->gl_pathc; i--; ++pp)
1189a5229c74SGary Mills 			if (*pp)
1190a5229c74SGary Mills 				free(*pp);
1191a5229c74SGary Mills 		free(pglob->gl_pathv);
1192a5229c74SGary Mills 		pglob->gl_pathv = NULL;
1193a5229c74SGary Mills 	}
1194a5229c74SGary Mills 	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1195a5229c74SGary Mills 	    pglob->gl_statv != NULL) {
1196a5229c74SGary Mills 		for (i = 0; i < pglob->gl_pathc; i++) {
1197a5229c74SGary Mills 			if (pglob->gl_statv[i] != NULL)
1198a5229c74SGary Mills 				free(pglob->gl_statv[i]);
1199a5229c74SGary Mills 		}
1200a5229c74SGary Mills 		free(pglob->gl_statv);
1201a5229c74SGary Mills 		pglob->gl_statv = NULL;
1202a5229c74SGary Mills 	}
1203a5229c74SGary Mills }
1204a5229c74SGary Mills 
1205a5229c74SGary Mills static DIR *
1206a5229c74SGary Mills g_opendir(wcat_t *str, glob_t *pglob)
1207a5229c74SGary Mills {
1208a5229c74SGary Mills 	char buf[MAXPATHLEN];
1209a5229c74SGary Mills 
1210a5229c74SGary Mills 	if (str->w_wc == EOS)
1211a5229c74SGary Mills 		(void) strlcpy(buf, ".", sizeof (buf));
1212a5229c74SGary Mills 	else {
1213a5229c74SGary Mills 		if (g_Ctoc(str, buf, sizeof (buf)))
1214a5229c74SGary Mills 			return (NULL);
1215a5229c74SGary Mills 	}
1216a5229c74SGary Mills 
1217a5229c74SGary Mills 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1218a5229c74SGary Mills 		return ((*pglob->gl_opendir)(buf));
1219a5229c74SGary Mills 
1220a5229c74SGary Mills 	return (opendir(buf));
1221a5229c74SGary Mills }
1222a5229c74SGary Mills 
1223a5229c74SGary Mills static int
1224a5229c74SGary Mills g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1225a5229c74SGary Mills {
1226a5229c74SGary Mills 	char buf[MAXPATHLEN];
1227a5229c74SGary Mills 
1228a5229c74SGary Mills 	if (g_Ctoc(fn, buf, sizeof (buf)))
1229a5229c74SGary Mills 		return (-1);
1230a5229c74SGary Mills 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1231a5229c74SGary Mills 		return ((*pglob->gl_lstat)(buf, sb));
1232a5229c74SGary Mills 	return (lstat(buf, sb));
1233a5229c74SGary Mills }
1234a5229c74SGary Mills 
1235a5229c74SGary Mills static int
1236a5229c74SGary Mills g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1237a5229c74SGary Mills {
1238a5229c74SGary Mills 	char buf[MAXPATHLEN];
1239a5229c74SGary Mills 
1240a5229c74SGary Mills 	if (g_Ctoc(fn, buf, sizeof (buf)))
1241a5229c74SGary Mills 		return (-1);
1242a5229c74SGary Mills 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1243a5229c74SGary Mills 		return ((*pglob->gl_stat)(buf, sb));
1244a5229c74SGary Mills 	return (stat(buf, sb));
1245a5229c74SGary Mills }
1246a5229c74SGary Mills 
1247a5229c74SGary Mills static wcat_t *
1248a5229c74SGary Mills g_strchr(const wcat_t *str, wchar_t ch)
1249a5229c74SGary Mills {
1250a5229c74SGary Mills 	do {
1251a5229c74SGary Mills 		if (str->w_at == 0 && str->w_wc == ch)
1252a5229c74SGary Mills 			return ((wcat_t *)str);
1253a5229c74SGary Mills 	} while ((str++)->w_wc != EOS);
1254a5229c74SGary Mills 	return (NULL);
1255a5229c74SGary Mills }
1256a5229c74SGary Mills 
1257a5229c74SGary Mills static int
1258a5229c74SGary Mills g_Ctoc(const wcat_t *str, char *buf, uint_t len)
1259a5229c74SGary Mills {
1260a5229c74SGary Mills 	int n;
1261a5229c74SGary Mills 	wchar_t w;
1262a5229c74SGary Mills 
1263a5229c74SGary Mills 	while (len >= MB_LEN_MAX) {
1264a5229c74SGary Mills 		w = (str++)->w_wc;
1265a5229c74SGary Mills 		if ((n = wctomb(buf, w)) > 0) {
1266a5229c74SGary Mills 			len -= n;
1267a5229c74SGary Mills 			buf += n;
1268a5229c74SGary Mills 		}
1269a5229c74SGary Mills 		if (n < 0)
1270a5229c74SGary Mills 			break;
1271a5229c74SGary Mills 		if (w == EOS)
1272a5229c74SGary Mills 			return (0);
1273a5229c74SGary Mills 	}
1274a5229c74SGary Mills 	return (1);
1275a5229c74SGary Mills }
1276a5229c74SGary Mills 
1277*33e8313dSRobert Mustacchi #if defined(_LP64) || _FILE_OFFSET_BITS != 64
1278*33e8313dSRobert Mustacchi 
1279a5229c74SGary Mills /* glob() function with legacy glob structure */
1280a5229c74SGary Mills int
1281a5229c74SGary Mills old_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
1282a5229c74SGary Mills     old_glob_t *pglob)
1283a5229c74SGary Mills {
1284a5229c74SGary Mills 
1285a5229c74SGary Mills 	glob_t gl;
1286a5229c74SGary Mills 	int rv;
1287a5229c74SGary Mills 
1288a5229c74SGary Mills 	flags &= GLOB_POSIX;
1289a5229c74SGary Mills 
1290a5229c74SGary Mills 	(void) memset(&gl, 0, sizeof (gl));
1291a5229c74SGary Mills 
1292a5229c74SGary Mills 	/*
1293a5229c74SGary Mills 	 * Copy all the members, old to new.  There's
1294a5229c74SGary Mills 	 * really no point in micro-optimizing the copying.
1295a5229c74SGary Mills 	 * Other members are set to zero.
1296a5229c74SGary Mills 	 */
1297a5229c74SGary Mills 	gl.gl_pathc = pglob->gl_pathc;
1298a5229c74SGary Mills 	gl.gl_pathv = pglob->gl_pathv;
1299a5229c74SGary Mills 	gl.gl_offs = pglob->gl_offs;
1300a5229c74SGary Mills 	gl.gl_pathp = pglob->gl_pathp;
1301a5229c74SGary Mills 	gl.gl_pathn = pglob->gl_pathn;
1302a5229c74SGary Mills 
1303a5229c74SGary Mills 	rv = _glob_ext(pattern, flags, errfunc, &gl);
1304a5229c74SGary Mills 
1305a5229c74SGary Mills 	/*
1306a5229c74SGary Mills 	 * Copy all the members, new to old.  There's
1307a5229c74SGary Mills 	 * really no point in micro-optimizing the copying.
1308a5229c74SGary Mills 	 */
1309a5229c74SGary Mills 	pglob->gl_pathc = gl.gl_pathc;
1310a5229c74SGary Mills 	pglob->gl_pathv = gl.gl_pathv;
1311a5229c74SGary Mills 	pglob->gl_offs = gl.gl_offs;
1312a5229c74SGary Mills 	pglob->gl_pathp = gl.gl_pathp;
1313a5229c74SGary Mills 	pglob->gl_pathn = gl.gl_pathn;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	return (rv);
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate 
1318a5229c74SGary Mills /* globfree() function with legacy glob structure */
1319a5229c74SGary Mills void
1320a5229c74SGary Mills old_globfree(old_glob_t *pglob)
1321a5229c74SGary Mills {
1322a5229c74SGary Mills 	glob_t gl;
1323a5229c74SGary Mills 
1324a5229c74SGary Mills 	(void) memset(&gl, 0, sizeof (gl));
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	/*
1327a5229c74SGary Mills 	 * Copy all the members, old to new.  There's
1328a5229c74SGary Mills 	 * really no point in micro-optimizing the copying.
1329a5229c74SGary Mills 	 * Other members are set to zero.
13307c478bd9Sstevel@tonic-gate 	 */
1331a5229c74SGary Mills 	gl.gl_pathc = pglob->gl_pathc;
1332a5229c74SGary Mills 	gl.gl_pathv = pglob->gl_pathv;
1333a5229c74SGary Mills 	gl.gl_offs = pglob->gl_offs;
1334a5229c74SGary Mills 	gl.gl_pathp = pglob->gl_pathp;
1335a5229c74SGary Mills 	gl.gl_pathn = pglob->gl_pathn;
13367c478bd9Sstevel@tonic-gate 
1337a5229c74SGary Mills 	_globfree_ext(&gl);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/*
1340a5229c74SGary Mills 	 * Copy all the members, new to old.  There's
1341a5229c74SGary Mills 	 * really no point in micro-optimizing the copying.
13427c478bd9Sstevel@tonic-gate 	 */
1343a5229c74SGary Mills 	pglob->gl_pathc = gl.gl_pathc;
1344a5229c74SGary Mills 	pglob->gl_pathv = gl.gl_pathv;
1345a5229c74SGary Mills 	pglob->gl_offs = gl.gl_offs;
1346a5229c74SGary Mills 	pglob->gl_pathp = gl.gl_pathp;
1347a5229c74SGary Mills 	pglob->gl_pathn = gl.gl_pathn;
1348a5229c74SGary Mills 
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate 
1351*33e8313dSRobert Mustacchi #endif	/* _LP64 || _FILE_OFFSET_BITS != 64 */
1352