/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, *
* Inc. Parts of this file are from the GNU C Library. *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Library General Public License as published *
* by the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Library General Public License for more details. *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite *
* 330, Boston, MA 02111-1307, USA. *
***************************************************************************
* 1stMud ROM Derivative (c) 2001-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#include "merc.h"
#ifndef HAVE_FNMATCH
#define FNM_PATHNAME (1 << 0)
#define FNM_NOESCAPE (1 << 1)
#define FNM_PERIOD (1 << 2)
#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
# define FNM_FILE_NAME FNM_PATHNAME
# define FNM_LEADING_DIR (1 << 3)
# define FNM_CASEFOLD (1 << 4)
#endif
#define FNM_NOMATCH 1
# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif
#ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
#else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
#endif
#ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
#else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
#endif
#define ISPRINT(c) (ISASCII (c) && isprint (c))
#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
#define ISALNUM(c) (ISASCII (c) && isalnum (c))
#define ISALPHA(c) (ISASCII (c) && isalpha (c))
#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
#define ISLOWER(c) (ISASCII (c) && islower (c))
#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
#define ISSPACE(c) (ISASCII (c) && isspace (c))
#define ISUPPER(c) (ISASCII (c) && isupper (c))
#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
# if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H
# if defined CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
# define CHAR_CLASS_MAX_LENGTH 256
# endif
# define IS_CHAR_CLASS(string) wctype (string)
# else
# define CHAR_CLASS_MAX_LENGTH 6
# define IS_CHAR_CLASS(string) \
(!str_cmp (string, "alpha") || !str_cmp (string, "upper") \
|| !str_cmp (string, "lower") || !str_cmp (string, "digit") \
|| !str_cmp (string, "alnum") || !str_cmp (string, "xdigit") \
|| !str_cmp (string, "space") || !str_cmp (string, "print") \
|| !str_cmp (string, "punct") || !str_cmp (string, "graph") \
|| !str_cmp (string, "cntrl") || !str_cmp (string, "blank"))
# endif
static int internal_fnmatch(const char *pattern, const char *string,
int no_leading_period, int flags)
{
register const char *p = pattern, *n = string;
register unsigned char c;
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
while ((c = *p++) != '\0')
{
c = FOLD(c);
switch (c)
{
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
else if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
break;
case '\\':
if (!(flags & FNM_NOESCAPE))
{
c = *p++;
if (c == '\0')
return FNM_NOMATCH;
c = FOLD(c);
}
if (FOLD((unsigned char) *n) != c)
return FNM_NOMATCH;
break;
case '*':
if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
else if (c == '?')
{
if (*n == '\0')
return FNM_NOMATCH;
else
++n;
}
}
if (c == '\0')
return ((flags & FNM_FILE_NAME)
&& strchr(n, '/') != NULL ? FNM_NOMATCH : 0);
else
{
const char *endp;
if (!(flags & FNM_FILE_NAME)
|| ((endp = strchr(n, '/')) == NULL))
endp = n + strlen(n);
if (c == '[')
{
int flags2 =
((flags & FNM_FILE_NAME) ? flags
: (flags & ~FNM_PERIOD));
for (--p; n < endp; ++n)
if (internal_fnmatch
(p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags & FNM_FILE_NAME)))),
flags2) == 0)
return 0;
}
else if (c == '/' && (flags & FNM_FILE_NAME))
{
while (*n != '\0' && *n != '/')
++n;
if (*n == '/'
&&
(internal_fnmatch
(p, n + 1, flags & FNM_PERIOD, flags) == 0))
return 0;
}
else
{
int flags2 =
((flags & FNM_FILE_NAME) ? flags
: (flags & ~FNM_PERIOD));
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *p;
c = FOLD(c);
for (--p; n < endp; ++n)
if (FOLD((unsigned char) *n) == c
&&
(internal_fnmatch
(p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags & FNM_FILE_NAME)))),
flags2) == 0))
return 0;
}
}
return FNM_NOMATCH;
case '[':
{
static int posixly_correct;
register int except;
char cold;
if (posixly_correct == 0)
posixly_correct =
getenv("POSIXLY_CORRECT") != NULL ? 1 : -1;
if (*n == '\0')
return FNM_NOMATCH;
if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
except = (*p == '!' || (posixly_correct < 0 && *p == '^'));
if (except)
++p;
c = *p++;
for (;;)
{
unsigned char fn = FOLD((unsigned char) *n);
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
c = FOLD((unsigned char) *p);
++p;
if (c == fn)
goto matched;
}
else if (c == '[' && *p == ':')
{
char str[CHAR_CLASS_MAX_LENGTH + 1];
size_t c1 = 0;
# if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H
wctype_t wt;
# endif
const char *startp = p;
for (;;)
{
if (c1 == CHAR_CLASS_MAX_LENGTH)
return FNM_NOMATCH;
c = *++p;
if (c == ':' && p[1] == ']')
{
p += 2;
break;
}
if (c < 'a' || c >= 'z')
{
p = startp;
c = '[';
goto normal_bracket;
}
str[c1++] = c;
}
str[c1] = '\0';
# if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H
wt = IS_CHAR_CLASS(str);
if (wt == 0)
return FNM_NOMATCH;
if (iswctype(btowc((unsigned char) *n), wt))
goto matched;
# else
if (
(!str_cmp(str, "alnum")
&& ISALNUM((unsigned char) *n))
|| (!str_cmp(str, "alpha")
&& ISALPHA((unsigned char) *n))
|| (!str_cmp(str, "blank")
&& ISBLANK((unsigned char) *n))
|| (!str_cmp(str, "cntrl")
&& ISCNTRL((unsigned char) *n))
|| (!str_cmp(str, "digit")
&& ISDIGIT((unsigned char) *n))
|| (!str_cmp(str, "graph")
&& ISGRAPH((unsigned char) *n))
|| (!str_cmp(str, "lower")
&& ISLOWER((unsigned char) *n))
|| (!str_cmp(str, "print")
&& ISPRINT((unsigned char) *n))
|| (!str_cmp(str, "punct")
&& ISPUNCT((unsigned char) *n))
|| (!str_cmp(str, "space")
&& ISSPACE((unsigned char) *n))
|| (!str_cmp(str, "upper")
&& ISUPPER((unsigned char) *n))
|| (!str_cmp(str, "xdigit")
&& ISXDIGIT((unsigned char) *n)))
goto matched;
# endif
}
else if (c == '\0')
return FNM_NOMATCH;
else
{
normal_bracket:
if (FOLD(c) == fn)
goto matched;
cold = c;
c = *p++;
if (c == '-' && *p != ']')
{
unsigned char cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
if (cold <= fn && fn <= FOLD(cend))
goto matched;
c = *p++;
}
}
if (c == ']')
break;
}
if (!except)
return FNM_NOMATCH;
break;
matched:
while (c != ']')
{
if (c == '\0')
return FNM_NOMATCH;
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
++p;
}
else if (c == '[' && *p == ':')
{
do
if (*++p == '\0')
return FNM_NOMATCH;
while (*p != ':' || p[1] == ']')
;
p += 2;
c = *p;
}
}
if (except)
return FNM_NOMATCH;
}
break;
default:
if (c != FOLD((unsigned char) *n))
return FNM_NOMATCH;
}
++n;
}
if (*n == '\0')
return 0;
if ((flags & FNM_LEADING_DIR) && *n == '/')
return 0;
return FNM_NOMATCH;
# undef FOLD
}
int fnmatch(const char *pattern, const char *string, int flags)
{
return internal_fnmatch(pattern, string, flags & FNM_PERIOD, flags);
}
#else
void fnmatch_dummy(void)
{
}
#endif
#ifndef HAVE_SCANDIR
int scandir(const char *dirname, struct dirent ***namelist,
int (*select) (const struct dirent *),
int (*dcomp) (const struct dirent **, const struct dirent **))
{
#ifdef WIN32
int len;
char *findIn, *d;
WIN32_FIND_DATA find;
HANDLE h;
int nDir = 0, NDir = 0;
struct dirent **dir = 0, *selectDir;
unsigned long ret;
len = strlen(dirname);
alloc_mem(findIn, char, len + 5);
strcpy(findIn, dirname);
for (d = findIn; *d; d++)
if (*d == '/')
*d = '\\';
if ((len == 0))
strcpy(findIn, ".\\*");
if ((len == 1) && (d[-1] == '.'))
strcpy(findIn, ".\\*");
if ((len > 0) && (d[-1] == '\\'))
{
*d++ = '*';
*d = 0;
}
if ((len > 1) && (d[-1] == '.') && (d[-2] == '\\'))
d[-1] = '*';
if ((h = FindFirstFile(findIn, &find)) == INVALID_HANDLE_VALUE)
{
LPVOID lpMsgBuf;
ret = GetLastError();
if (ret != ERROR_NO_MORE_FILES)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, ret, 0,
(LPTSTR) & lpMsgBuf, 0, NULL);
MessageBox(NULL, (LPTSTR) lpMsgBuf, "GetLastError",
MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);
}
*namelist = dir;
return nDir;
}
do
{
alloc_mem(selectDir, struct dirent, strlen(find.cFileName));
strcpy(selectDir->d_name, find.cFileName);
if (!select || (*select) (selectDir))
{
if (nDir == NDir)
{
struct dirent **tempDir;
alloc_mem(tempDir, struct dirent *, NDir + 33);
if (NDir)
memcpy(tempDir, dir, sizeof(struct dirent *) * NDir);
if (dir)
free_mem(dir);
dir = tempDir;
NDir += 32;
}
dir[nDir++] = selectDir;
dir[nDir] = 0;
}
else
free_mem(selectDir);
}
while (FindNextFile(h, &find));
ret = GetLastError();
if (ret != ERROR_NO_MORE_FILES)
{
LPVOID lpMsgBuf;
ret = GetLastError();
if (ret != ERROR_NO_MORE_FILES)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, ret, 0,
(LPTSTR) & lpMsgBuf, 0, NULL);
MessageBox(NULL, (LPTSTR) lpMsgBuf, "GetLastError",
MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);
}
}
FindClose(h);
free_mem(findIn);
if (dcomp)
qsort(dir, nDir, sizeof(*dir),
(int (*)(const void *, const void *)) dcomp);
*namelist = dir;
return nDir;
#else
register struct dirent *d, *p, **names;
register int nitems;
struct stat stb;
long arraysz;
DIR *dirp;
if ((dirp = opendir(dirname)) == NULL)
return (-1);
if (fstat(dirp->d_fd, &stb) < 0)
return (-1);
arraysz = (stb.st_size / 24);
names = (struct dirent **) malloc(arraysz * sizeof(struct dirent *));
if (names == NULL)
return (-1);
nitems = 0;
while ((d = readdir(dirp)) != NULL)
{
if (select != NULL && !(*select) (d))
continue;
p = (struct dirent *) malloc(d->d_reclen);
if (p == NULL)
return (-1);
p->d_ino = d->d_ino;
p->d_reclen = d->d_reclen;
p->d_off = d->d_off;
strcpy(p->d_name, d->d_name);
if (++nitems >= arraysz)
{
if (fstat(dirp->d_fd, &stb) < 0)
return (-1);
arraysz = stb.st_size / 12;
names =
(struct dirent **) realloc((char *) names,
arraysz * sizeof(struct dirent *));
if (names == NULL)
return (-1);
}
names[nitems - 1] = p;
}
closedir(dirp);
if (nitems && dcomp != NULL)
qsort(names, nitems, sizeof(struct dirent *),
(int (*)(const void *, const void *)) dcomp);
*namelist = names;
return (nitems);
#endif
}
int alphasort(const struct dirent **d1, const struct dirent **d2)
{
return (strcmp((*d1)->d_name, (*d2)->d_name));
}
#endif
#ifndef HAVE_INET_ATON
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
int inet_aton(const char *cp, struct in_addr *addr)
{
addr->s_addr = inet_addr(cp);
return (addr->s_addr == INADDR_NONE) ? 0 : 1;
}
#endif
#ifndef HAVE_GETTIMEOFDAY
void gettimeofday(struct timeval *t, void *tz)
{
struct timeb timebuffer;
ftime(&timebuffer);
t->tv_sec = timebuffer.time;
t->tv_usec = timebuffer.millitm * 1000;
}
#endif
#ifndef HAVE_STRREV
char *strrev(char *str)
{
char *p1, *p2;
if (!str || !*str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
#endif
void *rpl_malloc(size_t n)
{
if (n == 0)
n = 1;
return malloc(n);
}
void *rpl_realloc(void *ptr, size_t n)
{
if (n == 0)
n = 1;
return realloc(ptr, n);
}