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