From b6a8dec558c259d3320a5d0d4bc5f8c0d6c62a41 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 19 Jan 2012 10:39:57 -0500 Subject: [PATCH] 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 3c5b1e5db..3c7f4eddb 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 ], [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 4306cca23..69e806ecb 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 da1ee1ea8..618e174d0 100644 --- a/glib/tests/gdatetime.c +++ b/glib/tests/gdatetime.c @@ -871,6 +871,68 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\ TEST_PRINTF ("%Z", dst); } +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) { @@ -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);