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