[glib] gdatetime: Fix handling of unsupported nl_langinfo() items



commit bccc1057e33277fd566d51166a30e8d1e17c20e0
Author: Philip Withnall <withnall endlessm com>
Date:   Thu Nov 16 09:30:32 2017 +0000

    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

 glib/gdatetime.c       |   21 ++++++++++++++++++++-
 glib/tests/gdatetime.c |   22 ++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletions(-)
---
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 045c578..5123c20 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -2695,6 +2695,8 @@ g_date_time_format_locale (GDateTime   *datetime,
        {
        case 'a':
          name = WEEKDAY_ABBR (datetime);
+          if (g_strcmp0 (name, "") == 0)
+            return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
@@ -2712,6 +2714,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'A':
          name = WEEKDAY_FULL (datetime);
+          if (g_strcmp0 (name, "") == 0)
+            return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
@@ -2729,6 +2733,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'b':
          name = MONTH_ABBR (datetime);
+          if (g_strcmp0 (name, "") == 0)
+            return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
@@ -2746,6 +2752,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'B':
          name = MONTH_FULL (datetime);
+          if (g_strcmp0 (name, "") == 0)
+            return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
@@ -2763,6 +2771,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'c':
          {
+            if (g_strcmp0 (PREFERRED_DATE_TIME_FMT, "") == 0)
+              return FALSE;
            if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_TIME_FMT,
                                                   outstr, locale_is_utf8))
              return FALSE;
@@ -2796,6 +2806,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'h':
          name = MONTH_ABBR (datetime);
+          if (g_strcmp0 (name, "") == 0)
+            return FALSE;
 #if !defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
@@ -2855,6 +2867,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'r':
          {
+            if (g_strcmp0 (PREFERRED_12HR_TIME_FMT, "") == 0)
+              return FALSE;
            if (!g_date_time_locale_format_locale (datetime, PREFERRED_12HR_TIME_FMT,
                                                   outstr, locale_is_utf8))
              return FALSE;
@@ -2895,6 +2909,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'x':
          {
+            if (g_strcmp0 (PREFERRED_DATE_FMT, "") == 0)
+              return FALSE;
            if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_FMT,
                                                   outstr, locale_is_utf8))
              return FALSE;
@@ -2902,6 +2918,8 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'X':
          {
+            if (g_strcmp0 (PREFERRED_TIME_FMT, "") == 0)
+              return FALSE;
            if (!g_date_time_locale_format_locale (datetime, PREFERRED_TIME_FMT,
                                                   outstr, locale_is_utf8))
              return FALSE;
@@ -3059,7 +3077,8 @@ g_date_time_format_locale (GDateTime   *datetime,
  *   for the specifier.
  *
  * 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().
  *
  * Since: 2.26
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index fc117e2..296a1e9 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -1818,6 +1818,27 @@ test_strftime (void)
 }
 #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 doesn’t 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
 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/non_utf8_printf", test_non_utf8_printf);
   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/to_local", test_GDateTime_to_local);
   g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);


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