diff --git a/engine/common/common.h b/engine/common/common.h index 4d8e836c..b0b8810c 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -341,8 +341,6 @@ typedef struct host_parm_s qboolean movevars_changed; qboolean renderinfo_changed; - char rootdir[MAX_OSPATH]; // member root directory - char rodir[MAX_OSPATH]; // readonly root char gamefolder[MAX_QPATH]; // it's a default gamefolder poolhandle_t imagepool; // imagelib mempool poolhandle_t soundpool; // soundlib mempool @@ -376,7 +374,6 @@ typedef void (*xcommand_t)( void ); // // filesystem_engine.c // -qboolean FS_LoadProgs( void ); void FS_Init( void ); void FS_Shutdown( void ); void *FS_GetNativeObject( const char *obj ); diff --git a/engine/common/filesystem_engine.c b/engine/common/filesystem_engine.c index 79ba2398..e2ca64e6 100644 --- a/engine/common/filesystem_engine.c +++ b/engine/common/filesystem_engine.c @@ -16,6 +16,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +#include #include "common.h" #include "library.h" #include "platform/platform.h" @@ -26,6 +27,15 @@ fs_globals_t *FI; static pfnCreateInterface_t fs_pfnCreateInterface; static HINSTANCE fs_hInstance; +static void COM_StripDirectorySlash( char *pname ) +{ + size_t len; + + len = Q_strlen( pname ); + if( len > 0 && pname[len - 1] == '/' ) + pname[len - 1] = 0; +} + void *FS_GetNativeObject( const char *obj ) { if( fs_pfnCreateInterface ) @@ -80,7 +90,7 @@ static void FS_UnloadProgs( void ) #define FILESYSTEM_STDIO_DLL "filesystem_stdio." OS_LIB_EXT #endif -qboolean FS_LoadProgs( void ) +static qboolean FS_LoadProgs( void ) { const char *name = FILESYSTEM_STDIO_DLL; FSAPI GetFSAPI; @@ -89,36 +99,104 @@ qboolean FS_LoadProgs( void ) if( !fs_hInstance ) { - Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() ); + Sys_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() ); return false; } if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API ))) { FS_UnloadProgs(); - Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name ); + Sys_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name ); return false; } if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION ) { FS_UnloadProgs(); - Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ ); + Sys_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ ); return false; } if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" ))) { FS_UnloadProgs(); - Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name ); + Sys_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name ); return false; } Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ ); - return true; } +static qboolean FS_DetermineRootDirectory( char *out, size_t size ) +{ + const char *path = getenv( "XASH3D_BASEDIR" ); + + if( COM_CheckString( path )) + { + Q_strncpy( out, path, size ); + return true; + } + +#if TARGET_OS_IOS + Q_strncpy( out, IOS_GetDocsDir(), size ); + return true; +#elif XASH_ANDROID && XASH_SDL + path = SDL_AndroidGetExternalStoragePath(); + if( path != NULL ) + { + Q_strncpy( out, path, size ); + return true; + } + Sys_Error( "couldn't determine Android external storage path: %s", SDL_GetError( )); + return false; +#elif XASH_PSVITA + if( PSVita_GetBasePath( out, size )) + return true; + Sys_Error( "couldn't find Xash3D data directory" ); + return false; +#elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2 + path = SDL_GetBasePath(); + if( path != NULL ) + { + Q_strncpy( out, path, size ); + SDL_free(( void *)path ); + return true; + } + +#if XASH_POSIX || XASH_WIN32 + if( getcwd( out, size )) + return true; + Sys_Error( "couldn't determine current directory: %s, getcwd: %s", SDL_GetError(), strerror( errno )); +#else // !( XASH_POSIX || XASH_WIN32 ) + Sys_Error( "couldn't determine current directory: %s", SDL_GetError( )); +#endif // !( XASH_POSIX || XASH_WIN32 ) + return false; +#else // generic case + if( getcwd( out, size )) + return true; + + Sys_Error( "couldn't determine current directory: %s", strerror( errno )); + return false; +#endif // generic case +} + +static qboolean FS_DetermineReadOnlyRootDirectory( char *out, size_t size ) +{ + const char *env_rodir = getenv( "XASH3D_RODIR" ); + + if( _Sys_GetParmFromCmdLine( "-rodir", out, size )) + return true; + + if( COM_CheckString( env_rodir )) + { + Q_strncpy( out, env_rodir, size ); + return true; + } + + return false; +} + /* ================ FS_Init @@ -127,20 +205,39 @@ FS_Init void FS_Init( void ) { string gamedir; + char rodir[MAX_OSPATH], rootdir[MAX_OSPATH]; + rodir[0] = rootdir[0] = 0; - Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" ); - Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" ); - Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" ); + if( !FS_DetermineRootDirectory( rootdir, sizeof( rootdir )) || !COM_CheckStringEmpty( rootdir )) + { + Sys_Error( "couldn't determine current directory (empty string)" ); + return; + } + COM_FixSlashes( rootdir ); + COM_StripDirectorySlash( rootdir ); + + FS_DetermineReadOnlyRootDirectory( rodir, sizeof( rodir )); + COM_FixSlashes( rodir ); + COM_StripDirectorySlash( rodir ); if( !Sys_GetParmFromCmdLine( "-game", gamedir )) Q_strncpy( gamedir, SI.basedirName, sizeof( gamedir )); // gamedir == basedir - if( !FS_InitStdio( true, host.rootdir, SI.basedirName, gamedir, host.rodir )) + FS_LoadProgs(); + if( !FS_InitStdio( true, rootdir, SI.basedirName, gamedir, rodir )) { - Host_Error( "Can't init filesystem_stdio!\n" ); + Sys_Error( "Can't init filesystem_stdio!\n" ); return; } + // TODO: this function will cause engine to stop in case of fail + // when it will have an option to return string error, restore Sys_Error + g_fsapi.SetCurrentDirectory( rootdir ); + + Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" ); + Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" ); + Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" ); + if( !Sys_GetParmFromCmdLine( "-dll", SI.gamedll )) SI.gamedll[0] = 0; diff --git a/engine/common/host.c b/engine/common/host.c index 84955d4c..1402188e 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -18,8 +18,6 @@ GNU General Public License for more details. #include #endif // XASH_SDL #include // va_args -#include // errno -#include // strerror #if !XASH_WIN32 #include // fork #include @@ -29,7 +27,6 @@ GNU General Public License for more details. #if XASH_EMSCRIPTEN #include #endif -#include #include "common.h" #include "base_cmd.h" #include "client.h" @@ -1014,24 +1011,21 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole { char dev_level[4]; int developer = DEFAULT_DEV; - const char *baseDir; char ticrate[16]; - int len, i; + int i; // some commands may turn engine into infinite loop, // e.g. xash.exe +game xash -game xash // so we clear all cmd_args, but leave dbg states as well Sys_ParseCommandLine( argc, argv ); - if( !Sys_CheckParm( "-disablehelp" ) ) + if( !Sys_CheckParm( "-disablehelp" )) { - if( Sys_CheckParm( "-help" ) || Sys_CheckParm( "-h" ) || Sys_CheckParm( "--help" ) ) - { + if( Sys_CheckParm( "-help" ) || Sys_CheckParm( "-h" ) || Sys_CheckParm( "--help" )) Sys_PrintUsage(); - } } - if( !Sys_CheckParm( "-noch" ) ) + if( !Sys_CheckParm( "-noch" )) Sys_SetupCrashHandler(); host.enabledll = !Sys_CheckParm( "-nodll" ); @@ -1146,91 +1140,6 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole #endif Platform_Init(); - - baseDir = getenv( "XASH3D_BASEDIR" ); - - if( COM_CheckString( baseDir ) ) - { - Q_strncpy( host.rootdir, baseDir, sizeof( host.rootdir )); - } - else - { -#if TARGET_OS_IOS - Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof( host.rootdir )); -#elif XASH_ANDROID && XASH_SDL - Q_strncpy( host.rootdir, SDL_AndroidGetExternalStoragePath(), sizeof( host.rootdir )); -#elif XASH_PSVITA - if ( !PSVita_GetBasePath( host.rootdir, sizeof( host.rootdir ))) - { - Sys_Error( "couldn't find xash3d data directory" ); - host.rootdir[0] = 0; - } -#elif (XASH_SDL == 2) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2 - char *szBasePath = SDL_GetBasePath(); - if( szBasePath ) - { - Q_strncpy( host.rootdir, szBasePath, sizeof( host.rootdir )); - SDL_free( szBasePath ); - } - else - { -#if XASH_POSIX || XASH_WIN32 - if( !getcwd( host.rootdir, sizeof( host.rootdir ))) - Sys_Error( "couldn't determine current directory: %s, getcwd: %s", SDL_GetError(), strerror( errno )); -#else - Sys_Error( "couldn't determine current directory: %s", SDL_GetError() ); -#endif - } -#else - if( !getcwd( host.rootdir, sizeof( host.rootdir ))) - { - Sys_Error( "couldn't determine current directory: %s", strerror( errno ) ); - host.rootdir[0] = 0; - } -#endif - } - -#if XASH_WIN32 - COM_FixSlashes( host.rootdir ); -#endif - - len = Q_strlen( host.rootdir ); - - if( len && host.rootdir[len - 1] == '/' ) - host.rootdir[len - 1] = 0; - - // get readonly root. The order is: check for arg, then env. - // if still not got it, rodir is disabled. - host.rodir[0] = '\0'; - if( !Sys_GetParmFromCmdLine( "-rodir", host.rodir )) - { - char *roDir = getenv( "XASH3D_RODIR" ); - - if( COM_CheckString( roDir )) - Q_strncpy( host.rodir, roDir, sizeof( host.rodir )); - } - -#if XASH_WIN32 - COM_FixSlashes( host.rootdir ); -#endif - - len = Q_strlen( host.rodir ); - - if( len && host.rodir[len - 1] == '/' ) - host.rodir[len - 1] = 0; - - if( !COM_CheckStringEmpty( host.rootdir )) - { - Sys_Error( "Changing working directory failed (empty working directory)\n" ); - return; - } - - FS_LoadProgs(); - - // TODO: this function will cause engine to stop in case of fail - // when it will have an option to return string error, restore Sys_Error - FS_SetCurrentDirectory( host.rootdir ); - FS_Init(); Sys_InitLog();