# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1516460690 -3600
#      Sat Jan 20 16:04:50 2018 +0100
# Node ID 867168d5097347be47e1014ccfc17b804b5a1af8
# Parent  ce2eb28e0a6d8deeca8a2c82350c352a2237b7d9
Use wide character Windows API for file system (bug #49118).

* uniconv-wrappers.[c,h]: Add convenience C-functions "u8_to_wchar" and
"u8_from_wchar".

* stat-wrappers.c: Use wide character API for mkdir and stat.

* unistd-wrappers.c: Use wide character API for chdir, getcwd, and rmdir.

* lo-sysdep.[cc,h]: Add functions get_dirlist and fopen. Add conversion
functions between utf-8 and wchar_t. Add function get_ASCII_filename that
returns valid filename without non-ASCII characters.

* debug.cc, dirfns.cc, dlmread.cc, help.cc, load-path.cc, load-save.cc,
ls-hdf5.c, urlwrite.cc, gzip.cc, ov-java.cc, oct-parse.in.yy (parse_fcn_file),
file-ops.cc, file-stat.cc, file-info.cc, url-transfer.cc: Use new sysdep
functions.

* sysdep.cc: First steps to get Octave to work when installed on path with
non-ASCII chars. Use wchar interface for __open_with_system_app__, same_file,
octave_popen.

diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/debug.cc
--- a/libinterp/corefcn/debug.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/debug.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -45,6 +45,7 @@
 #include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
+#include "lo-sysdep.h"
 #include "octave-preserve-stream-state.h"
 #include "ov-usr-fcn.h"
 #include "ov.h"
@@ -579,7 +580,7 @@
     os << "dbtype: unknown function " << name << "\n";
   else
     {
-      std::ifstream fs (ff.c_str (), std::ios::in);
+      std::ifstream fs (octave::sys::get_ASCII_filename (ff).c_str (), std::ios::in);
 
       if (! fs)
         os << "dbtype: unable to open '" << ff << "' for reading!\n";
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/dirfns.cc
--- a/libinterp/corefcn/dirfns.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/dirfns.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -186,16 +186,16 @@
 
   dirname = octave::sys::file_ops::tilde_expand (dirname);
 
-  octave::sys::dir_entry dir (dirname);
+  string_vector dirlist;
+  std::string msg;
 
-  if (dir)
+  if (octave::sys::get_dirlist (dirname, dirlist, msg))
     {
-      string_vector dirlist = dir.read ();
       retval(0) = Cell (dirlist.sort ());
       retval(1) = 0.0;
     }
   else
-    retval(2) = dir.error ();
+    retval(2) = msg;
 
   return retval;
 }
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/dlmread.cc
--- a/libinterp/corefcn/dlmread.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/dlmread.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -34,6 +34,7 @@
 
 #include "file-ops.h"
 #include "lo-ieee.h"
+#include "lo-sysdep.h"
 
 #include "defun.h"
 #include "interpreter.h"
@@ -220,7 +221,7 @@
 
       tname = find_data_file_in_load_path ("dlmread", tname);
 
-      input_file.open (tname.c_str (), std::ios::in);
+      input_file.open (octave::sys::get_ASCII_filename (tname).c_str (), std::ios::in);
 
       if (! input_file)
         error ("dlmread: unable to open file '%s'", fname.c_str ());
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/help.cc
--- a/libinterp/corefcn/help.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/help.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -37,6 +37,7 @@
 #include "cmd-edit.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
 #include "str-vec.h"
@@ -579,8 +580,9 @@
 
     if (! initialized)
       {
-        std::ifstream file (m_built_in_docstrings_file.c_str (),
-                            std::ios::in | std::ios::binary);
+        std::ifstream file (
+          octave::sys::get_ASCII_filename (m_built_in_docstrings_file).c_str (),
+          std::ios::in | std::ios::binary);
 
         if (! file)
           error ("failed to open docstrings file: %s",
@@ -662,8 +664,9 @@
         std::streampos beg = txt_limits.first;
         std::streamoff len = txt_limits.second;
 
-        std::ifstream file (m_built_in_docstrings_file.c_str (),
-                            std::ios::in | std::ios::binary);
+        std::ifstream file (
+          octave::sys::get_ASCII_filename (m_built_in_docstrings_file).c_str (),
+          std::ios::in | std::ios::binary);
 
         if (! file)
           error ("failed to open docstrings file: %s",
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/load-path.cc
--- a/libinterp/corefcn/load-path.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/load-path.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -42,6 +42,7 @@
 #include "ov-usr-fcn.h"
 #include "pager.h"
 #include "parse.h"
+#include "sysdep.h"
 #include "unwind-prot.h"
 #include "utils.h"
 
@@ -1068,12 +1069,13 @@
   {
     load_path::dir_info::fcn_file_map_type retval;
 
-    sys::dir_entry dir (d);
-
-    if (dir)
+    string_vector flist;
+    std::string msg;
+
+    if (! octave::sys::get_dirlist (d, flist, msg))
+      warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
+    else
       {
-        string_vector flist = dir.read ();
-
         octave_idx_type len = flist.numel ();
 
         for (octave_idx_type i = 0; i < len; i++)
@@ -1104,11 +1106,6 @@
               }
           }
       }
-    else
-      {
-        std::string msg = dir.error ();
-        warning ("load_path: %s: %s", d.c_str (), msg.c_str ());
-      }
 
     return retval;
   }
@@ -2128,42 +2125,42 @@
   genpath (const std::string& dirname, const string_vector& skip)
   {
     std::string retval;
-
-    sys::dir_entry dir (dirname);
-
-    if (dir)
-      {
-        retval = dirname;
-
-        string_vector dirlist = dir.read ().sort (false);
-
-        octave_idx_type len = dirlist.numel ();
-
-        for (octave_idx_type i = 0; i < len; i++)
-          {
-            std::string elt = dirlist[i];
-
-            bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
-                           || elt[0] == '+');
+  string_vector dirlist;
+  std::string msg;
+
+  if (! sys::get_dirlist (dirname, dirlist, msg))
+    return retval;
+
+  retval = dirname;
+
+  dirlist = dirlist.sort (false);
+
+  octave_idx_type len = dirlist.numel ();
+
+  for (octave_idx_type i = 0; i < len; i++)
+    {
+      std::string elt = dirlist[i];
+
+      bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'
+                     || elt[0] == '+');
+
+      if (! skip_p)
+        {
+          for (octave_idx_type j = 0; j < skip.numel (); j++)
+            {
+              skip_p = (elt == skip[j]);
+              if (skip_p)
+                break;
+            }
 
             if (! skip_p)
               {
-                for (octave_idx_type j = 0; j < skip.numel (); j++)
-                  {
-                    skip_p = (elt == skip[j]);
-                    if (skip_p)
-                      break;
-                  }
-
-                if (! skip_p)
-                  {
-                    std::string nm = sys::file_ops::concat (dirname, elt);
-
-                    sys::file_stat fs (nm);
-
-                    if (fs && fs.is_dir ())
-                      retval += directory_path::path_sep_str () + genpath (nm, skip);
-                  }
+                std::string nm = sys::file_ops::concat (dirname, elt);
+
+                sys::file_stat fs (nm);
+
+                if (fs && fs.is_dir ())
+                  retval += directory_path::path_sep_str () + genpath (nm, skip);
               }
           }
       }
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/load-save.cc
--- a/libinterp/corefcn/load-save.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/load-save.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -221,7 +221,8 @@
 {
   bool retval = false;
 
-  std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+  std::ifstream file (octave::sys::get_ASCII_filename (fname).c_str (),
+                      std::ios::in | std::ios::binary);
 
   unsigned char magic[2];
   if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
@@ -309,7 +310,7 @@
 
 #if defined (HAVE_HDF5)
   // check this before we open the file
-  if (H5Fis_hdf5 (fname.c_str ()) > 0)
+  if (H5Fis_hdf5 (octave::sys::get_ASCII_filename (fname).c_str ()) > 0)
     return LS_HDF5;
 #endif
 
@@ -321,7 +322,8 @@
 
   if (! use_zlib)
     {
-      std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+      std::ifstream file (octave::sys::get_ASCII_filename (fname).c_str (),
+                          std::ios::in | std::ios::binary);
       if (file)
         {
           retval = get_file_format (file, orig_fname);
@@ -829,7 +831,8 @@
           else
 #endif
             {
-              std::ifstream file (fname.c_str (), mode);
+              std::ifstream file (
+                      octave::sys::get_ASCII_filename (fname).c_str (), mode);
 
               if (! file)
                 error ("load: unable to open input file '%s'",
@@ -1692,7 +1695,8 @@
             error ("save: appending to HDF5 files is not implemented");
 
           bool write_header_info
-            = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
+            = ! (append && H5Fis_hdf5 (
+                 octave::sys::get_ASCII_filename (fname).c_str ()) > 0);
 
           hdf5_ofstream hdf5_file (fname.c_str (), mode);
 
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/ls-hdf5.cc
--- a/libinterp/corefcn/ls-hdf5.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/ls-hdf5.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -89,13 +89,19 @@
 {
 #if defined (HAVE_HDF5)
 
+  const char *s_name = 
+                  octave::sys::get_ASCII_filename (std::string (name)).c_str ();
+
   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
+        // FIXME: For Windows, create a file with an ASCII name in an
+        //        accessible folder, close the file move and rename using
+        //        wide character API and re-open.
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
     }
@@ -136,13 +142,18 @@
 
   clear ();
 
+  const char *s_name = octave::sys::get_ASCII_filename (std::string (name)).c_str ();
+
   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
+        // FIXME: For Windows, create a file with an ASCII name in an
+        //        accessible folder, close the file move and rename using
+        //        wide character API and re-open.
         file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
                              octave_H5P_DEFAULT);
     }
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/sysdep.cc
--- a/libinterp/corefcn/sysdep.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/sysdep.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -121,26 +121,26 @@
 
   if (h != INVALID_HANDLE_VALUE)
     {
-      MODULEENTRY32 mod_info;
+      MODULEENTRY32W mod_info;
 
       ZeroMemory (&mod_info, sizeof (mod_info));
       mod_info.dwSize = sizeof (mod_info);
 
-      if (Module32First (h, &mod_info))
+      if (Module32FirstW (h, &mod_info))
         {
           do
             {
-              std::string mod_name (mod_info.szModule);
+              std::string mod_name (octave::sys::u8_from_wstring (mod_info.szModule));
 
               if (mod_name.find ("octinterp") != std::string::npos)
                 {
-                  bin_dir = mod_info.szExePath;
+                  bin_dir = octave::sys::u8_from_wstring (mod_info.szExePath);
                   if (! bin_dir.empty () && bin_dir.back () != '\\')
                     bin_dir.push_back ('\\');
                   break;
                 }
             }
-          while (Module32Next (h, &mod_info));
+          while (Module32NextW (h, &mod_info));
         }
 
       CloseHandle (h);
@@ -208,8 +208,9 @@
   octave_value retval;
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-  HINSTANCE status = ShellExecute (0, 0, file.c_str (), 0, 0,
-                                   SW_SHOWNORMAL);
+  HINSTANCE status = ShellExecuteW (0, 0,
+                                    octave::sys::u8_to_wstring (file).c_str (),
+                                    0, 0, SW_SHOWNORMAL);
 
   // ShellExecute returns a value greater than 32 if successful.
   retval = (reinterpret_cast<ptrdiff_t> (status) > 32);
@@ -257,11 +258,11 @@
 
   bool retval = false;
 
-  const char *f1 = file1.c_str ();
-  const char *f2 = file2.c_str ();
+  const wchar_t *f1 = octave::sys::u8_to_wstring (file1).c_str ();
+  const wchar_t *f2 = octave::sys::u8_to_wstring (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
@@ -269,14 +270,14 @@
   DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
 
   HANDLE hfile1
-    = CreateFile (f1, 0, share, 0, OPEN_EXISTING,
-                  f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+    = 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,
-                      f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
+        = CreateFileW (f2, 0, share, 0, OPEN_EXISTING,
+                       f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
 
       if (hfile2 != INVALID_HANDLE_VALUE)
         {
@@ -510,10 +511,12 @@
       // Use binary mode on Windows if unspecified
       char tmode[3] = {mode[0], 'b', '\0'};
 
-      return _popen (command, tmode);
+      return _wpopen (octave::sys::u8_to_wstring (command).c_str (),
+                      octave::sys::u8_to_wstring (tmode).c_str ());
     }
   else
-    return _popen (command, mode);
+    return _wpopen (octave::sys::u8_to_wstring (command).c_str (),
+                    octave::sys::u8_to_wstring (mode).c_str ());
 #else
   return popen (command, mode);
 #endif
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/corefcn/urlwrite.cc
--- a/libinterp/corefcn/urlwrite.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/corefcn/urlwrite.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -36,6 +36,7 @@
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-handle.h"
 #include "glob-match.h"
@@ -638,7 +639,8 @@
       else
         {
           // FIXME: Does ascii mode need to be flagged here?
-          std::ifstream ifile (file.c_str (), std::ios::in | std::ios::binary);
+          std::ifstream ifile (octave::sys::get_ASCII_filename (file).c_str (),
+                               std::ios::in | std::ios::binary);
 
           if (! ifile.is_open ())
             error ("__ftp_mput__: unable to open file");
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/dldfcn/gzip.cc
--- a/libinterp/dldfcn/gzip.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/dldfcn/gzip.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -61,6 +61,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "glob-match.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "str-vec.h"
 
@@ -97,7 +98,7 @@
     CFile (void) = delete;
 
     CFile (const std::string& path, const std::string& mode)
-      : m_fp (std::fopen (path.c_str (), mode.c_str ()))
+      : m_fp (octave::sys::fopen (path, mode))
     {
       if (! m_fp)
         throw std::runtime_error ("unable to open file");
@@ -483,13 +484,14 @@
       // is_dir and is_reg will return false if failed to stat.
       if (fs.is_dir ())
         {
-          sys::dir_entry dir (path);
-          if (dir)
+          string_vector dirlist;
+          std::string msg;
+
+          // Collect the whole list of filenames first, before recursion
+          // to avoid issues with infinite loop if the action generates
+          // files in the same directory (highly likely).
+          if (sys::get_dirlist (path, dirlist, msg))
             {
-              // Collect the whole list of filenames first, before recursion
-              // to avoid issues with infinite loop if the action generates
-              // files in the same directory (highly likely).
-              string_vector dirlist = dir.read ();
               for (octave_idx_type i = 0; i < dirlist.numel (); i++)
                 if (dirlist(i) != "." && dirlist(i) != "..")
                   walk (sys::file_ops::concat (path, dirlist(i)));
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/octave-value/ov-java.cc
--- a/libinterp/octave-value/ov-java.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/octave-value/ov-java.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -53,6 +53,7 @@
 #include "file-stat.h"
 #include "fpucw-wrappers.h"
 #include "load-path.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-shlib.h"
 #include "ov-java.h"
@@ -237,7 +238,7 @@
 
     void read_java_opts (const std::string& filename)
     {
-      std::ifstream js (filename.c_str ());
+      std::ifstream js (octave::sys::get_ASCII_filename (filename).c_str ());
 
       if (! js.bad () && ! js.fail ())
         {
@@ -413,7 +414,7 @@
 {
   std::string classpath;
 
-  std::ifstream fs (filepath.c_str ());
+  std::ifstream fs (octave::sys::get_ASCII_filename (filepath).c_str ());
 
   if (! fs.bad () && ! fs.fail ())
     {
diff -r ce2eb28e0a6d -r 867168d50973 libinterp/parse-tree/oct-parse.in.yy
--- a/libinterp/parse-tree/oct-parse.in.yy	Fri Jan 19 19:59:28 2018 -0800
+++ b/libinterp/parse-tree/oct-parse.in.yy	Sat Jan 20 16:04:50 2018 +0100
@@ -65,6 +65,7 @@
 #include "interpreter.h"
 #include "lex.h"
 #include "load-path.h"
+#include "lo-sysdep.h"
 #include "oct-hist.h"
 #include "oct-map.h"
 #include "ov-classdef.h"
@@ -4517,7 +4518,7 @@
   FILE *ffile = nullptr;
 
   if (! full_file.empty ())
-    ffile = std::fopen (full_file.c_str (), "rb");
+    ffile = octave::sys::fopen (full_file, "rb");
 
   if (ffile)
     {
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/system/file-ops.cc
--- a/liboctave/system/file-ops.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/system/file-ops.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -42,6 +42,7 @@
 #include "file-ops.h"
 #include "file-stat.h"
 #include "gen-tempname-wrapper.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
 #include "oct-passwd.h"
@@ -550,12 +551,10 @@
 
       int status = 0;
 
-      dir_entry dir (name);
+      string_vector dirlist;
 
-      if (dir)
+      if (get_dirlist (name, dirlist, msg))
         {
-          string_vector dirlist = dir.read ();
-
           for (octave_idx_type i = 0; i < dirlist.numel (); i++)
             {
               octave_quit ();
@@ -596,17 +595,10 @@
             }
 
           if (status >= 0)
-            {
-              dir.close ();
-              status = rmdir (name, msg);
-            }
+            status = rmdir (name, msg);
         }
       else
-        {
-          status = -1;
-
-          msg = dir.error ();
-        }
+        status = -1;
 
       return status;
     }
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/system/lo-sysdep.cc
--- a/liboctave/system/lo-sysdep.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/system/lo-sysdep.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -26,11 +26,21 @@
 
 #include <string>
 
+#include "dir-ops.h"
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#  include <versionhelpers.h>
+
+#  include "lo-hash.h"
+#endif
+
 namespace octave
 {
   namespace sys
@@ -67,5 +77,181 @@
 
       return octave_chdir_wrapper (path.c_str ());
     }
+
+    bool
+    get_dirlist (const std::string& dirname, string_vector& dirlist, std::string& msg)
+    {
+      dirlist = "";
+      msg = "";
+#if defined (OCTAVE_USE_WINDOWS_API)
+      _WIN32_FIND_DATAW ffd;
+
+      std::string path_name (dirname);
+      if (path_name.empty ())
+        return true;
+
+      if (path_name.back () == '\\' || path_name.back () == '/')
+        path_name.push_back ('*');
+      else
+        path_name.append (R"(\*)");
+
+      // Find first file in directory.
+      HANDLE hFind = FindFirstFileW (u8_to_wstring (path_name).c_str (),
+                              &ffd);
+      if (INVALID_HANDLE_VALUE == hFind) 
+        {
+          DWORD errCode = GetLastError ();
+          char *errorText;
+          FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
+                         FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_IGNORE_INSERTS,
+                         NULL, errCode,
+                         MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                         errorText, 0, NULL);
+          if (errorText != NULL)
+            {
+              msg = std::string (errorText);
+              LocalFree (errorText);
+            }
+          return false;
+        }
+
+      std::list<std::string> dirlist_str;
+      do
+        dirlist_str.push_back (u8_from_wstring (ffd.cFileName));
+      while (FindNextFileW (hFind, &ffd) != 0);
+
+      FindClose(hFind);
+
+      dirlist = string_vector (dirlist_str);
+
+#else
+
+      dir_entry dir (dirname);
+
+      if (! dir)
+        {
+          msg = dir.error ();
+          return false;
+        }
+
+      dirlist = dir.read ();
+
+      dir.close ();
+#endif
+
+      return true;
+    }
+
+    std::FILE *
+    fopen (const std::string& filename, const std::string& mode)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      return _wfopen (u8_to_wstring (filename).c_str (),
+                      u8_to_wstring (mode).c_str ());
+#else
+      return std::fopen (filename.c_str (), mode.c_str ());
+#endif
+    }
+
+    std::wstring
+    u8_to_wstring (const std::string& utf8_string)
+    {
+      wchar_t *wchar = nullptr;
+
+      wchar = u8_to_wchar (utf8_string.c_str ());
+
+      std::wstring retval = std::wstring (L"");
+      if (wchar != NULL)
+        {
+          retval = std::wstring (wchar);
+          free (static_cast<void *> (wchar));
+        }
+
+      return retval;
+    }
+
+    std::string
+    u8_from_wstring (const std::wstring& wchar_string)
+    {
+      char *mbchar = nullptr;
+
+      mbchar = u8_from_wchar (wchar_string.c_str ());
+
+      std::string retval = std::string ("");
+      if (mbchar != NULL)
+        {
+          retval = std::string (mbchar);
+          free (static_cast<void *> (mbchar));
+        }
+
+      return retval;
+    }
+
+    std::string
+    get_ASCII_filename (const std::string& orig_file_name)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      // 1. Check whether filename contains non-ASCII (UTF-8) characters
+      std::string::const_iterator first_non_ASCII = 
+                std::find_if (orig_file_name.begin (), orig_file_name.end (),
+                [](char c){return (c < 0 || c >= 128);});
+      if (first_non_ASCII == orig_file_name.end ())
+        return orig_file_name;
+
+      // 2. Check if file system stores short filenames (always ASCII-only).
+      const wchar_t *w_orig_file_name = u8_to_wstring (orig_file_name).c_str ();
+      // get short filename (8.3) from UTF-16 filename
+      long length = GetShortPathNameW (w_orig_file_name, NULL, 0);
+
+      // Dynamically allocate the correct size 
+      // (terminating null char was included in length)
+      wchar_t *w_short_file_name = new wchar_t[length];
+      length = GetShortPathNameW (w_orig_file_name, w_short_file_name, length);
+ 
+      std::string short_file_name = u8_from_wstring (std::wstring (w_short_file_name));
+
+      if (short_file_name.compare (orig_file_name) != 0)
+        return short_file_name;
+
+      // 3. Create hard link with only-ASCII characters
+      // get longest folder that only contains ASCII chars
+      size_t pos = (std::string (orig_file_name.begin (), first_non_ASCII)).
+                        find_last_of (octave::sys::file_ops::dir_sep_chars ());
+      std::string par_dir = orig_file_name.substr (0, pos+1);
+      
+      // create .oct_ascii directory
+      std::string oct_ascii_dir = par_dir + ".oct_ascii";
+      std::string test_dir = canonicalize_file_name (oct_ascii_dir);
+      if (test_dir.empty ())
+      {
+        std::string msg;
+        int status = octave::sys::mkdir (oct_ascii_dir, 0777, msg);
+        if (status < 0)
+          return orig_file_name;
+        // set hidden property
+        SetFileAttributesA (oct_ascii_dir.c_str (), FILE_ATTRIBUTE_HIDDEN);
+      }
+
+      // create file from hash of full filename
+      std::string filename_hash = oct_ascii_dir + file_ops::dir_sep_str () +
+                                  octave::crypto::hash ("SHA1", orig_file_name);
+      std::string _filename_hash_ = canonicalize_file_name (filename_hash);
+      if (! _filename_hash_.empty ())
+        return _filename_hash_;
+
+      wchar_t w_filename_hash[filename_hash.length ()+1] = {0};
+      for (size_t i=0; i < filename_hash.length (); i++)
+        w_filename_hash[i] = filename_hash.at (i);
+      if (CreateHardLinkW (w_filename_hash, w_orig_file_name, NULL))
+        return filename_hash;
+
+      return orig_file_name;
+
+#else
+      return orig_file_name;
+#endif
+    }
+
   }
 }
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/system/lo-sysdep.h
--- a/liboctave/system/lo-sysdep.h	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/system/lo-sysdep.h	Sat Jan 20 16:04:50 2018 +0100
@@ -40,6 +40,17 @@
     extern std::string getcwd (void);
 
     extern int chdir (const std::string&);
+
+    extern bool get_dirlist (const std::string& dirname, string_vector& dirlist,
+                             std::string& msg);
+
+    extern std::FILE * fopen (const std::string& name, const std::string& mode);
+
+    extern std::wstring u8_to_wstring (const std::string&);
+
+    extern std::string u8_from_wstring (const std::wstring&);
+
+    extern std::string get_ASCII_filename (const std::string& long_file_name);
   }
 }
 
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/util/file-info.cc
--- a/liboctave/util/file-info.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/util/file-info.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -32,6 +32,7 @@
 #include "file-info.h"
 #include "file-stat.h"
 #include "lo-error.h"
+#include "lo-sysdep.h"
 
 namespace octave
 {
@@ -81,7 +82,8 @@
 
     size_t sz = fs.size ();
 
-    std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+    std::ifstream file (octave::sys::get_ASCII_filename (fname).c_str (),
+                        std::ios::in | std::ios::binary);
 
     if (file)
       {
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/util/url-transfer.cc
--- a/liboctave/util/url-transfer.cc	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/util/url-transfer.cc	Sat Jan 20 16:04:50 2018 +0100
@@ -36,6 +36,7 @@
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "unwind-prot.h"
 #include "url-transfer.h"
 
@@ -149,62 +150,60 @@
 
         frame.add_fcn (reset_path, this);
 
-        sys::dir_entry dirlist (realdir);
-
-        if (dirlist)
-          {
-            string_vector files = dirlist.read ();
+        string_vector files;
+        std::string msg;
 
-            for (octave_idx_type i = 0; i < files.numel (); i++)
-              {
-                std::string file = files (i);
+        if (sys::get_dirlist (realdir, files, msg))
+          for (octave_idx_type i = 0; i < files.numel (); i++)
+            {
+              std::string file = files (i);
 
-                if (file == "." || file == "..")
-                  continue;
+              if (file == "." || file == "..")
+                continue;
 
-                std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
-                sys::file_stat fs (realfile);
+              std::string realfile = realdir + sys::file_ops::dir_sep_str () + file;
+              sys::file_stat fs (realfile);
 
-                if (! fs.exists ())
-                  {
-                    ok = false;
-                    errmsg = "__ftp__mput: file '" + realfile
-                             + "' does not exist";
-                    break;
-                  }
+              if (! fs.exists ())
+                {
+                  ok = false;
+                  errmsg = "__ftp__mput: file '" + realfile
+                           + "' does not exist";
+                  break;
+                }
 
-                if (fs.is_dir ())
-                  {
-                    file_list.append (mput_directory (realdir, file));
+              if (fs.is_dir ())
+                {
+                  file_list.append (mput_directory (realdir, file));
 
-                    if (! good ())
-                      break;
-                  }
-                else
-                  {
-                    // FIXME: Does ascii mode need to be flagged here?
-                    std::ifstream ifile (realfile.c_str (), std::ios::in |
-                                         std::ios::binary);
+                  if (! good ())
+                    break;
+                }
+              else
+                {
+                  // FIXME: Does ascii mode need to be flagged here?
+                  std::ifstream ifile (
+                    octave::sys::get_ASCII_filename (realfile).c_str (),
+                    std::ios::in | std::ios::binary);
 
-                    if (! ifile.is_open ())
-                      {
-                        ok = false;
-                        errmsg = "__ftp_mput__: unable to open file '"
-                                 + realfile + "'";
-                        break;
-                      }
-
-                    put (file, ifile);
+                  if (! ifile.is_open ())
+                    {
+                      ok = false;
+                      errmsg = "__ftp_mput__: unable to open file '"
+                               + realfile + "'";
+                      break;
+                    }
 
-                    ifile.close ();
+                  put (file, ifile);
 
-                    if (! good ())
-                      break;
+                  ifile.close ();
 
-                    file_list.append (realfile);
-                  }
-              }
-          }
+                  if (! good ())
+                    break;
+
+                  file_list.append (realfile);
+                }
+            }
         else
           {
             ok = false;
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/wrappers/stat-wrappers.c
--- a/liboctave/wrappers/stat-wrappers.c	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/wrappers/stat-wrappers.c	Sat Jan 20 16:04:50 2018 +0100
@@ -35,11 +35,25 @@
 #include <sys/stat.h>
 
 #include "stat-wrappers.h"
+#include "uniconv-wrappers.h"
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#endif
 
 int
 octave_mkdir_wrapper (const char *name, mode_t mode)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wname = u8_to_wchar (name);
+  int status = _wmkdir (wname);
+  free ((void *) wname);
+  octave_unused_parameter (mode);
+  return status;
+#else
   return mkdir (name, mode);
+#endif
 }
 
 int
@@ -100,7 +114,13 @@
 {
   struct stat buf;
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wfname = u8_to_wchar (fname);
+  int status = _wstat64 (wfname, &buf);
+  free ((void *) wfname);
+#else
   int status = stat (fname, &buf);
+#endif
 
   assign_stat_fields (&buf, mode, ino, dev, nlink, uid, gid, size,
                       atime, mtime, ctime, rdev, blksize, blocks);
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/wrappers/uniconv-wrappers.c
--- a/liboctave/wrappers/uniconv-wrappers.c	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.c	Sat Jan 20 16:04:50 2018 +0100
@@ -29,6 +29,10 @@
 #  include "config.h"
 #endif
 
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
 #include "uniconv.h"
 
 #include "uniconv-wrappers.h"
@@ -41,10 +45,52 @@
                                 src, srclen, NULL, NULL, lengthp);
 }
 
-extern char *
+char *
 octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
                             size_t srclen, size_t *lengthp)
 {
   return u8_conv_to_encoding (tocode, iconveh_question_mark,
                               src, srclen, NULL, NULL, lengthp);
 }
+
+char *
+u8_from_wchar (const wchar_t *wc)
+{
+  // Convert wide char array to multibyte UTF-8 char array
+  // The memory at the returned pointer must be freed after use.
+  const char *src = (const char *) (wc);
+  size_t srclen = wcslen (wc) * sizeof (wchar_t) / sizeof (char);
+
+  size_t length;
+  char *mbchar = (char *)
+          (octave_u8_conv_from_encoding ("wchar_t", src, srclen, &length));
+
+  // result is not 0 terminated
+  char *retval = malloc (length + 1);
+  memcpy (retval, mbchar, length);
+  free ((void *) mbchar);
+  retval[length] = 0; // 0 terminate string
+
+  return retval;
+}
+
+wchar_t *
+u8_to_wchar (const char *u8)
+{
+  // Convert multibyte UTF-8 char array to wide char array
+  // The memory at the returned pointer must be freed after use.
+  const uint8_t *src = (const uint8_t *) (u8);
+  size_t srclen = strlen (u8) * sizeof (char) / sizeof (uint8_t);
+
+  size_t length;
+
+  wchar_t *wchar = (wchar_t *)
+              (octave_u8_conv_to_encoding ("wchar_t", src, srclen+1, &length));
+  // result is not 0 terminated
+  wchar_t *retval = malloc (length + 1 * sizeof (wchar_t));
+  memcpy (retval, wchar, length);
+  free ((void *) wchar);
+  retval[length / sizeof (wchar_t)] = 0; // 0 terminate string
+
+  return retval;
+}
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/wrappers/uniconv-wrappers.h
--- a/liboctave/wrappers/uniconv-wrappers.h	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.h	Sat Jan 20 16:04:50 2018 +0100
@@ -46,6 +46,12 @@
 octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
                             size_t srclen, size_t *lengthp);
 
+extern char *
+u8_from_wchar (const wchar_t *wc);
+
+extern wchar_t *
+u8_to_wchar (const char *u8_char);
+
 #if defined __cplusplus
 }
 #endif
diff -r ce2eb28e0a6d -r 867168d50973 liboctave/wrappers/unistd-wrappers.c
--- a/liboctave/wrappers/unistd-wrappers.c	Fri Jan 19 19:59:28 2018 -0800
+++ b/liboctave/wrappers/unistd-wrappers.c	Sat Jan 20 16:04:50 2018 +0100
@@ -31,15 +31,18 @@
 
 #include <stdio.h>
 
-#include <stdio.h>
-
 #include <sys/types.h>
 #include <unistd.h>
 
 #if defined (__WIN32__) && ! defined (__CYGWIN__)
 #  include <process.h>
 #endif
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <wchar.h>
+#endif
 
+#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
 int
@@ -75,7 +78,14 @@
 int
 octave_chdir_wrapper (const char *nm)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wnm = u8_to_wchar (nm);
+  int status = _wchdir (wnm);
+  free ((void *) wnm);
+  return status;
+#else
   return chdir (nm);
+#endif
 }
 
 int
@@ -281,7 +291,28 @@
 char *
 octave_getcwd_wrapper (char *nm, size_t len)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *tmp = _wgetcwd (NULL, 0);
+  char *retval = NULL;
+
+  if (! tmp)
+    return retval;
+
+  retval = u8_from_wchar (tmp);
+  if (! nm)
+    return retval;
+  else
+    {
+      if (strlen (retval) > len)
+        return NULL;
+      
+      memcpy (nm, retval, len);
+      free (retval);
+      return nm;
+    }
+#else
   return getcwd (nm, len);
+#endif
 }
 
 gid_t
@@ -381,7 +412,14 @@
 int
 octave_rmdir_wrapper (const char *nm)
 {
+#if defined (OCTAVE_USE_WINDOWS_API)
+  wchar_t *wnm = u8_to_wchar (nm);
+  int status = _wrmdir (wnm);
+  free ((void *) wnm);
+  return status;
+#else
   return rmdir (nm);
+#endif
 }
 
 pid_t
