Synchronize with trunk.
[reactos.git] / lib / sdk / crt / misc / environ.c
1 /*
2 * environ.c
3 *
4 * ReactOS MSVCRT.DLL Compatibility Library
5 */
6
7 #include <precomp.h>
8 #include <internal/wine/msvcrt.h>
9
10 unsigned int _osplatform = 0;
11 unsigned int _osver = 0;
12 unsigned int _winminor = 0;
13 unsigned int _winmajor = 0;
14 unsigned int _winver = 0;
15
16 unsigned int __setlc_active = 0;
17 unsigned int __unguarded_readlc_active = 0;
18 char *_acmdln = NULL; /* pointer to ascii command line */
19 wchar_t *_wcmdln = NULL; /* pointer to wide character command line */
20 #undef _environ
21 #undef _wenviron
22 char **_environ = NULL; /* pointer to environment block */
23 wchar_t **_wenviron = NULL; /* pointer to environment block */
24 char **__initenv = NULL; /* pointer to initial environment block */
25 wchar_t **__winitenv = NULL; /* pointer to initial environment block */
26 #undef _pgmptr
27 char *_pgmptr = NULL; /* pointer to program name */
28 #undef _wpgmptr
29 wchar_t *_wpgmptr = NULL; /* pointer to program name */
30 int __app_type = _UNKNOWN_APP; /* application type */
31 int _commode = _IOCOMMIT;
32
33
34 int BlockEnvToEnvironA(void)
35 {
36 char *ptr, *environment_strings;
37 char **envptr;
38 int count = 1;
39 size_t len;
40
41 TRACE("BlockEnvToEnvironA()\n");
42
43 environment_strings = GetEnvironmentStringsA();
44 if (environment_strings == NULL) {
45 return -1;
46 }
47
48 for (ptr = environment_strings; *ptr; ptr += len)
49 {
50 len = strlen(ptr) + 1;
51 /* Skip drive letter settings. */
52 if (*ptr != '=')
53 count++;
54 }
55
56 __initenv = _environ = malloc(count * sizeof(char*));
57 if (_environ)
58 {
59 for (ptr = environment_strings, envptr = _environ; count > 1; ptr += len)
60 {
61 len = strlen(ptr) + 1;
62 /* Skip drive letter settings. */
63 if (*ptr != '=')
64 {
65 if ((*envptr = malloc(len)) == NULL)
66 {
67 for (envptr--; envptr >= _environ; envptr--)
68 free(*envptr);
69 FreeEnvironmentStringsA(environment_strings);
70 free(_environ);
71 __initenv = _environ = NULL;
72 return -1;
73 }
74 memcpy(*envptr++, ptr, len);
75 count--;
76 }
77 }
78 /* Add terminating NULL entry. */
79 *envptr = NULL;
80 }
81
82 FreeEnvironmentStringsA(environment_strings);
83 return _environ ? 0 : -1;
84 }
85
86 int BlockEnvToEnvironW(void)
87 {
88 wchar_t *ptr, *environment_strings;
89 wchar_t **envptr;
90 int count = 1;
91 size_t len;
92
93 TRACE("BlockEnvToEnvironW()\n");
94
95 environment_strings = GetEnvironmentStringsW();
96 if (environment_strings == NULL) {
97 return -1;
98 }
99
100 for (ptr = environment_strings; *ptr; ptr += len)
101 {
102 len = wcslen(ptr) + 1;
103 /* Skip drive letter settings. */
104 if (*ptr != '=')
105 count++;
106 }
107
108 __winitenv = _wenviron = malloc(count * sizeof(wchar_t*));
109 if (_wenviron)
110 {
111 for (ptr = environment_strings, envptr = _wenviron; count > 1; ptr += len)
112 {
113 len = wcslen(ptr) + 1;
114 /* Skip drive letter settings. */
115 if (*ptr != '=')
116 {
117 if ((*envptr = malloc(len * sizeof(wchar_t))) == NULL)
118 {
119 for (envptr--; envptr >= _wenviron; envptr--)
120 free(*envptr);
121 FreeEnvironmentStringsW(environment_strings);
122 free(_wenviron);
123 __winitenv = _wenviron = NULL;
124 return -1;
125 }
126 memcpy(*envptr++, ptr, len * sizeof(wchar_t));
127 count--;
128 }
129 }
130 /* Add terminating NULL entry. */
131 *envptr = NULL;
132 }
133
134 FreeEnvironmentStringsW(environment_strings);
135 return _wenviron ? 0 : -1;
136 }
137
138 /**
139 * Internal function to duplicate environment block. Although it's
140 * parameter are defined as char**, it's able to work also with
141 * wide character environment block which are of type wchar_t**.
142 *
143 * @param original_environment
144 * Environment to duplicate.
145 * @param wide
146 * Set to zero for multibyte environments, non-zero otherwise.
147 *
148 * @return Original environment in case of failure, otherwise
149 * pointer to new environment block.
150 */
151 char **DuplicateEnvironment(char **original_environment, int wide)
152 {
153 int count = 1;
154 char **envptr, **newenvptr, **newenv;
155
156 for (envptr = original_environment; *envptr != NULL; envptr++, count++)
157 ;
158
159 newenvptr = newenv = malloc(count * sizeof(char*));
160 if (newenv == NULL)
161 return original_environment;
162
163 for (envptr = original_environment; count > 1; newenvptr++, count--)
164 {
165 if (wide)
166 *newenvptr = (char*)_wcsdup((wchar_t*)*envptr++);
167 else
168 *newenvptr = _strdup(*envptr++);
169 if (*newenvptr == NULL)
170 {
171 for (newenvptr--; newenvptr >= newenv; newenvptr--)
172 free(*newenvptr);
173 free(newenv);
174 return original_environment;
175 }
176 }
177 *newenvptr = NULL;
178
179 return newenv;
180 }
181
182 /**
183 * Internal function to deallocate environment block. Although it's
184 * parameter are defined as char**, it's able to work also with
185 * wide character environment block which are of type wchar_t**.
186 *
187 * @param environment
188 * Environment to free.
189 */
190 void FreeEnvironment(char **environment)
191 {
192 char **envptr;
193 for (envptr = environment; *envptr != NULL; envptr++)
194 free(*envptr);
195 free(environment);
196 }
197
198 /**
199 * Internal version of _wputenv and _putenv. It works duplicates the
200 * original envirnments created during initilization if needed to prevent
201 * having spurious pointers floating around. Then it updates the internal
202 * environment tables (_environ and _wenviron) and at last updates the
203 * OS environemnt.
204 *
205 * Note that there can happen situation when the internal [_w]environ
206 * arrays will be updated, but the OS environment update will fail. In
207 * this case we don't undo the changes to the [_w]environ tables to
208 * comply with the Microsoft behaviour (and it's also much easier :-).
209 */
210 int SetEnv(const wchar_t *option)
211 {
212 wchar_t *epos, *name;
213 wchar_t **wenvptr;
214 wchar_t *woption;
215 char *mboption;
216 int remove, index, count, size, result = 0, found = 0;
217 wchar_t **wnewenv;
218 char **mbnewenv;
219
220 if (option == NULL || (epos = wcschr(option, L'=')) == NULL)
221 return -1;
222 remove = (epos[1] == 0);
223
224 /* Duplicate environment if needed. */
225 if (_environ == __initenv)
226 {
227 if ((_environ = DuplicateEnvironment(_environ, 0)) == __initenv)
228 return -1;
229 }
230 if (_wenviron == __winitenv)
231 {
232 if ((_wenviron = (wchar_t**)DuplicateEnvironment((char**)_wenviron, 1)) ==
233 __winitenv)
234 return -1;
235 }
236
237 /* Create a copy of the option name. */
238 name = malloc((epos - option + 1) * sizeof(wchar_t));
239 if (name == NULL)
240 return -1;
241 memcpy(name, option, (epos - option) * sizeof(wchar_t));
242 name[epos - option] = 0;
243
244 /* Find the option we're trying to modify. */
245 for (index = 0, wenvptr = _wenviron; *wenvptr != NULL; wenvptr++, index++)
246 {
247 if (!_wcsnicmp(*wenvptr, option, epos - option))
248 {
249 found = 1;
250 break;
251 }
252 }
253
254 if (remove)
255 {
256 if (!found)
257 {
258 free(name);
259 return 0;
260 }
261
262 /* Remove the option from wide character environment. */
263 free(*wenvptr);
264 for (count = index; *wenvptr != NULL; wenvptr++, count++)
265 *wenvptr = *(wenvptr + 1);
266 wnewenv = realloc(_wenviron, count * sizeof(wchar_t*));
267 if (wnewenv != NULL)
268 _wenviron = wnewenv;
269
270 /* Remove the option from multibyte environment. We assume
271 * the environments are in sync and the option is at the
272 * same position. */
273 free(_environ[index]);
274 memmove(&_environ[index], &_environ[index+1], (count - index) * sizeof(char*));
275 mbnewenv = realloc(_environ, count * sizeof(char*));
276 if (mbnewenv != NULL)
277 _environ = mbnewenv;
278
279 result = SetEnvironmentVariableW(name, NULL) ? 0 : -1;
280 }
281 else
282 {
283 /* Make a copy of the option that we will store in the environment block. */
284 woption = _wcsdup((wchar_t*)option);
285 if (woption == NULL)
286 {
287 free(name);
288 return -1;
289 }
290
291 /* Create a multibyte copy of the option. */
292 size = WideCharToMultiByte(CP_ACP, 0, option, -1, NULL, 0, NULL, NULL);
293 mboption = malloc(size);
294 if (mboption == NULL)
295 {
296 free(name);
297 free(woption);
298 return -1;
299 }
300 WideCharToMultiByte(CP_ACP, 0, option, -1, mboption, size, NULL, NULL);
301
302 if (found)
303 {
304 /* Replace the current entry. */
305 free(*wenvptr);
306 *wenvptr = woption;
307 free(_environ[index]);
308 _environ[index] = mboption;
309 }
310 else
311 {
312 /* Get the size of the original environment. */
313 for (count = index; *wenvptr != NULL; wenvptr++, count++)
314 ;
315
316 /* Create a new entry. */
317 if ((wnewenv = realloc(_wenviron, (count + 2) * sizeof(wchar_t*))) == NULL)
318 {
319 free(name);
320 free(mboption);
321 free(woption);
322 return -1;
323 }
324 _wenviron = wnewenv;
325 if ((mbnewenv = realloc(_environ, (count + 2) * sizeof(char*))) == NULL)
326 {
327 free(name);
328 free(mboption);
329 free(woption);
330 return -1;
331 }
332 _environ = mbnewenv;
333
334 /* Set the last entry to our option. */
335 _wenviron[count] = woption;
336 _environ[count] = mboption;
337 _wenviron[count + 1] = NULL;
338 _environ[count + 1] = NULL;
339 }
340
341 /* And finally update the OS environment. */
342 result = SetEnvironmentVariableW(name, epos + 1) ? 0 : -1;
343 }
344 free(name);
345
346 return result;
347 }
348
349 /*
350 * @implemented
351 */
352 int *__p__commode(void) // not exported by NTDLL
353 {
354 return &_commode;
355 }
356
357 /*
358 * @implemented
359 */
360 void __set_app_type(int app_type)
361 {
362 __app_type = app_type;
363 }
364
365 /*
366 * @implemented
367 */
368 char **__p__acmdln(void)
369 {
370 return &_acmdln;
371 }
372
373 /*
374 * @implemented
375 */
376 wchar_t **__p__wcmdln(void)
377 {
378 return &_wcmdln;
379 }
380
381 /*
382 * @implemented
383 */
384 char ***__p__environ(void)
385 {
386 return &_environ;
387 }
388
389 /*
390 * @implemented
391 */
392 wchar_t ***__p__wenviron(void)
393 {
394 return &_wenviron;
395 }
396
397 /*
398 * @implemented
399 */
400 char ***__p___initenv(void)
401 {
402 return &__initenv;
403 }
404
405 /*
406 * @implemented
407 */
408 wchar_t ***__p___winitenv(void)
409 {
410 return &__winitenv;
411 }
412
413 /*
414 * @implemented
415 */
416 errno_t _get_osplatform(unsigned int *pValue)
417 {
418 if (!MSVCRT_CHECK_PMT(pValue != NULL)) {
419 *_errno() = EINVAL;
420 return EINVAL;
421 }
422
423 *pValue = _osplatform;
424 return 0;
425 }
426
427 /*
428 * @implemented
429 */
430 int *__p___mb_cur_max(void)
431 {
432 return &get_locinfo()->mb_cur_max;
433 }
434
435 /*********************************************************************
436 * ___mb_cur_max_func(MSVCRT.@)
437 */
438 int CDECL ___mb_cur_max_func(void)
439 {
440 return get_locinfo()->mb_cur_max;
441 }
442
443 /*
444 * @implemented
445 */
446 unsigned int *__p__osver(void)
447 {
448 return &_osver;
449 }
450
451 /*
452 * @implemented
453 */
454 char **__p__pgmptr(void)
455 {
456 return &_pgmptr;
457 }
458
459 /*
460 * @implemented
461 */
462 int _get_pgmptr(char** p)
463 {
464 if (!MSVCRT_CHECK_PMT(p))
465 {
466 *_errno() = EINVAL;
467 return EINVAL;
468 }
469
470 *p = _pgmptr;
471 return 0;
472 }
473
474 /*
475 * @implemented
476 */
477 wchar_t **__p__wpgmptr(void)
478 {
479 return &_wpgmptr;
480 }
481
482 /*
483 * @implemented
484 */
485 int _get_wpgmptr(WCHAR** p)
486 {
487 if (!MSVCRT_CHECK_PMT(p))
488 {
489 *_errno() = EINVAL;
490 return EINVAL;
491 }
492
493 *p = _wpgmptr;
494 return 0;
495 }
496
497 /*
498 * @implemented
499 */
500 unsigned int *__p__winmajor(void)
501 {
502 return &_winmajor;
503 }
504
505 /*
506 * @implemented
507 */
508 unsigned int *__p__winminor(void)
509 {
510 return &_winminor;
511 }
512
513 /*
514 * @implemented
515 */
516 unsigned int *__p__winver(void)
517 {
518 return &_winver;
519 }
520
521 /* EOF */