Branch
Hash :
a5ce928d
Author :
Date :
2025-02-14T05:56:55
duplocale: Support all platforms. * lib/locale.in.h (duplocale): Declare also on platforms that don't already have a duplocale function. Don't define HAVE_WORKING_DUPLOCALE. * lib/duplocale.c: Include <stdlib.h>. (duplocale): Renamed from rpl_duplocale. Add implementation for platforms without native locale_t. * modules/duplocale (Depends-on): Add newlocale, freelocale. (configure.ac): Compile also on platforms without native locale_t. * tests/test-duplocale.c: Ignore HAVE_WORKING_DUPLOCALE. * tests/test-locale-h-c++.cc: Likewise. * doc/posix-functions/duplocale.texi: Mention the change.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
/* Test of duplicating a locale object.
Copyright (C) 2009-2025 Free Software Foundation, Inc.
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 3 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, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2007. */
#include <config.h>
#include <locale.h>
#include "signature.h"
SIGNATURE_CHECK (duplocale, locale_t, (locale_t));
#include <langinfo.h>
#if HAVE_MONETARY_H
# include <monetary.h>
#endif
#include <stdio.h>
#include <string.h>
#include "macros.h"
struct locale_dependent_values
{
#if HAVE_MONETARY_H
char monetary[100];
#endif
char numeric[100];
char time[100];
};
static void
get_locale_dependent_values (struct locale_dependent_values *result)
{
#if HAVE_MONETARY_H
strfmon (result->monetary, sizeof (result->monetary),
"%n", 123.75);
/* result->monetary is usually "$123.75" */
#endif
snprintf (result->numeric, sizeof (result->numeric),
"%g", 3.5);
/* result->numeric is usually "3,5" */
strncpy (result->time, nl_langinfo (MON_1), sizeof result->time - 1);
result->time[sizeof result->time - 1] = '\0';
/* result->time is usually "janvier" */
}
#if HAVE_WORKING_USELOCALE
static int
test_with_uselocale (void)
{
struct locale_dependent_values expected_results;
locale_t mixed1;
locale_t mixed2;
locale_t perthread;
/* Set up a locale which is a mix between different system locales. */
setlocale (LC_ALL, "en_US.UTF-8");
setlocale (LC_NUMERIC, "de_DE.UTF-8");
setlocale (LC_TIME, "fr_FR.UTF-8");
get_locale_dependent_values (&expected_results);
/* Save the locale in a locale_t object. */
mixed1 = duplocale (LC_GLOBAL_LOCALE);
ASSERT (mixed1 != NULL);
/* Use a per-thread locale. */
perthread = newlocale (LC_ALL_MASK, "es_ES.UTF-8", NULL);
if (perthread == NULL)
return 1;
uselocale (perthread);
/* Save the locale in a locale_t object again. */
mixed2 = duplocale (LC_GLOBAL_LOCALE);
ASSERT (mixed2 != NULL);
/* Set up a default locale. */
setlocale (LC_ALL, "C");
uselocale (LC_GLOBAL_LOCALE);
{
struct locale_dependent_values c_results;
get_locale_dependent_values (&c_results);
}
/* Now use the saved locale mixed1 again. */
setlocale (LC_ALL, "C");
uselocale (LC_GLOBAL_LOCALE);
uselocale (mixed1);
{
struct locale_dependent_values results;
get_locale_dependent_values (&results);
# if HAVE_MONETARY_H
ASSERT (strcmp (results.monetary, expected_results.monetary) == 0);
# endif
ASSERT (strcmp (results.numeric, expected_results.numeric) == 0);
ASSERT (strcmp (results.time, expected_results.time) == 0);
}
/* Now use the saved locale mixed2 again. */
setlocale (LC_ALL, "C");
uselocale (LC_GLOBAL_LOCALE);
uselocale (mixed2);
{
struct locale_dependent_values results;
get_locale_dependent_values (&results);
# if HAVE_MONETARY_H
ASSERT (strcmp (results.monetary, expected_results.monetary) == 0);
# endif
ASSERT (strcmp (results.numeric, expected_results.numeric) == 0);
ASSERT (strcmp (results.time, expected_results.time) == 0);
}
setlocale (LC_ALL, "C");
uselocale (LC_GLOBAL_LOCALE);
freelocale (mixed1);
freelocale (mixed2);
freelocale (perthread);
return 0;
}
#endif
#if HAVE_STRFMON_L || HAVE_SNPRINTF_L || (HAVE_NL_LANGINFO_L && HAVE_WORKING_USELOCALE)
static void
get_locale_dependent_values_from (struct locale_dependent_values *result, locale_t locale)
{
#if HAVE_STRFMON_L
strfmon_l (result->monetary, sizeof (result->monetary), locale,
"%n", 123.75);
/* result->monetary is usually "$123.75" */
#endif
#if HAVE_SNPRINTF_L
snprintf_l (result->numeric, sizeof (result->numeric), locale,
"%g", 3.5);
/* result->numeric is usually "3,5" */
#endif
#if HAVE_NL_LANGINFO_L && HAVE_WORKING_USELOCALE
strcpy (result->time, nl_langinfo_l (MON_1, locale));
/* result->time is usually "janvier" */
#endif
}
static int
test_with_locale_parameter (void)
{
struct locale_dependent_values expected_results;
locale_t mixed1;
locale_t mixed2;
/* Set up a locale which is a mix between different system locales. */
setlocale (LC_ALL, "en_US.UTF-8");
setlocale (LC_NUMERIC, "de_DE.UTF-8");
setlocale (LC_TIME, "fr_FR.UTF-8");
get_locale_dependent_values (&expected_results);
/* Save the locale in a locale_t object. */
mixed1 = duplocale (LC_GLOBAL_LOCALE);
ASSERT (mixed1 != NULL);
/* Create another locale_t object. */
mixed2 = newlocale (LC_ALL_MASK, "es_ES.UTF-8", NULL);
if (mixed2 == NULL)
return 1;
/* Set up a default locale. */
setlocale (LC_ALL, "C");
{
struct locale_dependent_values c_results;
get_locale_dependent_values (&c_results);
}
/* Now use the saved locale mixed2. */
{
struct locale_dependent_values results;
get_locale_dependent_values_from (&results, mixed2);
}
/* Now use the saved locale mixed1 again. */
{
struct locale_dependent_values results;
get_locale_dependent_values_from (&results, mixed1);
#if HAVE_STRFMON_L
ASSERT (strcmp (results.monetary, expected_results.monetary) == 0);
#endif
#if HAVE_SNPRINTF_L
ASSERT (strcmp (results.numeric, expected_results.numeric) == 0);
#endif
#if HAVE_NL_LANGINFO_L && HAVE_WORKING_USELOCALE
ASSERT (strcmp (results.time, expected_results.time) == 0);
#endif
}
freelocale (mixed1);
freelocale (mixed2);
return 0;
}
#endif
int
main ()
{
int skipped = 0;
#if HAVE_WORKING_USELOCALE
skipped |= test_with_uselocale ();
#endif
#if HAVE_STRFMON_L || HAVE_SNPRINTF_L || (HAVE_NL_LANGINFO_L && HAVE_WORKING_USELOCALE)
skipped |= test_with_locale_parameter ();
#endif
if (skipped)
{
if (test_exit_status != EXIT_SUCCESS)
return test_exit_status;
fprintf (stderr, "Skipping test: Spanish Unicode locale is not installed\n");
return 77;
}
return test_exit_status;
}