From e311a45653911d3d1e4ff71afac89df2cf71fca0 Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Mon, 5 Mar 2018 19:50:33 +0900 Subject: [PATCH] gcharset: Add g_get_language_names_with_category g_get_language_names() uses LC_MESSAGES and the fallback is useful for other locale categories too. https://bugzilla.gnome.org/show_bug.cgi?id=751826 --- glib/gcharset.c | 64 ++++++++++++++++++++++++++--------- glib/gcharset.h | 3 ++ glib/tests/charset.c | 75 ++++++++++++++++++++++++++++++++++++++++++ glib/tests/meson.build | 1 + 4 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 glib/tests/charset.c diff --git a/glib/gcharset.c b/glib/gcharset.c index 704ea13c8..8aa549694 100644 --- a/glib/gcharset.c +++ b/glib/gcharset.c @@ -18,6 +18,7 @@ #include "config.h" +#include "gcharset.h" #include "gcharsetprivate.h" #include "garray.h" @@ -553,44 +554,77 @@ language_names_cache_free (gpointer data) * that must not be modified or freed. * * Since: 2.6 - **/ + */ const gchar * const * g_get_language_names (void) { - static GPrivate cache_private = G_PRIVATE_INIT (language_names_cache_free); - GLanguageNamesCache *cache = g_private_get (&cache_private); - const gchar *value; + return g_get_language_names_with_category ("LC_MESSAGES"); +} + +/** + * g_get_language_names_with_category: + * @category_name: a locale category name + * + * Computes a list of applicable locale names with a locale category name, + * which can be used to construct the fallback locale-dependent filenames + * or search paths. The returned list is sorted from most desirable to + * least desirable and always contains the default locale "C". + * + * This function consults the environment variables `LANGUAGE`, `LC_ALL`, + * @category_name, and `LANG` to find the list of locales specified by the + * user. + * + * g_get_language_names() returns g_get_language_names_with_category("LC_MESSAGES"). + * + * Returns: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib + * that must not be modified or freed. + * + * Since: 2.58 + */ +const gchar * const * +g_get_language_names_with_category (const gchar *category_name) +{ + static GPrivate cache_private = G_PRIVATE_INIT ((void (*)(gpointer)) g_hash_table_remove_all); + GHashTable *cache = g_private_get (&cache_private); + const gchar *languages; + GLanguageNamesCache *name_cache; + + g_return_val_if_fail (category_name != NULL, NULL); if (!cache) { - cache = g_new0 (GLanguageNamesCache, 1); + cache = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, language_names_cache_free); g_private_set (&cache_private, cache); } - value = guess_category_value ("LC_MESSAGES"); - if (!value) - value = "C"; + languages = guess_category_value (category_name); + if (!languages) + languages = "C"; - if (!(cache->languages && strcmp (cache->languages, value) == 0)) + name_cache = (GLanguageNamesCache *) g_hash_table_lookup (cache, category_name); + if (!(name_cache && name_cache->languages && + strcmp (name_cache->languages, languages) == 0)) { GPtrArray *array; gchar **alist, **a; - g_free (cache->languages); - g_strfreev (cache->language_names); - cache->languages = g_strdup (value); + g_hash_table_remove (cache, category_name); array = g_ptr_array_sized_new (8); - alist = g_strsplit (value, ":", 0); + alist = g_strsplit (languages, ":", 0); for (a = alist; *a; a++) append_locale_variants (array, unalias_lang (*a)); g_strfreev (alist); g_ptr_array_add (array, g_strdup ("C")); g_ptr_array_add (array, NULL); - cache->language_names = (gchar **) g_ptr_array_free (array, FALSE); + name_cache = g_new0 (GLanguageNamesCache, 1); + name_cache->languages = g_strdup (languages); + name_cache->language_names = (gchar **) g_ptr_array_free (array, FALSE); + g_hash_table_insert (cache, g_strdup (category_name), name_cache); } - return (const gchar * const *) cache->language_names; + return (const gchar * const *) name_cache->language_names; } diff --git a/glib/gcharset.h b/glib/gcharset.h index fccedc7c3..bb20f5d43 100644 --- a/glib/gcharset.h +++ b/glib/gcharset.h @@ -34,6 +34,9 @@ gchar * g_get_codeset (void); GLIB_AVAILABLE_IN_ALL const gchar * const * g_get_language_names (void); +GLIB_AVAILABLE_IN_2_58 +const gchar * const * g_get_language_names_with_category + (const gchar *category_name); GLIB_AVAILABLE_IN_ALL gchar ** g_get_locale_variants (const gchar *locale); diff --git a/glib/tests/charset.c b/glib/tests/charset.c new file mode 100644 index 000000000..ef4370a42 --- /dev/null +++ b/glib/tests/charset.c @@ -0,0 +1,75 @@ +/* + * Copyright 2018 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * See the included COPYING file for more information. + */ + +#undef G_DISABLE_ASSERT +#undef G_LOG_DOMAIN + +#include "glib.h" + +#define TEST_LOCALE "fr_FR.UTF-8@latin:en_US.UTF-8" + +const gchar *TEST_RESULT[] = { + "fr_FR.UTF-8@latin", + "fr_FR@latin", + "fr.UTF-8@latin", + "fr@latin", + "fr_FR.UTF-8", + "fr_FR", + "fr.UTF-8", + "fr", + "en_US.UTF-8", + "en_US", + "en.UTF-8", + "en", + "C", + NULL +}; + +const gchar *TEST_TABLE[] = { + "LANGUAGE", + "LC_ALL", + "LC_CTYPE", + "LANG", + NULL +}; + +static void +test_language_names_with_category (void) +{ + const gchar * const *language_names = NULL; + gsize i, j; + + for (i = 0; TEST_TABLE[i]; ++i) + { + g_test_message ("Test %" G_GSIZE_FORMAT, i); + g_assert_true (g_setenv (TEST_TABLE[i], TEST_LOCALE, TRUE)); + language_names = g_get_language_names_with_category ("LC_CTYPE"); + g_assert_cmpuint (g_strv_length ((gchar **)language_names), ==, g_strv_length ((gchar **)TEST_RESULT)); + + for (j = 0; language_names[j]; ++j) + { + g_assert_cmpstr (language_names[j], ==, TEST_RESULT[j]); + } + g_unsetenv (TEST_TABLE[i]); + } +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_bug_base ("http://bugs.gnome.org/"); + + g_test_add_func ("/charset/language_names_with_category", test_language_names_with_category); + + return g_test_run (); +} diff --git a/glib/tests/meson.build b/glib/tests/meson.build index 4ac3620b8..1cf23ff13 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -6,6 +6,7 @@ glib_tests = [ 'bookmarkfile', 'bytes', 'cache', + 'charset', 'checksum', 'collate', 'cond',