These patches implement a portable freelocale() function, that matches the just-added newlocale() function.
2025-02-14 Bruno Haible <br...@clisp.org> freelocale: Add tests. * tests/test-freelocale.c: New file. * modules/freelocale-tests: New file. freelocale: New module. * lib/locale.in.h (freelocale): Consider GNULIB_FREELOCALE. Declare if not declared. * lib/freelocale.c: New file. * m4/freelocale.m4: New file. * m4/locale_h.m4 (gl_LOCALE_H_REQUIRE_DEFAULTS): Initialize GNULIB_FREELOCALE. * modules/locale-h (Makefile.am): Substitute GNULIB_FREELOCALE. * modules/freelocale: New file. * tests/test-locale-h-c++.cc: Check declaration of freelocale. * doc/posix-functions/freelocale.texi: Mention the new module.
>From 414c6c84f65d54c9ba79716d2c430e539ea0f0f4 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Fri, 14 Feb 2025 02:59:02 +0100 Subject: [PATCH 1/2] freelocale: New module. * lib/locale.in.h (freelocale): Consider GNULIB_FREELOCALE. Declare if not declared. * lib/freelocale.c: New file. * m4/freelocale.m4: New file. * m4/locale_h.m4 (gl_LOCALE_H_REQUIRE_DEFAULTS): Initialize GNULIB_FREELOCALE. * modules/locale-h (Makefile.am): Substitute GNULIB_FREELOCALE. * modules/freelocale: New file. * tests/test-locale-h-c++.cc: Check declaration of freelocale. * doc/posix-functions/freelocale.texi: Mention the new module. --- ChangeLog | 14 ++++++++++ doc/posix-functions/freelocale.texi | 13 ++++----- lib/freelocale.c | 42 +++++++++++++++++++++++++++++ lib/locale.in.h | 9 ++++--- m4/freelocale.m4 | 22 +++++++++++++++ m4/locale_h.m4 | 3 ++- modules/freelocale | 31 +++++++++++++++++++++ modules/locale-h | 1 + tests/test-locale-h-c++.cc | 2 +- 9 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 lib/freelocale.c create mode 100644 m4/freelocale.m4 create mode 100644 modules/freelocale diff --git a/ChangeLog b/ChangeLog index 1a73e832db..a0e3059066 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2025-02-14 Bruno Haible <br...@clisp.org> + + freelocale: New module. + * lib/locale.in.h (freelocale): Consider GNULIB_FREELOCALE. Declare if + not declared. + * lib/freelocale.c: New file. + * m4/freelocale.m4: New file. + * m4/locale_h.m4 (gl_LOCALE_H_REQUIRE_DEFAULTS): Initialize + GNULIB_FREELOCALE. + * modules/locale-h (Makefile.am): Substitute GNULIB_FREELOCALE. + * modules/freelocale: New file. + * tests/test-locale-h-c++.cc: Check declaration of freelocale. + * doc/posix-functions/freelocale.texi: Mention the new module. + 2025-02-14 Bruno Haible <br...@clisp.org> newlocale: Add tests. diff --git a/doc/posix-functions/freelocale.texi b/doc/posix-functions/freelocale.texi index 05ddfa05d6..1167f002fb 100644 --- a/doc/posix-functions/freelocale.texi +++ b/doc/posix-functions/freelocale.texi @@ -4,21 +4,22 @@ POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9799919799/functions/freelocale.html} -Gnulib module: --- +Gnulib module: freelocale +@mindex freelocale Portability problems fixed by Gnulib: @itemize -@end itemize - -Portability problems not fixed by Gnulib: -@itemize @item This function is missing on many platforms: -FreeBSD 9.0, NetBSD 5.0, OpenBSD 6.1, Minix 3.1.8, AIX 6.1, HP-UX 11, Solaris 11.3, Cygwin 2.5.x, mingw, MSVC 14, Android 4.4. +FreeBSD 9.0, NetBSD 6.1, OpenBSD 6.1, Minix 3.1.8, AIX 6.1, HP-UX 11, Solaris 11.3, Cygwin 2.5.x, mingw, MSVC 14, Android 4.4. @item This function is useless because the @code{locale_t} type is not defined on some platforms: z/OS. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize @item This function may cause crashes in subsequent @code{newlocale} invocations on some platforms: diff --git a/lib/freelocale.c b/lib/freelocale.c new file mode 100644 index 0000000000..9dd7cba02c --- /dev/null +++ b/lib/freelocale.c @@ -0,0 +1,42 @@ +/* Free a locale object. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file 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. + + This file 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <br...@clisp.org>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include <locale.h> + +#include <stdlib.h> + +void +freelocale (locale_t locale) +{ + int i; + for (i = 6; --i >= 0; ) + { +#if HAVE_WINDOWS_LOCALE_T + if (!(i == gl_log2_lcmask_to_index (gl_log2_lc_mask (LC_MESSAGES)) + || locale->category[i].is_c_locale)) + /* Documentation: + <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/free-locale> */ + _free_locale (locale->category[i].system_locale); +#endif + free (locale->category[i].name); + } + free (locale); +} diff --git a/lib/locale.in.h b/lib/locale.in.h index 7fa426859f..31d3e9b60b 100644 --- a/lib/locale.in.h +++ b/lib/locale.in.h @@ -361,7 +361,7 @@ _GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - " # endif #endif -#if /*@GNULIB_FREELOCALE@ ||*/ (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@) +#if @GNULIB_FREELOCALE@ || (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@) # if @REPLACE_FREELOCALE@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef freelocale @@ -371,13 +371,14 @@ _GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - " _GL_FUNCDECL_RPL (freelocale, void, (locale_t locale), _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (freelocale, void, (locale_t locale)); # else -# if @HAVE_FREELOCALE@ +# if !@HAVE_FREELOCALE@ +_GL_FUNCDECL_SYS (duplocale, locale_t, (locale_t locale), _GL_ARG_NONNULL ((1))); +# endif /* Need to cast, because on FreeBSD and Mac OS X 10.13, the return type is int. */ _GL_CXXALIAS_SYS_CAST (freelocale, void, (locale_t locale)); -# endif # endif -# if __GLIBC__ >= 2 && @HAVE_FREELOCALE@ +# if __GLIBC__ >= 2 _GL_CXXALIASWARN (freelocale); # endif #elif defined GNULIB_POSIXCHECK diff --git a/m4/freelocale.m4 b/m4/freelocale.m4 new file mode 100644 index 0000000000..61fc0a93bd --- /dev/null +++ b/m4/freelocale.m4 @@ -0,0 +1,22 @@ +# freelocale.m4 +# serial 1 +dnl Copyright (C) 2025 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl This file is offered as-is, without any warranty. + +AC_DEFUN([gl_FUNC_FREELOCALE], +[ + AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) + gl_CHECK_FUNCS_ANDROID([freelocale], [[#include <locale.h>]]) + if test $ac_cv_func_freelocale = no; then + HAVE_FREELOCALE=0 + fi +]) + +# Prerequisites of lib/freelocale.c. +AC_DEFUN([gl_PREREQ_FREELOCALE], +[ + : +]) diff --git a/m4/locale_h.m4 b/m4/locale_h.m4 index 0635a4c3bb..1e3cc11bf2 100644 --- a/m4/locale_h.m4 +++ b/m4/locale_h.m4 @@ -1,5 +1,5 @@ # locale_h.m4 -# serial 33 +# serial 34 dnl Copyright (C) 2007, 2009-2025 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -178,6 +178,7 @@ AC_DEFUN([gl_LOCALE_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NEWLOCALE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREELOCALE]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME_UNSAFE]) ]) m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS]) diff --git a/modules/freelocale b/modules/freelocale new file mode 100644 index 0000000000..fe1faaae59 --- /dev/null +++ b/modules/freelocale @@ -0,0 +1,31 @@ +Description: +freelocale() function: free a locale object. + +Files: +lib/freelocale.c +m4/freelocale.m4 + +Depends-on: +locale-h + +configure.ac: +gl_FUNC_FREELOCALE +gl_CONDITIONAL([GL_COND_OBJ_FREELOCALE], [test $HAVE_LOCALE_T = 0]) +AM_COND_IF([GL_COND_OBJ_FREELOCALE], [ + gl_PREREQ_FREELOCALE +]) +gl_LOCALE_MODULE_INDICATOR([freelocale]) + +Makefile.am: +if GL_COND_OBJ_FREELOCALE +lib_SOURCES += freelocale.c +endif + +Include: +<locale.h> + +License: +LGPLv2+ + +Maintainer: +all diff --git a/modules/locale-h b/modules/locale-h index a5317cf9c9..52f456ea86 100644 --- a/modules/locale-h +++ b/modules/locale-h @@ -40,6 +40,7 @@ locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GNULIB_SETLOCALE_NULL)/g' \ -e 's/@''GNULIB_NEWLOCALE''@/$(GNULIB_NEWLOCALE)/g' \ -e 's/@''GNULIB_DUPLOCALE''@/$(GNULIB_DUPLOCALE)/g' \ + -e 's/@''GNULIB_FREELOCALE''@/$(GNULIB_FREELOCALE)/g' \ -e 's/@''GNULIB_LOCALENAME_UNSAFE''@/$(GNULIB_LOCALENAME_UNSAFE)/g' \ -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \ -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \ diff --git a/tests/test-locale-h-c++.cc b/tests/test-locale-h-c++.cc index ad66ae4871..f2bcfaa71d 100644 --- a/tests/test-locale-h-c++.cc +++ b/tests/test-locale-h-c++.cc @@ -40,7 +40,7 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::newlocale, locale_t, (int, const char *, loca SIGNATURE_CHECK (GNULIB_NAMESPACE::duplocale, locale_t, (locale_t)); #endif -#if 0 +#if GNULIB_TEST_FREELOCALE SIGNATURE_CHECK (GNULIB_NAMESPACE::freelocale, void, (locale_t)); #endif -- 2.43.0
>From 1a50c9110370f66e757954f7cc3a9ad9e589d908 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Fri, 14 Feb 2025 03:06:56 +0100 Subject: [PATCH 2/2] freelocale: Add tests. * tests/test-freelocale.c: New file. * modules/freelocale-tests: New file. --- ChangeLog | 4 ++ modules/freelocale-tests | 13 +++++ tests/test-freelocale.c | 101 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 modules/freelocale-tests create mode 100644 tests/test-freelocale.c diff --git a/ChangeLog b/ChangeLog index a0e3059066..79089e4470 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2025-02-14 Bruno Haible <br...@clisp.org> + freelocale: Add tests. + * tests/test-freelocale.c: New file. + * modules/freelocale-tests: New file. + freelocale: New module. * lib/locale.in.h (freelocale): Consider GNULIB_FREELOCALE. Declare if not declared. diff --git a/modules/freelocale-tests b/modules/freelocale-tests new file mode 100644 index 0000000000..9c4c322e38 --- /dev/null +++ b/modules/freelocale-tests @@ -0,0 +1,13 @@ +Files: +tests/test-freelocale.c +tests/signature.h +tests/macros.h + +Depends-on: +newlocale + +configure.ac: + +Makefile.am: +TESTS += test-freelocale +check_PROGRAMS += test-freelocale diff --git a/tests/test-freelocale.c b/tests/test-freelocale.c new file mode 100644 index 0000000000..65c70b1ea1 --- /dev/null +++ b/tests/test-freelocale.c @@ -0,0 +1,101 @@ +/* Test of freeing a locale object. + Copyright (C) 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 <br...@clisp.org>, 2025. */ + +#include <config.h> + +#include <locale.h> + +#include "signature.h" +SIGNATURE_CHECK (freelocale, void, (locale_t)); + +#include "macros.h" + +#if defined _WIN32 && !defined __CYGWIN__ + +# define ENGLISH "English_United States" +# define FRENCH "French_France" +# define ENCODING ".1252" + +# define LOCALE1 ENGLISH ENCODING +# define LOCALE2 FRENCH ENCODING + +#else + +# define LOCALE1 "en_US.UTF-8" +# define LOCALE2 "fr_FR.UTF-8" + +#endif + +int +main () +{ + { + locale_t l1 = newlocale (LC_CTYPE_MASK, "C", NULL); + ASSERT (l1 != NULL); + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_MESSAGES_MASK, "C", NULL); + ASSERT (l1 != NULL); + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_ALL_MASK, "C", NULL); + ASSERT (l1 != NULL); + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_CTYPE_MASK, LOCALE1, NULL); + if (l1 != NULL) + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_MESSAGES_MASK, LOCALE1, NULL); + if (l1 != NULL) + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_ALL_MASK, LOCALE1, NULL); + if (l1 != NULL) + freelocale (l1); + } + { + locale_t l1 = newlocale (LC_ALL_MASK, LOCALE1, NULL); + if (l1 != NULL) + { + locale_t l2 = newlocale (LC_TIME_MASK, LOCALE2, l1); + if (l2 != NULL) + freelocale (l2); + else + freelocale (l1); + } + } + { + locale_t l1 = newlocale (LC_MESSAGES_MASK, LOCALE1, NULL); + if (l1 != NULL) + { + locale_t l2 = newlocale (LC_TIME_MASK, LOCALE2, l1); + if (l2 != NULL) + freelocale (l2); + else + freelocale (l1); + } + } + + return test_exit_status; +} -- 2.43.0