From patchwork Thu Sep 26 03:09:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Cournoyer X-Patchwork-Id: 31466 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id C255627BBEA; Thu, 26 Sep 2024 04:18:24 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-6.6 required=5.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,MAILING_LIST_MULTI, RCVD_IN_VALIDITY_CERTIFIED,RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE, SPF_HELO_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id B5AAA27BBE2 for ; Thu, 26 Sep 2024 04:18:23 +0100 (BST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1stf0d-00047p-Ft; Wed, 25 Sep 2024 23:17:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1stf0b-00046h-8D for guix-patches@gnu.org; Wed, 25 Sep 2024 23:17:37 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1stf0a-00080h-V9 for guix-patches@gnu.org; Wed, 25 Sep 2024 23:17:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:References:In-Reply-To:Date:From:To:Subject; bh=RHqZ9HrRDSt2Z64DKAPNwvkMSMWOZswUfB6hIKzvUMY=; b=T6jC8wPDE2H8Xm/E6pQx4fQfWC198wB8BzhwGVs0gEC5Z2TTOc0tT13+5l9GA95WoqSjWny4dA7UbfuGFBZu01U7+qWA+sjVbz2pqjox6Jqj4OIf/nrMEn0t43rL7saWfuIIk8syTRe3yhrfljWX1O2XnG6UI7fA3z9goQ1Cb8W4P6pg7fi7q6eyECxJoXPv8YlMMmLiTREIQAHc2zY9VV5C56Dl6RBLxd8uTIPp5HGlJ1hfzyBxKjXyXzU+RoGvyVx66OpoXHSP5X0FQ3eYUGsp7nMljfNMpuzPOuoQHGVkvLLgoohm0VzsRbbJSOvRYjtnINPVsg58ZJbN2w/CmQ==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1stf11-0001I2-G5 for guix-patches@gnu.org; Wed, 25 Sep 2024 23:18:03 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#73488] [PATCH 4/7] gnu: jgrf: Add search path mechanism. Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Thu, 26 Sep 2024 03:18:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 73488 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 73488@debbugs.gnu.org Cc: Maxim Cournoyer Received: via spool by 73488-submit@debbugs.gnu.org id=B73488.17273206344832 (code B ref 73488); Thu, 26 Sep 2024 03:18:03 +0000 Received: (at 73488) by debbugs.gnu.org; 26 Sep 2024 03:17:14 +0000 Received: from localhost ([127.0.0.1]:41858 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1stf0D-0001Fm-Jp for submit@debbugs.gnu.org; Wed, 25 Sep 2024 23:17:14 -0400 Received: from mail-pl1-f181.google.com ([209.85.214.181]:44346) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1stf0A-0001En-F0 for 73488@debbugs.gnu.org; Wed, 25 Sep 2024 23:17:11 -0400 Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-206e614953aso5355925ad.1 for <73488@debbugs.gnu.org>; Wed, 25 Sep 2024 20:16:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1727320538; x=1727925338; darn=debbugs.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RHqZ9HrRDSt2Z64DKAPNwvkMSMWOZswUfB6hIKzvUMY=; b=Bph/NEtar3f5dF/k/XAZPxgDglwfmVUi8qEo067T9yfO2LCa7AlEazJpbkLvaQoIPG I549j/JW2J6/59lykBwVt8/lbFse+UbuoPJQYaMKegneTuL8reNFXvUJGtZ1pyC1CQtr iK3ytyssih6/hrShVB5l5qY9yljjpa+0+uJVN1EluEDVhCeEBRsmCVoV9vsqanvtgfI2 9E80y8yV+48iwP+KzzxoEn2jBgxrBWEtyQePOELYL5hgmIw92yiLiARM4r+bZ3cUHxKg ycd8ccuQMZ1mSAXqBqq25ZoC1CNkhvChMFz8Rv+T7vUl1mD3o6Tq02qShLR0y/uKVmI0 JCqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727320538; x=1727925338; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RHqZ9HrRDSt2Z64DKAPNwvkMSMWOZswUfB6hIKzvUMY=; b=mM0uZa5gFT2MZzjJIm2gTBJgIzncfmz/1yE8REqMGkGIpBD7bCJGf3WZ0wJM/ba5AB O71RM5eHEihqGzdqly8PtDfMIr9U60R+H2SLxMSj5MBlQ0uUCZoB4v6HGZBLCxdXLjpp Jcjh5xK/EZcIXyquXmNOoGJqPLZ6Gj3F65o8N6L0d+dlMlZ5cEyv2o5TIRFEPWLxrZ8i 6a8VbiL/2KqcZA3mmgFH4LSKnHmODXp7BGLe9LomaQESY7YuWJ0b/2F4ZXN4udHXMnbe hqqDTszNzgERfmBSxF0wp6c3nLrCh0n85aMnJ6QFwzQR7+889I+eqYuvG2VBJ7YR6TJX anrA== X-Gm-Message-State: AOJu0YzqsvGGQOxRcrJVSpaw9ZLPi8nElW4c5ajExUrv2nMXmVTF3WeX yb+oIBDs+c+9kOheCJe3vDFktKkiGCIBso1ePPR30ogDemHMGqZgCV3Wug== X-Google-Smtp-Source: AGHT+IE2I4/EdM33S70g8syeUS4x9+5EIUc5AHYjL7REZG0Lf/CZO4BMiNWYozTczeSrWGFRvn/stg== X-Received: by 2002:a17:903:234f:b0:206:90ac:4412 with SMTP id d9443c01a7336-20afc45fa82mr53350755ad.2.1727320537364; Wed, 25 Sep 2024 20:15:37 -0700 (PDT) Received: from hurd.lan ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-20af17e0301sm29895875ad.156.2024.09.25.20.15.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 25 Sep 2024 20:15:36 -0700 (PDT) From: Maxim Cournoyer Date: Thu, 26 Sep 2024 12:09:58 +0900 Message-ID: <5376e48139307a045a3482aa4d4508e8f368f6e3.1727320201.git.maxim.cournoyer@gmail.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches 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