# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1552165765 -3600
#      Sat Mar 09 22:09:25 2019 +0100
# Node ID ad0b74e52f95c029ea874c60c0fdca0b1b6e2a5f
# Parent  23894ad6f7d1058b52eb654bb036be967e8dec92
Convert encoding just before writing to stream (bug #55452).

* utils.[cc,h] (format): Add overload with encoding specifier.
* oct-stream.cc (do_print_conv): Pass on encoding to octave::format.
  (do_printf): Convert strings to encoding.
* oct-stream.[cc,h] (printf): Don't convert format string separately.

diff -r 23894ad6f7d1 -r ad0b74e52f95 libinterp/corefcn/oct-stream.cc
--- a/libinterp/corefcn/oct-stream.cc	Thu Mar 07 15:11:17 2019 -0800
+++ b/libinterp/corefcn/oct-stream.cc	Sat Mar 09 22:09:25 2019 +0100
@@ -5545,23 +5545,24 @@
 
   template <typename T>
   int
-  do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1,
-                  int sa_2, T arg, const std::string& who)
+  do_printf_conv (std::ostream& os, const std::string& encoding,
+                  const char *fmt, int nsa, int sa_1, int sa_2, T arg,
+                  const std::string& who)
   {
     int retval = 0;
 
     switch (nsa)
       {
       case 2:
-        retval = octave::format (os, fmt, sa_1, sa_2, arg);
+        retval = octave::format (os, encoding, fmt, sa_1, sa_2, arg);
         break;
 
       case 1:
-        retval = octave::format (os, fmt, sa_1, arg);
+        retval = octave::format (os, encoding, fmt, sa_1, arg);
         break;
 
       case 0:
-        retval = octave::format (os, fmt, arg);
+        retval = octave::format (os, encoding, fmt, arg);
         break;
 
       default:
@@ -5721,7 +5722,8 @@
               tval = (lo_ieee_is_NA (dval) ? "NA" : "NaN");
           }
 
-        retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, tval, who);
+        retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa, sa_1,
+                                  sa_2, tval, who);
       }
     else
       {
@@ -5740,8 +5742,8 @@
                 // Insert "long" modifier.
                 tfmt.replace (tfmt.rfind (type), 1, llmod + type);
 
-                retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2,
-                                          tval.value (), who);
+                retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa,
+                                          sa_1, sa_2, tval.value (), who);
               }
             else
               {
@@ -5749,7 +5751,7 @@
 
                 double dval = val.double_value (true);
 
-                retval += do_printf_conv (os, tfmt.c_str (), nsa,
+                retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa,
                                           sa_1, sa_2, dval, who);
               }
             break;
@@ -5762,8 +5764,8 @@
                 // Insert "long" modifier.
                 tfmt.replace (tfmt.rfind (type), 1, llmod + type);
 
-                retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2,
-                                          tval.value (), who);
+                retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa,
+                                          sa_1, sa_2, tval.value (), who);
               }
             else
               {
@@ -5771,7 +5773,7 @@
 
                 double dval = val.double_value (true);
 
-                retval += do_printf_conv (os, tfmt.c_str (), nsa,
+                retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa,
                                           sa_1, sa_2, dval, who);
               }
             break;
@@ -5781,8 +5783,8 @@
             {
               double dval = val.double_value (true);
 
-              retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2,
-                                        dval, who);
+              retval += do_printf_conv (os, encoding (), tfmt.c_str (), nsa,
+                                        sa_1, sa_2, dval, who);
             }
             break;
 
@@ -5852,12 +5854,18 @@
 
             if (elt->type == '%')
               {
-                os << '%';
+                if (encoding ().compare ("utf-8"))
+                  os << string::u8_to_encoding (who, "%", encoding ());
+                else
+                  os << '%';
                 retval++;
               }
             else if (elt->args == 0 && ! elt->text.empty ())
               {
-                os << elt->text;
+                if (encoding ().compare ("utf-8"))
+                  os << string::u8_to_encoding (who, elt->text, encoding ());
+                else
+                  os << elt->text;
                 retval += (elt->text.length ());
               }
             else if (elt->type == 's' || elt->type == 'c')
@@ -5912,13 +5920,10 @@
   }
 
   int
-  base_stream::printf (std::string fmt,
+  base_stream::printf (const std::string& fmt,
                        const octave_value_list& args,
                        const std::string& who)
   {
-    if (encoding ().compare ("utf-8"))
-      fmt = string::u8_to_encoding (who, fmt, encoding ());
-
     printf_format_list fmt_list (fmt);
 
     if (fmt_list.num_conversions () == -1)
diff -r 23894ad6f7d1 -r ad0b74e52f95 libinterp/corefcn/oct-stream.h
--- a/libinterp/corefcn/oct-stream.h	Thu Mar 07 15:11:17 2019 -0800
+++ b/libinterp/corefcn/oct-stream.h	Sat Mar 09 22:09:25 2019 +0100
@@ -235,7 +235,7 @@
     int do_printf (printf_format_list& fmt_list, const octave_value_list& args,
                    const std::string& who /* = "printf" */);
 
-    int printf (std::string fmt, const octave_value_list& args,
+    int printf (const std::string& fmt, const octave_value_list& args,
                 const std::string& who /* = "printf" */);
 
     int puts (const std::string& s, const std::string& who /* = "puts" */);
diff -r 23894ad6f7d1 -r ad0b74e52f95 libinterp/corefcn/utils.cc
--- a/libinterp/corefcn/utils.cc	Thu Mar 07 15:11:17 2019 -0800
+++ b/libinterp/corefcn/utils.cc	Sat Mar 09 22:09:25 2019 +0100
@@ -42,6 +42,7 @@
 #include "oct-cmplx.h"
 #include "oct-env.h"
 #include "oct-locbuf.h"
+#include "oct-string.h"
 #include "pathsearch.h"
 #include "quit.h"
 #include "str-vec.h"
@@ -1238,6 +1239,33 @@
     return s.length ();
   }
 
+  size_t format (std::ostream& os, const std::string& enc, const char *fmt, ...)
+  {
+    size_t retval;
+
+    va_list args;
+    va_start (args, fmt);
+
+    retval = vformat (os, enc, fmt, args);
+
+    va_end (args);
+
+    return retval;
+  }
+
+  size_t vformat (std::ostream& os, const std::string& enc, const char *fmt,
+                  va_list args)
+  {
+    std::string s = vasprintf (fmt, args);
+
+    if (enc.compare ("utf-8"))
+      os << string::u8_to_encoding ("printf", s, enc);
+    else
+      os << s;
+
+    return s.length ();
+  }
+
   std::string vasprintf (const char *fmt, va_list args)
   {
     std::string retval;
diff -r 23894ad6f7d1 -r ad0b74e52f95 libinterp/corefcn/utils.h
--- a/libinterp/corefcn/utils.h	Thu Mar 07 15:11:17 2019 -0800
+++ b/libinterp/corefcn/utils.h	Sat Mar 09 22:09:25 2019 +0100
@@ -109,8 +109,15 @@
   format (std::ostream& os, const char *fmt, ...);
 
   extern OCTINTERP_API size_t
+  format (std::ostream& os, const std::string& enc, const char *fmt, ...);
+
+  extern OCTINTERP_API size_t
   vformat (std::ostream& os, const char *fmt, va_list args);
 
+  extern OCTINTERP_API size_t
+  vformat (std::ostream& os, const std::string& enc,
+           const char *fmt, va_list args);
+
   extern OCTINTERP_API std::string
   vasprintf (const char *fmt, va_list args);
 
