From 2edefe4fef4034fa409041a568fa92539b4af04f Mon Sep 17 00:00:00 2001 From: Bruno Haible 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 . (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 + + 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 . + (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 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 . */ + +/* Written by Bruno Haible , 2019. */ + +#include + +/* Specification. */ +#include "setlocale_null.h" + +#include +#include +#include +#if defined _WIN32 && !defined __CYGWIN__ +# include +#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 #include #include -#if defined _WIN32 && !defined __CYGWIN__ -# include -#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