src/stdlib/SDL_getenv.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Aug 2017 21:30:06 -0700
changeset 11232 b26929d6ca20
parent 10737 3406a0f8b041
permissions -rw-r--r--
Fixed bug 3284 - minor correction for SDL_setenv on _WIN32__ platform

Coriiander

Here is a minor correction for a non-breaking mistake in SDL_setenv for __WIN32__ platform. See below for details.

FILE:
"SDL/src/stdlib/SDL_getenv.c"

FUNCTION: (__WIN32__ platform)
int SDL_setenv(const char *name, const char *value, int overwrite)

CODE:
if (!overwrite) {
char ch = 0;
const size_t len = GetEnvironmentVariableA(name, &ch, sizeof (ch));
if (len > 0) {
return 0; /* asked not to overwrite existing value. */
}
}


WHAT'S WRONG:
The 3th argument to GetEnvironmentVariable (being DWORD nSize) must be the number of characters, not the number of bytes. SDL currently passes "the size of 1 char", rather "1". While it is non-breaking (1=1 after all), it is incorrect. Furthermore there is no need to specify the 2nd and 3th arguments at all.

CORRECTION 1: (corrected argument_
if (!overwrite) {
char ch = 0;
const size_t len = GetEnvironmentVariableA(name, &ch, 1);
if (len > 0) {
return 0; /* asked not to overwrite existing value. */
}
}

CORRECTION 2: (stripped of unneeded code)
if (!overwrite) {
if (GetEnvironmentVariableA(name, NULL, 0) > 0) {
return 0; /* asked not to overwrite existing value. */
}
}
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS)
    23 #define SDL_DISABLE_ANALYZE_MACROS 1
    24 #endif
    25 
    26 #include "../SDL_internal.h"
    27 
    28 #if defined(__WIN32__)
    29 #include "../core/windows/SDL_windows.h"
    30 #endif
    31 
    32 #include "SDL_stdinc.h"
    33 
    34 #if defined(__WIN32__) && (!defined(HAVE_SETENV) || !defined(HAVE_GETENV))
    35 /* Note this isn't thread-safe! */
    36 static char *SDL_envmem = NULL; /* Ugh, memory leak */
    37 static size_t SDL_envmemlen = 0;
    38 #endif
    39 
    40 /* Put a variable into the environment */
    41 /* Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/) */
    42 #if defined(HAVE_SETENV)
    43 int
    44 SDL_setenv(const char *name, const char *value, int overwrite)
    45 {
    46     /* Input validation */
    47     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
    48         return (-1);
    49     }
    50     
    51     return setenv(name, value, overwrite);
    52 }
    53 #elif defined(__WIN32__)
    54 int
    55 SDL_setenv(const char *name, const char *value, int overwrite)
    56 {
    57     /* Input validation */
    58     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
    59         return (-1);
    60     }
    61     
    62     if (!overwrite) {
    63         if (GetEnvironmentVariableA(name, NULL, 0) > 0) {
    64             return 0;  /* asked not to overwrite existing value. */
    65         }
    66     }
    67     if (!SetEnvironmentVariableA(name, *value ? value : NULL)) {
    68         return -1;
    69     }
    70     return 0;
    71 }
    72 /* We have a real environment table, but no real setenv? Fake it w/ putenv. */
    73 #elif (defined(HAVE_GETENV) && defined(HAVE_PUTENV) && !defined(HAVE_SETENV))
    74 int
    75 SDL_setenv(const char *name, const char *value, int overwrite)
    76 {
    77     size_t len;
    78     char *new_variable;
    79 
    80     /* Input validation */
    81     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
    82         return (-1);
    83     }
    84     
    85     if (getenv(name) != NULL) {
    86         if (overwrite) {
    87             unsetenv(name);
    88         } else {
    89             return 0;  /* leave the existing one there. */
    90         }
    91     }
    92 
    93     /* This leaks. Sorry. Get a better OS so we don't have to do this. */
    94     len = SDL_strlen(name) + SDL_strlen(value) + 2;
    95     new_variable = (char *) SDL_malloc(len);
    96     if (!new_variable) {
    97         return (-1);
    98     }
    99 
   100     SDL_snprintf(new_variable, len, "%s=%s", name, value);
   101     return putenv(new_variable);
   102 }
   103 #else /* roll our own */
   104 static char **SDL_env = (char **) 0;
   105 int
   106 SDL_setenv(const char *name, const char *value, int overwrite)
   107 {
   108     int added;
   109     int len, i;
   110     char **new_env;
   111     char *new_variable;
   112 
   113     /* Input validation */
   114     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
   115         return (-1);
   116     }
   117 
   118     /* See if it already exists */
   119     if (!overwrite && SDL_getenv(name)) {
   120         return 0;
   121     }
   122 
   123     /* Allocate memory for the variable */
   124     len = SDL_strlen(name) + SDL_strlen(value) + 2;
   125     new_variable = (char *) SDL_malloc(len);
   126     if (!new_variable) {
   127         return (-1);
   128     }
   129 
   130     SDL_snprintf(new_variable, len, "%s=%s", name, value);
   131     value = new_variable + SDL_strlen(name) + 1;
   132     name = new_variable;
   133 
   134     /* Actually put it into the environment */
   135     added = 0;
   136     i = 0;
   137     if (SDL_env) {
   138         /* Check to see if it's already there... */
   139         len = (value - name);
   140         for (; SDL_env[i]; ++i) {
   141             if (SDL_strncmp(SDL_env[i], name, len) == 0) {
   142                 break;
   143             }
   144         }
   145         /* If we found it, just replace the entry */
   146         if (SDL_env[i]) {
   147             SDL_free(SDL_env[i]);
   148             SDL_env[i] = new_variable;
   149             added = 1;
   150         }
   151     }
   152 
   153     /* Didn't find it in the environment, expand and add */
   154     if (!added) {
   155         new_env = SDL_realloc(SDL_env, (i + 2) * sizeof(char *));
   156         if (new_env) {
   157             SDL_env = new_env;
   158             SDL_env[i++] = new_variable;
   159             SDL_env[i++] = (char *) 0;
   160             added = 1;
   161         } else {
   162             SDL_free(new_variable);
   163         }
   164     }
   165     return (added ? 0 : -1);
   166 }
   167 #endif
   168 
   169 /* Retrieve a variable named "name" from the environment */
   170 #if defined(HAVE_GETENV)
   171 char *
   172 SDL_getenv(const char *name)
   173 {
   174     /* Input validation */
   175     if (!name || SDL_strlen(name)==0) {
   176         return NULL;
   177     }
   178 
   179     return getenv(name);
   180 }
   181 #elif defined(__WIN32__)
   182 char *
   183 SDL_getenv(const char *name)
   184 {
   185     size_t bufferlen;
   186 
   187     /* Input validation */
   188     if (!name || SDL_strlen(name)==0) {
   189         return NULL;
   190     }
   191     
   192     bufferlen =
   193         GetEnvironmentVariableA(name, SDL_envmem, (DWORD) SDL_envmemlen);
   194     if (bufferlen == 0) {
   195         return NULL;
   196     }
   197     if (bufferlen > SDL_envmemlen) {
   198         char *newmem = (char *) SDL_realloc(SDL_envmem, bufferlen);
   199         if (newmem == NULL) {
   200             return NULL;
   201         }
   202         SDL_envmem = newmem;
   203         SDL_envmemlen = bufferlen;
   204         GetEnvironmentVariableA(name, SDL_envmem, (DWORD) SDL_envmemlen);
   205     }
   206     return SDL_envmem;
   207 }
   208 #else
   209 char *
   210 SDL_getenv(const char *name)
   211 {
   212     int len, i;
   213     char *value;
   214 
   215     /* Input validation */
   216     if (!name || SDL_strlen(name)==0) {
   217         return NULL;
   218     }
   219     
   220     value = (char *) 0;
   221     if (SDL_env) {
   222         len = SDL_strlen(name);
   223         for (i = 0; SDL_env[i] && !value; ++i) {
   224             if ((SDL_strncmp(SDL_env[i], name, len) == 0) &&
   225                 (SDL_env[i][len] == '=')) {
   226                 value = &SDL_env[i][len + 1];
   227             }
   228         }
   229     }
   230     return value;
   231 }
   232 #endif
   233 
   234 
   235 #ifdef TEST_MAIN
   236 #include <stdio.h>
   237 
   238 int
   239 main(int argc, char *argv[])
   240 {
   241     char *value;
   242 
   243     printf("Checking for non-existent variable... ");
   244     fflush(stdout);
   245     if (!SDL_getenv("EXISTS")) {
   246         printf("okay\n");
   247     } else {
   248         printf("failed\n");
   249     }
   250     printf("Setting FIRST=VALUE1 in the environment... ");
   251     fflush(stdout);
   252     if (SDL_setenv("FIRST", "VALUE1", 0) == 0) {
   253         printf("okay\n");
   254     } else {
   255         printf("failed\n");
   256     }
   257     printf("Getting FIRST from the environment... ");
   258     fflush(stdout);
   259     value = SDL_getenv("FIRST");
   260     if (value && (SDL_strcmp(value, "VALUE1") == 0)) {
   261         printf("okay\n");
   262     } else {
   263         printf("failed\n");
   264     }
   265     printf("Setting SECOND=VALUE2 in the environment... ");
   266     fflush(stdout);
   267     if (SDL_setenv("SECOND", "VALUE2", 0) == 0) {
   268         printf("okay\n");
   269     } else {
   270         printf("failed\n");
   271     }
   272     printf("Getting SECOND from the environment... ");
   273     fflush(stdout);
   274     value = SDL_getenv("SECOND");
   275     if (value && (SDL_strcmp(value, "VALUE2") == 0)) {
   276         printf("okay\n");
   277     } else {
   278         printf("failed\n");
   279     }
   280     printf("Setting FIRST=NOVALUE in the environment... ");
   281     fflush(stdout);
   282     if (SDL_setenv("FIRST", "NOVALUE", 1) == 0) {
   283         printf("okay\n");
   284     } else {
   285         printf("failed\n");
   286     }
   287     printf("Getting FIRST from the environment... ");
   288     fflush(stdout);
   289     value = SDL_getenv("FIRST");
   290     if (value && (SDL_strcmp(value, "NOVALUE") == 0)) {
   291         printf("okay\n");
   292     } else {
   293         printf("failed\n");
   294     }
   295     printf("Checking for non-existent variable... ");
   296     fflush(stdout);
   297     if (!SDL_getenv("EXISTS")) {
   298         printf("okay\n");
   299     } else {
   300         printf("failed\n");
   301     }
   302     return (0);
   303 }
   304 #endif /* TEST_MAIN */
   305 
   306 /* vi: set ts=4 sw=4 expandtab: */