X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fenvironment.cpp;h=d6be70d54a6b1eb1db87d3f368d9fc1d2ed49499;hb=80bb5fdd23e124b4c4da8509634d95d1459e6a3b;hp=99c6971a07aac05f34d8756eaab316d9d39b61c9;hpb=b7cd2135c98553b761866f5eda0cc89ce6f826fd;p=xonotic%2Fnetradiant.git diff --git a/radiant/environment.cpp b/radiant/environment.cpp index 99c6971a..d6be70d5 100644 --- a/radiant/environment.cpp +++ b/radiant/environment.cpp @@ -1,25 +1,26 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant 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. + GtkRadiant 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. -GtkRadiant 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. + GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "environment.h" +#include "globaldefs.h" #include "stream/textstream.h" #include "string/string.h" @@ -30,246 +31,334 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "cmdlib.h" int g_argc; -char** g_argv; +char const** g_argv; -void args_init(int argc, char* argv[]) -{ - int i, j, k; - - for (i = 1; i < argc; i++) - { - for (k = i; k < argc; k++) - if (argv[k] != 0) - break; - - if (k > i) - { - k -= i; - for (j = i + k; j < argc; j++) - argv[j-k] = argv[j]; - argc -= k; - } - } - - g_argc = argc; - g_argv = argv; +void args_init( int argc, char const* argv[] ){ + int i, j, k; + + for ( i = 1; i < argc; i++ ) + { + for ( k = i; k < argc; k++ ) + { + if ( argv[k] != 0 ) { + break; + } + } + + if ( k > i ) { + k -= i; + for ( j = i + k; j < argc; j++ ) + { + argv[j - k] = argv[j]; + } + argc -= k; + } + } + + g_argc = argc; + g_argv = argv; } -char *gamedetect_argv_buffer[1024]; -void gamedetect_found_game(char *game, char *path) -{ - int argc; - static char buf[128]; - - if(g_argv == gamedetect_argv_buffer) - return; - - globalOutputStream() << "Detected game " << game << " in " << path << "\n"; - - sprintf(buf, "-%s-EnginePath", game); - argc = 0; - gamedetect_argv_buffer[argc++] = "-global-gamefile"; - gamedetect_argv_buffer[argc++] = game; - gamedetect_argv_buffer[argc++] = buf; - gamedetect_argv_buffer[argc++] = path; - if((size_t) (argc + g_argc) >= sizeof(gamedetect_argv_buffer) / sizeof(*gamedetect_argv_buffer) - 1) - g_argc = sizeof(gamedetect_argv_buffer) / sizeof(*gamedetect_argv_buffer) - g_argc - 1; - memcpy(gamedetect_argv_buffer + 4, g_argv, sizeof(*gamedetect_argv_buffer) * g_argc); - g_argc += argc; - g_argv = gamedetect_argv_buffer; +char const *gamedetect_argv_buffer[1024]; + +void gamedetect_found_game( char const *game, char *path ){ + int argc; + static char buf[128]; + + if ( g_argv == gamedetect_argv_buffer ) { + return; + } + + globalOutputStream() << "Detected game " << game << " in " << path << "\n"; + + sprintf( buf, "-%s-EnginePath", game ); + argc = 0; + gamedetect_argv_buffer[argc++] = "-global-gamefile"; + gamedetect_argv_buffer[argc++] = game; + gamedetect_argv_buffer[argc++] = buf; + gamedetect_argv_buffer[argc++] = path; + if ( (size_t) ( argc + g_argc ) >= sizeof( gamedetect_argv_buffer ) / sizeof( *gamedetect_argv_buffer ) - 1 ) { + g_argc = sizeof( gamedetect_argv_buffer ) / sizeof( *gamedetect_argv_buffer ) - g_argc - 1; + } + memcpy( gamedetect_argv_buffer + 4, g_argv, sizeof( *gamedetect_argv_buffer ) * g_argc ); + g_argc += argc; + g_argv = gamedetect_argv_buffer; } -void gamedetect() -{ - // if we're inside a Nexuiz install - // default to nexuiz.game (unless the user used an option to inhibit this) - bool nogamedetect = false; - int i; - for(i = 1; i < g_argc - 1; ++i) - if(g_argv[i][0] == '-') - { - if(!strcmp(g_argv[i], "-gamedetect")) - nogamedetect = !strcmp(g_argv[i+1], "false"); - ++i; +bool gamedetect_check_game( char const *gamefile, const char *checkfile1, const char *checkfile2, char *buf /* must have 64 bytes free after bufpos */, int bufpos ){ + buf[bufpos] = '/'; + + strcpy( buf + bufpos + 1, checkfile1 ); + globalOutputStream() << "Checking for a game file in " << buf << "\n"; + if ( !file_exists( buf ) ) { + return false; } - if(!nogamedetect) - { - static char buf[1024 + 64]; - strncpy(buf, environment_get_app_path(), sizeof(buf)); - buf[sizeof(buf) - 1 - 64] = 0; - if(!strlen(buf)) - return; - - char *p = buf + strlen(buf) - 1; // point directly on the slash of get_app_path - while(p != buf) + + if ( checkfile2 ) { + strcpy( buf + bufpos + 1, checkfile2 ); + globalOutputStream() << "Checking for a game file in " << buf << "\n"; + if ( !file_exists( buf ) ) { + return false; + } + } + + buf[bufpos + 1] = 0; + gamedetect_found_game( gamefile, buf ); + return true; +} + +void gamedetect(){ + // if we're inside a Nexuiz install + // default to nexuiz.game (unless the user used an option to inhibit this) + bool nogamedetect = false; + int i; + for ( i = 1; i < g_argc - 1; ++i ) { - // TODO add more games to this - // try to detect Nexuiz installs - strcpy(p, "/data/common-spog.pk3"); - globalOutputStream() << "Checking for a game file in " << buf << "\n"; - if(file_exists(buf)) - { -#if defined(WIN32) - strcpy(p, "/nexuiz.exe"); -#elif defined(__APPLE__) - strcpy(p, "/Nexuiz.app/Contents/Info.plist"); + if ( g_argv[i][0] == '-' ) { + if ( !strcmp( g_argv[i], "-gamedetect" ) ) { + nogamedetect = !strcmp( g_argv[i + 1], "false" ); + } + ++i; + } + } + if ( !nogamedetect ) { + static char buf[1024 + 64]; + strncpy( buf, environment_get_app_path(), sizeof( buf ) ); + buf[sizeof( buf ) - 1 - 64] = 0; + if ( !strlen( buf ) ) { + return; + } + + char *p = buf + strlen( buf ) - 1; // point directly on the slash of get_app_path + while ( p != buf ) + { + // TODO add more games to this + + // try to detect Nexuiz installs +#if GDEF_OS_WINDOWS + if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz.exe", buf, p - buf ) ) +#elif GDEF_OS_MACOS + if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "Nexuiz.app/Contents/Info.plist", buf, p - buf ) ) +#elif GDEF_OS_LINUX + if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz-linux-glx.sh", buf, p - buf ) ) #else - strcpy(p, "/nexuiz-linux-glx.sh"); + if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", NULL, buf, p - buf ) ) #endif - if(file_exists(buf)) - { - p[1] = 0; - gamedetect_found_game("nexuiz.game", buf); - return; + { return; } + + // try to detect Quetoo installs + if ( gamedetect_check_game( "quetoo.game", "default/icons/quetoo.png", NULL, buf, p - buf ) ) { + return; + } + + // try to detect Warsow installs + if ( gamedetect_check_game( "warsow.game", "basewsw/dedicated_autoexec.cfg", NULL, buf, p - buf ) ) { + return; + } + + // we found nothing + // go backwards + --p; + while ( p != buf && *p != '/' && *p != '\\' ) + --p; } - } - - // we found nothing - // go backwards - --p; - while(p != buf && *p != '/') - --p; } - } } namespace { - CopiedString home_path; - CopiedString app_path; + // executable file path + CopiedString app_filepath; + // directory paths + CopiedString home_path; + CopiedString app_path; + CopiedString lib_path; + CopiedString data_path; +} + +const char* environment_get_app_filepath(){ + return app_filepath.c_str(); +} + +const char* environment_get_home_path(){ + return home_path.c_str(); } -const char* environment_get_home_path() +const char* environment_get_app_path(){ + return app_path.c_str(); +} + +const char *environment_get_lib_path() { - return home_path.c_str(); + return lib_path.c_str(); } -const char* environment_get_app_path() +const char *environment_get_data_path() { - return app_path.c_str(); + return data_path.c_str(); } +bool portable_app_setup(){ + StringOutputStream confdir( 256 ); + confdir << app_path.c_str() << "settings/"; + if ( file_is_directory( confdir.c_str() ) ) { + home_path = confdir.c_str(); + return true; + } + return false; +} -#if defined(POSIX) +#if GDEF_OS_POSIX #include #include -#include +#include -#include +#include const char* LINK_NAME = -#if defined (__linux__) - "/proc/self/exe" -#else // FreeBSD and OSX - "/proc/curproc/file" +#if GDEF_OS_LINUX + "/proc/self/exe" +#else // FreeBSD and macOS + "/proc/curproc/file" #endif ; -/// brief Returns the filename of the executable belonging to the current process, or 0 if not found. -char* getexename(char *buf) -{ - /* Now read the symbolic link */ - int ret = readlink(LINK_NAME, buf, PATH_MAX); - - if(ret == -1) - { - globalOutputStream() << "getexename: falling back to argv[0]: " << makeQuoted(g_argv[0]); - const char* path = realpath(g_argv[0], buf); - if(path == 0) - { - /* In case of an error, leave the handling up to the caller */ - return ""; - } - } - - /* Ensure proper NUL termination */ - buf[ret] = 0; - - /* delete the program name */ - *(strrchr(buf, '/')) = '\0'; - - // NOTE: we build app path with a trailing '/' - // it's a general convention in Radiant to have the slash at the end of directories - if (buf[strlen(buf)-1] != '/') - { - strcat(buf, "/"); - } - - return buf; +/// brief Returns the filename of the executable belonging to the current process, or empty string if not found. +char const* getexename( char *buf ){ + /* Now read the symbolic link */ + const int ret = readlink( LINK_NAME, buf, PATH_MAX ); + + if ( ret == -1 ) { + globalOutputStream() << "getexename: falling back to argv[0]: " << makeQuoted( g_argv[0] ); + if( realpath( g_argv[0], buf ) == 0 ) { + /* In case of an error, leave the handling up to the caller */ + *buf = '\0'; + } + } + else { + /* Ensure proper NUL termination */ + buf[ret] = 0; + } + + return buf; } -void environment_init(int argc, char* argv[]) -{ - // Give away unnecessary root privileges. - // Important: must be done before calling gtk_init(). - char *loginname; - struct passwd *pw; - seteuid(getuid()); - if (geteuid() == 0 && (loginname = getlogin()) != 0 && - (pw = getpwnam(loginname)) != 0) - setuid(pw->pw_uid); - - args_init(argc, argv); - - { - StringOutputStream home(256); - home << DirectoryCleaned(g_get_home_dir()) << ".netradiant/"; - Q_mkdir(home.c_str()); - home_path = home.c_str(); - } - { - char real[PATH_MAX]; - app_path = getexename(real); - ASSERT_MESSAGE(!string_empty(app_path.c_str()), "failed to deduce app path"); - } - gamedetect(); +char const* getexepath( char *buf ) { + /* delete the program name */ + *( strrchr( buf, '/' ) ) = '\0'; + + // NOTE: we build app path with a trailing '/' + // it's a general convention in Radiant to have the slash at the end of directories + if ( buf[strlen( buf ) - 1] != '/' ) { + strcat( buf, "/" ); + } + + return buf; +} + +void environment_init( int argc, char const* argv[] ){ + // Give away unnecessary root privileges. + // Important: must be done before calling gtk_init(). + char *loginname; + struct passwd *pw; + seteuid( getuid() ); + if ( geteuid() == 0 && ( loginname = getlogin() ) != 0 && + ( pw = getpwnam( loginname ) ) != 0 ) { + setuid( pw->pw_uid ); + } + + args_init( argc, argv ); + + { + char real[PATH_MAX]; + app_filepath = getexename( real ); + ASSERT_MESSAGE( !string_empty( app_filepath.c_str() ), "failed to deduce app path" ); + + strncpy( real, app_filepath.c_str(), strlen( app_filepath.c_str() ) ); + app_path = getexepath( real ); + } + + { + StringOutputStream buffer; + buffer << app_path.c_str() << "../lib/" << RADIANT_BASENAME << "/"; + if ( file_is_directory( buffer.c_str() ) ) { + lib_path = buffer.c_str(); + } + else { + lib_path = app_path.c_str(); + } + } + + { + StringOutputStream buffer; + buffer << app_path.c_str() << "../share/" << RADIANT_BASENAME << "/"; + if ( file_is_directory( buffer.c_str() ) ) { + data_path = buffer.c_str(); + } + else { + data_path = app_path.c_str(); + } + } + + if ( !portable_app_setup() ) { + // this is used on both Linux and macOS + // but a macOS specific code may be written instead + StringOutputStream home( 256 ); + home << DirectoryCleaned(g_get_user_config_dir()) << "/" << RADIANT_BASENAME << "/"; + // first create ~/.config + // since it may be missing on brand new home directory + Q_mkdir( g_get_user_config_dir() ); + // then create ~/.config/netradiant + Q_mkdir( home.c_str() ); + home_path = home.c_str(); + } + gamedetect(); } -#elif defined(WIN32) +#elif GDEF_OS_WINDOWS #include -void environment_init(int argc, char* argv[]) -{ - args_init(argc, argv); - - { - char *appdata = getenv("APPDATA"); - - StringOutputStream home(256); - if(!appdata || string_empty(appdata)) - { - ERROR_MESSAGE("Application Data folder not available.\n" - "Radiant will use C:\\ for user preferences.\n"); - home << "C:"; - } - else - { - home << PathCleaned(appdata); - } - home << "/NetRadiantSettings/"; - Q_mkdir(home.c_str()); - home_path = home.c_str(); - } - { - // get path to the editor - char filename[MAX_PATH+1]; - GetModuleFileName(0, filename, MAX_PATH); - char* last_separator = strrchr(filename, '\\'); - if(last_separator != 0) - { - *(last_separator+1) = '\0'; - } - else - { - filename[0] = '\0'; - } - StringOutputStream app(256); - app << PathCleaned(filename); - app_path = app.c_str(); - } - gamedetect(); +void environment_init( int argc, char const* argv[] ){ + args_init( argc, argv ); + + { + // get path to the editor + char filename[MAX_PATH + 1]; + StringOutputStream app_filepath_stream( 256 ); + StringOutputStream app_path_stream( 256 ); + + GetModuleFileName( 0, filename, MAX_PATH ); + + app_filepath_stream << PathCleaned( filename ); + app_filepath = app_filepath_stream.c_str(); + + char* last_separator = strrchr( filename, '\\' ); + if ( last_separator != 0 ) { + *( last_separator + 1 ) = '\0'; + } + else + { + filename[0] = '\0'; + } + + app_path_stream << PathCleaned( filename ); + app_path = app_path_stream.c_str(); + + lib_path = app_path; + data_path = app_path; + } + + if ( !portable_app_setup() ) { + char *appdata = getenv( "APPDATA" ); + StringOutputStream home( 256 ); + home << PathCleaned( appdata ); + home << "/NetRadiantSettings/"; + Q_mkdir( home.c_str() ); + home_path = home.c_str(); + } + gamedetect(); } #else