From dc538f4f504c3fa99945c4443e6114809aa90b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Krzy=C5=9Bk=C3=B3w?= <46760021+Flower35@users.noreply.github.com> Date: Sat, 28 Dec 2024 00:05:54 +0100 Subject: [PATCH] Reworked the platform-dependent executable paths. Quoting the command line for Discord game invites. (#188) --- data/dynos.h | 2 +- src/pc/crash_handler.c | 4 +- src/pc/discord/discord.c | 36 ++++++--------- src/pc/discord/discord.h | 1 - src/pc/djui/djui_language.c | 2 +- src/pc/djui/djui_panel_language.c | 2 +- src/pc/djui/djui_panel_player.c | 2 +- src/pc/fs/fs.c | 2 +- src/pc/mods/mods.c | 2 +- src/pc/platform.c | 73 +++++++++++++++++++++++-------- src/pc/platform.h | 3 +- src/pc/rom_checker.cpp | 2 +- 12 files changed, 79 insertions(+), 52 deletions(-) diff --git a/data/dynos.h b/data/dynos.h index d3976732f..30429fe7e 100644 --- a/data/dynos.h +++ b/data/dynos.h @@ -29,7 +29,7 @@ extern "C" { #endif #define DYNOS_VERSION "1.0" -#define DYNOS_EXE_FOLDER sys_exe_path() +#define DYNOS_EXE_FOLDER sys_exe_path_dir() #define DYNOS_USER_FOLDER fs_get_write_path("") #define DYNOS_RES_FOLDER "dynos" #define DYNOS_PACKS_FOLDER DYNOS_RES_FOLDER "/packs" diff --git a/src/pc/crash_handler.c b/src/pc/crash_handler.c index b59190047..44a72b16d 100644 --- a/src/pc/crash_handler.c +++ b/src/pc/crash_handler.c @@ -458,8 +458,8 @@ static void crash_handler(const int signalNum, siginfo_t *info, UNUSED ucontext_ // Load symbols char filename[256] = { 0 }; - const char *exe_path = sys_exe_path(); - if (NULL != exe_path) { + const char *exe_path = sys_exe_path_dir(); + if (exe_path[0] != '\0') { snprintf(filename, 256, "%s/%s", exe_path, "coop.map"); } else { snprintf(filename, 256, "%s", "coop.map"); diff --git a/src/pc/discord/discord.c b/src/pc/discord/discord.c index 0790805f7..710867cbc 100644 --- a/src/pc/discord/discord.c +++ b/src/pc/discord/discord.c @@ -2,16 +2,15 @@ #include "pc/djui/djui.h" #include "pc/crash_handler.h" #include "pc/debuglog.h" +#include "pc/platform.h" -#if defined(_WIN32) || defined(_WIN64) -#include -#include +#if defined(_WIN32) +#include #else -#include #define MAX_PATH 1024 #endif -#define MAX_LAUNCH_CMD (MAX_PATH + 12) +#define MAX_LAUNCH_CMD (MAX_PATH + 2) #define APPLICATION_ID_COOPDX 1159627283506679839 @@ -54,26 +53,17 @@ static void get_oauth2_token_callback(UNUSED void* data, enum EDiscordResult res static void register_launch_command(void) { char cmd[MAX_LAUNCH_CMD] = { 0 }; - int rc; -#if defined(_WIN32) || defined(_WIN64) - HMODULE hModule = GetModuleHandle(NULL); - if (hModule == NULL) { - LOG_ERROR("unable to retrieve absolute path!"); - return; - } - GetModuleFileName(hModule, cmd, sizeof(cmd)); + + const char *exe_path = sys_exe_path_file(); + if (exe_path[0] == '\0') { return; } + +#if defined(_WIN32) + snprintf(cmd, MAX_LAUNCH_CMD, "\"%s\"", exe_path); // argv[0] double-quoted #else - char pidpath[MAX_LAUNCH_CMD] = { 0 }; - char fullpath[MAX_LAUNCH_CMD] = { 0 }; - snprintf(pidpath, MAX_LAUNCH_CMD - 1, "/proc/%d/exe", getpid()); - rc = readlink(pidpath, fullpath, MAX_LAUNCH_CMD - 1); - if (rc <= 0) { - LOG_ERROR("unable to retrieve absolute path! rc = %d", rc); - return; - } - snprintf(cmd, MAX_LAUNCH_CMD, "%s", fullpath); + snprintf(cmd, MAX_LAUNCH_CMD, "'%s'", exe_path); // argv[0] single-quoted #endif - rc = app.activities->register_command(app.activities, cmd); + + int rc = app.activities->register_command(app.activities, cmd); if (rc != DiscordResult_Ok) { LOG_ERROR("register command failed %d", rc); return; diff --git a/src/pc/discord/discord.h b/src/pc/discord/discord.h index 15db5c67d..11f2c1157 100644 --- a/src/pc/discord/discord.h +++ b/src/pc/discord/discord.h @@ -5,7 +5,6 @@ #ifdef _WIN32 #define DISCORD_ID_FORMAT "%lld" -#include #else #define DISCORD_ID_FORMAT "%ld" #endif diff --git a/src/pc/djui/djui_language.c b/src/pc/djui/djui_language.c index e4fe6f59a..9165aeeb6 100644 --- a/src/pc/djui/djui_language.c +++ b/src/pc/djui/djui_language.c @@ -19,7 +19,7 @@ bool djui_language_init(char* lang) { // construct path char path[SYS_MAX_PATH] = ""; if (!lang || lang[0] == '\0') { lang = "English"; } - snprintf(path, SYS_MAX_PATH, "%s/lang/%s.ini", sys_exe_path(), lang); + snprintf(path, SYS_MAX_PATH, "%s/lang/%s.ini", sys_exe_path_dir(), lang); // load sLang = ini_load(path); diff --git a/src/pc/djui/djui_panel_language.c b/src/pc/djui/djui_panel_language.c index 1e72c5ef9..83af3c13a 100644 --- a/src/pc/djui/djui_panel_language.c +++ b/src/pc/djui/djui_panel_language.c @@ -90,7 +90,7 @@ void djui_panel_language_create(struct DjuiBase* caller) { { // construct lang path char lpath[SYS_MAX_PATH] = ""; - snprintf(lpath, SYS_MAX_PATH, "%s/lang", sys_exe_path()); + snprintf(lpath, SYS_MAX_PATH, "%s/lang", sys_exe_path_dir()); // open directory struct dirent* dir = NULL; diff --git a/src/pc/djui/djui_panel_player.c b/src/pc/djui/djui_panel_player.c index c1a4b6069..0db02e5aa 100644 --- a/src/pc/djui/djui_panel_player.c +++ b/src/pc/djui/djui_panel_player.c @@ -441,7 +441,7 @@ void djui_panel_player_create(struct DjuiBase* caller) { djui_selectionbox_create(body, DLANG(PLAYER, MODEL), characterChoices, CT_MAX, &configPlayerModel, djui_panel_player_value_changed); player_palettes_reset(); - player_palettes_read(sys_exe_path(), true); + player_palettes_read(sys_exe_path_dir(), true); player_palettes_read(fs_get_write_path(PALETTES_DIRECTORY), false); char* palettePresets[MAX_PRESET_PALETTES + 1] = { DLANG(PALETTE, CUSTOM) }; diff --git a/src/pc/fs/fs.c b/src/pc/fs/fs.c index 843ac1feb..91514fa14 100644 --- a/src/pc/fs/fs.c +++ b/src/pc/fs/fs.c @@ -255,7 +255,7 @@ const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path) { // ! means "executable directory" if (path[0] == '!') { - if (snprintf(buf, bufsiz, "%s%s", sys_exe_path(), path + 1) < 0) { + if (snprintf(buf, bufsiz, "%s%s", sys_exe_path_dir(), path + 1) < 0) { return ""; } } else { diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 32a5830b3..a3fa13699 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -301,7 +301,7 @@ void mods_refresh_local(void) { if (hasUserPath) { mods_load(&gLocalMods, userModPath, true); } char defaultModsPath[SYS_MAX_PATH] = { 0 }; - snprintf(defaultModsPath, SYS_MAX_PATH, "%s/%s", sys_exe_path(), MOD_DIRECTORY); + snprintf(defaultModsPath, SYS_MAX_PATH, "%s/%s", sys_exe_path_dir(), MOD_DIRECTORY); mods_load(&gLocalMods, defaultModsPath, false); // sort diff --git a/src/pc/platform.c b/src/pc/platform.c index b0a022126..2d9e86725 100644 --- a/src/pc/platform.c +++ b/src/pc/platform.c @@ -5,14 +5,19 @@ #include #include -#ifdef _WIN32 +#if defined(_WIN32) #include #include #include +#elif defined(__APPLE__) +#include +#else +#include #endif #include "cliopts.h" #include "fs/fs.h" +#include "debuglog.h" #include "configfile.h" /* these are not available on some platforms, so might as well */ @@ -247,17 +252,31 @@ const char *sys_user_path(void) return sys_windows_short_path_from_wcs(shortPath, SYS_MAX_PATH, widePath) ? shortPath : NULL; } -const char *sys_exe_path(void) +const char *sys_exe_path_dir(void) +{ + static char path[SYS_MAX_PATH]; + if ('\0' != path[0]) { return path; } + + const char *exeFilepath = sys_exe_path_file(); + char *lastSeparator = strrchr(exeFilepath, '\\'); + if (lastSeparator != NULL) { + size_t count = (size_t)(lastSeparator - exeFilepath); + strncpy(path, exeFilepath, count); + } + + return path; +} + +const char *sys_exe_path_file(void) { static char shortPath[SYS_MAX_PATH] = { 0 }; if ('\0' != shortPath[0]) { return shortPath; } WCHAR widePath[SYS_MAX_PATH]; - if (0 == GetModuleFileNameW(NULL, widePath, SYS_MAX_PATH)) { return NULL; } - - WCHAR *lastBackslash = wcsrchr(widePath, L'\\'); - if (NULL != lastBackslash) { *lastBackslash = L'\0'; } - else { return NULL; } + if (0 == GetModuleFileNameW(NULL, widePath, SYS_MAX_PATH)) { + LOG_ERROR("unable to retrieve absolute path."); + return shortPath; + } return sys_windows_short_path_from_wcs(shortPath, SYS_MAX_PATH, widePath) ? shortPath : NULL; } @@ -307,20 +326,38 @@ const char *sys_user_path(void) { return path; } -const char *sys_exe_path(void) { - static char path[SYS_MAX_PATH] = { 0 }; +const char *sys_exe_path_dir(void) { + static char path[SYS_MAX_PATH]; if ('\0' != path[0]) { return path; } - char *sdlPath = SDL_GetBasePath(); - if (sdlPath && sdlPath[0]) { - // use the SDL path if it exists - const unsigned int len = strlen(sdlPath); - snprintf(path, sizeof(path), "%s", sdlPath); - path[sizeof(path)-1] = 0; - SDL_free(sdlPath); - if (path[len-1] == '/' || path[len-1] == '\\') - path[len-1] = 0; // strip the trailing separator + const char *exeFilepath = sys_exe_path_file(); + char *lastSeparator = strrchr(exeFilepath, '/'); + if (lastSeparator != NULL) { + size_t count = (size_t)(lastSeparator - exeFilepath); + strncpy(path, exeFilepath, count); } + + return path; +} + +const char *sys_exe_path_file(void) { + static char path[SYS_MAX_PATH]; + if ('\0' != path[0]) { return path; } + +#if defined(__APPLE__) + uint32_t bufsize = SYS_MAX_PATH; + int res = _NSGetExecutablePath(path, &bufsize); + +#else + char procPath[SYS_MAX_PATH]; + snprintf(procPath, SYS_MAX_PATH, "/proc/%d/exe", getpid()); + ssize_t res = readlink(procPath, path, SYS_MAX_PATH); + +#endif + if (res <= 0) { + LOG_ERROR("unable to retrieve absolute path."); + } + return path; } diff --git a/src/pc/platform.h b/src/pc/platform.h index bde57d212..19ab699dc 100644 --- a/src/pc/platform.h +++ b/src/pc/platform.h @@ -20,7 +20,8 @@ bool sys_windows_short_path_from_wcs(char *destPath, size_t destSize, const wcha bool sys_windows_short_path_from_mbs(char* destPath, size_t destSize, const char *mbsLongPath); #endif const char *sys_user_path(void); -const char *sys_exe_path(void); +const char *sys_exe_path_dir(void); +const char *sys_exe_path_file(void); const char *sys_file_extension(const char *fpath); const char *sys_file_name(const char *fpath); void sys_swap_backslashes(char* buffer); diff --git a/src/pc/rom_checker.cpp b/src/pc/rom_checker.cpp index 4785df5b2..f0f7ee68b 100644 --- a/src/pc/rom_checker.cpp +++ b/src/pc/rom_checker.cpp @@ -97,7 +97,7 @@ void legacy_folder_handler(void) { bool main_rom_handler(void) { if (scan_path_for_rom(fs_get_write_path(""))) { return true; } - scan_path_for_rom(sys_exe_path()); + scan_path_for_rom(sys_exe_path_dir()); return gRomIsValid; }