From: Bruno Haible Date: Wed, 18 Dec 2019 09:49:44 +0000 (+0100) Subject: setlocale-null: Handle NULL result from setlocale. X-Git-Tag: v1.0~4483 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=e144ded4615b8d7a77bd4f5a3f8bc309f46a78a5;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 2fffaf2a29..d0d4d11865 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2019-12-18 Bruno Haible + + 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 + + hard-locale: Make multithread-safe. + * lib/hard-locale.h (hard_locale): Move documentation to here. + * lib/hard-locale.c: Don't include . + (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 hard-locale: Add test. diff --git a/lib/locale.in.h b/lib/locale.in.h index 598668308b..67e6020fab 100644 --- a/lib/locale.in.h +++ b/lib/locale.in.h @@ -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 diff --git a/lib/setlocale_null.c b/lib/setlocale_null.c index 350eca7299..8072a4560e 100644 --- a/lib/setlocale_null.c +++ b/lib/setlocale_null.c @@ -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 }