rktio: add support for xlocale

Add support for using xlocale's thread-friendly API instead of
setlocale --- but it's not turned on, yet, for any platform.
This commit is contained in:
Matthew Flatt 2020-10-03 17:21:19 -06:00
parent 4525c231a7
commit 4d8851d1be
5 changed files with 92 additions and 16 deletions

View File

@ -1196,15 +1196,19 @@ RKTIO_EXTERN char *rktio_locale_encoding(rktio_t *rktio);
/* Returns the name of the current locale's encoding. */
RKTIO_EXTERN void rktio_set_locale(rktio_t *rktio, rktio_const_string_t name);
/* Sets the current locale, which affects string comparisons and
/* Sets the current locale, which affects rktio string comparisons and
conversions. It can also affect the C library's character-property
predicates and number printing/parsing. The empty string
corresponds to the OS's native locale. */
predicates and number printing/parsing by setting a thread-local or
process-wide locale, but that effect is not guaranteed. The empty
string corresponds to the OS's native locale, and a NULL string
pointer corresponds to the C locale. */
RKTIO_EXTERN_NOERR char *rktio_push_c_numeric_locale(rktio_t *rktio);
RKTIO_EXTERN void rktio_pop_c_numeric_locale(rktio_t *rktio, char *prev);
/* Use this pair of functions to temporarily switch the locale to the C
locale for number parsing and printing. The result of the first
RKTIO_EXTERN_NOERR void *rktio_push_c_numeric_locale(rktio_t *rktio);
RKTIO_EXTERN void rktio_pop_c_numeric_locale(rktio_t *rktio, void *prev);
/* Use this pair of functions to temporarily switch the locale to the
C locale for number parsing and printing. Unlike
rktio_set_locale(), these functions set and restore the
thread-local or even process-wide locale. The result of the first
function is deallocated when passed to second function. */
RKTIO_EXTERN char *rktio_system_language_country(rktio_t *rktio);

View File

@ -1338,14 +1338,14 @@
(((ref rktio_t) rktio) (rktio_const_string_t name)))
(define-function
()
(ref char)
(ref void)
rktio_push_c_numeric_locale
(((ref rktio_t) rktio)))
(define-function
()
void
rktio_pop_c_numeric_locale
(((ref rktio_t) rktio) ((*ref char) prev)))
(((ref rktio_t) rktio) ((ref void) prev)))
(define-function/errno
NULL
()

View File

@ -20,6 +20,21 @@
# include <CoreFoundation/CFLocale.h>
#endif
void rktio_convert_init(rktio_t *rktio) {
#ifdef RKTIO_USE_XLOCALE
rktio->locale = LC_GLOBAL_LOCALE;
#endif
}
void rktio_convert_deinit(rktio_t *rktio) {
#ifdef RKTIO_USE_XLOCALE
if (rktio->locale != LC_GLOBAL_LOCALE) {
freelocale(rktio->locale);
rktio->locale = LC_GLOBAL_LOCALE;
}
#endif
}
/*============================================================*/
/* Using iconv via a DLL */
/*============================================================*/
@ -228,6 +243,15 @@ int rktio_convert_properties(rktio_t *rktio)
void rktio_set_locale(rktio_t *rktio, const char *name)
{
#ifdef RKTIO_USE_XLOCALE
if (rktio->locale != LC_GLOBAL_LOCALE) {
freelocale(rktio->locale);
rktio->locale = LC_GLOBAL_LOCALE;
}
rktio->locale = newlocale(LC_COLLATE_MASK | LC_CTYPE_MASK, name, NULL);
if (rktio->locale == NULL)
rktio->locale = LC_GLOBAL_LOCALE;
#else
/* We only need CTYPE and COLLATE; two calls seem to be much
faster than one call with ALL */
if (name) {
@ -239,22 +263,32 @@ void rktio_set_locale(rktio_t *rktio, const char *name)
setlocale(LC_CTYPE, "C");
setlocale(LC_COLLATE, "C");
}
#endif
}
char *rktio_push_c_numeric_locale(rktio_t *rktio)
void *rktio_push_c_numeric_locale(rktio_t *rktio)
{
#ifdef RKTIO_USE_XLOCALE
return (void *)uselocale(newlocale(LC_NUMERIC, "C", NULL));
#else
char *prev;
prev = setlocale(LC_NUMERIC, NULL);
if (!prev || !strcmp(prev, "C"))
return NULL;
else
return setlocale(LC_NUMERIC, "C");
#endif
}
void rktio_pop_c_numeric_locale(rktio_t *rktio, char *prev)
void rktio_pop_c_numeric_locale(rktio_t *rktio, void *prev)
{
#ifdef RKTIO_USE_XLOCALE
locale_t tmp = uselocale((locale_t)prev);
freelocale(tmp);
#else
if (prev)
setlocale(LC_NUMERIC, prev);
#endif
}
/*============================================================*/
@ -263,7 +297,7 @@ void rktio_pop_c_numeric_locale(rktio_t *rktio, char *prev)
#ifdef RKTIO_SYSTEM_WINDOWS
static char *nl_langinfo_dup()
static char *nl_langinfo_dup(rktio_t *rktio)
{
int i;
char *current_locale_name;
@ -318,11 +352,15 @@ static char *nl_langinfo_dup()
#else
static char *nl_langinfo_dup()
static char *nl_langinfo_dup(rktio_t *rktio)
{
char *s;
# if HAVE_CODESET
# ifdef RKTIO_USE_XLOCALE
s = nl_langinfo_l(CODESET, rktio->locale);
# else
s = nl_langinfo(CODESET);
# endif
# else
/* nl_langinfo doesn't work, so just make up something */
s = "UTF-8";
@ -335,7 +373,7 @@ static char *nl_langinfo_dup()
char *rktio_locale_encoding(rktio_t *rktio)
{
return nl_langinfo_dup();
return nl_langinfo_dup(rktio);
}
/*============================================================*/
@ -539,7 +577,11 @@ char *rktio_locale_recase(rktio_t *rktio,
/* Re-case chars in "out" */
for (i = 0; i < iilen; i++) {
char t;
#ifdef RKTIO_USE_XLOCALE
t = (to_up) ? toupper_l(out[i], rktio->locale) : tolower_l(out[i], rktio->locale);
#else
t = (to_up) ? toupper(out[i]) : tolower(out[i]);
#endif
out[i] = t;
}
@ -553,9 +595,14 @@ char *rktio_locale_recase(rktio_t *rktio,
wchar_t *wc, *ws, wcbuf[RKTIO_WC_BUF_SIZE], cwc;
const char *s;
unsigned int j;
# ifdef RKTIO_USE_XLOCALE
# define mz_mbsnrtowcs(t, f, fl, tl, s) mbsrtowcs_l(t, f, tl, s, rktio->locale)
# define mz_wcsnrtombs(t, f, fl, tl, s) wcsrtombs_l(t, f, tl, s, rktio->locale)
# else
/* The "n" versions are apparently not too standard: */
# define mz_mbsnrtowcs(t, f, fl, tl, s) mbsrtowcs(t, f, tl, s)
# define mz_wcsnrtombs(t, f, fl, tl, s) wcsrtombs(t, f, tl, s)
# define mz_mbsnrtowcs(t, f, fl, tl, s) mbsrtowcs(t, f, tl, s)
# define mz_wcsnrtombs(t, f, fl, tl, s) wcsrtombs(t, f, tl, s)
# endif
/* ----- to wide char ---- */
@ -584,12 +631,20 @@ char *rktio_locale_recase(rktio_t *rktio,
if (to_up) {
for (j = 0; j < wl; j++) {
# ifdef RKTIO_USE_XLOCALE
cwc = towupper_l(wc[j], rktio->locale);
# else
cwc = towupper(wc[j]);
#endif
wc[j] = cwc;
}
} else {
for (j = 0; j < wl; j++) {
# ifdef RKTIO_USE_XLOCALE
cwc = towlower_l(wc[j], rktio->locale);
# else
cwc = towlower(wc[j]);
# endif
wc[j] = cwc;
}
}
@ -678,7 +733,11 @@ rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, rktio_bool_t to_up, rktio_cha
int rktio_locale_strcoll(rktio_t *rktio, const char *s1, const char *s2)
{
#ifdef RKTIO_USE_XLOCALE
return strcoll_l(s1, s2, rktio->locale);
#else
return strcoll(s1, s2);
#endif
}
int rktio_strcoll_utf16(rktio_t *rktio,

View File

@ -38,6 +38,8 @@ rktio_t *rktio_init(void)
rktio_syslog_init(rktio);
rktio_convert_init(rktio);
#ifdef OS_X
{
int a[2], i, k = 0;
@ -66,6 +68,7 @@ void rktio_destroy(rktio_t *rktio)
{
rktio_stop_background(rktio);
rktio_syslog_clean(rktio);
rktio_convert_deinit(rktio);
rktio_dll_clean(rktio);
rktio_error_clean(rktio);
rktio_process_deinit(rktio);

View File

@ -11,6 +11,9 @@
#ifdef RKTIO_USE_PTHREADS
# include <pthread.h>
#endif
#ifdef RKTIO_USE_XLOCALE
# include <xlocale.h>
#endif
#if defined(RKTIO_SYSTEM_UNIX) && !defined(RKTIO_STATIC_FDSET_SIZE)
# define USE_DYNAMIC_FDSET_SIZE
@ -132,6 +135,10 @@ struct rktio_t {
#ifdef OS_X
int macos_kernel_version; /* e.g., 10 => 10.6, 15 => 10.11 */
#endif
#ifdef RKTIO_USE_XLOCALE
locale_t locale;
#endif
};
/*========================================================================*/
@ -276,6 +283,9 @@ typedef char WIDE_PATH_t;
#endif
void rktio_convert_init(rktio_t *rktio);
void rktio_convert_deinit(rktio_t *rktio);
/*========================================================================*/
/* Hash table */
/*========================================================================*/