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