xref: /onnv-gate/usr/src/lib/libast/common/misc/glob.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin 
244887Schin /*
254887Schin  * file name expansion - posix.2 glob with gnu and ast extensions
264887Schin  *
274887Schin  *	David Korn
284887Schin  *	Glenn Fowler
294887Schin  *	AT&T Research
304887Schin  */
314887Schin 
324887Schin #include <ast.h>
334887Schin #include <ls.h>
344887Schin #include <stak.h>
354887Schin #include <ast_dir.h>
364887Schin #include <error.h>
374887Schin #include <ctype.h>
384887Schin #include <regex.h>
394887Schin 
404887Schin #define GLOB_MAGIC	0xaaaa0000
414887Schin 
424887Schin #define MATCH_RAW	1
434887Schin #define MATCH_MAKE	2
444887Schin #define MATCH_META	4
454887Schin 
464887Schin #define MATCHPATH(g)	(offsetof(globlist_t,gl_path)+(g)->gl_extra)
474887Schin 
484887Schin typedef int (*GL_error_f)(const char*, int);
494887Schin typedef void* (*GL_opendir_f)(const char*);
504887Schin typedef struct dirent* (*GL_readdir_f)(void*);
514887Schin typedef void (*GL_closedir_f)(void*);
524887Schin typedef int (*GL_stat_f)(const char*, struct stat*);
534887Schin 
544887Schin #define _GLOB_PRIVATE_ \
554887Schin 	GL_error_f	gl_errfn; \
564887Schin 	int		gl_error; \
574887Schin 	char*		gl_nextpath; \
584887Schin 	globlist_t*	gl_rescan; \
594887Schin 	globlist_t*	gl_match; \
604887Schin 	Stak_t*		gl_stak; \
614887Schin 	int		re_flags; \
624887Schin 	regex_t*	gl_ignore; \
634887Schin 	regex_t*	gl_ignorei; \
644887Schin 	regex_t		re_ignore; \
654887Schin 	regex_t		re_ignorei; \
664887Schin 	unsigned long	gl_starstar; \
674887Schin 	char*		gl_opt; \
684887Schin 	char*		gl_pat; \
694887Schin 	char*		gl_pad[4];
704887Schin 
714887Schin #include <glob.h>
724887Schin 
734887Schin /*
744887Schin  * default gl_diropen
754887Schin  */
764887Schin 
774887Schin static void*
gl_diropen(glob_t * gp,const char * path)784887Schin gl_diropen(glob_t* gp, const char* path)
794887Schin {
804887Schin 	return (*gp->gl_opendir)(path);
814887Schin }
824887Schin 
834887Schin /*
844887Schin  * default gl_dirnext
854887Schin  */
864887Schin 
874887Schin static char*
gl_dirnext(glob_t * gp,void * handle)884887Schin gl_dirnext(glob_t* gp, void* handle)
894887Schin {
904887Schin 	struct dirent*	dp;
914887Schin 
924887Schin 	while (dp = (struct dirent*)(*gp->gl_readdir)(handle))
934887Schin #ifdef D_FILENO
944887Schin 		if (D_FILENO(dp))
954887Schin #endif
964887Schin 		{
974887Schin #ifdef D_TYPE
984887Schin 			if (D_TYPE(dp) != DT_UNKNOWN && D_TYPE(dp) != DT_DIR && D_TYPE(dp) != DT_LNK)
994887Schin 				gp->gl_status |= GLOB_NOTDIR;
1004887Schin #endif
1014887Schin 			return dp->d_name;
1024887Schin 		}
1034887Schin 	return 0;
1044887Schin }
1054887Schin 
1064887Schin /*
1074887Schin  * default gl_dirclose
1084887Schin  */
1094887Schin 
1104887Schin static void
gl_dirclose(glob_t * gp,void * handle)1114887Schin gl_dirclose(glob_t* gp, void* handle)
1124887Schin {
1134887Schin 	(gp->gl_closedir)(handle);
1144887Schin }
1154887Schin 
1164887Schin /*
1174887Schin  * default gl_type
1184887Schin  */
1194887Schin 
1204887Schin static int
gl_type(glob_t * gp,const char * path,int flags)1218462SApril.Chin@Sun.COM gl_type(glob_t* gp, const char* path, int flags)
1224887Schin {
1234887Schin 	register int	type;
1244887Schin 	struct stat	st;
1254887Schin 
1268462SApril.Chin@Sun.COM 	if ((flags & GLOB_STARSTAR) ? (*gp->gl_lstat)(path, &st) : (*gp->gl_stat)(path, &st))
1274887Schin 		type = 0;
1284887Schin 	else if (S_ISDIR(st.st_mode))
1294887Schin 		type = GLOB_DIR;
1304887Schin 	else if (!S_ISREG(st.st_mode))
1314887Schin 		type = GLOB_DEV;
1324887Schin 	else if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1334887Schin 		type = GLOB_EXE;
1344887Schin 	else
1354887Schin 		type = GLOB_REG;
1364887Schin 	return type;
1374887Schin }
1384887Schin 
1394887Schin /*
1404887Schin  * default gl_attr
1414887Schin  */
1424887Schin 
1434887Schin static int
gl_attr(glob_t * gp,const char * path,int flags)1448462SApril.Chin@Sun.COM gl_attr(glob_t* gp, const char* path, int flags)
1454887Schin {
1464887Schin 	return strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? GLOB_ICASE : 0;
1474887Schin }
1484887Schin 
1494887Schin /*
1504887Schin  * default gl_nextdir
1514887Schin  */
1524887Schin 
1534887Schin static char*
gl_nextdir(glob_t * gp,char * dir)1544887Schin gl_nextdir(glob_t* gp, char* dir)
1554887Schin {
1564887Schin 	if (!(dir = gp->gl_nextpath))
1574887Schin 		dir = gp->gl_nextpath = stakcopy(pathbin());
1584887Schin 	switch (*gp->gl_nextpath)
1594887Schin 	{
1604887Schin 	case 0:
1614887Schin 		dir = 0;
1624887Schin 		break;
1634887Schin 	case ':':
1644887Schin 		while (*gp->gl_nextpath == ':')
1654887Schin 			gp->gl_nextpath++;
1664887Schin 		dir = ".";
1674887Schin 		break;
1684887Schin 	default:
1694887Schin 		while (*gp->gl_nextpath)
1704887Schin 			if (*gp->gl_nextpath++ == ':')
1714887Schin 			{
1724887Schin 				*(gp->gl_nextpath - 1) = 0;
1734887Schin 				break;
1744887Schin 			}
1754887Schin 		break;
1764887Schin 	}
1774887Schin 	return dir;
1784887Schin }
1794887Schin 
1804887Schin /*
1814887Schin  * error intercept
1824887Schin  */
1834887Schin 
1844887Schin static int
errorcheck(register glob_t * gp,const char * path)1854887Schin errorcheck(register glob_t* gp, const char* path)
1864887Schin {
1874887Schin 	int	r = 1;
1884887Schin 
1894887Schin 	if (gp->gl_errfn)
1904887Schin 		r = (*gp->gl_errfn)(path, errno);
1914887Schin 	if (gp->gl_flags & GLOB_ERR)
1924887Schin 		r = 0;
1934887Schin 	if (!r)
1944887Schin 		gp->gl_error = GLOB_ABORTED;
1954887Schin 	return r;
1964887Schin }
1974887Schin 
1984887Schin /*
1994887Schin  * remove backslashes
2004887Schin  */
2014887Schin 
2024887Schin static void
trim(register char * sp,register char * p1,int * n1,register char * p2,int * n2)2034887Schin trim(register char* sp, register char* p1, int* n1, register char* p2, int* n2)
2044887Schin {
2054887Schin 	register char*	dp = sp;
2064887Schin 	register int	c;
2074887Schin 	register int	n;
2084887Schin 
2094887Schin 	if (p1)
2104887Schin 		*n1 = 0;
2114887Schin 	if (p2)
2124887Schin 		*n2 = 0;
2134887Schin 	do
2144887Schin 	{
2154887Schin 		if ((c = *sp++) == '\\' && (c = *sp++))
2164887Schin 			n++;
2174887Schin 		if (sp == p1)
2184887Schin 		{
2194887Schin 			p1 = 0;
2204887Schin 			*n1 = sp - dp - 1;
2214887Schin 		}
2224887Schin 		if (sp == p2)
2234887Schin 		{
2244887Schin 			p2 = 0;
2254887Schin 			*n2 = sp - dp - 1;
2264887Schin 		}
2274887Schin 	} while (*dp++ = c);
2284887Schin }
2294887Schin 
2304887Schin static void
addmatch(register glob_t * gp,const char * dir,const char * pat,register const char * rescan,char * endslash,int meta)2314887Schin addmatch(register glob_t* gp, const char* dir, const char* pat, register const char* rescan, char* endslash, int meta)
2324887Schin {
2334887Schin 	register globlist_t*	ap;
2344887Schin 	int			offset;
2354887Schin 	int			type;
2364887Schin 
2374887Schin 	stakseek(MATCHPATH(gp));
2384887Schin 	if (dir)
2394887Schin 	{
2404887Schin 		stakputs(dir);
2414887Schin 		stakputc(gp->gl_delim);
2424887Schin 	}
2434887Schin 	if (endslash)
2444887Schin 		*endslash = 0;
2454887Schin 	stakputs(pat);
2464887Schin 	if (rescan)
2474887Schin 	{
2488462SApril.Chin@Sun.COM 		if ((*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0) != GLOB_DIR)
2494887Schin 			return;
2504887Schin 		stakputc(gp->gl_delim);
2514887Schin 		offset = staktell();
2524887Schin 		/* if null, reserve room for . */
2534887Schin 		if (*rescan)
2544887Schin 			stakputs(rescan);
2554887Schin 		else
2564887Schin 			stakputc(0);
2574887Schin 		stakputc(0);
2584887Schin 		rescan = stakptr(offset);
2594887Schin 		ap = (globlist_t*)stakfreeze(0);
2604887Schin 		ap->gl_begin = (char*)rescan;
2614887Schin 		ap->gl_next = gp->gl_rescan;
2624887Schin 		gp->gl_rescan = ap;
2634887Schin 	}
2644887Schin 	else
2654887Schin 	{
2668462SApril.Chin@Sun.COM 		if (!endslash && (gp->gl_flags & GLOB_MARK) && (type = (*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0)))
2674887Schin 		{
2684887Schin 			if ((gp->gl_flags & GLOB_COMPLETE) && type != GLOB_EXE)
2694887Schin 			{
2704887Schin 				stakseek(0);
2714887Schin 				return;
2724887Schin 			}
2734887Schin 			else if (type == GLOB_DIR && (gp->gl_flags & GLOB_MARK))
2744887Schin 				stakputc(gp->gl_delim);
2754887Schin 		}
2764887Schin 		ap = (globlist_t*)stakfreeze(1);
2774887Schin 		ap->gl_next = gp->gl_match;
2784887Schin 		gp->gl_match = ap;
2794887Schin 		gp->gl_pathc++;
2804887Schin 	}
2814887Schin 	ap->gl_flags = MATCH_RAW|meta;
2824887Schin 	if (gp->gl_flags & GLOB_COMPLETE)
2834887Schin 		ap->gl_flags |= MATCH_MAKE;
2844887Schin }
2854887Schin 
2864887Schin /*
2874887Schin  * this routine builds a list of files that match a given pathname
2884887Schin  * uses REG_SHELL of <regex> to match each component
2894887Schin  * a leading . must match explicitly
2904887Schin  */
2914887Schin 
2924887Schin static void
glob_dir(glob_t * gp,globlist_t * ap)2934887Schin glob_dir(glob_t* gp, globlist_t* ap)
2944887Schin {
2954887Schin 	register char*		rescan;
2964887Schin 	register char*		prefix;
2974887Schin 	register char*		pat;
2984887Schin 	register char*		name;
2994887Schin 	register int		c;
3004887Schin 	char*			dirname;
3014887Schin 	void*			dirf;
3024887Schin 	char			first;
3034887Schin 	regex_t*		ire;
3044887Schin 	regex_t*		pre;
3054887Schin 	regex_t			rec;
3064887Schin 	regex_t			rei;
3074887Schin 	int			notdir;
3084887Schin 	int			t1;
3094887Schin 	int			t2;
3104887Schin 	int			bracket;
3114887Schin 
3124887Schin 	int			anymeta = ap->gl_flags & MATCH_META;
3134887Schin 	int			complete = 0;
3144887Schin 	int			err = 0;
3154887Schin 	int			meta = ((gp->re_flags & REG_ICASE) && *ap->gl_begin != '/') ? MATCH_META : 0;
3164887Schin 	int			quote = 0;
3174887Schin 	int			savequote = 0;
3184887Schin 	char*			restore1 = 0;
3194887Schin 	char*			restore2 = 0;
3204887Schin 	regex_t*		prec = 0;
3214887Schin 	regex_t*		prei = 0;
3224887Schin 	char*			matchdir = 0;
3234887Schin 	int			starstar = 0;
3244887Schin 
3254887Schin 	if (*gp->gl_intr)
3264887Schin 	{
3274887Schin 		gp->gl_error = GLOB_INTR;
3284887Schin 		return;
3294887Schin 	}
3304887Schin 	pat = rescan = ap->gl_begin;
3314887Schin 	prefix = dirname = ap->gl_path + gp->gl_extra;
3324887Schin 	first = (rescan == prefix);
3334887Schin again:
3344887Schin 	bracket = 0;
3354887Schin 	for (;;)
3364887Schin 	{
3374887Schin 		switch (c = *rescan++)
3384887Schin 		{
3394887Schin 		case 0:
3404887Schin 			if (meta)
3414887Schin 			{
3424887Schin 				rescan = 0;
3434887Schin 				break;
3444887Schin 			}
3454887Schin 			if (quote)
3464887Schin 			{
3474887Schin 				trim(ap->gl_begin, rescan, &t1, NiL, NiL);
3484887Schin 				rescan -= t1;
3494887Schin 			}
3504887Schin 			if (!first && !*rescan && *(rescan - 2) == gp->gl_delim)
3514887Schin 			{
3524887Schin 				*(rescan - 2) = 0;
3538462SApril.Chin@Sun.COM 				c = (*gp->gl_type)(gp, prefix, 0);
3544887Schin 				*(rescan - 2) = gp->gl_delim;
3554887Schin 				if (c == GLOB_DIR)
3564887Schin 					addmatch(gp, NiL, prefix, NiL, rescan - 1, anymeta);
3574887Schin 			}
3588462SApril.Chin@Sun.COM 			else if ((anymeta || !(gp->gl_flags & GLOB_NOCHECK)) && (*gp->gl_type)(gp, prefix, 0))
3594887Schin 				addmatch(gp, NiL, prefix, NiL, NiL, anymeta);
3604887Schin 			return;
3614887Schin 		case '[':
3624887Schin 			if (!bracket)
3634887Schin 			{
3644887Schin 				bracket = MATCH_META;
3654887Schin 				if (*rescan == '!' || *rescan == '^')
3664887Schin 					rescan++;
3674887Schin 				if (*rescan == ']')
3684887Schin 					rescan++;
3694887Schin 			}
3704887Schin 			continue;
3714887Schin 		case ']':
3724887Schin 			meta |= bracket;
3734887Schin 			continue;
3744887Schin 		case '(':
3754887Schin 			if (!(gp->gl_flags & GLOB_AUGMENTED))
3764887Schin 				continue;
3774887Schin 		case '*':
3784887Schin 		case '?':
3794887Schin 			meta = MATCH_META;
3804887Schin 			continue;
3814887Schin 		case '\\':
3824887Schin 			if (!(gp->gl_flags & GLOB_NOESCAPE))
3834887Schin 			{
3844887Schin 				quote = 1;
3854887Schin 				if (*rescan)
3864887Schin 					rescan++;
3874887Schin 			}
3884887Schin 			continue;
3894887Schin 		default:
3904887Schin 			if (c == gp->gl_delim)
3914887Schin 			{
3924887Schin 				if (meta)
3934887Schin 					break;
3944887Schin 				pat = rescan;
3954887Schin 				bracket = 0;
3964887Schin 				savequote = quote;
3974887Schin 			}
3984887Schin 			continue;
3994887Schin 		}
4004887Schin 		break;
4014887Schin 	}
4024887Schin 	anymeta |= meta;
4034887Schin 	if (matchdir)
4044887Schin 		goto skip;
4054887Schin 	if (pat == prefix)
4064887Schin 	{
4074887Schin 		prefix = 0;
4084887Schin 		if (!rescan && (gp->gl_flags & GLOB_COMPLETE))
4094887Schin 		{
4104887Schin 			complete = 1;
4114887Schin 			dirname = 0;
4124887Schin 		}
4134887Schin 		else
4144887Schin 			dirname = ".";
4154887Schin 	}
4164887Schin 	else
4174887Schin 	{
4184887Schin 		if (pat == prefix + 1)
4194887Schin 			dirname = "/";
4204887Schin 		if (savequote)
4214887Schin 		{
4224887Schin 			quote = 0;
4234887Schin 			trim(ap->gl_begin, pat, &t1, rescan, &t2);
4244887Schin 			pat -= t1;
4254887Schin 			if (rescan)
4264887Schin 				rescan -= t2;
4274887Schin 		}
4284887Schin 		*(restore1 = pat - 1) = 0;
4294887Schin 	}
4304887Schin 	if (!complete && (gp->gl_flags & GLOB_STARSTAR))
4314887Schin 		while (pat[0] == '*' && pat[1] == '*' && (pat[2] == '/'  || pat[2]==0))
4324887Schin 		{
4334887Schin 			matchdir = pat;
4344887Schin 			if (pat[2])
4354887Schin 			{
4364887Schin 				pat += 3;
4374887Schin 				while (*pat=='/') pat++;
4384887Schin 				if (*pat)
4394887Schin 					continue;
4404887Schin 			}
4414887Schin 			rescan = *pat?0:pat;
4424887Schin 			pat = "*";
4434887Schin 			goto skip;
4444887Schin 		}
4454887Schin 	if (matchdir)
4464887Schin 	{
4474887Schin 		rescan = pat;
4484887Schin 		goto again;
4494887Schin 	}
4504887Schin skip:
4514887Schin 	if (rescan)
4524887Schin 		*(restore2 = rescan - 1) = 0;
4534887Schin 	if (rescan && !complete && (gp->gl_flags & GLOB_STARSTAR))
4544887Schin 	{
4554887Schin 		register char *p = rescan;
4564887Schin 		while (p[0] == '*' && p[1] == '*' && (p[2] == '/'  || p[2]==0))
4574887Schin 		{
4584887Schin 			rescan = p;
4594887Schin 			if (starstar = (p[2]==0))
4604887Schin 				break;
4614887Schin 			p += 3;
4624887Schin 			while (*p=='/')
4634887Schin 				p++;
4644887Schin 			if (*p==0)
4654887Schin 			{
4664887Schin 				starstar = 2;
4674887Schin 				break;
4684887Schin 			}
4694887Schin 		}
4704887Schin 	}
4714887Schin 	if (matchdir)
4724887Schin 		gp->gl_starstar++;
4734887Schin 	if (gp->gl_opt)
4744887Schin 		pat = strcpy(gp->gl_opt, pat);
4754887Schin 	for (;;)
4764887Schin 	{
4774887Schin 		if (complete)
4784887Schin 		{
4794887Schin 			if (!(dirname = (*gp->gl_nextdir)(gp, dirname)))
4804887Schin 				break;
4814887Schin 			prefix = streq(dirname, ".") ? (char*)0 : dirname;
4824887Schin 		}
4838462SApril.Chin@Sun.COM 		if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
4844887Schin 		{
4858462SApril.Chin@Sun.COM 			if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
4864887Schin 			{
4874887Schin 				if (!prei)
4884887Schin 				{
4894887Schin 					if (err = regcomp(&rei, pat, gp->re_flags|REG_ICASE))
4904887Schin 						break;
4914887Schin 					prei = &rei;
4924887Schin 				}
4934887Schin 				pre = prei;
4944887Schin 				if (gp->gl_ignore)
4954887Schin 				{
4964887Schin 					if (!gp->gl_ignorei)
4974887Schin 					{
4984887Schin 						if (regcomp(&gp->re_ignorei, gp->gl_fignore, gp->re_flags|REG_ICASE))
4994887Schin 						{
5004887Schin 							gp->gl_error = GLOB_APPERR;
5014887Schin 							break;
5024887Schin 						}
5034887Schin 						gp->gl_ignorei = &gp->re_ignorei;
5044887Schin 					}
5054887Schin 					ire = gp->gl_ignorei;
5064887Schin 				}
5074887Schin 				else
5084887Schin 					ire = 0;
5094887Schin 			}
5104887Schin 			else
5114887Schin 			{
5124887Schin 				if (!prec)
5134887Schin 				{
5144887Schin 					if (err = regcomp(&rec, pat, gp->re_flags))
5154887Schin 						break;
5164887Schin 					prec = &rec;
5174887Schin 				}
5184887Schin 				pre = prec;
5194887Schin 				ire = gp->gl_ignore;
5204887Schin 			}
5214887Schin 			if (restore2)
5224887Schin 				*restore2 = gp->gl_delim;
5234887Schin 			while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
5244887Schin 			{
5254887Schin 				if (notdir = (gp->gl_status & GLOB_NOTDIR))
5264887Schin 					gp->gl_status &= ~GLOB_NOTDIR;
5274887Schin 				if (ire && !regexec(ire, name, 0, NiL, 0))
5284887Schin 					continue;
5294887Schin 				if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
5304887Schin 					addmatch(gp, prefix, name, matchdir, NiL, anymeta);
5314887Schin 				if (!regexec(pre, name, 0, NiL, 0))
5324887Schin 				{
5334887Schin 					if (!rescan || !notdir)
5344887Schin 						addmatch(gp, prefix, name, rescan, NiL, anymeta);
5354887Schin 					if (starstar==1 || (starstar==2 && !notdir))
5364887Schin 						addmatch(gp, prefix, name, starstar==2?"":NiL, NiL, anymeta);
5374887Schin 				}
5384887Schin 				errno = 0;
5394887Schin 			}
5404887Schin 			(*gp->gl_dirclose)(gp, dirf);
5414887Schin 			if (err || errno && !errorcheck(gp, dirname))
5424887Schin 				break;
5434887Schin 		}
5444887Schin 		else if (!complete && !errorcheck(gp, dirname))
5454887Schin 			break;
5464887Schin 		if (!complete)
5474887Schin 			break;
5484887Schin 		if (*gp->gl_intr)
5494887Schin 		{
5504887Schin 			gp->gl_error = GLOB_INTR;
5514887Schin 			break;
5524887Schin 		}
5534887Schin 	}
5544887Schin 	if (restore1)
5554887Schin 		*restore1 = gp->gl_delim;
5564887Schin 	if (restore2)
5574887Schin 		*restore2 = gp->gl_delim;
5584887Schin 	if (prec)
5594887Schin 		regfree(prec);
5604887Schin 	if (prei)
5614887Schin 		regfree(prei);
5624887Schin 	if (err == REG_ESPACE)
5634887Schin 		gp->gl_error = GLOB_NOSPACE;
5644887Schin }
5654887Schin 
5664887Schin int
glob(const char * pattern,int flags,int (* errfn)(const char *,int),register glob_t * gp)5674887Schin glob(const char* pattern, int flags, int (*errfn)(const char*, int), register glob_t* gp)
5684887Schin {
5694887Schin 	register globlist_t*	ap;
5704887Schin 	register char*		pat;
5714887Schin 	globlist_t*		top;
5724887Schin 	Stak_t*			oldstak;
5734887Schin 	char**			argv;
5744887Schin 	char**			av;
5754887Schin 	size_t			skip;
5764887Schin 	unsigned long		f;
5774887Schin 	int			n;
5784887Schin 	int			x;
5794887Schin 
5804887Schin 	const char*		nocheck = pattern;
5814887Schin 	int			optlen = 0;
5824887Schin 	int			suflen = 0;
5834887Schin 	int			extra = 1;
5844887Schin 	unsigned char		intr = 0;
5854887Schin 
5864887Schin 	gp->gl_rescan = 0;
5874887Schin 	gp->gl_error = 0;
5884887Schin 	gp->gl_errfn = errfn;
5894887Schin 	if (flags & GLOB_APPEND)
5904887Schin 	{
5914887Schin 		if ((gp->gl_flags |= GLOB_APPEND) ^ (flags|GLOB_MAGIC))
5924887Schin 			return GLOB_APPERR;
5934887Schin 		if (((gp->gl_flags & GLOB_STACK) == 0) == (gp->gl_stak == 0))
5944887Schin 			return GLOB_APPERR;
5954887Schin 		if (gp->gl_starstar > 1)
5964887Schin 			gp->gl_flags |= GLOB_STARSTAR;
5974887Schin 		else
5984887Schin 			gp->gl_starstar = 0;
5994887Schin 	}
6004887Schin 	else
6014887Schin 	{
6024887Schin 		gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
6034887Schin 		gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
6044887Schin 		gp->gl_pathc = 0;
6054887Schin 		gp->gl_ignore = 0;
6064887Schin 		gp->gl_ignorei = 0;
6074887Schin 		gp->gl_starstar = 0;
6084887Schin 		if (!(flags & GLOB_DISC))
6094887Schin 		{
6104887Schin 			gp->gl_fignore = 0;
6114887Schin 			gp->gl_suffix = 0;
6124887Schin 			gp->gl_intr = 0;
6134887Schin 			gp->gl_delim = 0;
6144887Schin 			gp->gl_handle = 0;
6154887Schin 			gp->gl_diropen = 0;
6164887Schin 			gp->gl_dirnext = 0;
6174887Schin 			gp->gl_dirclose = 0;
6184887Schin 			gp->gl_type = 0;
6194887Schin 			gp->gl_attr = 0;
6204887Schin 			gp->gl_nextdir = 0;
6214887Schin 			gp->gl_stat = 0;
6228462SApril.Chin@Sun.COM 			gp->gl_lstat = 0;
6234887Schin 			gp->gl_extra = 0;
6244887Schin 		}
6254887Schin 		if (!(flags & GLOB_ALTDIRFUNC))
6264887Schin 		{
6274887Schin 			gp->gl_opendir = (GL_opendir_f)opendir;
6284887Schin 			gp->gl_readdir = (GL_readdir_f)readdir;
6294887Schin 			gp->gl_closedir = (GL_closedir_f)closedir;
6304887Schin 			if (!gp->gl_stat)
6318462SApril.Chin@Sun.COM 				gp->gl_stat = (GL_stat_f)pathstat;
6324887Schin 		}
6338462SApril.Chin@Sun.COM 		if (!gp->gl_lstat)
6348462SApril.Chin@Sun.COM 			gp->gl_lstat = (GL_stat_f)lstat;
6354887Schin 		if (!gp->gl_intr)
6364887Schin 			gp->gl_intr = &intr;
6374887Schin 		if (!gp->gl_delim)
6384887Schin 			gp->gl_delim = '/';
6394887Schin 		if (!gp->gl_diropen)
6404887Schin 			gp->gl_diropen = gl_diropen;
6414887Schin 		if (!gp->gl_dirnext)
6424887Schin 			gp->gl_dirnext = gl_dirnext;
6434887Schin 		if (!gp->gl_dirclose)
6444887Schin 			gp->gl_dirclose = gl_dirclose;
6454887Schin 		if (!gp->gl_type)
6464887Schin 			gp->gl_type = gl_type;
6474887Schin 		if (!gp->gl_attr)
6484887Schin 			gp->gl_attr = gl_attr;
6494887Schin 		if (flags & GLOB_ICASE)
6504887Schin 			gp->re_flags |= REG_ICASE;
6514887Schin 		if (!gp->gl_fignore)
6524887Schin 			gp->re_flags |= REG_SHELL_DOT;
6534887Schin 		else if (*gp->gl_fignore)
6544887Schin 		{
6554887Schin 			if (regcomp(&gp->re_ignore, gp->gl_fignore, gp->re_flags))
6564887Schin 				return GLOB_APPERR;
6574887Schin 			gp->gl_ignore = &gp->re_ignore;
6584887Schin 		}
6594887Schin 		if (gp->gl_flags & GLOB_STACK)
6604887Schin 			gp->gl_stak = 0;
6614887Schin 		else if (!(gp->gl_stak = stakcreate(0)))
6624887Schin 			return GLOB_NOSPACE;
6634887Schin 		if ((gp->gl_flags & GLOB_COMPLETE) && !gp->gl_nextdir)
6644887Schin 			gp->gl_nextdir = gl_nextdir;
6654887Schin 	}
6664887Schin 	skip = gp->gl_pathc;
6674887Schin 	if (gp->gl_stak)
6684887Schin 		oldstak = stakinstall(gp->gl_stak, 0);
6694887Schin 	if (flags & GLOB_DOOFFS)
6704887Schin 		extra += gp->gl_offs;
6714887Schin 	if (gp->gl_suffix)
6724887Schin 		suflen =  strlen(gp->gl_suffix);
6734887Schin 	if (*(pat = (char*)pattern) == '~' && *(pat + 1) == '(')
6744887Schin 	{
6754887Schin 		f = gp->gl_flags;
6764887Schin 		n = 1;
6774887Schin 		x = 1;
6784887Schin 		pat += 2;
6794887Schin 		for (;;)
6804887Schin 		{
6814887Schin 			switch (*pat++)
6824887Schin 			{
6834887Schin 			case 0:
6844887Schin 			case ':':
6854887Schin 				break;
6864887Schin 			case '-':
6874887Schin 				n = 0;
6884887Schin 				continue;
6894887Schin 			case '+':
6904887Schin 				n = 1;
6914887Schin 				continue;
6924887Schin 			case 'i':
6934887Schin 				if (n)
6944887Schin 					f |= GLOB_ICASE;
6954887Schin 				else
6964887Schin 					f &= ~GLOB_ICASE;
6974887Schin 				continue;
6984887Schin 			case 'M':
6994887Schin 				if (n)
7004887Schin 					f |= GLOB_BRACE;
7014887Schin 				else
7024887Schin 					f &= ~GLOB_BRACE;
7034887Schin 				continue;
7044887Schin 			case 'N':
7054887Schin 				if (n)
7064887Schin 					f &= ~GLOB_NOCHECK;
7074887Schin 				else
7084887Schin 					f |= GLOB_NOCHECK;
7094887Schin 				continue;
7108462SApril.Chin@Sun.COM 			case 'O':
7114887Schin 				if (n)
7124887Schin 					f |= GLOB_STARSTAR;
7134887Schin 				else
7144887Schin 					f &= ~GLOB_STARSTAR;
7154887Schin 				continue;
7164887Schin 			case ')':
7174887Schin 				flags = (gp->gl_flags = f) & 0xffff;
7184887Schin 				if (f & GLOB_ICASE)
7194887Schin 					gp->re_flags |= REG_ICASE;
7204887Schin 				else
7214887Schin 					gp->re_flags &= ~REG_ICASE;
7224887Schin 				if (x)
7234887Schin 					optlen = pat - (char*)pattern;
7244887Schin 				break;
7254887Schin 			default:
7264887Schin 				x = 0;
7274887Schin 				continue;
7284887Schin 			}
7294887Schin 			break;
7304887Schin 		}
7314887Schin 	}
7324887Schin 	top = ap = (globlist_t*)stakalloc((optlen ? 2 : 1) * strlen(pattern) + sizeof(globlist_t) + suflen + gp->gl_extra);
7334887Schin 	ap->gl_next = 0;
7344887Schin 	ap->gl_flags = 0;
7354887Schin 	ap->gl_begin = ap->gl_path + gp->gl_extra;
7364887Schin 	pat = strcopy(ap->gl_begin, pattern + optlen);
7374887Schin 	if (suflen)
7384887Schin 		pat = strcopy(pat, gp->gl_suffix);
7394887Schin 	gp->gl_pat = optlen ? strncpy(gp->gl_opt = pat + 1, pattern, optlen) : (char*)0;
7404887Schin 	suflen = 0;
7414887Schin 	if (!(flags & GLOB_LIST))
7424887Schin 		gp->gl_match = 0;
7434887Schin 	do
7444887Schin 	{
7454887Schin 		gp->gl_rescan = ap->gl_next;
7464887Schin 		glob_dir(gp, ap);
7474887Schin 	} while (!gp->gl_error && (ap = gp->gl_rescan));
7484887Schin 	if (gp->gl_pathc == skip)
7494887Schin 	{
7504887Schin 		if (flags & GLOB_NOCHECK)
7514887Schin 		{
7524887Schin 			gp->gl_pathc++;
7534887Schin 			top->gl_next = gp->gl_match;
7544887Schin 			gp->gl_match = top;
7554887Schin 			strcopy(top->gl_path + gp->gl_extra, nocheck);
7564887Schin 		}
7574887Schin 		else
7584887Schin 			gp->gl_error = GLOB_NOMATCH;
7594887Schin 	}
7604887Schin 	if (flags & GLOB_LIST)
7614887Schin 		gp->gl_list = gp->gl_match;
7624887Schin 	else
7634887Schin 	{
7644887Schin 		argv = (char**)stakalloc((gp->gl_pathc + extra) * sizeof(char*));
7654887Schin 		if (gp->gl_flags & GLOB_APPEND)
7664887Schin 		{
7674887Schin 			skip += --extra;
7684887Schin 			memcpy(argv, gp->gl_pathv, skip * sizeof(char*));
7694887Schin 			av = argv + skip;
7704887Schin 		}
7714887Schin 		else
7724887Schin 		{
7734887Schin 			av = argv;
7744887Schin 			while (--extra > 0)
7754887Schin 				*av++ = 0;
7764887Schin 		}
7774887Schin 		gp->gl_pathv = argv;
7784887Schin 		argv = av;
7794887Schin 		ap = gp->gl_match;
7804887Schin 		while (ap)
7814887Schin 		{
7824887Schin 			*argv++ = ap->gl_path + gp->gl_extra;
7834887Schin 			ap = ap->gl_next;
7844887Schin 		}
7854887Schin 		*argv = 0;
7864887Schin 		if (!(flags & GLOB_NOSORT) && (argv - av) > 1)
7874887Schin 		{
7884887Schin 			strsort(av, argv - av, strcoll);
7894887Schin 			if (gp->gl_starstar > 1)
7904887Schin 				av[gp->gl_pathc = struniq(av, argv - av)] = 0;
7914887Schin 			gp->gl_starstar = 0;
7924887Schin 		}
7934887Schin 	}
7944887Schin 	if (gp->gl_starstar > 1)
7954887Schin 		gp->gl_flags &= ~GLOB_STARSTAR;
7964887Schin 	if (gp->gl_stak)
7974887Schin 		stakinstall(oldstak, 0);
7984887Schin 	return gp->gl_error;
7994887Schin }
8004887Schin 
8014887Schin void
globfree(glob_t * gp)8024887Schin globfree(glob_t* gp)
8034887Schin {
8044887Schin 	if ((gp->gl_flags & GLOB_MAGIC) == GLOB_MAGIC)
8054887Schin 	{
8064887Schin 		gp->gl_flags &= ~GLOB_MAGIC;
8074887Schin 		if (gp->gl_stak)
8084887Schin 			stkclose(gp->gl_stak);
8094887Schin 		if (gp->gl_ignore)
8104887Schin 			regfree(gp->gl_ignore);
8114887Schin 		if (gp->gl_ignorei)
8124887Schin 			regfree(gp->gl_ignorei);
8134887Schin 	}
8144887Schin }
815