1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * file name expansion - posix.2 glob with gnu and ast extensions
26da2e3ebdSchin  *
27da2e3ebdSchin  *	David Korn
28da2e3ebdSchin  *	Glenn Fowler
29da2e3ebdSchin  *	AT&T Research
30da2e3ebdSchin  */
31da2e3ebdSchin 
32da2e3ebdSchin #include <ast.h>
33da2e3ebdSchin #include <ls.h>
34da2e3ebdSchin #include <stak.h>
35da2e3ebdSchin #include <ast_dir.h>
36da2e3ebdSchin #include <error.h>
37da2e3ebdSchin #include <ctype.h>
38da2e3ebdSchin #include <regex.h>
39da2e3ebdSchin 
40da2e3ebdSchin #define GLOB_MAGIC	0xaaaa0000
41da2e3ebdSchin 
42da2e3ebdSchin #define MATCH_RAW	1
43da2e3ebdSchin #define MATCH_MAKE	2
44da2e3ebdSchin #define MATCH_META	4
45da2e3ebdSchin 
46da2e3ebdSchin #define MATCHPATH(g)	(offsetof(globlist_t,gl_path)+(g)->gl_extra)
47da2e3ebdSchin 
48da2e3ebdSchin typedef int (*GL_error_f)(const char*, int);
49da2e3ebdSchin typedef void* (*GL_opendir_f)(const char*);
50da2e3ebdSchin typedef struct dirent* (*GL_readdir_f)(void*);
51da2e3ebdSchin typedef void (*GL_closedir_f)(void*);
52da2e3ebdSchin typedef int (*GL_stat_f)(const char*, struct stat*);
53da2e3ebdSchin 
54da2e3ebdSchin #define _GLOB_PRIVATE_ \
55da2e3ebdSchin 	GL_error_f	gl_errfn; \
56da2e3ebdSchin 	int		gl_error; \
57da2e3ebdSchin 	char*		gl_nextpath; \
58da2e3ebdSchin 	globlist_t*	gl_rescan; \
59da2e3ebdSchin 	globlist_t*	gl_match; \
60da2e3ebdSchin 	Stak_t*		gl_stak; \
61da2e3ebdSchin 	int		re_flags; \
62*b30d1939SAndy Fiddaman 	int		re_first; \
63da2e3ebdSchin 	regex_t*	gl_ignore; \
64da2e3ebdSchin 	regex_t*	gl_ignorei; \
65da2e3ebdSchin 	regex_t		re_ignore; \
66da2e3ebdSchin 	regex_t		re_ignorei; \
67da2e3ebdSchin 	unsigned long	gl_starstar; \
68da2e3ebdSchin 	char*		gl_opt; \
69da2e3ebdSchin 	char*		gl_pat; \
70da2e3ebdSchin 	char*		gl_pad[4];
71da2e3ebdSchin 
72da2e3ebdSchin #include <glob.h>
73da2e3ebdSchin 
74da2e3ebdSchin /*
75da2e3ebdSchin  * default gl_diropen
76da2e3ebdSchin  */
77da2e3ebdSchin 
78da2e3ebdSchin static void*
gl_diropen(glob_t * gp,const char * path)79da2e3ebdSchin gl_diropen(glob_t* gp, const char* path)
80da2e3ebdSchin {
81da2e3ebdSchin 	return (*gp->gl_opendir)(path);
82da2e3ebdSchin }
83da2e3ebdSchin 
84da2e3ebdSchin /*
85da2e3ebdSchin  * default gl_dirnext
86da2e3ebdSchin  */
87da2e3ebdSchin 
88da2e3ebdSchin static char*
gl_dirnext(glob_t * gp,void * handle)89da2e3ebdSchin gl_dirnext(glob_t* gp, void* handle)
90da2e3ebdSchin {
91da2e3ebdSchin 	struct dirent*	dp;
92da2e3ebdSchin 
93da2e3ebdSchin 	while (dp = (struct dirent*)(*gp->gl_readdir)(handle))
94*b30d1939SAndy Fiddaman 	{
95da2e3ebdSchin #ifdef D_TYPE
96*b30d1939SAndy Fiddaman 		if (D_TYPE(dp) != DT_UNKNOWN && D_TYPE(dp) != DT_DIR && D_TYPE(dp) != DT_LNK)
97*b30d1939SAndy Fiddaman 			gp->gl_status |= GLOB_NOTDIR;
98da2e3ebdSchin #endif
99*b30d1939SAndy Fiddaman 		return dp->d_name;
100*b30d1939SAndy Fiddaman 	}
101da2e3ebdSchin 	return 0;
102da2e3ebdSchin }
103da2e3ebdSchin 
104da2e3ebdSchin /*
105da2e3ebdSchin  * default gl_dirclose
106da2e3ebdSchin  */
107da2e3ebdSchin 
108da2e3ebdSchin static void
gl_dirclose(glob_t * gp,void * handle)109da2e3ebdSchin gl_dirclose(glob_t* gp, void* handle)
110da2e3ebdSchin {
111da2e3ebdSchin 	(gp->gl_closedir)(handle);
112da2e3ebdSchin }
113da2e3ebdSchin 
114da2e3ebdSchin /*
115da2e3ebdSchin  * default gl_type
116da2e3ebdSchin  */
117da2e3ebdSchin 
118da2e3ebdSchin static int
gl_type(glob_t * gp,const char * path,int flags)1197c2fbfb3SApril Chin gl_type(glob_t* gp, const char* path, int flags)
120da2e3ebdSchin {
121da2e3ebdSchin 	register int	type;
122da2e3ebdSchin 	struct stat	st;
123da2e3ebdSchin 
1247c2fbfb3SApril Chin 	if ((flags & GLOB_STARSTAR) ? (*gp->gl_lstat)(path, &st) : (*gp->gl_stat)(path, &st))
125da2e3ebdSchin 		type = 0;
126da2e3ebdSchin 	else if (S_ISDIR(st.st_mode))
127da2e3ebdSchin 		type = GLOB_DIR;
128da2e3ebdSchin 	else if (!S_ISREG(st.st_mode))
129da2e3ebdSchin 		type = GLOB_DEV;
130da2e3ebdSchin 	else if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
131da2e3ebdSchin 		type = GLOB_EXE;
132da2e3ebdSchin 	else
133da2e3ebdSchin 		type = GLOB_REG;
134da2e3ebdSchin 	return type;
135da2e3ebdSchin }
136da2e3ebdSchin 
137da2e3ebdSchin /*
138da2e3ebdSchin  * default gl_attr
139da2e3ebdSchin  */
140da2e3ebdSchin 
141da2e3ebdSchin static int
gl_attr(glob_t * gp,const char * path,int flags)1427c2fbfb3SApril Chin gl_attr(glob_t* gp, const char* path, int flags)
143da2e3ebdSchin {
144da2e3ebdSchin 	return strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? GLOB_ICASE : 0;
145da2e3ebdSchin }
146da2e3ebdSchin 
147da2e3ebdSchin /*
148da2e3ebdSchin  * default gl_nextdir
149da2e3ebdSchin  */
150da2e3ebdSchin 
151da2e3ebdSchin static char*
gl_nextdir(glob_t * gp,char * dir)152da2e3ebdSchin gl_nextdir(glob_t* gp, char* dir)
153da2e3ebdSchin {
154da2e3ebdSchin 	if (!(dir = gp->gl_nextpath))
155da2e3ebdSchin 		dir = gp->gl_nextpath = stakcopy(pathbin());
156da2e3ebdSchin 	switch (*gp->gl_nextpath)
157da2e3ebdSchin 	{
158da2e3ebdSchin 	case 0:
159da2e3ebdSchin 		dir = 0;
160da2e3ebdSchin 		break;
161da2e3ebdSchin 	case ':':
162da2e3ebdSchin 		while (*gp->gl_nextpath == ':')
163da2e3ebdSchin 			gp->gl_nextpath++;
164da2e3ebdSchin 		dir = ".";
165da2e3ebdSchin 		break;
166da2e3ebdSchin 	default:
167da2e3ebdSchin 		while (*gp->gl_nextpath)
168da2e3ebdSchin 			if (*gp->gl_nextpath++ == ':')
169da2e3ebdSchin 			{
170da2e3ebdSchin 				*(gp->gl_nextpath - 1) = 0;
171da2e3ebdSchin 				break;
172da2e3ebdSchin 			}
173da2e3ebdSchin 		break;
174da2e3ebdSchin 	}
175da2e3ebdSchin 	return dir;
176da2e3ebdSchin }
177da2e3ebdSchin 
178da2e3ebdSchin /*
179da2e3ebdSchin  * error intercept
180da2e3ebdSchin  */
181da2e3ebdSchin 
182da2e3ebdSchin static int
errorcheck(register glob_t * gp,const char * path)183da2e3ebdSchin errorcheck(register glob_t* gp, const char* path)
184da2e3ebdSchin {
185da2e3ebdSchin 	int	r = 1;
186da2e3ebdSchin 
187da2e3ebdSchin 	if (gp->gl_errfn)
188da2e3ebdSchin 		r = (*gp->gl_errfn)(path, errno);
189da2e3ebdSchin 	if (gp->gl_flags & GLOB_ERR)
190da2e3ebdSchin 		r = 0;
191da2e3ebdSchin 	if (!r)
192da2e3ebdSchin 		gp->gl_error = GLOB_ABORTED;
193da2e3ebdSchin 	return r;
194da2e3ebdSchin }
195da2e3ebdSchin 
196da2e3ebdSchin /*
197da2e3ebdSchin  * remove backslashes
198da2e3ebdSchin  */
199da2e3ebdSchin 
200da2e3ebdSchin static void
trim(register char * sp,register char * p1,int * n1,register char * p2,int * n2)201da2e3ebdSchin trim(register char* sp, register char* p1, int* n1, register char* p2, int* n2)
202da2e3ebdSchin {
203da2e3ebdSchin 	register char*	dp = sp;
204da2e3ebdSchin 	register int	c;
205da2e3ebdSchin 
206da2e3ebdSchin 	if (p1)
207da2e3ebdSchin 		*n1 = 0;
208da2e3ebdSchin 	if (p2)
209da2e3ebdSchin 		*n2 = 0;
210da2e3ebdSchin 	do
211da2e3ebdSchin 	{
212*b30d1939SAndy Fiddaman 		if ((c = *sp++) == '\\')
213*b30d1939SAndy Fiddaman 			c = *sp++;
214da2e3ebdSchin 		if (sp == p1)
215da2e3ebdSchin 		{
216da2e3ebdSchin 			p1 = 0;
217da2e3ebdSchin 			*n1 = sp - dp - 1;
218da2e3ebdSchin 		}
219da2e3ebdSchin 		if (sp == p2)
220da2e3ebdSchin 		{
221da2e3ebdSchin 			p2 = 0;
222da2e3ebdSchin 			*n2 = sp - dp - 1;
223da2e3ebdSchin 		}
224da2e3ebdSchin 	} while (*dp++ = c);
225da2e3ebdSchin }
226da2e3ebdSchin 
227da2e3ebdSchin static void
addmatch(register glob_t * gp,const char * dir,const char * pat,register const char * rescan,char * endslash,int meta)228da2e3ebdSchin addmatch(register glob_t* gp, const char* dir, const char* pat, register const char* rescan, char* endslash, int meta)
229da2e3ebdSchin {
230da2e3ebdSchin 	register globlist_t*	ap;
231da2e3ebdSchin 	int			offset;
232da2e3ebdSchin 	int			type;
233da2e3ebdSchin 
234da2e3ebdSchin 	stakseek(MATCHPATH(gp));
235da2e3ebdSchin 	if (dir)
236da2e3ebdSchin 	{
237da2e3ebdSchin 		stakputs(dir);
238da2e3ebdSchin 		stakputc(gp->gl_delim);
239da2e3ebdSchin 	}
240da2e3ebdSchin 	if (endslash)
241da2e3ebdSchin 		*endslash = 0;
242da2e3ebdSchin 	stakputs(pat);
243da2e3ebdSchin 	if (rescan)
244da2e3ebdSchin 	{
2457c2fbfb3SApril Chin 		if ((*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0) != GLOB_DIR)
246da2e3ebdSchin 			return;
247da2e3ebdSchin 		stakputc(gp->gl_delim);
248da2e3ebdSchin 		offset = staktell();
249da2e3ebdSchin 		/* if null, reserve room for . */
250da2e3ebdSchin 		if (*rescan)
251da2e3ebdSchin 			stakputs(rescan);
252da2e3ebdSchin 		else
253da2e3ebdSchin 			stakputc(0);
254da2e3ebdSchin 		stakputc(0);
255da2e3ebdSchin 		rescan = stakptr(offset);
256da2e3ebdSchin 		ap = (globlist_t*)stakfreeze(0);
257da2e3ebdSchin 		ap->gl_begin = (char*)rescan;
258da2e3ebdSchin 		ap->gl_next = gp->gl_rescan;
259da2e3ebdSchin 		gp->gl_rescan = ap;
260da2e3ebdSchin 	}
261da2e3ebdSchin 	else
262da2e3ebdSchin 	{
2637c2fbfb3SApril Chin 		if (!endslash && (gp->gl_flags & GLOB_MARK) && (type = (*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0)))
264da2e3ebdSchin 		{
265da2e3ebdSchin 			if ((gp->gl_flags & GLOB_COMPLETE) && type != GLOB_EXE)
266da2e3ebdSchin 			{
267da2e3ebdSchin 				stakseek(0);
268da2e3ebdSchin 				return;
269da2e3ebdSchin 			}
270da2e3ebdSchin 			else if (type == GLOB_DIR && (gp->gl_flags & GLOB_MARK))
271da2e3ebdSchin 				stakputc(gp->gl_delim);
272da2e3ebdSchin 		}
273da2e3ebdSchin 		ap = (globlist_t*)stakfreeze(1);
274da2e3ebdSchin 		ap->gl_next = gp->gl_match;
275da2e3ebdSchin 		gp->gl_match = ap;
276da2e3ebdSchin 		gp->gl_pathc++;
277da2e3ebdSchin 	}
278da2e3ebdSchin 	ap->gl_flags = MATCH_RAW|meta;
279da2e3ebdSchin 	if (gp->gl_flags & GLOB_COMPLETE)
280da2e3ebdSchin 		ap->gl_flags |= MATCH_MAKE;
281da2e3ebdSchin }
282da2e3ebdSchin 
283da2e3ebdSchin /*
284da2e3ebdSchin  * this routine builds a list of files that match a given pathname
285da2e3ebdSchin  * uses REG_SHELL of <regex> to match each component
286da2e3ebdSchin  * a leading . must match explicitly
287da2e3ebdSchin  */
288da2e3ebdSchin 
289da2e3ebdSchin static void
glob_dir(glob_t * gp,globlist_t * ap,int re_flags)290*b30d1939SAndy Fiddaman glob_dir(glob_t* gp, globlist_t* ap, int re_flags)
291da2e3ebdSchin {
292da2e3ebdSchin 	register char*		rescan;
293da2e3ebdSchin 	register char*		prefix;
294da2e3ebdSchin 	register char*		pat;
295da2e3ebdSchin 	register char*		name;
296da2e3ebdSchin 	register int		c;
297da2e3ebdSchin 	char*			dirname;
298da2e3ebdSchin 	void*			dirf;
299da2e3ebdSchin 	char			first;
300da2e3ebdSchin 	regex_t*		ire;
301da2e3ebdSchin 	regex_t*		pre;
302da2e3ebdSchin 	regex_t			rec;
303da2e3ebdSchin 	regex_t			rei;
304da2e3ebdSchin 	int			notdir;
305da2e3ebdSchin 	int			t1;
306da2e3ebdSchin 	int			t2;
307da2e3ebdSchin 	int			bracket;
308da2e3ebdSchin 
309da2e3ebdSchin 	int			anymeta = ap->gl_flags & MATCH_META;
310da2e3ebdSchin 	int			complete = 0;
311da2e3ebdSchin 	int			err = 0;
312da2e3ebdSchin 	int			meta = ((gp->re_flags & REG_ICASE) && *ap->gl_begin != '/') ? MATCH_META : 0;
313da2e3ebdSchin 	int			quote = 0;
314da2e3ebdSchin 	int			savequote = 0;
315da2e3ebdSchin 	char*			restore1 = 0;
316da2e3ebdSchin 	char*			restore2 = 0;
317da2e3ebdSchin 	regex_t*		prec = 0;
318da2e3ebdSchin 	regex_t*		prei = 0;
319da2e3ebdSchin 	char*			matchdir = 0;
320da2e3ebdSchin 	int			starstar = 0;
321da2e3ebdSchin 
322da2e3ebdSchin 	if (*gp->gl_intr)
323da2e3ebdSchin 	{
324da2e3ebdSchin 		gp->gl_error = GLOB_INTR;
325da2e3ebdSchin 		return;
326da2e3ebdSchin 	}
327da2e3ebdSchin 	pat = rescan = ap->gl_begin;
328da2e3ebdSchin 	prefix = dirname = ap->gl_path + gp->gl_extra;
329da2e3ebdSchin 	first = (rescan == prefix);
330da2e3ebdSchin again:
331da2e3ebdSchin 	bracket = 0;
332da2e3ebdSchin 	for (;;)
333da2e3ebdSchin 	{
334da2e3ebdSchin 		switch (c = *rescan++)
335da2e3ebdSchin 		{
336da2e3ebdSchin 		case 0:
337da2e3ebdSchin 			if (meta)
338da2e3ebdSchin 			{
339da2e3ebdSchin 				rescan = 0;
340da2e3ebdSchin 				break;
341da2e3ebdSchin 			}
342da2e3ebdSchin 			if (quote)
343da2e3ebdSchin 			{
344da2e3ebdSchin 				trim(ap->gl_begin, rescan, &t1, NiL, NiL);
345da2e3ebdSchin 				rescan -= t1;
346da2e3ebdSchin 			}
347da2e3ebdSchin 			if (!first && !*rescan && *(rescan - 2) == gp->gl_delim)
348da2e3ebdSchin 			{
349da2e3ebdSchin 				*(rescan - 2) = 0;
3507c2fbfb3SApril Chin 				c = (*gp->gl_type)(gp, prefix, 0);
351da2e3ebdSchin 				*(rescan - 2) = gp->gl_delim;
352da2e3ebdSchin 				if (c == GLOB_DIR)
353da2e3ebdSchin 					addmatch(gp, NiL, prefix, NiL, rescan - 1, anymeta);
354da2e3ebdSchin 			}
3557c2fbfb3SApril Chin 			else if ((anymeta || !(gp->gl_flags & GLOB_NOCHECK)) && (*gp->gl_type)(gp, prefix, 0))
356da2e3ebdSchin 				addmatch(gp, NiL, prefix, NiL, NiL, anymeta);
357da2e3ebdSchin 			return;
358da2e3ebdSchin 		case '[':
359da2e3ebdSchin 			if (!bracket)
360da2e3ebdSchin 			{
361da2e3ebdSchin 				bracket = MATCH_META;
362da2e3ebdSchin 				if (*rescan == '!' || *rescan == '^')
363da2e3ebdSchin 					rescan++;
364da2e3ebdSchin 				if (*rescan == ']')
365da2e3ebdSchin 					rescan++;
366da2e3ebdSchin 			}
367da2e3ebdSchin 			continue;
368da2e3ebdSchin 		case ']':
369da2e3ebdSchin 			meta |= bracket;
370da2e3ebdSchin 			continue;
371da2e3ebdSchin 		case '(':
372da2e3ebdSchin 			if (!(gp->gl_flags & GLOB_AUGMENTED))
373da2e3ebdSchin 				continue;
3745c16836eSToomas Soome 			/* FALLTHROUGH */
375da2e3ebdSchin 		case '*':
376da2e3ebdSchin 		case '?':
377da2e3ebdSchin 			meta = MATCH_META;
378da2e3ebdSchin 			continue;
379da2e3ebdSchin 		case '\\':
380da2e3ebdSchin 			if (!(gp->gl_flags & GLOB_NOESCAPE))
381da2e3ebdSchin 			{
382da2e3ebdSchin 				quote = 1;
383da2e3ebdSchin 				if (*rescan)
384da2e3ebdSchin 					rescan++;
385da2e3ebdSchin 			}
386da2e3ebdSchin 			continue;
387da2e3ebdSchin 		default:
388da2e3ebdSchin 			if (c == gp->gl_delim)
389da2e3ebdSchin 			{
390da2e3ebdSchin 				if (meta)
391da2e3ebdSchin 					break;
392da2e3ebdSchin 				pat = rescan;
393da2e3ebdSchin 				bracket = 0;
394da2e3ebdSchin 				savequote = quote;
395da2e3ebdSchin 			}
396da2e3ebdSchin 			continue;
397da2e3ebdSchin 		}
398da2e3ebdSchin 		break;
399da2e3ebdSchin 	}
400da2e3ebdSchin 	anymeta |= meta;
401da2e3ebdSchin 	if (matchdir)
402da2e3ebdSchin 		goto skip;
403da2e3ebdSchin 	if (pat == prefix)
404da2e3ebdSchin 	{
405da2e3ebdSchin 		prefix = 0;
406da2e3ebdSchin 		if (!rescan && (gp->gl_flags & GLOB_COMPLETE))
407da2e3ebdSchin 		{
408da2e3ebdSchin 			complete = 1;
409da2e3ebdSchin 			dirname = 0;
410da2e3ebdSchin 		}
411da2e3ebdSchin 		else
412da2e3ebdSchin 			dirname = ".";
413da2e3ebdSchin 	}
414da2e3ebdSchin 	else
415da2e3ebdSchin 	{
416da2e3ebdSchin 		if (pat == prefix + 1)
417da2e3ebdSchin 			dirname = "/";
418da2e3ebdSchin 		if (savequote)
419da2e3ebdSchin 		{
420da2e3ebdSchin 			quote = 0;
421da2e3ebdSchin 			trim(ap->gl_begin, pat, &t1, rescan, &t2);
422da2e3ebdSchin 			pat -= t1;
423da2e3ebdSchin 			if (rescan)
424da2e3ebdSchin 				rescan -= t2;
425da2e3ebdSchin 		}
426da2e3ebdSchin 		*(restore1 = pat - 1) = 0;
427da2e3ebdSchin 	}
428da2e3ebdSchin 	if (!complete && (gp->gl_flags & GLOB_STARSTAR))
429da2e3ebdSchin 		while (pat[0] == '*' && pat[1] == '*' && (pat[2] == '/'  || pat[2]==0))
430da2e3ebdSchin 		{
431da2e3ebdSchin 			matchdir = pat;
432da2e3ebdSchin 			if (pat[2])
433da2e3ebdSchin 			{
434da2e3ebdSchin 				pat += 3;
435*b30d1939SAndy Fiddaman 				while (*pat=='/')
436*b30d1939SAndy Fiddaman 					pat++;
437da2e3ebdSchin 				if (*pat)
438da2e3ebdSchin 					continue;
439da2e3ebdSchin 			}
440da2e3ebdSchin 			rescan = *pat?0:pat;
441da2e3ebdSchin 			pat = "*";
442da2e3ebdSchin 			goto skip;
443da2e3ebdSchin 		}
444da2e3ebdSchin 	if (matchdir)
445da2e3ebdSchin 	{
446da2e3ebdSchin 		rescan = pat;
447da2e3ebdSchin 		goto again;
448da2e3ebdSchin 	}
449da2e3ebdSchin skip:
450da2e3ebdSchin 	if (rescan)
451da2e3ebdSchin 		*(restore2 = rescan - 1) = 0;
452da2e3ebdSchin 	if (rescan && !complete && (gp->gl_flags & GLOB_STARSTAR))
453da2e3ebdSchin 	{
454*b30d1939SAndy Fiddaman 		register char*	p = rescan;
455*b30d1939SAndy Fiddaman 
456da2e3ebdSchin 		while (p[0] == '*' && p[1] == '*' && (p[2] == '/'  || p[2]==0))
457da2e3ebdSchin 		{
458da2e3ebdSchin 			rescan = p;
459da2e3ebdSchin 			if (starstar = (p[2]==0))
460da2e3ebdSchin 				break;
461da2e3ebdSchin 			p += 3;
462da2e3ebdSchin 			while (*p=='/')
463da2e3ebdSchin 				p++;
464da2e3ebdSchin 			if (*p==0)
465da2e3ebdSchin 			{
466da2e3ebdSchin 				starstar = 2;
467da2e3ebdSchin 				break;
468da2e3ebdSchin 			}
469da2e3ebdSchin 		}
470da2e3ebdSchin 	}
471da2e3ebdSchin 	if (matchdir)
472da2e3ebdSchin 		gp->gl_starstar++;
473da2e3ebdSchin 	if (gp->gl_opt)
474da2e3ebdSchin 		pat = strcpy(gp->gl_opt, pat);
475da2e3ebdSchin 	for (;;)
476da2e3ebdSchin 	{
477da2e3ebdSchin 		if (complete)
478da2e3ebdSchin 		{
479da2e3ebdSchin 			if (!(dirname = (*gp->gl_nextdir)(gp, dirname)))
480da2e3ebdSchin 				break;
481da2e3ebdSchin 			prefix = streq(dirname, ".") ? (char*)0 : dirname;
482da2e3ebdSchin 		}
4837c2fbfb3SApril Chin 		if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
484da2e3ebdSchin 		{
4857c2fbfb3SApril Chin 			if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
486da2e3ebdSchin 			{
487da2e3ebdSchin 				if (!prei)
488da2e3ebdSchin 				{
489da2e3ebdSchin 					if (err = regcomp(&rei, pat, gp->re_flags|REG_ICASE))
490da2e3ebdSchin 						break;
491da2e3ebdSchin 					prei = &rei;
492*b30d1939SAndy Fiddaman 					if (gp->re_first)
493da2e3ebdSchin 					{
494*b30d1939SAndy Fiddaman 						gp->re_first = 0;
495*b30d1939SAndy Fiddaman 						gp->re_flags = regstat(prei)->re_flags & ~REG_ICASE;
496da2e3ebdSchin 					}
497da2e3ebdSchin 				}
498*b30d1939SAndy Fiddaman 				pre = prei;
499da2e3ebdSchin 			}
500da2e3ebdSchin 			else
501da2e3ebdSchin 			{
502da2e3ebdSchin 				if (!prec)
503da2e3ebdSchin 				{
504da2e3ebdSchin 					if (err = regcomp(&rec, pat, gp->re_flags))
505da2e3ebdSchin 						break;
506da2e3ebdSchin 					prec = &rec;
507*b30d1939SAndy Fiddaman 					if (gp->re_first)
508*b30d1939SAndy Fiddaman 					{
509*b30d1939SAndy Fiddaman 						gp->re_first = 0;
510*b30d1939SAndy Fiddaman 						gp->re_flags = regstat(prec)->re_flags;
511*b30d1939SAndy Fiddaman 					}
512da2e3ebdSchin 				}
513da2e3ebdSchin 				pre = prec;
514*b30d1939SAndy Fiddaman 			}
515*b30d1939SAndy Fiddaman 			if ((ire = gp->gl_ignore) && (gp->re_flags & REG_ICASE))
516*b30d1939SAndy Fiddaman 			{
517*b30d1939SAndy Fiddaman 				if (!gp->gl_ignorei)
518*b30d1939SAndy Fiddaman 				{
519*b30d1939SAndy Fiddaman 					if (regcomp(&gp->re_ignorei, gp->gl_fignore, re_flags|REG_ICASE))
520*b30d1939SAndy Fiddaman 					{
521*b30d1939SAndy Fiddaman 						gp->gl_error = GLOB_APPERR;
522*b30d1939SAndy Fiddaman 						break;
523*b30d1939SAndy Fiddaman 					}
524*b30d1939SAndy Fiddaman 					gp->gl_ignorei = &gp->re_ignorei;
525*b30d1939SAndy Fiddaman 				}
526*b30d1939SAndy Fiddaman 				ire = gp->gl_ignorei;
527da2e3ebdSchin 			}
528da2e3ebdSchin 			if (restore2)
529da2e3ebdSchin 				*restore2 = gp->gl_delim;
530da2e3ebdSchin 			while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
531da2e3ebdSchin 			{
532da2e3ebdSchin 				if (notdir = (gp->gl_status & GLOB_NOTDIR))
533da2e3ebdSchin 					gp->gl_status &= ~GLOB_NOTDIR;
534da2e3ebdSchin 				if (ire && !regexec(ire, name, 0, NiL, 0))
535da2e3ebdSchin 					continue;
536da2e3ebdSchin 				if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
537da2e3ebdSchin 					addmatch(gp, prefix, name, matchdir, NiL, anymeta);
538da2e3ebdSchin 				if (!regexec(pre, name, 0, NiL, 0))
539da2e3ebdSchin 				{
540da2e3ebdSchin 					if (!rescan || !notdir)
541da2e3ebdSchin 						addmatch(gp, prefix, name, rescan, NiL, anymeta);
542da2e3ebdSchin 					if (starstar==1 || (starstar==2 && !notdir))
543da2e3ebdSchin 						addmatch(gp, prefix, name, starstar==2?"":NiL, NiL, anymeta);
544da2e3ebdSchin 				}
545da2e3ebdSchin 				errno = 0;
546da2e3ebdSchin 			}
547da2e3ebdSchin 			(*gp->gl_dirclose)(gp, dirf);
548da2e3ebdSchin 			if (err || errno && !errorcheck(gp, dirname))
549da2e3ebdSchin 				break;
550da2e3ebdSchin 		}
551da2e3ebdSchin 		else if (!complete && !errorcheck(gp, dirname))
552da2e3ebdSchin 			break;
553da2e3ebdSchin 		if (!complete)
554da2e3ebdSchin 			break;
555da2e3ebdSchin 		if (*gp->gl_intr)
556da2e3ebdSchin 		{
557da2e3ebdSchin 			gp->gl_error = GLOB_INTR;
558da2e3ebdSchin 			break;
559da2e3ebdSchin 		}
560da2e3ebdSchin 	}
561da2e3ebdSchin 	if (restore1)
562da2e3ebdSchin 		*restore1 = gp->gl_delim;
563da2e3ebdSchin 	if (restore2)
564da2e3ebdSchin 		*restore2 = gp->gl_delim;
565da2e3ebdSchin 	if (prec)
566da2e3ebdSchin 		regfree(prec);
567da2e3ebdSchin 	if (prei)
568da2e3ebdSchin 		regfree(prei);
569da2e3ebdSchin 	if (err == REG_ESPACE)
570da2e3ebdSchin 		gp->gl_error = GLOB_NOSPACE;
571da2e3ebdSchin }
572da2e3ebdSchin 
573f3618278SToomas Soome static void
_closedir(void * ptr)574f3618278SToomas Soome _closedir(void *ptr)
575f3618278SToomas Soome {
576f3618278SToomas Soome 	(void) closedir(ptr);
577f3618278SToomas Soome }
578f3618278SToomas Soome 
579da2e3ebdSchin int
glob(const char * pattern,int flags,int (* errfn)(const char *,int),register glob_t * gp)580da2e3ebdSchin glob(const char* pattern, int flags, int (*errfn)(const char*, int), register glob_t* gp)
581da2e3ebdSchin {
582da2e3ebdSchin 	register globlist_t*	ap;
583da2e3ebdSchin 	register char*		pat;
584da2e3ebdSchin 	globlist_t*		top;
585da2e3ebdSchin 	Stak_t*			oldstak;
586da2e3ebdSchin 	char**			argv;
587da2e3ebdSchin 	char**			av;
588da2e3ebdSchin 	size_t			skip;
589da2e3ebdSchin 	unsigned long		f;
590da2e3ebdSchin 	int			n;
591da2e3ebdSchin 	int			x;
592*b30d1939SAndy Fiddaman 	int			re_flags;
593da2e3ebdSchin 
594da2e3ebdSchin 	const char*		nocheck = pattern;
595da2e3ebdSchin 	int			optlen = 0;
596da2e3ebdSchin 	int			suflen = 0;
597da2e3ebdSchin 	int			extra = 1;
598da2e3ebdSchin 	unsigned char		intr = 0;
599da2e3ebdSchin 
600da2e3ebdSchin 	gp->gl_rescan = 0;
601da2e3ebdSchin 	gp->gl_error = 0;
602da2e3ebdSchin 	gp->gl_errfn = errfn;
603da2e3ebdSchin 	if (flags & GLOB_APPEND)
604da2e3ebdSchin 	{
605da2e3ebdSchin 		if ((gp->gl_flags |= GLOB_APPEND) ^ (flags|GLOB_MAGIC))
606da2e3ebdSchin 			return GLOB_APPERR;
607da2e3ebdSchin 		if (((gp->gl_flags & GLOB_STACK) == 0) == (gp->gl_stak == 0))
608da2e3ebdSchin 			return GLOB_APPERR;
609da2e3ebdSchin 		if (gp->gl_starstar > 1)
610da2e3ebdSchin 			gp->gl_flags |= GLOB_STARSTAR;
611da2e3ebdSchin 		else
612da2e3ebdSchin 			gp->gl_starstar = 0;
613da2e3ebdSchin 	}
614da2e3ebdSchin 	else
615da2e3ebdSchin 	{
616da2e3ebdSchin 		gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
617da2e3ebdSchin 		gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
618da2e3ebdSchin 		gp->gl_pathc = 0;
619da2e3ebdSchin 		gp->gl_ignore = 0;
620da2e3ebdSchin 		gp->gl_ignorei = 0;
621da2e3ebdSchin 		gp->gl_starstar = 0;
622da2e3ebdSchin 		if (!(flags & GLOB_DISC))
623da2e3ebdSchin 		{
624da2e3ebdSchin 			gp->gl_fignore = 0;
625da2e3ebdSchin 			gp->gl_suffix = 0;
626da2e3ebdSchin 			gp->gl_intr = 0;
627da2e3ebdSchin 			gp->gl_delim = 0;
628da2e3ebdSchin 			gp->gl_handle = 0;
629da2e3ebdSchin 			gp->gl_diropen = 0;
630da2e3ebdSchin 			gp->gl_dirnext = 0;
631da2e3ebdSchin 			gp->gl_dirclose = 0;
632da2e3ebdSchin 			gp->gl_type = 0;
633da2e3ebdSchin 			gp->gl_attr = 0;
634da2e3ebdSchin 			gp->gl_nextdir = 0;
635da2e3ebdSchin 			gp->gl_stat = 0;
6367c2fbfb3SApril Chin 			gp->gl_lstat = 0;
637da2e3ebdSchin 			gp->gl_extra = 0;
638da2e3ebdSchin 		}
639da2e3ebdSchin 		if (!(flags & GLOB_ALTDIRFUNC))
640da2e3ebdSchin 		{
641da2e3ebdSchin 			gp->gl_opendir = (GL_opendir_f)opendir;
642da2e3ebdSchin 			gp->gl_readdir = (GL_readdir_f)readdir;
643f3618278SToomas Soome 			gp->gl_closedir = _closedir;
644da2e3ebdSchin 			if (!gp->gl_stat)
6457c2fbfb3SApril Chin 				gp->gl_stat = (GL_stat_f)pathstat;
646da2e3ebdSchin 		}
6477c2fbfb3SApril Chin 		if (!gp->gl_lstat)
6487c2fbfb3SApril Chin 			gp->gl_lstat = (GL_stat_f)lstat;
649da2e3ebdSchin 		if (!gp->gl_intr)
650da2e3ebdSchin 			gp->gl_intr = &intr;
651da2e3ebdSchin 		if (!gp->gl_delim)
652da2e3ebdSchin 			gp->gl_delim = '/';
653da2e3ebdSchin 		if (!gp->gl_diropen)
654da2e3ebdSchin 			gp->gl_diropen = gl_diropen;
655da2e3ebdSchin 		if (!gp->gl_dirnext)
656da2e3ebdSchin 			gp->gl_dirnext = gl_dirnext;
657da2e3ebdSchin 		if (!gp->gl_dirclose)
658da2e3ebdSchin 			gp->gl_dirclose = gl_dirclose;
659da2e3ebdSchin 		if (!gp->gl_type)
660da2e3ebdSchin 			gp->gl_type = gl_type;
661da2e3ebdSchin 		if (!gp->gl_attr)
662da2e3ebdSchin 			gp->gl_attr = gl_attr;
663*b30d1939SAndy Fiddaman 		if (flags & GLOB_GROUP)
664*b30d1939SAndy Fiddaman 			gp->re_flags |= REG_SHELL_GROUP;
665da2e3ebdSchin 		if (flags & GLOB_ICASE)
666da2e3ebdSchin 			gp->re_flags |= REG_ICASE;
667da2e3ebdSchin 		if (!gp->gl_fignore)
668da2e3ebdSchin 			gp->re_flags |= REG_SHELL_DOT;
669da2e3ebdSchin 		else if (*gp->gl_fignore)
670da2e3ebdSchin 		{
671da2e3ebdSchin 			if (regcomp(&gp->re_ignore, gp->gl_fignore, gp->re_flags))
672da2e3ebdSchin 				return GLOB_APPERR;
673da2e3ebdSchin 			gp->gl_ignore = &gp->re_ignore;
674da2e3ebdSchin 		}
675da2e3ebdSchin 		if (gp->gl_flags & GLOB_STACK)
676da2e3ebdSchin 			gp->gl_stak = 0;
677da2e3ebdSchin 		else if (!(gp->gl_stak = stakcreate(0)))
678da2e3ebdSchin 			return GLOB_NOSPACE;
679da2e3ebdSchin 		if ((gp->gl_flags & GLOB_COMPLETE) && !gp->gl_nextdir)
680da2e3ebdSchin 			gp->gl_nextdir = gl_nextdir;
681da2e3ebdSchin 	}
682da2e3ebdSchin 	skip = gp->gl_pathc;
683da2e3ebdSchin 	if (gp->gl_stak)
684da2e3ebdSchin 		oldstak = stakinstall(gp->gl_stak, 0);
685da2e3ebdSchin 	if (flags & GLOB_DOOFFS)
686da2e3ebdSchin 		extra += gp->gl_offs;
687da2e3ebdSchin 	if (gp->gl_suffix)
688da2e3ebdSchin 		suflen =  strlen(gp->gl_suffix);
689da2e3ebdSchin 	if (*(pat = (char*)pattern) == '~' && *(pat + 1) == '(')
690da2e3ebdSchin 	{
691da2e3ebdSchin 		f = gp->gl_flags;
692da2e3ebdSchin 		n = 1;
693da2e3ebdSchin 		x = 1;
694da2e3ebdSchin 		pat += 2;
695da2e3ebdSchin 		for (;;)
696da2e3ebdSchin 		{
697da2e3ebdSchin 			switch (*pat++)
698da2e3ebdSchin 			{
699da2e3ebdSchin 			case 0:
700da2e3ebdSchin 			case ':':
701da2e3ebdSchin 				break;
702da2e3ebdSchin 			case '-':
703da2e3ebdSchin 				n = 0;
704da2e3ebdSchin 				continue;
705da2e3ebdSchin 			case '+':
706da2e3ebdSchin 				n = 1;
707da2e3ebdSchin 				continue;
708da2e3ebdSchin 			case 'i':
709da2e3ebdSchin 				if (n)
710da2e3ebdSchin 					f |= GLOB_ICASE;
711da2e3ebdSchin 				else
712da2e3ebdSchin 					f &= ~GLOB_ICASE;
713da2e3ebdSchin 				continue;
714da2e3ebdSchin 			case 'M':
715da2e3ebdSchin 				if (n)
716da2e3ebdSchin 					f |= GLOB_BRACE;
717da2e3ebdSchin 				else
718da2e3ebdSchin 					f &= ~GLOB_BRACE;
719da2e3ebdSchin 				continue;
720da2e3ebdSchin 			case 'N':
721da2e3ebdSchin 				if (n)
722da2e3ebdSchin 					f &= ~GLOB_NOCHECK;
723da2e3ebdSchin 				else
724da2e3ebdSchin 					f |= GLOB_NOCHECK;
725da2e3ebdSchin 				continue;
7267c2fbfb3SApril Chin 			case 'O':
727da2e3ebdSchin 				if (n)
728da2e3ebdSchin 					f |= GLOB_STARSTAR;
729da2e3ebdSchin 				else
730da2e3ebdSchin 					f &= ~GLOB_STARSTAR;
731da2e3ebdSchin 				continue;
732da2e3ebdSchin 			case ')':
733da2e3ebdSchin 				flags = (gp->gl_flags = f) & 0xffff;
734da2e3ebdSchin 				if (f & GLOB_ICASE)
735da2e3ebdSchin 					gp->re_flags |= REG_ICASE;
736da2e3ebdSchin 				else
737da2e3ebdSchin 					gp->re_flags &= ~REG_ICASE;
738da2e3ebdSchin 				if (x)
739da2e3ebdSchin 					optlen = pat - (char*)pattern;
740da2e3ebdSchin 				break;
741da2e3ebdSchin 			default:
742da2e3ebdSchin 				x = 0;
743da2e3ebdSchin 				continue;
744da2e3ebdSchin 			}
745da2e3ebdSchin 			break;
746da2e3ebdSchin 		}
747da2e3ebdSchin 	}
748da2e3ebdSchin 	top = ap = (globlist_t*)stakalloc((optlen ? 2 : 1) * strlen(pattern) + sizeof(globlist_t) + suflen + gp->gl_extra);
749da2e3ebdSchin 	ap->gl_next = 0;
750da2e3ebdSchin 	ap->gl_flags = 0;
751da2e3ebdSchin 	ap->gl_begin = ap->gl_path + gp->gl_extra;
752da2e3ebdSchin 	pat = strcopy(ap->gl_begin, pattern + optlen);
753da2e3ebdSchin 	if (suflen)
754da2e3ebdSchin 		pat = strcopy(pat, gp->gl_suffix);
755*b30d1939SAndy Fiddaman 	if (optlen)
756*b30d1939SAndy Fiddaman 		strlcpy(gp->gl_pat = gp->gl_opt = pat + 1, pattern, optlen);
757*b30d1939SAndy Fiddaman 	else
758*b30d1939SAndy Fiddaman 		gp->gl_pat = 0;
759da2e3ebdSchin 	suflen = 0;
760da2e3ebdSchin 	if (!(flags & GLOB_LIST))
761da2e3ebdSchin 		gp->gl_match = 0;
762*b30d1939SAndy Fiddaman 	re_flags = gp->re_flags;
763*b30d1939SAndy Fiddaman 	gp->re_first = 1;
764da2e3ebdSchin 	do
765da2e3ebdSchin 	{
766da2e3ebdSchin 		gp->gl_rescan = ap->gl_next;
767*b30d1939SAndy Fiddaman 		glob_dir(gp, ap, re_flags);
768da2e3ebdSchin 	} while (!gp->gl_error && (ap = gp->gl_rescan));
769*b30d1939SAndy Fiddaman 	gp->re_flags = re_flags;
770da2e3ebdSchin 	if (gp->gl_pathc == skip)
771da2e3ebdSchin 	{
772da2e3ebdSchin 		if (flags & GLOB_NOCHECK)
773da2e3ebdSchin 		{
774da2e3ebdSchin 			gp->gl_pathc++;
775da2e3ebdSchin 			top->gl_next = gp->gl_match;
776da2e3ebdSchin 			gp->gl_match = top;
777da2e3ebdSchin 			strcopy(top->gl_path + gp->gl_extra, nocheck);
778da2e3ebdSchin 		}
779da2e3ebdSchin 		else
780da2e3ebdSchin 			gp->gl_error = GLOB_NOMATCH;
781da2e3ebdSchin 	}
782da2e3ebdSchin 	if (flags & GLOB_LIST)
783da2e3ebdSchin 		gp->gl_list = gp->gl_match;
784da2e3ebdSchin 	else
785da2e3ebdSchin 	{
786da2e3ebdSchin 		argv = (char**)stakalloc((gp->gl_pathc + extra) * sizeof(char*));
787da2e3ebdSchin 		if (gp->gl_flags & GLOB_APPEND)
788da2e3ebdSchin 		{
789da2e3ebdSchin 			skip += --extra;
790da2e3ebdSchin 			memcpy(argv, gp->gl_pathv, skip * sizeof(char*));
791da2e3ebdSchin 			av = argv + skip;
792da2e3ebdSchin 		}
793da2e3ebdSchin 		else
794da2e3ebdSchin 		{
795da2e3ebdSchin 			av = argv;
796da2e3ebdSchin 			while (--extra > 0)
797da2e3ebdSchin 				*av++ = 0;
798da2e3ebdSchin 		}
799da2e3ebdSchin 		gp->gl_pathv = argv;
800da2e3ebdSchin 		argv = av;
801da2e3ebdSchin 		ap = gp->gl_match;
802da2e3ebdSchin 		while (ap)
803da2e3ebdSchin 		{
804da2e3ebdSchin 			*argv++ = ap->gl_path + gp->gl_extra;
805da2e3ebdSchin 			ap = ap->gl_next;
806da2e3ebdSchin 		}
807da2e3ebdSchin 		*argv = 0;
808da2e3ebdSchin 		if (!(flags & GLOB_NOSORT) && (argv - av) > 1)
809da2e3ebdSchin 		{
810da2e3ebdSchin 			strsort(av, argv - av, strcoll);
811da2e3ebdSchin 			if (gp->gl_starstar > 1)
812da2e3ebdSchin 				av[gp->gl_pathc = struniq(av, argv - av)] = 0;
813da2e3ebdSchin 			gp->gl_starstar = 0;
814da2e3ebdSchin 		}
815da2e3ebdSchin 	}
816da2e3ebdSchin 	if (gp->gl_starstar > 1)
817da2e3ebdSchin 		gp->gl_flags &= ~GLOB_STARSTAR;
818da2e3ebdSchin 	if (gp->gl_stak)
819da2e3ebdSchin 		stakinstall(oldstak, 0);
820da2e3ebdSchin 	return gp->gl_error;
821da2e3ebdSchin }
822da2e3ebdSchin 
823da2e3ebdSchin void
globfree(glob_t * gp)824da2e3ebdSchin globfree(glob_t* gp)
825da2e3ebdSchin {
826da2e3ebdSchin 	if ((gp->gl_flags & GLOB_MAGIC) == GLOB_MAGIC)
827da2e3ebdSchin 	{
828da2e3ebdSchin 		gp->gl_flags &= ~GLOB_MAGIC;
829da2e3ebdSchin 		if (gp->gl_stak)
830da2e3ebdSchin 			stkclose(gp->gl_stak);
831da2e3ebdSchin 		if (gp->gl_ignore)
832da2e3ebdSchin 			regfree(gp->gl_ignore);
833da2e3ebdSchin 		if (gp->gl_ignorei)
834da2e3ebdSchin 			regfree(gp->gl_ignorei);
835da2e3ebdSchin 	}
836da2e3ebdSchin }
837