]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/environment.cpp
radiant/camwindow, radiant/xywindow: Fix use of uninitialized values
[xonotic/netradiant.git] / radiant / environment.cpp
index 60100cec38fc8cf5eff6b0a0e74114bb92fe847b..d6be70d54a6b1eb1db87d3f368d9fc1d2ed49499 100644 (file)
 #include "cmdlib.h"
 
 int g_argc;
-char const **g_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 const** g_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 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_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;
 }
 
-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 (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;
+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 ( 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) {
-        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
+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;
+               }
+       }
+       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 ) )
+                       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 ) )
+                       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
-            if (gamedetect_check_game("nexuiz.game", "data/common-spog.pk3", "nexuiz-linux-glx.sh", buf, p - buf))
+                       if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", NULL, buf, p - buf ) )
 #endif
-            { 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;
-            }
-        }
-    }
+                       { 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;
+               }
+       }
 }
 
-namespace {
-    CopiedString home_path;
-    CopiedString app_path;
+namespace
+{
+       // executable file path
+       CopiedString app_filepath;
+       // directory paths
+       CopiedString home_path;
+       CopiedString app_path;
+       CopiedString lib_path;
+       CopiedString data_path;
 }
 
-const char *environment_get_home_path()
-{
-    return home_path.c_str();
+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_app_path(){
+       return app_path.c_str();
 }
 
-const char *environment_get_app_path()
+const char *environment_get_lib_path()
 {
-    return app_path.c_str();
+       return lib_path.c_str();
 }
 
-bool portable_app_setup()
+const char *environment_get_data_path()
 {
-    StringOutputStream confdir(256);
-    confdir << app_path.c_str() << "settings/";
-    if (file_exists(confdir.c_str())) {
-        home_path = confdir.c_str();
-        return true;
-    }
-    return false;
+       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 GDEF_OS_POSIX
@@ -198,71 +216,104 @@ bool portable_app_setup()
 
 #include <glib.h>
 
-const char *LINK_NAME =
+const charLINK_NAME =
 #if GDEF_OS_LINUX
-        "/proc/self/exe"
-#else // FreeBSD and OSX
-"/proc/curproc/file"
+       "/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 const *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 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_path = getexename(real);
-        ASSERT_MESSAGE(!string_empty(app_path.c_str()), "failed to deduce app path");
-    }
-
-    if (!portable_app_setup()) {
-        StringOutputStream home(256);
-        home << DirectoryCleaned(g_get_user_config_dir()) << "netradiant/";
-        Q_mkdir(home.c_str());
-        home_path = home.c_str();
-    }
-    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 GDEF_OS_WINDOWS
@@ -270,34 +321,44 @@ void environment_init(int argc, char const *argv[])
 #include <windows.h>
 
 void environment_init( int argc, char const* argv[] ){
-    args_init( argc, argv );
-
-    {
-        // 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();
-    }
-
-    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();
+       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