gdatetime: Fix handling of unsupported nl_langinfo() items

If nl_langinfo() doesn’t support a particular item, it returns the empty
string. We should check for that and return NULL from
g_date_time_format() accordingly, otherwise the user could unwittingly
end up with a formatted date/time which is missing some or all of its
components.

This arose with %r in de_DE, which is unsupported by nl_langinfo()
because Germans almost never write time in 12-hour format.

Add a unit test.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

https://bugzilla.gnome.org/show_bug.cgi?id=790416
This commit is contained in:
Philip Withnall 2017-11-16 09:30:32 +00:00
parent e644bfa37e
commit bccc1057e3
2 changed files with 42 additions and 1 deletions

View File

@ -2695,6 +2695,8 @@ g_date_time_format_locale (GDateTime *datetime,
{ {
case 'a': case 'a':
name = WEEKDAY_ABBR (datetime); name = WEEKDAY_ABBR (datetime);
if (g_strcmp0 (name, "") == 0)
return FALSE;
#if !defined (HAVE_LANGINFO_TIME) #if !defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
@ -2712,6 +2714,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'A': case 'A':
name = WEEKDAY_FULL (datetime); name = WEEKDAY_FULL (datetime);
if (g_strcmp0 (name, "") == 0)
return FALSE;
#if !defined (HAVE_LANGINFO_TIME) #if !defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
@ -2729,6 +2733,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'b': case 'b':
name = MONTH_ABBR (datetime); name = MONTH_ABBR (datetime);
if (g_strcmp0 (name, "") == 0)
return FALSE;
#if !defined (HAVE_LANGINFO_TIME) #if !defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
@ -2746,6 +2752,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'B': case 'B':
name = MONTH_FULL (datetime); name = MONTH_FULL (datetime);
if (g_strcmp0 (name, "") == 0)
return FALSE;
#if !defined (HAVE_LANGINFO_TIME) #if !defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
@ -2763,6 +2771,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'c': case 'c':
{ {
if (g_strcmp0 (PREFERRED_DATE_TIME_FMT, "") == 0)
return FALSE;
if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_TIME_FMT, if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_TIME_FMT,
outstr, locale_is_utf8)) outstr, locale_is_utf8))
return FALSE; return FALSE;
@ -2796,6 +2806,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'h': case 'h':
name = MONTH_ABBR (datetime); name = MONTH_ABBR (datetime);
if (g_strcmp0 (name, "") == 0)
return FALSE;
#if !defined (HAVE_LANGINFO_TIME) #if !defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
@ -2855,6 +2867,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'r': case 'r':
{ {
if (g_strcmp0 (PREFERRED_12HR_TIME_FMT, "") == 0)
return FALSE;
if (!g_date_time_locale_format_locale (datetime, PREFERRED_12HR_TIME_FMT, if (!g_date_time_locale_format_locale (datetime, PREFERRED_12HR_TIME_FMT,
outstr, locale_is_utf8)) outstr, locale_is_utf8))
return FALSE; return FALSE;
@ -2895,6 +2909,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'x': case 'x':
{ {
if (g_strcmp0 (PREFERRED_DATE_FMT, "") == 0)
return FALSE;
if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_FMT, if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_FMT,
outstr, locale_is_utf8)) outstr, locale_is_utf8))
return FALSE; return FALSE;
@ -2902,6 +2918,8 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'X': case 'X':
{ {
if (g_strcmp0 (PREFERRED_TIME_FMT, "") == 0)
return FALSE;
if (!g_date_time_locale_format_locale (datetime, PREFERRED_TIME_FMT, if (!g_date_time_locale_format_locale (datetime, PREFERRED_TIME_FMT,
outstr, locale_is_utf8)) outstr, locale_is_utf8))
return FALSE; return FALSE;
@ -3059,7 +3077,8 @@ g_date_time_format_locale (GDateTime *datetime,
* for the specifier. * for the specifier.
* *
* Returns: a newly allocated string formatted to the requested format * Returns: a newly allocated string formatted to the requested format
* or %NULL in the case that there was an error. The string * or %NULL in the case that there was an error (such as a format specifier
* not being supported in the current locale). The string
* should be freed with g_free(). * should be freed with g_free().
* *
* Since: 2.26 * Since: 2.26

View File

@ -1818,6 +1818,27 @@ test_strftime (void)
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
/* Check that g_date_time_format() correctly returns %NULL for format
* placeholders which are not supported in the current locale. */
static void
test_GDateTime_strftime_error_handling (void)
{
gchar *oldlocale;
oldlocale = g_strdup (setlocale (LC_ALL, NULL));
setlocale (LC_ALL, "de_DE.utf-8");
if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
{
/* de_DE doesnt ever write time in 12-hour notation, so %r is
* unsupported for it. */
TEST_PRINTF_TIME (23, 0, 0, "%r", NULL);
}
else
g_test_skip ("locale de_DE not available, skipping error handling tests");
setlocale (LC_ALL, oldlocale);
g_free (oldlocale);
}
static void static void
test_find_interval (void) test_find_interval (void)
{ {
@ -2141,6 +2162,7 @@ main (gint argc,
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/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/strftime/error_handling", test_GDateTime_strftime_error_handling);
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);
g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix); g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);