# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1525984286 -7200
#      Thu May 10 22:31:26 2018 +0200
# Node ID e39aed851be782352704d130f77f3e874e4bab7e
# Parent  70eb00feba7cf6637a53d38ae56e3badec448576
Make "tolower" and "toupper" Unicode aware (bug #53873).

* ov-ch-mat.cc (map): Use UTF-8 aware functions for "tolower" and "toupper".

* mappers.cc: Add tests to "tolower" and "toupper".

* unicase-wrappers.[c/h]: Add wrappers for "u8_tolower" and "u8_toupper".

* bootstrap.conf: Add modules "unicase/u8-tolower" and "unicase/u8-toupper".

diff -r 70eb00feba7c -r e39aed851be7 bootstrap.conf
--- a/bootstrap.conf	Thu May 10 21:05:55 2018 +0200
+++ b/bootstrap.conf	Thu May 10 22:31:26 2018 +0200
@@ -91,6 +91,8 @@
   tempname
   tmpfile
   uname
+  unicase/u8-tolower
+  unicase/u8-toupper
   uniconv/u8-conv-from-enc
   uniconv/u8-conv-to-enc
   unistd
diff -r 70eb00feba7c -r e39aed851be7 libinterp/corefcn/mappers.cc
--- a/libinterp/corefcn/mappers.cc	Thu May 10 21:05:55 2018 +0200
+++ b/libinterp/corefcn/mappers.cc	Thu May 10 22:31:26 2018 +0200
@@ -2139,6 +2139,7 @@
 %!assert (tolower ({"ABC", "DEF", {"GHI", {"JKL"}}}), {"abc", "def", {"ghi", {"jkl"}}})
 %!assert (tolower (["ABC"; "DEF"]), ["abc"; "def"])
 %!assert (tolower ({["ABC"; "DEF"]}), {["abc";"def"]})
+%!assert (tolower (["ABCÄÖÜSS"; "abcäöüß"]), ["abcäöüss"; "abcäöüß"])
 %!assert (tolower (68), 68)
 %!assert (tolower ({[68, 68; 68, 68]}), {[68, 68; 68, 68]})
 %!assert (tolower (68i), 68i)
@@ -2203,6 +2204,7 @@
 %!assert (toupper ({"abc", "def", {"ghi", {"jkl"}}}), {"ABC", "DEF", {"GHI", {"JKL"}}})
 %!assert (toupper (["abc"; "def"]), ["ABC"; "DEF"])
 %!assert (toupper ({["abc"; "def"]}), {["ABC";"DEF"]})
+%!assert (toupper (["ABCÄÖÜSS"; "abcäöüß"]), ["ABCÄÖÜSS"; "ABCÄÖÜSS"])
 %!assert (toupper (100), 100)
 %!assert (toupper ({[100, 100; 100, 100]}), {[100, 100; 100, 100]})
 %!assert (toupper (100i), 100i)
diff -r 70eb00feba7c -r e39aed851be7 libinterp/octave-value/ov-ch-mat.cc
--- a/libinterp/octave-value/ov-ch-mat.cc	Thu May 10 21:05:55 2018 +0200
+++ b/libinterp/octave-value/ov-ch-mat.cc	Thu May 10 22:31:26 2018 +0200
@@ -41,6 +41,7 @@
 
 #include "lo-ieee.h"
 #include "mx-base.h"
+#include "unicase-wrappers.h"
 
 #include "mxarray.h"
 #include "ov-base.h"
@@ -270,8 +271,36 @@
     STRING_MAPPER (xisspace, std::isspace, bool);
     STRING_MAPPER (xisupper, std::isupper, bool);
     STRING_MAPPER (xisxdigit, std::isxdigit, bool);
-    STRING_MAPPER (xtolower, std::tolower, char);
-    STRING_MAPPER (xtoupper, std::toupper, char);
+
+    case umap_xtolower:
+      {
+        charNDArray in_matrix = matrix;
+        if (matrix.ndims () == 2)
+          in_matrix = matrix.transpose ();
+        size_t output_length;
+        uint8_t *output = octave_u8_tolower_wrapper (
+              reinterpret_cast<const uint8_t *> (in_matrix.data ()),
+              matrix.numel (), nullptr, nullptr, &output_length);
+        charNDArray ch_array = charNDArray (in_matrix.dims ());
+        std::memmove (ch_array.fortran_vec (), output, output_length);
+        return octave_value ((matrix.ndims () == 2) ? ch_array.transpose ()
+                                                    : ch_array);
+      }
+
+    case umap_xtoupper:
+      {
+        charNDArray in_matrix = matrix;
+        if (matrix.ndims () == 2)
+          in_matrix = matrix.transpose ();
+        size_t output_length;
+        uint8_t *output = octave_u8_toupper_wrapper (
+              reinterpret_cast<const uint8_t *> (in_matrix.data ()),
+              matrix.numel (), nullptr, nullptr, &output_length);
+        charNDArray ch_array = charNDArray (in_matrix.dims ());
+        std::memmove (ch_array.fortran_vec (), output, output_length);
+        return octave_value ((matrix.ndims () == 2) ? ch_array.transpose ()
+                                                    : ch_array);
+      }
 
     // For Matlab compatibility, these should work on ASCII values
     // without error or warning.
diff -r 70eb00feba7c -r e39aed851be7 liboctave/wrappers/unicase-wrappers.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unicase-wrappers.c	Thu May 10 22:31:26 2018 +0200
@@ -0,0 +1,45 @@
+/*
+
+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 "unicase.h"
+
+#include "unicase-wrappers.h"
+
+uint8_t *
+octave_u8_tolower_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp)
+{
+  return u8_tolower (s, n, iso639_language, NULL, resultbuf, lengthp);
+}
+
+uint8_t *
+octave_u8_toupper_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp)
+{
+  return u8_toupper (s, n, iso639_language, NULL, resultbuf, lengthp);
+}
diff -r 70eb00feba7c -r e39aed851be7 liboctave/wrappers/unicase-wrappers.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/unicase-wrappers.h	Thu May 10 22:31:26 2018 +0200
@@ -0,0 +1,44 @@
+/*
+
+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_unicase_wrappers_h)
+#define octave_unicase_wrappers_h 1
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t *
+octave_u8_tolower_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp);
+
+extern uint8_t *
+octave_u8_toupper_wrapper (const uint8_t *s, size_t n,
+                           const char *iso639_language,
+                           uint8_t *resultbuf, size_t *lengthp);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
