591a314f6d14e0a649ab533c6833fe25e19c3815
[platform/upstream/SDL.git] / src / stdlib / SDL_getenv.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2018 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 #if defined(__ANDROID__)
33 #include "../core/android/SDL_android.h"
34 #endif
35
36 #include "SDL_stdinc.h"
37
38 #if defined(__WIN32__) && (!defined(HAVE_SETENV) || !defined(HAVE_GETENV))
39 /* Note this isn't thread-safe! */
40 static char *SDL_envmem = NULL; /* Ugh, memory leak */
41 static size_t SDL_envmemlen = 0;
42 #endif
43
44 /* Put a variable into the environment */
45 /* Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/) */
46 #if defined(HAVE_SETENV)
47 int
48 SDL_setenv(const char *name, const char *value, int overwrite)
49 {
50     /* Input validation */
51     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
52         return (-1);
53     }
54     
55     return setenv(name, value, overwrite);
56 }
57 #elif defined(__WIN32__)
58 int
59 SDL_setenv(const char *name, const char *value, int overwrite)
60 {
61     /* Input validation */
62     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
63         return (-1);
64     }
65     
66     if (!overwrite) {
67         if (GetEnvironmentVariableA(name, NULL, 0) > 0) {
68             return 0;  /* asked not to overwrite existing value. */
69         }
70     }
71     if (!SetEnvironmentVariableA(name, *value ? value : NULL)) {
72         return -1;
73     }
74     return 0;
75 }
76 /* We have a real environment table, but no real setenv? Fake it w/ putenv. */
77 #elif (defined(HAVE_GETENV) && defined(HAVE_PUTENV) && !defined(HAVE_SETENV))
78 int
79 SDL_setenv(const char *name, const char *value, int overwrite)
80 {
81     size_t len;
82     char *new_variable;
83
84     /* Input validation */
85     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
86         return (-1);
87     }
88     
89     if (getenv(name) != NULL) {
90         if (overwrite) {
91             unsetenv(name);
92         } else {
93             return 0;  /* leave the existing one there. */
94         }
95     }
96
97     /* This leaks. Sorry. Get a better OS so we don't have to do this. */
98     len = SDL_strlen(name) + SDL_strlen(value) + 2;
99     new_variable = (char *) SDL_malloc(len);
100     if (!new_variable) {
101         return (-1);
102     }
103
104     SDL_snprintf(new_variable, len, "%s=%s", name, value);
105     return putenv(new_variable);
106 }
107 #else /* roll our own */
108 static char **SDL_env = (char **) 0;
109 int
110 SDL_setenv(const char *name, const char *value, int overwrite)
111 {
112     int added;
113     int len, i;
114     char **new_env;
115     char *new_variable;
116
117     /* Input validation */
118     if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) {
119         return (-1);
120     }
121
122     /* See if it already exists */
123     if (!overwrite && SDL_getenv(name)) {
124         return 0;
125     }
126
127     /* Allocate memory for the variable */
128     len = SDL_strlen(name) + SDL_strlen(value) + 2;
129     new_variable = (char *) SDL_malloc(len);
130     if (!new_variable) {
131         return (-1);
132     }
133
134     SDL_snprintf(new_variable, len, "%s=%s", name, value);
135     value = new_variable + SDL_strlen(name) + 1;
136     name = new_variable;
137
138     /* Actually put it into the environment */
139     added = 0;
140     i = 0;
141     if (SDL_env) {
142         /* Check to see if it's already there... */
143         len = (value - name);
144         for (; SDL_env[i]; ++i) {
145             if (SDL_strncmp(SDL_env[i], name, len) == 0) {
146                 break;
147             }
148         }
149         /* If we found it, just replace the entry */
150         if (SDL_env[i]) {
151             SDL_free(SDL_env[i]);
152             SDL_env[i] = new_variable;
153             added = 1;
154         }
155     }
156
157     /* Didn't find it in the environment, expand and add */
158     if (!added) {
159         new_env = SDL_realloc(SDL_env, (i + 2) * sizeof(char *));
160         if (new_env) {
161             SDL_env = new_env;
162             SDL_env[i++] = new_variable;
163             SDL_env[i++] = (char *) 0;
164             added = 1;
165         } else {
166             SDL_free(new_variable);
167         }
168     }
169     return (added ? 0 : -1);
170 }
171 #endif
172
173 /* Retrieve a variable named "name" from the environment */
174 #if defined(HAVE_GETENV)
175 char *
176 SDL_getenv(const char *name)
177 {
178 #if defined(__ANDROID__)
179     /* Make sure variables from the application manifest are available */
180     Android_JNI_GetManifestEnvironmentVariables();
181 #endif
182
183     /* Input validation */
184     if (!name || !*name) {
185         return NULL;
186     }
187
188     return getenv(name);
189 }
190 #elif defined(__WIN32__)
191 char *
192 SDL_getenv(const char *name)
193 {
194     size_t bufferlen;
195
196     /* Input validation */
197     if (!name || SDL_strlen(name)==0) {
198         return NULL;
199     }
200     
201     bufferlen =
202         GetEnvironmentVariableA(name, SDL_envmem, (DWORD) SDL_envmemlen);
203     if (bufferlen == 0) {
204         return NULL;
205     }
206     if (bufferlen > SDL_envmemlen) {
207         char *newmem = (char *) SDL_realloc(SDL_envmem, bufferlen);
208         if (newmem == NULL) {
209             return NULL;
210         }
211         SDL_envmem = newmem;
212         SDL_envmemlen = bufferlen;
213         GetEnvironmentVariableA(name, SDL_envmem, (DWORD) SDL_envmemlen);
214     }
215     return SDL_envmem;
216 }
217 #else
218 char *
219 SDL_getenv(const char *name)
220 {
221     int len, i;
222     char *value;
223
224     /* Input validation */
225     if (!name || SDL_strlen(name)==0) {
226         return NULL;
227     }
228     
229     value = (char *) 0;
230     if (SDL_env) {
231         len = SDL_strlen(name);
232         for (i = 0; SDL_env[i] && !value; ++i) {
233             if ((SDL_strncmp(SDL_env[i], name, len) == 0) &&
234                 (SDL_env[i][len] == '=')) {
235                 value = &SDL_env[i][len + 1];
236             }
237         }
238     }
239     return value;
240 }
241 #endif
242
243
244 #ifdef TEST_MAIN
245 #include <stdio.h>
246
247 int
248 main(int argc, char *argv[])
249 {
250     char *value;
251
252     printf("Checking for non-existent variable... ");
253     fflush(stdout);
254     if (!SDL_getenv("EXISTS")) {
255         printf("okay\n");
256     } else {
257         printf("failed\n");
258     }
259     printf("Setting FIRST=VALUE1 in the environment... ");
260     fflush(stdout);
261     if (SDL_setenv("FIRST", "VALUE1", 0) == 0) {
262         printf("okay\n");
263     } else {
264         printf("failed\n");
265     }
266     printf("Getting FIRST from the environment... ");
267     fflush(stdout);
268     value = SDL_getenv("FIRST");
269     if (value && (SDL_strcmp(value, "VALUE1") == 0)) {
270         printf("okay\n");
271     } else {
272         printf("failed\n");
273     }
274     printf("Setting SECOND=VALUE2 in the environment... ");
275     fflush(stdout);
276     if (SDL_setenv("SECOND", "VALUE2", 0) == 0) {
277         printf("okay\n");
278     } else {
279         printf("failed\n");
280     }
281     printf("Getting SECOND from the environment... ");
282     fflush(stdout);
283     value = SDL_getenv("SECOND");
284     if (value && (SDL_strcmp(value, "VALUE2") == 0)) {
285         printf("okay\n");
286     } else {
287         printf("failed\n");
288     }
289     printf("Setting FIRST=NOVALUE in the environment... ");
290     fflush(stdout);
291     if (SDL_setenv("FIRST", "NOVALUE", 1) == 0) {
292         printf("okay\n");
293     } else {
294         printf("failed\n");
295     }
296     printf("Getting FIRST from the environment... ");
297     fflush(stdout);
298     value = SDL_getenv("FIRST");
299     if (value && (SDL_strcmp(value, "NOVALUE") == 0)) {
300         printf("okay\n");
301     } else {
302         printf("failed\n");
303     }
304     printf("Checking for non-existent variable... ");
305     fflush(stdout);
306     if (!SDL_getenv("EXISTS")) {
307         printf("okay\n");
308     } else {
309         printf("failed\n");
310     }
311     return (0);
312 }
313 #endif /* TEST_MAIN */
314
315 /* vi: set ts=4 sw=4 expandtab: */