+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.
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
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
}