changeset 29492:be4b78fb4411

Replace Unicode conversion functions from gnulib with STL functions. * liboctave/system/lo-sysdep.cc (u8_to_wstring, u8_from_wstring): Use C++11 functions to convert between UTF-8 and the Unicode encoding that is used for "wstring"s. (putenv_wrapper): Use "u8_to_wstring" instead of "u8_to_wchar". * liboctave/system/oct-env.cc (do_get_user_config_directory, do_get_user_data_directory): Use "u8_from_wstring" instead of "u8_from_wchar". * libinterp/corefcn/sysdep.cc (popen): Use "u8_to_wstring" instead of "u8_to_wchar".
author Markus Mützel <markus.muetzel@gmx.de>
date Fri, 02 Apr 2021 19:28:07 +0200
parents 747f592e2001
children de40b395b9c3
files libinterp/corefcn/sysdep.cc liboctave/system/lo-sysdep.cc liboctave/system/oct-env.cc
diffstat 3 files changed, 55 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/sysdep.cc	Mon Apr 05 09:15:48 2021 -0700
+++ b/libinterp/corefcn/sysdep.cc	Fri Apr 02 19:28:07 2021 +0200
@@ -698,24 +698,14 @@
   FILE * popen (const char *command, const char *mode)
   {
 #if defined (__MINGW32__) || defined (_MSC_VER)
-    wchar_t *wcommand = u8_to_wchar (command);
-    wchar_t *wmode = u8_to_wchar (mode);
-
-    unwind_action free_memory ([=] ()
-                               {
-                                 ::free (wcommand);
-                                 ::free (wmode);
-                               });
+    std::wstring wcommand = octave::sys::u8_to_wstring (command);
+    std::wstring wmode = octave::sys::u8_to_wstring (mode);
 
-    if (wmode && wmode[0] && ! wmode[1])
-      {
-        // Use binary mode on Windows if unspecified
-        wchar_t tmode[3] = {wmode[0], L'b', L'\0'};
+    // Use binary mode on Windows if unspecified
+    if (wmode.length () < 2)
+      wmode += L'b';
 
-        return _wpopen (wcommand, tmode);
-      }
-    else
-      return _wpopen (wcommand, wmode);
+    return _wpopen (wcommand.c_str (), wmode.c_str ());
 #else
     return ::popen (command, mode);
 #endif
--- a/liboctave/system/lo-sysdep.cc	Mon Apr 05 09:15:48 2021 -0700
+++ b/liboctave/system/lo-sysdep.cc	Fri Apr 02 19:28:07 2021 +0200
@@ -28,6 +28,8 @@
 #endif
 
 #include <cstdlib>
+#include <locale>
+#include <codecvt>
 
 #include "dir-ops.h"
 #include "file-ops.h"
@@ -35,7 +37,6 @@
 #include "lo-sysdep.h"
 #include "localcharset-wrapper.h"
 #include "putenv-wrapper.h"
-#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 #include "unsetenv-wrapper.h"
 
@@ -46,6 +47,7 @@
 #  include "filepos-wrappers.h"
 #  include "lo-hash.h"
 #  include "oct-locbuf.h"
+#  include "uniconv-wrappers.h"
 #  include "unwind-prot.h"
 #endif
 
@@ -425,33 +427,34 @@
     void
     putenv_wrapper (const std::string& name, const std::string& value)
     {
-      // 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.
+      std::string new_env = name + "=" + value;
 
-      int new_len = name.length () + value.length () + 2;
-
-      // FIXME: This leaks memory, but so would a call to setenv.
+      // FIXME: The malloc 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));
-
-      if (new_item)
-        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 defined (OCTAVE_USE_WINDOWS_API)
-      wchar_t *wnew_item = u8_to_wchar (new_item);
+      std::wstring new_wenv = u8_to_wstring (new_env);
+
+      int len = (new_wenv.length () + 1) * sizeof (wchar_t);
+
+      wchar_t *new_item = static_cast<wchar_t *> (std::malloc (len));
+
+      wcscpy (new_item, new_wenv.c_str());
 
-      // free new_item, but leak wnew_item (see above)
-      unwind_action free_new_item ([=] () { std::free (new_item); });
+      if (_wputenv (new_item) < 0)
+        (*current_liboctave_error_handler)
+          ("putenv (%s) failed", new_env.c_str());
+#else
+      int len = new_env.length () + 1;
 
-      if (_wputenv (wnew_item) < 0)
-        (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
-#else
+      char *new_item = static_cast<char *> (std::malloc (len));
+
+      std::strcpy (new_item, new_env.c_str());
+
       if (octave_putenv_wrapper (new_item) < 0)
         (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
 #endif
@@ -486,20 +489,21 @@
     std::wstring
     u8_to_wstring (const std::string& utf8_string)
     {
-      size_t srclen = utf8_string.length ();
-      const uint8_t *src = reinterpret_cast<const uint8_t *>
-                           (utf8_string.c_str ());
-
-      size_t length = 0;
-      wchar_t *wchar = reinterpret_cast<wchar_t *>
-                       (octave_u8_conv_to_encoding ("wchar_t", src, srclen,
-                                                    &length));
+      // convert multibyte UTF-8 string to wide character string
+      static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>
+        wchar_conv;
 
       std::wstring retval = L"";
-      if (wchar != nullptr)
+
+      try
         {
-          retval = std::wstring (wchar, length / sizeof (wchar_t));
-          free (static_cast<void *> (wchar));
+          retval = wchar_conv.from_bytes (utf8_string);
+        }
+      catch (const std::range_error& e)
+        {
+          // What to do in case of error?
+          // error ("u8_to_wstring: converting from UTF-8 to wchar_t: %s",
+          //        e.what ());
         }
 
       return retval;
@@ -508,19 +512,21 @@
     std::string
     u8_from_wstring (const std::wstring& wchar_string)
     {
-      size_t srclen = wchar_string.length () * sizeof (wchar_t);
-      const char *src = reinterpret_cast<const char *> (wchar_string.c_str ());
-
-      size_t length = 0;
-      char *mbchar = reinterpret_cast<char *>
-                     (octave_u8_conv_from_encoding ("wchar_t", src, srclen,
-                                                    &length));
+      // convert wide character string to multibyte UTF-8 string
+      static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>
+        wchar_conv;
 
       std::string retval = "";
-      if (mbchar != nullptr)
+
+      try
         {
-          retval = std::string (mbchar, length);
-          free (static_cast<void *> (mbchar));
+          retval = wchar_conv.to_bytes (wchar_string);
+        }
+      catch (const std::range_error& e)
+        {
+          // What to do in case of error?
+          // error ("u8_from_wstring: converting from wchar_t to UTF-8: %s",
+          //        e.what ());
         }
 
       return retval;
--- a/liboctave/system/oct-env.cc	Mon Apr 05 09:15:48 2021 -0700
+++ b/liboctave/system/oct-env.cc	Fri Apr 02 19:28:07 2021 +0200
@@ -61,8 +61,6 @@
 #include "unistd-wrappers.h"
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-#  include "uniconv-wrappers.h"
-
 #  include <windows.h>
 #  include <shlobj.h>
 #endif
@@ -254,18 +252,14 @@
       wchar_t path[MAX_PATH+1];
       if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
                             nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
-        {
-          char *app_data = u8_from_wchar (path);
-          cfg_dir = app_data;
-          free (app_data);
-        }
+        cfg_dir = u8_from_wstring (path);
 #else
       cfg_dir = do_getenv ("XDG_CONFIG_HOME");
+#endif
 
       if (cfg_dir.empty ())
         cfg_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
              + ".config";
-#endif
 
       return cfg_dir;
     }
@@ -279,18 +273,14 @@
       wchar_t path[MAX_PATH+1];
       if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
                             nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
-        {
-          char *app_data = u8_from_wchar (path);
-          data_dir = app_data;
-          free (app_data);
-        }
+        data_dir = u8_from_wstring (path);
 #else
       data_dir = do_getenv ("XDG_DATA_HOME");
+#endif
 
       if (data_dir.empty ())
         data_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
              + ".local" + sys::file_ops::dir_sep_str () + "share";
-#endif
 
       return data_dir;
   }