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