diff --git a/docs/README-migration.md b/docs/README-migration.md index 171823a01..daa521af4 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -1743,6 +1743,8 @@ Please note that the case-folding technique used by SDL3 will not produce correc SDL_strtoll(), SDL_strtoull(), SDL_lltoa(), and SDL_ulltoa() use long long values instead of 64-bit values, to match their C runtime counterparts. +SDL_setenv() is not thread-safe and has been renamed SDL_setenv_unsafe(). + The following macros have been removed: * SDL_TABLESIZE() - use SDL_arraysize() instead diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index e7ca1cc7c..924c5399b 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -1156,16 +1156,33 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyEnvironment(SDL_Environment *env); /** * Get the value of a variable in the environment. * + * This function uses SDL's cached copy of the environment and is thread-safe. + * + * \param name the name of the variable to get. + * \returns a pointer to the value of the variable or NULL if it can't be + * found. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + */ +extern SDL_DECLSPEC const char * SDLCALL SDL_getenv(const char *name); + +/** + * Get the value of a variable in the environment. + * + * This function bypasses SDL's cached copy of the environment and is not thread-safe. + * * \param name the name of the variable to get. * \returns a pointer to the value of the variable or NULL if it can't be * found. * * \threadsafety This function is not thread safe, consider using - * SDL_GetEnvironmentVariable() instead. + * SDL_getenv() instead. * * \since This function is available since SDL 3.0.0. * - * \sa SDL_GetEnvironmentVariable + * \sa SDL_getenv */ extern SDL_DECLSPEC const char * SDLCALL SDL_getenv_unsafe(const char *name); diff --git a/src/SDL_hints.c b/src/SDL_hints.c index a91877bba..8dd9c551c 100644 --- a/src/SDL_hints.c +++ b/src/SDL_hints.c @@ -72,7 +72,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr return SDL_InvalidParamError("name"); } - const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name); + const char *env = SDL_getenv(name); if (env && (priority < SDL_HINT_OVERRIDE)) { return SDL_SetError("An environment variable is taking priority"); } @@ -126,7 +126,7 @@ SDL_bool SDL_ResetHint(const char *name) return SDL_InvalidParamError("name"); } - const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name); + const char *env = SDL_getenv(name); const SDL_PropertiesID hints = GetHintProperties(false); if (!hints) { @@ -165,7 +165,7 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c return; // uh...okay. } - const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name); + const char *env = SDL_getenv(name); if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) { SDL_HintWatch *entry = hint->callbacks; while (entry) { @@ -196,7 +196,7 @@ const char *SDL_GetHint(const char *name) return NULL; } - const char *result = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name); + const char *result = SDL_getenv(name); const SDL_PropertiesID hints = GetHintProperties(false); if (hints) { diff --git a/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c index f5dc4b20e..f48a5b25d 100644 --- a/src/audio/SDL_audiodev.c +++ b/src/audio/SDL_audiodev.c @@ -87,7 +87,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const bool recording, const bool c } // Figure out what our audio device is - audiodev = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "AUDIODEV"); + audiodev = SDL_getenv("AUDIODEV"); if (!audiodev) { if (classic) { audiodev = SDL_PATH_DEV_AUDIO; diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index 62daaf3a5..dbbc3e174 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -331,14 +331,14 @@ static char *IBus_GetDBusAddressFilename(void) } // Use this environment variable if it exists. - addr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "IBUS_ADDRESS"); + addr = SDL_getenv("IBUS_ADDRESS"); if (addr && *addr) { return SDL_strdup(addr); } /* Otherwise, we have to get the hostname, display, machine id, config dir and look up the address from a filepath using all those bits, eek. */ - disp_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "DISPLAY"); + disp_env = SDL_getenv("DISPLAY"); if (!disp_env || !*disp_env) { display = SDL_strdup(":0.0"); @@ -363,7 +363,7 @@ static char *IBus_GetDBusAddressFilename(void) } if (!*host) { - const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE"); + const char *session = SDL_getenv("XDG_SESSION_TYPE"); if (session && SDL_strcmp(session, "wayland") == 0) { host = "unix-wayland"; } else { @@ -373,11 +373,11 @@ static char *IBus_GetDBusAddressFilename(void) SDL_memset(config_dir, 0, sizeof(config_dir)); - conf_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_CONFIG_HOME"); + conf_env = SDL_getenv("XDG_CONFIG_HOME"); if (conf_env && *conf_env) { SDL_strlcpy(config_dir, conf_env, sizeof(config_dir)); } else { - const char *home_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + const char *home_env = SDL_getenv("HOME"); if (!home_env || !*home_env) { SDL_free(display); return NULL; diff --git a/src/core/linux/SDL_ime.c b/src/core/linux/SDL_ime.c index a371e658e..a853618bb 100644 --- a/src/core/linux/SDL_ime.c +++ b/src/core/linux/SDL_ime.c @@ -44,8 +44,8 @@ static void InitIME(void) { static bool inited = false; #ifdef HAVE_FCITX - const char *im_module = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_IM_MODULE"); - const char *xmodifiers = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XMODIFIERS"); + const char *im_module = SDL_getenv("SDL_IM_MODULE"); + const char *xmodifiers = SDL_getenv("XMODIFIERS"); #endif if (inited == true) { diff --git a/src/core/linux/SDL_sandbox.c b/src/core/linux/SDL_sandbox.c index 797d36c1e..5a8df8487 100644 --- a/src/core/linux/SDL_sandbox.c +++ b/src/core/linux/SDL_sandbox.c @@ -33,9 +33,9 @@ SDL_Sandbox SDL_DetectSandbox(void) /* For Snap, we check multiple variables because they might be set for * unrelated reasons. This is the same thing WebKitGTK does. */ - if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP") != NULL && - SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_NAME") != NULL && - SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_REVISION") != NULL) { + if (SDL_getenv("SNAP") != NULL && + SDL_getenv("SNAP_NAME") != NULL && + SDL_getenv("SNAP_REVISION") != NULL) { return SDL_SANDBOX_SNAP; } diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 6b3825675..01f6f506d 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -239,7 +239,6 @@ SDL3_0.0.0 { SDL_GetBasePath; SDL_GetBooleanProperty; SDL_GetCPUCacheLineSize; - SDL_GetNumLogicalCPUCores; SDL_GetCameraDriver; SDL_GetCameraFormat; SDL_GetCameraID; @@ -414,6 +413,7 @@ SDL3_0.0.0 { SDL_GetNumJoystickBalls; SDL_GetNumJoystickButtons; SDL_GetNumJoystickHats; + SDL_GetNumLogicalCPUCores; SDL_GetNumRenderDrivers; SDL_GetNumVideoDrivers; SDL_GetNumberProperty; @@ -1029,6 +1029,7 @@ SDL3_0.0.0 { SDL_fmod; SDL_fmodf; SDL_free; + SDL_getenv; SDL_getenv_unsafe; SDL_hid_ble_scan; SDL_hid_close; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 322127180..e0d1be092 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -264,7 +264,6 @@ #define SDL_GetBasePath SDL_GetBasePath_REAL #define SDL_GetBooleanProperty SDL_GetBooleanProperty_REAL #define SDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize_REAL -#define SDL_GetNumLogicalCPUCores SDL_GetNumLogicalCPUCores_REAL #define SDL_GetCameraDriver SDL_GetCameraDriver_REAL #define SDL_GetCameraFormat SDL_GetCameraFormat_REAL #define SDL_GetCameraID SDL_GetCameraID_REAL @@ -439,6 +438,7 @@ #define SDL_GetNumJoystickBalls SDL_GetNumJoystickBalls_REAL #define SDL_GetNumJoystickButtons SDL_GetNumJoystickButtons_REAL #define SDL_GetNumJoystickHats SDL_GetNumJoystickHats_REAL +#define SDL_GetNumLogicalCPUCores SDL_GetNumLogicalCPUCores_REAL #define SDL_GetNumRenderDrivers SDL_GetNumRenderDrivers_REAL #define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL #define SDL_GetNumberProperty SDL_GetNumberProperty_REAL @@ -1054,6 +1054,7 @@ #define SDL_fmod SDL_fmod_REAL #define SDL_fmodf SDL_fmodf_REAL #define SDL_free SDL_free_REAL +#define SDL_getenv SDL_getenv_REAL #define SDL_getenv_unsafe SDL_getenv_unsafe_REAL #define SDL_hid_ble_scan SDL_hid_ble_scan_REAL #define SDL_hid_close SDL_hid_close_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index ab406b4f5..8c3c10a05 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -284,7 +284,6 @@ SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_GetBasePath,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_GetBooleanProperty,(SDL_PropertiesID a, const char *b, SDL_bool c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return) -SDL_DYNAPI_PROC(int,SDL_GetNumLogicalCPUCores,(void),(),return) SDL_DYNAPI_PROC(const char*,SDL_GetCameraDriver,(int a),(a),return) SDL_DYNAPI_PROC(SDL_bool,SDL_GetCameraFormat,(SDL_Camera *a, SDL_CameraSpec *b),(a,b),return) SDL_DYNAPI_PROC(SDL_CameraID,SDL_GetCameraID,(SDL_Camera *a),(a),return) @@ -459,6 +458,7 @@ SDL_DYNAPI_PROC(int,SDL_GetNumJoystickAxes,(SDL_Joystick *a),(a),return) SDL_DYNAPI_PROC(int,SDL_GetNumJoystickBalls,(SDL_Joystick *a),(a),return) SDL_DYNAPI_PROC(int,SDL_GetNumJoystickButtons,(SDL_Joystick *a),(a),return) SDL_DYNAPI_PROC(int,SDL_GetNumJoystickHats,(SDL_Joystick *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_GetNumLogicalCPUCores,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GetNumRenderDrivers,(void),(),return) SDL_DYNAPI_PROC(int,SDL_GetNumVideoDrivers,(void),(),return) SDL_DYNAPI_PROC(Sint64,SDL_GetNumberProperty,(SDL_PropertiesID a, const char *b, Sint64 c),(a,b,c),return) @@ -1063,6 +1063,7 @@ SDL_DYNAPI_PROC(float,SDL_floorf,(float a),(a),return) SDL_DYNAPI_PROC(double,SDL_fmod,(double a, double b),(a,b),return) SDL_DYNAPI_PROC(float,SDL_fmodf,(float a, float b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_free,(void *a),(a),) +SDL_DYNAPI_PROC(const char*,SDL_getenv,(const char *a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_getenv_unsafe,(const char *a),(a),return) SDL_DYNAPI_PROC(void,SDL_hid_ble_scan,(SDL_bool a),(a),) SDL_DYNAPI_PROC(int,SDL_hid_close,(SDL_hid_device *a),(a),return) diff --git a/src/filesystem/cocoa/SDL_sysfilesystem.m b/src/filesystem/cocoa/SDL_sysfilesystem.m index c88ad1c1a..07a75ff74 100644 --- a/src/filesystem/cocoa/SDL_sysfilesystem.m +++ b/src/filesystem/cocoa/SDL_sysfilesystem.m @@ -144,7 +144,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) switch (folder) { case SDL_FOLDER_HOME: - base = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + base = SDL_getenv("HOME"); if (!base) { SDL_SetError("No $HOME environment variable available"); diff --git a/src/filesystem/emscripten/SDL_sysfilesystem.c b/src/filesystem/emscripten/SDL_sysfilesystem.c index 8e228203c..e10081c77 100644 --- a/src/filesystem/emscripten/SDL_sysfilesystem.c +++ b/src/filesystem/emscripten/SDL_sysfilesystem.c @@ -93,7 +93,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) return NULL; } - home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + home = SDL_getenv("HOME"); if (!home) { SDL_SetError("No $HOME environment variable available"); return NULL; diff --git a/src/filesystem/haiku/SDL_sysfilesystem.cc b/src/filesystem/haiku/SDL_sysfilesystem.cc index e8f707155..60e7d5b09 100644 --- a/src/filesystem/haiku/SDL_sysfilesystem.cc +++ b/src/filesystem/haiku/SDL_sysfilesystem.cc @@ -68,7 +68,7 @@ char *SDL_SYS_GetBasePath(void) char *SDL_SYS_GetPrefPath(const char *org, const char *app) { // !!! FIXME: is there a better way to do this? - const char *home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + const char *home = SDL_getenv("HOME"); const char *append = "/config/settings/"; size_t len = SDL_strlen(home); @@ -102,7 +102,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) const char *home = NULL; char *result; - home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + home = SDL_getenv("HOME"); if (!home) { SDL_SetError("No $HOME environment variable available"); return NULL; diff --git a/src/filesystem/unix/SDL_sysfilesystem.c b/src/filesystem/unix/SDL_sysfilesystem.c index 80938c47c..6f46a5b3f 100644 --- a/src/filesystem/unix/SDL_sysfilesystem.c +++ b/src/filesystem/unix/SDL_sysfilesystem.c @@ -74,7 +74,7 @@ static char *readSymLink(const char *path) #ifdef SDL_PLATFORM_OPENBSD static char *search_path_for_binary(const char *bin) { - const char *envr_real = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "PATH"); + const char *envr_real = SDL_getenv("PATH"); char *envr; size_t alloc_size; char *exe = NULL; @@ -163,7 +163,7 @@ char *SDL_SYS_GetBasePath(void) exe = search_path_for_binary(cmdline[0]); } else { if (exe && *exe == '.') { - const char *pwd = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "PWD"); + const char *pwd = SDL_getenv("PWD"); if (pwd && *pwd) { SDL_asprintf(&pwddst, "%s/%s", pwd, exe); } @@ -265,7 +265,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app) * * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html */ - const char *envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_DATA_HOME"); + const char *envr = SDL_getenv("XDG_DATA_HOME"); const char *append; char *result = NULL; char *ptr = NULL; @@ -281,7 +281,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app) if (!envr) { // You end up with "$HOME/.local/share/Game Name 2" - envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + envr = SDL_getenv("HOME"); if (!envr) { // we could take heroic measures with /etc/passwd, but oh well. SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set"); @@ -368,12 +368,12 @@ static char *xdg_user_dir_lookup_with_fallback (const char *type, const char *fa int relative; size_t l; - home_dir = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + home_dir = SDL_getenv("HOME"); if (!home_dir) goto error; - config_home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_CONFIG_HOME"); + config_home = SDL_getenv("XDG_CONFIG_HOME"); if (!config_home || config_home[0] == 0) { l = SDL_strlen (home_dir) + SDL_strlen ("/.config/user-dirs.dirs") + 1; @@ -495,7 +495,7 @@ static char *xdg_user_dir_lookup (const char *type) if (dir) return dir; - home_dir = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + home_dir = SDL_getenv("HOME"); if (!home_dir) return NULL; @@ -533,7 +533,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder) */ switch(folder) { case SDL_FOLDER_HOME: - param = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME"); + param = SDL_getenv("HOME"); if (!param) { SDL_SetError("No $HOME environment variable available"); diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c index c40afacbf..2f6ef78ea 100644 --- a/src/haptic/SDL_haptic.c +++ b/src/haptic/SDL_haptic.c @@ -537,7 +537,7 @@ SDL_bool SDL_SetHapticGain(SDL_Haptic *haptic, int gain) } // The user can use an environment variable to override the max gain. - env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_HAPTIC_GAIN_MAX"); + env = SDL_getenv("SDL_HAPTIC_GAIN_MAX"); if (env) { max_gain = SDL_atoi(env); diff --git a/src/locale/unix/SDL_syslocale.c b/src/locale/unix/SDL_syslocale.c index ac4301dc1..e945da5c8 100644 --- a/src/locale/unix/SDL_syslocale.c +++ b/src/locale/unix/SDL_syslocale.c @@ -78,13 +78,13 @@ bool SDL_SYS_GetPreferredLocales(char *buf, size_t buflen) *tmp = '\0'; // LANG is the primary locale (maybe) - envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG"); + envr = SDL_getenv("LANG"); if (envr) { SDL_strlcpy(tmp, envr, buflen); } // fallback languages - envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANGUAGE"); + envr = SDL_getenv("LANGUAGE"); if (envr) { if (*tmp) { SDL_strlcat(tmp, ":", buflen); diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index c29fc3149..0243b9bf9 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -20,7 +20,6 @@ */ #include "SDL_internal.h" -#include "SDL_getenv_c.h" #include "../SDL_hashtable.h" #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) @@ -37,11 +36,6 @@ (defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && \ (defined(HAVE_UNSETENV) || defined(HAVE_PUTENV)) #define HAVE_LIBC_ENVIRONMENT -#else -#define HAVE_LOCAL_ENVIRONMENT -#endif - -#if !defined(SDL_PLATFORM_WINDOWS) #if defined(SDL_PLATFORM_MACOS) #include #define environ (*_NSGetEnviron()) @@ -51,272 +45,10 @@ #else extern char **environ; #endif -#endif // !SDL_PLATFORM_WINDOWS - -// Put a variable into the environment -// Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/) -#ifdef HAVE_LIBC_ENVIRONMENT -#if defined(HAVE_SETENV) -int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) -{ - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { - return -1; - } - - return setenv(name, value, overwrite); -} -// We have a real environment table, but no real setenv? Fake it w/ putenv. #else -int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) -{ - char *new_variable; - - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { - return -1; - } - - if (getenv(name) != NULL) { - if (!overwrite) { - return 0; // leave the existing one there. - } - } - - // This leaks. Sorry. Get a better OS so we don't have to do this. - SDL_asprintf(&new_variable, "%s=%s", name, value); - if (!new_variable) { - return -1; - } - return putenv(new_variable); -} +#define HAVE_LOCAL_ENVIRONMENT +static char **environ; #endif -#elif defined(HAVE_WIN32_ENVIRONMENT) -int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) -{ - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { - return -1; - } - - if (!overwrite) { - if (GetEnvironmentVariableA(name, NULL, 0) > 0) { - return 0; // asked not to overwrite existing value. - } - } - if (!SetEnvironmentVariableA(name, value)) { - return -1; - } - return 0; -} -#else // roll our own - -// We'll leak this, as environment variables are intended to persist past SDL_Quit() -static char **SDL_env; - -int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) -{ - int added; - size_t len, i; - char **new_env; - char *new_variable; - - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { - return -1; - } - - // See if it already exists - if (!overwrite && SDL_getenv_unsafe(name)) { - return 0; - } - - // Allocate memory for the variable - len = SDL_strlen(name) + SDL_strlen(value) + 2; - new_variable = (char *)SDL_malloc(len); - if (!new_variable) { - return -1; - } - - SDL_snprintf(new_variable, len, "%s=%s", name, value); - value = new_variable + SDL_strlen(name) + 1; - name = new_variable; - - // Actually put it into the environment - added = 0; - i = 0; - if (SDL_env) { - // Check to see if it's already there... - len = (value - name); - for (; SDL_env[i]; ++i) { - if (SDL_strncmp(SDL_env[i], name, len) == 0) { - // If we found it, just replace the entry - SDL_free(SDL_env[i]); - SDL_env[i] = new_variable; - added = 1; - break; - } - } - } - - // Didn't find it in the environment, expand and add - if (!added) { - new_env = SDL_realloc(SDL_env, (i + 2) * sizeof(char *)); - if (new_env) { - SDL_env = new_env; - SDL_env[i++] = new_variable; - SDL_env[i++] = (char *)0; - added = 1; - } else { - SDL_free(new_variable); - } - } - return added ? 0 : -1; -} -#endif // HAVE_LIBC_ENVIRONMENT - -#ifdef HAVE_LIBC_ENVIRONMENT -#if defined(HAVE_UNSETENV) -int SDL_unsetenv_unsafe(const char *name) -{ - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { - return -1; - } - - return unsetenv(name); -} -// We have a real environment table, but no unsetenv? Fake it w/ putenv. -#else -int SDL_unsetenv_unsafe(const char *name) -{ - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { - return -1; - } - - // Hope this environment uses the non-standard extension of removing the environment variable if it has no '=' - return putenv(name); -} -#endif -#elif defined(HAVE_WIN32_ENVIRONMENT) -int SDL_unsetenv_unsafe(const char *name) -{ - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { - return -1; - } - - if (!SetEnvironmentVariableA(name, NULL)) { - return -1; - } - return 0; -} -#else -int SDL_unsetenv_unsafe(const char *name) -{ - size_t len, i; - - // Input validation - if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { - return -1; - } - - if (SDL_env) { - len = SDL_strlen(name); - for (i = 0; SDL_env[i]; ++i) { - if ((SDL_strncmp(SDL_env[i], name, len) == 0) && - (SDL_env[i][len] == '=')) { - // Just clear out this entry for now - *SDL_env[i] = '\0'; - break; - } - } - } - return 0; -} -#endif // HAVE_LIBC_ENVIRONMENT - -// Retrieve a variable named "name" from the environment -#ifdef HAVE_LIBC_ENVIRONMENT -const char *SDL_getenv_unsafe(const char *name) -{ -#ifdef SDL_PLATFORM_ANDROID - // Make sure variables from the application manifest are available - Android_JNI_GetManifestEnvironmentVariables(); -#endif - - // Input validation - if (!name || *name == '\0') { - return NULL; - } - - return getenv(name); -} -#elif defined(HAVE_WIN32_ENVIRONMENT) -const char *SDL_getenv_unsafe(const char *name) -{ - DWORD length, maxlen = 0; - char *string = NULL; - const char *result = NULL; - - // Input validation - if (!name || *name == '\0') { - return NULL; - } - - for ( ; ; ) { - SetLastError(ERROR_SUCCESS); - length = GetEnvironmentVariableA(name, string, maxlen); - - if (length > maxlen) { - char *temp = (char *)SDL_realloc(string, length); - if (!temp) { - return NULL; - } - string = temp; - maxlen = length; - } else { - if (GetLastError() != ERROR_SUCCESS) { - if (string) { - SDL_free(string); - } - return NULL; - } - break; - } - } - if (string) { - result = SDL_GetPersistentString(string); - SDL_free(string); - } - return result; -} -#else -const char *SDL_getenv_unsafe(const char *name) -{ - size_t len, i; - char *value; - - // Input validation - if (!name || *name == '\0') { - return NULL; - } - - value = (char *)0; - if (SDL_env) { - len = SDL_strlen(name); - for (i = 0; SDL_env[i]; ++i) { - if ((SDL_strncmp(SDL_env[i], name, len) == 0) && - (SDL_env[i][len] == '=')) { - value = &SDL_env[i][len + 1]; - break; - } - } - } - return value; -} -#endif // HAVE_LIBC_ENVIRONMENT struct SDL_Environment @@ -387,20 +119,22 @@ SDL_Environment *SDL_CreateEnvironment(SDL_bool populated) Android_JNI_GetManifestEnvironmentVariables(); #endif char **strings = environ; - for (int i = 0; strings[i]; ++i) { - char *variable = SDL_strdup(strings[i]); - if (!variable) { - continue; - } + if (strings) { + for (int i = 0; strings[i]; ++i) { + char *variable = SDL_strdup(strings[i]); + if (!variable) { + continue; + } - char *value = SDL_strchr(variable, '='); - if (!value || value == variable) { - SDL_free(variable); - continue; - } - *value++ = '\0'; + char *value = SDL_strchr(variable, '='); + if (!value || value == variable) { + SDL_free(variable); + continue; + } + *value++ = '\0'; - SDL_InsertIntoHashTable(env->strings, variable, value); + SDL_InsertIntoHashTable(env->strings, variable, value); + } } #endif // SDL_PLATFORM_WINDOWS } @@ -558,3 +292,285 @@ void SDL_DestroyEnvironment(SDL_Environment *env) SDL_DestroyHashTable(env->strings); SDL_free(env); } + +// Put a variable into the environment +// Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/) +#ifdef HAVE_LIBC_ENVIRONMENT +#if defined(HAVE_SETENV) +int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) +{ + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { + return -1; + } + + SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0)); + + return setenv(name, value, overwrite); +} +// We have a real environment table, but no real setenv? Fake it w/ putenv. +#else +int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) +{ + char *new_variable; + + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { + return -1; + } + + SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0)); + + if (getenv(name) != NULL) { + if (!overwrite) { + return 0; // leave the existing one there. + } + } + + // This leaks. Sorry. Get a better OS so we don't have to do this. + SDL_asprintf(&new_variable, "%s=%s", name, value); + if (!new_variable) { + return -1; + } + return putenv(new_variable); +} +#endif +#elif defined(HAVE_WIN32_ENVIRONMENT) +int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) +{ + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { + return -1; + } + + SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0)); + + if (!overwrite) { + if (GetEnvironmentVariableA(name, NULL, 0) > 0) { + return 0; // asked not to overwrite existing value. + } + } + if (!SetEnvironmentVariableA(name, value)) { + return -1; + } + return 0; +} +#else // roll our own + +int SDL_setenv_unsafe(const char *name, const char *value, int overwrite) +{ + int added; + size_t len, i; + char **new_env; + char *new_variable; + + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { + return -1; + } + + // See if it already exists + if (!overwrite && SDL_getenv_unsafe(name)) { + return 0; + } + + SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0)); + + // Allocate memory for the variable + len = SDL_strlen(name) + SDL_strlen(value) + 2; + new_variable = (char *)SDL_malloc(len); + if (!new_variable) { + return -1; + } + + SDL_snprintf(new_variable, len, "%s=%s", name, value); + value = new_variable + SDL_strlen(name) + 1; + name = new_variable; + + // Actually put it into the environment + added = 0; + i = 0; + if (environ) { + // Check to see if it's already there... + len = (value - name); + for (; environ[i]; ++i) { + if (SDL_strncmp(environ[i], name, len) == 0) { + // If we found it, just replace the entry + SDL_free(environ[i]); + environ[i] = new_variable; + added = 1; + break; + } + } + } + + // Didn't find it in the environment, expand and add + if (!added) { + new_env = SDL_realloc(environ, (i + 2) * sizeof(char *)); + if (new_env) { + environ = new_env; + environ[i++] = new_variable; + environ[i++] = (char *)0; + added = 1; + } else { + SDL_free(new_variable); + } + } + return added ? 0 : -1; +} +#endif // HAVE_LIBC_ENVIRONMENT + +#ifdef HAVE_LIBC_ENVIRONMENT +#if defined(HAVE_UNSETENV) +int SDL_unsetenv_unsafe(const char *name) +{ + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { + return -1; + } + + SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name); + + return unsetenv(name); +} +// We have a real environment table, but no unsetenv? Fake it w/ putenv. +#else +int SDL_unsetenv_unsafe(const char *name) +{ + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { + return -1; + } + + SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name); + + // Hope this environment uses the non-standard extension of removing the environment variable if it has no '=' + return putenv(name); +} +#endif +#elif defined(HAVE_WIN32_ENVIRONMENT) +int SDL_unsetenv_unsafe(const char *name) +{ + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { + return -1; + } + + SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name); + + if (!SetEnvironmentVariableA(name, NULL)) { + return -1; + } + return 0; +} +#else +int SDL_unsetenv_unsafe(const char *name) +{ + size_t len, i; + + // Input validation + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { + return -1; + } + + SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name); + + if (environ) { + len = SDL_strlen(name); + for (i = 0; environ[i]; ++i) { + if ((SDL_strncmp(environ[i], name, len) == 0) && + (environ[i][len] == '=')) { + // Just clear out this entry for now + *environ[i] = '\0'; + break; + } + } + } + return 0; +} +#endif // HAVE_LIBC_ENVIRONMENT + +// Retrieve a variable named "name" from the environment +#ifdef HAVE_LIBC_ENVIRONMENT +const char *SDL_getenv_unsafe(const char *name) +{ +#ifdef SDL_PLATFORM_ANDROID + // Make sure variables from the application manifest are available + Android_JNI_GetManifestEnvironmentVariables(); +#endif + + // Input validation + if (!name || *name == '\0') { + return NULL; + } + + return getenv(name); +} +#elif defined(HAVE_WIN32_ENVIRONMENT) +const char *SDL_getenv_unsafe(const char *name) +{ + DWORD length, maxlen = 0; + char *string = NULL; + const char *result = NULL; + + // Input validation + if (!name || *name == '\0') { + return NULL; + } + + for ( ; ; ) { + SetLastError(ERROR_SUCCESS); + length = GetEnvironmentVariableA(name, string, maxlen); + + if (length > maxlen) { + char *temp = (char *)SDL_realloc(string, length); + if (!temp) { + return NULL; + } + string = temp; + maxlen = length; + } else { + if (GetLastError() != ERROR_SUCCESS) { + if (string) { + SDL_free(string); + } + return NULL; + } + break; + } + } + if (string) { + result = SDL_GetPersistentString(string); + SDL_free(string); + } + return result; +} +#else +const char *SDL_getenv_unsafe(const char *name) +{ + size_t len, i; + const char *value = NULL; + + // Input validation + if (!name || *name == '\0') { + return NULL; + } + + if (environ) { + len = SDL_strlen(name); + for (i = 0; environ[i]; ++i) { + if ((SDL_strncmp(environ[i], name, len) == 0) && + (environ[i][len] == '=')) { + value = &environ[i][len + 1]; + break; + } + } + } + return value; +} +#endif // HAVE_LIBC_ENVIRONMENT + +const char *SDL_getenv(const char *name) +{ + return SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name); +} diff --git a/src/stdlib/SDL_getenv_c.h b/src/stdlib/SDL_getenv_c.h deleted file mode 100644 index 200107734..000000000 --- a/src/stdlib/SDL_getenv_c.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2024 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -extern void SDL_FreeEnvironmentMemory(void); diff --git a/src/stdlib/SDL_iconv.c b/src/stdlib/SDL_iconv.c index 7aff8c59c..e5d8fb571 100644 --- a/src/stdlib/SDL_iconv.c +++ b/src/stdlib/SDL_iconv.c @@ -163,15 +163,15 @@ static const char *getlocale(char *buffer, size_t bufsize) const char *lang; char *ptr; - lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_ALL"); + lang = SDL_getenv("LC_ALL"); if (!lang) { - lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_CTYPE"); + lang = SDL_getenv("LC_CTYPE"); } if (!lang) { - lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_MESSAGES"); + lang = SDL_getenv("LC_MESSAGES"); } if (!lang) { - lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG"); + lang = SDL_getenv("LANG"); } if (!lang || !*lang || SDL_strcmp(lang, "C") == 0) { lang = "ASCII"; diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index 3d3542795..53886b989 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -341,7 +341,7 @@ static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_ #if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA) /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */ - path = SDL_getenv_unsafe("SDL_VIDEO_GL_DRIVER"); + path = SDL_getenv("SDL_VIDEO_GL_DRIVER"); if (path) { opengl_dll_handle = SDL_LoadObject(path); } @@ -401,7 +401,7 @@ static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_ if (egl_dll_handle) { SDL_UnloadObject(egl_dll_handle); } - path = SDL_getenv_unsafe("SDL_VIDEO_EGL_DRIVER"); + path = SDL_getenv("SDL_VIDEO_EGL_DRIVER"); if (!path) { path = DEFAULT_EGL; } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 9b5261961..b209116d0 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1292,11 +1292,11 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, */ // Look up the preferred locale, falling back to "C" as default - locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_ALL"); + locale = SDL_getenv("LC_ALL"); if (!locale) { - locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_CTYPE"); + locale = SDL_getenv("LC_CTYPE"); if (!locale) { - locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG"); + locale = SDL_getenv("LANG"); if (!locale) { locale = "C"; } diff --git a/src/video/wayland/SDL_waylandmessagebox.c b/src/video/wayland/SDL_waylandmessagebox.c index e32e65c5a..c0c37f9a0 100644 --- a/src/video/wayland/SDL_waylandmessagebox.c +++ b/src/video/wayland/SDL_waylandmessagebox.c @@ -85,8 +85,8 @@ bool Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *butto SDL_Process *process; // Are we trying to connect to or are currently in a Wayland session? - if (!SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "WAYLAND_DISPLAY")) { - const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE"); + if (!SDL_getenv("WAYLAND_DISPLAY")) { + const char *session = SDL_getenv("XDG_SESSION_TYPE"); if (session && SDL_strcasecmp(session, "wayland") != 0) { return SDL_SetError("Not on a wayland display"); } diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index b6f7e9824..576e898a9 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -345,7 +345,7 @@ static bool wayland_get_system_cursor(SDL_VideoData *vdata, SDL_CursorData *cdat // Fallback envvar if the DBus properties don't exist if (size <= 0) { - const char *xcursor_size = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XCURSOR_SIZE"); + const char *xcursor_size = SDL_getenv("XCURSOR_SIZE"); if (xcursor_size) { size = SDL_atoi(xcursor_size); } @@ -381,7 +381,7 @@ static bool wayland_get_system_cursor(SDL_VideoData *vdata, SDL_CursorData *cdat // Fallback envvar if the DBus properties don't exist if (!xcursor_theme) { - xcursor_theme = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XCURSOR_THEME"); + xcursor_theme = SDL_getenv("XCURSOR_THEME"); } theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, size, vdata->shm); diff --git a/src/video/wayland/SDL_waylandshmbuffer.c b/src/video/wayland/SDL_waylandshmbuffer.c index 813f2ee6f..40ff2bd90 100644 --- a/src/video/wayland/SDL_waylandshmbuffer.c +++ b/src/video/wayland/SDL_waylandshmbuffer.c @@ -80,7 +80,7 @@ static int CreateTempFD(off_t size) const char *xdg_path; char tmp_path[PATH_MAX]; - xdg_path = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_RUNTIME_DIR"); + xdg_path = SDL_getenv("XDG_RUNTIME_DIR"); if (!xdg_path) { return -1; } diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index d893b4b43..b57052ebc 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -429,8 +429,8 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols) bool display_is_external = !!display; // Are we trying to connect to or are currently in a Wayland session? - if (!SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "WAYLAND_DISPLAY")) { - const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE"); + if (!SDL_getenv("WAYLAND_DISPLAY")) { + const char *session = SDL_getenv("XDG_SESSION_TYPE"); if (session && SDL_strcasecmp(session, "wayland") != 0) { return NULL; } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index d043b13c1..b2ed1f679 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1914,7 +1914,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) /* Note that we don't check for empty strings, as that is still * considered a valid activation token! */ - const char *activation_token = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_ACTIVATION_TOKEN"); + const char *activation_token = SDL_getenv("XDG_ACTIVATION_TOKEN"); if (activation_token) { xdg_activation_v1_activate(c->activation_manager, activation_token, diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index e3e10636d..1ec1df1d8 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -169,7 +169,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) char *prev_locale = setlocale(LC_ALL, NULL); char *prev_xmods = X11_XSetLocaleModifiers(NULL); const char *new_xmods = ""; - const char *env_xmods = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XMODIFIERS"); + const char *env_xmods = SDL_getenv("XMODIFIERS"); bool has_dbus_ime_support = false; if (prev_locale) { diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index aa8161e43..1194af2c0 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -248,7 +248,7 @@ static float GetGlobalContentScale(SDL_VideoDevice *_this) // If that failed, try the GDK_SCALE envvar... if (scale_factor <= 0.0) { - const char *scale_str = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "GDK_SCALE"); + const char *scale_str = SDL_getenv("GDK_SCALE"); if (scale_str) { scale_factor = SDL_atoi(scale_str); }