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

Reply via email to