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