msvcrt: Hold _ENV_LOCK when accessing environment variables.
[wine.git] / dlls / msvcrt / environ.c
blob9e358d971f9fc96d6ef80e577bc96afaf91593ec
1 /*
2 * msvcrt.dll environment functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "msvcrt.h"
24 #include "mtdll.h"
25 #include <winnls.h>
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
30 int env_init(BOOL unicode, BOOL modif)
32 if (!unicode && !MSVCRT___initenv)
34 char *environ_strings = GetEnvironmentStringsA();
35 int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
36 char *ptr;
38 for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
40 /* Don't count environment variables starting with '=' which are command shell specific */
41 if (*ptr != '=') count++;
42 len += strlen(ptr) + 1;
44 MSVCRT___initenv = malloc(count * sizeof(*MSVCRT___initenv) + len);
45 if (!MSVCRT___initenv)
47 FreeEnvironmentStringsA(environ_strings);
48 return -1;
51 memcpy(&MSVCRT___initenv[count], environ_strings, len);
52 for (ptr = (char *)&MSVCRT___initenv[count]; *ptr; ptr += strlen(ptr) + 1)
54 /* Skip special environment strings set by the command shell */
55 if (*ptr != '=') MSVCRT___initenv[i++] = ptr;
57 MSVCRT___initenv[i] = NULL;
58 FreeEnvironmentStringsA(environ_strings);
60 MSVCRT__environ = MSVCRT___initenv;
63 if (!unicode && modif && MSVCRT__environ == MSVCRT___initenv)
65 int i = 0;
67 while(MSVCRT___initenv[i]) i++;
68 MSVCRT__environ = malloc((i + 1) * sizeof(char *));
69 if (!MSVCRT__environ) return -1;
70 for (i = 0; MSVCRT___initenv[i]; i++)
71 MSVCRT__environ[i] = strdup(MSVCRT___initenv[i]);
72 MSVCRT__environ[i] = NULL;
75 if (unicode && !MSVCRT___winitenv)
77 wchar_t *wenviron_strings = GetEnvironmentStringsW();
78 int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
79 wchar_t *wptr;
81 for (wptr = wenviron_strings; *wptr; wptr += wcslen(wptr) + 1)
83 /* Don't count environment variables starting with '=' which are command shell specific */
84 if (*wptr != '=') count++;
85 len += wcslen(wptr) + 1;
87 MSVCRT___winitenv = malloc(count * sizeof(*MSVCRT___winitenv) + len * sizeof(wchar_t));
88 if (!MSVCRT___winitenv)
90 FreeEnvironmentStringsW(wenviron_strings);
91 return -1;
94 memcpy(&MSVCRT___winitenv[count], wenviron_strings, len * sizeof(wchar_t));
95 for (wptr = (wchar_t *)&MSVCRT___winitenv[count]; *wptr; wptr += wcslen(wptr) + 1)
97 /* Skip special environment strings set by the command shell */
98 if (*wptr != '=') MSVCRT___winitenv[i++] = wptr;
100 MSVCRT___winitenv[i] = NULL;
101 FreeEnvironmentStringsW(wenviron_strings);
103 MSVCRT__wenviron = MSVCRT___winitenv;
106 if (unicode && modif && MSVCRT__wenviron == MSVCRT___winitenv)
108 int i = 0;
110 while(MSVCRT___winitenv[i]) i++;
111 MSVCRT__wenviron = malloc((i + 1) * sizeof(wchar_t *));
112 if (!MSVCRT__wenviron) return -1;
113 for (i = 0; MSVCRT___winitenv[i]; i++)
114 MSVCRT__wenviron[i] = wcsdup(MSVCRT___winitenv[i]);
115 MSVCRT__wenviron[i] = NULL;
118 return 0;
121 static int env_get_index(const char *name)
123 int i, len;
125 len = strlen(name);
126 for (i = 0; MSVCRT__environ[i]; i++)
128 if (!strncmp(name, MSVCRT__environ[i], len) && MSVCRT__environ[i][len] == '=')
129 return i;
131 return i;
134 static int wenv_get_index(const wchar_t *name)
136 int i, len;
138 len = wcslen(name);
139 for (i = 0; MSVCRT__wenviron[i]; i++)
141 if (!wcsncmp(name, MSVCRT__wenviron[i], len) && MSVCRT__wenviron[i][len] == '=')
142 return i;
144 return i;
147 static int env_set(char **env, wchar_t **wenv)
149 wchar_t *weq = wcschr(*wenv, '=');
150 char *eq = strchr(*env, '=');
151 int idx;
153 *weq = 0;
154 if (!SetEnvironmentVariableW(*wenv, weq[1] ? weq + 1 : NULL) &&
155 GetLastError() != ERROR_ENVVAR_NOT_FOUND)
156 return -1;
158 *eq = 0;
159 idx = env_get_index(*env);
160 *eq = '=';
161 if (!eq[1])
163 for(; MSVCRT__environ[idx]; idx++)
164 MSVCRT__environ[idx] = MSVCRT__environ[idx + 1];
166 else if (MSVCRT__environ[idx])
168 free(MSVCRT__environ[idx]);
169 MSVCRT__environ[idx] = *env;
170 *env = NULL;
172 else
174 char **new_env = realloc(MSVCRT__environ, (idx + 2) * sizeof(*MSVCRT__environ));
175 if (!new_env) return -1;
176 MSVCRT__environ = new_env;
177 MSVCRT__environ[idx] = *env;
178 MSVCRT__environ[idx + 1] = NULL;
179 *env = NULL;
182 if (!MSVCRT__wenviron) return 0;
183 idx = wenv_get_index(*wenv);
184 *weq = '=';
185 if (!weq[1])
187 for(; MSVCRT__wenviron[idx]; idx++)
188 MSVCRT__wenviron[idx] = MSVCRT__wenviron[idx + 1];
190 else if (MSVCRT__wenviron[idx])
192 free(MSVCRT__wenviron[idx]);
193 MSVCRT__wenviron[idx] = *wenv;
194 *wenv = NULL;
196 else
198 wchar_t **new_env = realloc(MSVCRT__wenviron, (idx + 2) * sizeof(*MSVCRT__wenviron));
199 if (!new_env) return -1;
200 MSVCRT__wenviron = new_env;
201 MSVCRT__wenviron[idx] = *wenv;
202 MSVCRT__wenviron[idx + 1] = NULL;
203 *wenv = NULL;
205 return 0;
208 static char * getenv_helper(const char *name)
210 int idx;
212 if (!name) return NULL;
214 idx = env_get_index(name);
215 if (!MSVCRT__environ[idx]) return NULL;
216 return strchr(MSVCRT__environ[idx], '=') + 1;
219 /*********************************************************************
220 * getenv (MSVCRT.@)
222 char * CDECL getenv(const char *name)
224 char *ret;
226 if (!MSVCRT_CHECK_PMT(name != NULL)) return NULL;
228 _lock(_ENV_LOCK);
229 ret = getenv_helper(name);
230 _unlock(_ENV_LOCK);
231 return ret;
234 static wchar_t * wgetenv_helper(const wchar_t *name)
236 int idx;
238 if (!name) return NULL;
239 if (env_init(TRUE, FALSE)) return NULL;
241 idx = wenv_get_index(name);
242 if (!MSVCRT__wenviron[idx]) return NULL;
243 return wcschr(MSVCRT__wenviron[idx], '=') + 1;
246 /*********************************************************************
247 * _wgetenv (MSVCRT.@)
249 wchar_t * CDECL _wgetenv(const wchar_t *name)
251 wchar_t *ret;
253 if (!MSVCRT_CHECK_PMT(name != NULL)) return NULL;
255 _lock(_ENV_LOCK);
256 ret = wgetenv_helper(name);
257 _unlock(_ENV_LOCK);
258 return ret;
261 static int putenv_helper(const char *name, const char *val, const char *eq)
263 wchar_t *wenv;
264 char *env;
265 int r;
267 _lock(_ENV_LOCK);
268 r = env_init(FALSE, TRUE);
269 _unlock(_ENV_LOCK);
270 if (r) return -1;
272 if (eq)
274 env = strdup(name);
275 if (!env) return -1;
277 else
279 int name_len = strlen(name);
281 r = strlen(val);
282 env = malloc(name_len + r + 2);
283 if (!env) return -1;
284 memcpy(env, name, name_len);
285 env[name_len] = '=';
286 strcpy(env + name_len + 1, val);
289 wenv = msvcrt_wstrdupa(env);
290 if (!wenv)
292 free(env);
293 return -1;
296 _lock(_ENV_LOCK);
297 r = env_set(&env, &wenv);
298 _unlock(_ENV_LOCK);
299 free(env);
300 free(wenv);
301 return r;
304 static char *msvcrt_astrdupw(const wchar_t *wstr)
306 const unsigned int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
307 char *str = malloc(len * sizeof(char));
309 if (!str)
310 return NULL;
311 WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
312 return str;
316 static int wputenv_helper(const wchar_t *name, const wchar_t *val, const wchar_t *eq)
318 wchar_t *wenv;
319 char *env;
320 int r;
322 _lock(_ENV_LOCK);
323 r = env_init(TRUE, TRUE);
324 _unlock(_ENV_LOCK);
325 if (r) return -1;
327 if (eq)
329 wenv = wcsdup(name);
330 if (!wenv) return -1;
332 else
334 int name_len = wcslen(name);
336 r = wcslen(val);
337 wenv = malloc((name_len + r + 2) * sizeof(wchar_t));
338 if (!wenv) return -1;
339 memcpy(wenv, name, name_len * sizeof(wchar_t));
340 wenv[name_len] = '=';
341 wcscpy(wenv + name_len + 1, val);
344 env = msvcrt_astrdupw(wenv);
345 if (!env)
347 free(wenv);
348 return -1;
351 _lock(_ENV_LOCK);
352 r = env_set(&env, &wenv);
353 _unlock(_ENV_LOCK);
354 free(env);
355 free(wenv);
356 return r;
359 /*********************************************************************
360 * _putenv (MSVCRT.@)
362 int CDECL _putenv(const char *str)
364 const char *eq;
366 TRACE("%s\n", debugstr_a(str));
368 if (!str || !(eq = strchr(str, '=')))
369 return -1;
371 return putenv_helper(str, NULL, eq);
374 /*********************************************************************
375 * _wputenv (MSVCRT.@)
377 int CDECL _wputenv(const wchar_t *str)
379 const wchar_t *eq;
381 TRACE("%s\n", debugstr_w(str));
383 if (!str || !(eq = wcschr(str, '=')))
384 return -1;
386 return wputenv_helper(str, NULL, eq);
389 /*********************************************************************
390 * _putenv_s (MSVCRT.@)
392 errno_t CDECL _putenv_s(const char *name, const char *value)
394 errno_t ret = 0;
396 TRACE("%s %s\n", debugstr_a(name), debugstr_a(value));
398 if (!MSVCRT_CHECK_PMT(name != NULL)) return EINVAL;
399 if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
401 if (putenv_helper(name, value, NULL) < 0)
403 msvcrt_set_errno(GetLastError());
404 ret = *_errno();
407 return ret;
410 /*********************************************************************
411 * _wputenv_s (MSVCRT.@)
413 errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value)
415 errno_t ret = 0;
417 TRACE("%s %s\n", debugstr_w(name), debugstr_w(value));
419 if (!MSVCRT_CHECK_PMT(name != NULL)) return EINVAL;
420 if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
422 if (wputenv_helper(name, value, NULL) < 0)
424 msvcrt_set_errno(GetLastError());
425 ret = *_errno();
428 return ret;
431 #if _MSVCR_VER>=80
433 /******************************************************************
434 * _dupenv_s (MSVCR80.@)
436 int CDECL _dupenv_s(char **buffer, size_t *numberOfElements, const char *varname)
438 char *e;
439 size_t sz;
441 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
442 if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL;
444 _lock(_ENV_LOCK);
445 if (!(e = getenv(varname)))
447 _unlock(_ENV_LOCK);
448 *buffer = NULL;
449 if (numberOfElements) *numberOfElements = 0;
450 return 0;
453 sz = strlen(e) + 1;
454 *buffer = malloc(sz);
455 if (*buffer) strcpy(*buffer, e);
456 _unlock(_ENV_LOCK);
458 if (!*buffer)
460 if (numberOfElements) *numberOfElements = 0;
461 return *_errno() = ENOMEM;
463 if (numberOfElements) *numberOfElements = sz;
464 return 0;
467 /******************************************************************
468 * _wdupenv_s (MSVCR80.@)
470 int CDECL _wdupenv_s(wchar_t **buffer, size_t *numberOfElements,
471 const wchar_t *varname)
473 wchar_t *e;
474 size_t sz;
476 if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
477 if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL;
479 _lock(_ENV_LOCK);
480 if (!(e = _wgetenv(varname)))
482 _unlock(_ENV_LOCK);
483 *buffer = NULL;
484 if (numberOfElements) *numberOfElements = 0;
485 return 0;
488 sz = wcslen(e) + 1;
489 *buffer = malloc(sz * sizeof(wchar_t));
490 if (*buffer) wcscpy(*buffer, e);
491 _unlock(_ENV_LOCK);
493 if (!*buffer)
495 if (numberOfElements) *numberOfElements = 0;
496 return *_errno() = ENOMEM;
498 if (numberOfElements) *numberOfElements = sz;
499 return 0;
502 #endif /* _MSVCR_VER>=80 */
504 /******************************************************************
505 * getenv_s (MSVCRT.@)
507 int CDECL getenv_s(size_t *ret_len, char* buffer, size_t len, const char *varname)
509 char *e;
511 if (!MSVCRT_CHECK_PMT(ret_len != NULL)) return EINVAL;
512 *ret_len = 0;
513 if (!MSVCRT_CHECK_PMT((buffer && len > 0) || (!buffer && !len))) return EINVAL;
514 if (buffer) buffer[0] = 0;
516 _lock(_ENV_LOCK);
517 e = getenv_helper(varname);
518 if (e)
520 *ret_len = strlen(e) + 1;
521 if (len >= *ret_len) strcpy(buffer, e);
523 _unlock(_ENV_LOCK);
525 if (!e || !len) return 0;
526 if (len < *ret_len) return ERANGE;
527 return 0;
530 /******************************************************************
531 * _wgetenv_s (MSVCRT.@)
533 int CDECL _wgetenv_s(size_t *ret_len, wchar_t *buffer, size_t len,
534 const wchar_t *varname)
536 wchar_t *e;
538 if (!MSVCRT_CHECK_PMT(ret_len != NULL)) return EINVAL;
539 *ret_len = 0;
540 if (!MSVCRT_CHECK_PMT((buffer && len > 0) || (!buffer && !len))) return EINVAL;
541 if (buffer) buffer[0] = 0;
543 _lock(_ENV_LOCK);
544 e = wgetenv_helper(varname);
545 if (e)
547 *ret_len = wcslen(e) + 1;
548 if (len >= *ret_len) wcscpy(buffer, e);
550 _unlock(_ENV_LOCK);
552 if (!e || !len) return 0;
553 if (len < *ret_len) return ERANGE;
554 return 0;
557 /*********************************************************************
558 * _get_environ (MSVCRT.@)
560 void CDECL _get_environ(char ***ptr)
562 *ptr = MSVCRT__environ;
565 /*********************************************************************
566 * _get_wenviron (MSVCRT.@)
568 void CDECL _get_wenviron(wchar_t ***ptr)
570 *ptr = MSVCRT__wenviron;