# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1537720252 -7200
#      Sun Sep 23 18:30:52 2018 +0200
# Node ID ad8cc9ef6f075d01af93a8da3696931bcf2fa45c
# Parent  8b35d78ff488ee2416c9ac0f749cc2e4384efe55
Support non-ASCII characters in environment variables in Windows (bug #53922).

* lo-sysdep.[cc/h] (octave::sys::getenv_wrapper, octave::sys::putenv_wrapper):
Add new functions to call Unicode API on Windows.

* oct-env.cc (putenv, do_getenv), sysdep.cc (Funsetenv): Use these new
functions.

* lo-utils.[cc/h] (octave_putenv): Remove function moved to lo-sysdep.

diff -r 8b35d78ff488 -r ad8cc9ef6f07 libinterp/corefcn/sysdep.cc
--- a/libinterp/corefcn/sysdep.cc	Fri Sep 28 12:38:33 2018 +0200
+++ b/libinterp/corefcn/sysdep.cc	Sun Sep 23 18:30:52 2018 +0200
@@ -66,7 +66,6 @@
 #include "oct-env.h"
 #include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
-#include "unsetenv-wrapper.h"
 
 #include "builtin-defun-decls.h"
 #include "Cell.h"
@@ -714,7 +713,7 @@
 
   std::string tmp = args(0).string_value ();
 
-  return ovl (octave_unsetenv_wrapper (tmp.c_str ()));
+  return ovl (octave::sys::unsetenv_wrapper (tmp));
 }
 
 /*
diff -r 8b35d78ff488 -r ad8cc9ef6f07 liboctave/system/lo-sysdep.cc
--- a/liboctave/system/lo-sysdep.cc	Fri Sep 28 12:38:33 2018 +0200
+++ b/liboctave/system/lo-sysdep.cc	Sun Sep 23 18:30:52 2018 +0200
@@ -30,8 +30,10 @@
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "putenv-wrapper.h"
 #include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
+#include "unsetenv-wrapper.h"
 
 #if defined (OCTAVE_USE_WINDOWS_API)
 #  include <windows.h>
@@ -153,6 +155,67 @@
 #endif
     }
 
+    void
+    putenv_wrapper (const std::string& name, const std::string& value)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      std::wstring wname = u8_to_wstring (name);
+      std::wstring wval = u8_to_wstring (value);
+
+      if (SetEnvironmentVariableW (wname.c_str (), wval.c_str ()) == 0)
+        (*current_liboctave_error_handler)
+          ("putenv (%s, %s) failed with error %d", name, value,
+           GetLastError ());
+#else
+      // This function was adapted from xputenv from Karl Berry's kpathsearch
+      // library.
+      // FIXME: make this do the right thing if we don't have a SMART_PUTENV.
+
+      int new_len = name.length () + value.length () + 2;
+
+      // FIXME: This leaks memory, but so would a call to setenv.
+      // Short of extreme measures to track memory, altering the environment
+      // always leaks memory, but the saving grace is that the leaks are small.
+
+      char *new_item = static_cast<char *> (std::malloc (new_len));
+
+      sprintf (new_item, "%s=%s", name.c_str (), value.c_str ());
+
+      // As far as I can see there's no way to distinguish between the
+      // various errors; putenv doesn't have errno values.
+
+      if (octave_putenv_wrapper (new_item) < 0)
+        (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
+#endif
+    }
+
+    std::string
+    getenv_wrapper (const std::string& name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      std::wstring wname = u8_to_wstring (name);
+      const size_t MAX_ENV_SIZE = 32767;
+      wchar_t *buf = static_cast<wchar_t *>
+        (std::malloc (MAX_ENV_SIZE * sizeof (wchar_t)));
+      int size = GetEnvironmentVariableW (wname.c_str (), buf, MAX_ENV_SIZE);
+      return size ? u8_from_wstring (std::wstring (buf, size)) : "";
+#else
+      char *env = ::getenv (name.c_str ());
+      return env ? env : "";
+#endif
+    }
+
+    int
+    unsetenv_wrapper (const std::string& name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      std::wstring wname = u8_to_wstring (name);
+      return (SetEnvironmentVariableW (wname.c_str (), nullptr) ? 0 : -1);
+#else
+      return octave_unsetenv_wrapper (name.c_str ());
+#endif
+    }
+
     std::wstring
     u8_to_wstring (const std::string& utf8_string)
     {
diff -r 8b35d78ff488 -r ad8cc9ef6f07 liboctave/system/lo-sysdep.h
--- a/liboctave/system/lo-sysdep.h	Fri Sep 28 12:38:33 2018 +0200
+++ b/liboctave/system/lo-sysdep.h	Sun Sep 23 18:30:52 2018 +0200
@@ -46,6 +46,13 @@
 
     extern std::FILE * fopen (const std::string& name, const std::string& mode);
 
+    extern void putenv_wrapper (const std::string& name,
+                                const std::string& value);
+
+    extern std::string getenv_wrapper (const std::string&);
+
+    extern int unsetenv_wrapper (const std::string&);
+
     extern std::wstring u8_to_wstring (const std::string&);
 
     extern std::string u8_from_wstring (const std::wstring&);
diff -r 8b35d78ff488 -r ad8cc9ef6f07 liboctave/system/oct-env.cc
--- a/liboctave/system/oct-env.cc	Fri Sep 28 12:38:33 2018 +0200
+++ b/liboctave/system/oct-env.cc	Sun Sep 23 18:30:52 2018 +0200
@@ -241,7 +241,7 @@
     void
     env::putenv (const std::string& name, const std::string& value)
     {
-      octave_putenv (name, value);
+      putenv_wrapper (name, value);
     }
 
     bool
@@ -531,9 +531,7 @@
     std::string
     env::do_getenv (const std::string& name) const
     {
-      char *value = ::getenv (name.c_str ());
-
-      return value ? value : "";
+      return getenv_wrapper (name);
     }
 
     // Do the work of changing to the directory NEWDIR.
diff -r 8b35d78ff488 -r ad8cc9ef6f07 liboctave/util/lo-utils.cc
--- a/liboctave/util/lo-utils.cc	Fri Sep 28 12:38:33 2018 +0200
+++ b/liboctave/util/lo-utils.cc	Sun Sep 23 18:30:52 2018 +0200
@@ -39,7 +39,6 @@
 #include "lo-ieee.h"
 #include "lo-mappers.h"
 #include "lo-utils.h"
-#include "putenv-wrapper.h"
 
 bool xis_int_or_inf_or_nan (double x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
@@ -85,30 +84,6 @@
   return tmp;
 }
 
-// This function was adapted from xputenv from Karl Berry's kpathsearch
-// library.
-
-// FIXME: make this do the right thing if we don't have a SMART_PUTENV.
-
-void
-octave_putenv (const std::string& name, const std::string& value)
-{
-  int new_len = name.length () + value.length () + 2;
-
-  // FIXME: This leaks memory, but so would a call to setenv.
-  // Short of extreme measures to track memory, altering the environment
-  // always leaks memory, but the saving grace is that the leaks are small.
-  char *new_item = static_cast<char *> (std::malloc (new_len));
-
-  sprintf (new_item, "%s=%s", name.c_str (), value.c_str ());
-
-  // As far as I can see there's no way to distinguish between the
-  // various errors; putenv doesn't have errno values.
-
-  if (octave_putenv_wrapper (new_item) < 0)
-    (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
-}
-
 std::string
 octave_fgets (FILE *f)
 {
diff -r 8b35d78ff488 -r ad8cc9ef6f07 liboctave/util/lo-utils.h
--- a/liboctave/util/lo-utils.h	Fri Sep 28 12:38:33 2018 +0200
+++ b/liboctave/util/lo-utils.h	Sun Sep 23 18:30:52 2018 +0200
@@ -76,9 +76,6 @@
 
 extern OCTAVE_API char * strsave (const char *);
 
-extern OCTAVE_API void
-octave_putenv (const std::string&, const std::string&);
-
 extern OCTAVE_API std::string octave_fgets (std::FILE *);
 extern OCTAVE_API std::string octave_fgetl (std::FILE *);
 
