From: Eric Pouech epouech@codeweavers.com
--- dlls/msvcrt/data.c | 80 +------------------------- dlls/msvcrt/environ.c | 105 +++++++++++++++++++++++++++++----- dlls/msvcrt/msvcrt.h | 5 +- dlls/msvcrt/tests/environ.c | 3 - dlls/ucrtbase/tests/environ.c | 3 +- 5 files changed, 97 insertions(+), 99 deletions(-)
diff --git a/dlls/msvcrt/data.c b/dlls/msvcrt/data.c index 8a8552a151e..bec1e61e411 100644 --- a/dlls/msvcrt/data.c +++ b/dlls/msvcrt/data.c @@ -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; diff --git a/dlls/msvcrt/environ.c b/dlls/msvcrt/environ.c index 96793a8261b..431b4efa2eb 100644 --- a/dlls/msvcrt/environ.c +++ b/dlls/msvcrt/environ.c @@ -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; }
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 7c2dd4835f5..fe626e2e79f 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -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 *);
diff --git a/dlls/msvcrt/tests/environ.c b/dlls/msvcrt/tests/environ.c index 17d75733c85..84d610e6c76 100644 --- a/dlls/msvcrt/tests/environ.c +++ b/dlls/msvcrt/tests/environ.c @@ -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 ); } diff --git a/dlls/ucrtbase/tests/environ.c b/dlls/ucrtbase/tests/environ.c index 4d2dbadd33d..5cc019af673 100644 --- a/dlls/ucrtbase/tests/environ.c +++ b/dlls/ucrtbase/tests/environ.c @@ -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" ); }