Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/misc/glob.c
1810 views
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 <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
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*
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*
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
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
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
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*
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
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
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
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
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
case '*':
375
case '?':
376
meta = MATCH_META;
377
continue;
378
case '\\':
379
if (!(gp->gl_flags & GLOB_NOESCAPE))
380
{
381
quote = 1;
382
if (*rescan)
383
rescan++;
384
}
385
continue;
386
default:
387
if (c == gp->gl_delim)
388
{
389
if (meta)
390
break;
391
pat = rescan;
392
bracket = 0;
393
savequote = quote;
394
}
395
continue;
396
}
397
break;
398
}
399
anymeta |= meta;
400
if (matchdir)
401
goto skip;
402
if (pat == prefix)
403
{
404
prefix = 0;
405
if (!rescan && (gp->gl_flags & GLOB_COMPLETE))
406
{
407
complete = 1;
408
dirname = 0;
409
}
410
else
411
dirname = ".";
412
}
413
else
414
{
415
if (pat == prefix + 1)
416
dirname = "/";
417
if (savequote)
418
{
419
quote = 0;
420
trim(ap->gl_begin, pat, &t1, rescan, &t2);
421
pat -= t1;
422
if (rescan)
423
rescan -= t2;
424
}
425
*(restore1 = pat - 1) = 0;
426
}
427
if (!complete && (gp->gl_flags & GLOB_STARSTAR))
428
while (pat[0] == '*' && pat[1] == '*' && (pat[2] == '/' || pat[2]==0))
429
{
430
matchdir = pat;
431
if (pat[2])
432
{
433
pat += 3;
434
while (*pat=='/')
435
pat++;
436
if (*pat)
437
continue;
438
}
439
rescan = *pat?0:pat;
440
pat = "*";
441
goto skip;
442
}
443
if (matchdir)
444
{
445
rescan = pat;
446
goto again;
447
}
448
skip:
449
if (rescan)
450
*(restore2 = rescan - 1) = 0;
451
if (rescan && !complete && (gp->gl_flags & GLOB_STARSTAR))
452
{
453
register char* p = rescan;
454
455
while (p[0] == '*' && p[1] == '*' && (p[2] == '/' || p[2]==0))
456
{
457
rescan = p;
458
if (starstar = (p[2]==0))
459
break;
460
p += 3;
461
while (*p=='/')
462
p++;
463
if (*p==0)
464
{
465
starstar = 2;
466
break;
467
}
468
}
469
}
470
if (matchdir)
471
gp->gl_starstar++;
472
if (gp->gl_opt)
473
pat = strcpy(gp->gl_opt, pat);
474
for (;;)
475
{
476
if (complete)
477
{
478
if (!(dirname = (*gp->gl_nextdir)(gp, dirname)))
479
break;
480
prefix = streq(dirname, ".") ? (char*)0 : dirname;
481
}
482
if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
483
{
484
if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
485
{
486
if (!prei)
487
{
488
if (err = regcomp(&rei, pat, gp->re_flags|REG_ICASE))
489
break;
490
prei = &rei;
491
if (gp->re_first)
492
{
493
gp->re_first = 0;
494
gp->re_flags = regstat(prei)->re_flags & ~REG_ICASE;
495
}
496
}
497
pre = prei;
498
}
499
else
500
{
501
if (!prec)
502
{
503
if (err = regcomp(&rec, pat, gp->re_flags))
504
break;
505
prec = &rec;
506
if (gp->re_first)
507
{
508
gp->re_first = 0;
509
gp->re_flags = regstat(prec)->re_flags;
510
}
511
}
512
pre = prec;
513
}
514
if ((ire = gp->gl_ignore) && (gp->re_flags & REG_ICASE))
515
{
516
if (!gp->gl_ignorei)
517
{
518
if (regcomp(&gp->re_ignorei, gp->gl_fignore, re_flags|REG_ICASE))
519
{
520
gp->gl_error = GLOB_APPERR;
521
break;
522
}
523
gp->gl_ignorei = &gp->re_ignorei;
524
}
525
ire = gp->gl_ignorei;
526
}
527
if (restore2)
528
*restore2 = gp->gl_delim;
529
while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
530
{
531
if (notdir = (gp->gl_status & GLOB_NOTDIR))
532
gp->gl_status &= ~GLOB_NOTDIR;
533
if (ire && !regexec(ire, name, 0, NiL, 0))
534
continue;
535
if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
536
addmatch(gp, prefix, name, matchdir, NiL, anymeta);
537
if (!regexec(pre, name, 0, NiL, 0))
538
{
539
if (!rescan || !notdir)
540
addmatch(gp, prefix, name, rescan, NiL, anymeta);
541
if (starstar==1 || (starstar==2 && !notdir))
542
addmatch(gp, prefix, name, starstar==2?"":NiL, NiL, anymeta);
543
}
544
errno = 0;
545
}
546
(*gp->gl_dirclose)(gp, dirf);
547
if (err || errno && !errorcheck(gp, dirname))
548
break;
549
}
550
else if (!complete && !errorcheck(gp, dirname))
551
break;
552
if (!complete)
553
break;
554
if (*gp->gl_intr)
555
{
556
gp->gl_error = GLOB_INTR;
557
break;
558
}
559
}
560
if (restore1)
561
*restore1 = gp->gl_delim;
562
if (restore2)
563
*restore2 = gp->gl_delim;
564
if (prec)
565
regfree(prec);
566
if (prei)
567
regfree(prei);
568
if (err == REG_ESPACE)
569
gp->gl_error = GLOB_NOSPACE;
570
}
571
572
int
573
glob(const char* pattern, int flags, int (*errfn)(const char*, int), register glob_t* gp)
574
{
575
register globlist_t* ap;
576
register char* pat;
577
globlist_t* top;
578
Stak_t* oldstak;
579
char** argv;
580
char** av;
581
size_t skip;
582
unsigned long f;
583
int n;
584
int x;
585
int re_flags;
586
587
const char* nocheck = pattern;
588
int optlen = 0;
589
int suflen = 0;
590
int extra = 1;
591
unsigned char intr = 0;
592
593
gp->gl_rescan = 0;
594
gp->gl_error = 0;
595
gp->gl_errfn = errfn;
596
if (flags & GLOB_APPEND)
597
{
598
if ((gp->gl_flags |= GLOB_APPEND) ^ (flags|GLOB_MAGIC))
599
return GLOB_APPERR;
600
if (((gp->gl_flags & GLOB_STACK) == 0) == (gp->gl_stak == 0))
601
return GLOB_APPERR;
602
if (gp->gl_starstar > 1)
603
gp->gl_flags |= GLOB_STARSTAR;
604
else
605
gp->gl_starstar = 0;
606
}
607
else
608
{
609
gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
610
gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
611
gp->gl_pathc = 0;
612
gp->gl_ignore = 0;
613
gp->gl_ignorei = 0;
614
gp->gl_starstar = 0;
615
if (!(flags & GLOB_DISC))
616
{
617
gp->gl_fignore = 0;
618
gp->gl_suffix = 0;
619
gp->gl_intr = 0;
620
gp->gl_delim = 0;
621
gp->gl_handle = 0;
622
gp->gl_diropen = 0;
623
gp->gl_dirnext = 0;
624
gp->gl_dirclose = 0;
625
gp->gl_type = 0;
626
gp->gl_attr = 0;
627
gp->gl_nextdir = 0;
628
gp->gl_stat = 0;
629
gp->gl_lstat = 0;
630
gp->gl_extra = 0;
631
}
632
if (!(flags & GLOB_ALTDIRFUNC))
633
{
634
gp->gl_opendir = (GL_opendir_f)opendir;
635
gp->gl_readdir = (GL_readdir_f)readdir;
636
gp->gl_closedir = (GL_closedir_f)closedir;
637
if (!gp->gl_stat)
638
gp->gl_stat = (GL_stat_f)pathstat;
639
}
640
if (!gp->gl_lstat)
641
gp->gl_lstat = (GL_stat_f)lstat;
642
if (!gp->gl_intr)
643
gp->gl_intr = &intr;
644
if (!gp->gl_delim)
645
gp->gl_delim = '/';
646
if (!gp->gl_diropen)
647
gp->gl_diropen = gl_diropen;
648
if (!gp->gl_dirnext)
649
gp->gl_dirnext = gl_dirnext;
650
if (!gp->gl_dirclose)
651
gp->gl_dirclose = gl_dirclose;
652
if (!gp->gl_type)
653
gp->gl_type = gl_type;
654
if (!gp->gl_attr)
655
gp->gl_attr = gl_attr;
656
if (flags & GLOB_GROUP)
657
gp->re_flags |= REG_SHELL_GROUP;
658
if (flags & GLOB_ICASE)
659
gp->re_flags |= REG_ICASE;
660
if (!gp->gl_fignore)
661
gp->re_flags |= REG_SHELL_DOT;
662
else if (*gp->gl_fignore)
663
{
664
if (regcomp(&gp->re_ignore, gp->gl_fignore, gp->re_flags))
665
return GLOB_APPERR;
666
gp->gl_ignore = &gp->re_ignore;
667
}
668
if (gp->gl_flags & GLOB_STACK)
669
gp->gl_stak = 0;
670
else if (!(gp->gl_stak = stakcreate(0)))
671
return GLOB_NOSPACE;
672
if ((gp->gl_flags & GLOB_COMPLETE) && !gp->gl_nextdir)
673
gp->gl_nextdir = gl_nextdir;
674
}
675
skip = gp->gl_pathc;
676
if (gp->gl_stak)
677
oldstak = stakinstall(gp->gl_stak, 0);
678
if (flags & GLOB_DOOFFS)
679
extra += gp->gl_offs;
680
if (gp->gl_suffix)
681
suflen = strlen(gp->gl_suffix);
682
if (*(pat = (char*)pattern) == '~' && *(pat + 1) == '(')
683
{
684
f = gp->gl_flags;
685
n = 1;
686
x = 1;
687
pat += 2;
688
for (;;)
689
{
690
switch (*pat++)
691
{
692
case 0:
693
case ':':
694
break;
695
case '-':
696
n = 0;
697
continue;
698
case '+':
699
n = 1;
700
continue;
701
case 'i':
702
if (n)
703
f |= GLOB_ICASE;
704
else
705
f &= ~GLOB_ICASE;
706
continue;
707
case 'M':
708
if (n)
709
f |= GLOB_BRACE;
710
else
711
f &= ~GLOB_BRACE;
712
continue;
713
case 'N':
714
if (n)
715
f &= ~GLOB_NOCHECK;
716
else
717
f |= GLOB_NOCHECK;
718
continue;
719
case 'O':
720
if (n)
721
f |= GLOB_STARSTAR;
722
else
723
f &= ~GLOB_STARSTAR;
724
continue;
725
case ')':
726
flags = (gp->gl_flags = f) & 0xffff;
727
if (f & GLOB_ICASE)
728
gp->re_flags |= REG_ICASE;
729
else
730
gp->re_flags &= ~REG_ICASE;
731
if (x)
732
optlen = pat - (char*)pattern;
733
break;
734
default:
735
x = 0;
736
continue;
737
}
738
break;
739
}
740
}
741
top = ap = (globlist_t*)stakalloc((optlen ? 2 : 1) * strlen(pattern) + sizeof(globlist_t) + suflen + gp->gl_extra);
742
ap->gl_next = 0;
743
ap->gl_flags = 0;
744
ap->gl_begin = ap->gl_path + gp->gl_extra;
745
pat = strcopy(ap->gl_begin, pattern + optlen);
746
if (suflen)
747
pat = strcopy(pat, gp->gl_suffix);
748
if (optlen)
749
strlcpy(gp->gl_pat = gp->gl_opt = pat + 1, pattern, optlen);
750
else
751
gp->gl_pat = 0;
752
suflen = 0;
753
if (!(flags & GLOB_LIST))
754
gp->gl_match = 0;
755
re_flags = gp->re_flags;
756
gp->re_first = 1;
757
do
758
{
759
gp->gl_rescan = ap->gl_next;
760
glob_dir(gp, ap, re_flags);
761
} while (!gp->gl_error && (ap = gp->gl_rescan));
762
gp->re_flags = re_flags;
763
if (gp->gl_pathc == skip)
764
{
765
if (flags & GLOB_NOCHECK)
766
{
767
gp->gl_pathc++;
768
top->gl_next = gp->gl_match;
769
gp->gl_match = top;
770
strcopy(top->gl_path + gp->gl_extra, nocheck);
771
}
772
else
773
gp->gl_error = GLOB_NOMATCH;
774
}
775
if (flags & GLOB_LIST)
776
gp->gl_list = gp->gl_match;
777
else
778
{
779
argv = (char**)stakalloc((gp->gl_pathc + extra) * sizeof(char*));
780
if (gp->gl_flags & GLOB_APPEND)
781
{
782
skip += --extra;
783
memcpy(argv, gp->gl_pathv, skip * sizeof(char*));
784
av = argv + skip;
785
}
786
else
787
{
788
av = argv;
789
while (--extra > 0)
790
*av++ = 0;
791
}
792
gp->gl_pathv = argv;
793
argv = av;
794
ap = gp->gl_match;
795
while (ap)
796
{
797
*argv++ = ap->gl_path + gp->gl_extra;
798
ap = ap->gl_next;
799
}
800
*argv = 0;
801
if (!(flags & GLOB_NOSORT) && (argv - av) > 1)
802
{
803
strsort(av, argv - av, strcoll);
804
if (gp->gl_starstar > 1)
805
av[gp->gl_pathc = struniq(av, argv - av)] = 0;
806
gp->gl_starstar = 0;
807
}
808
}
809
if (gp->gl_starstar > 1)
810
gp->gl_flags &= ~GLOB_STARSTAR;
811
if (gp->gl_stak)
812
stakinstall(oldstak, 0);
813
return gp->gl_error;
814
}
815
816
void
817
globfree(glob_t* gp)
818
{
819
if ((gp->gl_flags & GLOB_MAGIC) == GLOB_MAGIC)
820
{
821
gp->gl_flags &= ~GLOB_MAGIC;
822
if (gp->gl_stak)
823
stkclose(gp->gl_stak);
824
if (gp->gl_ignore)
825
regfree(gp->gl_ignore);
826
if (gp->gl_ignorei)
827
regfree(gp->gl_ignorei);
828
}
829
}
830
831