Commit a45ca342 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

msvcrt: Lazily initialize ___winitenv.

parent 55b18b14
......@@ -60,77 +60,6 @@ int MSVCRT_app_type = 0;
char* MSVCRT__pgmptr = NULL;
WCHAR* MSVCRT__wpgmptr = NULL;
/* Get a snapshot of the current environment
* and construct the __p__environ array
*
* The pointer returned from GetEnvironmentStrings may get invalid when
* some other module cause a reallocation of the env-variable block
*
* blk is an array of pointers to environment strings, ending with a NULL
* and after that the actual copy of the environment strings, ending in a \0
*/
char ** msvcrt_SnapshotOfEnvironmentA(char **blk)
{
char* environ_strings = GetEnvironmentStringsA();
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
char *ptr;
for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
{
/* Don't count environment variables starting with '=' which are command shell specific */
if (*ptr != '=') count++;
len += strlen(ptr) + 1;
}
blk = realloc(blk, count * sizeof(char*) + len);
if (blk)
{
if (count)
{
memcpy(&blk[count],environ_strings,len);
for (ptr = (char*) &blk[count]; *ptr; ptr += strlen(ptr) + 1)
{
/* Skip special environment strings set by the command shell */
if (*ptr != '=') blk[i++] = ptr;
}
}
blk[i] = NULL;
}
FreeEnvironmentStringsA(environ_strings);
return blk;
}
wchar_t ** msvcrt_SnapshotOfEnvironmentW(wchar_t **wblk)
{
wchar_t* wenviron_strings = GetEnvironmentStringsW();
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
wchar_t *wptr;
for (wptr = wenviron_strings; *wptr; wptr += wcslen(wptr) + 1)
{
/* Don't count environment variables starting with '=' which are command shell specific */
if (*wptr != '=') count++;
len += wcslen(wptr) + 1;
}
wblk = realloc(wblk, count * sizeof(wchar_t*) + len * sizeof(wchar_t));
if (wblk)
{
if (count)
{
memcpy(&wblk[count],wenviron_strings,len * sizeof(wchar_t));
for (wptr = (wchar_t*)&wblk[count]; *wptr; wptr += wcslen(wptr) + 1)
{
/* Skip special environment strings set by the command shell */
if (*wptr != '=') wblk[i++] = wptr;
}
}
wblk[i] = NULL;
}
FreeEnvironmentStringsW(wenviron_strings);
return wblk;
}
static char **build_argv( WCHAR **wargv )
{
int argc;
......@@ -433,9 +362,7 @@ void msvcrt_init_args(void)
MSVCRT___unguarded_readlc_active = 0;
MSVCRT__fmode = _O_TEXT;
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(NULL);
MSVCRT___initenv = msvcrt_SnapshotOfEnvironmentA(NULL);
MSVCRT___winitenv = msvcrt_SnapshotOfEnvironmentW(NULL);
env_init(FALSE, FALSE);
MSVCRT__pgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
if (MSVCRT__pgmptr)
......@@ -554,9 +481,8 @@ int CDECL __wgetmainargs(int *argc, wchar_t** *wargv, wchar_t** *wenvp,
MSVCRT___wargv = initial_wargv;
}
/* Initialize the _wenviron array if it's not already created. */
if (!MSVCRT__wenviron)
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
env_init(TRUE, FALSE);
*argc = MSVCRT___argc;
*wargv = MSVCRT___wargv;
*wenvp = MSVCRT__wenviron;
......
......@@ -25,6 +25,83 @@
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
int env_init(BOOL unicode, BOOL modif)
{
if (!unicode && (!MSVCRT___initenv || modif))
{
char *environ_strings = GetEnvironmentStringsA();
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
char **blk, *ptr;
for (ptr = environ_strings; *ptr; ptr += strlen(ptr) + 1)
{
/* Don't count environment variables starting with '=' which are command shell specific */
if (*ptr != '=') count++;
len += strlen(ptr) + 1;
}
if (MSVCRT___initenv != MSVCRT__environ)
blk = realloc(MSVCRT__environ, count * sizeof(*MSVCRT__environ) + len);
else
blk = malloc(count * sizeof(*MSVCRT__environ) + len);
if (!blk)
{
FreeEnvironmentStringsA(environ_strings);
return -1;
}
MSVCRT__environ = blk;
memcpy(&MSVCRT__environ[count], environ_strings, len);
for (ptr = (char *)&MSVCRT__environ[count]; *ptr; ptr += strlen(ptr) + 1)
{
/* Skip special environment strings set by the command shell */
if (*ptr != '=') MSVCRT__environ[i++] = ptr;
}
MSVCRT__environ[i] = NULL;
FreeEnvironmentStringsA(environ_strings);
if (!MSVCRT___initenv)
MSVCRT___initenv = MSVCRT__environ;
}
if (unicode && (!MSVCRT___winitenv || modif))
{
wchar_t *wenviron_strings = GetEnvironmentStringsW();
int count = 1, len = 1, i = 0; /* keep space for the trailing NULLS */
wchar_t **wblk, *wptr;
for (wptr = wenviron_strings; *wptr; wptr += wcslen(wptr) + 1)
{
/* Don't count environment variables starting with '=' which are command shell specific */
if (*wptr != '=') count++;
len += wcslen(wptr) + 1;
}
if (MSVCRT___winitenv != MSVCRT__wenviron)
wblk = realloc(MSVCRT__wenviron, count * sizeof(*MSVCRT__wenviron) + len * sizeof(wchar_t));
else
wblk = malloc(count * sizeof(*MSVCRT__wenviron) + len * sizeof(wchar_t));
if (!wblk)
{
FreeEnvironmentStringsW(wenviron_strings);
return -1;
}
MSVCRT__wenviron = wblk;
memcpy(&MSVCRT__wenviron[count], wenviron_strings, len * sizeof(wchar_t));
for (wptr = (wchar_t *)&MSVCRT__wenviron[count]; *wptr; wptr += wcslen(wptr) + 1)
{
/* Skip special environment strings set by the command shell */
if (*wptr != '=') MSVCRT__wenviron[i++] = wptr;
}
MSVCRT__wenviron[i] = NULL;
FreeEnvironmentStringsW(wenviron_strings);
if (!MSVCRT___winitenv)
MSVCRT___winitenv = MSVCRT__wenviron;
}
return 0;
}
static int env_get_index(const char *name)
{
int i, len;
......@@ -77,10 +154,7 @@ static wchar_t * wgetenv_helper(const wchar_t *name)
int idx;
if (!name) return NULL;
/* Initialize the _wenviron array if it's not already created. */
if (!MSVCRT__wenviron)
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
if (env_init(TRUE, FALSE)) return NULL;
idx = wenv_get_index(name);
if (!MSVCRT__wenviron[idx]) return NULL;
......@@ -133,10 +207,9 @@ int CDECL _putenv(const char *str)
/* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0;
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
if (ret != -1) ret = env_init(FALSE, TRUE);
/* Update the __p__wenviron array only when already initialized */
if (MSVCRT__wenviron)
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
if (ret != -1 && MSVCRT__wenviron) ret = env_init(TRUE, TRUE);
finish:
HeapFree(GetProcessHeap(), 0, name);
......@@ -154,6 +227,8 @@ int CDECL _wputenv(const wchar_t *str)
TRACE("%s\n", debugstr_w(str));
if (env_init(TRUE, FALSE)) return -1;
if (!str)
return -1;
name = HeapAlloc(GetProcessHeap(), 0, (wcslen(str) + 1) * sizeof(wchar_t));
......@@ -178,8 +253,8 @@ int CDECL _wputenv(const wchar_t *str)
/* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0;
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
if (ret != -1) ret = env_init(FALSE, TRUE);
if (ret != -1) ret = env_init(TRUE, TRUE);
finish:
HeapFree(GetProcessHeap(), 0, name);
......@@ -208,9 +283,8 @@ errno_t CDECL _putenv_s(const char *name, const char *value)
}
}
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
env_init(FALSE, TRUE);
env_init(TRUE, TRUE);
return ret;
}
......@@ -223,6 +297,8 @@ errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value)
TRACE("%s %s\n", debugstr_w(name), debugstr_w(value));
env_init(TRUE, FALSE);
if (!MSVCRT_CHECK_PMT(name != NULL)) return EINVAL;
if (!MSVCRT_CHECK_PMT(value != NULL)) return EINVAL;
......@@ -236,9 +312,8 @@ errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value)
}
}
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
env_init(FALSE, TRUE);
env_init(TRUE, TRUE);
return ret;
}
......
......@@ -205,9 +205,10 @@ void __cdecl _amsg_exit(int errnum);
extern char **MSVCRT__environ;
extern wchar_t **MSVCRT__wenviron;
extern char **MSVCRT___initenv;
extern wchar_t **MSVCRT___winitenv;
extern char ** msvcrt_SnapshotOfEnvironmentA(char **);
extern wchar_t ** msvcrt_SnapshotOfEnvironmentW(wchar_t **);
int env_init(BOOL, BOOL);
wchar_t *msvcrt_wstrdupa(const char *);
......
......@@ -139,7 +139,6 @@ static void test__environ(void)
{
initenv = *p__p___initenv();
todo_wine
ok( initenv == *p_environ,
"Expected _environ to be equal to initial env\n" );
}
......@@ -195,7 +194,6 @@ static void test__wenviron(void)
if (p__p___winitenv)
{
wchar_t ***retptr = p__p___winitenv();
todo_wine
ok( !*retptr, "Expected initial env to be NULL\n" );
}
else
......@@ -235,7 +233,6 @@ static void test__wenviron(void)
"Expected _wenviron to be different from __p___winitenv() %p %p\n", *retptr, *p_wenviron );
/* test that w-initial env is derived from current _environ[] and not from ansi initial env */
value = env_get_valueW( *retptr, L"cat" );
todo_wine
ok( value && !wcscmp( value, L"dog" ),
"Expecting initial env to be derived from current env (got %ls)\n", value );
}
......
......@@ -132,13 +132,12 @@ static void test_initial_environ( void )
ok( p__p__environ() != NULL, "Unexpected NULL _environ[]\n" );
ok( *p__p__environ() != NULL, "Unexpected empty _environ[]\n" );
ok( p_get_initial_narrow_environment() != NULL, "Unexpected empty narrow initial environment\n" );
todo_wine
ok( p_get_initial_narrow_environment() == *p__p__environ(), "Expecting _environ[] to match initial narrow environment\n" );
ok( p__p__wenviron() != NULL, "Unexpected NULL _wenviron[]\n" );
ok( *p__p__wenviron() == NULL, "Unexpected non empty _wenviron[]\n" );
ok( p_get_initial_wide_environment() != NULL, "Unexpected empty wide initial environment\n" );
todo_wine
ok( p_get_initial_wide_environment() != NULL, "Unexpected empty wide initial environment\n" );
ok( p_get_initial_wide_environment() == *p__p__wenviron(), "Expecting _wenviron[] to match initial wide environment\n" );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment