mirror of
https://github.com/reactos/reactos.git
synced 2024-08-25 04:38:43 +00:00
![Timo Kreuzer](/assets/img/avatar_default.png)
* Fix initialization of _commode. In msvcrt it is allocated from .bss, i.e. initialized with 0. * _fileinfo is initialized with -1 * _aexit_rtn is a pointer, not a function * Fix _sys_nerr
522 lines
11 KiB
C
522 lines
11 KiB
C
/*
|
|
* environ.c
|
|
*
|
|
* ReactOS MSVCRT.DLL Compatibility Library
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
#include <internal/wine/msvcrt.h>
|
|
|
|
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 */
|