mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-07 13:31:27 +00:00
2cbe211e7c
The EDuke32 and RedNukem frontends are working, Blood isn't yet. Notes: many of the CMake variables and its output still refer to zdoom. Before changing that I wanted to make sure to be able to commit something that works. support code for Windows XP has been entirely removed. On Windows this will only target Vista and up. the crc32.h header had to be renamed to deconflict from zlib. several Windows API calls were changed to call the A-versions directly. Weirdly enough there were places that defined their parameters as T types but in a non-working way. removed some remaining editor files and support for the native software rendering only Windows backend. in a few simple cases, replaced 'char' with 'uint8_t'. The code as-is depends on chars being unsigned which is non-portable. This needs to be carefully reviewed.
603 lines
12 KiB
C++
603 lines
12 KiB
C++
/*
|
|
* Playing-field leveler for Build
|
|
*/
|
|
|
|
#define LIBDIVIDE_BODY
|
|
#include "compat.h"
|
|
#include "debugbreak.h"
|
|
|
|
#ifdef _WIN32
|
|
# define NEED_SHLOBJ_H
|
|
# include "windows_inc.h"
|
|
#elif __APPLE__
|
|
# include "osxbits.h"
|
|
#endif
|
|
|
|
#ifndef USE_PHYSFS
|
|
#if defined(_MSC_VER)
|
|
# include <io.h>
|
|
#else
|
|
# include <dirent.h>
|
|
#endif
|
|
#endif
|
|
|
|
#if defined __linux || defined EDUKE32_BSD
|
|
# include <libgen.h> // for dirname()
|
|
#endif
|
|
#if defined EDUKE32_BSD
|
|
# include <limits.h> // for PATH_MAX
|
|
# include <sys/sysctl.h> // for sysctl() to get path to executable
|
|
#endif
|
|
|
|
#include "baselayer.h"
|
|
|
|
#include "vfs.h"
|
|
|
|
////////// PANICKING ALLOCATION FUNCTIONS //////////
|
|
|
|
static void (*g_MemErrHandler)(int32_t line, const char *file, const char *func);
|
|
|
|
#ifdef DEBUGGINGAIDS
|
|
static const char *g_MemErrFunc = "???";
|
|
static const char *g_MemErrFile = "???";
|
|
static int32_t g_MemErrLine;
|
|
|
|
void xalloc_set_location(int32_t line, const char *file, const char *func)
|
|
{
|
|
g_MemErrLine = line;
|
|
g_MemErrFile = file;
|
|
|
|
if (func)
|
|
g_MemErrFunc = func;
|
|
}
|
|
#endif
|
|
|
|
void *handle_memerr(void *p)
|
|
{
|
|
UNREFERENCED_PARAMETER(p);
|
|
debug_break();
|
|
|
|
if (g_MemErrHandler)
|
|
{
|
|
#ifdef DEBUGGINGAIDS
|
|
g_MemErrHandler(g_MemErrLine, g_MemErrFile, g_MemErrFunc);
|
|
#else
|
|
g_MemErrHandler(0, "???", "???");
|
|
#endif
|
|
}
|
|
|
|
Bexit(EXIT_FAILURE);
|
|
EDUKE32_UNREACHABLE_SECTION(return &handle_memerr);
|
|
}
|
|
|
|
void set_memerr_handler(void(*handlerfunc)(int32_t, const char *, const char *))
|
|
{
|
|
g_MemErrHandler = handlerfunc;
|
|
}
|
|
|
|
//
|
|
// Stuff which must be a function
|
|
//
|
|
char *Bgethomedir(void)
|
|
{
|
|
#ifdef _WIN32
|
|
|
|
char appdata[MAX_PATH];
|
|
|
|
if (SUCCEEDED(SHGetSpecialFolderPathA(NULL, appdata, CSIDL_APPDATA, FALSE)))
|
|
{
|
|
return Xstrdup(appdata);
|
|
}
|
|
return NULL;
|
|
#elif defined EDUKE32_OSX
|
|
return osx_gethomedir();
|
|
#else
|
|
char *e = getenv("HOME");
|
|
if (!e) return NULL;
|
|
return Xstrdup(e);
|
|
#endif
|
|
}
|
|
|
|
char *Bgetappdir(void)
|
|
{
|
|
char *dir = NULL;
|
|
|
|
#ifdef _WIN32
|
|
char appdir[MAX_PATH];
|
|
|
|
if (GetModuleFileNameA(NULL, appdir, MAX_PATH) > 0) {
|
|
// trim off the filename
|
|
char *slash = Bstrrchr(appdir, '\\');
|
|
if (slash) slash[0] = 0;
|
|
dir = Xstrdup(appdir);
|
|
}
|
|
|
|
#elif defined EDUKE32_OSX
|
|
dir = osx_getappdir();
|
|
#elif defined __FreeBSD__
|
|
// the sysctl should also work when /proc/ is not mounted (which seems to
|
|
// be common on FreeBSD), so use it..
|
|
char buf[PATH_MAX] = {0};
|
|
int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
size_t len = sizeof(buf) - 1;
|
|
int ret = sysctl(name, ARRAY_SIZE(name), buf, &len, NULL, 0);
|
|
|
|
if (ret == 0 && buf[0] != '\0')
|
|
{
|
|
// again, remove executable name with dirname()
|
|
// on FreeBSD dirname() seems to use some internal buffer
|
|
dir = Xstrdup(dirname(buf));
|
|
}
|
|
#elif defined __linux || defined EDUKE32_BSD
|
|
char buf[PATH_MAX] = {0};
|
|
char buf2[PATH_MAX] = {0};
|
|
# ifdef __linux
|
|
Bsnprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
|
|
# else // the BSDs.. except for FreeBSD which has a sysctl
|
|
Bsnprintf(buf, sizeof(buf), "/proc/%d/file", getpid());
|
|
# endif
|
|
int len = readlink(buf, buf2, sizeof(buf2));
|
|
if (len != -1) {
|
|
// remove executable name with dirname(3)
|
|
// on Linux, dirname() will modify buf2 (cutting off executable name) and return it
|
|
// on FreeBSD it seems to use some internal buffer instead.. anyway, just strdup()
|
|
dir = Xstrdup(dirname(buf2));
|
|
}
|
|
#endif
|
|
|
|
return dir;
|
|
}
|
|
|
|
int32_t Bcorrectfilename(char *filename, int32_t removefn)
|
|
{
|
|
char *fn = Xstrdup(filename);
|
|
char *tokarr[64], *first, *next = NULL;
|
|
|
|
for (first=fn; *first; first++)
|
|
{
|
|
#ifdef _WIN32
|
|
if (*first == '\\') *first = '/';
|
|
#endif
|
|
}
|
|
|
|
int leadslash = (*fn == '/');
|
|
int trailslash = (first>fn && first[-1] == '/');
|
|
int ntok = 0;
|
|
|
|
first = fn;
|
|
do
|
|
{
|
|
char *token = Bstrtoken(first, "/", &next, 1);
|
|
first = NULL;
|
|
if (!token) break;
|
|
else if (token[0] == 0) continue;
|
|
else if (token[0] == '.' && token[1] == 0) continue;
|
|
else if (token[0] == '.' && token[1] == '.' && token[2] == 0) ntok = max(0,ntok-1);
|
|
else tokarr[ntok++] = token;
|
|
}
|
|
while (1);
|
|
|
|
if (!trailslash && removefn) { ntok = max(0,ntok-1); trailslash = 1; }
|
|
if (ntok == 0 && trailslash && leadslash) trailslash = 0;
|
|
|
|
first = filename;
|
|
if (leadslash) *(first++) = '/';
|
|
for (int i=0; i<ntok; i++)
|
|
{
|
|
if (i>0) *(first++) = '/';
|
|
for (char *token=tokarr[i]; *token; token++)
|
|
*(first++) = *token;
|
|
}
|
|
if (trailslash) *(first++) = '/';
|
|
*(first++) = 0;
|
|
|
|
Xfree(fn);
|
|
return 0;
|
|
}
|
|
|
|
#ifndef USE_PHYSFS
|
|
int32_t Bcanonicalisefilename(char *filename, int32_t removefn)
|
|
{
|
|
char cwd[BMAX_PATH];
|
|
char *fnp = filename;
|
|
|
|
#ifdef _WIN32
|
|
int drv = 0;
|
|
|
|
if (filename[0] && filename[1] == ':')
|
|
{
|
|
// filename is prefixed with a drive
|
|
drv = toupper(filename[0]) - 'A' + 1;
|
|
fnp += 2;
|
|
}
|
|
|
|
if (!_getdcwd(drv, cwd, sizeof(cwd)))
|
|
return -1;
|
|
|
|
for (char *p = cwd; *p; p++)
|
|
if (*p == '\\')
|
|
*p = '/';
|
|
#else
|
|
if (!buildvfs_getcwd(cwd, sizeof(cwd)))
|
|
return -1;
|
|
#endif
|
|
|
|
char *p = Bstrrchr(cwd, '/');
|
|
if (!p || p[1])
|
|
Bstrcat(cwd, "/");
|
|
|
|
char fn[BMAX_PATH];
|
|
Bstrcpy(fn, fnp);
|
|
|
|
#ifdef _WIN32
|
|
for (p = fn; *p; p++)
|
|
if (*p == '\\')
|
|
*p = '/';
|
|
#endif
|
|
|
|
if (fn[0] != '/')
|
|
{
|
|
// we are dealing with a path relative to the current directory
|
|
Bstrcpy(filename, cwd);
|
|
Bstrcat(filename, fn);
|
|
}
|
|
else
|
|
{
|
|
#ifdef _WIN32
|
|
filename[0] = cwd[0];
|
|
filename[1] = ':';
|
|
filename[2] = 0;
|
|
Bstrcat(filename, fn);
|
|
#else
|
|
Bstrcpy(filename, fn);
|
|
#endif
|
|
}
|
|
fnp = filename;
|
|
#ifdef _WIN32
|
|
fnp += 2; // skip the drive
|
|
#endif
|
|
UNREFERENCED_PARAMETER(removefn); // change the call below to use removefn instead of 1?
|
|
return Bcorrectfilename(fnp, 1);
|
|
}
|
|
#endif
|
|
|
|
char *Bgetsystemdrives(void)
|
|
{
|
|
#ifdef _WIN32
|
|
char *str, *p;
|
|
DWORD drv, mask;
|
|
int32_t number = 0;
|
|
|
|
drv = GetLogicalDrives();
|
|
if (drv == 0)
|
|
return NULL;
|
|
|
|
for (mask = 1; mask < 0x8000000l; mask <<= 1)
|
|
{
|
|
if ((drv & mask) == 0)
|
|
continue;
|
|
number++;
|
|
}
|
|
|
|
str = p = (char *)Xmalloc(1 + (3 * number));
|
|
number = 0;
|
|
for (mask = 1; mask < 0x8000000l; mask <<= 1, number++)
|
|
{
|
|
if ((drv & mask) == 0)
|
|
continue;
|
|
*(p++) = 'A' + number;
|
|
*(p++) = ':';
|
|
*(p++) = 0;
|
|
}
|
|
*(p++) = 0;
|
|
|
|
return str;
|
|
#else
|
|
// Perhaps have Unix OS's put /, /home/user, and /mnt/* in the "drives" list?
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifndef USE_PHYSFS
|
|
typedef struct
|
|
{
|
|
#ifdef _MSC_VER
|
|
intptr_t dir;
|
|
struct _finddata_t fid;
|
|
#else
|
|
DIR *dir;
|
|
#endif
|
|
struct Bdirent info;
|
|
int32_t status;
|
|
char name[1];
|
|
} BDIR_real;
|
|
|
|
BDIR *Bopendir(const char *name)
|
|
{
|
|
BDIR_real *dirr;
|
|
#ifdef _MSC_VER
|
|
char *t, *tt;
|
|
t = (char *)Xmalloc(Bstrlen(name) + 1 + 4);
|
|
#endif
|
|
|
|
dirr = (BDIR_real *)Xmalloc(sizeof(BDIR_real) + Bstrlen(name));
|
|
|
|
#ifdef _MSC_VER
|
|
Bstrcpy(t, name);
|
|
tt = t + Bstrlen(name) - 1;
|
|
while (*tt == ' ' && tt > t) tt--;
|
|
if (*tt != '/' && *tt != '\\')
|
|
*(++tt) = '/';
|
|
*(++tt) = '*';
|
|
*(++tt) = '.';
|
|
*(++tt) = '*';
|
|
*(++tt) = 0;
|
|
|
|
dirr->dir = _findfirst(t, &dirr->fid);
|
|
Xfree(t);
|
|
if (dirr->dir == -1)
|
|
{
|
|
Xfree(dirr);
|
|
return NULL;
|
|
}
|
|
#else
|
|
dirr->dir = opendir(name);
|
|
if (dirr->dir == NULL)
|
|
{
|
|
Xfree(dirr);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
dirr->status = 0;
|
|
Bstrcpy(dirr->name, name);
|
|
|
|
return (BDIR *)dirr;
|
|
}
|
|
|
|
struct Bdirent *Breaddir(BDIR *dir)
|
|
{
|
|
BDIR_real *dirr = (BDIR_real *)dir;
|
|
|
|
#ifdef _MSC_VER
|
|
if (dirr->status > 0)
|
|
{
|
|
if (_findnext(dirr->dir, &dirr->fid) != 0)
|
|
{
|
|
dirr->status = -1;
|
|
return NULL;
|
|
}
|
|
}
|
|
dirr->info.namlen = Bstrlen(dirr->fid.name);
|
|
dirr->info.name = dirr->fid.name;
|
|
dirr->status++;
|
|
#else
|
|
struct dirent *de = readdir(dirr->dir);
|
|
if (de == NULL)
|
|
{
|
|
dirr->status = -1;
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
dirr->status++;
|
|
}
|
|
dirr->info.namlen = Bstrlen(de->d_name);
|
|
dirr->info.name = de->d_name;
|
|
#endif
|
|
dirr->info.mode = 0;
|
|
dirr->info.size = 0;
|
|
dirr->info.mtime = 0;
|
|
|
|
char *fn = (char *)Xmalloc(Bstrlen(dirr->name) + 1 + dirr->info.namlen + 1);
|
|
Bsprintf(fn, "%s/%s", dirr->name, dirr->info.name);
|
|
|
|
#ifdef USE_PHYSFS
|
|
PHYSFS_Stat st;
|
|
if (PHYSFS_stat(fn, &st))
|
|
{
|
|
// dirr->info.mode = TODO;
|
|
dirr->info.size = st.filesize;
|
|
dirr->info.mtime = st.modtime;
|
|
}
|
|
#else
|
|
struct Bstat st;
|
|
if (!Bstat(fn, &st))
|
|
{
|
|
dirr->info.mode = st.st_mode;
|
|
dirr->info.size = st.st_size;
|
|
dirr->info.mtime = st.st_mtime;
|
|
}
|
|
#endif
|
|
|
|
Xfree(fn);
|
|
|
|
return &dirr->info;
|
|
}
|
|
|
|
int32_t Bclosedir(BDIR *dir)
|
|
{
|
|
BDIR_real *dirr = (BDIR_real *)dir;
|
|
|
|
#ifdef _MSC_VER
|
|
_findclose(dirr->dir);
|
|
#else
|
|
closedir(dirr->dir);
|
|
#endif
|
|
Xfree(dirr);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
char *Bstrtoken(char *s, const char *delim, char **ptrptr, int chop)
|
|
{
|
|
if (!ptrptr)
|
|
return NULL;
|
|
|
|
char *p = s ? s : *ptrptr;
|
|
|
|
if (!p)
|
|
return NULL;
|
|
|
|
while (*p != 0 && Bstrchr(delim, *p)) p++;
|
|
|
|
if (*p == 0)
|
|
{
|
|
*ptrptr = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
char * const start = p;
|
|
|
|
while (*p != 0 && !Bstrchr(delim, *p)) p++;
|
|
|
|
if (*p == 0)
|
|
*ptrptr = NULL;
|
|
else
|
|
{
|
|
if (chop)
|
|
*(p++) = 0;
|
|
*ptrptr = p;
|
|
}
|
|
|
|
return start;
|
|
}
|
|
|
|
char *Bstrtolower(char *str)
|
|
{
|
|
if (!str)
|
|
return NULL;
|
|
|
|
int len = Bstrlen(str);
|
|
|
|
if (len <= 0)
|
|
return str;
|
|
|
|
int i = 0;
|
|
|
|
do
|
|
{
|
|
*(str + i) = Btolower(*(str + i));
|
|
i++;
|
|
} while (--len);
|
|
|
|
return str;
|
|
}
|
|
|
|
|
|
//Brute-force case-insensitive, slash-insensitive, * and ? wildcard matcher
|
|
//Returns: 1:matches, 0:doesn't match
|
|
#ifndef WITHKPLIB
|
|
extern char toupperlookup[256];
|
|
|
|
static int32_t wildmatch(const char *match, const char *wild)
|
|
{
|
|
do
|
|
{
|
|
if (*match && (toupperlookup[*wild] == toupperlookup[*match] || *wild == '?'))
|
|
{
|
|
wild++, match++;
|
|
continue;
|
|
}
|
|
else if ((*match|*wild) == '\0')
|
|
return 1;
|
|
else if (*wild == '*')
|
|
{
|
|
do { wild++; } while (*wild == '*');
|
|
do
|
|
{
|
|
if (*wild == '\0')
|
|
return 1;
|
|
while (*match && toupperlookup[*match] != toupperlookup[*wild]) match++;
|
|
if (*match && *(match+1) && toupperlookup[*(match+1)] != toupperlookup[*(wild+1)])
|
|
{
|
|
match++;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
while (1);
|
|
if (toupperlookup[*match] == toupperlookup[*wild])
|
|
continue;
|
|
}
|
|
return 0;
|
|
}
|
|
while (1);
|
|
}
|
|
#endif
|
|
|
|
#if !defined(_WIN32)
|
|
char *Bstrlwr(char *s)
|
|
{
|
|
if (!s) return s;
|
|
char *t = s;
|
|
while (*t) { *t = Btolower(*t); t++; }
|
|
return s;
|
|
}
|
|
|
|
char *Bstrupr(char *s)
|
|
{
|
|
if (!s) return s;
|
|
char *t = s;
|
|
while (*t) { *t = Btoupper(*t); t++; }
|
|
return s;
|
|
}
|
|
#endif
|
|
|
|
#define BMAXPAGESIZE 16384
|
|
|
|
int Bgetpagesize(void)
|
|
{
|
|
static int pageSize = -1;
|
|
|
|
if (pageSize == -1)
|
|
{
|
|
#ifdef _WIN32
|
|
SYSTEM_INFO system_info;
|
|
GetSystemInfo(&system_info);
|
|
pageSize = system_info.dwPageSize;
|
|
#else
|
|
pageSize = sysconf(_SC_PAGESIZE);
|
|
#endif
|
|
}
|
|
|
|
return (unsigned)pageSize < BMAXPAGESIZE ? pageSize : BMAXPAGESIZE;
|
|
}
|
|
|
|
//
|
|
// Bgetsysmemsize() -- gets the amount of system memory in the machine
|
|
//
|
|
|
|
uint32_t Bgetsysmemsize(void)
|
|
{
|
|
uint32_t siz = UINT32_MAX;
|
|
|
|
#ifdef _WIN32
|
|
//WinNT
|
|
MEMORYSTATUSEX memst;
|
|
memst.dwLength = sizeof(MEMORYSTATUSEX);
|
|
if (GlobalMemoryStatusEx(&memst))
|
|
siz = min<decltype(memst.ullTotalPhys)>(UINT32_MAX, memst.ullTotalPhys);
|
|
|
|
#elif (defined(_SC_PAGE_SIZE) || defined(_SC_PAGESIZE)) && defined(_SC_PHYS_PAGES) && !defined(GEKKO)
|
|
#ifdef _SC_PAGE_SIZE
|
|
int64_t const scpagesiz = sysconf(_SC_PAGE_SIZE);
|
|
#else
|
|
int64_t const scpagesiz = sysconf(_SC_PAGESIZE);
|
|
#endif
|
|
int64_t const scphyspages = sysconf(_SC_PHYS_PAGES);
|
|
|
|
if (scpagesiz >= 0 && scphyspages >= 0)
|
|
siz = (uint32_t)min<uint64_t>(UINT32_MAX, scpagesiz * scphyspages);
|
|
|
|
//initprintf("Bgetsysmemsize(): %d pages of %d bytes, %d bytes of system memory\n",
|
|
// scphyspages, scpagesiz, siz);
|
|
|
|
#endif
|
|
|
|
return siz;
|
|
}
|
|
|