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