Implement gamedata loading from binary path

even if $PWD is not the same path as the executable is in, the game
will look for game data in directories next to the executable.
This commit is contained in:
Daniel Gibson 2015-04-11 20:11:19 +02:00
parent d2f7d27ad0
commit 544a464eea
4 changed files with 168 additions and 2 deletions

View file

@ -574,6 +574,7 @@ GAME_OBJS_ = \
# Used by the client
CLIENT_OBJS_ := \
src/backends/generic/misc.o \
src/backends/generic/qal.o \
src/backends/generic/vid.o \
src/backends/generic/qgl.o \
@ -698,7 +699,8 @@ SERVER_OBJS_ := \
src/server/sv_save.o \
src/server/sv_send.o \
src/server/sv_user.o \
src/server/sv_world.o
src/server/sv_world.o \
src/backends/generic/misc.o
ifeq ($(OSTYPE), Windows)
SERVER_OBJS_ += \

141
src/backends/generic/misc.c Normal file
View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* This file implements some generic funktions
*
* =======================================================================
*/
#include <stdio.h>
#include <string.h>
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <unistd.h> // readlink(), amongst others
#endif
#ifdef __FreeBSD__
#include <sys/sysctl.h> // for sysctl() to get path to executable
#endif
#ifdef _WIN32
#include <windows.h> // GetModuleFileNameA()
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h> // _NSGetExecutablePath
#endif
#ifndef PATH_MAX
// this is mostly for windows. windows has a MAX_PATH = 260 #define, but allows
// longer paths anyway.. this might not be the maximum allowed length, but is
// hopefully good enough for realistic usecases
#define PATH_MAX 4096
#define _DG__DEFINED_PATH_MAX
#endif
static void SetExecutablePath(char* exePath)
{
// !!! this assumes that exePath can hold PATH_MAX chars !!!
#ifdef _WIN32
DWORD len = GetModuleFileNameA(NULL, exePath, PATH_MAX);
if(len <= 0 || len == PATH_MAX)
{
// an error occured, clear exe path
exePath[0] = '\0';
}
#elif defined(__linux) || defined(__NetBSD__) || defined(__OpenBSD__)
// all the platforms that have /proc/$pid/exe or similar that symlink the
// real executable - basiscally Linux and the BSDs except for FreeBSD which
// doesn't enable proc by default and has a sysctl() for this
char buf[PATH_MAX] = {0};
#ifdef __linux
snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid());
#else // the BSDs
snprintf(buf, sizeof(buf), "/proc/%d/file", getpid());
#endif
// readlink() doesn't null-terminate!
int len = readlink(buf, exePath, PATH_MAX-1);
if (len <= 0)
{
// an error occured, clear exe path
exePath[0] = '\0';
}
else
{
exePath[len] = '\0';
}
#elif defined(__FreeBSD__)
// the sysctl should also work when /proc/ is not mounted (which seems to
// be common on FreeBSD), so use it..
int name[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
size_t len = PATH_MAX-1;
int ret = sysctl(name, sizeof(name)/sizeof(name[0]), exePath, &len, NULL, 0);
if(ret != 0)
{
// an error occured, clear exe path
exePath[0] = '\0';
}
#elif defined(__APPLE__)
uint32_t bufSize = PATH_MAX;
if(_NSGetExecutablePath(exePath, &bufSize) != 0)
{
// WTF, PATH_MAX is not enough to hold the path?
// an error occured, clear exe path
exePath[0] = '\0';
}
// TODO: realpath() ?
// TODO: no idea what this is if the executable is in an app bundle
#else
#error "Unsupported Platform!" // feel free to add implementation for your platform and send me a patch
#endif
}
const char *Sys_GetBinaryDir(void)
{
static char exeDir[PATH_MAX] = {0};
if(exeDir[0] != '\0') return exeDir;
SetExecutablePath(exeDir);
// cut off executable name
char* lastSlash = strrchr(exeDir, '/');
#ifdef _WIN32
char* lastBackSlash = strrchr(exeDir, '\\');
if(lastSlash == NULL || lastBackSlash > lastSlash) lastSlash = lastBackSlash;
#endif // _WIN32
if(lastSlash != NULL) lastSlash[1] = '\0'; // cut off after last (back)slash
return exeDir;
}

View file

@ -1368,7 +1368,7 @@ FS_AddHomeAsGameDirectory(char *dir)
return;
}
len = snprintf(gdir, sizeof(gdir), "%s%s/", home, dir);
len = snprintf(gdir, sizeof(gdir), "%s%s/", home, dir);
FS_CreatePath(gdir);
if ((len > 0) && (len < sizeof(gdir)) && (gdir[len - 1] == '/'))
@ -1400,6 +1400,26 @@ FS_AddSystemwideGameDirectory(char *dir)
}
#endif
void FS_AddBinaryDirAsGameDirectory(const char* dir)
{
char gdir[MAX_OSPATH];
const char *datadir = Sys_GetBinaryDir();
if(datadir[0] == '\0')
{
return;
}
int len = snprintf(gdir, sizeof(gdir), "%s%s/", datadir, dir);
printf("Using binary dir %s to fetch paks\n", gdir);
if ((len > 0) && (len < sizeof(gdir)) && (gdir[len - 1] == '/'))
{
gdir[len - 1] = 0;
}
FS_AddGameDirectory(gdir);
}
/*
* Allows enumerating all of the directories in the search path.
*/
@ -1675,6 +1695,7 @@ FS_SetGamedir(char *dir)
#endif
FS_AddGameDirectory(va("%s/%s", fs_basedir->string, dir));
FS_AddBinaryDirAsGameDirectory(dir);
FS_AddHomeAsGameDirectory(dir);
}
}
@ -2086,6 +2107,7 @@ FS_InitFilesystem(void)
/* Add baseq2 to search path. */
FS_AddGameDirectory(va("%s/" BASEDIRNAME, fs_basedir->string));
FS_AddBinaryDirAsGameDirectory(BASEDIRNAME);
FS_AddHomeAsGameDirectory(BASEDIRNAME);
/* Any set gamedirs will be freed up to here. */

View file

@ -793,6 +793,7 @@ void Sys_SendKeyEvents(void);
void Sys_Error(char *error, ...);
void Sys_Quit(void);
char *Sys_GetHomeDir(void);
const char *Sys_GetBinaryDir(void);
void Sys_FreeLibrary(void *handle);
void *Sys_LoadLibrary(const char *path, const char *sym, void **handle);