From 156d6f8bc8a3dd4dbdd89a3148ab3f82bf86faf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:49:16 +0200 Subject: [PATCH 1/7] Add provisions for portable mode to global dir functions --- src/86box.c | 2 ++ src/include/86box/86box.h | 19 +++++++++++------ src/qt/qt_platform.cpp | 45 ++++++++++++++++++++++++++++----------- src/unix/unix.c | 16 ++++++++------ 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/86box.c b/src/86box.c index 36638687a..baf0a32ea 100644 --- a/src/86box.c +++ b/src/86box.c @@ -228,6 +228,8 @@ int other_scsi_present = 0; /* SCSI contro present */ int is_pcjr = 0; /* The current machine is PCjr. */ +int portable_mode = 0; /* We are running in portable mode + (global dirs = exe path) */ // Accelerator key array struct accelKey acc_keys[NUM_ACCELS]; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 175b5b302..2906cf31f 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -42,6 +42,8 @@ #define GLOBAL_CONFIG_FILE "86box_global.cfg" #define NVR_PATH "nvr" #define SCREENSHOT_PATH "screenshots" +#define VMM_PATH "Virtual Machines" +#define VMM_PATH_WINDOWS "86Box VMs" /* Recently used images */ #define MAX_PREV_IMAGES 10 @@ -188,14 +190,17 @@ extern int hook_enabled; /* (C) Keyboard hook is enabled */ extern int vmm_disabled; /* (G) disable built-in manager */ extern char vmm_path_cfg[1024]; /* (G) VMs path (unless -E is used) */ -extern char exe_path[2048]; /* path (dir) of executable */ -extern char usr_path[1024]; /* path (dir) of user data */ -extern char cfg_path[1024]; /* full path of config file */ +extern char exe_path[2048]; /* path (dir) of executable */ +extern char usr_path[1024]; /* path (dir) of user data */ +extern char cfg_path[1024]; /* full path of config file */ extern char global_cfg_path[1024]; /* full path of global config file */ -extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ -extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ -extern char vmm_path[1024]; /* VM Manager path to scan */ -extern int start_vmm; +extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ +extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ +extern char vmm_path[1024]; /* VM Manager path to scan */ +extern int start_vmm; /* the current execution will start the manager */ +extern int portable_mode /* we are running in portable mode + (global dirs = exe path) */ + #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 0de5d840c..653926071 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -668,25 +668,37 @@ plat_chdir(char *path) void plat_get_global_config_dir(char *outbuf, const size_t len) { - const auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); - if (!dir.exists()) { - if (!dir.mkpath(".")) { - qWarning("Failed to create global configuration directory %s", dir.absolutePath().toUtf8().constData()); + if (portable_mode) { + strncpy(outbuf, exe_path, len); + } else { + const auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); + if (!dir.exists()) { + if (!dir.mkpath(".")) { + qWarning("Failed to create global configuration directory %s", dir.absolutePath().toUtf8().constData()); + } } + strncpy(outbuf, dir.canonicalPath().toUtf8().constData(), len); } - strncpy(outbuf, dir.canonicalPath().toUtf8().constData(), len); + + path_slash(outbuf); } void plat_get_global_data_dir(char *outbuf, const size_t len) { - const auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - if (!dir.exists()) { - if (!dir.mkpath(".")) { - qWarning("Failed to create global data directory %s", dir.absolutePath().toUtf8().constData()); + if (portable_mode) { + strncpy(outbuf, exe_path, len); + } else { + const auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + if (!dir.exists()) { + if (!dir.mkpath(".")) { + qWarning("Failed to create global data directory %s", dir.absolutePath().toUtf8().constData()); + } } + strncpy(outbuf, dir.canonicalPath().toUtf8().constData(), len); } - strncpy(outbuf, dir.canonicalPath().toUtf8().constData(), len); + + path_slash(outbuf); } void @@ -694,17 +706,26 @@ plat_get_temp_dir(char *outbuf, const uint8_t len) { const auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)); strncpy(outbuf, dir.canonicalPath().toUtf8().constData(), len); + path_slash(outbuf); } void plat_get_vmm_dir(char *outbuf, const size_t len) { + QString path; + + if (portable_mode) { + path = QDir(exe_path).filePath(VMM_PATH); + } else { #ifdef Q_OS_WINDOWS - const auto path = QDir::home().filePath("86Box VMs"); + path = QDir::home().filePath(VMM_PATH_WINDOWS); #else - const auto path = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("Virtual Machines"); + path = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath(VMM_PATH); #endif + } + strncpy(outbuf, path.toUtf8().constData(), len); + path_slash(outbuf); } void diff --git a/src/unix/unix.c b/src/unix/unix.c index bc9b9fedf..b4d6daa17 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -875,19 +875,21 @@ plat_init_rom_paths(void) void plat_get_global_config_dir(char *outbuf, const size_t len) { - char *prefPath = SDL_GetPrefPath(NULL, "86Box"); - strncpy(outbuf, prefPath, len); - path_slash(outbuf); - SDL_free(prefPath); + return plat_get_global_data_dir(outbuf, len); } void plat_get_global_data_dir(char *outbuf, const size_t len) { - char *prefPath = SDL_GetPrefPath(NULL, "86Box"); - strncpy(outbuf, prefPath, len); + if (portable_mode) { + strncpy(outbuf, exe_path, len); + } else { + char *prefPath = SDL_GetPrefPath(NULL, "86Box"); + strncpy(outbuf, prefPath, len); + SDL_free(prefPath); + } + path_slash(outbuf); - SDL_free(prefPath); } void From 2cc59ac721bc2c0495cc861c677cbfe8fd32d0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:51:09 +0200 Subject: [PATCH 2/7] Fix build --- src/include/86box/86box.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 2906cf31f..521e50965 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -198,7 +198,7 @@ extern int open_dir_usr_path; /* default file open dialog directory of usr_ extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ extern char vmm_path[1024]; /* VM Manager path to scan */ extern int start_vmm; /* the current execution will start the manager */ -extern int portable_mode /* we are running in portable mode +extern int portable_mode; /* we are running in portable mode (global dirs = exe path) */ #ifndef USE_NEW_DYNAREC From e042d5212ac74066b9a0d46b43aafa49fc50a89d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 21:01:32 +0200 Subject: [PATCH 3/7] Implement logic for enabling portable mode --- src/86box.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/86box.c b/src/86box.c index baf0a32ea..a0fe983c4 100644 --- a/src/86box.c +++ b/src/86box.c @@ -757,6 +757,22 @@ pc_init(int argc, char *argv[]) path_slash(exe_path); + /* + * Determine if we are running in portable mode. + * + * We enable portable mode if the EXE path + * contains the global config file. + */ + path_append_filename(global, exe_path, GLOBAL_CONFIG_FILE); + + FILE *fp = fopen(global, "r"); + if (fp) { + portable_mode = 1; + fclose(fp); + } + + global = NULL; + /* * Get the current working directory. * From 15c1a7e04aae38da36091881597f6965c11d1ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 21:36:12 +0200 Subject: [PATCH 4/7] Use an actual buffer for portable mode detection lol --- src/86box.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/86box.c b/src/86box.c index a0fe983c4..5570b5269 100644 --- a/src/86box.c +++ b/src/86box.c @@ -763,16 +763,14 @@ pc_init(int argc, char *argv[]) * We enable portable mode if the EXE path * contains the global config file. */ - path_append_filename(global, exe_path, GLOBAL_CONFIG_FILE); + path_append_filename(temp, exe_path, GLOBAL_CONFIG_FILE); - FILE *fp = fopen(global, "r"); + FILE *fp = fopen(temp, "r"); if (fp) { portable_mode = 1; fclose(fp); } - global = NULL; - /* * Get the current working directory. * From f153ad5877c1f8a4e89549484cdab5f9fe905164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 21:36:35 +0200 Subject: [PATCH 5/7] Add log message when running in portable mode --- src/86box.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/86box.c b/src/86box.c index 5570b5269..a5344f7e9 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1112,6 +1112,10 @@ usage: pclog("#\n# %ls v%ls logfile, created %s\n#\n", EMU_NAME_W, EMU_VERSION_FULL_W, temp); + if (portable_mode) { + pclog("# Portable mode enabled.\n"); + } + pclog("# Emulator path: %s\n", exe_path); pclog("# Global configuration file: %s\n", global_cfg_path); From 89d1a2406b8e814b003d66387f6faddc38bae992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 21:37:17 +0200 Subject: [PATCH 6/7] Normalize EXE path before ensuring a slash Fixes exe_path ending up with two slashes at the end on Windows --- src/86box.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/86box.c b/src/86box.c index a5344f7e9..498c86871 100644 --- a/src/86box.c +++ b/src/86box.c @@ -755,6 +755,7 @@ pc_init(int argc, char *argv[]) path_get_dirname(exe_path, p); #endif + path_normalize(exe_path); path_slash(exe_path); /* From e3fe30cac51a5b16915bc027812723adbe80efe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 24 Aug 2025 23:15:44 +0200 Subject: [PATCH 7/7] Save VMM path relative to the EXE path --- src/config.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/config.c b/src/config.c index 345e2a483..e88a4753e 100644 --- a/src/config.c +++ b/src/config.c @@ -140,10 +140,17 @@ load_global(void) vmm_disabled = ini_section_get_int(cat, "vmm_disabled", 0); p = ini_section_get_string(cat, "vmm_path", NULL); - if (p != NULL) - strncpy(vmm_path_cfg, p, sizeof(vmm_path_cfg) - 1); - else + if (p != NULL) { + /* Convert relative paths to absolute in portable mode */ + if (portable_mode && !path_abs(p)) { + path_append_filename(vmm_path_cfg, exe_path, p); + path_normalize(vmm_path_cfg); + } else { + strncpy(vmm_path_cfg, p, sizeof(vmm_path_cfg) - 1); + } + } else { plat_get_vmm_dir(vmm_path_cfg, sizeof(vmm_path_cfg)); + } } /* Load "General" section. */ @@ -1620,7 +1627,7 @@ load_other_removable_devices(void) sprintf(temp, "zip_%02i_image_path", c + 1); p = ini_section_get_string(cat, temp, ""); - + sprintf(temp, "zip_%02i_writeprot", c + 1); rdisk_drives[c].read_only = ini_section_get_int(cat, temp, 0); ini_section_delete_var(cat, temp); @@ -1724,7 +1731,7 @@ load_other_removable_devices(void) sprintf(temp, "rdisk_%02i_image_path", c + 1); p = ini_section_get_string(cat, temp, ""); - + sprintf(temp, "rdisk_%02i_writeprot", c + 1); rdisk_drives[c].read_only = ini_section_get_int(cat, temp, 0); ini_section_delete_var(cat, temp); @@ -2213,10 +2220,16 @@ save_global(void) else ini_section_delete_var(cat, "vmm_disabled"); - if (vmm_path_cfg[0] != 0) - ini_section_set_string(cat, "vmm_path", vmm_path_cfg); - else + if (vmm_path_cfg[0] != 0) { + /* Save path as relative to the EXE path in portable mode */ + if (portable_mode && path_abs(vmm_path_cfg) && !strnicmp(vmm_path_cfg, exe_path, strlen(exe_path))) { + ini_section_set_string(cat, "vmm_path", &vmm_path_cfg[strlen(exe_path)]); + } else { + ini_section_set_string(cat, "vmm_path", vmm_path_cfg); + } + } else { ini_section_delete_var(cat, "vmm_path"); + } } /* Save "General" section. */