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:
hendricks266 2014-12-08 04:31:57 +00:00
parent 442a9bbfef
commit 0b91499ee0
5 changed files with 376 additions and 51 deletions

View File

@ -761,7 +761,8 @@ char *Bgetenv(const char *name);
#endif #endif
char *Bgethomedir(void); char *Bgethomedir(void);
char *Bgetsupportdir(int32_t global); char *Bgetsupportdir(void);
char *Bgetappdir(void);
uint32_t Bgetsysmemsize(void); uint32_t Bgetsysmemsize(void);
int32_t Bcorrectfilename(char *filename, int32_t removefn); int32_t Bcorrectfilename(char *filename, int32_t removefn);
int32_t Bcanonicalisefilename(char *filename, int32_t removefn); int32_t Bcanonicalisefilename(char *filename, int32_t removefn);

View File

@ -9,6 +9,11 @@ extern "C" {
int32_t osx_msgbox(const char *name, const char *msg); int32_t osx_msgbox(const char *name, const char *msg);
int32_t osx_ynbox(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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -17,6 +17,8 @@
#ifdef _WIN32 #ifdef _WIN32
# include <shlobj.h> # include <shlobj.h>
# include <direct.h> # include <direct.h>
#elif __APPLE__
# include "osxbits.h"
#endif #endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -25,6 +27,13 @@
# include <dirent.h> # include <dirent.h>
#endif #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" #include "baselayer.h"
////////// PANICKING ALLOCATION FUNCTIONS ////////// ////////// PANICKING ALLOCATION FUNCTIONS //////////
@ -393,22 +402,8 @@ char *Bgethomedir(void)
if (loaded) if (loaded)
FreeLibrary(hShell32); FreeLibrary(hShell32);
return NULL; return NULL;
#elif defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 #elif defined __APPLE__
FSRef ref; return osx_gethomedir();
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(GEKKO) #elif defined(GEKKO)
// return current drive's name // return current drive's name
char *drv, cwd[BMAX_PATH] = {0}; char *drv, cwd[BMAX_PATH] = {0};
@ -424,32 +419,63 @@ char *Bgethomedir(void)
#endif #endif
} }
char *Bgetsupportdir(int32_t global) char *Bgetsupportdir(void)
{ {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3_ #if defined __APPLE__
UNREFERENCED_PARAMETER(global); return osx_getsupportdir();
return Bgethomedir();
#else #else
FSRef ref; return Bgethomedir();
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;
#endif #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) int32_t Bcorrectfilename(char *filename, int32_t removefn)
{ {
char *fn; char *fn;

View File

@ -58,3 +58,92 @@ int osx_ynbox(const char *name, const char *msg)
return r; 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;
}

View File

@ -15,6 +15,8 @@
# ifndef KEY_WOW64_32KEY # ifndef KEY_WOW64_32KEY
# define KEY_WOW64_32KEY 0x0200 # define KEY_WOW64_32KEY 0x0200
# endif # endif
#elif defined __APPLE__
# include "osxbits.h"
#endif #endif
#include "common.h" #include "common.h"
@ -292,16 +294,14 @@ void G_ExtInit(void)
{ {
char cwd[BMAX_PATH]; char cwd[BMAX_PATH];
if (getcwd(cwd,BMAX_PATH)) #ifdef __APPLE__
{ char *appdir = Bgetappdir();
#if defined(__APPLE__) addsearchpath(appdir);
/* Dirty hack on OS X to also look for gamedata inside the application bundle - rhoenie 08/08 */ Bfree(appdir);
char seekinappcontainer[BMAX_PATH];
Bsnprintf(seekinappcontainer,sizeof(seekinappcontainer),"%s/EDuke32.app/", cwd);
addsearchpath(seekinappcontainer);
#endif #endif
if (getcwd(cwd,BMAX_PATH) && Bstrcmp(cwd,"/") != 0)
addsearchpath(cwd); addsearchpath(cwd);
}
if (CommandPaths) if (CommandPaths)
{ {
@ -337,8 +337,6 @@ void G_ExtInit(void)
Bsnprintf(cwd,sizeof(cwd),"%s/" Bsnprintf(cwd,sizeof(cwd),"%s/"
#if defined(_WIN32) #if defined(_WIN32)
"EDuke32 Settings" "EDuke32 Settings"
#elif defined(__APPLE__)
"Library/Application Support/EDuke32"
#elif defined(GEKKO) #elif defined(GEKKO)
"apps/eduke32" "apps/eduke32"
#else #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) void G_AddSearchPaths(void)
{ {
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@ -613,10 +800,27 @@ void G_AddSearchPaths(void)
addsearchpath("/usr/share/games/eduke32"); addsearchpath("/usr/share/games/eduke32");
addsearchpath("/usr/local/share/games/eduke32"); addsearchpath("/usr/local/share/games/eduke32");
#elif defined(__APPLE__) #elif defined(__APPLE__)
addsearchpath("/Library/Application Support/JFDuke3D"); char buf[BMAX_PATH];
addsearchpath("/Library/Application Support/EDuke32"); 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) #elif defined (_WIN32)
// detect Steam and GOG versions of Duke3D
char buf[BMAX_PATH]; char buf[BMAX_PATH];
const char* instpath; const char* instpath;