Commit e144ded4 authored by Bruno Haible's avatar Bruno Haible
Browse files

setlocale-null: Handle NULL result from setlocale.

* lib/locale.in.h (setlocale_null): Document EINVAL return value.
* lib/setlocale_null.c (setlocale_null_unlocked): Handle NULL result
from setlocale or _wsetlocale.
parent 2d1b7501
2019-12-18 Bruno Haible <bruno@clisp.org>
setlocale-null: Handle NULL result from setlocale.
* lib/locale.in.h (setlocale_null): Document EINVAL return value.
* lib/setlocale_null.c (setlocale_null_unlocked): Handle NULL result
from setlocale or _wsetlocale.
2019-12-18 Bruno Haible <bruno@clisp.org>
hard-locale: Make multithread-safe.
* lib/hard-locale.h (hard_locale): Move documentation to here.
* lib/hard-locale.c: Don't include <stdlib.h>.
(GLIBC_VERSION): Remove macro.
(hard_locale): Assume that all systems name the "C" and "POSIX" locales
"C" or "POSIX". Invoke setlocale_null instead of setlocale.
* modules/hard-locale (Depends-on): Remove strdup. Add setlocale-null.
2019-12-18 Bruno Haible <bruno@clisp.org>
 
hard-locale: Add test.
......@@ -228,10 +228,10 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
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, 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.
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.
For this call to be multithread-safe, *all* calls to
setlocale (CATEGORY, NULL) in all other threads must have been converted
to use setlocale_null as well, and the other threads must not make other
......
......@@ -63,52 +63,103 @@ setlocale_null_unlocked (int category, char *buf, size_t bufsize)
on _wsetlocale() and uses malloc() for the result. We are better off
using _wsetlocale() directly. */
const wchar_t *result = _wsetlocale (category, NULL);
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;
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
{
if (bufsize > 0)
size_t length = wcslen (result);
if (length < bufsize)
{
/* 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++)
for (i = 0; i <= length; i++)
buf[i] = result[i];
buf[bufsize - 1] = '\0';
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;
}
return ERANGE;
}
#else
const char *result = setlocale (category, NULL);
size_t length = strlen (result);
if (length < bufsize)
# 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
if (result == NULL)
{
memcpy (buf, result, length + 1);
return 0;
/* 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
{
if (bufsize > 0)
size_t length = strlen (result);
if (length < bufsize)
{
memcpy (buf, result, length + 1);
return 0;
}
else
{
/* 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';
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;
}
return ERANGE;
}
#endif
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment