Added SDL_unsetenv()

This commit is contained in:
Sam Lantinga 2024-07-26 22:57:53 -07:00
parent b854e1fe0b
commit 473feab2a4
9 changed files with 133 additions and 37 deletions

View File

@ -665,6 +665,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumAllocations(void);
extern SDL_DECLSPEC const char * SDLCALL SDL_getenv(const char *name);
extern SDL_DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
extern SDL_DECLSPEC int SDLCALL SDL_unsetenv(const char *name);
typedef int (SDLCALL *SDL_CompareCallback)(const void *a, const void *b);
extern SDL_DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, SDL_CompareCallback compare);

View File

@ -75,12 +75,10 @@
#cmakedefine HAVE_CALLOC 1
#cmakedefine HAVE_REALLOC 1
#cmakedefine HAVE_FREE 1
#ifndef SDL_PLATFORM_WIN32 /* Don't use C runtime versions of these on Windows */
#cmakedefine HAVE_GETENV 1
#cmakedefine HAVE_SETENV 1
#cmakedefine HAVE_PUTENV 1
#cmakedefine HAVE_UNSETENV 1
#endif
#cmakedefine HAVE_ABS 1
#cmakedefine HAVE_BCOPY 1
#cmakedefine HAVE_MEMSET 1

View File

@ -58,7 +58,6 @@
#define HAVE_REALLOC 1
#define HAVE_FREE 1
#define HAVE_GETENV 1
#define HAVE_SETENV 1
#define HAVE_PUTENV 1
#define HAVE_SETENV 1
#define HAVE_UNSETENV 1

View File

@ -50,7 +50,6 @@
#define HAVE_REALLOC 1
#define HAVE_FREE 1
#define HAVE_GETENV 1
#define HAVE_SETENV 1
#define HAVE_PUTENV 1
#define HAVE_SETENV 1
#define HAVE_UNSETENV 1

View File

@ -1038,6 +1038,7 @@ SDL3_0.0.0 {
SDL_uitoa;
SDL_ulltoa;
SDL_ultoa;
SDL_unsetenv;
SDL_utf8strlcpy;
SDL_utf8strlen;
SDL_utf8strnlen;

View File

@ -1063,6 +1063,7 @@
#define SDL_uitoa SDL_uitoa_REAL
#define SDL_ulltoa SDL_ulltoa_REAL
#define SDL_ultoa SDL_ultoa_REAL
#define SDL_unsetenv SDL_unsetenv_REAL
#define SDL_utf8strlcpy SDL_utf8strlcpy_REAL
#define SDL_utf8strlen SDL_utf8strlen_REAL
#define SDL_utf8strnlen SDL_utf8strnlen_REAL

View File

@ -1069,6 +1069,7 @@ SDL_DYNAPI_PROC(float,SDL_truncf,(float a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_uitoa,(unsigned int a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_ulltoa,(Uint64 a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_ultoa,(unsigned long a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_unsetenv,(const char *a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_utf8strlcpy,(SDL_OUT_Z_CAP(c) char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_utf8strlen,(const char *a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_utf8strnlen,(const char *a, size_t b),(a,b),return)

View File

@ -30,11 +30,12 @@
#include "../core/android/SDL_android.h"
#endif
#if (defined(HAVE_GETENV) && defined(HAVE_SETENV)) || \
(defined(HAVE_GETENV) && defined(HAVE_PUTENV) && defined(HAVE_UNSETENV))
#define HAVE_LIBC_ENVIRONMENT
#elif defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
#define HAVE_WIN32_ENVIRONMENT
#elif defined(HAVE_GETENV) && \
(defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && \
(defined(HAVE_UNSETENV) || defined(HAVE_PUTENV))
#define HAVE_LIBC_ENVIRONMENT
#else
#define HAVE_LOCAL_ENVIRONMENT
#endif
@ -64,15 +65,13 @@ int SDL_setenv(const char *name, const char *value, int overwrite)
}
if (getenv(name) != NULL) {
if (overwrite) {
unsetenv(name);
} else {
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_aprintf(&new_variable, "%s=%s", name, value);
SDL_asprintf(&new_variable, "%s=%s", name, value);
if (!new_variable) {
return -1;
}
@ -92,7 +91,7 @@ int SDL_setenv(const char *name, const char *value, int overwrite)
return 0; /* asked not to overwrite existing value. */
}
}
if (!SetEnvironmentVariableA(name, *value ? value : NULL)) {
if (!SetEnvironmentVariableA(name, value)) {
return -1;
}
return 0;
@ -138,15 +137,13 @@ int SDL_setenv(const char *name, const char *value, int overwrite)
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;
}
}
/* If we found it, just replace the entry */
if (SDL_env[i]) {
SDL_free(SDL_env[i]);
SDL_env[i] = new_variable;
added = 1;
}
}
/* Didn't find it in the environment, expand and add */
@ -165,6 +162,68 @@ int SDL_setenv(const char *name, const char *value, int overwrite)
}
#endif // HAVE_LIBC_ENVIRONMENT
#ifdef HAVE_LIBC_ENVIRONMENT
#if defined(HAVE_UNSETENV)
int SDL_unsetenv(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(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(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(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(const char *name)
@ -194,6 +253,7 @@ const char *SDL_getenv(const char *name)
}
for ( ; ; ) {
SetLastError(ERROR_SUCCESS);
length = GetEnvironmentVariableA(name, string, maxlen);
if (length > maxlen) {
@ -204,6 +264,12 @@ const char *SDL_getenv(const char *name)
string = temp;
maxlen = length;
} else {
if (GetLastError() != ERROR_SUCCESS) {
if (string) {
SDL_free(string);
}
return NULL;
}
break;
}
}
@ -227,10 +293,11 @@ const char *SDL_getenv(const char *name)
value = (char *)0;
if (SDL_env) {
len = SDL_strlen(name);
for (i = 0; SDL_env[i] && !value; ++i) {
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;
}
}
}

View File

@ -624,7 +624,7 @@ static int stdlib_getsetenv(void *arg)
text);
}
/* Set value 1 without overwrite */
/* Set value 1 with overwrite */
overwrite = 1;
expected = value1;
result = SDL_setenv(name, value1, overwrite);
@ -643,6 +643,35 @@ static int stdlib_getsetenv(void *arg)
text);
}
/* Verify setenv() with empty string vs unsetenv() */
result = SDL_setenv("FOO", "1", 1);
SDLTest_AssertPass("Call to SDL_setenv('FOO','1', 1)");
SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result);
expected = "1";
text = SDL_getenv("FOO");
SDLTest_AssertPass("Call to SDL_getenv('FOO')");
SDLTest_AssertCheck(text && SDL_strcmp(text, expected) == 0, "Verify returned text, expected: %s, got: %s", expected, text);
result = SDL_setenv("FOO", "", 1);
SDLTest_AssertPass("Call to SDL_setenv('FOO','', 1)");
SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result);
expected = "";
text = SDL_getenv("FOO");
SDLTest_AssertPass("Call to SDL_getenv('FOO')");
SDLTest_AssertCheck(text && SDL_strcmp(text, expected) == 0, "Verify returned text, expected: '%s', got: '%s'", expected, text);
result = SDL_unsetenv("FOO");
SDLTest_AssertPass("Call to SDL_unsetenv('FOO')");
SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result);
text = SDL_getenv("FOO");
SDLTest_AssertPass("Call to SDL_getenv('FOO')");
SDLTest_AssertCheck(text == NULL, "Verify returned text, expected: (null), got: %s", text);
result = SDL_setenv("FOO", "0", 0);
SDLTest_AssertPass("Call to SDL_setenv('FOO','0', 0)");
SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result);
expected = "0";
text = SDL_getenv("FOO");
SDLTest_AssertPass("Call to SDL_getenv('FOO')");
SDLTest_AssertCheck(text && SDL_strcmp(text, expected) == 0, "Verify returned text, expected: %s, got: %s", expected, text);
/* Negative cases */
for (overwrite = 0; overwrite <= 1; overwrite++) {
result = SDL_setenv(NULL, value1, overwrite);
@ -1026,35 +1055,35 @@ stdlib_overflow(void *arg)
/* ================= Test References ================== */
/* Standard C routine test cases */
static const SDLTest_TestCaseReference stdlibTest1 = {
static const SDLTest_TestCaseReference stdlibTest_strnlen = {
stdlib_strnlen, "stdlib_strnlen", "Call to SDL_strnlen", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest2 = {
static const SDLTest_TestCaseReference stdlibTest_strlcpy = {
stdlib_strlcpy, "stdlib_strlcpy", "Call to SDL_strlcpy", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest3 = {
static const SDLTest_TestCaseReference stdlibTest_strstr = {
stdlib_strstr, "stdlib_strstr", "Call to SDL_strstr", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest4 = {
static const SDLTest_TestCaseReference stdlibTest_snprintf = {
stdlib_snprintf, "stdlib_snprintf", "Call to SDL_snprintf", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest5 = {
static const SDLTest_TestCaseReference stdlibTest_swprintf = {
stdlib_swprintf, "stdlib_swprintf", "Call to SDL_swprintf", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest6 = {
static const SDLTest_TestCaseReference stdlibTest_getsetenv = {
stdlib_getsetenv, "stdlib_getsetenv", "Call to SDL_getenv and SDL_setenv", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest7 = {
static const SDLTest_TestCaseReference stdlibTest_sscanf = {
stdlib_sscanf, "stdlib_sscanf", "Call to SDL_sscanf", TEST_ENABLED
};
static const SDLTest_TestCaseReference stdlibTest8 = {
static const SDLTest_TestCaseReference stdlibTest_aligned_alloc = {
stdlib_aligned_alloc, "stdlib_aligned_alloc", "Call to SDL_aligned_alloc", TEST_ENABLED
};
@ -1064,14 +1093,14 @@ static const SDLTest_TestCaseReference stdlibTestOverflow = {
/* Sequence of Standard C routine test cases */
static const SDLTest_TestCaseReference *stdlibTests[] = {
&stdlibTest1,
&stdlibTest2,
&stdlibTest3,
&stdlibTest4,
&stdlibTest5,
&stdlibTest6,
&stdlibTest7,
&stdlibTest8,
&stdlibTest_strnlen,
&stdlibTest_strlcpy,
&stdlibTest_strstr,
&stdlibTest_snprintf,
&stdlibTest_swprintf,
&stdlibTest_getsetenv,
&stdlibTest_sscanf,
&stdlibTest_aligned_alloc,
&stdlibTestOverflow,
NULL
};