1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 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* 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* 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 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 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 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* 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 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 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 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 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 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 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