Sync with trunk (r48008)
[reactos.git] / lib / sdk / crt / misc / environ.c
1 /* $Id$
2 *
3 * environ.c
4 *
5 * ReactOS MSVCRT.DLL Compatibility Library
6 */
7
8 #include <precomp.h>
9 #include <internal/tls.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13
14 unsigned int _osplatform = 0;
15 unsigned int _osver = 0;
16 unsigned int _winminor = 0;
17 unsigned int _winmajor = 0;
18 unsigned int _winver = 0;
19
20
21 char *_acmdln = NULL; /* pointer to ascii command line */
22 wchar_t *_wcmdln = NULL; /* pointer to wide character command line */
23 #undef _environ
24 #undef _wenviron
25 char **_environ = NULL; /* pointer to environment block */
26 wchar_t **_wenviron = NULL; /* pointer to environment block */
27 char **__initenv = NULL; /* pointer to initial environment block */
28 wchar_t **__winitenv = NULL; /* pointer to initial environment block */
29 #undef _pgmptr
30 char *_pgmptr = NULL; /* pointer to program name */
31 #undef _wpgmptr
32 wchar_t *_wpgmptr = NULL; /* pointer to program name */
33 int __app_type = 0; //_UNKNOWN_APP; /* application type */
34 int __mb_cur_max = 1;
35
36 int _commode = _IOCOMMIT;
37
38
39 int BlockEnvToEnvironA(void)
40 {
41 char *ptr, *environment_strings;
42 char **envptr;
43 int count = 1, len;
44
45 TRACE("BlockEnvToEnvironA()\n");
46
47 environment_strings = GetEnvironmentStringsA();
48 if (environment_strings == NULL) {
49 return -1;
50 }
51
52 for (ptr = environment_strings; *ptr; ptr += len)
53 {
54 len = strlen(ptr) + 1;
55 /* Skip drive letter settings. */
56 if (*ptr != '=')
57 count++;
58 }
59
60 __initenv = _environ = malloc(count * sizeof(char*));
61 if (_environ)
62 {
63 for (ptr = environment_strings, envptr = _environ; count > 1; ptr += len)
64 {
65 len = strlen(ptr) + 1;
66 /* Skip drive letter settings. */
67 if (*ptr != '=')
68 {
69 if ((*envptr = malloc(len)) == NULL)
70 {
71 for (envptr--; envptr >= _environ; envptr--);
72 free(*envptr);
73 FreeEnvironmentStringsA(environment_strings);
74 free(_environ);
75 __initenv = _environ = NULL;
76 return -1;
77 }
78 memcpy(*envptr++, ptr, len);
79 count--;
80 }
81 }
82 /* Add terminating NULL entry. */
83 *envptr = NULL;
84 }
85
86 FreeEnvironmentStringsA(environment_strings);
87 return _environ ? 0 : -1;
88 }
89
90 int BlockEnvToEnvironW(void)
91 {
92 wchar_t *ptr, *environment_strings;
93 wchar_t **envptr;
94 int count = 1, len;
95
96 TRACE("BlockEnvToEnvironW()\n");
97
98 environment_strings = GetEnvironmentStringsW();
99 if (environment_strings == NULL) {
100 return -1;
101 }
102
103 for (ptr = environment_strings; *ptr; ptr += len)
104 {
105 len = wcslen(ptr) + 1;
106 /* Skip drive letter settings. */
107 if (*ptr != '=')
108 count++;
109 }
110
111 __winitenv = _wenviron = malloc(count * sizeof(wchar_t*));
112 if (_wenviron)
113 {
114 for (ptr = environment_strings, envptr = _wenviron; count > 1; ptr += len)
115 {
116 len = wcslen(ptr) + 1;
117 /* Skip drive letter settings. */
118 if (*ptr != '=')
119 {
120 if ((*envptr = malloc(len * sizeof(wchar_t))) == NULL)
121 {
122 for (envptr--; envptr >= _wenviron; envptr--);
123 free(*envptr);
124 FreeEnvironmentStringsW(environment_strings);
125 free(_wenviron);
126 __winitenv = _wenviron = NULL;
127 return -1;
128 }
129 memcpy(*envptr++, ptr, len * sizeof(wchar_t));
130 count--;
131 }
132 }
133 /* Add terminating NULL entry. */
134 *envptr = NULL;
135 }
136
137 FreeEnvironmentStringsW(environment_strings);
138 return _wenviron ? 0 : -1;
139 }
140
141 /**
142 * Internal function to duplicate environment block. Although it's
143 * parameter are defined as char**, it's able to work also with
144 * wide character environment block which are of type wchar_t**.
145 *
146 * @param original_environment
147 * Environment to duplicate.
148 * @param wide
149 * Set to zero for multibyte environments, non-zero otherwise.
150 *
151 * @return Original environment in case of failure, otherwise
152 * pointer to new environment block.
153 */
154 char **DuplicateEnvironment(char **original_environment, int wide)
155 {
156 int count = 1;
157 char **envptr, **newenvptr, **newenv;
158
159 for (envptr = original_environment; *envptr != NULL; envptr++, count++)
160 ;
161
162 newenvptr = newenv = malloc(count * sizeof(char*));
163 if (newenv == NULL)
164 return original_environment;
165
166 for (envptr = original_environment; count > 1; newenvptr++, count--)
167 {
168 if (wide)
169 *newenvptr = (char*)_wcsdup((wchar_t*)*envptr++);
170 else
171 *newenvptr = _strdup(*envptr++);
172 if (*newenvptr == NULL)
173 {
174 for (newenvptr--; newenvptr >= newenv; newenvptr--);
175 free(*newenvptr);
176 free(newenv);
177 return original_environment;
178 }
179 }
180 *newenvptr = NULL;
181
182 return newenv;
183 }
184
185 /**
186 * Internal function to deallocate environment block. Although it's
187 * parameter are defined as char**, it's able to work also with
188 * wide character environment block which are of type wchar_t**.
189 *
190 * @param environment
191 * Environment to free.
192 */
193 void FreeEnvironment(char **environment)
194 {
195 char **envptr;
196 for (envptr = environment; *envptr != NULL; envptr++)
197 free(*envptr);
198 free(environment);
199 }
200
201 /**
202 * Internal version of _wputenv and _putenv. It works duplicates the
203 * original envirnments created during initilization if needed to prevent
204 * having spurious pointers floating around. Then it updates the internal
205 * environment tables (_environ and _wenviron) and at last updates the
206 * OS environemnt.
207 *
208 * Note that there can happen situation when the internal [_w]environ
209 * arrays will be updated, but the OS environment update will fail. In
210 * this case we don't undo the changes to the [_w]environ tables to
211 * comply with the Microsoft behaviour (and it's also much easier :-).
212 */
213 int SetEnv(const wchar_t *option)
214 {
215 wchar_t *epos, *name;
216 wchar_t **wenvptr;
217 wchar_t *woption;
218 char *mboption;
219 int remove, index, count, size, result = 0, found = 0;
220
221 if (option == NULL || (epos = wcschr(option, L'=')) == NULL)
222 return -1;
223 remove = (epos[1] == 0);
224
225 /* Duplicate environment if needed. */
226 if (_environ == __initenv)
227 {
228 if ((_environ = DuplicateEnvironment(_environ, 0)) == __initenv)
229 return -1;
230 }
231 if (_wenviron == __winitenv)
232 {
233 if ((_wenviron = (wchar_t**)DuplicateEnvironment((char**)_wenviron, 1)) ==
234 __winitenv)
235 return -1;
236 }
237
238 /* Create a copy of the option name. */
239 name = malloc((epos - option + 1) * sizeof(wchar_t));
240 if (name == NULL)
241 return -1;
242 memcpy(name, option, (epos - option) * sizeof(wchar_t));
243 name[epos - option] = 0;
244
245 /* Find the option we're trying to modify. */
246 for (index = 0, wenvptr = _wenviron; *wenvptr != NULL; wenvptr++, index++)
247 {
248 if (!_wcsnicmp(*wenvptr, option, epos - option))
249 {
250 found = 1;
251 break;
252 }
253 }
254
255 if (remove)
256 {
257 if (!found)
258 {
259 free(name);
260 return 0;
261 }
262
263 /* Remove the option from wide character environment. */
264 free(*wenvptr);
265 for (count = index; *wenvptr != NULL; wenvptr++, count++)
266 *wenvptr = *(wenvptr + 1);
267 _wenviron = realloc(_wenviron, count * sizeof(wchar_t*));
268
269 /* Remove the option from multibyte environment. We assume
270 * the environments are in sync and the option is at the
271 * same position. */
272 free(_environ[index]);
273 memmove(&_environ[index], &_environ[index+1], (count - index) * sizeof(char*));
274 _environ = realloc(_environ, count * sizeof(char*));
275
276 result = SetEnvironmentVariableW(name, NULL) ? 0 : -1;
277 }
278 else
279 {
280 /* Make a copy of the option that we will store in the environment block. */
281 woption = _wcsdup((wchar_t*)option);
282 if (woption == NULL)
283 {
284 free(name);
285 return -1;
286 }
287
288 /* Create a multibyte copy of the option. */
289 size = WideCharToMultiByte(CP_ACP, 0, option, -1, NULL, 0, NULL, NULL);
290 mboption = malloc(size);
291 if (mboption == NULL)
292 {
293 free(name);
294 free(woption);
295 return -1;
296 }
297 WideCharToMultiByte(CP_ACP, 0, option, -1, mboption, size, NULL, NULL);
298
299 if (found)
300 {
301 /* Replace the current entry. */
302 free(*wenvptr);
303 *wenvptr = woption;
304 free(_environ[index]);
305 _environ[index] = mboption;
306 }
307 else
308 {
309 wchar_t **wnewenv;
310 char **mbnewenv;
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 int *__p___mb_cur_max(void)
417 {
418 return &__mb_cur_max;
419 }
420
421 /*
422 * @implemented
423 */
424 unsigned int *__p__osver(void)
425 {
426 return &_osver;
427 }
428
429 /*
430 * @implemented
431 */
432 char **__p__pgmptr(void)
433 {
434 return &_pgmptr;
435 }
436
437 /*
438 * @implemented
439 */
440 wchar_t **__p__wpgmptr(void)
441 {
442 return &_wpgmptr;
443 }
444
445 /*
446 * @implemented
447 */
448 unsigned int *__p__winmajor(void)
449 {
450 return &_winmajor;
451 }
452
453 /*
454 * @implemented
455 */
456 unsigned int *__p__winminor(void)
457 {
458 return &_winminor;
459 }
460
461 /*
462 * @implemented
463 */
464 unsigned int *__p__winver(void)
465 {
466 return &_winver;
467 }
468
469 /* EOF */