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; ...@@ -60,77 +60,6 @@ int MSVCRT_app_type = 0;
char* MSVCRT__pgmptr = NULL; char* MSVCRT__pgmptr = NULL;
WCHAR* MSVCRT__wpgmptr = 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 ) static char **build_argv( WCHAR **wargv )
{ {
int argc; int argc;
...@@ -433,9 +362,7 @@ void msvcrt_init_args(void) ...@@ -433,9 +362,7 @@ void msvcrt_init_args(void)
MSVCRT___unguarded_readlc_active = 0; MSVCRT___unguarded_readlc_active = 0;
MSVCRT__fmode = _O_TEXT; MSVCRT__fmode = _O_TEXT;
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(NULL); env_init(FALSE, FALSE);
MSVCRT___initenv = msvcrt_SnapshotOfEnvironmentA(NULL);
MSVCRT___winitenv = msvcrt_SnapshotOfEnvironmentW(NULL);
MSVCRT__pgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH); MSVCRT__pgmptr = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
if (MSVCRT__pgmptr) if (MSVCRT__pgmptr)
...@@ -554,9 +481,8 @@ int CDECL __wgetmainargs(int *argc, wchar_t** *wargv, wchar_t** *wenvp, ...@@ -554,9 +481,8 @@ int CDECL __wgetmainargs(int *argc, wchar_t** *wargv, wchar_t** *wenvp,
MSVCRT___wargv = initial_wargv; MSVCRT___wargv = initial_wargv;
} }
/* Initialize the _wenviron array if it's not already created. */ env_init(TRUE, FALSE);
if (!MSVCRT__wenviron)
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
*argc = MSVCRT___argc; *argc = MSVCRT___argc;
*wargv = MSVCRT___wargv; *wargv = MSVCRT___wargv;
*wenvp = MSVCRT__wenviron; *wenvp = MSVCRT__wenviron;
......
...@@ -25,6 +25,83 @@ ...@@ -25,6 +25,83 @@
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); 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) static int env_get_index(const char *name)
{ {
int i, len; int i, len;
...@@ -77,10 +154,7 @@ static wchar_t * wgetenv_helper(const wchar_t *name) ...@@ -77,10 +154,7 @@ static wchar_t * wgetenv_helper(const wchar_t *name)
int idx; int idx;
if (!name) return NULL; if (!name) return NULL;
if (env_init(TRUE, FALSE)) return NULL;
/* Initialize the _wenviron array if it's not already created. */
if (!MSVCRT__wenviron)
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(NULL);
idx = wenv_get_index(name); idx = wenv_get_index(name);
if (!MSVCRT__wenviron[idx]) return NULL; if (!MSVCRT__wenviron[idx]) return NULL;
...@@ -133,10 +207,9 @@ int CDECL _putenv(const char *str) ...@@ -133,10 +207,9 @@ int CDECL _putenv(const char *str)
/* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */ /* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0; 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 */ /* Update the __p__wenviron array only when already initialized */
if (MSVCRT__wenviron) if (ret != -1 && MSVCRT__wenviron) ret = env_init(TRUE, TRUE);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron);
finish: finish:
HeapFree(GetProcessHeap(), 0, name); HeapFree(GetProcessHeap(), 0, name);
...@@ -154,6 +227,8 @@ int CDECL _wputenv(const wchar_t *str) ...@@ -154,6 +227,8 @@ int CDECL _wputenv(const wchar_t *str)
TRACE("%s\n", debugstr_w(str)); TRACE("%s\n", debugstr_w(str));
if (env_init(TRUE, FALSE)) return -1;
if (!str) if (!str)
return -1; return -1;
name = HeapAlloc(GetProcessHeap(), 0, (wcslen(str) + 1) * sizeof(wchar_t)); name = HeapAlloc(GetProcessHeap(), 0, (wcslen(str) + 1) * sizeof(wchar_t));
...@@ -178,8 +253,8 @@ int CDECL _wputenv(const wchar_t *str) ...@@ -178,8 +253,8 @@ int CDECL _wputenv(const wchar_t *str)
/* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */ /* _putenv returns success on deletion of nonexistent variable, unlike [Rtl]SetEnvironmentVariable */
if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0; if ((ret == -1) && (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) ret = 0;
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ); if (ret != -1) ret = env_init(FALSE, TRUE);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron); if (ret != -1) ret = env_init(TRUE, TRUE);
finish: finish:
HeapFree(GetProcessHeap(), 0, name); HeapFree(GetProcessHeap(), 0, name);
...@@ -208,9 +283,8 @@ errno_t CDECL _putenv_s(const char *name, const char *value) ...@@ -208,9 +283,8 @@ errno_t CDECL _putenv_s(const char *name, const char *value)
} }
} }
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ); env_init(FALSE, TRUE);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron); env_init(TRUE, TRUE);
return ret; return ret;
} }
...@@ -223,6 +297,8 @@ errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value) ...@@ -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)); 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(name != NULL)) return EINVAL;
if (!MSVCRT_CHECK_PMT(value != 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) ...@@ -236,9 +312,8 @@ errno_t CDECL _wputenv_s(const wchar_t *name, const wchar_t *value)
} }
} }
MSVCRT__environ = msvcrt_SnapshotOfEnvironmentA(MSVCRT__environ); env_init(FALSE, TRUE);
MSVCRT__wenviron = msvcrt_SnapshotOfEnvironmentW(MSVCRT__wenviron); env_init(TRUE, TRUE);
return ret; return ret;
} }
......
...@@ -205,9 +205,10 @@ void __cdecl _amsg_exit(int errnum); ...@@ -205,9 +205,10 @@ void __cdecl _amsg_exit(int errnum);
extern char **MSVCRT__environ; extern char **MSVCRT__environ;
extern wchar_t **MSVCRT__wenviron; extern wchar_t **MSVCRT__wenviron;
extern char **MSVCRT___initenv;
extern wchar_t **MSVCRT___winitenv;
extern char ** msvcrt_SnapshotOfEnvironmentA(char **); int env_init(BOOL, BOOL);
extern wchar_t ** msvcrt_SnapshotOfEnvironmentW(wchar_t **);
wchar_t *msvcrt_wstrdupa(const char *); wchar_t *msvcrt_wstrdupa(const char *);
......
...@@ -139,7 +139,6 @@ static void test__environ(void) ...@@ -139,7 +139,6 @@ static void test__environ(void)
{ {
initenv = *p__p___initenv(); initenv = *p__p___initenv();
todo_wine
ok( initenv == *p_environ, ok( initenv == *p_environ,
"Expected _environ to be equal to initial env\n" ); "Expected _environ to be equal to initial env\n" );
} }
...@@ -195,7 +194,6 @@ static void test__wenviron(void) ...@@ -195,7 +194,6 @@ static void test__wenviron(void)
if (p__p___winitenv) if (p__p___winitenv)
{ {
wchar_t ***retptr = p__p___winitenv(); wchar_t ***retptr = p__p___winitenv();
todo_wine
ok( !*retptr, "Expected initial env to be NULL\n" ); ok( !*retptr, "Expected initial env to be NULL\n" );
} }
else else
...@@ -235,7 +233,6 @@ static void test__wenviron(void) ...@@ -235,7 +233,6 @@ static void test__wenviron(void)
"Expected _wenviron to be different from __p___winitenv() %p %p\n", *retptr, *p_wenviron ); "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 */ /* test that w-initial env is derived from current _environ[] and not from ansi initial env */
value = env_get_valueW( *retptr, L"cat" ); value = env_get_valueW( *retptr, L"cat" );
todo_wine
ok( value && !wcscmp( value, L"dog" ), ok( value && !wcscmp( value, L"dog" ),
"Expecting initial env to be derived from current env (got %ls)\n", value ); "Expecting initial env to be derived from current env (got %ls)\n", value );
} }
......
...@@ -132,13 +132,12 @@ static void test_initial_environ( void ) ...@@ -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 NULL _environ[]\n" );
ok( *p__p__environ() != NULL, "Unexpected empty _environ[]\n" ); ok( *p__p__environ() != NULL, "Unexpected empty _environ[]\n" );
ok( p_get_initial_narrow_environment() != NULL, "Unexpected empty narrow initial environment\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_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 NULL _wenviron[]\n" );
ok( *p__p__wenviron() == NULL, "Unexpected non empty _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 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" ); 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