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 48typedef int (*GL_error_f)(const char*, int); 49typedef void* (*GL_opendir_f)(const char*); 50typedef struct dirent* (*GL_readdir_f)(void*); 51typedef void (*GL_closedir_f)(void*); 52typedef 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 78static void* 79gl_diropen(glob_t* gp, const char* path) 80{ 81 return (*gp->gl_opendir)(path); 82} 83 84/* 85 * default gl_dirnext 86 */ 87 88static char* 89gl_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 108static void 109gl_dirclose(glob_t* gp, void* handle) 110{ 111 (gp->gl_closedir)(handle); 112} 113 114/* 115 * default gl_type 116 */ 117 118static int 119gl_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 141static int 142gl_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 151static char* 152gl_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 182static int 183errorcheck(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 200static void 201trim(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 227static void 228addmatch(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 289static void 290glob_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); 330again: 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 } 448skip: 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 572int 573glob(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 816void 817globfree(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