These patches add a module 'setlocale_null-unlocked', that allows code
to do the equivalent of setlocale(_,NULL) — with platform-specific
workarounds — when we know that it does not need locking.


2024-02-15  Bruno Haible  <br...@clisp.org>

        setlocale_null-unlocked: Add tests.
        * tests/test-setlocale_null-unlocked.c: New file, based on
        tests/test-setlocale_null.c.
        * modules/setlocale-null-unlocked-tests: New file.

        setlocale_null-unlocked: New module.
        * lib/setlocale_null.h (setlocale_null_r_unlocked,
        setlocale_null_unlocked): New declarations.
        * lib/setlocale_null-unlocked.c: New file, based on
        lib/setlocale_null.c.
        * lib/setlocale_null.c: Don't include <wchar.h>.
        (setlocale_null_unlocked, setlocale_null_r_unlocked): Remove functions.
        * modules/setlocale-null-unlocked: New file.
        * modules/setlocale-null (Depends-on): Add setlocale-null-unlocked.

2024-02-15  Bruno Haible  <br...@clisp.org>

        setlocale-null: Refactor.
        * lib/setlocale_null.c
        (setlocale_null_r_with_lock): Renamed from setlocale_null_with_lock.
        (setlocale_null_r_unlocked): Renamed from setlocale_null_unlocked.
        (setlocale_null_unlocked): Renamed from setlocale_null_androidfix.

>From c75f99155342338ae9de19b164fd3e255bf96da4 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 15 Feb 2024 09:47:08 +0100
Subject: [PATCH 1/7] setlocale-null: Refactor.

* lib/setlocale_null.c
(setlocale_null_r_with_lock): Renamed from setlocale_null_with_lock.
(setlocale_null_r_unlocked): Renamed from setlocale_null_unlocked.
(setlocale_null_unlocked): Renamed from setlocale_null_androidfix.
---
 ChangeLog            |  8 ++++++++
 lib/setlocale_null.c | 42 +++++++++++++++++++++---------------------
 2 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 05732c7e9d..4ba5cbfc28 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2024-02-15  Bruno Haible  <br...@clisp.org>
+
+	setlocale-null: Refactor.
+	* lib/setlocale_null.c
+	(setlocale_null_r_with_lock): Renamed from setlocale_null_with_lock.
+	(setlocale_null_r_unlocked): Renamed from setlocale_null_unlocked.
+	(setlocale_null_unlocked): Renamed from setlocale_null_androidfix.
+
 2024-02-15  Bruno Haible  <br...@clisp.org>
 
 	localename-unsafe: New module.
diff --git a/lib/setlocale_null.c b/lib/setlocale_null.c
index 697502fbfe..152452e04f 100644
--- a/lib/setlocale_null.c
+++ b/lib/setlocale_null.c
@@ -63,7 +63,7 @@
 #undef setlocale
 
 static const char *
-setlocale_null_androidfix (int category)
+setlocale_null_unlocked (int category)
 {
   const char *result = setlocale (category, NULL);
 
@@ -94,7 +94,7 @@ setlocale_null_androidfix (int category)
 }
 
 static int
-setlocale_null_unlocked (int category, char *buf, size_t bufsize)
+setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
 {
 #if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
   /* On native Windows, nowadays, the setlocale() implementation is based
@@ -143,7 +143,7 @@ setlocale_null_unlocked (int category, char *buf, size_t bufsize)
         }
     }
 #else
-  const char *result = setlocale_null_androidfix (category);
+  const char *result = setlocale_null_unlocked (category);
 
   if (result == NULL)
     {
@@ -181,7 +181,7 @@ setlocale_null_unlocked (int category, char *buf, size_t bufsize)
 
 #if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
 
-/* Use a lock, so that no two threads can invoke setlocale_null_unlocked
+/* Use a lock, so that no two threads can invoke setlocale_null_r_unlocked
    at the same time.  */
 
 /* Prohibit renaming this symbol.  */
@@ -190,20 +190,20 @@ setlocale_null_unlocked (int category, char *buf, size_t bufsize)
 # if AVOID_ANY_THREADS
 
 /* The option '--disable-threads' explicitly requests no locking.  */
-#  define setlocale_null_with_lock setlocale_null_unlocked
+#  define setlocale_null_r_with_lock setlocale_null_r_unlocked
 
 # elif defined _WIN32 && !defined __CYGWIN__
 
 extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
 
 static int
-setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
 {
   CRITICAL_SECTION *lock = gl_get_setlocale_null_lock ();
   int ret;
 
   EnterCriticalSection (lock);
-  ret = setlocale_null_unlocked (category, buf, bufsize);
+  ret = setlocale_null_r_unlocked (category, buf, bufsize);
   LeaveCriticalSection (lock);
 
   return ret;
@@ -234,7 +234,7 @@ extern
 #  endif
 
 static int
-setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
 {
   if (pthread_in_use())
     {
@@ -243,14 +243,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
 
       if (pthread_mutex_lock (lock))
         abort ();
-      ret = setlocale_null_unlocked (category, buf, bufsize);
+      ret = setlocale_null_r_unlocked (category, buf, bufsize);
       if (pthread_mutex_unlock (lock))
         abort ();
 
       return ret;
     }
   else
-    return setlocale_null_unlocked (category, buf, bufsize);
+    return setlocale_null_r_unlocked (category, buf, bufsize);
 }
 
 # elif HAVE_THREADS_H
@@ -258,14 +258,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
 extern mtx_t *gl_get_setlocale_null_lock (void);
 
 static int
-setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
 {
   mtx_t *lock = gl_get_setlocale_null_lock ();
   int ret;
 
   if (mtx_lock (lock) != thrd_success)
     abort ();
-  ret = setlocale_null_unlocked (category, buf, bufsize);
+  ret = setlocale_null_r_unlocked (category, buf, bufsize);
   if (mtx_unlock (lock) != thrd_success)
     abort ();
 
@@ -282,27 +282,27 @@ setlocale_null_r (int category, char *buf, size_t bufsize)
 #if SETLOCALE_NULL_ALL_MTSAFE
 # if SETLOCALE_NULL_ONE_MTSAFE
 
-  return setlocale_null_unlocked (category, buf, bufsize);
+  return setlocale_null_r_unlocked (category, buf, bufsize);
 
 # else
 
   if (category == LC_ALL)
-    return setlocale_null_unlocked (category, buf, bufsize);
+    return setlocale_null_r_unlocked (category, buf, bufsize);
   else
-    return setlocale_null_with_lock (category, buf, bufsize);
+    return setlocale_null_r_with_lock (category, buf, bufsize);
 
 # endif
 #else
 # if SETLOCALE_NULL_ONE_MTSAFE
 
   if (category == LC_ALL)
-    return setlocale_null_with_lock (category, buf, bufsize);
+    return setlocale_null_r_with_lock (category, buf, bufsize);
   else
-    return setlocale_null_unlocked (category, buf, bufsize);
+    return setlocale_null_r_unlocked (category, buf, bufsize);
 
 # else
 
-  return setlocale_null_with_lock (category, buf, bufsize);
+  return setlocale_null_r_with_lock (category, buf, bufsize);
 
 # endif
 #endif
@@ -312,7 +312,7 @@ const char *
 setlocale_null (int category)
 {
 #if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE
-  return setlocale_null_androidfix (category);
+  return setlocale_null_unlocked (category);
 #else
 
   /* This call must be multithread-safe.  To achieve this without using
@@ -328,7 +328,7 @@ setlocale_null (int category)
   if (category == LC_ALL)
     {
 # if SETLOCALE_NULL_ALL_MTSAFE
-      return setlocale_null_androidfix (LC_ALL);
+      return setlocale_null_unlocked (LC_ALL);
 # else
       char buf[SETLOCALE_NULL_ALL_MAX];
       static char resultbuf[SETLOCALE_NULL_ALL_MAX];
@@ -342,7 +342,7 @@ setlocale_null (int category)
   else
     {
 # if SETLOCALE_NULL_ONE_MTSAFE
-      return setlocale_null_androidfix (category);
+      return setlocale_null_unlocked (category);
 # else
       enum
         {
-- 
2.34.1

>From 2edefe4fef4034fa409041a568fa92539b4af04f Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 15 Feb 2024 10:30:54 +0100
Subject: [PATCH 2/7] setlocale_null-unlocked: New module.

* lib/setlocale_null.h (setlocale_null_r_unlocked,
setlocale_null_unlocked): New declarations.
* lib/setlocale_null-unlocked.c: New file, based on
lib/setlocale_null.c.
* lib/setlocale_null.c: Don't include <wchar.h>.
(setlocale_null_unlocked, setlocale_null_r_unlocked): Remove functions.
* modules/setlocale-null-unlocked: New file.
* modules/setlocale-null (Depends-on): Add setlocale-null-unlocked.
---
 ChangeLog                       |  12 +++
 lib/setlocale_null-unlocked.c   | 149 ++++++++++++++++++++++++++++++++
 lib/setlocale_null.c            | 123 --------------------------
 lib/setlocale_null.h            |  28 ++++++
 modules/setlocale-null          |   1 +
 modules/setlocale-null-unlocked |  27 ++++++
 6 files changed, 217 insertions(+), 123 deletions(-)
 create mode 100644 lib/setlocale_null-unlocked.c
 create mode 100644 modules/setlocale-null-unlocked

diff --git a/ChangeLog b/ChangeLog
index 4ba5cbfc28..b2668b99bf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2024-02-15  Bruno Haible  <br...@clisp.org>
+
+	setlocale_null-unlocked: New module.
+	* lib/setlocale_null.h (setlocale_null_r_unlocked,
+	setlocale_null_unlocked): New declarations.
+	* lib/setlocale_null-unlocked.c: New file, based on
+	lib/setlocale_null.c.
+	* lib/setlocale_null.c: Don't include <wchar.h>.
+	(setlocale_null_unlocked, setlocale_null_r_unlocked): Remove functions.
+	* modules/setlocale-null-unlocked: New file.
+	* modules/setlocale-null (Depends-on): Add setlocale-null-unlocked.
+
 2024-02-15  Bruno Haible  <br...@clisp.org>
 
 	setlocale-null: Refactor.
diff --git a/lib/setlocale_null-unlocked.c b/lib/setlocale_null-unlocked.c
new file mode 100644
index 0000000000..0a86f0df78
--- /dev/null
+++ b/lib/setlocale_null-unlocked.c
@@ -0,0 +1,149 @@
+/* Query the name of the current global locale, without locking.
+   Copyright (C) 2019-2024 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>, 2019.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "setlocale_null.h"
+
+#include <errno.h>
+#include <locale.h>
+#include <string.h>
+#if defined _WIN32 && !defined __CYGWIN__
+# include <wchar.h>
+#endif
+
+/* Use the system's setlocale() function, not the gnulib override, here.  */
+#undef setlocale
+
+const char *
+setlocale_null_unlocked (int category)
+{
+  const char *result = setlocale (category, NULL);
+
+#ifdef __ANDROID__
+  if (result == NULL)
+    switch (category)
+      {
+      case LC_CTYPE:
+      case LC_NUMERIC:
+      case LC_TIME:
+      case LC_COLLATE:
+      case LC_MONETARY:
+      case LC_MESSAGES:
+      case LC_ALL:
+      case LC_PAPER:
+      case LC_NAME:
+      case LC_ADDRESS:
+      case LC_TELEPHONE:
+      case LC_MEASUREMENT:
+        result = "C";
+        break;
+      default:
+        break;
+      }
+#endif
+
+  return result;
+}
+
+int
+setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
+{
+#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
+  /* On native Windows, nowadays, the setlocale() implementation is based
+     on _wsetlocale() and uses malloc() for the result.  We are better off
+     using _wsetlocale() directly.  */
+  const wchar_t *result = _wsetlocale (category, NULL);
+
+  if (result == NULL)
+    {
+      /* CATEGORY is invalid.  */
+      if (bufsize > 0)
+        /* Return an empty string in BUF.
+           This is a convenience for callers that don't want to write explicit
+           code for handling EINVAL.  */
+        buf[0] = '\0';
+      return EINVAL;
+    }
+  else
+    {
+      size_t length = wcslen (result);
+      if (length < bufsize)
+        {
+          size_t i;
+
+          /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
+          for (i = 0; i <= length; i++)
+            buf[i] = result[i];
+
+          return 0;
+        }
+      else
+        {
+          if (bufsize > 0)
+            {
+              /* Return a truncated result in BUF.
+                 This is a convenience for callers that don't want to write
+                 explicit code for handling ERANGE.  */
+              size_t i;
+
+              /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
+              for (i = 0; i < bufsize; i++)
+                buf[i] = result[i];
+              buf[bufsize - 1] = '\0';
+            }
+          return ERANGE;
+        }
+    }
+#else
+  const char *result = setlocale_null_unlocked (category);
+
+  if (result == NULL)
+    {
+      /* CATEGORY is invalid.  */
+      if (bufsize > 0)
+        /* Return an empty string in BUF.
+           This is a convenience for callers that don't want to write explicit
+           code for handling EINVAL.  */
+        buf[0] = '\0';
+      return EINVAL;
+    }
+  else
+    {
+      size_t length = strlen (result);
+      if (length < bufsize)
+        {
+          memcpy (buf, result, length + 1);
+          return 0;
+        }
+      else
+        {
+          if (bufsize > 0)
+            {
+              /* Return a truncated result in BUF.
+                 This is a convenience for callers that don't want to write
+                 explicit code for handling ERANGE.  */
+              memcpy (buf, result, bufsize - 1);
+              buf[bufsize - 1] = '\0';
+            }
+          return ERANGE;
+        }
+    }
+#endif
+}
diff --git a/lib/setlocale_null.c b/lib/setlocale_null.c
index 152452e04f..5ecf413de0 100644
--- a/lib/setlocale_null.c
+++ b/lib/setlocale_null.c
@@ -25,9 +25,6 @@
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
-#if defined _WIN32 && !defined __CYGWIN__
-# include <wchar.h>
-#endif
 
 #if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
 
@@ -59,126 +56,6 @@
 
 #endif
 
-/* Use the system's setlocale() function, not the gnulib override, here.  */
-#undef setlocale
-
-static const char *
-setlocale_null_unlocked (int category)
-{
-  const char *result = setlocale (category, NULL);
-
-#ifdef __ANDROID__
-  if (result == NULL)
-    switch (category)
-      {
-      case LC_CTYPE:
-      case LC_NUMERIC:
-      case LC_TIME:
-      case LC_COLLATE:
-      case LC_MONETARY:
-      case LC_MESSAGES:
-      case LC_ALL:
-      case LC_PAPER:
-      case LC_NAME:
-      case LC_ADDRESS:
-      case LC_TELEPHONE:
-      case LC_MEASUREMENT:
-        result = "C";
-        break;
-      default:
-        break;
-      }
-#endif
-
-  return result;
-}
-
-static int
-setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
-{
-#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
-  /* On native Windows, nowadays, the setlocale() implementation is based
-     on _wsetlocale() and uses malloc() for the result.  We are better off
-     using _wsetlocale() directly.  */
-  const wchar_t *result = _wsetlocale (category, NULL);
-
-  if (result == NULL)
-    {
-      /* CATEGORY is invalid.  */
-      if (bufsize > 0)
-        /* Return an empty string in BUF.
-           This is a convenience for callers that don't want to write explicit
-           code for handling EINVAL.  */
-        buf[0] = '\0';
-      return EINVAL;
-    }
-  else
-    {
-      size_t length = wcslen (result);
-      if (length < bufsize)
-        {
-          size_t i;
-
-          /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
-          for (i = 0; i <= length; i++)
-            buf[i] = result[i];
-
-          return 0;
-        }
-      else
-        {
-          if (bufsize > 0)
-            {
-              /* Return a truncated result in BUF.
-                 This is a convenience for callers that don't want to write
-                 explicit code for handling ERANGE.  */
-              size_t i;
-
-              /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
-              for (i = 0; i < bufsize; i++)
-                buf[i] = result[i];
-              buf[bufsize - 1] = '\0';
-            }
-          return ERANGE;
-        }
-    }
-#else
-  const char *result = setlocale_null_unlocked (category);
-
-  if (result == NULL)
-    {
-      /* CATEGORY is invalid.  */
-      if (bufsize > 0)
-        /* Return an empty string in BUF.
-           This is a convenience for callers that don't want to write explicit
-           code for handling EINVAL.  */
-        buf[0] = '\0';
-      return EINVAL;
-    }
-  else
-    {
-      size_t length = strlen (result);
-      if (length < bufsize)
-        {
-          memcpy (buf, result, length + 1);
-          return 0;
-        }
-      else
-        {
-          if (bufsize > 0)
-            {
-              /* Return a truncated result in BUF.
-                 This is a convenience for callers that don't want to write
-                 explicit code for handling ERANGE.  */
-              memcpy (buf, result, bufsize - 1);
-              buf[bufsize - 1] = '\0';
-            }
-          return ERANGE;
-        }
-    }
-#endif
-}
-
 #if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
 
 /* Use a lock, so that no two threads can invoke setlocale_null_r_unlocked
diff --git a/lib/setlocale_null.h b/lib/setlocale_null.h
index defa2b41a6..966c53cfaa 100644
--- a/lib/setlocale_null.h
+++ b/lib/setlocale_null.h
@@ -44,6 +44,34 @@ extern "C" {
    55+5*58.  */
 #define SETLOCALE_NULL_ALL_MAX (148+12*256+1)
 
+/* setlocale_null_r_unlocked (CATEGORY, BUF, BUFSIZE) is like
+   setlocale (CATEGORY, NULL), except that
+     - it returns the resulting locale category name or locale name in the
+       user-supplied buffer BUF, which must be BUFSIZE bytes long.
+   The recommended minimum buffer size is
+     - SETLOCALE_NULL_MAX for CATEGORY != LC_ALL, and
+     - SETLOCALE_NULL_ALL_MAX for CATEGORY == LC_ALL.
+   The return value is an error code: 0 if the call is successful, EINVAL if
+   CATEGORY is invalid, or ERANGE if BUFSIZE is smaller than the length needed
+   size (including the trailing NUL byte).  In the latter case, a truncated
+   result is returned in BUF, but still NUL-terminated if BUFSIZE > 0.
+   This call is guaranteed to be multithread-safe only if
+     - CATEGORY != LC_ALL and SETLOCALE_NULL_ONE_MTSAFE is true, or
+     - CATEGORY == LC_ALL and SETLOCALE_NULL_ALL_MTSAFE is true,
+   and the other threads must not make other setlocale invocations (since
+   changing the global locale has side effects on all threads).  */
+extern int setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
+  _GL_ARG_NONNULL ((2));
+
+/* setlocale_null_unlocked (CATEGORY) is like setlocale (CATEGORY, NULL).
+   The return value is NULL if CATEGORY is invalid.
+   This call is guaranteed to be multithread-safe only if
+     - CATEGORY != LC_ALL and SETLOCALE_NULL_ONE_MTSAFE is true, or
+     - CATEGORY == LC_ALL and SETLOCALE_NULL_ALL_MTSAFE is true,
+   and the other threads must not make other setlocale invocations (since
+   changing the global locale has side effects on all threads).  */
+extern const char *setlocale_null_unlocked (int category);
+
 /* setlocale_null_r (CATEGORY, BUF, BUFSIZE) is like setlocale (CATEGORY, NULL),
    except that
      - it is guaranteed to be multithread-safe,
diff --git a/modules/setlocale-null b/modules/setlocale-null
index 91efd51483..782e29ad8d 100644
--- a/modules/setlocale-null
+++ b/modules/setlocale-null
@@ -13,6 +13,7 @@ m4/visibility.m4
 Depends-on:
 locale
 snippet/arg-nonnull
+setlocale-null-unlocked
 
 configure.ac:
 gl_FUNC_SETLOCALE_NULL
diff --git a/modules/setlocale-null-unlocked b/modules/setlocale-null-unlocked
new file mode 100644
index 0000000000..21d9611501
--- /dev/null
+++ b/modules/setlocale-null-unlocked
@@ -0,0 +1,27 @@
+Description:
+setlocale_null_unlocked() function: query the name of the current global locale,
+without locking.
+
+Files:
+lib/setlocale_null.h
+lib/setlocale_null-unlocked.c
+
+Depends-on:
+locale
+snippet/arg-nonnull
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += setlocale_null-unlocked.c
+
+Include:
+#include "setlocale_null.h"
+
+Link:
+
+License:
+LGPLv2+
+
+Maintainer:
+Bruno Haible
-- 
2.34.1

>From af029caa3537b78d2e62e2674cfc82381bb29e66 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 15 Feb 2024 10:32:57 +0100
Subject: [PATCH 3/7] setlocale_null-unlocked: Add tests.

* tests/test-setlocale_null-unlocked.c: New file, based on
tests/test-setlocale_null.c.
* modules/setlocale-null-unlocked-tests: New file.
---
 ChangeLog                             |  5 ++++
 modules/setlocale-null-unlocked-tests | 10 ++++++++
 tests/test-setlocale_null-unlocked.c  | 35 +++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)
 create mode 100644 modules/setlocale-null-unlocked-tests
 create mode 100644 tests/test-setlocale_null-unlocked.c

diff --git a/ChangeLog b/ChangeLog
index b2668b99bf..761f51bc36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2024-02-15  Bruno Haible  <br...@clisp.org>
 
+	setlocale_null-unlocked: Add tests.
+	* tests/test-setlocale_null-unlocked.c: New file, based on
+	tests/test-setlocale_null.c.
+	* modules/setlocale-null-unlocked-tests: New file.
+
 	setlocale_null-unlocked: New module.
 	* lib/setlocale_null.h (setlocale_null_r_unlocked,
 	setlocale_null_unlocked): New declarations.
diff --git a/modules/setlocale-null-unlocked-tests b/modules/setlocale-null-unlocked-tests
new file mode 100644
index 0000000000..1fbfb895a0
--- /dev/null
+++ b/modules/setlocale-null-unlocked-tests
@@ -0,0 +1,10 @@
+Files:
+tests/test-setlocale_null-unlocked.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-setlocale_null-unlocked
+check_PROGRAMS += test-setlocale_null-unlocked
diff --git a/tests/test-setlocale_null-unlocked.c b/tests/test-setlocale_null-unlocked.c
new file mode 100644
index 0000000000..d06dec6071
--- /dev/null
+++ b/tests/test-setlocale_null-unlocked.c
@@ -0,0 +1,35 @@
+/* Test of setlocale_null_r_unlocked function.
+   Copyright (C) 2019-2024 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>, 2019.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "setlocale_null.h"
+
+#include <locale.h>
+
+/* Check that SETLOCALE_NULL_ALL_MAX is a constant expression.  */
+static char buf[SETLOCALE_NULL_ALL_MAX];
+
+int
+main ()
+{
+  /* Check that setlocale_null_r_unlocked() can be used without any
+     libraries.  */
+  return setlocale_null_r_unlocked (LC_ALL, buf, sizeof (buf)) != 0;
+}
-- 
2.34.1

Reply via email to