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