Package: guix-patches;
Reported by: Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Date: Thu, 26 Sep 2024 03:03:01 UTC
Severity: normal
Tags: patch
Done: Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Maxim Cournoyer <maxim.cournoyer <at> gmail.com> To: 73488 <at> debbugs.gnu.org Cc: Maxim Cournoyer <maxim.cournoyer <at> gmail.com> Subject: [bug#73488] [PATCH 4/7] gnu: jgrf: Add search path mechanism. Date: Thu, 26 Sep 2024 12:09:58 +0900
This makes it possible to automatically find core files in a profile. * gnu/packages/patches/jgrf-implement-search-paths.patch: New file. * gnu/local.mk (dist_patch_DATA): Register it. * gnu/packages/emulators.scm (jgrf) [source]: Apply patch. [native-search-paths]: New field. Change-Id: Ibd78d44dcdf23f4310b2f838d73b8e57d7f31b2a --- gnu/local.mk | 1 + gnu/packages/emulators.scm | 10 +- .../patches/jgrf-implement-search-paths.patch | 302 ++++++++++++++++++ 3 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 gnu/packages/patches/jgrf-implement-search-paths.patch diff --git a/gnu/local.mk b/gnu/local.mk index 507cbfebca..1e85ab5352 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1589,6 +1589,7 @@ dist_patch_DATA = \ %D%/packages/patches/jfsutils-add-sysmacros.patch \ %D%/packages/patches/jfsutils-gcc-compat.patch \ %D%/packages/patches/jfsutils-include-systypes.patch \ + %D%/packages/patches/jgrf-implement-search-paths.patch \ %D%/packages/patches/john-the-ripper-jumbo-with-gcc-11.patch \ %D%/packages/patches/json-c-0.13-CVE-2020-12762.patch \ %D%/packages/patches/json-c-0.12-CVE-2020-12762.patch \ diff --git a/gnu/packages/emulators.scm b/gnu/packages/emulators.scm index 6a5ff6cc19..49208f302d 100644 --- a/gnu/packages/emulators.scm +++ b/gnu/packages/emulators.scm @@ -2308,7 +2308,8 @@ (define-public jgrf (delete-file-recursively "deps/miniz"))) (sha256 (base32 - "19n6h8l3vy5g2bqvxhxwqxlg070hjz22384yisadzwl3gjkkgpxk")))) + "19n6h8l3vy5g2bqvxhxwqxlg070hjz22384yisadzwl3gjkkgpxk")) + (patches (search-patches "jgrf-implement-search-paths.patch")))) (build-system gnu-build-system) (arguments (list #:tests? #f ;no test suite @@ -2331,6 +2332,13 @@ (define-public jgrf sdl2 zlib `(,zstd "lib"))) + (native-search-paths + (list (search-path-specification + (variable "JOLLYGOOD_CORE_DIRS") + (files '("lib/jollygood"))) + (search-path-specification + (variable "JOLLYGOOD_ASSETS_DIRS") + (files '("share/jollygood"))))) (home-page "https://gitlab.com/jgemu/jgrf") (synopsis "Jolly Good Reference Frontend") (description "The Jolly Good Reference Frontend (accessible via the diff --git a/gnu/packages/patches/jgrf-implement-search-paths.patch b/gnu/packages/patches/jgrf-implement-search-paths.patch new file mode 100644 index 0000000000..f4c6f20568 --- /dev/null +++ b/gnu/packages/patches/jgrf-implement-search-paths.patch @@ -0,0 +1,302 @@ +Upstream status: https://gitlab.com/jgemu/jgrf/-/merge_requests/61 + +Add support for searching core files and core files assets via the +JOLLYGOOD_CORE_DIRS and JOLLYGOOD_ASSETS_DIRS environment variables. + +diff --git a/Makefile b/Makefile +index ed6eb1c..fb0709c 100644 +--- a/Makefile ++++ b/Makefile +@@ -20,7 +20,9 @@ INCLUDES = -I$(DEPDIR) $(CFLAGS_JG) $(CFLAGS_EPOXY) $(CFLAGS_MINIZ) \ + + LIBS = -lm + +-DEFINES := ++# Define the '_GNU_SOURCE' macro to make the `strdup' function ++# available on GNU systems. ++DEFINES := -D_GNU_SOURCE + + # Conditions for DEFINES + ifneq ($(OS), Windows_NT) +diff --git a/deps/ezmenu.h b/deps/ezmenu.h +index 8400a02..6c8e14b 100644 +--- a/deps/ezmenu.h ++++ b/deps/ezmenu.h +@@ -66,10 +66,10 @@ enum ezmenu_input { + + static void ezmenu_init(struct ezmenu *m, int hres, int vres, + int fontw, int fonth) { +- memset(m, 0, sizeof *m); ++ memset(m, 0, sizeof(*m)); + m->w = hres/fontw; + m->h = vres/fonth; +- m->vislines = calloc(sizeof(char*), m->h); ++ m->vislines = calloc(m->h, sizeof(char*)); + } + + static void ezmenu_setlines(struct ezmenu *m, char**lines, unsigned linecount) { +diff --git a/jollygood.6 b/jollygood.6 +index 9f36407..17fef9c 100644 +--- a/jollygood.6 ++++ b/jollygood.6 +@@ -336,6 +336,14 @@ The directory for user-specific data files. + This path is used to find data files used by the cores. + Set by default to + .Pa $HOME/.local/share/jollygood/ . ++.It JOLLYGOOD_CORE_DIRS ++Colon-separated (or semicolon, on Windows) directories containing core ++files. If set, these core files directories take precedence over the ++default ones. ++.It JOLLYGOOD_ASSETS_DIRS ++Colon-separated (or semicolon, on Windows) directories containing core ++assets files. If set, these core assets directories take precedence ++over the default ones. + .El + .Sh EXAMPLES + .Bl -tag -width indent +diff --git a/src/jgrf.c b/src/jgrf.c +index 3a40d2d..12eede3 100644 +--- a/src/jgrf.c ++++ b/src/jgrf.c +@@ -161,6 +161,12 @@ static void mkdirr(const char *dir) { + #endif + } + ++#if defined(__MINGW32__) || defined(__MINGW64__) ++// Avoid a deprecation warning on Windows, where strdup exists but is ++// deprecated in favor of _strdup. ++#define strdup _strdup ++#endif ++ + // Create user directories + static void jgrf_mkdirs(void) { + mkdirr(gdata.configpath); +@@ -1096,6 +1102,88 @@ void jgrf_frametime(double frametime) { + corefps = frametime + 0.5; + } + ++// Wrapper that logs and errors in case of realloc problems. ++static void* jgrf_realloc(void* array, const size_t size) { ++ void* new_array; ++ if (size > 0 && !(new_array = realloc(array, size))) ++ jgrf_log(JG_LOG_ERR, "Realloc failure\n"); ++ return new_array; ++} ++ ++static void jgrf_strip_trailing_sep(char* word) { ++ int end = strlen(word) - 1; ++ while (word[end] == SEP) { ++ word[end] = '\0'; ++ end -= 1; ++ } ++} ++ ++// Tokenize PATH based on the platform path separator and return an ++// array of strings, or NULL if there nothing could be tokenized. The ++// count of the number of items is written at the location pointed by ++// the COUNT pointer. The returned array is dynamically allocated and ++// should be freed when no longer needed, along its inner strings. ++// `transform' can be provided to manipulate the recovered path items; ++// it must be the pointer of a procedure accepting a single string ++// (char*) path item as argument or NULL. ++static char** tokenize_path(int* count, const char* path, ++ void (*transform) (char*)) { ++ int length = 10; ++ int index = 0; ++ char* save_ptr; ++ char** items = jgrf_realloc(NULL, sizeof(char*) * length); ++ char* item; ++ char pathsep_str[2] = {PATHSEP, '\0'}; ++ char* wr_path = strdup(path); ++ if (!wr_path) ++ jgrf_log(JG_LOG_ERR, "strdup memory allocation failure\n"); ++ ++ item = strtok_r(wr_path, pathsep_str, &save_ptr); ++ while (item) { ++ if (transform) ++ transform(item); ++ ++ // Resize the array if needed. ++ if (index >= length) { ++ length += 10; ++ items = jgrf_realloc(items, sizeof(char*) * length); ++ } ++ ++ // Assign the component. ++ items[index] = strdup(item); ++ if (!items[index]) ++ jgrf_log(JG_LOG_ERR, "stdup memory allocation failure\n"); ++ ++ index += 1; ++ item = strtok_r(NULL, pathsep_str, &save_ptr); ++ } ++ free(wr_path); ++ jgrf_realloc(items, sizeof(char*) * index); ++ ++ *count = index; ++ return items; ++} ++ ++// Look if a core named NAME exists under the directory CORE_DIR. Set ++// CORE_FILE as a side-effect. Return 1 if found, 0 otherwise. ++static int search_core_file(char* core_file, size_t max_length, ++ const char* core_dir, const char* name) { ++ struct stat fbuf; ++ snprintf(core_file, max_length, "%s%c%s.%s", ++ core_dir, SEP, name, SOEXT); ++ return !stat(core_file, &fbuf); ++} ++ ++// Look if an core assets directory for core named NAME exists under ++// the directory ASSETS_DIR. Set CORE_ASSETS as a side-effect. Return ++// 1 if found, 0 otherwise. ++static int search_core_assets(char* core_assets, size_t max_length, ++ const char* assets_dir, const char* name) { ++ struct stat fbuf; ++ snprintf(core_assets, max_length, "%s%c%s", assets_dir, SEP, name); ++ return !stat(core_assets, &fbuf); ++} ++ + int main(int argc, char *argv[]) { + if (argc < 2) { + jgrf_cli_usage(argv[0]); +@@ -1188,7 +1276,7 @@ int main(int argc, char *argv[]) { + jg_get_coreinfo("")->name); + + #if defined(LIBDIR) && defined(DATADIR) // Check for core assets system-wide +- char coreassets[256]; ++ char coreassets[384]; + snprintf(coreassets, sizeof(coreassets), + "%s%cjollygood%c%s", DATADIR, SEP, SEP, gdata.corename); + +@@ -1204,7 +1292,7 @@ int main(int argc, char *argv[]) { + } + else if (!jgrf_core_default()) + jgrf_log(JG_LOG_ERR, +- "Cannot detect default core, or invalid file. Exiting...\n"); ++ "Cannot detect default core, or invalid file. Exiting...\n"); + + // Set the core path to the local core path + char corepath[384]; +@@ -1222,20 +1310,85 @@ int main(int argc, char *argv[]) { + } + #if defined(LIBDIR) && defined(DATADIR) // Check for the core system-wide + else { +- snprintf(corepath, sizeof(corepath), "%s%cjollygood%c%s.%s", +- LIBDIR, SEP, SEP, gdata.corename, SOEXT); +- +- // If it was found, set the core assets path +- if (stat(corepath, &fbuf) == 0) { +- snprintf(gdata.coreassets, sizeof(gdata.coreassets), +- "%s%cjollygood%c%s", DATADIR, SEP, SEP, gdata.corename); +- corefound = 1; ++ int core_assets_found = 0; ++ int count = 0; ++ ++ // Look for the core file in the JOLLYGOOD_CORE_DIRS search ++ // path. ++ const char* core_dirs_env = getenv("JOLLYGOOD_CORE_DIRS"); ++ if (core_dirs_env) { ++ char** core_dirs = tokenize_path(&count, core_dirs_env, ++ jgrf_strip_trailing_sep); ++ for (int i=0; i < count; ++i) { ++ const char* dir = core_dirs[i]; ++ if (search_core_file(corepath, sizeof corepath, ++ dir, gdata.corename)) { ++ corefound = 1; ++ break; ++ } ++ } ++ // Free all the allocated strings. ++ for (int i=0; i < count; ++i) ++ free(core_dirs[i]); ++ free(core_dirs); ++ } ++ ++ // Look in the configured LIBDIR as a fallback. ++ if (!corefound) { ++ char internal_core_dir[256]; ++ snprintf(internal_core_dir, sizeof internal_core_dir, "%s%c%s", ++ LIBDIR, SEP, "jollygood"); ++ if (search_core_file(corepath, sizeof corepath, ++ internal_core_dir, gdata.corename)) { ++ corefound = 1; ++ } else { ++ jgrf_log(JG_LOG_ERR, ++ "Could not locate core file. Exiting...\n"); ++ } + } +- } + +- // If no core was found, there is no reason to keep the program running +- if (!corefound) +- jgrf_log(JG_LOG_ERR, "Failed to locate core. Exiting...\n"); ++ // If it was found, set the core assets path. First consider ++ // the JOLLYGOOD_ASSETS_DIRS search path. ++ if (corefound) { ++ const char* assets_dirs_env = getenv("JOLLYGOOD_ASSETS_DIRS"); ++ if (assets_dirs_env) { ++ char** assets_dirs = tokenize_path(&count, assets_dirs_env, ++ jgrf_strip_trailing_sep); ++ for (int i=0; i < count; ++i) { ++ const char* dir = assets_dirs[i]; ++ if (search_core_assets(gdata.coreassets, ++ sizeof gdata.coreassets, ++ dir, gdata.corename)) { ++ core_assets_found = 1; ++ break; ++ } ++ } ++ for (int i=0; i < count; ++i) ++ free(assets_dirs[i]); ++ free(assets_dirs); ++ } ++ ++ // Look in the configured DATADIR as a fallback. ++ if (!core_assets_found) { ++ char internal_core_assets_dir[256]; ++ snprintf(internal_core_assets_dir, ++ sizeof internal_core_assets_dir, ++ "%s%c%s", DATADIR, SEP, "jollygood"); ++ if (search_core_assets(gdata.coreassets, ++ sizeof gdata.coreassets, ++ internal_core_assets_dir, ++ gdata.corename)) { ++ core_assets_found = 1; ++ } else { ++ // Not all emulators have core assets, ++ // e.g. 'cega', so this is not a critical ++ // condition. ++ jgrf_log(JG_LOG_INF, "No assets directory for core %s\n", ++ gdata.corename); ++ } ++ } ++ } ++ } + #endif // defined(LIBDIR) && defined(DATADIR) + + #endif // JGRF_STATIC +diff --git a/src/jgrf.h b/src/jgrf.h +index b3f4627..57bba0e 100644 +--- a/src/jgrf.h ++++ b/src/jgrf.h +@@ -45,8 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) + #define SEP '\\' ++ #define PATHSEP ';' + #else + #define SEP '/' ++ #define PATHSEP ':' + #endif + + typedef struct jgrf_gdata_t { // Global Data +@@ -59,7 +61,7 @@ typedef struct jgrf_gdata_t { // Global Data + char coreversion[32]; // Core Version + char gamename[128]; // Internally used game name + char gamefname[128]; // Internally used game name with extension +- char coreassets[256]; // Core asset path ++ char coreassets[384]; // Core asset path + char userassets[128]; // User asset path + char biospath[128]; // BIOS path + char cheatpath[128]; // Cheat path -- 2.46.0
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.