[gnome-desktop] Revert "Revert "Replace usage of non-portable `uselocale` with locale-dependent functions""



commit 856cc6c6820810f0de81e4249a6a60996e0b80c5
Author: Dan Cîrnaț <cirnatdan NetBSD org>
Date:   Thu Apr 15 16:09:59 2021 +0200

    Revert "Revert "Replace usage of non-portable `uselocale` with locale-dependent functions""
    
    This reverts commit 96565763e950e9c281751c5fe35c9ba83cb61ac8.

 config.h.meson                            |  6 +++
 libgnome-desktop/gnome-gettext-portable.c | 72 +++++++++++++++++++++++++++++
 libgnome-desktop/gnome-gettext-portable.h | 42 +++++++++++++++++
 libgnome-desktop/gnome-languages.c        | 76 +++++++++++++------------------
 libgnome-desktop/gnome-wall-clock.c       |  9 +---
 libgnome-desktop/meson.build              |  3 +-
 meson.build                               |  1 +
 tests/languages.c                         | 58 +++++++++++++++++++++++
 tests/meson.build                         |  3 +-
 tests/wall-clock.c                        | 52 ++++++---------------
 tests/wallclock-reftest.c                 | 17 ++-----
 11 files changed, 234 insertions(+), 105 deletions(-)
---
diff --git a/config.h.meson b/config.h.meson
index 75b0170d..2c4778b0 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -27,3 +27,9 @@
 
 /* Define to include GNU extensions */
 #mesondefine _GNU_SOURCE
+
+/* define on systems that have the `uselocale` function */
+#mesondefine HAVE_USELOCALE
+
+/* define on system if OS has extended locale header */
+#mesondefine HAVE_XLOCALE
diff --git a/libgnome-desktop/gnome-gettext-portable.c b/libgnome-desktop/gnome-gettext-portable.c
new file mode 100644
index 00000000..aaba4d08
--- /dev/null
+++ b/libgnome-desktop/gnome-gettext-portable.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2021 Dan Cîrnaț <dan alt md>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include "config.h"
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#ifndef HAVE_USELOCALE
+/**
+ * FIXME: This function does nothing if there's no thread-safe
+ * alternative to uselocale on some systems (NetBSD). Replace it
+ * when an implementation becomes available.
+ */
+locale_t
+uselocale (locale_t newloc)
+{
+       return (locale_t) 0;
+}
+#endif
+
+char * 
+dgettext_l (locale_t    locale, 
+            const char *domain,
+            const char *msgid)
+{
+       locale_t old_locale = uselocale (locale);
+       char *ret = dgettext (domain, msgid);
+       uselocale (old_locale);
+       return ret;
+}
+
+const gchar *
+g_dgettext_l (locale_t     locale,
+              const gchar *domain,
+              const gchar *msgid)
+{
+       locale_t old_locale = uselocale (locale);
+       const gchar *ret = g_dgettext (domain, msgid);
+       uselocale (old_locale); 
+       return ret;
+}
+
+const gchar *
+g_dpgettext_l (locale_t     locale,
+               const gchar *domain,
+               const gchar *msgctxtid,
+               gsize        msgidoffset)
+{
+       locale_t old_locale = uselocale (locale);
+       const gchar *ret = g_dpgettext (domain, msgctxtid, msgidoffset);
+       uselocale (old_locale);
+       return ret;
+}
diff --git a/libgnome-desktop/gnome-gettext-portable.h b/libgnome-desktop/gnome-gettext-portable.h
new file mode 100644
index 00000000..c8af3691
--- /dev/null
+++ b/libgnome-desktop/gnome-gettext-portable.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2021 Dan Cîrnaț <dan alt md>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <locale.h>
+#include <string.h>
+
+const char * 
+dgettext_l (locale_t    locale,
+            const char *domain,
+            const char *msgid);
+
+const gchar *
+g_dgettext_l (locale_t     locale,
+              const gchar *domain,
+              const gchar *msgid);
+
+const gchar *
+g_dpgettext_l (locale_t     locale,
+               const gchar *domain,
+               const gchar *msgctxtid,
+               gsize        msgidoffset);
+
+#define  _l(locale_t,String) ((char *) g_dgettext_l (locale_t, GETTEXT_PACKAGE, String))
diff --git a/libgnome-desktop/gnome-languages.c b/libgnome-desktop/gnome-languages.c
index d38f9b89..bd62489c 100644
--- a/libgnome-desktop/gnome-languages.c
+++ b/libgnome-desktop/gnome-languages.c
@@ -28,7 +28,6 @@
 #include <string.h>
 #include <errno.h>
 #include <dirent.h>
-#include <locale.h>
 #include <langinfo.h>
 #include <sys/stat.h>
 
@@ -36,6 +35,8 @@
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
+#include "gnome-gettext-portable.h"
+
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include "gnome-languages.h"
 
@@ -303,16 +304,14 @@ language_name_get_codeset_details (const char  *language_name,
                                    gboolean    *is_utf8)
 {
         locale_t locale;
-        locale_t old_locale;
         const char *codeset = NULL;
 
         locale = newlocale (LC_CTYPE_MASK, language_name, (locale_t) 0);
         if (locale == (locale_t) 0)
                 return;
 
-        old_locale = uselocale (locale);
 
-        codeset = nl_langinfo (CODESET);
+        codeset = nl_langinfo_l (CODESET, locale);
 
         if (pcodeset != NULL) {
                 *pcodeset = g_strdup (codeset);
@@ -324,7 +323,6 @@ language_name_get_codeset_details (const char  *language_name,
                 *is_utf8 = strcmp (normalized_codeset, "UTF-8") == 0;
         }
 
-        uselocale (old_locale);
         freelocale (locale);
 }
 
@@ -704,28 +702,24 @@ get_translated_language (const char *code,
         if (language != NULL) {
                 const char *translated_name;
                 locale_t loc = 0;
-                locale_t old_locale = 0;
 
-                if (locale != NULL) {
-                        loc = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0);
-                        if (loc == (locale_t) 0)
-                                return NULL;
-                        old_locale = uselocale (loc);
+                if (locale == NULL) {
+                        locale = setlocale (LC_MESSAGES, NULL);
                 }
+                loc = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0);
+                if (loc == (locale_t) 0)
+                        return NULL;
 
                 if (is_fallback_language (code)) {
                         name = g_strdup (_("Unspecified"));
                 } else {
                         g_autofree char *tmp = NULL;
-                        translated_name = dgettext ("iso_639", language);
+                        translated_name = dgettext_l (loc, "iso_639", language);
                         tmp = get_first_item_in_semicolon_list (translated_name);
                         name = capitalize_utf8_string (tmp);
                 }
 
-                if (locale != NULL) {
-                        uselocale (old_locale);
-                        freelocale (loc);
-                }
+                freelocale (loc);
         }
 
         return name;
@@ -762,24 +756,20 @@ get_translated_territory (const char *code,
         if (territory != NULL) {
                 const char *translated_territory;
                 locale_t loc;
-                locale_t old_locale = 0;
                 g_autofree char *tmp = NULL;
 
-                if (locale != NULL) {
-                        loc = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0);
-                        if (loc == (locale_t) 0)
-                                return NULL;
-                        old_locale = uselocale (loc);
+                if (locale == NULL) {
+                        locale = setlocale (LC_MESSAGES, NULL);
                 }
+                loc = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0);
+                if (loc == (locale_t) 0)
+                        return NULL;
 
-                translated_territory = dgettext ("iso_3166", territory);
+                translated_territory = dgettext_l (loc, "iso_3166", territory);
                 tmp = get_first_item_in_semicolon_list (translated_territory);
                 name = capitalize_utf8_string (tmp);
 
-                if (locale != NULL) {
-                        uselocale (old_locale);
-                        freelocale (loc);
-                }
+                freelocale (loc);
         }
 
         return name;
@@ -1359,16 +1349,15 @@ gnome_get_translated_modifier (const char *modifier,
         char *retval;
         GHashTable *modifiers_map;
         locale_t loc;
-        locale_t old_locale;
 
         g_return_val_if_fail (modifier != NULL, NULL);
 
-        if (translation != NULL) {
-                loc = newlocale (LC_MESSAGES_MASK, translation, (locale_t) 0);
-                if (loc == (locale_t) 0) {
-                        return NULL;
-                }
-                old_locale = uselocale (loc);
+        if (translation == NULL) {
+                translation = setlocale (LC_MESSAGES, NULL);
+        }
+        loc = newlocale (LC_MESSAGES_MASK, translation, (locale_t) 0);
+        if (loc == (locale_t) 0) {
+                return NULL;
         }
 
         /* Modifiers as listed in glibc's SUPPORTED file:
@@ -1379,26 +1368,26 @@ gnome_get_translated_modifier (const char *modifier,
         /* TRANSLATORS: Used to distinguish the labels representing the gez_ER
            and gez_ET locales from gez_ER@abegede respective gez_ET@abegede. The
            difference is related to collation. */
-        g_hash_table_insert (modifiers_map, "abegede", _("Abegede"));
+        g_hash_table_insert (modifiers_map, "abegede", _l(loc, "Abegede"));
         /* TRANSLATORS: Used to distinguish Cyrillic from Latin written language variants. */
-        g_hash_table_insert (modifiers_map, "cyrillic", _("Cyrillic"));
+        g_hash_table_insert (modifiers_map, "cyrillic", _l(loc, "Cyrillic"));
         /* TRANSLATORS: Also known as "Nagari", a written variant for many languages
            of the Indian subcontinent. See:
            https://en.wikipedia.org/wiki/Devanagari */
-        g_hash_table_insert (modifiers_map, "devanagari", _("Devanagari"));
+        g_hash_table_insert (modifiers_map, "devanagari", _l(loc, "Devanagari"));
         /* TRANSLATORS: Used to distinguish the label representing the tt_RU
            locale from tt_RU@iqtelif. It's a special alphabet for Tatar. */
-        g_hash_table_insert (modifiers_map, "iqtelif", _("IQTElif"));
+        g_hash_table_insert (modifiers_map, "iqtelif", _l(loc, "IQTElif"));
         /* TRANSLATORS: The alphabet/script, not the language. Used to distinguish
            Latin from Cyrillic written language variants. */
-        g_hash_table_insert (modifiers_map, "latin", _("Latin"));
+        g_hash_table_insert (modifiers_map, "latin", _l(loc, "Latin"));
         /* TRANSLATORS: "Saho" is a variant of the Afar language. Used to
            distinguish the label representing the aa_ER locale from aa_ER@saaho. */
-        g_hash_table_insert (modifiers_map, "saaho", _("Saho"));
+        g_hash_table_insert (modifiers_map, "saaho", _l(loc, "Saho"));
         /* TRANSLATORS: "Valencia" is a dialect of the Catalan language spoken
            in Valencia. Used to distinguish the label representing the ca_ES
            locale from ca_ES@valencia. */
-        g_hash_table_insert (modifiers_map, "valencia", _("Valencia"));
+        g_hash_table_insert (modifiers_map, "valencia", _l(loc, "Valencia"));
 
         if (g_hash_table_contains (modifiers_map, modifier))
                 retval = g_strdup (g_hash_table_lookup (modifiers_map, modifier));
@@ -1407,10 +1396,7 @@ gnome_get_translated_modifier (const char *modifier,
 
         g_hash_table_destroy (modifiers_map);
 
-        if (translation != NULL) {
-                uselocale (old_locale);
-                freelocale (loc);
-        }
+        freelocale (loc);
 
         return retval;
 }
diff --git a/libgnome-desktop/gnome-wall-clock.c b/libgnome-desktop/gnome-wall-clock.c
index caede60d..b4d72b87 100644
--- a/libgnome-desktop/gnome-wall-clock.c
+++ b/libgnome-desktop/gnome-wall-clock.c
@@ -24,8 +24,8 @@
 
 #include "config.h"
 
-#include <locale.h>
 #include <glib/gi18n-lib.h>
+#include "gnome-gettext-portable.h"
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include "gnome-wall-clock.h"
@@ -289,18 +289,13 @@ translate_time_format_string (const char *str)
   const char *locale = g_getenv ("LC_TIME");
   const char *res;
   char *sep;
-  locale_t old_loc;
   locale_t loc = (locale_t)0;
 
   if (locale)
     loc = newlocale (LC_MESSAGES_MASK, locale, (locale_t)0);
 
-  old_loc = uselocale (loc);
-
   sep = strchr (str, '\004');
-  res = g_dpgettext (GETTEXT_PACKAGE, str, sep ? sep - str + 1 : 0);
-
-  uselocale (old_loc);
+  res = g_dpgettext_l (loc, GETTEXT_PACKAGE, str, sep ? sep - str + 1 : 0);
 
   if (loc != (locale_t)0)
     freelocale (loc);
diff --git a/libgnome-desktop/meson.build b/libgnome-desktop/meson.build
index 483f1ff6..8c3a2dfd 100644
--- a/libgnome-desktop/meson.build
+++ b/libgnome-desktop/meson.build
@@ -48,7 +48,8 @@ libgnome_desktop_sources = [
   'default-input-sources.h',
   'meta-xrandr-shared.h',
   'gnome-desktop-thumbnail-script.c',
-  'gnome-desktop-thumbnail-script.h'
+  'gnome-desktop-thumbnail-script.h',
+  'gnome-gettext-portable.c'
 ]
 
 libgnome_desktop_headers = [
diff --git a/meson.build b/meson.build
index 3efd6773..490d43e6 100644
--- a/meson.build
+++ b/meson.build
@@ -94,6 +94,7 @@ conf.set('HAVE_XKBREGISTRY', xkbregistry_dep.found())
 
 conf.set('HAVE_TIMERFD', cc.has_function('timerfd_create'))
 conf.set('HAVE_OPENAT', cc.has_function('openat'))
+conf.set('HAVE_USELOCALE', cc.has_function('uselocale'))
 
 config_h = declare_dependency(
   sources: configure_file(
diff --git a/tests/languages.c b/tests/languages.c
new file mode 100644
index 00000000..34c1cc02
--- /dev/null
+++ b/tests/languages.c
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
+ *
+ * Copyright (C) 2021 Dan Cîrnaț <dan alt md>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <gdesktop-enums.h>
+#include <glib.h>
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+#include <locale.h>
+#include <string.h>
+
+static void
+test_using_null_locale (void)
+{
+       const char *translated_territory;
+       const char *translated_language;
+       const char *translated_modifier;
+
+       translated_territory = gnome_get_country_from_code("US", NULL);
+       g_assert (translated_territory != NULL);
+
+       translated_language = gnome_get_language_from_locale("ro", NULL);
+       g_assert (translated_language != NULL);
+
+       translated_modifier = gnome_get_translated_modifier("euro", NULL);
+       g_assert (translated_modifier != NULL);
+
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+       g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
+
+       g_test_init (&argc, &argv, NULL);
+
+       g_test_add_func ("/languages/using-null-locale", test_using_null_locale);
+
+       return g_test_run ();
+}
diff --git a/tests/meson.build b/tests/meson.build
index 6ad97ebd..8333a810 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -13,7 +13,8 @@ test_env = [
 
 test_programs = [
   'wall-clock',
- 'wallclock-reftest'
+  'wallclock-reftest',
+  'languages'
 ]
 
 test_metas = []
diff --git a/tests/wall-clock.c b/tests/wall-clock.c
index 486cfa38..0e8c49c9 100644
--- a/tests/wall-clock.c
+++ b/tests/wall-clock.c
@@ -36,8 +36,7 @@ test_utf8_character (const char *utf8_char,
 {
        GDateTime  *datetime;
        GnomeWallClock *clock;
-       locale_t locale;
-       locale_t save_locale;
+       const char *save_locale;
        const char *str;
 
        /* When testing that UTF8 locales don't use double spaces
@@ -47,9 +46,7 @@ test_utf8_character (const char *utf8_char,
 
        /* In the C locale, make sure the time string is formatted with regular
          * colons */
-       locale = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
-       g_assert_true (locale != (locale_t)0);
-       save_locale = uselocale (locale);
+       save_locale = setlocale (LC_ALL, NULL);
        clock = gnome_wall_clock_new ();
        str = gnome_wall_clock_string_for_datetime (clock,
                                                    datetime,
@@ -60,13 +57,7 @@ test_utf8_character (const char *utf8_char,
        g_object_unref (clock);
 
        /* In a UTF8 locale, we want ratio characters and no colons. */
-       locale = newlocale (LC_ALL_MASK, "en_US.utf8", locale);
-       if (locale == (locale_t)0) {
-               g_test_message ("en_US.utf8 locale not found");
-               g_test_fail ();
-               return;
-       }
-       uselocale (locale);
+       setlocale (LC_ALL, "en_US.utf8");
        clock = gnome_wall_clock_new ();
        str = gnome_wall_clock_string_for_datetime (clock,
                                                    datetime,
@@ -78,13 +69,7 @@ test_utf8_character (const char *utf8_char,
 
        /* ... and same thing with an RTL locale: should be formatted with
          * ratio characters */
-       locale = newlocale (LC_ALL_MASK, "he_IL.utf8", locale);
-       if (locale == (locale_t)0) {
-               g_test_message ("he_IL.utf8 locale not found");
-               g_test_fail ();
-               return;
-       }
-       uselocale (locale);
+       setlocale (LC_ALL, "he_IL.utf8");
        clock = gnome_wall_clock_new ();
        str = gnome_wall_clock_string_for_datetime (clock,
                                                    datetime,
@@ -97,8 +82,7 @@ test_utf8_character (const char *utf8_char,
        g_date_time_unref (datetime);
 
        /* Restore previous locale */
-       uselocale (save_locale);
-       freelocale (locale);
+       setlocale (LC_ALL, save_locale);
 }
 
 static void
@@ -118,17 +102,11 @@ test_clock_format_setting (void)
 {
        GnomeWallClock *clock;
        GSettings *settings;
-       locale_t locale;
-       locale_t save_locale;
+       const char *save_locale;
        const char *str;
 
-       locale = newlocale (LC_ALL_MASK, "en_US.utf8", (locale_t) 0);
-       if (locale == (locale_t)0) {
-               g_test_message ("en_US.utf8 locale not found");
-               g_test_fail ();
-               return;
-       }
-       save_locale = uselocale (locale);
+       save_locale = setlocale (LC_ALL, NULL);
+       setlocale (LC_ALL, "en_US.utf8");
 
        settings = g_settings_new ("org.gnome.desktop.interface");
 
@@ -149,8 +127,7 @@ test_clock_format_setting (void)
        g_object_unref (settings);
 
        /* Restore previous locale */
-       uselocale (save_locale);
-       freelocale (locale);
+       setlocale (LC_ALL, save_locale);
 }
 
 static gboolean
@@ -202,14 +179,12 @@ test_weekday_setting (void)
 {
        GnomeWallClock *clock;
        GSettings *settings;
-       locale_t locale;
-       locale_t save_locale;
+       const char *save_locale;
        const char *str, *ptr, *s;
 
        /* Save current locale */
-       locale = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
-       g_assert_true (locale != (locale_t)0);
-       save_locale = uselocale (locale);
+       save_locale = setlocale (LC_ALL, NULL);
+       setlocale (LC_ALL, "C");
        settings = g_settings_new ("org.gnome.desktop.interface");
 
        /* Set 24h format, so that the only alphabetical part will be the weekday */
@@ -245,8 +220,7 @@ test_weekday_setting (void)
        g_object_unref (settings);
 
        /* Restore previous locale */
-       uselocale (save_locale);
-       freelocale (locale);
+       setlocale (LC_ALL, save_locale);
 }
 
 int
diff --git a/tests/wallclock-reftest.c b/tests/wallclock-reftest.c
index 1238ea89..e6026032 100644
--- a/tests/wallclock-reftest.c
+++ b/tests/wallclock-reftest.c
@@ -439,21 +439,15 @@ test_ui_file (GFile         *file,
   GnomeWallClock *clock;
   GDateTime *datetime;
   char *str;
-  locale_t loc, previous_locale;
+  const char *previous_locale;
 
   ui_file = g_file_get_path (file);
 
   locale = get_locale_for_file (ui_file);
   g_assert (locale);
-  loc = newlocale (LC_ALL_MASK, locale, (locale_t) 0);
-  if (loc == (locale_t)0)
-    {
-      g_test_message ("locale '%s' not found", locale);
-      g_test_fail();
-      return;
-    }
-  previous_locale = uselocale (loc);
-  g_assert_true (previous_locale != (locale_t) 0);
+  previous_locale = setlocale (LC_ALL, NULL);
+  setlocale (LC_ALL, locale);
+  g_assert_true (previous_locale != NULL);
 
   clock = gnome_wall_clock_new ();
   datetime = g_date_time_new_local (2014, 5, 28, 23, 59, 59);
@@ -465,8 +459,7 @@ test_ui_file (GFile         *file,
   g_date_time_unref (datetime);
   g_object_unref (clock);
 
-  uselocale (previous_locale);
-  freelocale (loc);
+  setlocale (LC_ALL, previous_locale);
 
   provider = add_extra_css (ui_file, ".css");
 


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