reactos/sdk/lib/crt/misc/environ.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 = _IOCOMMIT;
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 */