summaryrefslogtreecommitdiffstats
path: root/gl/setlocale_null.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/setlocale_null.c')
-rw-r--r--gl/setlocale_null.c176
1 files changed, 32 insertions, 144 deletions
diff --git a/gl/setlocale_null.c b/gl/setlocale_null.c
index 6ac563d..5ecf413 100644
--- a/gl/setlocale_null.c
+++ b/gl/setlocale_null.c
@@ -1,5 +1,5 @@
1/* Query the name of the current global locale. 1/* Query the name of the current global locale.
2 Copyright (C) 2019-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 3
4 This file is free software: you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as 5 it under the terms of the GNU Lesser General Public License as
@@ -25,12 +25,14 @@
25#include <locale.h> 25#include <locale.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28#if defined _WIN32 && !defined __CYGWIN__
29# include <wchar.h>
30#endif
31 28
32#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) 29#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
33# if defined _WIN32 && !defined __CYGWIN__ 30
31# if AVOID_ANY_THREADS
32
33/* The option '--disable-threads' explicitly requests no locking. */
34
35# elif defined _WIN32 && !defined __CYGWIN__
34 36
35# define WIN32_LEAN_AND_MEAN /* avoid including junk */ 37# define WIN32_LEAN_AND_MEAN /* avoid including junk */
36# include <windows.h> 38# include <windows.h>
@@ -51,154 +53,40 @@
51# include <threads.h> 53# include <threads.h>
52 54
53# endif 55# endif
54#endif
55 56
56/* Use the system's setlocale() function, not the gnulib override, here. */
57#undef setlocale
58
59static const char *
60setlocale_null_androidfix (int category)
61{
62 const char *result = setlocale (category, NULL);
63
64#ifdef __ANDROID__
65 if (result == NULL)
66 switch (category)
67 {
68 case LC_CTYPE:
69 case LC_NUMERIC:
70 case LC_TIME:
71 case LC_COLLATE:
72 case LC_MONETARY:
73 case LC_MESSAGES:
74 case LC_ALL:
75 case LC_PAPER:
76 case LC_NAME:
77 case LC_ADDRESS:
78 case LC_TELEPHONE:
79 case LC_MEASUREMENT:
80 result = "C";
81 break;
82 default:
83 break;
84 }
85#endif 57#endif
86 58
87 return result; 59#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
88}
89
90static int
91setlocale_null_unlocked (int category, char *buf, size_t bufsize)
92{
93#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
94 /* On native Windows, nowadays, the setlocale() implementation is based
95 on _wsetlocale() and uses malloc() for the result. We are better off
96 using _wsetlocale() directly. */
97 const wchar_t *result = _wsetlocale (category, NULL);
98
99 if (result == NULL)
100 {
101 /* CATEGORY is invalid. */
102 if (bufsize > 0)
103 /* Return an empty string in BUF.
104 This is a convenience for callers that don't want to write explicit
105 code for handling EINVAL. */
106 buf[0] = '\0';
107 return EINVAL;
108 }
109 else
110 {
111 size_t length = wcslen (result);
112 if (length < bufsize)
113 {
114 size_t i;
115
116 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
117 for (i = 0; i <= length; i++)
118 buf[i] = result[i];
119 60
120 return 0; 61/* Use a lock, so that no two threads can invoke setlocale_null_r_unlocked
121 }
122 else
123 {
124 if (bufsize > 0)
125 {
126 /* Return a truncated result in BUF.
127 This is a convenience for callers that don't want to write
128 explicit code for handling ERANGE. */
129 size_t i;
130
131 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
132 for (i = 0; i < bufsize; i++)
133 buf[i] = result[i];
134 buf[bufsize - 1] = '\0';
135 }
136 return ERANGE;
137 }
138 }
139#else
140 const char *result = setlocale_null_androidfix (category);
141
142 if (result == NULL)
143 {
144 /* CATEGORY is invalid. */
145 if (bufsize > 0)
146 /* Return an empty string in BUF.
147 This is a convenience for callers that don't want to write explicit
148 code for handling EINVAL. */
149 buf[0] = '\0';
150 return EINVAL;
151 }
152 else
153 {
154 size_t length = strlen (result);
155 if (length < bufsize)
156 {
157 memcpy (buf, result, length + 1);
158 return 0;
159 }
160 else
161 {
162 if (bufsize > 0)
163 {
164 /* Return a truncated result in BUF.
165 This is a convenience for callers that don't want to write
166 explicit code for handling ERANGE. */
167 memcpy (buf, result, bufsize - 1);
168 buf[bufsize - 1] = '\0';
169 }
170 return ERANGE;
171 }
172 }
173#endif
174}
175
176#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */
177
178/* Use a lock, so that no two threads can invoke setlocale_null_unlocked
179 at the same time. */ 62 at the same time. */
180 63
181/* Prohibit renaming this symbol. */ 64/* Prohibit renaming this symbol. */
182# undef gl_get_setlocale_null_lock 65# undef gl_get_setlocale_null_lock
183 66
184# if defined _WIN32 && !defined __CYGWIN__ 67# if AVOID_ANY_THREADS
68
69/* The option '--disable-threads' explicitly requests no locking. */
70# define setlocale_null_r_with_lock setlocale_null_r_unlocked
71
72# elif defined _WIN32 && !defined __CYGWIN__
185 73
186extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void); 74extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
187 75
188static int 76static int
189setlocale_null_with_lock (int category, char *buf, size_t bufsize) 77setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
190{ 78{
191 CRITICAL_SECTION *lock = gl_get_setlocale_null_lock (); 79 CRITICAL_SECTION *lock = gl_get_setlocale_null_lock ();
192 int ret; 80 int ret;
193 81
194 EnterCriticalSection (lock); 82 EnterCriticalSection (lock);
195 ret = setlocale_null_unlocked (category, buf, bufsize); 83 ret = setlocale_null_r_unlocked (category, buf, bufsize);
196 LeaveCriticalSection (lock); 84 LeaveCriticalSection (lock);
197 85
198 return ret; 86 return ret;
199} 87}
200 88
201# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */ 89# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
202 90
203extern 91extern
204# if defined _WIN32 || defined __CYGWIN__ 92# if defined _WIN32 || defined __CYGWIN__
@@ -223,7 +111,7 @@ extern
223# endif 111# endif
224 112
225static int 113static int
226setlocale_null_with_lock (int category, char *buf, size_t bufsize) 114setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
227{ 115{
228 if (pthread_in_use()) 116 if (pthread_in_use())
229 { 117 {
@@ -232,14 +120,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
232 120
233 if (pthread_mutex_lock (lock)) 121 if (pthread_mutex_lock (lock))
234 abort (); 122 abort ();
235 ret = setlocale_null_unlocked (category, buf, bufsize); 123 ret = setlocale_null_r_unlocked (category, buf, bufsize);
236 if (pthread_mutex_unlock (lock)) 124 if (pthread_mutex_unlock (lock))
237 abort (); 125 abort ();
238 126
239 return ret; 127 return ret;
240 } 128 }
241 else 129 else
242 return setlocale_null_unlocked (category, buf, bufsize); 130 return setlocale_null_r_unlocked (category, buf, bufsize);
243} 131}
244 132
245# elif HAVE_THREADS_H 133# elif HAVE_THREADS_H
@@ -247,14 +135,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
247extern mtx_t *gl_get_setlocale_null_lock (void); 135extern mtx_t *gl_get_setlocale_null_lock (void);
248 136
249static int 137static int
250setlocale_null_with_lock (int category, char *buf, size_t bufsize) 138setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
251{ 139{
252 mtx_t *lock = gl_get_setlocale_null_lock (); 140 mtx_t *lock = gl_get_setlocale_null_lock ();
253 int ret; 141 int ret;
254 142
255 if (mtx_lock (lock) != thrd_success) 143 if (mtx_lock (lock) != thrd_success)
256 abort (); 144 abort ();
257 ret = setlocale_null_unlocked (category, buf, bufsize); 145 ret = setlocale_null_r_unlocked (category, buf, bufsize);
258 if (mtx_unlock (lock) != thrd_success) 146 if (mtx_unlock (lock) != thrd_success)
259 abort (); 147 abort ();
260 148
@@ -271,27 +159,27 @@ setlocale_null_r (int category, char *buf, size_t bufsize)
271#if SETLOCALE_NULL_ALL_MTSAFE 159#if SETLOCALE_NULL_ALL_MTSAFE
272# if SETLOCALE_NULL_ONE_MTSAFE 160# if SETLOCALE_NULL_ONE_MTSAFE
273 161
274 return setlocale_null_unlocked (category, buf, bufsize); 162 return setlocale_null_r_unlocked (category, buf, bufsize);
275 163
276# else 164# else
277 165
278 if (category == LC_ALL) 166 if (category == LC_ALL)
279 return setlocale_null_unlocked (category, buf, bufsize); 167 return setlocale_null_r_unlocked (category, buf, bufsize);
280 else 168 else
281 return setlocale_null_with_lock (category, buf, bufsize); 169 return setlocale_null_r_with_lock (category, buf, bufsize);
282 170
283# endif 171# endif
284#else 172#else
285# if SETLOCALE_NULL_ONE_MTSAFE 173# if SETLOCALE_NULL_ONE_MTSAFE
286 174
287 if (category == LC_ALL) 175 if (category == LC_ALL)
288 return setlocale_null_with_lock (category, buf, bufsize); 176 return setlocale_null_r_with_lock (category, buf, bufsize);
289 else 177 else
290 return setlocale_null_unlocked (category, buf, bufsize); 178 return setlocale_null_r_unlocked (category, buf, bufsize);
291 179
292# else 180# else
293 181
294 return setlocale_null_with_lock (category, buf, bufsize); 182 return setlocale_null_r_with_lock (category, buf, bufsize);
295 183
296# endif 184# endif
297#endif 185#endif
@@ -301,7 +189,7 @@ const char *
301setlocale_null (int category) 189setlocale_null (int category)
302{ 190{
303#if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE 191#if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE
304 return setlocale_null_androidfix (category); 192 return setlocale_null_unlocked (category);
305#else 193#else
306 194
307 /* This call must be multithread-safe. To achieve this without using 195 /* This call must be multithread-safe. To achieve this without using
@@ -317,7 +205,7 @@ setlocale_null (int category)
317 if (category == LC_ALL) 205 if (category == LC_ALL)
318 { 206 {
319# if SETLOCALE_NULL_ALL_MTSAFE 207# if SETLOCALE_NULL_ALL_MTSAFE
320 return setlocale_null_androidfix (LC_ALL); 208 return setlocale_null_unlocked (LC_ALL);
321# else 209# else
322 char buf[SETLOCALE_NULL_ALL_MAX]; 210 char buf[SETLOCALE_NULL_ALL_MAX];
323 static char resultbuf[SETLOCALE_NULL_ALL_MAX]; 211 static char resultbuf[SETLOCALE_NULL_ALL_MAX];
@@ -331,7 +219,7 @@ setlocale_null (int category)
331 else 219 else
332 { 220 {
333# if SETLOCALE_NULL_ONE_MTSAFE 221# if SETLOCALE_NULL_ONE_MTSAFE
334 return setlocale_null_androidfix (category); 222 return setlocale_null_unlocked (category);
335# else 223# else
336 enum 224 enum
337 { 225 {