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

Reply via email to