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* 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 /* 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 574 _closedir(void *ptr) 575 { 576 (void) closedir(ptr); 577 } 578 579 int 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 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