mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 01:11:44 +00:00
Mac OS X: Add detection of the Steam and GOG releases of Duke 3D and the Steam release of NAM. DONT_BUILD.
git-svn-id: https://svn.eduke32.com/eduke32@4801 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
442a9bbfef
commit
0b91499ee0
5 changed files with 376 additions and 51 deletions
|
@ -761,7 +761,8 @@ char *Bgetenv(const char *name);
|
|||
#endif
|
||||
|
||||
char *Bgethomedir(void);
|
||||
char *Bgetsupportdir(int32_t global);
|
||||
char *Bgetsupportdir(void);
|
||||
char *Bgetappdir(void);
|
||||
uint32_t Bgetsysmemsize(void);
|
||||
int32_t Bcorrectfilename(char *filename, int32_t removefn);
|
||||
int32_t Bcanonicalisefilename(char *filename, int32_t removefn);
|
||||
|
|
|
@ -9,6 +9,11 @@ extern "C" {
|
|||
int32_t osx_msgbox(const char *name, const char *msg);
|
||||
int32_t osx_ynbox(const char *name, const char *msg);
|
||||
|
||||
char *osx_gethomedir(void);
|
||||
char *osx_getsupportdir(void);
|
||||
char *osx_getappdir(void);
|
||||
char *osx_getapplicationsdir(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifdef _WIN32
|
||||
# include <shlobj.h>
|
||||
# include <direct.h>
|
||||
#elif __APPLE__
|
||||
# include "osxbits.h"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
@ -25,6 +27,13 @@
|
|||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <libgen.h> // for dirname()
|
||||
#endif
|
||||
#if defined(__FreeBSD__)
|
||||
# include <sys/sysctl.h> // for sysctl() to get path to executable
|
||||
#endif
|
||||
|
||||
#include "baselayer.h"
|
||||
|
||||
////////// PANICKING ALLOCATION FUNCTIONS //////////
|
||||
|
@ -393,22 +402,8 @@ char *Bgethomedir(void)
|
|||
if (loaded)
|
||||
FreeLibrary(hShell32);
|
||||
return NULL;
|
||||
#elif defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3
|
||||
FSRef ref;
|
||||
CFStringRef str;
|
||||
CFURLRef base;
|
||||
char *s;
|
||||
|
||||
if (FSFindFolder(kUserDomain, kVolumeRootFolderType, kDontCreateFolder, &ref) < 0) return NULL;
|
||||
base = CFURLCreateFromFSRef(NULL, &ref);
|
||||
if (!base) return NULL;
|
||||
str = CFURLCopyFileSystemPath(base, kCFURLPOSIXPathStyle);
|
||||
CFRelease(base);
|
||||
if (!str) return NULL;
|
||||
s = (char *)CFStringGetCStringPtr(str,CFStringGetSystemEncoding());
|
||||
if (s) s = Bstrdup(s);
|
||||
CFRelease(str);
|
||||
return s;
|
||||
#elif defined __APPLE__
|
||||
return osx_gethomedir();
|
||||
#elif defined(GEKKO)
|
||||
// return current drive's name
|
||||
char *drv, cwd[BMAX_PATH] = {0};
|
||||
|
@ -424,32 +419,63 @@ char *Bgethomedir(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
char *Bgetsupportdir(int32_t global)
|
||||
char *Bgetsupportdir(void)
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3_
|
||||
UNREFERENCED_PARAMETER(global);
|
||||
return Bgethomedir();
|
||||
#if defined __APPLE__
|
||||
return osx_getsupportdir();
|
||||
#else
|
||||
FSRef ref;
|
||||
CFStringRef str;
|
||||
CFURLRef base;
|
||||
char *s;
|
||||
|
||||
if (FSFindFolder(global ? kLocalDomain : kUserDomain,
|
||||
kApplicationSupportFolderType,
|
||||
kDontCreateFolder, &ref) < 0) return NULL;
|
||||
base = CFURLCreateFromFSRef(NULL, &ref);
|
||||
if (!base) return NULL;
|
||||
str = CFURLCopyFileSystemPath(base, kCFURLPOSIXPathStyle);
|
||||
CFRelease(base);
|
||||
if (!str) return NULL;
|
||||
s = (char *)CFStringGetCStringPtr(str,CFStringGetSystemEncoding());
|
||||
if (s) s = Bstrdup(s);
|
||||
CFRelease(str);
|
||||
return s;
|
||||
return Bgethomedir();
|
||||
#endif
|
||||
}
|
||||
|
||||
char *Bgetappdir(void)
|
||||
{
|
||||
char *dir = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
TCHAR appdir[MAX_PATH];
|
||||
|
||||
if (GetModuleFileName(NULL, appdir, MAX_PATH) > 0) {
|
||||
// trim off the filename
|
||||
char *slash = strrchr(appdir, '\\');
|
||||
if (slash) slash[0] = 0;
|
||||
dir = strdup(appdir);
|
||||
}
|
||||
|
||||
#elif defined __APPLE__
|
||||
dir = osx_getappdir();
|
||||
#elif defined(__linux) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
char buf[PATH_MAX] = {0};
|
||||
char buf2[PATH_MAX] = {0};
|
||||
# ifdef __linux
|
||||
snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
|
||||
# else // the BSDs.. except for FreeBSD which has a sysctl
|
||||
snprintf(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 = strdup(dirname(buf2));
|
||||
}
|
||||
#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, sizeof(name)/sizeof(name[0]), 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 = strdup(dirname(buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
int32_t Bcorrectfilename(char *filename, int32_t removefn)
|
||||
{
|
||||
char *fn;
|
||||
|
|
|
@ -58,3 +58,92 @@ int osx_ynbox(const char *name, const char *msg)
|
|||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *osx_gethomedir(void)
|
||||
{
|
||||
NSString *path = NSHomeDirectory();
|
||||
const char *Cpath = [path UTF8String];
|
||||
char *returnpath = NULL;
|
||||
|
||||
if (Cpath)
|
||||
returnpath = Bstrdup(Cpath);
|
||||
|
||||
[path release];
|
||||
|
||||
return returnpath;
|
||||
}
|
||||
|
||||
char *osx_getsupportdir(void)
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
char *returnpath = NULL;
|
||||
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
const char *Cpath = [[paths objectAtIndex:0] UTF8String];
|
||||
|
||||
if (Cpath)
|
||||
returnpath = Bstrdup(Cpath);
|
||||
}
|
||||
|
||||
[paths release];
|
||||
|
||||
return returnpath;
|
||||
}
|
||||
|
||||
char *osx_getappdir(void)
|
||||
{
|
||||
CFBundleRef mainBundle;
|
||||
CFURLRef resUrl, fullUrl;
|
||||
CFStringRef str;
|
||||
const char *s;
|
||||
char *dir = NULL;
|
||||
|
||||
mainBundle = CFBundleGetMainBundle();
|
||||
if (!mainBundle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resUrl = CFBundleCopyResourcesDirectoryURL(mainBundle);
|
||||
CFRelease(mainBundle);
|
||||
if (!resUrl) {
|
||||
return NULL;
|
||||
}
|
||||
fullUrl = CFURLCopyAbsoluteURL(resUrl);
|
||||
if (fullUrl) {
|
||||
CFRelease(resUrl);
|
||||
resUrl = fullUrl;
|
||||
}
|
||||
|
||||
str = CFURLCopyFileSystemPath(resUrl, kCFURLPOSIXPathStyle);
|
||||
CFRelease(resUrl);
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = CFStringGetCStringPtr(str, CFStringGetSystemEncoding());
|
||||
if (s) {
|
||||
dir = strdup(s);
|
||||
}
|
||||
CFRelease(str);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
char *osx_getapplicationsdir(void)
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSAllApplicationsDirectory, NSLocalDomainMask, YES);
|
||||
char *returnpath = NULL;
|
||||
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
const char *Cpath = [[paths objectAtIndex:0] UTF8String];
|
||||
|
||||
if (Cpath)
|
||||
returnpath = Bstrdup(Cpath);
|
||||
}
|
||||
|
||||
[paths release];
|
||||
|
||||
return returnpath;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
# ifndef KEY_WOW64_32KEY
|
||||
# define KEY_WOW64_32KEY 0x0200
|
||||
# endif
|
||||
#elif defined __APPLE__
|
||||
# include "osxbits.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
@ -292,16 +294,14 @@ void G_ExtInit(void)
|
|||
{
|
||||
char cwd[BMAX_PATH];
|
||||
|
||||
if (getcwd(cwd,BMAX_PATH))
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
/* Dirty hack on OS X to also look for gamedata inside the application bundle - rhoenie 08/08 */
|
||||
char seekinappcontainer[BMAX_PATH];
|
||||
Bsnprintf(seekinappcontainer,sizeof(seekinappcontainer),"%s/EDuke32.app/", cwd);
|
||||
addsearchpath(seekinappcontainer);
|
||||
#ifdef __APPLE__
|
||||
char *appdir = Bgetappdir();
|
||||
addsearchpath(appdir);
|
||||
Bfree(appdir);
|
||||
#endif
|
||||
|
||||
if (getcwd(cwd,BMAX_PATH) && Bstrcmp(cwd,"/") != 0)
|
||||
addsearchpath(cwd);
|
||||
}
|
||||
|
||||
if (CommandPaths)
|
||||
{
|
||||
|
@ -337,8 +337,6 @@ void G_ExtInit(void)
|
|||
Bsnprintf(cwd,sizeof(cwd),"%s/"
|
||||
#if defined(_WIN32)
|
||||
"EDuke32 Settings"
|
||||
#elif defined(__APPLE__)
|
||||
"Library/Application Support/EDuke32"
|
||||
#elif defined(GEKKO)
|
||||
"apps/eduke32"
|
||||
#else
|
||||
|
@ -605,6 +603,195 @@ static void G_LoadAddon(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void G_AddSteamPathsApple(const char *basepath)
|
||||
{
|
||||
char buf[BMAX_PATH];
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath);
|
||||
addsearchpath(buf);
|
||||
}
|
||||
|
||||
// A bare-bones "parser" for Valve's KeyValues VDF format.
|
||||
// There is no guarantee this will function properly with ill-formed files.
|
||||
static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend)
|
||||
{
|
||||
while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend)
|
||||
(*vdfbuf)++;
|
||||
|
||||
// comments
|
||||
if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/')
|
||||
{
|
||||
while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend)
|
||||
(*vdfbuf)++;
|
||||
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
}
|
||||
}
|
||||
static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend)
|
||||
{
|
||||
(*vdfbuf)++;
|
||||
while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend)
|
||||
(*vdfbuf)++;
|
||||
}
|
||||
static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend)
|
||||
{
|
||||
while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend)
|
||||
(*vdfbuf)++;
|
||||
}
|
||||
static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend)
|
||||
{
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
|
||||
if (*vdfbuf == vdfbufend)
|
||||
return;
|
||||
|
||||
if ((*vdfbuf)[0] == '{')
|
||||
{
|
||||
(*vdfbuf)++;
|
||||
do
|
||||
{
|
||||
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
||||
}
|
||||
while ((*vdfbuf)[0] != '}');
|
||||
(*vdfbuf)++;
|
||||
}
|
||||
else if ((*vdfbuf)[0] == '\"')
|
||||
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
|
||||
else if ((*vdfbuf)[0] != '}')
|
||||
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
|
||||
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
}
|
||||
static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend)
|
||||
{
|
||||
char *token = *vdfbuf;
|
||||
|
||||
if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend)
|
||||
{
|
||||
token++;
|
||||
|
||||
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
|
||||
(*vdfbuf)[0] = '\0';
|
||||
|
||||
// account for escape sequences
|
||||
char *writeseeker = token, *readseeker = token;
|
||||
while (readseeker <= *vdfbuf)
|
||||
{
|
||||
if (readseeker[0] == '\\')
|
||||
readseeker++;
|
||||
|
||||
writeseeker[0] = readseeker[0];
|
||||
|
||||
writeseeker++;
|
||||
readseeker++;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
|
||||
(*vdfbuf)[0] = '\0';
|
||||
|
||||
return token;
|
||||
}
|
||||
static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token)
|
||||
{
|
||||
char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
||||
if (token != NULL) // pass in NULL to find the next key instead of a specific one
|
||||
while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend)
|
||||
{
|
||||
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
||||
ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
||||
}
|
||||
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
}
|
||||
static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token)
|
||||
{
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
|
||||
// end of scope
|
||||
if ((*vdfbuf)[0] == '}')
|
||||
return 0;
|
||||
|
||||
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
||||
|
||||
// ignore the wrong type
|
||||
while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend)
|
||||
{
|
||||
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
||||
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
||||
}
|
||||
|
||||
if (*vdfbuf == vdfbufend)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token)
|
||||
{
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
|
||||
// end of scope
|
||||
if ((*vdfbuf)[0] == '}')
|
||||
return NULL;
|
||||
|
||||
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
||||
|
||||
// ignore the wrong type
|
||||
while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend)
|
||||
{
|
||||
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
||||
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
||||
}
|
||||
|
||||
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
||||
|
||||
if (*vdfbuf == vdfbufend)
|
||||
return NULL;
|
||||
|
||||
return KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
||||
}
|
||||
|
||||
static void G_ParseSteamKeyValuesForPaths(const char *vdf)
|
||||
{
|
||||
int32_t fd = Bopen(vdf, BO_RDONLY);
|
||||
int32_t size = Bfilelength(fd);
|
||||
char *vdfbufstart, *vdfbuf, *vdfbufend;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
vdfbufstart = vdfbuf = (char*)Bmalloc(size);
|
||||
size = (int32_t)Bread(fd, vdfbuf, size);
|
||||
Bclose(fd);
|
||||
vdfbufend = vdfbuf + size;
|
||||
|
||||
if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders"))
|
||||
{
|
||||
char *result;
|
||||
vdfbuf++;
|
||||
while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL)
|
||||
G_AddSteamPathsApple(result);
|
||||
}
|
||||
|
||||
Bfree(vdfbufstart);
|
||||
}
|
||||
#endif
|
||||
|
||||
void G_AddSearchPaths(void)
|
||||
{
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
|
@ -613,10 +800,27 @@ void G_AddSearchPaths(void)
|
|||
addsearchpath("/usr/share/games/eduke32");
|
||||
addsearchpath("/usr/local/share/games/eduke32");
|
||||
#elif defined(__APPLE__)
|
||||
addsearchpath("/Library/Application Support/JFDuke3D");
|
||||
addsearchpath("/Library/Application Support/EDuke32");
|
||||
char buf[BMAX_PATH];
|
||||
char *applications = osx_getapplicationsdir();
|
||||
char *support = Bgetsupportdir();
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/Steam", support);
|
||||
G_AddSteamPathsApple(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support);
|
||||
G_ParseSteamKeyValuesForPaths(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bsnprintf(buf, sizeof(buf), "%s/JFDuke3D", support);
|
||||
addsearchpath(buf);
|
||||
Bsnprintf(buf, sizeof(buf), "%s/EDuke32", support);
|
||||
addsearchpath(buf);
|
||||
|
||||
Bfree(applications);
|
||||
Bfree(support);
|
||||
#elif defined (_WIN32)
|
||||
// detect Steam and GOG versions of Duke3D
|
||||
char buf[BMAX_PATH];
|
||||
const char* instpath;
|
||||
|
||||
|
|
Loading…
Reference in a new issue