Author: chromatic
Date: Sun Jun 17 14:01:10 2007
New Revision: 19068
Modified:
trunk/config/gen/platform/win32/env.c
trunk/t/pmc/env.t
Log:
[Config] Improve environment handling on Windows (Ron Blaschke, RT #43235;
fixes #37301 and #40972).
Modified: trunk/config/gen/platform/win32/env.c
==============================================================================
--- trunk/config/gen/platform/win32/env.c (original)
+++ trunk/config/gen/platform/win32/env.c Sun Jun 17 14:01:10 2007
@@ -1,13 +1,58 @@
/*
+ On Windows there are two ways to access the environment. Either through the
+ Windows environment block, using GetEnvironmentVariable,
+ SetEnvironmentVariable and GetEnvironmentStrings, or the C runtime using
+ _getenv, _putenv and _environ.
+
+ Changes through the C runtime are reflected in the environment block, but
+ changes in the environment block are NOT reflected in the C runtime!
+
+ To keep both in sync we always update environment variables through the C
+ runtime. Getting an environment variable can be done either way,
+ whichever is more convenient.
+*/
+
+/*
** Parrot_setenv()
*/
void
Parrot_setenv(const char *name, const char *value)
{
- SetEnvironmentVariable(name, value);
-}
+ assert(name != NULL);
+ assert(value != NULL);
+ {
+ const int name_len = strlen(name );
+ const int value_len = strlen(value);
+
+ {
+ char * const envstring = malloc(
+ name_len /* name */
+ + 1 /* '=' */
+ + value_len /* value */
+ + 1 /* string terminator */
+ );
+ if (envstring == NULL) {
+ /* TODO: Shouldn't we tell anyone that we failed? */
+ return;
+ }
+
+ /* Save a bit of time, by using the fact we already have the
+ lengths, avoiding strcat */
+ strcpy(envstring, name );
+ strcpy(envstring + name_len, "=" );
+ strcpy(envstring + name_len + 1, value);
+
+ if (_putenv(envstring) == 0) {
+ /* success */
+ } else {
+ /* TODO: Shouldn't we tell anyone that we failed? */
+ }
+ free(envstring);
+ }
+ }
+}
char *
Parrot_getenv(const char *name, int *free_it)
@@ -25,10 +70,15 @@
return buffer;
}
+
void
Parrot_unsetenv(const char *name)
{
- SetEnvironmentVariable(name, NULL);
+/* You can remove a variable from the environment by specifying an empty
+ string -- in other words, by specifying only varname=.
+ -- _putenv, _wputenv (CRT) documentation
+*/
+ Parrot_setenv(name, "");
}
/*
Modified: trunk/t/pmc/env.t
==============================================================================
--- trunk/t/pmc/env.t (original)
+++ trunk/t/pmc/env.t Sun Jun 17 14:01:10 2007
@@ -92,11 +92,7 @@
ok 2
OUT
-SKIP:
-{
- skip 'iterator not available on win32' => 1
- if 'MSWin32' eq $^O;
- pasm_output_is( <<'CODE', <<OUT, "iterate" );
+pasm_output_is( <<'CODE', <<OUT, "iterate" );
new P0, .Env
set P0["PARROT_1"], "hello"
set P0["PARROT_2"], "polly"
@@ -121,10 +117,8 @@
CODE
ok
OUT
-}
SKIP: {
-
# This will not work on our unsetenv implementation
skip( "no native unsetenv", 1 ) unless $PConfig{"unsetenv"};
pasm_output_is( <<'CODE', <<OUT, "exists/delete" );
@@ -173,10 +167,7 @@
0
OUTPUT
-SKIP: {
- skip 'not changing environment on windows', 2 if $^O eq 'MSWin32';
-
- pir_output_is( << 'CODE', << 'OUTPUT', "get_integer()" );
+pir_output_is( << 'CODE', << 'OUTPUT', "get_integer()" );
.sub main
.local pmc env
.local int num_before, num_after, num_diff
@@ -197,7 +188,7 @@
3
OUTPUT
- pir_output_is( << 'CODE', << 'OUTPUT', "get_number()" );
+pir_output_is( << 'CODE', << 'OUTPUT', "get_number()" );
.sub main
.local pmc env
.local num num_before, num_after, num_diff
@@ -217,7 +208,6 @@
CODE
3.000000
OUTPUT
-}
pasm_output_is( <<'CODE', <<OUT, "getenv - null key" );
new P0, .Env