[glib] g_date_time_format: fix output in non-UTF-8 locales



commit b6a8dec558c259d3320a5d0d4bc5f8c0d6c62a41
Author: Dan Winship <danw gnome org>
Date:   Thu Jan 19 10:39:57 2012 -0500

    g_date_time_format: fix output in non-UTF-8 locales
    
    In non-UTF-8 locales, the translations and nl_langinfo() return values
    must be converted to UTF-8 before being returned to the caller.
    Likewise, when making a recursive call to expand a format like '%x',
    the format string must first be converted to UTF-8.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=668250

 configure.ac           |   26 +-
 glib/gdatetime.c       |  574 ++++++++++++++++++++++++++++--------------------
 glib/tests/gdatetime.c |   63 ++++++
 3 files changed, 413 insertions(+), 250 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3c5b1e5..3c7f4ed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1305,24 +1305,24 @@ if test x$glib_cv_langinfo_time = xyes; then
   AC_DEFINE(HAVE_LANGINFO_TIME,1,[Have nl_langinfo (PM_STR)])
 fi
 
-dnl Check for nl_langinfo and _NL_CTYPE_OUTDIGITn_WC
-AC_CACHE_CHECK([for nl_langinfo (_NL_CTYPE_OUTDIGITn_WC)], glib_cv_langinfo_outdigit,[
+dnl Check for nl_langinfo and _NL_CTYPE_OUTDIGITn_MB
+AC_CACHE_CHECK([for nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)], glib_cv_langinfo_outdigit,[
         AC_TRY_COMPILE([#include <langinfo.h>],
                 [char *str;
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT0_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT1_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT2_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT3_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT4_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT5_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT6_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT7_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT8_WC);
-                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT9_WC);],
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT0_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT1_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT2_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT3_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT4_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT5_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT6_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT7_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT8_MB);
+                 str = nl_langinfo (_NL_CTYPE_OUTDIGIT9_MB);],
                 [glib_cv_langinfo_outdigit=yes],
                 [glib_cv_langinfo_outdigit=no])])
 if test x$glib_cv_langinfo_outdigit = xyes; then
-  AC_DEFINE(HAVE_LANGINFO_OUTDIGIT,1,[Have nl_langinfo (_NL_CTYPE_OUTDIGITn_WC)])
+  AC_DEFINE(HAVE_LANGINFO_OUTDIGIT,1,[Have nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)])
 fi
 
 dnl ****************************************
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 4306cca..69e806e 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -62,6 +62,8 @@
 
 #include "gslice.h"
 #include "gatomic.h"
+#include "gcharset.h"
+#include "gconvert.h"
 #include "gfileutils.h"
 #include "ghash.h"
 #include "gmain.h"
@@ -2083,15 +2085,15 @@ g_date_time_to_utc (GDateTime *datetime)
 static void
 format_number (GString  *str,
                gboolean  use_alt_digits,
-               gchar     pad,
+               gchar    *pad,
                gint      width,
                guint32   number)
 {
-  const gunichar ascii_digits[10] = {
-    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+  const gchar *ascii_digits[10] = {
+    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
   };
-  const gunichar *digits = ascii_digits;
-  gunichar tmp[10];
+  const gchar **digits = ascii_digits;
+  const gchar *tmp[10];
   gint i = 0;
 
   g_return_if_fail (width <= 10);
@@ -2099,18 +2101,14 @@ format_number (GString  *str,
 #ifdef HAVE_LANGINFO_OUTDIGIT
   if (use_alt_digits)
     {
-      static gunichar alt_digits[10];
+      static const gchar *alt_digits[10];
       static gsize initialised;
       /* 2^32 has 10 digits */
 
       if G_UNLIKELY (g_once_init_enter (&initialised))
         {
 #define DO_DIGIT(n) \
-      {                                                                     \
-        union { guint integer; char *pointer; } val;                        \
-        val.pointer = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_WC);           \
-        alt_digits[n] = val.integer;                                        \
-      }
+        alt_digits[n] = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_MB)
           DO_DIGIT(0); DO_DIGIT(1); DO_DIGIT(2); DO_DIGIT(3); DO_DIGIT(4);
           DO_DIGIT(5); DO_DIGIT(6); DO_DIGIT(7); DO_DIGIT(8); DO_DIGIT(9);
 #undef DO_DIGIT
@@ -2129,13 +2127,330 @@ format_number (GString  *str,
   while (number);
 
   while (pad && i < width)
-    tmp[i++] = pad == '0' ? digits[0] : pad;
+    tmp[i++] = *pad == '0' ? digits[0] : pad;
 
   /* should really be impossible */
   g_assert (i <= 10);
 
   while (i)
-    g_string_append_unichar (str, tmp[--i]);
+    g_string_append (str, tmp[--i]);
+}
+
+static gboolean g_date_time_format_locale (GDateTime   *datetime,
+					   const gchar *format,
+					   GString     *outstr,
+					   gboolean     locale_is_utf8);
+
+/* g_date_time_format() subroutine that takes a locale-encoded format
+ * string and produces a locale-encoded date/time string.
+ */
+static gboolean
+g_date_time_locale_format_locale (GDateTime   *datetime,
+				  const gchar *format,
+				  GString     *outstr,
+				  gboolean     locale_is_utf8)
+{
+  gchar *utf8_format;
+  gboolean success;
+
+  if (locale_is_utf8)
+    return g_date_time_format_locale (datetime, format, outstr,
+				      locale_is_utf8);
+
+  utf8_format = g_locale_to_utf8 (format, -1, NULL, NULL, NULL);
+  if (!utf8_format)
+    return FALSE;
+
+  success = g_date_time_format_locale (datetime, utf8_format, outstr,
+				       locale_is_utf8);
+  g_free (utf8_format);
+  return success;
+}
+
+/* g_date_time_format() subroutine that takes a UTF-8 format
+ * string and produces a locale-encoded date/time string.
+ */
+static gboolean
+g_date_time_format_locale (GDateTime   *datetime,
+			   const gchar *format,
+			   GString     *outstr,
+			   gboolean     locale_is_utf8)
+{
+  guint     len;
+  gchar    *tmp;
+  gunichar  c;
+  gboolean  alt_digits = FALSE;
+  gboolean  pad_set = FALSE;
+  gchar    *pad = "";
+  gchar    *ampm;
+  const gchar *tz;
+
+  while (*format)
+    {
+      len = strcspn (format, "%");
+      if (len)
+	{
+	  if (locale_is_utf8)
+	    g_string_append_len (outstr, format, len);
+	  else
+	    {
+	      tmp = g_locale_from_utf8 (format, len, NULL, NULL, NULL);
+	      if (!tmp)
+		return FALSE;
+	      g_string_append (outstr, tmp);
+	      g_free (tmp);
+	    }
+	}
+
+      format += len;
+      if (!*format)
+	break;
+
+      g_assert (*format == '%');
+      format++;
+      if (!*format)
+	break;
+
+      alt_digits = FALSE;
+      pad_set = FALSE;
+
+    next_mod:
+      c = g_utf8_get_char (format);
+      format = g_utf8_next_char (format);
+      switch (c)
+	{
+	case 'a':
+	  g_string_append (outstr, WEEKDAY_ABBR (datetime));
+	  break;
+	case 'A':
+	  g_string_append (outstr, WEEKDAY_FULL (datetime));
+	  break;
+	case 'b':
+	  g_string_append (outstr, MONTH_ABBR (datetime));
+	  break;
+	case 'B':
+	  g_string_append (outstr, MONTH_FULL (datetime));
+	  break;
+	case 'c':
+	  {
+	    if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_TIME_FMT,
+						   outstr, locale_is_utf8))
+	      return FALSE;
+	  }
+	  break;
+	case 'C':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_year (datetime) / 100);
+	  break;
+	case 'd':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_day_of_month (datetime));
+	  break;
+	case 'e':
+	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
+			 g_date_time_get_day_of_month (datetime));
+	  break;
+	case 'F':
+	  g_string_append_printf (outstr, "%d-%02d-%02d",
+				  g_date_time_get_year (datetime),
+				  g_date_time_get_month (datetime),
+				  g_date_time_get_day_of_month (datetime));
+	  break;
+	case 'g':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_week_numbering_year (datetime) % 100);
+	  break;
+	case 'G':
+	  format_number (outstr, alt_digits, pad_set ? pad : 0, 0,
+			 g_date_time_get_week_numbering_year (datetime));
+	  break;
+	case 'h':
+	  g_string_append (outstr, MONTH_ABBR (datetime));
+	  break;
+	case 'H':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_hour (datetime));
+	  break;
+	case 'I':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
+	  break;
+	case 'j':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 3,
+			 g_date_time_get_day_of_year (datetime));
+	  break;
+	case 'k':
+	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
+			 g_date_time_get_hour (datetime));
+	  break;
+	case 'l':
+	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
+			 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
+	  break;
+	case 'n':
+	  g_string_append_c (outstr, '\n');
+	  break;
+	case 'm':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_month (datetime));
+	  break;
+	case 'M':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_minute (datetime));
+	  break;
+	case 'O':
+	  alt_digits = TRUE;
+	  goto next_mod;
+	case 'p':
+	  ampm = GET_AMPM (datetime);
+	  if (!locale_is_utf8)
+	    {
+	      ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
+	      if (!tmp)
+		return FALSE;
+	    }
+	  ampm = g_utf8_strup (ampm, -1);
+	  if (!locale_is_utf8)
+	    {
+	      g_free (tmp);
+	      tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL);
+	      g_free (ampm);
+	      if (!tmp)
+		return FALSE;
+	      ampm = tmp;
+	    }
+	  g_string_append (outstr, ampm);
+	  g_free (ampm);
+	  break;
+	case 'P':
+	  ampm = GET_AMPM (datetime);
+	  if (!locale_is_utf8)
+	    {
+	      ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
+	      if (!tmp)
+		return FALSE;
+	    }
+	  ampm = g_utf8_strdown (ampm, -1);
+	  if (!locale_is_utf8)
+	    {
+	      g_free (tmp);
+	      tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL);
+	      g_free (ampm);
+	      if (!tmp)
+		return FALSE;
+	      ampm = tmp;
+	    }
+	  g_string_append (outstr, ampm);
+	  g_free (ampm);
+	  break;
+	case 'r':
+	  {
+	    if (!g_date_time_locale_format_locale (datetime, PREFERRED_12HR_TIME_FMT,
+						   outstr, locale_is_utf8))
+	      return FALSE;
+	  }
+	  break;
+	case 'R':
+	  g_string_append_printf (outstr, "%02d:%02d",
+				  g_date_time_get_hour (datetime),
+				  g_date_time_get_minute (datetime));
+	  break;
+	case 's':
+	  g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime));
+	  break;
+	case 'S':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_second (datetime));
+	  break;
+	case 't':
+	  g_string_append_c (outstr, '\t');
+	  break;
+	case 'T':
+	  g_string_append_printf (outstr, "%02d:%02d:%02d",
+				  g_date_time_get_hour (datetime),
+				  g_date_time_get_minute (datetime),
+				  g_date_time_get_second (datetime));
+	  break;
+	case 'u':
+	  format_number (outstr, alt_digits, 0, 0,
+			 g_date_time_get_day_of_week (datetime));
+	  break;
+	case 'V':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_week_of_year (datetime));
+	  break;
+	case 'w':
+	  format_number (outstr, alt_digits, 0, 0,
+			 g_date_time_get_day_of_week (datetime) % 7);
+	  break;
+	case 'x':
+	  {
+	    if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_FMT,
+						   outstr, locale_is_utf8))
+	      return FALSE;
+	  }
+	  break;
+	case 'X':
+	  {
+	    if (!g_date_time_locale_format_locale (datetime, PREFERRED_TIME_FMT,
+						   outstr, locale_is_utf8))
+	      return FALSE;
+	  }
+	  break;
+	case 'y':
+	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
+			 g_date_time_get_year (datetime) % 100);
+	  break;
+	case 'Y':
+	  format_number (outstr, alt_digits, 0, 0,
+			 g_date_time_get_year (datetime));
+	  break;
+	case 'z':
+	  if (datetime->tz != NULL)
+	    {
+	      gint64 offset = g_date_time_get_utc_offset (datetime)
+		/ USEC_PER_SECOND;
+
+	      g_string_append_printf (outstr, "%+03d%02d",
+				      (int) offset / 3600,
+				      (int) abs(offset) / 60 % 60);
+	    }
+	  else
+	    g_string_append (outstr, "+0000");
+	  break;
+	case 'Z':
+	  tz = g_date_time_get_timezone_abbreviation (datetime);
+	  if (!locale_is_utf8)
+	    {
+	      tz = tmp = g_locale_from_utf8 (tz, -1, NULL, NULL, NULL);
+	      if (!tmp)
+		return FALSE;
+	    }
+	  g_string_append (outstr, tz);
+	  if (!locale_is_utf8)
+	    g_free (tmp);
+	  break;
+	case '%':
+	  g_string_append_c (outstr, '%');
+	  break;
+	case '-':
+	  pad_set = TRUE;
+	  pad = "";
+	  goto next_mod;
+	case '_':
+	  pad_set = TRUE;
+	  pad = " ";
+	  goto next_mod;
+	case '0':
+	  pad_set = TRUE;
+	  pad = "0";
+	  goto next_mod;
+	default:
+	  return FALSE;
+	}
+    }
+
+  return TRUE;
 }
 
 /**
@@ -2411,242 +2726,27 @@ g_date_time_format (GDateTime   *datetime,
                     const gchar *format)
 {
   GString  *outstr;
-  gchar    *tmp;
-  gunichar  c;
-  gboolean  in_mod = FALSE;
-  gboolean  alt_digits = FALSE;
-  gboolean  pad_set = FALSE;
-  gchar     pad = '\0';
-  gchar    *ampm;
+  gchar *utf8;
+  gboolean locale_is_utf8 = g_get_charset (NULL);
 
   g_return_val_if_fail (datetime != NULL, NULL);
   g_return_val_if_fail (format != NULL, NULL);
   g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
 
   outstr = g_string_sized_new (strlen (format) * 2);
-  in_mod = FALSE;
 
-  for (; *format; format = g_utf8_next_char (format))
+  if (!g_date_time_format_locale (datetime, format, outstr, locale_is_utf8))
     {
-      c = g_utf8_get_char (format);
-
-      switch (c)
-        {
-        case '%':
-          if (!in_mod)
-            {
-              in_mod = TRUE;
-              alt_digits = FALSE;
-              pad_set = FALSE;
-              break;
-            }
-            /* Fall through */
-        default:
-          if (in_mod)
-            {
-              switch (c)
-                {
-                case 'a':
-                  g_string_append (outstr, WEEKDAY_ABBR (datetime));
-                  break;
-                case 'A':
-                  g_string_append (outstr, WEEKDAY_FULL (datetime));
-                  break;
-                case 'b':
-                  g_string_append (outstr, MONTH_ABBR (datetime));
-                  break;
-                case 'B':
-                  g_string_append (outstr, MONTH_FULL (datetime));
-                  break;
-                case 'c':
-                  {
-                    tmp = g_date_time_format (datetime, PREFERRED_DATE_TIME_FMT);
-                    g_string_append (outstr, tmp);
-                    g_free (tmp);
-                  }
-                  break;
-                case 'C':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_year (datetime) / 100);
-                  break;
-                case 'd':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_day_of_month (datetime));
-                  break;
-                case 'e':
-                  format_number (outstr, alt_digits, pad_set ? pad : ' ', 2,
-                                 g_date_time_get_day_of_month (datetime));
-                  break;
-                case 'F':
-                  g_string_append_printf (outstr, "%d-%02d-%02d",
-                                          g_date_time_get_year (datetime),
-                                          g_date_time_get_month (datetime),
-                                          g_date_time_get_day_of_month (datetime));
-                  break;
-                case 'g':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_week_numbering_year (datetime) % 100);
-                  break;
-                case 'G':
-                  format_number (outstr, alt_digits, pad_set ? pad : 0, 0,
-                                 g_date_time_get_week_numbering_year (datetime));
-                  break;
-                case 'h':
-                  g_string_append (outstr, MONTH_ABBR (datetime));
-                  break;
-                case 'H':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_hour (datetime));
-                  break;
-                case 'I':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
-                  break;
-                case 'j':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 3,
-                                 g_date_time_get_day_of_year (datetime));
-                  break;
-                case 'k':
-                  format_number (outstr, alt_digits, pad_set ? pad : ' ', 2,
-                                 g_date_time_get_hour (datetime));
-                  break;
-                case 'l':
-                  format_number (outstr, alt_digits, pad_set ? pad : ' ', 2,
-                                 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
-                  break;
-                case 'n':
-                  g_string_append_c (outstr, '\n');
-                  break;
-                case 'm':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_month (datetime));
-                  break;
-                case 'M':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_minute (datetime));
-                  break;
-                case 'O':
-                  alt_digits = TRUE;
-                  goto next_mod;
-                case 'p':
-                  ampm = g_utf8_strup (GET_AMPM (datetime), -1);
-                  g_string_append (outstr, ampm);
-                  g_free (ampm);
-                  break;
-                case 'P':
-                  ampm = g_utf8_strdown (GET_AMPM (datetime), -1);
-                  g_string_append (outstr, ampm);
-                  g_free (ampm);
-                  break;
-                case 'r':
-                  {
-                    tmp = g_date_time_format (datetime, PREFERRED_12HR_TIME_FMT);
-                    g_string_append (outstr, tmp);
-                    g_free (tmp);
-                  }
-                  break;
-                case 'R':
-                  g_string_append_printf (outstr, "%02d:%02d",
-                                          g_date_time_get_hour (datetime),
-                                          g_date_time_get_minute (datetime));
-                  break;
-                case 's':
-                  g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime));
-                  break;
-                case 'S':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_second (datetime));
-                  break;
-                case 't':
-                  g_string_append_c (outstr, '\t');
-                  break;
-                case 'T':
-                  g_string_append_printf (outstr, "%02d:%02d:%02d",
-                                          g_date_time_get_hour (datetime),
-                                          g_date_time_get_minute (datetime),
-                                          g_date_time_get_second (datetime));
-                  break;
-                case 'u':
-                  format_number (outstr, alt_digits, 0, 0,
-                                 g_date_time_get_day_of_week (datetime));
-                  break;
-                case 'V':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_week_of_year (datetime));
-                  break;
-                case 'w':
-                  format_number (outstr, alt_digits, 0, 0,
-                                 g_date_time_get_day_of_week (datetime) % 7);
-                  break;
-                case 'x':
-                  {
-                    tmp = g_date_time_format (datetime, PREFERRED_DATE_FMT);
-                    g_string_append (outstr, tmp);
-                    g_free (tmp);
-                  }
-                  break;
-                case 'X':
-                  {
-                    tmp = g_date_time_format (datetime, PREFERRED_TIME_FMT);
-                    g_string_append (outstr, tmp);
-                    g_free (tmp);
-                  }
-                  break;
-                case 'y':
-                  format_number (outstr, alt_digits, pad_set ? pad : '0', 2,
-                                 g_date_time_get_year (datetime) % 100);
-                  break;
-                case 'Y':
-                  format_number (outstr, alt_digits, 0, 0,
-                                 g_date_time_get_year (datetime));
-                  break;
-                case 'z':
-                  if (datetime->tz != NULL)
-                    {
-                      gint64 offset = g_date_time_get_utc_offset (datetime)
-                                    / USEC_PER_SECOND;
-
-                      g_string_append_printf (outstr, "%+03d%02d",
-                                              (int) offset / 3600,
-                                              (int) abs(offset) / 60 % 60);
-                    }
-                  else
-                    g_string_append (outstr, "+0000");
-                  break;
-                case 'Z':
-                  g_string_append (outstr, g_date_time_get_timezone_abbreviation (datetime));
-                  break;
-                case '%':
-                  g_string_append_c (outstr, '%');
-                  break;
-                case '-':
-                  pad_set = TRUE;
-                  pad = 0;
-                  goto next_mod;
-                case '_':
-                  pad_set = TRUE;
-                  pad = ' ';
-                  goto next_mod;
-                case '0':
-                  pad_set = TRUE;
-                  pad = '0';
-                  goto next_mod;
-                default:
-                  goto bad_format;
-                }
-              in_mod = FALSE;
-            }
-          else
-            g_string_append_unichar (outstr, c);
-        }
-next_mod: ;
+      g_string_free (outstr, TRUE);
+      return NULL;
     }
 
-  return g_string_free (outstr, FALSE);
+  if (locale_is_utf8)
+    return g_string_free (outstr, FALSE);
 
-bad_format:
+  utf8 = g_locale_to_utf8 (outstr->str, outstr->len, NULL, NULL, NULL);
   g_string_free (outstr, TRUE);
-  return NULL;
+  return utf8;
 }
 
 
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index da1ee1e..618e174 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -872,6 +872,68 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\
 }
 
 static void
+test_non_utf8_printf (void)
+{
+  gchar *oldlocale;
+
+  oldlocale = g_strdup (setlocale (LC_ALL, NULL));
+  setlocale (LC_ALL, "ja_JP.eucjp");
+  if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL)
+    {
+      g_test_message ("locale ja_JP.eucjp not available, skipping non-UTF8 tests");
+      return;
+    }
+
+  /* These are the outputs that ja_JP.UTF-8 generates; if everything
+   * is working then ja_JP.eucjp should generate the same.
+   */
+  TEST_PRINTF ("%a", "\345\234\237");
+  TEST_PRINTF ("%A", "\345\234\237\346\233\234\346\227\245");
+  TEST_PRINTF ("%b", "10\346\234\210");
+  TEST_PRINTF ("%B", "10\346\234\210");
+  TEST_PRINTF ("%d", "24");
+  TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
+  TEST_PRINTF ("%e", "24"); // fixme
+  TEST_PRINTF ("%h", "10\346\234\210");
+  TEST_PRINTF ("%H", "00");
+  TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
+  TEST_PRINTF ("%I", "12");
+  TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
+  TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
+  TEST_PRINTF ("%j", "297");
+  TEST_PRINTF ("%k", " 0");
+  TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
+  TEST_PRINTF ("%l", "12");
+  TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
+  TEST_PRINTF_TIME (13, 13, 13, "%l", " 1");
+  TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
+  TEST_PRINTF ("%m", "10");
+  TEST_PRINTF ("%M", "00");
+  TEST_PRINTF ("%p", "\345\215\210\345\211\215");
+  TEST_PRINTF_TIME (13, 13, 13, "%p", "\345\215\210\345\276\214");
+  TEST_PRINTF ("%P", "\345\215\210\345\211\215");
+  TEST_PRINTF_TIME (13, 13, 13, "%P", "\345\215\210\345\276\214");
+  TEST_PRINTF ("%r", "\345\215\210\345\211\21512\346\231\20200\345\210\20600\347\247\222");
+  TEST_PRINTF_TIME (13, 13, 13, "%r", "\345\215\210\345\276\21401\346\231\20213\345\210\20613\347\247\222");
+  TEST_PRINTF ("%R", "00:00");
+  TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
+  TEST_PRINTF ("%S", "00");
+  TEST_PRINTF ("%t", "	");
+  TEST_PRINTF ("%u", "6");
+  TEST_PRINTF ("%x", "2009\345\271\26410\346\234\21024\346\227\245");
+  TEST_PRINTF ("%X", "00\346\231\20200\345\210\20600\347\247\222");
+  TEST_PRINTF_TIME (13, 14, 15, "%X", "13\346\231\20214\345\210\20615\347\247\222");
+  TEST_PRINTF ("%y", "09");
+  TEST_PRINTF ("%Y", "2009");
+  TEST_PRINTF ("%%", "%");
+  TEST_PRINTF ("%", "");
+  TEST_PRINTF ("%9", NULL);
+
+  setlocale (LC_ALL, oldlocale);
+  g_free (oldlocale);
+}
+
+static void
 test_modifiers (void)
 {
   gchar *oldlocale;
@@ -1196,6 +1258,7 @@ main (gint   argc,
   g_test_add_func ("/GDateTime/new_full", test_GDateTime_new_full);
   g_test_add_func ("/GDateTime/now", test_GDateTime_now);
   g_test_add_func ("/GDateTime/printf", test_GDateTime_printf);
+  g_test_add_func ("/GDateTime/non_utf8_printf", test_non_utf8_printf);
   g_test_add_func ("/GDateTime/strftime", test_strftime);
   g_test_add_func ("/GDateTime/modifiers", test_modifiers);
   g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]