mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
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
This commit is contained in:
parent
9fa374ccf7
commit
b6a8dec558
26
configure.ac
26
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)])
|
AC_DEFINE(HAVE_LANGINFO_TIME,1,[Have nl_langinfo (PM_STR)])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check for nl_langinfo and _NL_CTYPE_OUTDIGITn_WC
|
dnl Check for nl_langinfo and _NL_CTYPE_OUTDIGITn_MB
|
||||||
AC_CACHE_CHECK([for nl_langinfo (_NL_CTYPE_OUTDIGITn_WC)], glib_cv_langinfo_outdigit,[
|
AC_CACHE_CHECK([for nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)], glib_cv_langinfo_outdigit,[
|
||||||
AC_TRY_COMPILE([#include <langinfo.h>],
|
AC_TRY_COMPILE([#include <langinfo.h>],
|
||||||
[char *str;
|
[char *str;
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT0_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT0_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT1_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT1_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT2_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT2_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT3_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT3_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT4_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT4_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT5_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT5_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT6_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT6_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT7_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT7_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT8_WC);
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT8_MB);
|
||||||
str = nl_langinfo (_NL_CTYPE_OUTDIGIT9_WC);],
|
str = nl_langinfo (_NL_CTYPE_OUTDIGIT9_MB);],
|
||||||
[glib_cv_langinfo_outdigit=yes],
|
[glib_cv_langinfo_outdigit=yes],
|
||||||
[glib_cv_langinfo_outdigit=no])])
|
[glib_cv_langinfo_outdigit=no])])
|
||||||
if test x$glib_cv_langinfo_outdigit = xyes; then
|
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
|
fi
|
||||||
|
|
||||||
dnl ****************************************
|
dnl ****************************************
|
||||||
|
574
glib/gdatetime.c
574
glib/gdatetime.c
@ -62,6 +62,8 @@
|
|||||||
|
|
||||||
#include "gslice.h"
|
#include "gslice.h"
|
||||||
#include "gatomic.h"
|
#include "gatomic.h"
|
||||||
|
#include "gcharset.h"
|
||||||
|
#include "gconvert.h"
|
||||||
#include "gfileutils.h"
|
#include "gfileutils.h"
|
||||||
#include "ghash.h"
|
#include "ghash.h"
|
||||||
#include "gmain.h"
|
#include "gmain.h"
|
||||||
@ -2083,15 +2085,15 @@ g_date_time_to_utc (GDateTime *datetime)
|
|||||||
static void
|
static void
|
||||||
format_number (GString *str,
|
format_number (GString *str,
|
||||||
gboolean use_alt_digits,
|
gboolean use_alt_digits,
|
||||||
gchar pad,
|
gchar *pad,
|
||||||
gint width,
|
gint width,
|
||||||
guint32 number)
|
guint32 number)
|
||||||
{
|
{
|
||||||
const gunichar ascii_digits[10] = {
|
const gchar *ascii_digits[10] = {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
|
||||||
};
|
};
|
||||||
const gunichar *digits = ascii_digits;
|
const gchar **digits = ascii_digits;
|
||||||
gunichar tmp[10];
|
const gchar *tmp[10];
|
||||||
gint i = 0;
|
gint i = 0;
|
||||||
|
|
||||||
g_return_if_fail (width <= 10);
|
g_return_if_fail (width <= 10);
|
||||||
@ -2099,18 +2101,14 @@ format_number (GString *str,
|
|||||||
#ifdef HAVE_LANGINFO_OUTDIGIT
|
#ifdef HAVE_LANGINFO_OUTDIGIT
|
||||||
if (use_alt_digits)
|
if (use_alt_digits)
|
||||||
{
|
{
|
||||||
static gunichar alt_digits[10];
|
static const gchar *alt_digits[10];
|
||||||
static gsize initialised;
|
static gsize initialised;
|
||||||
/* 2^32 has 10 digits */
|
/* 2^32 has 10 digits */
|
||||||
|
|
||||||
if G_UNLIKELY (g_once_init_enter (&initialised))
|
if G_UNLIKELY (g_once_init_enter (&initialised))
|
||||||
{
|
{
|
||||||
#define DO_DIGIT(n) \
|
#define DO_DIGIT(n) \
|
||||||
{ \
|
alt_digits[n] = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_MB)
|
||||||
union { guint integer; char *pointer; } val; \
|
|
||||||
val.pointer = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_WC); \
|
|
||||||
alt_digits[n] = val.integer; \
|
|
||||||
}
|
|
||||||
DO_DIGIT(0); DO_DIGIT(1); DO_DIGIT(2); DO_DIGIT(3); DO_DIGIT(4);
|
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);
|
DO_DIGIT(5); DO_DIGIT(6); DO_DIGIT(7); DO_DIGIT(8); DO_DIGIT(9);
|
||||||
#undef DO_DIGIT
|
#undef DO_DIGIT
|
||||||
@ -2129,13 +2127,330 @@ format_number (GString *str,
|
|||||||
while (number);
|
while (number);
|
||||||
|
|
||||||
while (pad && i < width)
|
while (pad && i < width)
|
||||||
tmp[i++] = pad == '0' ? digits[0] : pad;
|
tmp[i++] = *pad == '0' ? digits[0] : pad;
|
||||||
|
|
||||||
/* should really be impossible */
|
/* should really be impossible */
|
||||||
g_assert (i <= 10);
|
g_assert (i <= 10);
|
||||||
|
|
||||||
while (i)
|
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)
|
const gchar *format)
|
||||||
{
|
{
|
||||||
GString *outstr;
|
GString *outstr;
|
||||||
gchar *tmp;
|
gchar *utf8;
|
||||||
gunichar c;
|
gboolean locale_is_utf8 = g_get_charset (NULL);
|
||||||
gboolean in_mod = FALSE;
|
|
||||||
gboolean alt_digits = FALSE;
|
|
||||||
gboolean pad_set = FALSE;
|
|
||||||
gchar pad = '\0';
|
|
||||||
gchar *ampm;
|
|
||||||
|
|
||||||
g_return_val_if_fail (datetime != NULL, NULL);
|
g_return_val_if_fail (datetime != NULL, NULL);
|
||||||
g_return_val_if_fail (format != NULL, NULL);
|
g_return_val_if_fail (format != NULL, NULL);
|
||||||
g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
|
g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
|
||||||
|
|
||||||
outstr = g_string_sized_new (strlen (format) * 2);
|
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);
|
g_string_free (outstr, TRUE);
|
||||||
|
return NULL;
|
||||||
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: ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
g_string_free (outstr, TRUE);
|
||||||
return NULL;
|
return utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -871,6 +871,68 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\
|
|||||||
TEST_PRINTF ("%Z", dst);
|
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
|
static void
|
||||||
test_modifiers (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/new_full", test_GDateTime_new_full);
|
||||||
g_test_add_func ("/GDateTime/now", test_GDateTime_now);
|
g_test_add_func ("/GDateTime/now", test_GDateTime_now);
|
||||||
g_test_add_func ("/GDateTime/printf", test_GDateTime_printf);
|
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/strftime", test_strftime);
|
||||||
g_test_add_func ("/GDateTime/modifiers", test_modifiers);
|
g_test_add_func ("/GDateTime/modifiers", test_modifiers);
|
||||||
g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
|
g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
|
||||||
|
Loading…
Reference in New Issue
Block a user