1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A
1N/A/*
1N/A * file name expansion - posix.2 glob with gnu and ast extensions
1N/A *
1N/A * David Korn
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A */
1N/A
1N/A#include <ast.h>
1N/A#include <ls.h>
1N/A#include <stak.h>
1N/A#include <ast_dir.h>
1N/A#include <error.h>
1N/A#include <ctype.h>
1N/A#include <regex.h>
1N/A
1N/A#define GLOB_MAGIC 0xaaaa0000
1N/A
1N/A#define MATCH_RAW 1
1N/A#define MATCH_MAKE 2
1N/A#define MATCH_META 4
1N/A
1N/A#define MATCHPATH(g) (offsetof(globlist_t,gl_path)+(g)->gl_extra)
1N/A
1N/Atypedef int (*GL_error_f)(const char*, int);
1N/Atypedef void* (*GL_opendir_f)(const char*);
1N/Atypedef struct dirent* (*GL_readdir_f)(void*);
1N/Atypedef void (*GL_closedir_f)(void*);
1N/Atypedef int (*GL_stat_f)(const char*, struct stat*);
1N/A
1N/A#define _GLOB_PRIVATE_ \
1N/A GL_error_f gl_errfn; \
1N/A int gl_error; \
1N/A char* gl_nextpath; \
1N/A globlist_t* gl_rescan; \
1N/A globlist_t* gl_match; \
1N/A Stak_t* gl_stak; \
1N/A int re_flags; \
1N/A int re_first; \
1N/A regex_t* gl_ignore; \
1N/A regex_t* gl_ignorei; \
1N/A regex_t re_ignore; \
1N/A regex_t re_ignorei; \
1N/A unsigned long gl_starstar; \
1N/A char* gl_opt; \
1N/A char* gl_pat; \
1N/A char* gl_pad[4];
1N/A
1N/A#include <glob.h>
1N/A
1N/A/*
1N/A * default gl_diropen
1N/A */
1N/A
1N/Astatic void*
1N/Agl_diropen(glob_t* gp, const char* path)
1N/A{
1N/A return (*gp->gl_opendir)(path);
1N/A}
1N/A
1N/A/*
1N/A * default gl_dirnext
1N/A */
1N/A
1N/Astatic char*
1N/Agl_dirnext(glob_t* gp, void* handle)
1N/A{
1N/A struct dirent* dp;
1N/A
1N/A while (dp = (struct dirent*)(*gp->gl_readdir)(handle))
1N/A {
1N/A#ifdef D_TYPE
1N/A if (D_TYPE(dp) != DT_UNKNOWN && D_TYPE(dp) != DT_DIR && D_TYPE(dp) != DT_LNK)
1N/A gp->gl_status |= GLOB_NOTDIR;
1N/A#endif
1N/A return dp->d_name;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/A/*
1N/A * default gl_dirclose
1N/A */
1N/A
1N/Astatic void
1N/Agl_dirclose(glob_t* gp, void* handle)
1N/A{
1N/A (gp->gl_closedir)(handle);
1N/A}
1N/A
1N/A/*
1N/A * default gl_type
1N/A */
1N/A
1N/Astatic int
1N/Agl_type(glob_t* gp, const char* path, int flags)
1N/A{
1N/A register int type;
1N/A struct stat st;
1N/A
1N/A if ((flags & GLOB_STARSTAR) ? (*gp->gl_lstat)(path, &st) : (*gp->gl_stat)(path, &st))
1N/A type = 0;
1N/A else if (S_ISDIR(st.st_mode))
1N/A type = GLOB_DIR;
1N/A else if (!S_ISREG(st.st_mode))
1N/A type = GLOB_DEV;
1N/A else if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1N/A type = GLOB_EXE;
1N/A else
1N/A type = GLOB_REG;
1N/A return type;
1N/A}
1N/A
1N/A/*
1N/A * default gl_attr
1N/A */
1N/A
1N/Astatic int
1N/Agl_attr(glob_t* gp, const char* path, int flags)
1N/A{
1N/A return strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? GLOB_ICASE : 0;
1N/A}
1N/A
1N/A/*
1N/A * default gl_nextdir
1N/A */
1N/A
1N/Astatic char*
1N/Agl_nextdir(glob_t* gp, char* dir)
1N/A{
1N/A if (!(dir = gp->gl_nextpath))
1N/A dir = gp->gl_nextpath = stakcopy(pathbin());
1N/A switch (*gp->gl_nextpath)
1N/A {
1N/A case 0:
1N/A dir = 0;
1N/A break;
1N/A case ':':
1N/A while (*gp->gl_nextpath == ':')
1N/A gp->gl_nextpath++;
1N/A dir = ".";
1N/A break;
1N/A default:
1N/A while (*gp->gl_nextpath)
1N/A if (*gp->gl_nextpath++ == ':')
1N/A {
1N/A *(gp->gl_nextpath - 1) = 0;
1N/A break;
1N/A }
1N/A break;
1N/A }
1N/A return dir;
1N/A}
1N/A
1N/A/*
1N/A * error intercept
1N/A */
1N/A
1N/Astatic int
1N/Aerrorcheck(register glob_t* gp, const char* path)
1N/A{
1N/A int r = 1;
1N/A
1N/A if (gp->gl_errfn)
1N/A r = (*gp->gl_errfn)(path, errno);
1N/A if (gp->gl_flags & GLOB_ERR)
1N/A r = 0;
1N/A if (!r)
1N/A gp->gl_error = GLOB_ABORTED;
1N/A return r;
1N/A}
1N/A
1N/A/*
1N/A * remove backslashes
1N/A */
1N/A
1N/Astatic void
1N/Atrim(register char* sp, register char* p1, int* n1, register char* p2, int* n2)
1N/A{
1N/A register char* dp = sp;
1N/A register int c;
1N/A
1N/A if (p1)
1N/A *n1 = 0;
1N/A if (p2)
1N/A *n2 = 0;
1N/A do
1N/A {
1N/A if ((c = *sp++) == '\\')
1N/A c = *sp++;
1N/A if (sp == p1)
1N/A {
1N/A p1 = 0;
1N/A *n1 = sp - dp - 1;
1N/A }
1N/A if (sp == p2)
1N/A {
1N/A p2 = 0;
1N/A *n2 = sp - dp - 1;
1N/A }
1N/A } while (*dp++ = c);
1N/A}
1N/A
1N/Astatic void
1N/Aaddmatch(register glob_t* gp, const char* dir, const char* pat, register const char* rescan, char* endslash, int meta)
1N/A{
1N/A register globlist_t* ap;
1N/A int offset;
1N/A int type;
1N/A
1N/A stakseek(MATCHPATH(gp));
1N/A if (dir)
1N/A {
1N/A stakputs(dir);
1N/A stakputc(gp->gl_delim);
1N/A }
1N/A if (endslash)
1N/A *endslash = 0;
1N/A stakputs(pat);
1N/A if (rescan)
1N/A {
1N/A if ((*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0) != GLOB_DIR)
1N/A return;
1N/A stakputc(gp->gl_delim);
1N/A offset = staktell();
1N/A /* if null, reserve room for . */
1N/A if (*rescan)
1N/A stakputs(rescan);
1N/A else
1N/A stakputc(0);
1N/A stakputc(0);
1N/A rescan = stakptr(offset);
1N/A ap = (globlist_t*)stakfreeze(0);
1N/A ap->gl_begin = (char*)rescan;
1N/A ap->gl_next = gp->gl_rescan;
1N/A gp->gl_rescan = ap;
1N/A }
1N/A else
1N/A {
1N/A if (!endslash && (gp->gl_flags & GLOB_MARK) && (type = (*gp->gl_type)(gp, stakptr(MATCHPATH(gp)), 0)))
1N/A {
1N/A if ((gp->gl_flags & GLOB_COMPLETE) && type != GLOB_EXE)
1N/A {
1N/A stakseek(0);
1N/A return;
1N/A }
1N/A else if (type == GLOB_DIR && (gp->gl_flags & GLOB_MARK))
1N/A stakputc(gp->gl_delim);
1N/A }
1N/A ap = (globlist_t*)stakfreeze(1);
1N/A ap->gl_next = gp->gl_match;
1N/A gp->gl_match = ap;
1N/A gp->gl_pathc++;
1N/A }
1N/A ap->gl_flags = MATCH_RAW|meta;
1N/A if (gp->gl_flags & GLOB_COMPLETE)
1N/A ap->gl_flags |= MATCH_MAKE;
1N/A}
1N/A
1N/A/*
1N/A * this routine builds a list of files that match a given pathname
1N/A * uses REG_SHELL of <regex> to match each component
1N/A * a leading . must match explicitly
1N/A */
1N/A
1N/Astatic void
1N/Aglob_dir(glob_t* gp, globlist_t* ap, int re_flags)
1N/A{
1N/A register char* rescan;
1N/A register char* prefix;
1N/A register char* pat;
1N/A register char* name;
1N/A register int c;
1N/A char* dirname;
1N/A void* dirf;
1N/A char first;
1N/A regex_t* ire;
1N/A regex_t* pre;
1N/A regex_t rec;
1N/A regex_t rei;
1N/A int notdir;
1N/A int t1;
1N/A int t2;
1N/A int bracket;
1N/A
1N/A int anymeta = ap->gl_flags & MATCH_META;
1N/A int complete = 0;
1N/A int err = 0;
1N/A int meta = ((gp->re_flags & REG_ICASE) && *ap->gl_begin != '/') ? MATCH_META : 0;
1N/A int quote = 0;
1N/A int savequote = 0;
1N/A char* restore1 = 0;
1N/A char* restore2 = 0;
1N/A regex_t* prec = 0;
1N/A regex_t* prei = 0;
1N/A char* matchdir = 0;
1N/A int starstar = 0;
1N/A
1N/A if (*gp->gl_intr)
1N/A {
1N/A gp->gl_error = GLOB_INTR;
1N/A return;
1N/A }
1N/A pat = rescan = ap->gl_begin;
1N/A prefix = dirname = ap->gl_path + gp->gl_extra;
1N/A first = (rescan == prefix);
1N/Aagain:
1N/A bracket = 0;
1N/A for (;;)
1N/A {
1N/A switch (c = *rescan++)
1N/A {
1N/A case 0:
1N/A if (meta)
1N/A {
1N/A rescan = 0;
1N/A break;
1N/A }
1N/A if (quote)
1N/A {
1N/A trim(ap->gl_begin, rescan, &t1, NiL, NiL);
1N/A rescan -= t1;
1N/A }
1N/A if (!first && !*rescan && *(rescan - 2) == gp->gl_delim)
1N/A {
1N/A *(rescan - 2) = 0;
1N/A c = (*gp->gl_type)(gp, prefix, 0);
1N/A *(rescan - 2) = gp->gl_delim;
1N/A if (c == GLOB_DIR)
1N/A addmatch(gp, NiL, prefix, NiL, rescan - 1, anymeta);
1N/A }
1N/A else if ((anymeta || !(gp->gl_flags & GLOB_NOCHECK)) && (*gp->gl_type)(gp, prefix, 0))
1N/A addmatch(gp, NiL, prefix, NiL, NiL, anymeta);
1N/A return;
1N/A case '[':
1N/A if (!bracket)
1N/A {
1N/A bracket = MATCH_META;
1N/A if (*rescan == '!' || *rescan == '^')
1N/A rescan++;
1N/A if (*rescan == ']')
1N/A rescan++;
1N/A }
1N/A continue;
1N/A case ']':
1N/A meta |= bracket;
1N/A continue;
1N/A case '(':
1N/A if (!(gp->gl_flags & GLOB_AUGMENTED))
1N/A continue;
1N/A case '*':
1N/A case '?':
1N/A meta = MATCH_META;
1N/A continue;
1N/A case '\\':
1N/A if (!(gp->gl_flags & GLOB_NOESCAPE))
1N/A {
1N/A quote = 1;
1N/A if (*rescan)
1N/A rescan++;
1N/A }
1N/A continue;
1N/A default:
1N/A if (c == gp->gl_delim)
1N/A {
1N/A if (meta)
1N/A break;
1N/A pat = rescan;
1N/A bracket = 0;
1N/A savequote = quote;
1N/A }
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A anymeta |= meta;
1N/A if (matchdir)
1N/A goto skip;
1N/A if (pat == prefix)
1N/A {
1N/A prefix = 0;
1N/A if (!rescan && (gp->gl_flags & GLOB_COMPLETE))
1N/A {
1N/A complete = 1;
1N/A dirname = 0;
1N/A }
1N/A else
1N/A dirname = ".";
1N/A }
1N/A else
1N/A {
1N/A if (pat == prefix + 1)
1N/A dirname = "/";
1N/A if (savequote)
1N/A {
1N/A quote = 0;
1N/A trim(ap->gl_begin, pat, &t1, rescan, &t2);
1N/A pat -= t1;
1N/A if (rescan)
1N/A rescan -= t2;
1N/A }
1N/A *(restore1 = pat - 1) = 0;
1N/A }
1N/A if (!complete && (gp->gl_flags & GLOB_STARSTAR))
1N/A while (pat[0] == '*' && pat[1] == '*' && (pat[2] == '/' || pat[2]==0))
1N/A {
1N/A matchdir = pat;
1N/A if (pat[2])
1N/A {
1N/A pat += 3;
1N/A while (*pat=='/')
1N/A pat++;
1N/A if (*pat)
1N/A continue;
1N/A }
1N/A rescan = *pat?0:pat;
1N/A pat = "*";
1N/A goto skip;
1N/A }
1N/A if (matchdir)
1N/A {
1N/A rescan = pat;
1N/A goto again;
1N/A }
1N/Askip:
1N/A if (rescan)
1N/A *(restore2 = rescan - 1) = 0;
1N/A if (rescan && !complete && (gp->gl_flags & GLOB_STARSTAR))
1N/A {
1N/A register char* p = rescan;
1N/A
1N/A while (p[0] == '*' && p[1] == '*' && (p[2] == '/' || p[2]==0))
1N/A {
1N/A rescan = p;
1N/A if (starstar = (p[2]==0))
1N/A break;
1N/A p += 3;
1N/A while (*p=='/')
1N/A p++;
1N/A if (*p==0)
1N/A {
1N/A starstar = 2;
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A if (matchdir)
1N/A gp->gl_starstar++;
1N/A if (gp->gl_opt)
1N/A pat = strcpy(gp->gl_opt, pat);
1N/A for (;;)
1N/A {
1N/A if (complete)
1N/A {
1N/A if (!(dirname = (*gp->gl_nextdir)(gp, dirname)))
1N/A break;
1N/A prefix = streq(dirname, ".") ? (char*)0 : dirname;
1N/A }
1N/A if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
1N/A {
1N/A if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
1N/A {
1N/A if (!prei)
1N/A {
1N/A if (err = regcomp(&rei, pat, gp->re_flags|REG_ICASE))
1N/A break;
1N/A prei = &rei;
1N/A if (gp->re_first)
1N/A {
1N/A gp->re_first = 0;
1N/A gp->re_flags = regstat(prei)->re_flags & ~REG_ICASE;
1N/A }
1N/A }
1N/A pre = prei;
1N/A }
1N/A else
1N/A {
1N/A if (!prec)
1N/A {
1N/A if (err = regcomp(&rec, pat, gp->re_flags))
1N/A break;
1N/A prec = &rec;
1N/A if (gp->re_first)
1N/A {
1N/A gp->re_first = 0;
1N/A gp->re_flags = regstat(prec)->re_flags;
1N/A }
1N/A }
1N/A pre = prec;
1N/A }
1N/A if ((ire = gp->gl_ignore) && (gp->re_flags & REG_ICASE))
1N/A {
1N/A if (!gp->gl_ignorei)
1N/A {
1N/A if (regcomp(&gp->re_ignorei, gp->gl_fignore, re_flags|REG_ICASE))
1N/A {
1N/A gp->gl_error = GLOB_APPERR;
1N/A break;
1N/A }
1N/A gp->gl_ignorei = &gp->re_ignorei;
1N/A }
1N/A ire = gp->gl_ignorei;
1N/A }
1N/A if (restore2)
1N/A *restore2 = gp->gl_delim;
1N/A while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
1N/A {
1N/A if (notdir = (gp->gl_status & GLOB_NOTDIR))
1N/A gp->gl_status &= ~GLOB_NOTDIR;
1N/A if (ire && !regexec(ire, name, 0, NiL, 0))
1N/A continue;
1N/A if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
1N/A addmatch(gp, prefix, name, matchdir, NiL, anymeta);
1N/A if (!regexec(pre, name, 0, NiL, 0))
1N/A {
1N/A if (!rescan || !notdir)
1N/A addmatch(gp, prefix, name, rescan, NiL, anymeta);
1N/A if (starstar==1 || (starstar==2 && !notdir))
1N/A addmatch(gp, prefix, name, starstar==2?"":NiL, NiL, anymeta);
1N/A }
1N/A errno = 0;
1N/A }
1N/A (*gp->gl_dirclose)(gp, dirf);
1N/A if (err || errno && !errorcheck(gp, dirname))
1N/A break;
1N/A }
1N/A else if (!complete && !errorcheck(gp, dirname))
1N/A break;
1N/A if (!complete)
1N/A break;
1N/A if (*gp->gl_intr)
1N/A {
1N/A gp->gl_error = GLOB_INTR;
1N/A break;
1N/A }
1N/A }
1N/A if (restore1)
1N/A *restore1 = gp->gl_delim;
1N/A if (restore2)
1N/A *restore2 = gp->gl_delim;
1N/A if (prec)
1N/A regfree(prec);
1N/A if (prei)
1N/A regfree(prei);
1N/A if (err == REG_ESPACE)
1N/A gp->gl_error = GLOB_NOSPACE;
1N/A}
1N/A
1N/Aint
1N/Aglob(const char* pattern, int flags, int (*errfn)(const char*, int), register glob_t* gp)
1N/A{
1N/A register globlist_t* ap;
1N/A register char* pat;
1N/A globlist_t* top;
1N/A Stak_t* oldstak;
1N/A char** argv;
1N/A char** av;
1N/A size_t skip;
1N/A unsigned long f;
1N/A int n;
1N/A int x;
1N/A int re_flags;
1N/A
1N/A const char* nocheck = pattern;
1N/A int optlen = 0;
1N/A int suflen = 0;
1N/A int extra = 1;
1N/A unsigned char intr = 0;
1N/A
1N/A gp->gl_rescan = 0;
1N/A gp->gl_error = 0;
1N/A gp->gl_errfn = errfn;
1N/A if (flags & GLOB_APPEND)
1N/A {
1N/A if ((gp->gl_flags |= GLOB_APPEND) ^ (flags|GLOB_MAGIC))
1N/A return GLOB_APPERR;
1N/A if (((gp->gl_flags & GLOB_STACK) == 0) == (gp->gl_stak == 0))
1N/A return GLOB_APPERR;
1N/A if (gp->gl_starstar > 1)
1N/A gp->gl_flags |= GLOB_STARSTAR;
1N/A else
1N/A gp->gl_starstar = 0;
1N/A }
1N/A else
1N/A {
1N/A gp->gl_flags = (flags&0xffff)|GLOB_MAGIC;
1N/A gp->re_flags = REG_SHELL|REG_NOSUB|REG_LEFT|REG_RIGHT|((flags&GLOB_AUGMENTED)?REG_AUGMENTED:0);
1N/A gp->gl_pathc = 0;
1N/A gp->gl_ignore = 0;
1N/A gp->gl_ignorei = 0;
1N/A gp->gl_starstar = 0;
1N/A if (!(flags & GLOB_DISC))
1N/A {
1N/A gp->gl_fignore = 0;
1N/A gp->gl_suffix = 0;
1N/A gp->gl_intr = 0;
1N/A gp->gl_delim = 0;
1N/A gp->gl_handle = 0;
1N/A gp->gl_diropen = 0;
1N/A gp->gl_dirnext = 0;
1N/A gp->gl_dirclose = 0;
1N/A gp->gl_type = 0;
1N/A gp->gl_attr = 0;
1N/A gp->gl_nextdir = 0;
1N/A gp->gl_stat = 0;
1N/A gp->gl_lstat = 0;
1N/A gp->gl_extra = 0;
1N/A }
1N/A if (!(flags & GLOB_ALTDIRFUNC))
1N/A {
1N/A gp->gl_opendir = (GL_opendir_f)opendir;
1N/A gp->gl_readdir = (GL_readdir_f)readdir;
1N/A gp->gl_closedir = (GL_closedir_f)closedir;
1N/A if (!gp->gl_stat)
1N/A gp->gl_stat = (GL_stat_f)pathstat;
1N/A }
1N/A if (!gp->gl_lstat)
1N/A gp->gl_lstat = (GL_stat_f)lstat;
1N/A if (!gp->gl_intr)
1N/A gp->gl_intr = &intr;
1N/A if (!gp->gl_delim)
1N/A gp->gl_delim = '/';
1N/A if (!gp->gl_diropen)
1N/A gp->gl_diropen = gl_diropen;
1N/A if (!gp->gl_dirnext)
1N/A gp->gl_dirnext = gl_dirnext;
1N/A if (!gp->gl_dirclose)
1N/A gp->gl_dirclose = gl_dirclose;
1N/A if (!gp->gl_type)
1N/A gp->gl_type = gl_type;
1N/A if (!gp->gl_attr)
1N/A gp->gl_attr = gl_attr;
1N/A if (flags & GLOB_GROUP)
1N/A gp->re_flags |= REG_SHELL_GROUP;
1N/A if (flags & GLOB_ICASE)
1N/A gp->re_flags |= REG_ICASE;
1N/A if (!gp->gl_fignore)
1N/A gp->re_flags |= REG_SHELL_DOT;
1N/A else if (*gp->gl_fignore)
1N/A {
1N/A if (regcomp(&gp->re_ignore, gp->gl_fignore, gp->re_flags))
1N/A return GLOB_APPERR;
1N/A gp->gl_ignore = &gp->re_ignore;
1N/A }
1N/A if (gp->gl_flags & GLOB_STACK)
1N/A gp->gl_stak = 0;
1N/A else if (!(gp->gl_stak = stakcreate(0)))
1N/A return GLOB_NOSPACE;
1N/A if ((gp->gl_flags & GLOB_COMPLETE) && !gp->gl_nextdir)
1N/A gp->gl_nextdir = gl_nextdir;
1N/A }
1N/A skip = gp->gl_pathc;
1N/A if (gp->gl_stak)
1N/A oldstak = stakinstall(gp->gl_stak, 0);
1N/A if (flags & GLOB_DOOFFS)
1N/A extra += gp->gl_offs;
1N/A if (gp->gl_suffix)
1N/A suflen = strlen(gp->gl_suffix);
1N/A if (*(pat = (char*)pattern) == '~' && *(pat + 1) == '(')
1N/A {
1N/A f = gp->gl_flags;
1N/A n = 1;
1N/A x = 1;
1N/A pat += 2;
1N/A for (;;)
1N/A {
1N/A switch (*pat++)
1N/A {
1N/A case 0:
1N/A case ':':
1N/A break;
1N/A case '-':
1N/A n = 0;
1N/A continue;
1N/A case '+':
1N/A n = 1;
1N/A continue;
1N/A case 'i':
1N/A if (n)
1N/A f |= GLOB_ICASE;
1N/A else
1N/A f &= ~GLOB_ICASE;
1N/A continue;
1N/A case 'M':
1N/A if (n)
1N/A f |= GLOB_BRACE;
1N/A else
1N/A f &= ~GLOB_BRACE;
1N/A continue;
1N/A case 'N':
1N/A if (n)
1N/A f &= ~GLOB_NOCHECK;
1N/A else
1N/A f |= GLOB_NOCHECK;
1N/A continue;
1N/A case 'O':
1N/A if (n)
1N/A f |= GLOB_STARSTAR;
1N/A else
1N/A f &= ~GLOB_STARSTAR;
1N/A continue;
1N/A case ')':
1N/A flags = (gp->gl_flags = f) & 0xffff;
1N/A if (f & GLOB_ICASE)
1N/A gp->re_flags |= REG_ICASE;
1N/A else
1N/A gp->re_flags &= ~REG_ICASE;
1N/A if (x)
1N/A optlen = pat - (char*)pattern;
1N/A break;
1N/A default:
1N/A x = 0;
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A }
1N/A top = ap = (globlist_t*)stakalloc((optlen ? 2 : 1) * strlen(pattern) + sizeof(globlist_t) + suflen + gp->gl_extra);
1N/A ap->gl_next = 0;
1N/A ap->gl_flags = 0;
1N/A ap->gl_begin = ap->gl_path + gp->gl_extra;
1N/A pat = strcopy(ap->gl_begin, pattern + optlen);
1N/A if (suflen)
1N/A pat = strcopy(pat, gp->gl_suffix);
1N/A if (optlen)
1N/A strlcpy(gp->gl_pat = gp->gl_opt = pat + 1, pattern, optlen);
1N/A else
1N/A gp->gl_pat = 0;
1N/A suflen = 0;
1N/A if (!(flags & GLOB_LIST))
1N/A gp->gl_match = 0;
1N/A re_flags = gp->re_flags;
1N/A gp->re_first = 1;
1N/A do
1N/A {
1N/A gp->gl_rescan = ap->gl_next;
1N/A glob_dir(gp, ap, re_flags);
1N/A } while (!gp->gl_error && (ap = gp->gl_rescan));
1N/A gp->re_flags = re_flags;
1N/A if (gp->gl_pathc == skip)
1N/A {
1N/A if (flags & GLOB_NOCHECK)
1N/A {
1N/A gp->gl_pathc++;
1N/A top->gl_next = gp->gl_match;
1N/A gp->gl_match = top;
1N/A strcopy(top->gl_path + gp->gl_extra, nocheck);
1N/A }
1N/A else
1N/A gp->gl_error = GLOB_NOMATCH;
1N/A }
1N/A if (flags & GLOB_LIST)
1N/A gp->gl_list = gp->gl_match;
1N/A else
1N/A {
1N/A argv = (char**)stakalloc((gp->gl_pathc + extra) * sizeof(char*));
1N/A if (gp->gl_flags & GLOB_APPEND)
1N/A {
1N/A skip += --extra;
1N/A memcpy(argv, gp->gl_pathv, skip * sizeof(char*));
1N/A av = argv + skip;
1N/A }
1N/A else
1N/A {
1N/A av = argv;
1N/A while (--extra > 0)
1N/A *av++ = 0;
1N/A }
1N/A gp->gl_pathv = argv;
1N/A argv = av;
1N/A ap = gp->gl_match;
1N/A while (ap)
1N/A {
1N/A *argv++ = ap->gl_path + gp->gl_extra;
1N/A ap = ap->gl_next;
1N/A }
1N/A *argv = 0;
1N/A if (!(flags & GLOB_NOSORT) && (argv - av) > 1)
1N/A {
1N/A strsort(av, argv - av, strcoll);
1N/A if (gp->gl_starstar > 1)
1N/A av[gp->gl_pathc = struniq(av, argv - av)] = 0;
1N/A gp->gl_starstar = 0;
1N/A }
1N/A }
1N/A if (gp->gl_starstar > 1)
1N/A gp->gl_flags &= ~GLOB_STARSTAR;
1N/A if (gp->gl_stak)
1N/A stakinstall(oldstak, 0);
1N/A return gp->gl_error;
1N/A}
1N/A
1N/Avoid
1N/Aglobfree(glob_t* gp)
1N/A{
1N/A if ((gp->gl_flags & GLOB_MAGIC) == GLOB_MAGIC)
1N/A {
1N/A gp->gl_flags &= ~GLOB_MAGIC;
1N/A if (gp->gl_stak)
1N/A stkclose(gp->gl_stak);
1N/A if (gp->gl_ignore)
1N/A regfree(gp->gl_ignore);
1N/A if (gp->gl_ignorei)
1N/A regfree(gp->gl_ignorei);
1N/A }
1N/A}