Re-added SDL_getenv() as a thread-safe getenv() implementation

This commit is contained in:
Sam Lantinga 2024-09-15 09:16:30 -07:00
parent 718845a33d
commit 28b94c4758
28 changed files with 374 additions and 359 deletions

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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 <crt_externs.h>
#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,6 +119,7 @@ SDL_Environment *SDL_CreateEnvironment(SDL_bool populated)
Android_JNI_GetManifestEnvironmentVariables();
#endif
char **strings = environ;
if (strings) {
for (int i = 0; strings[i]; ++i) {
char *variable = SDL_strdup(strings[i]);
if (!variable) {
@ -402,6 +135,7 @@ SDL_Environment *SDL_CreateEnvironment(SDL_bool populated)
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);
}

View File

@ -1,23 +0,0 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
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);

View File

@ -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";

View File

@ -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;
}

View File

@ -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";
}

View File

@ -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");
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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) {

View File

@ -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);
}