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