# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1479043108 -3600
#      Sun Nov 13 14:18:28 2016 +0100
# Node ID 5ae34919549ebb040c39de40c951cf9e790534bf
# Parent  dc828d9a7f3ab1e175199ea47ea88d08ad38fbaa
Use wide character Windows API (bug #49118).

* unistd-wrappers.[cc,h], stat-wrappers.[cc,h]: Add wrappers for wide
characters Windows API.

* file-ops.[cc,h]: Add helper functions for convertion between multibyte
UTF-8 strings and wide character (UTF-16) strings. Add helper function
to get short filename (8.3) from wide character (UTF-16) filename. Use
wide character API for mkdir.

* lo-sysdep.cc, sysdep.cc, oct-parse.in.yy: Use wide character API for
getcwd, chdir, same_file_internal and parse_fcn_file.

* ls-hdf5.c, load-save.cc: Use short filenames (8.3) for HDF5.

diff -r dc828d9a7f3a -r 5ae34919549e libinterp/corefcn/load-save.cc
--- a/libinterp/corefcn/load-save.cc	Thu Nov 10 20:03:02 2016 -0800
+++ b/libinterp/corefcn/load-save.cc	Sun Nov 13 14:18:28 2016 +0100
@@ -302,7 +302,11 @@
 
 #if defined (HAVE_HDF5)
   // check this before we open the file
+#if defined (OCTAVE_USE_WINDOWS_API)
+  if (H5Fis_hdf5 (octave::sys::get_short_filename (fname.c_str ())) > 0)
+#else
   if (H5Fis_hdf5 (fname.c_str ()) > 0)
+#endif
     return LS_HDF5;
 #endif
 
@@ -1661,8 +1665,14 @@
           if (append)
             error ("save: appending to HDF5 files is not implemented");
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+          bool write_header_info
+            = ! (append && H5Fis_hdf5 (
+                 octave::sys::get_short_filename (fname.c_str ())) > 0);
+#else
           bool write_header_info
             = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
+#endif
 
           hdf5_ofstream hdf5_file (fname.c_str (), mode);
 
diff -r dc828d9a7f3a -r 5ae34919549e libinterp/corefcn/ls-hdf5.cc
--- a/libinterp/corefcn/ls-hdf5.cc	Thu Nov 10 20:03:02 2016 -0800
+++ b/libinterp/corefcn/ls-hdf5.cc	Sun Nov 13 14:18:28 2016 +0100
@@ -91,15 +91,30 @@
 {
 #if defined (HAVE_HDF5)
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+  const char *s_name = octave::sys::get_short_filename (name);
+#else
+  const char *s_name = name;
+#endif
+
   if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
+    file_id = H5Fopen (s_name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
   else if (mode & std::ios::out)
     {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+      if (mode & std::ios::app && H5Fis_hdf5 (s_name) > 0)
+        file_id = H5Fopen (s_name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
       else
+#if defined (OCTAVE_USE_WINDOWS_API)
+        {
+          // FIXME: Create a file with an ASCII name in an accessible folder.
+          //        Close the file, move and rename using wchar_t and re-open.
+          file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
+                              octave_H5P_DEFAULT);
+        }
+#else
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
+#endif
     }
   if (file_id < 0)
     std::ios::setstate (std::ios::badbit);
@@ -138,15 +153,30 @@
 
   clear ();
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+  const char *s_name = octave::sys::get_short_filename (name);
+#else
+  const char *s_name = name;
+#endif
+
   if (mode & std::ios::in)
-    file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
+    file_id = H5Fopen (s_name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
   else if (mode & std::ios::out)
     {
-      if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
-        file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
+      if (mode & std::ios::app && H5Fis_hdf5 (s_name) > 0)
+        file_id = H5Fopen (s_name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
       else
+#if defined (OCTAVE_USE_WINDOWS_API)
+        {
+          // FIXME: Create a file with an ASCII name in an accessible folder.
+          //        Close the file move and rename using wchar_t and re-open
+          file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
+                              octave_H5P_DEFAULT);
+        }
+#else
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
+#endif
     }
   if (file_id < 0)
     std::ios::setstate (std::ios::badbit);
diff -r dc828d9a7f3a -r 5ae34919549e libinterp/corefcn/sysdep.cc
--- a/libinterp/corefcn/sysdep.cc	Thu Nov 10 20:03:02 2016 -0800
+++ b/libinterp/corefcn/sysdep.cc	Sun Nov 13 14:18:28 2016 +0100
@@ -267,11 +267,11 @@
 
   bool retval = false;
 
-  const char *f1 = file1.c_str ();
-  const char *f2 = file2.c_str ();
+  const wchar_t *f1 = octave::sys::mb2wc (file1.c_str ());
+  const wchar_t *f2 = octave::sys::mb2wc (file2.c_str ());
 
-  bool f1_is_dir = GetFileAttributes (f1) & FILE_ATTRIBUTE_DIRECTORY;
-  bool f2_is_dir = GetFileAttributes (f2) & FILE_ATTRIBUTE_DIRECTORY;
+  bool f1_is_dir = GetFileAttributesW (f1) & FILE_ATTRIBUTE_DIRECTORY;
+  bool f2_is_dir = GetFileAttributesW (f2) & FILE_ATTRIBUTE_DIRECTORY;
 
   // Windows native code
   // Reference: http://msdn2.microsoft.com/en-us/library/aa363788.aspx
@@ -279,13 +279,13 @@
   DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
   HANDLE hfile1
-    = CreateFile (f1, 0, share, 0, OPEN_EXISTING,
+    = CreateFileW (f1, 0, share, 0, OPEN_EXISTING,
                   f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
   if (hfile1 != INVALID_HANDLE_VALUE)
     {
       HANDLE hfile2
-        = CreateFile (f2, 0, share, 0, OPEN_EXISTING,
+        = CreateFileW (f2, 0, share, 0, OPEN_EXISTING,
                       f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
       if (hfile2 != INVALID_HANDLE_VALUE)
diff -r dc828d9a7f3a -r 5ae34919549e libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.in.yy	Thu Nov 10 20:03:02 2016 -0800
+++ b/libinterp/parse-tree/oct-parse.in.yy	Sun Nov 13 14:18:28 2016 +0100
@@ -4156,7 +4156,11 @@
   FILE *ffile = 0;
 
   if (! full_file.empty ())
+#if defined (OCTAVE_USE_WINDOWS_API)
+    ffile = _wfopen (octave::sys::mb2wc (full_file.c_str ()), L"rb");
+#else
     ffile = std::fopen (full_file.c_str (), "rb");
+#endif
 
   if (ffile)
     {
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/system/file-ops.cc
--- a/liboctave/system/file-ops.cc	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/system/file-ops.cc	Sun Nov 13 14:18:28 2016 +0100
@@ -33,6 +33,10 @@
 #  include <algorithm>
 #endif
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#endif
+
 #include <iostream>
 #include <vector>
 
@@ -415,7 +419,12 @@
     {
       msg = "";
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      int status = octave_wmkdir_wrapper (mb2wc (name.c_str ()));
+      octave_unused_parameter (mode);
+#else
       int status = octave_mkdir_wrapper (name.c_str (), mode);
+#endif
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -553,7 +562,11 @@
 
       int status = -1;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      status = octave_wrmdir_wrapper (mb2wc (name.c_str ()));
+#else
       status = octave_rmdir_wrapper (name.c_str ());
+#endif
 
       if (status < 0)
         msg = std::strerror (errno);
@@ -747,6 +760,48 @@
 
       return retval;
     }
+#if defined (OCTAVE_USE_WINDOWS_API)
+    wchar_t *
+    mb2wc (const char *mb)
+    {
+      // convert multibyte UTF-8 string to wide character string
+      int mblen = static_cast<int> (strlen (mb));
+      int wlen = MultiByteToWideChar (65001, 0, mb, mblen, NULL, 0);
+      wchar_t* wc = new wchar_t[wlen+1];
+      MultiByteToWideChar (65001, 0, mb, mblen, wc, wlen);
+      wc[wlen] = 0; // null-terminate string
+      return wc;
+    }
+
+    char *
+    wc2mb (const wchar_t *wc)
+    {
+      // convert wide character string to multibyte UTF-8 string
+      int w_len = static_cast<int> (wcslen (wc));
+      int mb_len = WideCharToMultiByte (65001, 0, wc, w_len, NULL, 0, NULL, NULL);
+      char* mb = new char[mb_len+1];
+      WideCharToMultiByte (65001, 0, wc, w_len, mb, mb_len, NULL, NULL);
+      mb[mb_len] = 0; // null-terminate string
+      return mb;
+    }
+
+    char *
+    get_short_filename (const char *long_filename)
+    {
+      wchar_t *w_long_filename = mb2wc (long_filename);
+      // get short filename (8.3) from wide character filename
+      long length = GetShortPathNameW (w_long_filename, NULL, 0);
+
+      // Dynamically allocate the correct size 
+      // (terminating null char was included in length)
+      wchar_t *w_short_filename = new wchar_t[length];
+      length = GetShortPathNameW (w_long_filename, w_short_filename, length);
+      char *retval = wc2mb (w_short_filename);
+
+      return retval;
+    }
+#endif
+
   }
 }
 
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/system/file-ops.h
--- a/liboctave/system/file-ops.h	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/system/file-ops.h	Sun Nov 13 14:18:28 2016 +0100
@@ -31,6 +31,10 @@
 
 #include "str-vec.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <wchar.h>
+#endif
+
 namespace octave
 {
   namespace sys
@@ -218,6 +222,17 @@
 
     extern OCTAVE_API std::string
     canonicalize_file_name (const std::string&, std::string&);
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+    extern wchar_t *
+    mb2wc (const char *mb);
+
+    extern char *
+    wc2mb (const wchar_t *wc);
+
+    extern char *
+    get_short_filename (const char *long_filename);
+#endif
   }
 }
 
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/system/lo-sysdep.cc
--- a/liboctave/system/lo-sysdep.cc	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/system/lo-sysdep.cc	Sun Nov 13 14:18:28 2016 +0100
@@ -40,6 +40,14 @@
     {
       std::string retval;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t *tmp = octave_wgetcwd_wrapper (NULL, 0);
+
+      if (! tmp)
+        (*current_liboctave_error_handler) ("unable to find current directory");
+
+      retval = wc2mb (tmp);
+#else
       // Using octave_getcwd_wrapper ensures that we have a getcwd that
       // will allocate a buffer as large as necessary if buf and size are
       // both 0.
@@ -50,6 +58,7 @@
         (*current_liboctave_error_handler) ("unable to find current directory");
 
       retval = tmp;
+#endif
       free (tmp);
 
       return retval;
@@ -63,9 +72,10 @@
 #if defined (OCTAVE_USE_WINDOWS_API)
       if (path.length () == 2 && path[1] == ':')
         path += "\\";
+      return octave_wchdir_wrapper (mb2wc (path.c_str ()));
+#else
+      return octave_chdir_wrapper (path.c_str ());
 #endif
-
-      return octave_chdir_wrapper (path.c_str ());
     }
   }
 }
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/wrappers/stat-wrappers.c
--- a/liboctave/wrappers/stat-wrappers.c	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/wrappers/stat-wrappers.c	Sun Nov 13 14:18:28 2016 +0100
@@ -42,6 +42,14 @@
   return mkdir (name, mode);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+int
+octave_wmkdir_wrapper (const wchar_t *name)
+{
+  return _wmkdir (name);
+}
+#endif
+
 int
 octave_mkfifo_wrapper (const char *name, mode_t mode)
 {
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/wrappers/stat-wrappers.h
--- a/liboctave/wrappers/stat-wrappers.h	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/wrappers/stat-wrappers.h	Sun Nov 13 14:18:28 2016 +0100
@@ -30,6 +30,10 @@
 #  include <time.h>
 #endif
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <wchar.h>
+#endif
+
 #include <sys/types.h>
 
 #if defined __cplusplus
@@ -38,6 +42,10 @@
 
 extern int octave_mkdir_wrapper (const char *name, mode_t mode);
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+extern int octave_wmkdir_wrapper (const wchar_t *name);
+#endif
+
 extern int octave_mkfifo_wrapper (const char *name, mode_t mode);
 
 extern int octave_umask_wrapper (mode_t mode);
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/wrappers/unistd-wrappers.c
--- a/liboctave/wrappers/unistd-wrappers.c	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/wrappers/unistd-wrappers.c	Sun Nov 13 14:18:28 2016 +0100
@@ -78,6 +78,14 @@
   return chdir (nm);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+int
+octave_wchdir_wrapper (const wchar_t *nm)
+{
+  return _wchdir (nm);
+}
+#endif
+
 int
 octave_close_wrapper (int fd)
 {
@@ -284,6 +292,14 @@
   return getcwd (nm, len);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+wchar_t *
+octave_wgetcwd_wrapper (wchar_t *nm, size_t len)
+{
+  return _wgetcwd (nm, len);
+}
+#endif
+
 gid_t
 octave_getegid_wrapper (void)
 {
@@ -384,6 +400,14 @@
   return rmdir (nm);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+int
+octave_wrmdir_wrapper (const wchar_t *name)
+{
+  return _wrmdir (name);
+}
+#endif
+
 pid_t
 octave_setsid_wrapper (void)
 {
diff -r dc828d9a7f3a -r 5ae34919549e liboctave/wrappers/unistd-wrappers.h
--- a/liboctave/wrappers/unistd-wrappers.h	Thu Nov 10 20:03:02 2016 -0800
+++ b/liboctave/wrappers/unistd-wrappers.h	Sun Nov 13 14:18:28 2016 +0100
@@ -29,6 +29,10 @@
 
 #include <sys/types.h>
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <wchar.h>
+#endif
+
 #if defined __cplusplus
 extern "C" {
 #endif
@@ -45,6 +49,10 @@
 
 extern int octave_chdir_wrapper (const char *nm);
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+extern int octave_wchdir_wrapper (const wchar_t *nm);
+#endif
+
 extern int octave_close_wrapper (int fd);
 
 extern const char *octave_ctermid_wrapper (void);
@@ -61,6 +69,10 @@
 
 extern char *octave_getcwd_wrapper (char *nm, size_t len);
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+extern wchar_t *octave_wgetcwd_wrapper (wchar_t *nm, size_t len);
+#endif
+
 extern gid_t octave_getegid_wrapper (void);
 
 extern uid_t octave_geteuid_wrapper (void);
@@ -84,6 +96,9 @@
 extern int octave_pipe_wrapper (int *fd);
 
 extern int octave_rmdir_wrapper (const char *nm);
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+extern int octave_wrmdir_wrapper (const wchar_t *name);
+#endif
 
 extern pid_t octave_setsid_wrapper (void);
 
