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 			/* FALLTHROUGH */
375 		case '*':
376 		case '?':
377 			meta = MATCH_META;
378 			continue;
379 		case '\\':
380 			if (!(gp->gl_flags & GLOB_NOESCAPE))
381 			{
382 				quote = 1;
383 				if (*rescan)
384 					rescan++;
385 			}
386 			continue;
387 		default:
388 			if (c == gp->gl_delim)
389 			{
390 				if (meta)
391 					break;
392 				pat = rescan;
393 				bracket = 0;
394 				savequote = quote;
395 			}
396 			continue;
397 		}
398 		break;
399 	}
400 	anymeta |= meta;
401 	if (matchdir)
402 		goto skip;
403 	if (pat == prefix)
404 	{
405 		prefix = 0;
406 		if (!rescan && (gp->gl_flags & GLOB_COMPLETE))
407 		{
408 			complete = 1;
409 			dirname = 0;
410 		}
411 		else
412 			dirname = ".";
413 	}
414 	else
415 	{
416 		if (pat == prefix + 1)
417 			dirname = "/";
418 		if (savequote)
419 		{
420 			quote = 0;
421 			trim(ap->gl_begin, pat, &t1, rescan, &t2);
422 			pat -= t1;
423 			if (rescan)
424 				rescan -= t2;
425 		}
426 		*(restore1 = pat - 1) = 0;
427 	}
428 	if (!complete && (gp->gl_flags & GLOB_STARSTAR))
429 		while (pat[0] == '*' && pat[1] == '*' && (pat[2] == '/'  || pat[2]==0))
430 		{
431 			matchdir = pat;
432 			if (pat[2])
433 			{
434 				pat += 3;
435 				while (*pat=='/')
436 					pat++;
437 				if (*pat)
438 					continue;
439 			}
440 			rescan = *pat?0:pat;
441 			pat = "*";
442 			goto skip;
443 		}
444 	if (matchdir)
445 	{
446 		rescan = pat;
447 		goto again;
448 	}
449 skip:
450 	if (rescan)
451 		*(restore2 = rescan - 1) = 0;
452 	if (rescan && !complete && (gp->gl_flags & GLOB_STARSTAR))
453 	{
454 		register char*	p = rescan;
455 
456 		while (p[0] == '*' && p[1] == '*' && (p[2] == '/'  || p[2]==0))
457 		{
458 			rescan = p;
459 			if (starstar = (p[2]==0))
460 				break;
461 			p += 3;
462 			while (*p=='/')
463 				p++;
464 			if (*p==0)
465 			{
466 				starstar = 2;
467 				break;
468 			}
469 		}
470 	}
471 	if (matchdir)
472 		gp->gl_starstar++;
473 	if (gp->gl_opt)
474 		pat = strcpy(gp->gl_opt, pat);
475 	for (;;)
476 	{
477 		if (complete)
478 		{
479 			if (!(dirname = (*gp->gl_nextdir)(gp, dirname)))
480 				break;
481 			prefix = streq(dirname, ".") ? (char*)0 : dirname;
482 		}
483 		if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
484 		{
485 			if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
486 			{
487 				if (!prei)
488 				{
489 					if (err = regcomp(&rei, pat, gp->re_flags|REG_ICASE))
490 						break;
491 					prei = &rei;
492 					if (gp->re_first)
493 					{
494 						gp->re_first = 0;
495 						gp->re_flags = regstat(prei)->re_flags & ~REG_ICASE;
496 					}
497 				}
498 				pre = prei;
499 			}
500 			else
501 			{
502 				if (!prec)
503 				{
504 					if (err = regcomp(&rec, pat, gp->re_flags))
505 						break;
506 					prec = &rec;
507 					if (gp->re_first)
508 					{
509 						gp->re_first = 0;
510 						gp->re_flags = regstat(prec)->re_flags;
511 					}
512 				}
513 				pre = prec;
514 			}
515 			if ((ire = gp->gl_ignore) && (gp->re_flags & REG_ICASE))
516 			{
517 				if (!gp->gl_ignorei)
518 				{
519 					if (regcomp(&gp->re_ignorei, gp->gl_fignore, re_flags|REG_ICASE))
520 					{
521 						gp->gl_error = GLOB_APPERR;
522 						break;
523 					}
524 					gp->gl_ignorei = &gp->re_ignorei;
525 				}
526 				ire = gp->gl_ignorei;
527 			}
528 			if (restore2)
529 				*restore2 = gp->gl_delim;
530 			while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
531 			{
532 				if (notdir = (gp->gl_status & GLOB_NOTDIR))
533 					gp->gl_status &= ~GLOB_NOTDIR;
534 				if (ire && !regexec(ire, name, 0, NiL, 0))
535 					continue;
536 				if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
537 					addmatch(gp, prefix, name, matchdir, NiL, anymeta);
538 				if (!regexec(pre, name, 0, NiL, 0))
539 				{
540 					if (!rescan || !notdir)
541 						addmatch(gp, prefix, name, rescan, NiL, anymeta);
542 					if (starstar==1 || (starstar==2 && !notdir))
543 						addmatch(gp, prefix, name, starstar==2?"":NiL, NiL, anymeta);
544 				}
545 				errno = 0;
546 			}
547 			(*gp->gl_dirclose)(gp, dirf);
548 			if (err || errno && !errorcheck(gp, dirname))
549 				break;
550 		}
551 		else if (!complete && !errorcheck(gp, dirname))
552 			break;
553 		if (!complete)
554 			break;
555 		if (*gp->gl_intr)
556 		{
557 			gp->gl_error = GLOB_INTR;
558 			break;
559 		}
560 	}
561 	if (restore1)
562 		*restore1 = gp->gl_delim;
563 	if (restore2)
564 		*restore2 = gp->gl_delim;
565 	if (prec)
566 		regfree(prec);
567 	if (prei)
568 		regfree(prei);
569 	if (err == REG_ESPACE)
570 		gp->gl_error = GLOB_NOSPACE;
571 }
572 
573 static void
_closedir(void * ptr)574 _closedir(void *ptr)
575 {
576 	(void) closedir(ptr);
577 }
578 
579 int
glob(const char * pattern,int flags,int (* errfn)(const char *,int),register glob_t * gp)580 glob(const char* pattern, int flags, int (*errfn)(const char*, int), register glob_t* gp)
581 {
582 	register globlist_t*	ap;
583 	register char*		pat;
584 	globlist_t*		top;
585 	Stak_t*			oldstak;
586 	char**			argv;
587 	char**			av;
588 	size_t			skip;
589 	unsigned long		f;
590 	int			n;
591 	int			x;
592 	int			re_flags;
593 
594 	const char*		nocheck = pattern;
595 	int			optlen = 0;
596 	int			suflen = 0;
597 	int			extra = 1;
598 	unsigned char		intr = 0;
599 
600 	gp->gl_rescan = 0;
601 	gp->gl_error = 0;
602 	gp->gl_errfn = errfn;
603 	if (flags & GLOB_APPEND)
604 	{
605 		if ((gp->gl_flags |= GLOB_APPEND) ^ (flags|GLOB_MAGIC))
606 			return GLOB_APPERR;
607 		if (((gp->gl_flags & GLOB_STACK) == 0) == (gp->gl_stak == 0))
608 			return GLOB_APPERR;
609 		if (gp->gl_starstar > 1)
610 			gp->gl_flags |= GLOB_STARSTAR;
611 		else
612 			gp->gl_starstar = 0;
613 	}
614 	else
615 	{
616 		gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
617 		gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
618 		gp->gl_pathc = 0;
619 		gp->gl_ignore = 0;
620 		gp->gl_ignorei = 0;
621 		gp->gl_starstar = 0;
622 		if (!(flags & GLOB_DISC))
623 		{
624 			gp->gl_fignore = 0;
625 			gp->gl_suffix = 0;
626 			gp->gl_intr = 0;
627 			gp->gl_delim = 0;
628 			gp->gl_handle = 0;
629 			gp->gl_diropen = 0;
630 			gp->gl_dirnext = 0;
631 			gp->gl_dirclose = 0;
632 			gp->gl_type = 0;
633 			gp->gl_attr = 0;
634 			gp->gl_nextdir = 0;
635 			gp->gl_stat = 0;
636 			gp->gl_lstat = 0;
637 			gp->gl_extra = 0;
638 		}
639 		if (!(flags & GLOB_ALTDIRFUNC))
640 		{
641 			gp->gl_opendir = (GL_opendir_f)opendir;
642 			gp->gl_readdir = (GL_readdir_f)readdir;
643 			gp->gl_closedir = _closedir;
644 			if (!gp->gl_stat)
645 				gp->gl_stat = (GL_stat_f)pathstat;
646 		}
647 		if (!gp->gl_lstat)
648 			gp->gl_lstat = (GL_stat_f)lstat;
649 		if (!gp->gl_intr)
650 			gp->gl_intr = &intr;
651 		if (!gp->gl_delim)
652 			gp->gl_delim = '/';
653 		if (!gp->gl_diropen)
654 			gp->gl_diropen = gl_diropen;
655 		if (!gp->gl_dirnext)
656 			gp->gl_dirnext = gl_dirnext;
657 		if (!gp->gl_dirclose)
658 			gp->gl_dirclose = gl_dirclose;
659 		if (!gp->gl_type)
660 			gp->gl_type = gl_type;
661 		if (!gp->gl_attr)
662 			gp->gl_attr = gl_attr;
663 		if (flags & GLOB_GROUP)
664 			gp->re_flags |= REG_SHELL_GROUP;
665 		if (flags & GLOB_ICASE)
666 			gp->re_flags |= REG_ICASE;
667 		if (!gp->gl_fignore)
668 			gp->re_flags |= REG_SHELL_DOT;
669 		else if (*gp->gl_fignore)
670 		{
671 			if (regcomp(&gp->re_ignore, gp->gl_fignore, gp->re_flags))
672 				return GLOB_APPERR;
673 			gp->gl_ignore = &gp->re_ignore;
674 		}
675 		if (gp->gl_flags & GLOB_STACK)
676 			gp->gl_stak = 0;
677 		else if (!(gp->gl_stak = stakcreate(0)))
678 			return GLOB_NOSPACE;
679 		if ((gp->gl_flags & GLOB_COMPLETE) && !gp->gl_nextdir)
680 			gp->gl_nextdir = gl_nextdir;
681 	}
682 	skip = gp->gl_pathc;
683 	if (gp->gl_stak)
684 		oldstak = stakinstall(gp->gl_stak, 0);
685 	if (flags & GLOB_DOOFFS)
686 		extra += gp->gl_offs;
687 	if (gp->gl_suffix)
688 		suflen =  strlen(gp->gl_suffix);
689 	if (*(pat = (char*)pattern) == '~' && *(pat + 1) == '(')
690 	{
691 		f = gp->gl_flags;
692 		n = 1;
693 		x = 1;
694 		pat += 2;
695 		for (;;)
696 		{
697 			switch (*pat++)
698 			{
699 			case 0:
700 			case ':':
701 				break;
702 			case '-':
703 				n = 0;
704 				continue;
705 			case '+':
706 				n = 1;
707 				continue;
708 			case 'i':
709 				if (n)
710 					f |= GLOB_ICASE;
711 				else
712 					f &= ~GLOB_ICASE;
713 				continue;
714 			case 'M':
715 				if (n)
716 					f |= GLOB_BRACE;
717 				else
718 					f &= ~GLOB_BRACE;
719 				continue;
720 			case 'N':
721 				if (n)
722 					f &= ~GLOB_NOCHECK;
723 				else
724 					f |= GLOB_NOCHECK;
725 				continue;
726 			case 'O':
727 				if (n)
728 					f |= GLOB_STARSTAR;
729 				else
730 					f &= ~GLOB_STARSTAR;
731 				continue;
732 			case ')':
733 				flags = (gp->gl_flags = f) & 0xffff;
734 				if (f & GLOB_ICASE)
735 					gp->re_flags |= REG_ICASE;
736 				else
737 					gp->re_flags &= ~REG_ICASE;
738 				if (x)
739 					optlen = pat - (char*)pattern;
740 				break;
741 			default:
742 				x = 0;
743 				continue;
744 			}
745 			break;
746 		}
747 	}
748 	top = ap = (globlist_t*)stakalloc((optlen ? 2 : 1) * strlen(pattern) + sizeof(globlist_t) + suflen + gp->gl_extra);
749 	ap->gl_next = 0;
750 	ap->gl_flags = 0;
751 	ap->gl_begin = ap->gl_path + gp->gl_extra;
752 	pat = strcopy(ap->gl_begin, pattern + optlen);
753 	if (suflen)
754 		pat = strcopy(pat, gp->gl_suffix);
755 	if (optlen)
756 		strlcpy(gp->gl_pat = gp->gl_opt = pat + 1, pattern, optlen);
757 	else
758 		gp->gl_pat = 0;
759 	suflen = 0;
760 	if (!(flags & GLOB_LIST))
761 		gp->gl_match = 0;
762 	re_flags = gp->re_flags;
763 	gp->re_first = 1;
764 	do
765 	{
766 		gp->gl_rescan = ap->gl_next;
767 		glob_dir(gp, ap, re_flags);
768 	} while (!gp->gl_error && (ap = gp->gl_rescan));
769 	gp->re_flags = re_flags;
770 	if (gp->gl_pathc == skip)
771 	{
772 		if (flags & GLOB_NOCHECK)
773 		{
774 			gp->gl_pathc++;
775 			top->gl_next = gp->gl_match;
776 			gp->gl_match = top;
777 			strcopy(top->gl_path + gp->gl_extra, nocheck);
778 		}
779 		else
780 			gp->gl_error = GLOB_NOMATCH;
781 	}
782 	if (flags & GLOB_LIST)
783 		gp->gl_list = gp->gl_match;
784 	else
785 	{
786 		argv = (char**)stakalloc((gp->gl_pathc + extra) * sizeof(char*));
787 		if (gp->gl_flags & GLOB_APPEND)
788 		{
789 			skip += --extra;
790 			memcpy(argv, gp->gl_pathv, skip * sizeof(char*));
791 			av = argv + skip;
792 		}
793 		else
794 		{
795 			av = argv;
796 			while (--extra > 0)
797 				*av++ = 0;
798 		}
799 		gp->gl_pathv = argv;
800 		argv = av;
801 		ap = gp->gl_match;
802 		while (ap)
803 		{
804 			*argv++ = ap->gl_path + gp->gl_extra;
805 			ap = ap->gl_next;
806 		}
807 		*argv = 0;
808 		if (!(flags & GLOB_NOSORT) && (argv - av) > 1)
809 		{
810 			strsort(av, argv - av, strcoll);
811 			if (gp->gl_starstar > 1)
812 				av[gp->gl_pathc = struniq(av, argv - av)] = 0;
813 			gp->gl_starstar = 0;
814 		}
815 	}
816 	if (gp->gl_starstar > 1)
817 		gp->gl_flags &= ~GLOB_STARSTAR;
818 	if (gp->gl_stak)
819 		stakinstall(oldstak, 0);
820 	return gp->gl_error;
821 }
822 
823 void
globfree(glob_t * gp)824 globfree(glob_t* gp)
825 {
826 	if ((gp->gl_flags & GLOB_MAGIC) == GLOB_MAGIC)
827 	{
828 		gp->gl_flags &= ~GLOB_MAGIC;
829 		if (gp->gl_stak)
830 			stkclose(gp->gl_stak);
831 		if (gp->gl_ignore)
832 			regfree(gp->gl_ignore);
833 		if (gp->gl_ignorei)
834 			regfree(gp->gl_ignorei);
835 	}
836 }
837