From 43ccc403e08b7b72eb687f2d3700e14ea078d30a Mon Sep 17 00:00:00 2001 From: divverent Date: Sun, 28 Feb 2010 19:10:37 +0000 Subject: [PATCH] Detect appended data to the DP executable. If it's a pk3, it is added FIRST (TODO: should this be LAST) into the search path. If it contains a darkplaces.opt text file, its contents are parsed and used as extra command line arguments. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10034 d7cf8633-e32d-0410-b094-e92efae38249 --- common.c | 1 + common.h | 1 + fs.c | 140 +++++++++++++++++++++++++++++++++++++++------------ fs.h | 1 + host.c | 4 ++ sys.h | 2 + sys_linux.c | 1 + sys_sdl.c | 1 + sys_shared.c | 54 ++++++++++++++++++++ sys_win.c | 2 + 10 files changed, 174 insertions(+), 33 deletions(-) diff --git a/common.c b/common.c index ad5f5abb..a9b21b6b 100644 --- a/common.c +++ b/common.c @@ -33,6 +33,7 @@ cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launche char com_token[MAX_INPUTLINE]; int com_argc; const char **com_argv; +int com_selffd = -1; gamemode_t gamemode; const char *gamename; diff --git a/common.h b/common.h index 45cf7de5..4c7165c1 100644 --- a/common.h +++ b/common.h @@ -204,6 +204,7 @@ int COM_ParseToken_Console(const char **datapointer); extern int com_argc; extern const char **com_argv; +extern int com_selffd; int COM_CheckParm (const char *parm); void COM_Init (void); diff --git a/fs.c b/fs.c index cbcf7c03..c9e6d565 100644 --- a/fs.c +++ b/fs.c @@ -232,6 +232,7 @@ typedef struct pk3_endOfCentralDir_s unsigned int cdir_size; ///< size of the central directory unsigned int cdir_offset; ///< with respect to the starting disk number unsigned short comment_size; + fs_offset_t prepended_garbage; } pk3_endOfCentralDir_t; @@ -327,6 +328,7 @@ const char *const fs_checkgamedir_missing = "missing"; char fs_userdir[MAX_OSPATH]; char fs_gamedir[MAX_OSPATH]; char fs_basedir[MAX_OSPATH]; +static pack_t *fs_selfpack = NULL; // list of active game directories (empty if not running a mod) int fs_numgamedirs = 0; @@ -527,6 +529,8 @@ qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOf eocd->cdir_size = LittleLong (eocd->cdir_size); eocd->cdir_offset = LittleLong (eocd->cdir_offset); eocd->comment_size = LittleShort (eocd->comment_size); + eocd->prepended_garbage = filesize - (ind + ZIP_END_CDIR_SIZE) - eocd->cdir_offset - eocd->cdir_size; // this detects "SFX" zip files + eocd->cdir_offset += eocd->prepended_garbage; Mem_Free (buffer); @@ -620,7 +624,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) flags = PACKFILE_FLAG_DEFLATED; else flags = 0; - offset = BuffLittleLong (&ptr[42]); + offset = BuffLittleLong (&ptr[42]) + eocd->prepended_garbage; packsize = BuffLittleLong (&ptr[20]); realsize = BuffLittleLong (&ptr[24]); @@ -661,21 +665,12 @@ FS_LoadPackPK3 Create a package entry associated with a PK3 file ==================== */ -pack_t *FS_LoadPackPK3 (const char *packfile) +pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle) { - int packhandle; pk3_endOfCentralDir_t eocd; pack_t *pack; int real_nb_files; -#if _MSC_VER >= 1400 - _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE); -#else - packhandle = open (packfile, O_RDONLY | O_BINARY); -#endif - if (packhandle < 0) - return NULL; - if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd)) { Con_Printf ("%s is not a PK3 file\n", packfile); @@ -722,6 +717,18 @@ pack_t *FS_LoadPackPK3 (const char *packfile) Con_DPrintf("Added packfile %s (%i files)\n", packfile, real_nb_files); return pack; } +pack_t *FS_LoadPackPK3 (const char *packfile) +{ + int packhandle; +#if _MSC_VER >= 1400 + _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE); +#else + packhandle = open (packfile, O_RDONLY | O_BINARY); +#endif + if (packhandle < 0) + return NULL; + return FS_LoadPackPK3FromFD(packfile, packhandle); +} /* @@ -1251,7 +1258,7 @@ void FS_ClearSearchPath (void) { searchpath_t *search = fs_searchpaths; fs_searchpaths = search->next; - if (search->pack) + if (search->pack && search->pack != fs_selfpack) { if(!search->pack->vpack) { @@ -1267,6 +1274,18 @@ void FS_ClearSearchPath (void) } } +static void FS_AddSelfPack(void) +{ + if(fs_selfpack) + { + searchpath_t *search; + search = Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->next = fs_searchpaths; + search->pack = fs_selfpack; + fs_searchpaths = search; + } +} + /* ================ @@ -1313,6 +1332,9 @@ void FS_Rescan (void) } Cvar_SetQuick(&cvar_fs_gamedir, gamedirbuf); // so QC or console code can query it + // add back the selfpack as new first item + FS_AddSelfPack(); + // set the default screenshot name to either the mod name or the // gamemode screenshot name if (strcmp(com_modname, gamedirname1)) @@ -1577,6 +1599,56 @@ static void FS_ListGameDirs(void) } } +/* +================ +FS_Init_SelfPack +================ +*/ +void FS_Init_SelfPack (void) +{ + PK3_OpenLibrary (); + fs_mempool = Mem_AllocPool("file management", 0, NULL); + if(com_selffd >= 0) + { + fs_selfpack = FS_LoadPackPK3FromFD(com_argv[0], com_selffd); + if(fs_selfpack) + { + char *buf, *q; + const char *p; + FS_AddSelfPack(); + buf = (char *) FS_LoadFile("darkplaces.opt", tempmempool, true, NULL); + if(buf) + { + const char **new_argv; + int i = 0; + int args_left = 256; + if(com_argc == 0) + { + com_argv[0] = "dummy"; + com_argv[1] = NULL; + com_argc = 1; + } + new_argv = Mem_Alloc(fs_mempool, sizeof(*com_argv) * (com_argc + args_left + 1)); + p = buf; + while(COM_ParseToken_Console(&p)) + { + if(i >= args_left) + break; + q = Mem_Alloc(fs_mempool, strlen(com_token) + 1); + strlcpy(q, com_token, strlen(com_token) + 1); + new_argv[i+1] = q; + ++i; + } + new_argv[0] = com_argv[0]; + memcpy(&new_argv[i+2], &com_argv[1], sizeof(*com_argv) * com_argc); + com_argv = new_argv; + com_argc = com_argc + i; + } + Mem_Free(buf); + } + } +} + /* ================ FS_Init @@ -1604,8 +1676,6 @@ void FS_Init (void) // don't care for the result; if it fails, %USERPROFILE% will be used instead #endif - fs_mempool = Mem_AllocPool("file management", 0, NULL); - // Add the personal game directory if((i = COM_CheckParm("-userdir")) && i < com_argc - 1) { @@ -1694,8 +1764,6 @@ void FS_Init (void) #endif #endif - PK3_OpenLibrary (); - // -basedir // Overrides the system supplied base directory (under GAMENAME) // COMMANDLINEOPTION: Filesystem: -basedir chooses what base directory the game data is in, inside this there should be a data directory for the game (for example id1) @@ -1782,16 +1850,9 @@ void FS_Shutdown (void) #endif } -/* -==================== -FS_SysOpen - -Internal function used to create a qfile_t and open the relevant non-packed file on disk -==================== -*/ -static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking) +int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking) { - qfile_t* file; + int handle; int mod, opt; unsigned int ind; @@ -1812,7 +1873,7 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non break; default: Con_Printf ("FS_SysOpen(%s, %s): invalid mode\n", filepath, mode); - return NULL; + return -1; } for (ind = 1; mode[ind] != '\0'; ind++) { @@ -1833,15 +1894,28 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non if (nonblocking) opt |= O_NONBLOCK; - file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); - memset (file, 0, sizeof (*file)); - file->ungetc = EOF; - #if _MSC_VER >= 1400 - _sopen_s(&file->handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE); + _sopen_s(&handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE); #else - file->handle = open (filepath, mod | opt, 0666); + handle = open (filepath, mod | opt, 0666); #endif + return handle; +} + +/* +==================== +FS_SysOpen + +Internal function used to create a qfile_t and open the relevant non-packed file on disk +==================== +*/ +static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking) +{ + qfile_t* file; + + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); + file->ungetc = EOF; + file->handle = FS_SysOpenFD(filepath, mode, nonblocking); if (file->handle < 0) { Mem_Free (file); @@ -1851,7 +1925,7 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non file->real_length = lseek (file->handle, 0, SEEK_END); // For files opened in append mode, we start at the end of the file - if (mod & O_APPEND) + if (mode[0] == 'a') file->position = file->real_length; else lseek (file->handle, 0, SEEK_SET); diff --git a/fs.h b/fs.h index 78909aa7..65ee54ec 100644 --- a/fs.h +++ b/fs.h @@ -57,6 +57,7 @@ extern char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH]; qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs); // already_loaded may be NULL if caller does not care const char *FS_WhichPack(const char *filename); +int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking); qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet); qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet); qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet); diff --git a/host.c b/host.c index f90173f3..e51b3914 100644 --- a/host.c +++ b/host.c @@ -1006,6 +1006,7 @@ qboolean sys_nostdout = false; extern void u8_Init(void); extern void Render_Init(void); extern void Mathlib_Init(void); +extern void FS_Init_SelfPack(void); extern void FS_Init(void); extern void FS_Shutdown(void); extern void PR_Cmd_Init(void); @@ -1083,6 +1084,9 @@ static void Host_Init (void) // initialize console window (only used by sys_win.c) Sys_InitConsole(); + // initialize the self-pack (must be before COM_InitGameType as it may add command line options) + FS_Init_SelfPack(); + // detect gamemode from commandline options or executable name COM_InitGameType(); diff --git a/sys.h b/sys.h index 5a9831a7..37fcc804 100644 --- a/sys.h +++ b/sys.h @@ -86,6 +86,8 @@ void Sys_AllowProfiling (qboolean enable); double Sys_DoubleTime (void); +void Sys_ProvideSelfFD (void); + char *Sys_ConsoleInput (void); /// called to yield for a little bit so as not to hog cpu when paused or debugging diff --git a/sys_linux.c b/sys_linux.c index 269d2b9c..167121a8 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -146,6 +146,7 @@ int main (int argc, char **argv) com_argc = argc; com_argv = (const char **)argv; + Sys_ProvideSelfFD(); #ifdef FNDELAY fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); diff --git a/sys_sdl.c b/sys_sdl.c index d0efa835..724eb79d 100644 --- a/sys_sdl.c +++ b/sys_sdl.c @@ -168,6 +168,7 @@ int main (int argc, char *argv[]) com_argc = argc; com_argv = (const char **)argv; + Sys_ProvideSelfFD(); #ifndef WIN32 fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); diff --git a/sys_shared.c b/sys_shared.c index b2a712fc..3b83a498 100644 --- a/sys_shared.c +++ b/sys_shared.c @@ -421,3 +421,57 @@ void Sys_Sleep(int microseconds) printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000)); } } + +const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize) +{ + const char *p = PATH; + const char *q; + if(p && name) + { + while((q = strchr(p, ':'))) + { + dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name); + if(FS_SysFileExists(buf)) + return buf; + p = q + 1; + } + if(!q) // none found - try the last item + { + dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name); + if(FS_SysFileExists(buf)) + return buf; + } + } + return name; +} + +const char *Sys_FindExecutableName(void) +{ +#if defined(WIN32) + return com_argv[0]; +#else + static char exenamebuf[MAX_OSPATH+1]; + ssize_t n = -1; +#if defined(__FreeBSD__) + n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1); +#elif defined(__linux__) + n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1); +#endif + if(n > 0 && (size_t)(n) < sizeof(exenamebuf)) + { + exenamebuf[n] = 0; + return exenamebuf; + } + if(strchr(com_argv[0], '/')) + return com_argv[0]; // possibly a relative path + else + return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf)); +#endif +} + +void Sys_ProvideSelfFD(void) +{ + if(com_selffd != -1) + return; + com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false); +} diff --git a/sys_win.c b/sys_win.c index 2ed54abc..4adaf692 100644 --- a/sys_win.c +++ b/sys_win.c @@ -355,6 +355,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin } } + Sys_ProvideSelfFD(); + Host_Main(); /* return success of application */ -- 2.39.2