/* * environ.c * * ReactOS MSVCRT.DLL Compatibility Library */ #include #include unsigned int _osplatform = 0; unsigned int _osver = 0; unsigned int _winminor = 0; unsigned int _winmajor = 0; unsigned int _winver = 0; unsigned int __setlc_active = 0; unsigned int __unguarded_readlc_active = 0; char *_acmdln = NULL; /* pointer to ascii command line */ wchar_t *_wcmdln = NULL; /* pointer to wide character command line */ #undef _environ #undef _wenviron char **_environ = NULL; /* pointer to environment block */ wchar_t **_wenviron = NULL; /* pointer to environment block */ char **__initenv = NULL; /* pointer to initial environment block */ wchar_t **__winitenv = NULL; /* pointer to initial environment block */ #undef _pgmptr char *_pgmptr = NULL; /* pointer to program name */ #undef _wpgmptr wchar_t *_wpgmptr = NULL; /* pointer to program name */ int __app_type = _UNKNOWN_APP; /* application type */ int _commode; int BlockEnvToEnvironA(void) { char *ptr, *environment_strings; char **envptr; int count = 1; size_t len; TRACE("BlockEnvToEnvironA()\n"); environment_strings = GetEnvironmentStringsA(); if (environment_strings == NULL) { return -1; } for (ptr = environment_strings; *ptr; ptr += len) { len = strlen(ptr) + 1; /* Skip drive letter settings. */ if (*ptr != '=') count++; } __initenv = _environ = malloc(count * sizeof(char*)); if (_environ) { for (ptr = environment_strings, envptr = _environ; count > 1; ptr += len) { len = strlen(ptr) + 1; /* Skip drive letter settings. */ if (*ptr != '=') { if ((*envptr = malloc(len)) == NULL) { for (envptr--; envptr >= _environ; envptr--) free(*envptr); FreeEnvironmentStringsA(environment_strings); free(_environ); __initenv = _environ = NULL; return -1; } memcpy(*envptr++, ptr, len); count--; } } /* Add terminating NULL entry. */ *envptr = NULL; } FreeEnvironmentStringsA(environment_strings); return _environ ? 0 : -1; } int BlockEnvToEnvironW(void) { wchar_t *ptr, *environment_strings; wchar_t **envptr; int count = 1; size_t len; TRACE("BlockEnvToEnvironW()\n"); environment_strings = GetEnvironmentStringsW(); if (environment_strings == NULL) { return -1; } for (ptr = environment_strings; *ptr; ptr += len) { len = wcslen(ptr) + 1; /* Skip drive letter settings. */ if (*ptr != '=') count++; } __winitenv = _wenviron = malloc(count * sizeof(wchar_t*)); if (_wenviron) { for (ptr = environment_strings, envptr = _wenviron; count > 1; ptr += len) { len = wcslen(ptr) + 1; /* Skip drive letter settings. */ if (*ptr != '=') { if ((*envptr = malloc(len * sizeof(wchar_t))) == NULL) { for (envptr--; envptr >= _wenviron; envptr--) free(*envptr); FreeEnvironmentStringsW(environment_strings); free(_wenviron); __winitenv = _wenviron = NULL; return -1; } memcpy(*envptr++, ptr, len * sizeof(wchar_t)); count--; } } /* Add terminating NULL entry. */ *envptr = NULL; } FreeEnvironmentStringsW(environment_strings); return _wenviron ? 0 : -1; } /** * Internal function to duplicate environment block. Although it's * parameter are defined as char**, it's able to work also with * wide character environment block which are of type wchar_t**. * * @param original_environment * Environment to duplicate. * @param wide * Set to zero for multibyte environments, non-zero otherwise. * * @return Original environment in case of failure, otherwise * pointer to new environment block. */ char **DuplicateEnvironment(char **original_environment, int wide) { int count = 1; char **envptr, **newenvptr, **newenv; for (envptr = original_environment; *envptr != NULL; envptr++, count++) ; newenvptr = newenv = malloc(count * sizeof(char*)); if (newenv == NULL) return original_environment; for (envptr = original_environment; count > 1; newenvptr++, count--) { if (wide) *newenvptr = (char*)_wcsdup((wchar_t*)*envptr++); else *newenvptr = _strdup(*envptr++); if (*newenvptr == NULL) { for (newenvptr--; newenvptr >= newenv; newenvptr--) free(*newenvptr); free(newenv); return original_environment; } } *newenvptr = NULL; return newenv; } /** * Internal function to deallocate environment block. Although it's * parameter are defined as char**, it's able to work also with * wide character environment block which are of type wchar_t**. * * @param environment * Environment to free. */ void FreeEnvironment(char **environment) { char **envptr; for (envptr = environment; *envptr != NULL; envptr++) free(*envptr); free(environment); } /** * Internal version of _wputenv and _putenv. It works duplicates the * original envirnments created during initilization if needed to prevent * having spurious pointers floating around. Then it updates the internal * environment tables (_environ and _wenviron) and at last updates the * OS environemnt. * * Note that there can happen situation when the internal [_w]environ * arrays will be updated, but the OS environment update will fail. In * this case we don't undo the changes to the [_w]environ tables to * comply with the Microsoft behaviour (and it's also much easier :-). */ int SetEnv(const wchar_t *option) { wchar_t *epos, *name; wchar_t **wenvptr; wchar_t *woption; char *mboption; int remove, index, count, size, result = 0, found = 0; wchar_t **wnewenv; char **mbnewenv; if (option == NULL || (epos = wcschr(option, L'=')) == NULL) return -1; remove = (epos[1] == 0); /* Duplicate environment if needed. */ if (_environ == __initenv) { if ((_environ = DuplicateEnvironment(_environ, 0)) == __initenv) return -1; } if (_wenviron == __winitenv) { if ((_wenviron = (wchar_t**)DuplicateEnvironment((char**)_wenviron, 1)) == __winitenv) return -1; } /* Create a copy of the option name. */ name = malloc((epos - option + 1) * sizeof(wchar_t)); if (name == NULL) return -1; memcpy(name, option, (epos - option) * sizeof(wchar_t)); name[epos - option] = 0; /* Find the option we're trying to modify. */ for (index = 0, wenvptr = _wenviron; *wenvptr != NULL; wenvptr++, index++) { if (!_wcsnicmp(*wenvptr, option, epos - option)) { found = 1; break; } } if (remove) { if (!found) { free(name); return 0; } /* Remove the option from wide character environment. */ free(*wenvptr); for (count = index; *wenvptr != NULL; wenvptr++, count++) *wenvptr = *(wenvptr + 1); wnewenv = realloc(_wenviron, count * sizeof(wchar_t*)); if (wnewenv != NULL) _wenviron = wnewenv; /* Remove the option from multibyte environment. We assume * the environments are in sync and the option is at the * same position. */ free(_environ[index]); memmove(&_environ[index], &_environ[index+1], (count - index) * sizeof(char*)); mbnewenv = realloc(_environ, count * sizeof(char*)); if (mbnewenv != NULL) _environ = mbnewenv; result = SetEnvironmentVariableW(name, NULL) ? 0 : -1; } else { /* Make a copy of the option that we will store in the environment block. */ woption = _wcsdup((wchar_t*)option); if (woption == NULL) { free(name); return -1; } /* Create a multibyte copy of the option. */ size = WideCharToMultiByte(CP_ACP, 0, option, -1, NULL, 0, NULL, NULL); mboption = malloc(size); if (mboption == NULL) { free(name); free(woption); return -1; } WideCharToMultiByte(CP_ACP, 0, option, -1, mboption, size, NULL, NULL); if (found) { /* Replace the current entry. */ free(*wenvptr); *wenvptr = woption; free(_environ[index]); _environ[index] = mboption; } else { /* Get the size of the original environment. */ for (count = index; *wenvptr != NULL; wenvptr++, count++) ; /* Create a new entry. */ if ((wnewenv = realloc(_wenviron, (count + 2) * sizeof(wchar_t*))) == NULL) { free(name); free(mboption); free(woption); return -1; } _wenviron = wnewenv; if ((mbnewenv = realloc(_environ, (count + 2) * sizeof(char*))) == NULL) { free(name); free(mboption); free(woption); return -1; } _environ = mbnewenv; /* Set the last entry to our option. */ _wenviron[count] = woption; _environ[count] = mboption; _wenviron[count + 1] = NULL; _environ[count + 1] = NULL; } /* And finally update the OS environment. */ result = SetEnvironmentVariableW(name, epos + 1) ? 0 : -1; } free(name); return result; } /* * @implemented */ int *__p__commode(void) // not exported by NTDLL { return &_commode; } /* * @implemented */ void __set_app_type(int app_type) { __app_type = app_type; } /* * @implemented */ char **__p__acmdln(void) { return &_acmdln; } /* * @implemented */ wchar_t **__p__wcmdln(void) { return &_wcmdln; } /* * @implemented */ char ***__p__environ(void) { return &_environ; } /* * @implemented */ wchar_t ***__p__wenviron(void) { return &_wenviron; } /* * @implemented */ char ***__p___initenv(void) { return &__initenv; } /* * @implemented */ wchar_t ***__p___winitenv(void) { return &__winitenv; } /* * @implemented */ errno_t _get_osplatform(unsigned int *pValue) { if (!MSVCRT_CHECK_PMT(pValue != NULL)) { *_errno() = EINVAL; return EINVAL; } *pValue = _osplatform; return 0; } /* * @implemented */ int *__p___mb_cur_max(void) { return &get_locinfo()->mb_cur_max; } /********************************************************************* * ___mb_cur_max_func(MSVCRT.@) */ int CDECL ___mb_cur_max_func(void) { return get_locinfo()->mb_cur_max; } /* * @implemented */ unsigned int *__p__osver(void) { return &_osver; } /* * @implemented */ char **__p__pgmptr(void) { return &_pgmptr; } /* * @implemented */ int _get_pgmptr(char** p) { if (!MSVCRT_CHECK_PMT(p)) { *_errno() = EINVAL; return EINVAL; } *p = _pgmptr; return 0; } /* * @implemented */ wchar_t **__p__wpgmptr(void) { return &_wpgmptr; } /* * @implemented */ int _get_wpgmptr(WCHAR** p) { if (!MSVCRT_CHECK_PMT(p)) { *_errno() = EINVAL; return EINVAL; } *p = _wpgmptr; return 0; } /* * @implemented */ unsigned int *__p__winmajor(void) { return &_winmajor; } /* * @implemented */ unsigned int *__p__winminor(void) { return &_winminor; } /* * @implemented */ unsigned int *__p__winver(void) { return &_winver; } /* EOF */