From 4424e291bfd2f2608a899ba4644fab0c9e8ab5c7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 16 Dec 2009 10:59:51 +0000 Subject: [PATCH] Implemented SDL_setenv(), moved SDL_putenv() to compat. Fixes Bugzilla #779. --- configure.in | 2 +- include/SDL_compat.h | 2 + include/SDL_config.h.in | 1 + include/SDL_config_iphoneos.h | 2 + include/SDL_config_macosx.h | 1 + include/SDL_config_nintendods.h | 1 + include/SDL_config_pandora.h | 1 + include/SDL_config_wiz.h | 1 + include/SDL_stdinc.h | 18 ++----- src/SDL_compat.c | 22 +++++++++ src/audio/esd/SDL_esdaudio.c | 4 +- src/stdlib/SDL_getenv.c | 86 +++++++++++++++++++-------------- test/testime.c | 2 +- 13 files changed, 90 insertions(+), 53 deletions(-) diff --git a/configure.in b/configure.in index 4cc6b7158..1f7444cf1 100644 --- a/configure.in +++ b/configure.in @@ -207,7 +207,7 @@ if test x$enable_libc = xyes; then AC_DEFINE(HAVE_MPROTECT) ]), ) - AC_CHECK_FUNCS(malloc calloc realloc free getenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep sysctlbyname) + AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp sscanf snprintf vsnprintf sigaction setjmp nanosleep sysctlbyname) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) AC_CHECK_FUNCS(ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt) diff --git a/include/SDL_compat.h b/include/SDL_compat.h index 511d1a529..49bd9f8ca 100644 --- a/include/SDL_compat.h +++ b/include/SDL_compat.h @@ -297,6 +297,8 @@ extern DECLSPEC int SDLCALL SDL_EnableUNICODE(int enable); #define SDL_RenderFill SDL_RenderRect +extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); + /*@}*//*Compatibility*/ /* Ends C function definitions when using C++ */ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index c4b8a3cfd..ec20f5e5e 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -90,6 +90,7 @@ #undef HAVE_ALLOCA #ifndef _WIN32 /* Don't use C runtime versions of these on Windows */ #undef HAVE_GETENV +#undef HAVE_SETENV #undef HAVE_PUTENV #undef HAVE_UNSETENV #endif diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 1be963a49..2d8d565ee 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -61,7 +61,9 @@ typedef unsigned long uintptr_t; #define HAVE_FREE 1 #define HAVE_ALLOCA 1 #define HAVE_GETENV 1 +#define HAVE_SETENV 1 #define HAVE_PUTENV 1 +#define HAVE_SETENV 1 #define HAVE_UNSETENV 1 #define HAVE_QSORT 1 #define HAVE_ABS 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index 984c4e945..0ffb13df7 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -60,6 +60,7 @@ #define HAVE_FREE 1 #define HAVE_ALLOCA 1 #define HAVE_GETENV 1 +#define HAVE_SETENV 1 #define HAVE_PUTENV 1 #define HAVE_UNSETENV 1 #define HAVE_QSORT 1 diff --git a/include/SDL_config_nintendods.h b/include/SDL_config_nintendods.h index c45df8538..5f71b98d5 100644 --- a/include/SDL_config_nintendods.h +++ b/include/SDL_config_nintendods.h @@ -62,6 +62,7 @@ typedef unsigned __PTRDIFF_TYPE__ uintptr_t; #define HAVE_FREE 1 #define HAVE_ALLOCA 1 #define HAVE_GETENV 1 +#define HAVE_SETENV 1 #define HAVE_PUTENV 1 #define HAVE_QSORT 1 #define HAVE_ABS 1 diff --git a/include/SDL_config_pandora.h b/include/SDL_config_pandora.h index 38fdde40c..da05654b8 100644 --- a/include/SDL_config_pandora.h +++ b/include/SDL_config_pandora.h @@ -53,6 +53,7 @@ #define HAVE_FREE 1 #define HAVE_ALLOCA 1 #define HAVE_GETENV 1 +#define HAVE_SETENV 1 #define HAVE_PUTENV 1 #define HAVE_UNSETENV 1 #define HAVE_QSORT 1 diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h index 515cb1474..1b4b4ab33 100644 --- a/include/SDL_config_wiz.h +++ b/include/SDL_config_wiz.h @@ -58,6 +58,7 @@ #define HAVE_FREE 1 #define HAVE_ALLOCA 1 #define HAVE_GETENV 1 +#define HAVE_SETENV 1 #define HAVE_PUTENV 1 #define HAVE_UNSETENV 1 #define HAVE_QSORT 1 diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 82fb0c255..c1a5fe979 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -267,20 +267,12 @@ char *alloca(); extern DECLSPEC char *SDLCALL SDL_getenv(const char *name); #endif -/** - * \warning On some platforms, the string you pass to SDL_putenv() becomes - * part of the environment table directly...it will use this specific - * buffer, and not a copy of it! This means you can't free it, and - * other pieces of code may try to write to it. In practice, this - * isn't a big deal, but be aware of the possibility. - * However, due to this issue, you should be prepared to - * pass a (char*), or be willing to cast away the constness of your - * string for this call. - */ -#ifdef HAVE_PUTENV -#define SDL_putenv putenv +/* SDL_putenv() has moved to SDL_compat. */ +#ifdef HAVE_SETENV +#define SDL_setenv setenv #else -extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); +extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, + int overwrite); #endif #ifdef HAVE_QSORT diff --git a/src/SDL_compat.c b/src/SDL_compat.c index 798728a6d..5e0f48744 100644 --- a/src/SDL_compat.c +++ b/src/SDL_compat.c @@ -1754,4 +1754,26 @@ SDL_EnableUNICODE(int enable) return previous; } + +int +SDL_putenv(const char *_var) +{ + char *ptr = NULL; + char *var = SDL_strdup(_var); + if (var == NULL) { + return -1; /* we don't set errno. */ + } + + ptr = strchr(var, '='); + if (ptr == NULL) { + SDL_free(var); + return -1; + } + + *ptr = '\0'; /* split the string into name and value. */ + SDL_setenv(var, ptr + 1, 1); + SDL_free(var); + return 0; +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index 545520f7c..74510429d 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -321,9 +321,7 @@ ESD_Init(SDL_AudioDriverImpl * impl) int connection = 0; /* Don't start ESD if it's not running */ - if (SDL_getenv("ESD_NO_SPAWN") == NULL) { - SDL_putenv("ESD_NO_SPAWN=1"); - } + SDL_setenv("ESD_NO_SPAWN", "1", 0); connection = SDL_NAME(esd_open_sound) (NULL); if (connection < 0) { diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index 54d53a049..89d3386c1 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -35,31 +35,18 @@ static char *SDL_envmem = NULL; /* Ugh, memory leak */ static size_t SDL_envmemlen = 0; -/* Put a variable of the form "name=value" into the environment */ +/* Put a variable into the environment */ int -SDL_putenv(const char *variable) +SDL_setenv(const char *name, const char *value, int overwrite) { - size_t bufferlen; - char *value; - const char *sep; - - sep = SDL_strchr(variable, '='); - if (sep == NULL) { - return -1; - } - bufferlen = SDL_strlen(variable) + 1; - if (bufferlen > SDL_envmemlen) { - char *newmem = (char *) SDL_realloc(SDL_envmem, bufferlen); - if (newmem == NULL) { - return -1; + if (!overwrite) { + char ch = 0; + const size_t len = GetEnvironmentVariable(name, &ch, sizeof (ch)); + if (len > 0) { + return 0; /* asked not to overwrite existing value. */ } - SDL_envmem = newmem; - SDL_envmemlen = bufferlen; } - SDL_strlcpy(SDL_envmem, variable, bufferlen); - value = SDL_envmem + (sep - variable); - *value++ = '\0'; - if (!SetEnvironmentVariable(SDL_envmem, *value ? value : NULL)) { + if (!SetEnvironmentVariable(name, *value ? value : NULL)) { return -1; } return 0; @@ -92,36 +79,31 @@ SDL_getenv(const char *name) static char **SDL_env = (char **) 0; -/* Put a variable of the form "name=value" into the environment */ +/* Put a variable into the environment */ int -SDL_putenv(const char *variable) +SDL_setenv(const char *name, const char *value, int overwrite) { - const char *name, *value; int added; int len, i; char **new_env; char *new_variable; /* A little error checking */ - if (!variable) { - return (-1); - } - name = variable; - for (value = variable; *value && (*value != '='); ++value) { - /* Keep looking for '=' */ ; - } - if (*value) { - ++value; - } else { + if (!name || !value) { return (-1); } /* Allocate memory for the variable */ - new_variable = SDL_strdup(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; @@ -135,6 +117,10 @@ SDL_putenv(const char *variable) } /* If we found it, just replace the entry */ if (SDL_env[i]) { + if (!overwrite) { + SDL_free(new_variable); + return 0; + } SDL_free(SDL_env[i]); SDL_env[i] = new_variable; added = 1; @@ -180,6 +166,36 @@ SDL_getenv(const char *name) #endif /* !HAVE_GETENV */ + +/* We have a real environment table, but no real setenv? Fake it w/ putenv. */ +#if (defined(HAVE_GETENV) && defined(HAVE_PUTENV) && !defined(HAVE_SETENV)) +int +SDL_setenv(const char *name, const char *value, int overwrite) +{ + size_t len; + char *new_variable; + + if (getenv(name) != NULL) { + if (overwrite) { + unsetenv(name); + } else { + return 0; /* leave the existing one there. */ + } + } + + /* This leaks. Sorry. Get a better OS so we don't have to do this. */ + 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); + return putenv(new_variable); +} +#endif + + #ifdef TEST_MAIN #include diff --git a/test/testime.c b/test/testime.c index 1cd9dbd25..cf6768ac8 100644 --- a/test/testime.c +++ b/test/testime.c @@ -60,7 +60,7 @@ void InitVideo(int argc, char *argv[]) } } - SDL_putenv("SDL_VIDEO_WINDOW_POS=center"); + SDL_setenv("SDL_VIDEO_WINDOW_POS", "center", 1); if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());