#include "defs.h"
#include "config.h"
#if defined(NEED_GLOB)
#include <sys/param.h>
#ifdef __EMX__
#include <sys/types.h>
#endif
#include <sys/stat.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include "bsdglob.h"
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ircaux.h"
#define MAIN_SOURCE
#include "modval.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN PATHLEN
#endif
#undef EOS
#define DOLLAR '$'
#define DOT '.'
#define EOS '\0'
#define LBRACKET '['
#define NOT '!'
#define QUESTION '?'
#define QUOTE '\\'
#define RANGE '-'
#define RBRACKET ']'
#define SEP '/'
#define STAR '*'
#define TILDE '~'
#define UNDERSCORE '_'
#define LBRACE '{'
#define RBRACE '}'
#define SLASH '/'
#define COMMA ','
#define M_QUOTE 0x8000
#define M_PROTECT 0x4000
#define M_ANYCASE 0x2000
#define M_MASK 0xffff
#define M_ASCII 0x00ff
#if 0
#ifdef ULTRIX
#define S_IFLNK 0120000
#define S_ISLNK( mode ) (((mode) & _S_IFMT) == S_IFLNK)
#endif
#endif
typedef u_short Char;
#define CHAR(c) ((Char)((c)&M_ASCII))
#define META(c) ((Char)((c)|M_QUOTE))
#define M_ALL META('*')
#define M_END META(']')
#define M_NOT META('!')
#define M_ONE META('?')
#define M_RNG META('-')
#define M_SET META('[')
#define ismeta(c) (((c)&M_QUOTE) != 0)
static int compare (const void *, const void *);
static void g_Ctoc (const Char *, char *);
static int g_lstat (Char *, struct stat *, glob_t *);
static DIR * g_opendir (Char *, glob_t *);
static Char * g_strchr (Char *, int);
#ifdef S_ISLNK
static int g_stat (Char *, struct stat *, glob_t *);
#endif
static int glob0 (const Char *, glob_t *);
static int glob1 (Char *, glob_t *);
static int glob2 (Char *, Char *, Char *, glob_t *);
static int glob3 (Char *, Char *, Char *, Char *, glob_t *);
static int globextend (const Char *, glob_t *);
static const Char * globtilde (const Char *, Char *, glob_t *);
static int globexp1 (const Char *, glob_t *);
static int globexp2 (const Char *, const Char *, glob_t *, int *);
static int match (Char *, Char *, Char *, int);
int BX_bsd_glob ( const char *pattern,
int flags,
int (*errfunc) (const char *, int),
glob_t *pglob )
{
const u_char *patnext;
int c;
Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
#if defined(__EMX__) || defined(WINNT)
strlwr((char *)pattern);
#endif
patnext = (u_char *) pattern;
if (!(flags & GLOB_APPEND)) {
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
if (!(flags & GLOB_DOOFFS))
pglob->gl_offs = 0;
}
pglob->gl_flags = flags & ~GLOB_MAGCHAR;
pglob->gl_errfunc = errfunc;
pglob->gl_matchc = 0;
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN;
if (flags & GLOB_QUOTE) {
while (bufnext < bufend && (c = *patnext++) != EOS)
if (c == QUOTE) {
if ((c = *patnext++) == EOS) {
c = QUOTE;
--patnext;
}
*bufnext++ = c | M_PROTECT;
}
else
*bufnext++ = c;
}
else
while (bufnext < bufend && (c = *patnext++) != EOS)
*bufnext++ = c;
*bufnext = EOS;
if (flags & GLOB_BRACE)
return globexp1(patbuf, pglob);
else
return glob0(patbuf, pglob);
}
static int globexp1 ( const Char *pattern,
glob_t *pglob )
{
const Char* ptr = pattern;
int rv;
if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
return glob0(pattern, pglob);
while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
if (!globexp2(ptr, pattern, pglob, &rv))
return rv;
return glob0(pattern, pglob);
}
static int globexp2 ( const Char *ptr,
const Char *pattern,
glob_t *pglob,
int *rv )
{
int i;
Char *lm, *ls;
const Char *pe, *pm, *pl;
Char patbuf[MAXPATHLEN + 1];
for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
continue;
ls = lm;
for (i = 0, pe = ++ptr; *pe; pe++)
if (*pe == LBRACKET)
{
for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
continue;
if (*pe == EOS)
{
pe = pm;
}
}
else if (*pe == LBRACE)
i++;
else if (*pe == RBRACE)
{
if (i == 0)
break;
i--;
}
if (i != 0 || *pe == EOS)
{
*rv = glob0(patbuf, pglob);
return 0;
}
for (i = 0, pl = pm = ptr; pm <= pe; pm++)
switch (*pm)
{
case LBRACKET:
for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
continue;
if (*pm == EOS)
{
pm = pl;
}
break;
case LBRACE:
i++;
break;
case RBRACE:
if (i)
{
i--;
break;
}
case COMMA:
if (i && *pm == COMMA)
break;
else
{
for (lm = ls; (pl < pm); *lm++ = *pl++)
continue;
for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
continue;
*rv = globexp1(patbuf, pglob);
pl = pm + 1;
}
break;
default:
break;
}
*rv = 0;
return 0;
}
static const Char *globtilde ( const Char *pattern,
Char *patbuf,
glob_t *pglob )
{
struct passwd *pwd;
char *h;
const Char *p;
Char *b;
if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
return pattern;
for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH;
*h++ = *p++)
continue;
*h = EOS;
if (((char *) patbuf)[0] == EOS) {
if ((h = getenv("HOME")) == NULL) {
if ((pwd = getpwuid(getuid())) == NULL)
return pattern;
else
h = pwd->pw_dir;
}
}
else {
if ((pwd = getpwnam((char*) patbuf)) == NULL)
return pattern;
else
h = pwd->pw_dir;
}
for (b = patbuf; *h; *b++ = *h++)
continue;
while ((*b++ = *p++) != EOS)
continue;
#if defined(__EMX__) || defined(WINNT)
convert_unix((char *)patbuf);
#endif
return patbuf;
}
static int glob0 ( const Char *pattern,
glob_t *pglob )
{
const Char *qpatnext;
int c, err, oldpathc;
Char *bufnext, patbuf[MAXPATHLEN+1];
qpatnext = globtilde(pattern, patbuf, pglob);
oldpathc = pglob->gl_pathc;
bufnext = patbuf;
while ((c = *qpatnext++) != EOS)
{
switch (c)
{
case LBRACKET:
c = *qpatnext;
if (c == NOT)
++qpatnext;
if (*qpatnext == EOS || g_strchr((Char *) qpatnext+1, RBRACKET) == NULL)
{
*bufnext++ = LBRACKET;
if (c == NOT)
--qpatnext;
break;
}
*bufnext++ = M_SET;
if (c == NOT)
*bufnext++ = M_NOT;
c = *qpatnext++;
do
{
*bufnext++ = CHAR(c);
if (*qpatnext == RANGE && (c = qpatnext[1]) != RBRACKET)
{
*bufnext++ = M_RNG;
*bufnext++ = CHAR(c);
qpatnext += 2;
}
}
while ((c = *qpatnext++) != RBRACKET);
pglob->gl_flags |= GLOB_MAGCHAR;
*bufnext++ = M_END;
break;
case QUESTION:
pglob->gl_flags |= GLOB_MAGCHAR;
*bufnext++ = M_ONE;
break;
case STAR:
pglob->gl_flags |= GLOB_MAGCHAR;
if (bufnext == patbuf || bufnext[-1] != M_ALL)
*bufnext++ = M_ALL;
break;
default:
*bufnext++ = CHAR(c);
break;
}
}
*bufnext = EOS;
if ((err = glob1(patbuf, pglob)) != 0)
return(err);
if (pglob->gl_pathc == oldpathc &&
((pglob->gl_flags & GLOB_NOCHECK) ||
((pglob->gl_flags & GLOB_NOMAGIC) &&
!(pglob->gl_flags & GLOB_MAGCHAR))))
return(globextend(pattern, pglob));
else if (!(pglob->gl_flags & GLOB_NOSORT))
{
if (pglob->gl_pathv)
qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
pglob->gl_pathc - oldpathc, sizeof(char *), compare);
}
return(0);
}
static int compare ( const void *p,
const void *q )
{
return(strcmp(*(char **)p, *(char **)q));
}
static int glob1 ( Char *pattern,
glob_t *pglob )
{
Char pathbuf[MAXPATHLEN+1];
if (*pattern == EOS)
return(0);
return(glob2(pathbuf, pathbuf, pattern, pglob));
}
static int glob2 ( Char *pathbuf,
Char *pathend,
Char *pattern,
glob_t *pglob )
{
struct stat sb;
Char *p, *q;
int anymeta;
for (anymeta = 0;;)
{
if (*pattern == EOS)
{
*pathend = EOS;
if (g_lstat(pathbuf, &sb, pglob))
return(0);
if (((pglob->gl_flags & GLOB_MARK) &&
pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
#ifdef S_ISLNK
|| (S_ISLNK(sb.st_mode) &&
(g_stat(pathbuf, &sb, pglob) == 0) &&
S_ISDIR(sb.st_mode))
#endif
))
{
*pathend++ = SEP;
*pathend = EOS;
}
++pglob->gl_matchc;
return(globextend(pathbuf, pglob));
}
q = pathend;
p = pattern;
while (*p != EOS && *p != SEP)
{
if (ismeta(*p))
anymeta = 1;
*q++ = *p++;
}
if (!anymeta)
{
pathend = q;
pattern = p;
while (*pattern == SEP)
*pathend++ = *pattern++;
} else
return(glob3(pathbuf, pathend, pattern, p, pglob));
}
}
static int glob3 ( Char *pathbuf,
Char *pathend,
Char *pattern,
Char *restpattern,
glob_t *pglob )
{
register struct dirent *dp;
DIR *dirp;
int err;
char buf[MAXPATHLEN];
int nocase = 0;
struct dirent *(*readdirfunc)();
*pathend = EOS;
errno = 0;
if ((dirp = g_opendir(pathbuf, pglob)) == NULL)
{
if (pglob->gl_errfunc)
{
g_Ctoc(pathbuf, buf);
if (pglob->gl_errfunc(buf, errno) ||
pglob->gl_flags & GLOB_ERR)
return (GLOB_ABEND);
}
return(0);
}
err = 0;
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
readdirfunc = pglob->gl_readdir;
else
readdirfunc = readdir;
if (pglob->gl_flags & GLOB_INSENSITIVE)
nocase = 1;
while ((dp = (*readdirfunc)(dirp)))
{
register u_char *sc;
register Char *dc;
#if defined(__EMX__) || defined(WINNT)
if(dp->d_name && *(dp->d_name))
strlwr(dp->d_name);
#endif
if (dp->d_name[0] == DOT && *pattern != DOT)
continue;
for (sc = (u_char *) dp->d_name, dc = pathend;
(*dc++ = *sc++) != EOS;)
continue;
if (!match(pathend, pattern, restpattern, nocase))
{
*pathend = EOS;
continue;
}
err = glob2(pathbuf, --dc, restpattern, pglob);
if (err)
break;
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir)(dirp);
else
closedir(dirp);
return(err);
}
static int globextend ( const Char *path,
glob_t *pglob )
{
register char **pathv;
register int i;
u_int newsize;
char *copy;
const Char *p;
newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
pathv = pglob->gl_pathv ?
(char **)realloc((char *)pglob->gl_pathv, newsize) :
(char **)malloc(newsize);
if (pathv == NULL)
return(GLOB_NOSPACE);
if (pglob->gl_pathv == NULL && pglob->gl_offs > 0)
{
pathv += pglob->gl_offs;
for (i = pglob->gl_offs; --i >= 0; )
*--pathv = NULL;
}
pglob->gl_pathv = pathv;
for (p = path; *p++;)
continue;
if ((copy = malloc(p - path)) != NULL)
{
g_Ctoc(path, copy);
pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
}
pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
return(copy == NULL ? GLOB_NOSPACE : 0);
}
static int match ( register Char *name,
register Char *pat,
register Char *patend,
int nocase )
{
int ok, negate_range;
Char c, k;
while (pat < patend)
{
c = *pat++;
switch (c & M_MASK)
{
case M_ALL:
if (pat == patend)
return(1);
do
if (match(name, pat, patend, nocase))
return(1);
while (*name++ != EOS);
return(0);
case M_ONE:
if (*name++ == EOS)
return(0);
break;
case M_SET:
ok = 0;
if ((k = *name++) == EOS)
return(0);
if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
++pat;
while (((c = *pat++) & M_MASK) != M_END)
{
if ((*pat & M_MASK) == M_RNG)
{
if (c <= k && k <= pat[1])
ok = 1;
pat += 2;
} else if (c == k)
ok = 1;
}
if (ok == negate_range)
return(0);
break;
default:
if (nocase)
{
if (toupper(CHAR(*name++)) != toupper(CHAR(c)))
return 0;
}
else
{
if (*name++ != c)
return 0;
}
break;
}
}
return(*name == EOS);
}
void BX_bsd_globfree ( glob_t *pglob )
{
register int i;
register char **pp;
if (pglob->gl_pathv != NULL) {
pp = pglob->gl_pathv + pglob->gl_offs;
for (i = pglob->gl_pathc; i--; ++pp)
if (*pp)
free(*pp);
free(pglob->gl_pathv);
}
}
static DIR *g_opendir ( register Char *str,
glob_t *pglob )
{
char buf[MAXPATHLEN];
if (!*str)
strcpy(buf, ".");
else
g_Ctoc(str, buf);
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return((*pglob->gl_opendir)(buf));
return(opendir(buf));
}
static int g_lstat ( register Char *fn,
struct stat *sb,
glob_t *pglob )
{
char buf[MAXPATHLEN];
g_Ctoc(fn, buf);
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return((*pglob->gl_lstat)(buf, sb));
#if defined(__EMX__) || defined(__OPENNT)
return(stat(buf, sb));
#else
return(lstat(buf, sb));
#endif
}
#ifdef S_ISLNK
static int g_stat ( register Char *fn,
struct stat *sb,
glob_t *pglob )
{
char buf[MAXPATHLEN];
g_Ctoc(fn, buf);
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return((*pglob->gl_stat)(buf, sb));
return(stat(buf, sb));
}
#endif
static Char *g_strchr ( Char *str,
int ch )
{
do {
if (*str == ch)
return (str);
} while (*str++);
return (NULL);
}
static void g_Ctoc ( register const Char *str,
char *buf )
{
register char *dc;
for (dc = buf; (*dc++ = *str++) != EOS;)
continue;
}
#endif