From 4b09a6329aa8b5cb9392c5bab7a97e152b7d9fef Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 5 Apr 2022 02:16:23 +0600 Subject: [PATCH] Multiple ROM paths implementation --- src/86box.c | 129 +++++++++++++++++++++++++++++++++++----- src/include/86box/rom.h | 7 +++ src/mem/rom.c | 12 +++- 3 files changed, 132 insertions(+), 16 deletions(-) diff --git a/src/86box.c b/src/86box.c index db0182d84..a645d88d6 100644 --- a/src/86box.c +++ b/src/86box.c @@ -32,6 +32,7 @@ #ifndef _WIN32 #include +#include #endif #ifdef __APPLE__ #include @@ -125,6 +126,7 @@ uint64_t unique_id = 0; uint64_t source_hwnd = 0; #endif char rom_path[1024] = { '\0'}; /* (O) full path to ROMs */ +rom_path_t rom_paths = { "", NULL }; /* (O) full paths to ROMs */ char log_path[1024] = { '\0'}; /* (O) full path of logfile */ char vm_name[1024] = { '\0'}; /* (O) display name of the VM */ @@ -383,6 +385,48 @@ pc_log(const char *fmt, ...) #define pc_log(fmt, ...) #endif +static void +add_rom_path(const char* path) +{ + static char cwd[1024]; + memset(cwd, 0x00, sizeof(cwd)); + rom_path_t* cur_rom_path = &rom_paths; + while (cur_rom_path->next != NULL) { + cur_rom_path = cur_rom_path->next; + } + if (!plat_path_abs((char*)path)) { + /* + * This looks like a relative path. + * + * Add it to the current working directory + * to convert it (back) to an absolute path. + */ + plat_getcwd(cwd, 1024); + plat_path_slash(cwd); + snprintf(cur_rom_path->rom_path, 1024, "%s%s%c", cwd, path, 0); + } + else { + /* + * The user-provided path seems like an + * absolute path, so just use that. + */ + strncpy(cur_rom_path->rom_path, path, 1024); + } + plat_path_slash(cur_rom_path->rom_path); + cur_rom_path->next = calloc(1, sizeof(rom_path_t)); +} + +// Copied over from Unix code, which in turn is lifted from musl. Needed for parsing XDG_DATA_DIRS. +static char *local_strsep(char **str, const char *sep) +{ + char *s = *str, *end; + if (!s) return NULL; + end = s + strcspn(s, sep); + if (*end) *end++ = 0; + else end = 0; + *str = end; + return s; +} /* * Perform initial startup of the PC. @@ -496,6 +540,7 @@ usage: if ((c+1) == argc) goto usage; strcpy(path2, argv[++c]); + add_rom_path(path2); } else if (!strcasecmp(argv[c], "--config") || !strcasecmp(argv[c], "-C")) { if ((c+1) == argc) goto usage; @@ -591,26 +636,77 @@ usage: plat_dir_create(usr_path); } - if (path2[0] == '\0') { + if (vmrp) { + char vmrppath[1024] = { 0 }; + strcpy(vmrppath, usr_path); + plat_path_slash(vmrppath); + strcat(vmrppath, "roms"); + plat_path_slash(vmrppath); + add_rom_path(vmrppath); + if (path2[0] == '\0') { + strcpy(path2, vmrppath); + } + } + + { + char default_rom_path[1024] = { 0 }; #if defined(__APPLE__) - getDefaultROMPath(path2); + getDefaultROMPath(default_rom_path); #elif !defined(_WIN32) appimage = getenv("APPIMAGE"); if (appimage && (appimage[0] != '\0')) { - plat_get_dirname(path2, appimage); - plat_path_slash(path2); - strcat(path2, "roms"); - plat_path_slash(path2); + plat_get_dirname(default_rom_path, appimage); + plat_path_slash(default_rom_path); + strcat(default_rom_path, "roms"); + plat_path_slash(default_rom_path); } #endif + if (default_rom_path[0] == '\0') { + plat_getcwd(default_rom_path, 1024); + plat_path_slash(default_rom_path); + snprintf(default_rom_path, 1024, "%s%s%c", default_rom_path, "roms", 0); + plat_path_slash(default_rom_path); + } + add_rom_path(default_rom_path); + if (path2[0] == '\0') { + strcpy(path2, default_rom_path); + } } - if (vmrp && (path2[0] == '\0')) { - strcpy(path2, usr_path); - plat_path_slash(path2); - strcat(path2, "roms"); - plat_path_slash(path2); - } +#if !defined __APPLE__ && !defined _WIN32 + if (getenv("XDG_DATA_HOME")) { + char xdg_rom_path[1024] = { 0 }; + strncpy(xdg_rom_path, getenv("XDG_DATA_HOME"), 1024); + plat_path_slash(xdg_rom_path); + strcat(xdg_rom_path, "86Box/roms/"); + add_rom_path(xdg_rom_path); + } else { + char home_rom_path[1024] = { 0 }; + snprintf(home_rom_path, 1024, "%s/.local/share/86Box/roms/", getenv("HOME") ? getenv("HOME") : getpwuid(getuid())->pw_dir); + add_rom_path(home_rom_path); + } + if (getenv("XDG_DATA_DIRS")) { + char* xdg_rom_paths = strdup(getenv("XDG_DATA_DIRS")); + char* xdg_rom_paths_orig = xdg_rom_paths; + char* cur_xdg_rom_path = NULL; + if (xdg_rom_paths) { + while (xdg_rom_paths[strlen(xdg_rom_paths) - 1] == ':') { + xdg_rom_paths[strlen(xdg_rom_paths) - 1] = '\0'; + } + while ((cur_xdg_rom_path = local_strsep(&xdg_rom_paths, ";")) != NULL) { + char real_xdg_rom_path[1024] = { '\0' }; + strcat(real_xdg_rom_path, cur_xdg_rom_path); + plat_path_slash(real_xdg_rom_path); + strcat(real_xdg_rom_path, "86Box/roms/"); + add_rom_path(real_xdg_rom_path); + } + } + free(xdg_rom_paths_orig); + } else { + add_rom_path("/usr/local/share/86Box/roms/"); + add_rom_path("/usr/share/86Box/roms/"); + } +#endif /* * If the user provided a path for ROMs, use that @@ -708,8 +804,13 @@ usage: pclog("# VM: %s\n#\n", vm_name); pclog("# Emulator path: %s\n", exe_path); pclog("# Userfiles path: %s\n", usr_path); - if (rom_path[0] != '\0') - pclog("# ROM path: %s\n", rom_path); + if (rom_paths.next) { + rom_path_t* cur_rom_path = &rom_paths; + while (cur_rom_path->next) { + pclog("# ROM path: %s\n", cur_rom_path->rom_path); + cur_rom_path = cur_rom_path->next; + } + } else #ifndef _WIN32 pclog("# ROM path: %sroms/\n", exe_path); diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index dfea9f0b5..63500d912 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -41,6 +41,13 @@ typedef struct { } rom_t; +typedef struct rom_path_t { + char rom_path[1024]; + struct rom_path_t* next; +} rom_path_t; + +extern rom_path_t rom_paths; + extern uint8_t rom_read(uint32_t addr, void *p); extern uint16_t rom_readw(uint32_t addr, void *p); extern uint32_t rom_readl(uint32_t addr, void *p); diff --git a/src/mem/rom.c b/src/mem/rom.c index 30e873a4e..907c090ee 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -69,11 +69,19 @@ rom_fopen(char *fn, char *mode) fn2 = (char *) malloc(strlen(fn) + 1); memcpy(fn2, fn, strlen(fn) + 1); - if (rom_path[0] != '\0') { + if (rom_paths.next) { + rom_path_t* cur_rom_path = &rom_paths; memset(fn2, 0x00, strlen(fn) + 1); memcpy(fn2, &(fn[5]), strlen(fn) - 4); - plat_append_filename(temp, rom_path, fn2); + while (cur_rom_path->next) { + memset(temp, 0, sizeof(temp)); + plat_append_filename(temp, cur_rom_path->rom_path, fn2); + if (rom_present(temp)) { + break; + } + cur_rom_path = cur_rom_path->next; + } } else { /* Make sure to make it a backslash, just in case there's malformed code calling us that assumes Windows. */