xref: /reactos/sdk/lib/crt/misc/environ.c (revision 84344399)
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;
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 */
522