Merge 13159:13510 from trunk
[reactos.git] / reactos / lib / crt / misc / environ.c
1 /* $Id$
2 *
3 * dllmain.c
4 *
5 * ReactOS MSVCRT.DLL Compatibility Library
6 */
7
8 #include "precomp.h"
9 #include <msvcrt/internal/tls.h>
10 #include <msvcrt/stdlib.h>
11 #include <msvcrt/string.h>
12
13 #define NDEBUG
14 #include <msvcrt/msvcrtdbg.h>
15
16
17 unsigned int _osver = 0;
18 unsigned int _winminor = 0;
19 unsigned int _winmajor = 0;
20 unsigned int _winver = 0;
21
22
23 char *_acmdln = NULL; /* pointer to ascii command line */
24 wchar_t *_wcmdln = NULL; /* pointer to wide character command line */
25 #undef _environ
26 #undef _wenviron
27 char **_environ = NULL; /* pointer to environment block */
28 wchar_t **_wenviron = NULL; /* pointer to environment block */
29 char **__initenv = NULL; /* pointer to initial environment block */
30 wchar_t **__winitenv = NULL; /* pointer to initial environment block */
31 #undef _pgmptr
32 char *_pgmptr = 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 DPRINT("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 DPRINT("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
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 -1;
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 for (; _environ[index] != NULL; index++)
273 _environ[index] = _environ[index + 1];
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 char ***__p__environ(void)
377 {
378 return &_environ;
379 }
380
381 /*
382 * @implemented
383 */
384 wchar_t ***__p__wenviron(void)
385 {
386 return &_wenviron;
387 }
388
389 /*
390 * @implemented
391 */
392 char ***__p___initenv(void)
393 {
394 return &__initenv;
395 }
396
397 /*
398 * @implemented
399 */
400 wchar_t ***__p___winitenv(void)
401 {
402 return &__winitenv;
403 }
404
405 /*
406 * @implemented
407 */
408 int *__p___mb_cur_max(void)
409 {
410 return &__mb_cur_max;
411 }
412
413 /*
414 * @implemented
415 */
416 unsigned int *__p__osver(void)
417 {
418 return &_osver;
419 }
420
421 /*
422 * @implemented
423 */
424 char **__p__pgmptr(void)
425 {
426 return &_pgmptr;
427 }
428
429 /*
430 * @implemented
431 */
432 unsigned int *__p__winmajor(void)
433 {
434 return &_winmajor;
435 }
436
437 /*
438 * @implemented
439 */
440 unsigned int *__p__winminor(void)
441 {
442 return &_winminor;
443 }
444
445 /*
446 * @implemented
447 */
448 unsigned int *__p__winver(void)
449 {
450 return &_winver;
451 }
452
453 /* EOF */