From fea632b0e9f8bed21a2985b3879b9f590f918b2c Mon Sep 17 00:00:00 2001 From: Themaister Date: Mon, 6 Feb 2012 15:51:35 +0100 Subject: [PATCH] Add environment variable system extension. --- dynamic.c | 31 +++++++++++++++++++++++++++++++ general.h | 3 +++ libsnes.hpp | 15 +++++++++++++++ settings.c | 12 ++++++++++++ ssnes.c | 6 ++++++ ssnes.cfg | 11 ++++++++++- 6 files changed, 77 insertions(+), 1 deletion(-) diff --git a/dynamic.c b/dynamic.c index a6190943c8..d8a6cb1464 100644 --- a/dynamic.c +++ b/dynamic.c @@ -335,6 +335,33 @@ static bool environment_cb(unsigned cmd, void *data) SSNES_LOG("Environ GET_CAN_REWIND: %s\n", g_settings.rewind_enable ? "true" : "false"); break; + case SNES_ENVIRONMENT_GET_VARIABLE: + { + struct snes_variable *var = data; + if (var->key) + { + // Split string has '\0' delimiters so we have to find the position in original string, + // then pass the corresponding offset into the split string. + const char *key = strstr(g_extern.system.environment, var->key); + size_t key_len = strlen(var->key); + if (key && key[key_len] == '=') + { + ptrdiff_t offset = key - g_extern.system.environment; + var->value = &g_extern.system.environment_split[offset + key_len + 1]; + } + else + var->value = NULL; + } + else + var->value = g_extern.system.environment; + + SSNES_LOG("Environ GET_VARIABLE: %s=%s\n", + var->key ? var->key : "null", + var->value ? var->value : "null"); + + break; + } + default: SSNES_LOG("Environ UNSUPPORTED (#%u)!\n", cmd); return false; @@ -377,5 +404,9 @@ static void set_environment_defaults(void) g_extern.system.geom.base_height = 224; g_extern.system.geom.max_width = 512; g_extern.system.geom.max_height = 512; + + // Split up environment variables beforehand. + if (g_extern.system.environment_split && strtok(g_extern.system.environment_split, ";")) + while (strtok(NULL, ";")); } diff --git a/general.h b/general.h index 5561ca652f..3439111da8 100644 --- a/general.h +++ b/general.h @@ -264,6 +264,9 @@ struct global struct snes_system_timing timing; bool timing_set; bool need_fullpath; + + char *environment; + char *environment_split; } system; struct diff --git a/libsnes.hpp b/libsnes.hpp index 77160f76a1..3f36045009 100755 --- a/libsnes.hpp +++ b/libsnes.hpp @@ -100,6 +100,21 @@ extern "C" { // Some implementations might need to take extra precautions // to allow this as smoothly as possible. +#define SNES_ENVIRONMENT_GET_VARIABLE 8 // struct snes_variable * -- + // Interface to aquire user-defined information from environment + // that cannot feasibly be supported in a multi-system way. + // Mostly used for obscure, + // specific features that the user can tap into when neseccary. + +struct snes_variable +{ + const char *key; // Variable to query in SNES_ENVIRONMENT_GET_VARIABLE. + // If NULL, obtains the complete environment string if more complex parsing is necessary. + // The environment string is formatted as key-value pairs delimited by semicolons as so: + // "key1=value1;key2=value2;..." + const char *value; // Value to be obtained. If key does not exist, it is set to NULL. +}; + struct snes_geometry { unsigned base_width; // Nominal video width of system. diff --git a/settings.c b/settings.c index 8dc22daab1..08cc72f1c1 100644 --- a/settings.c +++ b/settings.c @@ -466,6 +466,18 @@ bool config_load_file(const char *path) CONFIG_GET_BOOL(block_sram_overwrite, "block_sram_overwrite"); CONFIG_GET_BOOL(savestate_auto_index, "savestate_auto_index"); + if (config_get_string(conf, "environment_variables", + &g_extern.system.environment)) + { + g_extern.system.environment_split = strdup(g_extern.system.environment); + if (!g_extern.system.environment_split) + { + SSNES_ERR("Failed to allocate environment variables. Will ignore them.\n"); + free(g_extern.system.environment); + g_extern.system.environment = NULL; + } + } + if (!g_extern.has_set_save_path && config_get_array(conf, "savefile_directory", tmp_str, sizeof(tmp_str))) { if (path_is_directory(tmp_str)) diff --git a/ssnes.c b/ssnes.c index 9a96d762e4..2ba4142d42 100644 --- a/ssnes.c +++ b/ssnes.c @@ -2079,10 +2079,15 @@ static void init_state(void) void ssnes_main_clear_state(void) { memset(&g_settings, 0, sizeof(g_settings)); + + free(g_extern.system.environment); + free(g_extern.system.environment_split); memset(&g_extern, 0, sizeof(g_extern)); + #ifdef SSNES_CONSOLE memset(&g_console, 0, sizeof(g_console)); #endif + init_state(); } @@ -2274,6 +2279,7 @@ int main(int argc, char *argv[]) if ((init_ret = ssnes_main_init(argc, argv))) return init_ret; while (ssnes_main_iterate()); ssnes_main_deinit(); + ssnes_main_clear_state(); return 0; } diff --git a/ssnes.cfg b/ssnes.cfg index cb7a6b6490..6045182034 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -8,9 +8,18 @@ # This will be overridden by explicit command line options. # savestate_directory = -## If enabled, load libsnes from a dynamic location. +# If enabled, load libsnes from a dynamic location. # libsnes_path = "/path/to/libsnes.so" +# Environment variables internally in SSNES. +# Implementations can tap into this user-specificed information to enable functionality +# that is deemed too obscure to expose directly. +# Some variables might be "standardized" at a later time if needed. +# The string is formatted as key value pairs delimited by a semicolon ';'. +# Any white space between the delimiter ';' and the '=' is significant. +# I.e.: "key1=value1;key2=value2;..." +# environment_variables = + #### Video # Video driver to use. "gl", "xvideo", "sdl" or "ext" (external API driver)