# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1525633431 -7200
#      Sun May 06 21:03:51 2018 +0200
# Node ID 229909880ca413b12efb2055449da87e4040fbf8
# Parent  6a7445cac2db331756f351278aec8343e496511c
Add support for arbitrary character encodings in m-files (bug #53842).

* input.cc: Add new variable "Vmfile_encoding". Convert from local encoding to
UTF-8 in file_reader::get_input. Add new function "__mfile_encoding__".

* iconv-wrappers.[c/h]: Add new wrapper files for iconv_open and iconv_close.

* wrappers/module.mk: Add new files.

diff -r 6a7445cac2db -r 229909880ca4 bootstrap.conf
--- a/bootstrap.conf	Sat May 05 20:13:18 2018 +0200
+++ b/bootstrap.conf	Sun May 06 21:03:51 2018 +0200
@@ -94,6 +94,8 @@
   uniconv/u8-conv-from-enc
   uniconv/u8-conv-to-enc
   unistd
+  unistr/u8-to-u16
+  unistr/u8-to-u32
   unlink
   unsetenv
   vasprintf
diff -r 6a7445cac2db -r 229909880ca4 libinterp/corefcn/ft-text-renderer.cc
--- a/libinterp/corefcn/ft-text-renderer.cc	Sat May 05 20:13:18 2018 +0200
+++ b/libinterp/corefcn/ft-text-renderer.cc	Sun May 06 21:03:51 2018 +0200
@@ -53,6 +53,7 @@
 #include <utility>
 
 #include "singleton-cleanup.h"
+#include "unistr-wrappers.h"
 
 #include "defaults.h"
 #include "error.h"
@@ -872,67 +873,61 @@
         FT_UInt glyph_index, previous = 0;
 
         std::string str = e.string_value ();
-        size_t n = str.length ();
+        size_t n;
+        // convert str to UTF-32
+        uint32_t *u32_str;
+        u32_str = octave_u8_to_u32_wrapper (reinterpret_cast<const uint8_t *> (str.c_str ()), str.length (), nullptr, &n);
+        if (! u32_str)
+          error ("ft_text_renderer: converting from UTF-8 to UTF-32: %s",
+                 std::strerror (errno));
         size_t curr = 0;
         size_t idx = 0;
-        mbstate_t ps;
-        memset (&ps, 0, sizeof (ps));  // Initialize state to 0.
-        wchar_t wc;
         std::string fname = font.get_face ()->family_name;
         text_renderer::string fs (str, font, xoffset, yoffset);
         std::vector<double> xdata;
 
         while (n > 0)
           {
-            size_t r = std::mbrtowc (&wc, str.data () + curr, n, &ps);
+            n -= 1;
 
-            if (r > 0
-                && r != static_cast<size_t> (-1)
-                && r != static_cast<size_t> (-2))
+            if (u32_str[curr] == 10)
               {
-                n -= r;
-                curr += r;
-
-                if (wc == L'\n')
+                // Finish previous string in strlist before processing
+                // the newline character
+                fs.set_y (line_yoffset + yoffset);
+                fs.set_color (color);
+                // FIXME: Do we have to convert back to UTF-8 and keep strlist
+                // in sync? Might fail with multi-byte characters as it is now.
+                std::string s = str.substr (idx, curr - idx);
+                if (! s.empty ())
                   {
-                    // Finish previous string in strlist before processing
-                    // the newline character
-                    fs.set_y (line_yoffset + yoffset);
-                    fs.set_color (color);
-                    std::string s = str.substr (idx, curr - idx - 1);
-                    if (! s.empty ())
-                      {
-                        fs.set_string (s);
-                        fs.set_xdata (xdata);
-                        fs.set_family (fname);
-                        strlist.push_back (fs);
-                      }
+                    fs.set_string (s);
+                    fs.set_xdata (xdata);
+                    fs.set_family (fname);
+                    strlist.push_back (fs);
                   }
-                else
-                  xdata.push_back (xoffset);
-
-                glyph_index = process_character (wc, previous);
-
-                if (wc == L'\n')
-                  {
-                    previous = 0;
-                    // Start a new string in strlist
-                    idx = curr;
-                    xdata.clear ();
-                    fs = text_renderer::string (str.substr (idx), font,
-                                                line_xoffset, yoffset);
-                  }
-                else
-                  previous = glyph_index;
               }
             else
+              xdata.push_back (xoffset);
+
+            glyph_index = process_character (u32_str[curr], previous);
+
+
+            if (u32_str[curr] == 10)
               {
-                if (r != 0)
-                  ::warning ("ft_text_renderer: failed to decode string `%s' with "
-                             "locale `%s'", str.c_str (),
-                             std::setlocale (LC_CTYPE, nullptr));
-                break;
+                previous = 0;
+                // Start a new string in strlist
+                idx = curr+1;
+                xdata.clear ();
+                // FIXME: Do we have to convert back to UTF-8 and keep strlist
+                // in sync? Might fail with multi-byte characters as it is now.
+                fs = text_renderer::string (str.substr (idx), font,
+                                            line_xoffset, yoffset);
               }
+            else
+              previous = glyph_index;
+
+            curr += 1;
           }
 
         if (! fs.get_string ().empty ())
diff -r 6a7445cac2db -r 229909880ca4 liboctave/wrappers/module.mk
--- a/liboctave/wrappers/module.mk	Sat May 05 20:13:18 2018 +0200
+++ b/liboctave/wrappers/module.mk	Sun May 06 21:03:51 2018 +0200
@@ -31,6 +31,7 @@
   %reldir%/uname-wrapper.h \
   %reldir%/uniconv-wrappers.h \
   %reldir%/unistd-wrappers.h \
+  %reldir%/unistr-wrappers.h \
   %reldir%/unsetenv-wrapper.h \
   %reldir%/vasprintf-wrapper.h \
   %reldir%/wait-for-input.h \
@@ -69,6 +70,7 @@
   %reldir%/uname-wrapper.c \
   %reldir%/uniconv-wrappers.c \
   %reldir%/unistd-wrappers.c \
+  %reldir%/unistr-wrappers.c \
   %reldir%/unsetenv-wrapper.c \
   %reldir%/vasprintf-wrapper.c \
   %reldir%/wait-for-input.c \
diff -r 6a7445cac2db -r 229909880ca4 liboctave/wrappers/unistr-wrappers.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unistr-wrappers.c	Sun May 06 21:03:51 2018 +0200
@@ -0,0 +1,43 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "unistr.h"
+
+#include "unistr-wrappers.h"
+
+uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp)
+{
+  return u8_to_u16 (src, src_len, result_buf, lengthp);
+}
+
+uint32_t *
+octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
+                          uint32_t *result_buf, size_t *lengthp)
+{
+  return u8_to_u32 (src, src_len, result_buf, lengthp);
+}
diff -r 6a7445cac2db -r 229909880ca4 liboctave/wrappers/unistr-wrappers.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unistr-wrappers.h	Sun May 06 21:03:51 2018 +0200
@@ -0,0 +1,42 @@
+/*
+
+Copyright (C) 2018 Markus Mützel
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (octave_unistr_wrappers_h)
+#define octave_unistr_wrappers_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern uint32_t *
+octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
+                          uint32_t *result_buf, size_t *lengthp);
+
+extern uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
