1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 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 | size_t 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 | size_t 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: */ |
316 | |