summaryrefslogtreecommitdiffstats
path: root/lib/libc/locale
diff options
context:
space:
mode:
authortheraven <theraven@FreeBSD.org>2011-11-20 14:45:42 +0000
committertheraven <theraven@FreeBSD.org>2011-11-20 14:45:42 +0000
commit0f6ef690b3118882121ed67561c7ce2660cfebe1 (patch)
tree909189922493cddbeeac84af2e316dc897661311 /lib/libc/locale
parent18b29f3fb8abee5d57ed8f4a44f806bec7e0eeff (diff)
downloadFreeBSD-src-0f6ef690b3118882121ed67561c7ce2660cfebe1.zip
FreeBSD-src-0f6ef690b3118882121ed67561c7ce2660cfebe1.tar.gz
Implement xlocale APIs from Darwin, mainly for use by libc++. This adds a
load of _l suffixed versions of various standard library functions that use the global locale, making them take an explicit locale parameter. Also adds support for per-thread locales. This work was funded by the FreeBSD Foundation. Please test any code you have that uses the C standard locale functions! Reviewed by: das (gdtoa changes) Approved by: dim (mentor)
Diffstat (limited to 'lib/libc/locale')
-rw-r--r--lib/libc/locale/DESIGN.xlocale159
-rw-r--r--lib/libc/locale/Makefile.inc9
-rw-r--r--lib/libc/locale/Symbol.map95
-rw-r--r--lib/libc/locale/ascii.c23
-rw-r--r--lib/libc/locale/big5.c19
-rw-r--r--lib/libc/locale/btowc.c15
-rw-r--r--lib/libc/locale/collate.c92
-rw-r--r--lib/libc/locale/collate.h28
-rw-r--r--lib/libc/locale/collcmp.c12
-rw-r--r--lib/libc/locale/ctype.c33
-rw-r--r--lib/libc/locale/duplocale.378
-rw-r--r--lib/libc/locale/euc.c19
-rw-r--r--lib/libc/locale/freelocale.361
-rw-r--r--lib/libc/locale/gb18030.c21
-rw-r--r--lib/libc/locale/gb2312.c21
-rw-r--r--lib/libc/locale/gbk.c19
-rw-r--r--lib/libc/locale/lmessages.c65
-rw-r--r--lib/libc/locale/lmessages.h9
-rw-r--r--lib/libc/locale/lmonetary.c73
-rw-r--r--lib/libc/locale/lmonetary.h13
-rw-r--r--lib/libc/locale/lnumeric.c68
-rw-r--r--lib/libc/locale/lnumeric.h13
-rw-r--r--lib/libc/locale/localeconv.315
-rw-r--r--lib/libc/locale/localeconv.c37
-rw-r--r--lib/libc/locale/mblen.c19
-rw-r--r--lib/libc/locale/mblocal.h57
-rw-r--r--lib/libc/locale/mbrlen.c20
-rw-r--r--lib/libc/locale/mbrtowc.c21
-rw-r--r--lib/libc/locale/mbsinit.c14
-rw-r--r--lib/libc/locale/mbsnrtowcs.c25
-rw-r--r--lib/libc/locale/mbsrtowcs.c20
-rw-r--r--lib/libc/locale/mbstowcs.c15
-rw-r--r--lib/libc/locale/mbtowc.c18
-rw-r--r--lib/libc/locale/mskanji.c19
-rw-r--r--lib/libc/locale/newlocale.3109
-rw-r--r--lib/libc/locale/nextwctype.c19
-rw-r--r--lib/libc/locale/nl_langinfo.c72
-rw-r--r--lib/libc/locale/none.c46
-rw-r--r--lib/libc/locale/querylocale.357
-rw-r--r--lib/libc/locale/runetype.c27
-rw-r--r--lib/libc/locale/setlocale.c5
-rw-r--r--lib/libc/locale/setrunelocale.c155
-rw-r--r--lib/libc/locale/table.c18
-rw-r--r--lib/libc/locale/tolower.c19
-rw-r--r--lib/libc/locale/toupper.c21
-rw-r--r--lib/libc/locale/uselocale.359
-rw-r--r--lib/libc/locale/utf8.c23
-rw-r--r--lib/libc/locale/wcrtomb.c21
-rw-r--r--lib/libc/locale/wcsftime.c26
-rw-r--r--lib/libc/locale/wcsnrtombs.c28
-rw-r--r--lib/libc/locale/wcsrtombs.c21
-rw-r--r--lib/libc/locale/wcstod.c37
-rw-r--r--lib/libc/locale/wcstof.c23
-rw-r--r--lib/libc/locale/wcstoimax.c23
-rw-r--r--lib/libc/locale/wcstol.c21
-rw-r--r--lib/libc/locale/wcstold.c36
-rw-r--r--lib/libc/locale/wcstoll.c21
-rw-r--r--lib/libc/locale/wcstombs.c17
-rw-r--r--lib/libc/locale/wcstoul.c21
-rw-r--r--lib/libc/locale/wcstoull.c23
-rw-r--r--lib/libc/locale/wcstoumax.c23
-rw-r--r--lib/libc/locale/wctob.c15
-rw-r--r--lib/libc/locale/wctomb.c18
-rw-r--r--lib/libc/locale/wctrans.c31
-rw-r--r--lib/libc/locale/wctype.c24
-rw-r--r--lib/libc/locale/wcwidth.c13
-rw-r--r--lib/libc/locale/xlocale.3270
-rw-r--r--lib/libc/locale/xlocale.c334
-rw-r--r--lib/libc/locale/xlocale_private.h198
69 files changed, 2646 insertions, 453 deletions
diff --git a/lib/libc/locale/DESIGN.xlocale b/lib/libc/locale/DESIGN.xlocale
new file mode 100644
index 0000000..5d998d3
--- /dev/null
+++ b/lib/libc/locale/DESIGN.xlocale
@@ -0,0 +1,159 @@
+$FreeBSD$
+
+Design of xlocale
+=================
+
+The xlocale APIs come from Darwin, although a subset is now part of POSIX 2008.
+They fall into two broad categories:
+
+- Manipulation of per-thread locales (POSIX)
+- Locale-aware functions taking an explicit locale argument (Darwin)
+
+This document describes the implementation of these APIs for FreeBSD.
+
+Goals
+-----
+
+The overall goal of this implementation is to be compatible with the Darwin
+version. Additionally, it should include minimal changes to the existing
+locale code. A lot of the existing locale code originates with 4BSD or earlier
+and has had over a decade of testing. Replacing this code, unless absolutely
+necessary, gives us the potential for more bugs without much benefit.
+
+With this in mind, various libc-private functions have been modified to take a
+locale_t parameter. This causes a compiler error if they are accidentally
+called without a locale. This approach was taken, rather than adding _l
+variants of these functions, to make it harder for accidental uses of the
+global-locale versions to slip in.
+
+Locale Objects
+--------------
+
+A locale is encapsulated in a `locale_t`, which is an opaque type: a pointer to
+a `struct _xlocale`. The name `_xlocale` is unfortunate, as it does not fit
+well with existing conventions, but is used because this is the name the Darwin
+implementation gives to this structure and so may be used by existing (bad) code.
+
+This structure should include all of the information corresponding to a locale.
+A locale_t is almost immutable after creation. There are no functions that modify it,
+and it can therefore be used without locking. It is the responsibility of the
+caller to ensure that a locale is not deallocated during a call that uses it.
+
+Each locale contains a number of components, one for each of the categories
+supported by `setlocale()`. These are likewise immutable after creation. This
+differs from the Darwin implementation, which includes a deprecated
+`setinvalidrune()` function that can modify the rune locale.
+
+The exception to these mutability rules is a set of `mbstate_t` flags stored
+with each locale. These are used by various functions that previously had a
+static local `mbstate_t` variable.
+
+The components are reference counted, and so can be aliased between locale
+objects. This makes copying locales very cheap.
+
+The Global Locale
+-----------------
+
+All locales and locale components are reference counted. The global locale,
+however, is special. It, and all of its components, are static and so no
+malloc() memory is required when using a single locale.
+
+This means that threads using the global locale are subject to the same
+constraints as with the pre-xlocale libc. Calls to any locale-aware functions
+in threads using the global locale, while modifying the global locale, have
+undefined behaviour.
+
+Because of this, we have to ensure that we always copy the components of the
+global locale, rather than alias them.
+
+It would be cleaner to simply remove the special treatment of the global locale
+and have a locale_t lazily allocated for the global context. This would cost a
+little more `malloc()` memory, so is not done in the initial version.
+
+Caching
+-------
+
+The existing locale implementation included several ad-hoc caching layers.
+None of these were thread safe. Caching is only really of use for supporting
+the pattern where the locale is briefly changed to something and then changed
+back.
+
+The current xlocale implementation removes the caching entirely. This pattern
+is not one that should be encouraged. If you need to make some calls with a
+modified locale, then you should use the _l suffix versions of the calls,
+rather than switch the global locale. If you do need to temporarily switch the
+locale and then switch it back, `uselocale()` provides a way of doing this very
+easily: It returns the old locale, which can then be passed to a subsequent
+call to `uselocale()` to restore it, without the need to load any locale data
+from the disk.
+
+If, in the future, it is determined that caching is beneficial, it can be added
+quite easily in xlocale.c. Given, however, that any locale-aware call is going
+to be a preparation for presenting data to the user, and so is invariably going
+to be part of an I/O operation, this seems like a case of premature
+optimisation.
+
+localeconv
+----------
+
+The `localeconv()` function is an exception to the immutable-after-creation
+rule. In the classic implementation, this function returns a pointer to some
+global storage, which is initialised with the data from the current locale.
+This is not possible in a multithreaded environment, with multiple locales.
+
+Instead, each locale contains a `struct lconv` that is lazily initialised on
+calls to `localeconv()`. This is not protected by any locking, however this is
+still safe on any machine where word-sized stores are atomic: two concurrent
+calls will write the same data into the structure.
+
+Explicit Locale Calls
+---------------------
+
+A large number of functions have been modified to take an explicit `locale_t`
+parameter. The old APIs are then reimplemented with a call to `__get_locale()`
+to supply the `locale_t` parameter. This is in line with the Darwin public
+APIs, but also simplifies the modifications to these functions. The
+`__get_locale()` function is now the only way to access the current locale
+within libc. All of the old globals have gone, so there is now a linker error
+if any functions attempt to use them.
+
+The ctype.h functions are a little different. These are not implemented in
+terms of their locale-aware versions, for performance reasons. Each of these
+is implemented as a short inline function.
+
+Differences to Darwin APIs
+--------------------------
+
+`strtoq_l()` and `strtouq_l() `are not provided. These are extensions to
+deprecated functions - we should not be encouraging people to use deprecated
+interfaces.
+
+Locale Placeholders
+-------------------
+
+The pointer values 0 and -1 have special meanings as `locale_t` values. Any
+public function that accepts a `locale_t` parameter must use the `FIX_LOCALE()`
+macro on it before using it. For efficiency, this can be emitted in functions
+which *only* use their locale parameter as an argument to another public
+function, as the callee will do the `FIX_LOCALE()` itself.
+
+Potential Improvements
+----------------------
+
+Currently, the current rune set is accessed via a function call. This makes it
+fairly expensive to use any of the ctype.h functions. We could improve this
+quite a lot by storing the rune locale data in a __thread-qualified variable.
+
+Several of the existing FreeBSD locale-aware functions appear to be wrong. For
+example, most of the `strto*()` family should probably use `digittoint_l()`,
+but instead they assume ASCII. These will break if using a character encoding
+that does not put numbers and the letters A-F in the same location as ASCII.
+Some functions, like `strcoll()` only work on single-byte encodings. No
+attempt has been made to fix existing limitations in the libc functions other
+than to add support for xlocale.
+
+Intuitively, setting a thread-local locale should ensure that all locale-aware
+functions can be used safely from that thread. In fact, this is not the case
+in either this implementation or the Darwin one. You must call `duplocale()`
+or `newlocale()` before calling `uselocale()`. This is a bit ugly, and it
+would be better if libc ensure that every thread had its own locale object.
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
index 8fff0589..55800d0 100644
--- a/lib/libc/locale/Makefile.inc
+++ b/lib/libc/locale/Makefile.inc
@@ -5,7 +5,7 @@
.PATH: ${.CURDIR}/${LIBC_ARCH}/locale ${.CURDIR}/locale
SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
- gb18030.c gb2312.c gbk.c isctype.c iswctype.c \
+ gb18030.c gb2312.c gbk.c ctype.c isctype.c iswctype.c \
ldpart.c lmessages.c lmonetary.c lnumeric.c localeconv.c mblen.c \
mbrlen.c \
mbrtowc.c mbsinit.c mbsnrtowcs.c \
@@ -20,7 +20,8 @@ SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
wcstoimax.c wcstol.c wcstold.c wcstoll.c \
wcstombs.c \
wcstoul.c wcstoull.c wcstoumax.c wctob.c wctomb.c wctrans.c wctype.c \
- wcwidth.c
+ wcwidth.c\
+ xlocale.c
SYM_MAPS+=${.CURDIR}/locale/Symbol.map
@@ -37,7 +38,9 @@ MAN+= btowc.3 \
wcsftime.3 \
wcrtomb.3 \
wcsrtombs.3 wcstod.3 wcstol.3 wcstombs.3 wctomb.3 \
- wctrans.3 wctype.3 wcwidth.3
+ wctrans.3 wctype.3 wcwidth.3 \
+ duplocale.3 freelocale.3 newlocale.3 querylocale.3 uselocale.3 xlocale.3
+
MAN+= big5.5 euc.5 gb18030.5 gb2312.5 gbk.5 mskanji.5 utf8.5
MLINKS+=btowc.3 wctob.3
diff --git a/lib/libc/locale/Symbol.map b/lib/libc/locale/Symbol.map
index 20d092b..01242b6 100644
--- a/lib/libc/locale/Symbol.map
+++ b/lib/libc/locale/Symbol.map
@@ -101,6 +101,101 @@ FBSD_1.0 {
wcwidth;
};
+FBSD_1.3 {
+ newlocale;
+ duplocale;
+ freelocale;
+ querylocale;
+ uselocale;
+ __getCurrentRuneLocale;
+ btowc_l;
+ localeconv_l;
+ mblen_l;
+ mbrlen_l;
+ mbrtowc_l;
+ mbsinit_l;
+ mbsnrtowcs_l;
+ mbsrtowcs_l;
+ mbstowcs_l;
+ mbtowc_l;
+ nl_langinfo_l;
+ strcoll_l;
+ strfmon_l;
+ strftime_l;
+ strptime_l;
+ strxfrm_l;
+ wcrtomb_l;
+ wcscoll_l;
+ wcsnrtombs_l;
+ wcsrtombs_l;
+ wcstombs_l;
+ wcsxfrm_l;
+ wctob_l;
+ wctomb_l;
+ ___tolower_l;
+ ___toupper_l;
+ ___runetype_l;
+ digittoint_l;
+ isalnum_l;
+ isalpha_l;
+ isblank_l;
+ iscntrl_l;
+ isdigit_l;
+ isgraph_l;
+ ishexnumber_l;
+ isideogram_l;
+ islower_l;
+ isnumber_l;
+ isphonogram_l;
+ isprint_l;
+ ispunct_l;
+ isrune_l;
+ isspace_l;
+ isspecial_l;
+ isupper_l;
+ isxdigit_l;
+ tolower_l;
+ toupper_l;
+ iswalnum_l;
+ iswalpha_l;
+ iswblank_l;
+ iswcntrl_l;
+ iswdigit_l;
+ iswgraph_l;
+ iswhexnumber_l;
+ iswideogram_l;
+ iswlower_l;
+ iswnumber_l;
+ iswphonogram_l;
+ iswprint_l;
+ iswpunct_l;
+ iswrune_l;
+ iswspace_l;
+ iswspecial_l;
+ iswupper_l;
+ iswxdigit_l;
+ towlower_l;
+ towupper_l;
+ iswctype_l;
+ wctype_l;
+ nextwctype_l;
+ ___mb_cur_max;
+ ___mb_cur_max_l;
+ towctrans_l;
+ wctrans_l;
+ wcsftime_l;
+ wcstod_l;
+ wcstof_l;
+ wcstoimax_l;
+ wcstol_l;
+ wcstold_l;
+ wcstoll_l;
+ wcstoul_l;
+ wcstoull_l;
+ wcstoumax_l;
+ __runes_for_locale;
+};
+
FBSDprivate_1.0 {
_PathLocale;
__detect_path_locale;
diff --git a/lib/libc/locale/ascii.c b/lib/libc/locale/ascii.c
index 493bf42..784814d 100644
--- a/lib/libc/locale/ascii.c
+++ b/lib/libc/locale/ascii.c
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -56,17 +61,17 @@ static size_t _ascii_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
size_t, size_t, mbstate_t * __restrict);
int
-_ascii_init(_RuneLocale *rl)
+_ascii_init(struct xlocale_ctype *l,_RuneLocale *rl)
{
- __mbrtowc = _ascii_mbrtowc;
- __mbsinit = _ascii_mbsinit;
- __mbsnrtowcs = _ascii_mbsnrtowcs;
- __wcrtomb = _ascii_wcrtomb;
- __wcsnrtombs = _ascii_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 1;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _ascii_mbrtowc;
+ l->__mbsinit = _ascii_mbsinit;
+ l->__mbsnrtowcs = _ascii_mbsnrtowcs;
+ l->__wcrtomb = _ascii_wcrtomb;
+ l->__wcsnrtombs = _ascii_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 128;
return(0);
}
diff --git a/lib/libc/locale/big5.c b/lib/libc/locale/big5.c
index 19977d0..4b37265 100644
--- a/lib/libc/locale/big5.c
+++ b/lib/libc/locale/big5.c
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -62,15 +67,15 @@ typedef struct {
} _BIG5State;
int
-_BIG5_init(_RuneLocale *rl)
+_BIG5_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _BIG5_mbrtowc;
- __wcrtomb = _BIG5_wcrtomb;
- __mbsinit = _BIG5_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _BIG5_mbrtowc;
+ l->__wcrtomb = _BIG5_wcrtomb;
+ l->__mbsinit = _BIG5_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
diff --git a/lib/libc/locale/btowc.c b/lib/libc/locale/btowc.c
index 2c4d493..72507bc 100644
--- a/lib/libc/locale/btowc.c
+++ b/lib/libc/locale/btowc.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,12 +37,13 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
wint_t
-btowc(int c)
+btowc_l(int c, locale_t l)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char cc;
wchar_t wc;
+ FIX_LOCALE(l);
if (c == EOF)
return (WEOF);
@@ -47,7 +53,12 @@ btowc(int c)
* counts.
*/
cc = (char)c;
- if (__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
return (WEOF);
return (wc);
}
+wint_t
+btowc(int c)
+{
+ return btowc_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
index 6833598..e87b6dc 100644
--- a/lib/libc/locale/collate.c
+++ b/lib/libc/locale/collate.c
@@ -3,6 +3,16 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -44,24 +54,77 @@ __FBSDID("$FreeBSD$");
#include "libc_private.h"
-int __collate_load_error = 1;
-int __collate_substitute_nontrivial;
+/*
+ * To avoid modifying the original (single-threaded) code too much, we'll just
+ * define the old globals as fields inside the table.
+ *
+ * We also modify the collation table test functions to search the thread-local
+ * table first and the global table second.
+ */
+#define __collate_load_error (table->__collate_load_error)
+#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
+#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
+#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
+#define __collate_chain_pri_table (table->__collate_chain_pri_table)
-u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
-struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
-struct __collate_st_chain_pri *__collate_chain_pri_table;
+
+struct xlocale_collate __xlocale_global_collate = {
+ {{0}, "C"}, 1, 0
+};
+
+ struct xlocale_collate __xlocale_C_collate = {
+ {{0}, "C"}, 1, 0
+};
void __collate_err(int ex, const char *f) __dead2;
int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
+
+static void
+destruct_collate(void *t)
+{
+ struct xlocale_collate *table = t;
+ if (__collate_chain_pri_table) {
+ free(__collate_chain_pri_table);
+ }
+ free(t);
+}
+
+void *
+__collate_load(const char *encoding, locale_t unused)
+{
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ return &__xlocale_C_collate;
+ }
+ struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 1);
+ table->header.header.destructor = destruct_collate;
+ // FIXME: Make sure that _LDP_CACHE is never returned. We should be doing
+ // the caching outside of this section
+ if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
+ xlocale_release(table);
+ return NULL;
+ }
+ return table;
+}
+
+/**
+ * Load the collation tables for the specified encoding into the global table.
+ */
+int
__collate_load_tables(const char *encoding)
{
+ return __collate_load_tables_l(encoding, &__xlocale_global_collate);
+}
+
+int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
+{
FILE *fp;
int i, saverr, chains;
uint32_t u32;
char strbuf[STR_LEN], buf[PATH_MAX];
void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table;
- static char collate_encoding[ENCODING_LEN + 1];
/* 'encoding' must be already checked. */
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
@@ -69,18 +132,6 @@ __collate_load_tables(const char *encoding)
return (_LDP_CACHE);
}
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (strcmp(encoding, collate_encoding) == 0) {
- __collate_load_error = 0;
- return (_LDP_CACHE);
- }
-
- /*
- * Slurp the locale file into the cache.
- */
-
/* 'PathLocale' must be already set & checked. */
/* Range checking not needed, encoding has fixed size */
(void)strcpy(buf, _PathLocale);
@@ -165,7 +216,6 @@ __collate_load_tables(const char *encoding)
sizeof(*__collate_chain_pri_table), chains, fp);
(void)fclose(fp);
- (void)strcpy(collate_encoding, encoding);
if (__collate_substitute_table_ptr != NULL)
free(__collate_substitute_table_ptr);
__collate_substitute_table_ptr = TMP_substitute_table;
@@ -201,7 +251,7 @@ __collate_load_tables(const char *encoding)
}
u_char *
-__collate_substitute(const u_char *s)
+__collate_substitute(struct xlocale_collate *table, const u_char *s)
{
int dest_len, len, nlen;
int delta = strlen(s);
@@ -228,7 +278,7 @@ __collate_substitute(const u_char *s)
}
void
-__collate_lookup(const u_char *t, int *len, int *prim, int *sec)
+__collate_lookup(struct xlocale_collate *table, const u_char *t, int *len, int *prim, int *sec)
{
struct __collate_st_chain_pri *p2;
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
index 2f5f5d4..ad034d4 100644
--- a/lib/libc/locale/collate.h
+++ b/lib/libc/locale/collate.h
@@ -3,6 +3,11 @@
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,6 +38,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
+#include "xlocale_private.h"
#define STR_LEN 10
#define TABLE_SIZE 100
@@ -47,20 +53,26 @@ struct __collate_st_chain_pri {
int prim, sec;
};
-extern int __collate_load_error;
-extern int __collate_substitute_nontrivial;
#define __collate_substitute_table (*__collate_substitute_table_ptr)
-extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
-extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
-extern struct __collate_st_chain_pri *__collate_chain_pri_table;
+
+struct xlocale_collate {
+ struct xlocale_component header;
+ int __collate_load_error;
+ int __collate_substitute_nontrivial;
+
+ u_char (*__collate_substitute_table_ptr)[UCHAR_MAX + 1][STR_LEN];
+ struct __collate_st_char_pri (*__collate_char_pri_table_ptr)[UCHAR_MAX + 1];
+ struct __collate_st_chain_pri *__collate_chain_pri_table;
+};
+
__BEGIN_DECLS
u_char *__collate_strdup(u_char *);
-u_char *__collate_substitute(const u_char *);
+u_char *__collate_substitute(struct xlocale_collate *, const u_char *);
int __collate_load_tables(const char *);
-void __collate_lookup(const u_char *, int *, int *, int *);
-int __collate_range_cmp(int, int);
+void __collate_lookup(struct xlocale_collate *, const u_char *, int *, int *, int *);
+int __collate_range_cmp(struct xlocale_collate *, int, int);
#ifdef COLLATE_DEBUG
void __collate_print_tables(void);
#endif
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
index 313e043..aa17afd 100644
--- a/lib/libc/locale/collcmp.c
+++ b/lib/libc/locale/collcmp.c
@@ -2,6 +2,11 @@
* Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,17 +33,20 @@
__FBSDID("$FreeBSD$");
#include <string.h>
+#include <xlocale.h>
#include "collate.h"
/*
* Compare two characters using collate
*/
-int __collate_range_cmp(int c1, int c2)
+int __collate_range_cmp(struct xlocale_collate *table, int c1, int c2)
{
static char s1[2], s2[2];
s1[0] = c1;
s2[0] = c2;
- return (strcoll(s1, s2));
+ struct _xlocale l = {{0}};
+ l.components[XLC_COLLATE] = (struct xlocale_component *)table;
+ return (strcoll_l(s1, s2, &l));
}
diff --git a/lib/libc/locale/ctype.c b/lib/libc/locale/ctype.c
new file mode 100644
index 0000000..f0ec3f6
--- /dev/null
+++ b/lib/libc/locale/ctype.c
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions * are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
diff --git a/lib/libc/locale/duplocale.3 b/lib/libc/locale/duplocale.3
new file mode 100644
index 0000000..19d2569
--- /dev/null
+++ b/lib/libc/locale/duplocale.3
@@ -0,0 +1,78 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17 2011
+.Dt DUPLOCALE 3
+.Os
+.Sh NAME
+.Nm duplocale
+.Nd duplicate an locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft locale_t
+.Fn duplocale "locale_t locale"
+.Sh DESCRIPTION
+Duplicates an existing
+.Fa locale_t
+returning a new
+.Fa locale_t
+that refers to the same locale values but has independent internal state.
+Various functions, such as
+.Xr mblen 3
+require presistent state. These functions formerly used static variables and
+calls to them from multiple threads had undefined behavior. They now use
+fields in the
+.Fa locale_t
+associated with the current thread by
+.Xr uselocale 3 .
+These calls are therefore only thread safe on threads with a unique per-thread
+locale.
+.Pt
+The locale returned by this call must be freed with
+.Xr freelocale 3 .
+.Sh BUGS
+Ideally,
+.Xr uselocale 3
+should make a copy of the
+.Fa locale_t
+implicitly to ensure thread safety, and a copy of the global locale should be
+installed lazily on each thread. The FreeBSD implementation does not do this,
+for compatibility with Darwin.
+.Sh SEE ALSO
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
index 188073e..26ad413 100644
--- a/lib/libc/locale/euc.c
+++ b/lib/libc/locale/euc.c
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -70,7 +75,7 @@ typedef struct {
} _EucState;
int
-_EUC_init(_RuneLocale *rl)
+_EUC_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
_EucInfo *ei;
int x, new__mb_cur_max;
@@ -113,12 +118,12 @@ _EUC_init(_RuneLocale *rl)
}
rl->__variable = ei;
rl->__variable_len = sizeof(_EucInfo);
- _CurrentRuneLocale = rl;
- __mb_cur_max = new__mb_cur_max;
- __mbrtowc = _EUC_mbrtowc;
- __wcrtomb = _EUC_wcrtomb;
- __mbsinit = _EUC_mbsinit;
- __mb_sb_limit = 256;
+ l->runes = rl;
+ l->__mb_cur_max = new__mb_cur_max;
+ l->__mbrtowc = _EUC_mbrtowc;
+ l->__wcrtomb = _EUC_wcrtomb;
+ l->__mbsinit = _EUC_mbsinit;
+ l->__mb_sb_limit = 256;
return (0);
}
diff --git a/lib/libc/locale/freelocale.3 b/lib/libc/locale/freelocale.3
new file mode 100644
index 0000000..cf7174d
--- /dev/null
+++ b/lib/libc/locale/freelocale.3
@@ -0,0 +1,61 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd September 17 2011
+.Dt FREELOCALE 3
+.Os
+.Sh NAME
+.Nm freelocale
+.Nd Frees a locale created with
+.Xr duplocale 3
+or
+.Xr newlocale 3 .
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft int
+.Fn freelocale "locale_t locale"
+.Sh DESCRIPTION
+Frees a
+.Fa locale_t .
+This relinquishes any resources held exclusively by this locale. Note that
+locales share reference-counted components, so a call to this function is not
+guaranteed to free all of the components.
+.Sh RETURN VALUES
+Returns 0 on success or -1 on error.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/gb18030.c b/lib/libc/locale/gb18030.c
index 1457d3e..9214385 100644
--- a/lib/libc/locale/gb18030.c
+++ b/lib/libc/locale/gb18030.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,8 +44,6 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB18030_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB18030_mbsinit(const mbstate_t *);
@@ -53,15 +56,15 @@ typedef struct {
} _GB18030State;
int
-_GB18030_init(_RuneLocale *rl)
+_GB18030_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _GB18030_mbrtowc;
- __wcrtomb = _GB18030_wcrtomb;
- __mbsinit = _GB18030_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 4;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _GB18030_mbrtowc;
+ l->__wcrtomb = _GB18030_wcrtomb;
+ l->__mbsinit = _GB18030_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ l->__mb_sb_limit = 128;
return (0);
}
diff --git a/lib/libc/locale/gb2312.c b/lib/libc/locale/gb2312.c
index 74a7bdc..5fbc07d 100644
--- a/lib/libc/locale/gb2312.c
+++ b/lib/libc/locale/gb2312.c
@@ -3,6 +3,11 @@
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,8 +40,6 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-extern int __mb_sb_limit;
-
static size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GB2312_mbsinit(const mbstate_t *);
@@ -49,15 +52,15 @@ typedef struct {
} _GB2312State;
int
-_GB2312_init(_RuneLocale *rl)
+_GB2312_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- _CurrentRuneLocale = rl;
- __mbrtowc = _GB2312_mbrtowc;
- __wcrtomb = _GB2312_wcrtomb;
- __mbsinit = _GB2312_mbsinit;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->runes = rl;
+ l->__mbrtowc = _GB2312_mbrtowc;
+ l->__wcrtomb = _GB2312_wcrtomb;
+ l->__mbsinit = _GB2312_mbsinit;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
diff --git a/lib/libc/locale/gbk.c b/lib/libc/locale/gbk.c
index 802f78e..43269c7 100644
--- a/lib/libc/locale/gbk.c
+++ b/lib/libc/locale/gbk.c
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -55,15 +60,15 @@ typedef struct {
} _GBKState;
int
-_GBK_init(_RuneLocale *rl)
+_GBK_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _GBK_mbrtowc;
- __wcrtomb = _GBK_wcrtomb;
- __mbsinit = _GBK_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 128;
+ l->__mbrtowc = _GBK_mbrtowc;
+ l->__wcrtomb = _GBK_wcrtomb;
+ l->__mbsinit = _GBK_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
return (0);
}
diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c
index 3498be2..a0664d0 100644
--- a/lib/libc/locale/lmessages.c
+++ b/lib/libc/locale/lmessages.c
@@ -2,6 +2,11 @@
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,6 +41,14 @@ __FBSDID("$FreeBSD$");
#define LCMESSAGES_SIZE_MIN \
(offsetof(struct lc_messages_T, yesstr) / sizeof(char *))
+struct xlocale_messages {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_messages_T locale;
+};
+
+struct xlocale_messages __xlocale_global_messages;
+
static char empty[] = "";
static const struct lc_messages_T _C_messages_locale = {
@@ -45,33 +58,55 @@ static const struct lc_messages_T _C_messages_locale = {
"no" /* nostr */
};
-static struct lc_messages_T _messages_locale;
-static int _messages_using_locale;
-static char *_messages_locale_buf;
+static void destruct_messages(void *v)
+{
+ struct xlocale_messages *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
-int
-__messages_load_locale(const char *name)
+static int
+messages_load_locale(struct xlocale_messages *loc, int *using_locale, const char *name)
{
int ret;
+ struct lc_messages_T *l = &loc->locale;
- ret = __part_load_locale(name, &_messages_using_locale,
- &_messages_locale_buf, "LC_MESSAGES",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MESSAGES",
LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
- (const char **)&_messages_locale);
+ (const char **)l);
if (ret == _LDP_LOADED) {
- if (_messages_locale.yesstr == NULL)
- _messages_locale.yesstr = empty;
- if (_messages_locale.nostr == NULL)
- _messages_locale.nostr = empty;
+ if (l->yesstr == NULL)
+ l->yesstr = empty;
+ if (l->nostr == NULL)
+ l->nostr = empty;
}
return (ret);
}
+int
+__messages_load_locale(const char *name)
+{
+ return messages_load_locale(&__xlocale_global_messages,
+ &__xlocale_global_locale.using_messages_locale, name);
+}
+void *
+__messages_load(const char *name, locale_t l)
+{
+ struct xlocale_messages *new = calloc(sizeof(struct xlocale_messages), 1);
+ new->header.header.destructor = destruct_messages;
+ if (messages_load_locale(new, &l->using_messages_locale, name) == _LDP_ERROR) {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
struct lc_messages_T *
-__get_current_messages_locale(void)
+__get_current_messages_locale(locale_t loc)
{
- return (_messages_using_locale
- ? &_messages_locale
+ return (loc->using_messages_locale
+ ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale
: (struct lc_messages_T *)&_C_messages_locale);
}
diff --git a/lib/libc/locale/lmessages.h b/lib/libc/locale/lmessages.h
index 41dcfa9..ea9c57e 100644
--- a/lib/libc/locale/lmessages.h
+++ b/lib/libc/locale/lmessages.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -29,6 +34,8 @@
#ifndef _LMESSAGES_H_
#define _LMESSAGES_H_
+#include "xlocale_private.h"
+
struct lc_messages_T {
const char *yesexpr;
const char *noexpr;
@@ -36,7 +43,7 @@ struct lc_messages_T {
const char *nostr;
};
-struct lc_messages_T *__get_current_messages_locale(void);
+struct lc_messages_T *__get_current_messages_locale(locale_t);
int __messages_load_locale(const char *);
#endif /* !_LMESSAGES_H_ */
diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c
index 8d55ab2..a9d67d3 100644
--- a/lib/libc/locale/lmonetary.c
+++ b/lib/libc/locale/lmonetary.c
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include "ldpart.h"
#include "lmonetary.h"
-extern int __mlocale_changed;
extern const char * __fix_locale_grouping_str(const char *);
#define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *))
@@ -69,9 +73,7 @@ static const struct lc_monetary_T _C_monetary_locale = {
numempty /* int_n_sign_posn */
};
-static struct lc_monetary_T _monetary_locale;
-static int _monetary_using_locale;
-static char *_monetary_locale_buf;
+struct xlocale_monetary __xlocale_global_monetary;
static char
cnv(const char *str)
@@ -83,23 +85,34 @@ cnv(const char *str)
return ((char)i);
}
-int
-__monetary_load_locale(const char *name)
+static void
+destruct_monetary(void *v)
+{
+ struct xlocale_monetary *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+static int
+monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
+ int *changed, const char *name)
{
int ret;
+ struct lc_monetary_T *l = &loc->locale;
- ret = __part_load_locale(name, &_monetary_using_locale,
- &_monetary_locale_buf, "LC_MONETARY",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MONETARY",
LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
- (const char **)&_monetary_locale);
+ (const char **)l);
if (ret != _LDP_ERROR)
- __mlocale_changed = 1;
+ *changed = 1;
if (ret == _LDP_LOADED) {
- _monetary_locale.mon_grouping =
- __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+ l->mon_grouping =
+ __fix_locale_grouping_str(l->mon_grouping);
-#define M_ASSIGN_CHAR(NAME) (((char *)_monetary_locale.NAME)[0] = \
- cnv(_monetary_locale.NAME))
+#define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \
+ cnv(l->NAME))
M_ASSIGN_CHAR(int_frac_digits);
M_ASSIGN_CHAR(frac_digits);
@@ -117,9 +130,9 @@ __monetary_load_locale(const char *name)
*/
#define M_ASSIGN_ICHAR(NAME) \
do { \
- if (_monetary_locale.int_##NAME == NULL) \
- _monetary_locale.int_##NAME = \
- _monetary_locale.NAME; \
+ if (l->int_##NAME == NULL) \
+ l->int_##NAME = \
+ l->NAME; \
else \
M_ASSIGN_CHAR(int_##NAME); \
} while (0)
@@ -133,12 +146,32 @@ __monetary_load_locale(const char *name)
}
return (ret);
}
+int
+__monetary_load_locale(const char *name)
+{
+ return monetary_load_locale_l(&__xlocale_global_monetary,
+ &__xlocale_global_locale.using_monetary_locale,
+ &__xlocale_global_locale.monetary_locale_changed, name);
+}
+void* __monetary_load(const char *name, locale_t l)
+{
+ struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary), 1);
+ new->header.header.destructor = destruct_monetary;
+ if (monetary_load_locale_l(new, &l->using_monetary_locale,
+ &l->monetary_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
struct lc_monetary_T *
-__get_current_monetary_locale(void)
+__get_current_monetary_locale(locale_t loc)
{
- return (_monetary_using_locale
- ? &_monetary_locale
+ return (loc->using_monetary_locale
+ ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale
: (struct lc_monetary_T *)&_C_monetary_locale);
}
diff --git a/lib/libc/locale/lmonetary.h b/lib/libc/locale/lmonetary.h
index 45ec323..b606862 100644
--- a/lib/libc/locale/lmonetary.h
+++ b/lib/libc/locale/lmonetary.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,6 +33,7 @@
#ifndef _LMONETARY_H_
#define _LMONETARY_H_
+#include "xlocale_private.h"
struct lc_monetary_T {
const char *int_curr_symbol;
@@ -52,8 +58,13 @@ struct lc_monetary_T {
const char *int_p_sign_posn;
const char *int_n_sign_posn;
};
+struct xlocale_monetary {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_monetary_T locale;
+};
-struct lc_monetary_T *__get_current_monetary_locale(void);
+struct lc_monetary_T *__get_current_monetary_locale(locale_t loc);
int __monetary_load_locale(const char *);
#endif /* !_LMONETARY_H_ */
diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c
index d4ed04f..a2468f4 100644
--- a/lib/libc/locale/lnumeric.c
+++ b/lib/libc/locale/lnumeric.c
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,7 +37,6 @@ __FBSDID("$FreeBSD$");
#include "ldpart.h"
#include "lnumeric.h"
-extern int __nlocale_changed;
extern const char *__fix_locale_grouping_str(const char *);
#define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
@@ -45,37 +49,67 @@ static const struct lc_numeric_T _C_numeric_locale = {
numempty /* grouping */
};
-static struct lc_numeric_T _numeric_locale;
-static int _numeric_using_locale;
-static char *_numeric_locale_buf;
+static void
+destruct_numeric(void *v)
+{
+ struct xlocale_numeric *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+struct xlocale_numeric __xlocale_global_numeric;
-int
-__numeric_load_locale(const char *name)
+static int
+numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed,
+ const char *name)
{
int ret;
+ struct lc_numeric_T *l = &loc->locale;
- ret = __part_load_locale(name, &_numeric_using_locale,
- &_numeric_locale_buf, "LC_NUMERIC",
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_NUMERIC",
LCNUMERIC_SIZE, LCNUMERIC_SIZE,
- (const char **)&_numeric_locale);
+ (const char**)l);
if (ret != _LDP_ERROR)
- __nlocale_changed = 1;
+ *changed= 1;
if (ret == _LDP_LOADED) {
/* Can't be empty according to C99 */
- if (*_numeric_locale.decimal_point == '\0')
- _numeric_locale.decimal_point =
+ if (*l->decimal_point == '\0')
+ l->decimal_point =
_C_numeric_locale.decimal_point;
- _numeric_locale.grouping =
- __fix_locale_grouping_str(_numeric_locale.grouping);
+ l->grouping =
+ __fix_locale_grouping_str(l->grouping);
}
return (ret);
}
+int
+__numeric_load_locale(const char *name)
+{
+ return numeric_load_locale(&__xlocale_global_numeric,
+ &__xlocale_global_locale.using_numeric_locale,
+ &__xlocale_global_locale.numeric_locale_changed, name);
+}
+void *
+__numeric_load(const char *name, locale_t l)
+{
+ struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric), 1);
+ new->header.header.destructor = destruct_numeric;
+ if (numeric_load_locale(new, &l->using_numeric_locale,
+ &l->numeric_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
struct lc_numeric_T *
-__get_current_numeric_locale(void)
+__get_current_numeric_locale(locale_t loc)
{
- return (_numeric_using_locale
- ? &_numeric_locale
+ return (loc->using_numeric_locale
+ ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale
: (struct lc_numeric_T *)&_C_numeric_locale);
}
diff --git a/lib/libc/locale/lnumeric.h b/lib/libc/locale/lnumeric.h
index cc6965b..5088dd4 100644
--- a/lib/libc/locale/lnumeric.h
+++ b/lib/libc/locale/lnumeric.h
@@ -2,6 +2,11 @@
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,14 +33,20 @@
#ifndef _LNUMERIC_H_
#define _LNUMERIC_H_
+#include "xlocale_private.h"
struct lc_numeric_T {
const char *decimal_point;
const char *thousands_sep;
const char *grouping;
};
+struct xlocale_numeric {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_numeric_T locale;
+};
-struct lc_numeric_T *__get_current_numeric_locale(void);
+struct lc_numeric_T *__get_current_numeric_locale(locale_t loc);
int __numeric_load_locale(const char *);
#endif /* !_LNUMERIC_H_ */
diff --git a/lib/libc/locale/localeconv.3 b/lib/libc/locale/localeconv.3
index c4b5746..6ebb878 100644
--- a/lib/libc/locale/localeconv.3
+++ b/lib/libc/locale/localeconv.3
@@ -44,6 +44,9 @@
.In locale.h
.Ft struct lconv *
.Fn localeconv "void"
+.In xlocale.h
+.Ft struct lconv *
+.Fn localeconv_l "locale_t locale"
.Sh DESCRIPTION
The
.Fn localeconv
@@ -196,6 +199,11 @@ a value that is not in the current locale.
A
.Dv CHAR_MAX
result similarly denotes an unavailable value.
+.Pp
+The
+.Fn localeconv_l
+function takes an explicit locale parameter. For more information, see
+.Xr xlocale 3 .
.Sh RETURN VALUES
The
.Fn localeconv
@@ -204,6 +212,13 @@ which may be altered by later calls to
.Xr setlocale 3
or
.Fn localeconv .
+The return value for
+.Fn localeconv_l
+is stored with the locale. It will remain valid until a subsequent call to
+.Xr freelocale 3 .
+If a thread-local locale is in effect then the return value from
+.Fn localeconv
+will remain valid until the locale is destroyed.
.Sh ERRORS
No errors are defined.
.Sh SEE ALSO
diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c
index fed8d35..4b19160 100644
--- a/lib/libc/locale/localeconv.c
+++ b/lib/libc/locale/localeconv.c
@@ -3,6 +3,11 @@
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -48,25 +53,24 @@ __FBSDID("$FreeBSD$");
* lconv structure are computed only when the monetary or numeric
* locale has been changed.
*/
-int __mlocale_changed = 1;
-int __nlocale_changed = 1;
/*
* Return the current locale conversion.
*/
struct lconv *
-localeconv()
+localeconv_l(locale_t loc)
{
- static struct lconv ret;
+ FIX_LOCALE(loc);
+ struct lconv *ret = &loc->lconv;
- if (__mlocale_changed) {
+ if (loc->monetary_locale_changed) {
/* LC_MONETARY part */
struct lc_monetary_T * mptr;
-#define M_ASSIGN_STR(NAME) (ret.NAME = (char*)mptr->NAME)
-#define M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0])
+#define M_ASSIGN_STR(NAME) (ret->NAME = (char*)mptr->NAME)
+#define M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0])
- mptr = __get_current_monetary_locale();
+ mptr = __get_current_monetary_locale(loc);
M_ASSIGN_STR(int_curr_symbol);
M_ASSIGN_STR(currency_symbol);
M_ASSIGN_STR(mon_decimal_point);
@@ -88,21 +92,26 @@ localeconv()
M_ASSIGN_CHAR(int_n_sep_by_space);
M_ASSIGN_CHAR(int_p_sign_posn);
M_ASSIGN_CHAR(int_n_sign_posn);
- __mlocale_changed = 0;
+ loc->monetary_locale_changed = 0;
}
- if (__nlocale_changed) {
+ if (loc->numeric_locale_changed) {
/* LC_NUMERIC part */
struct lc_numeric_T * nptr;
-#define N_ASSIGN_STR(NAME) (ret.NAME = (char*)nptr->NAME)
+#define N_ASSIGN_STR(NAME) (ret->NAME = (char*)nptr->NAME)
- nptr = __get_current_numeric_locale();
+ nptr = __get_current_numeric_locale(loc);
N_ASSIGN_STR(decimal_point);
N_ASSIGN_STR(thousands_sep);
N_ASSIGN_STR(grouping);
- __nlocale_changed = 0;
+ loc->numeric_locale_changed = 0;
}
- return (&ret);
+ return ret;
+}
+struct lconv *
+localeconv(void)
+{
+ return localeconv_l(__get_locale());
}
diff --git a/lib/libc/locale/mblen.c b/lib/libc/locale/mblen.c
index 4a2cc5c..1bacf3e 100644
--- a/lib/libc/locale/mblen.c
+++ b/lib/libc/locale/mblen.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,19 +37,25 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
int
-mblen(const char *s, size_t n)
+mblen_l(const char *s, size_t n, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->mblen = initial;
return (0);
}
- rval = __mbrtowc(NULL, s, n, &mbs);
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, &locale->mblen);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+
+int
+mblen(const char *s, size_t n)
+{
+ return mblen_l(s, n, __get_locale());
+}
diff --git a/lib/libc/locale/mblocal.h b/lib/libc/locale/mblocal.h
index 0faebe5..d172764 100644
--- a/lib/libc/locale/mblocal.h
+++ b/lib/libc/locale/mblocal.h
@@ -2,6 +2,11 @@
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,35 +35,45 @@
#define _MBLOCAL_H_
#include <runetype.h>
+#include "xlocale_private.h"
+
/*
- * Rune initialization function prototypes.
+ * Conversion function pointers for current encoding.
*/
-int _none_init(_RuneLocale *);
-int _ascii_init(_RuneLocale *);
-int _UTF8_init(_RuneLocale *);
-int _EUC_init(_RuneLocale *);
-int _GB18030_init(_RuneLocale *);
-int _GB2312_init(_RuneLocale *);
-int _GBK_init(_RuneLocale *);
-int _BIG5_init(_RuneLocale *);
-int _MSKanji_init(_RuneLocale *);
+struct xlocale_ctype {
+ struct xlocale_component header;
+ _RuneLocale *runes;
+ size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+ int (*__mbsinit)(const mbstate_t *);
+ size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
+ size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ int __mb_cur_max;
+ int __mb_sb_limit;
+};
+#define XLOCALE_CTYPE(x) ((struct xlocale_ctype*)(x)->components[XLC_CTYPE])
+extern struct xlocale_ctype __xlocale_global_ctype;
/*
- * Conversion function pointers for current encoding.
+ * Rune initialization function prototypes.
*/
-extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
- size_t, mbstate_t * __restrict);
-extern int (*__mbsinit)(const mbstate_t *);
-extern size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
-extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
-extern size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+int _none_init(struct xlocale_ctype *, _RuneLocale *);
+int _ascii_init(struct xlocale_ctype *, _RuneLocale *);
+int _UTF8_init(struct xlocale_ctype *, _RuneLocale *);
+int _EUC_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB18030_init(struct xlocale_ctype *, _RuneLocale *);
+int _GB2312_init(struct xlocale_ctype *, _RuneLocale *);
+int _GBK_init(struct xlocale_ctype *, _RuneLocale *);
+int _BIG5_init(struct xlocale_ctype *, _RuneLocale *);
+int _MSKanji_init(struct xlocale_ctype *, _RuneLocale *);
extern size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
- size_t, size_t, mbstate_t * __restrict);
+ size_t, size_t, mbstate_t * __restrict);
#endif /* _MBLOCAL_H_ */
diff --git a/lib/libc/locale/mbrlen.c b/lib/libc/locale/mbrlen.c
index b4c3a04..9ce0bc0 100644
--- a/lib/libc/locale/mbrlen.c
+++ b/lib/libc/locale/mbrlen.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,11 +36,16 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
-mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale)
{
- static mbstate_t mbs;
-
+ FIX_LOCALE(locale);
if (ps == NULL)
- ps = &mbs;
- return (__mbrtowc(NULL, s, n, ps));
+ ps = &locale->mbrlen;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps));
+}
+
+size_t
+mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+{
+ return mbrlen_l(s, n, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c
index 42d5f7a..8f1aebd 100644
--- a/lib/libc/locale/mbrtowc.c
+++ b/lib/libc/locale/mbrtowc.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,12 +36,18 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
+mbrtowc_l(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtowc;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, ps));
+}
+
+size_t
mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbrtowc(pwc, s, n, ps));
+ return mbrtowc_l(pwc, s, n, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbsinit.c b/lib/libc/locale/mbsinit.c
index 24408c7..be44fe5 100644
--- a/lib/libc/locale/mbsinit.c
+++ b/lib/libc/locale/mbsinit.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,8 +36,13 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
int
+mbsinit_l(const mbstate_t *ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (XLOCALE_CTYPE(locale)->__mbsinit(ps));
+}
+int
mbsinit(const mbstate_t *ps)
{
-
- return (__mbsinit(ps));
+ return mbsinit_l(ps, __get_locale());
}
diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c
index 5284087..15b48dd7 100644
--- a/lib/libc/locale/mbsnrtowcs.c
+++ b/lib/libc/locale/mbsnrtowcs.c
@@ -1,5 +1,10 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,14 +39,19 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
+mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsnrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, nms, len, ps));
+}
+size_t
mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbsnrtowcs(dst, src, nms, len, ps));
+ return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale());
}
size_t
@@ -52,13 +62,14 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
size_t nchr;
wchar_t wc;
size_t nb;
+ struct xlocale_ctype *ct = XLOCALE_CTYPE(__get_locale());
s = *src;
nchr = 0;
if (dst == NULL) {
for (;;) {
- if ((nb = __mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+ if ((nb = ct->__mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
else if (nb == 0 || nb == (size_t)-2)
@@ -71,7 +82,7 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
}
while (len-- > 0) {
- if ((nb = __mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+ if ((nb = ct->__mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
diff --git a/lib/libc/locale/mbsrtowcs.c b/lib/libc/locale/mbsrtowcs.c
index 1239c82..9032b94 100644
--- a/lib/libc/locale/mbsrtowcs.c
+++ b/lib/libc/locale/mbsrtowcs.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,12 +39,17 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
+mbsrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+}
+size_t
mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+ return mbsrtowcs_l(dst, src, len, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbstowcs.c b/lib/libc/locale/mbstowcs.c
index 194ec2e..6905d2e 100644
--- a/lib/libc/locale/mbstowcs.c
+++ b/lib/libc/locale/mbstowcs.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,19 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
-mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+mbstowcs_l(wchar_t * __restrict pwcs, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const char *sp;
+ FIX_LOCALE(locale);
mbs = initial;
sp = s;
- return (__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
+}
+size_t
+mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+{
+ return mbstowcs_l(pwcs, s, n, __get_locale());
}
diff --git a/lib/libc/locale/mbtowc.c b/lib/libc/locale/mbtowc.c
index ad5b735..70fc19e 100644
--- a/lib/libc/locale/mbtowc.c
+++ b/lib/libc/locale/mbtowc.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,19 +37,24 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
int
-mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+mbtowc_l(wchar_t * __restrict pwc, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->mbtowc = initial;
return (0);
}
- rval = __mbrtowc(pwc, s, n, &mbs);
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, &locale->mbtowc);
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
+int
+mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+{
+ return mbtowc_l(pwc, s, n, __get_locale());
+}
diff --git a/lib/libc/locale/mskanji.c b/lib/libc/locale/mskanji.c
index 9ee91de..9fdd080 100644
--- a/lib/libc/locale/mskanji.c
+++ b/lib/libc/locale/mskanji.c
@@ -6,6 +6,11 @@
* (C) Sin'ichiro MIYATANI / Phase One, Inc
* May 12, 1995
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -60,15 +65,15 @@ typedef struct {
} _MSKanjiState;
int
-_MSKanji_init(_RuneLocale *rl)
+_MSKanji_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _MSKanji_mbrtowc;
- __wcrtomb = _MSKanji_wcrtomb;
- __mbsinit = _MSKanji_mbsinit;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 2;
- __mb_sb_limit = 256;
+ l->__mbrtowc = _MSKanji_mbrtowc;
+ l->__wcrtomb = _MSKanji_wcrtomb;
+ l->__mbsinit = _MSKanji_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 256;
return (0);
}
diff --git a/lib/libc/locale/newlocale.3 b/lib/libc/locale/newlocale.3
new file mode 100644
index 0000000..b351f99
--- /dev/null
+++ b/lib/libc/locale/newlocale.3
@@ -0,0 +1,109 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd September 17 2011
+.Dt newlocale 3
+.Os
+.Sh NAME
+.Nm newlocale
+.Nd Creates a new locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale
+.Ft
+.Fn newlocale "int mask" "const char * locale" "locale_t base"
+.Sh DESCRIPTION
+Creates a new locale, inheriting some properties from an existing locale. The
+.Fa mask
+defines the components that the new locale will have set to the locale with the
+name specified in the
+.Fa locale
+parameter. Any other components will be inherited from
+.Fa base .
+.Pt
+The
+.Fa mask
+is either
+.Fa LC_ALL_MASK,
+indicating all possible locale components, or the logical OR of some
+combination of the following:
+.Bl -tag -width "LC_MESSAGES_MASK" -offset indent
+.It LC_COLLATE_MASK
+The locale for string collation routines. This controls alphabetic ordering in
+.Xr strcoll 3
+ and
+.Xr strxfrm 3 .
+.It LC_CTYPE_MASK
+The locale for the
+.Xr ctype 3
+and
+.Xr multibyte 3
+functions. This controls recognition of upper and lower case, alpha- betic or
+non-alphabetic characters, and so on.
+.It LC_MESSAGES_MASK
+Set a locale for message catalogs, see
+.Xr catopen 3
+function.
+.It LC_MONETARY_MASK
+Set a locale for formatting monetary values; this affects
+the
+.Xr localeconv 3
+function.
+.It LC_NUMERIC_MASK
+Set a locale for formatting numbers. This controls the for-
+matting of decimal points in input and output of floating
+point numbers in functions such as
+.Xr printf 3
+and
+.Xr scanf 3 ,
+as well as values returned by
+.Xr localeconv 3 .
+.It LC_TIME_MASK
+Set a locale for formatting dates and times using the
+.Xr strftime 3
+function.
+.El
+
+This function uses the same rules for loading locale components as
+.Xr setlocale 3 .
+.Sh RETURN VALUES
+Returns a new, valid,
+.Fa locale_t
+or NULL if an error occurs. You must free the returned locale with
+.Xr freelocale 3 .
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
diff --git a/lib/libc/locale/nextwctype.c b/lib/libc/locale/nextwctype.c
index 9363b0a..9fc8ce0 100644
--- a/lib/libc/locale/nextwctype.c
+++ b/lib/libc/locale/nextwctype.c
@@ -2,6 +2,11 @@
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,12 +35,15 @@ __FBSDID("$FreeBSD$");
#include <runetype.h>
#include <wchar.h>
#include <wctype.h>
+#include "mblocal.h"
wint_t
-nextwctype(wint_t wc, wctype_t wct)
+nextwctype_l(wint_t wc, wctype_t wct, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneLocale *runes = XLOCALE_CTYPE(locale)->runes;
+ _RuneRange *rr = &runes->__runetype_ext;
_RuneEntry *base, *re;
int noinc;
@@ -43,7 +51,7 @@ nextwctype(wint_t wc, wctype_t wct)
if (wc < _CACHED_RUNES) {
wc++;
while (wc < _CACHED_RUNES) {
- if (_CurrentRuneLocale->__runetype[wc] & wct)
+ if (runes->__runetype[wc] & wct)
return (wc);
wc++;
}
@@ -88,3 +96,8 @@ found:
}
return (-1);
}
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+ return nextwctype_l(wc, wct, __get_locale());
+}
diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c
index 26ca025..3e8fe7c 100644
--- a/lib/libc/locale/nl_langinfo.c
+++ b/lib/libc/locale/nl_langinfo.c
@@ -2,6 +2,11 @@
* Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,15 +46,16 @@ __FBSDID("$FreeBSD$");
#define _REL(BASE) ((int)item-BASE)
char *
-nl_langinfo(nl_item item)
+nl_langinfo_l(nl_item item, locale_t loc)
{
- char *ret, *s, *cs;
- static char *csym = NULL;
+ char *ret, *cs;
+ const char *s;
+ FIX_LOCALE(loc);
switch (item) {
case CODESET:
ret = "";
- if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
+ if ((s = querylocale(LC_CTYPE_MASK, loc)) != NULL) {
if ((cs = strchr(s, '.')) != NULL)
ret = cs + 1;
else if (strcmp(s, "C") == 0 ||
@@ -58,46 +64,46 @@ nl_langinfo(nl_item item)
}
break;
case D_T_FMT:
- ret = (char *) __get_current_time_locale()->c_fmt;
+ ret = (char *) __get_current_time_locale(loc)->c_fmt;
break;
case D_FMT:
- ret = (char *) __get_current_time_locale()->x_fmt;
+ ret = (char *) __get_current_time_locale(loc)->x_fmt;
break;
case T_FMT:
- ret = (char *) __get_current_time_locale()->X_fmt;
+ ret = (char *) __get_current_time_locale(loc)->X_fmt;
break;
case T_FMT_AMPM:
- ret = (char *) __get_current_time_locale()->ampm_fmt;
+ ret = (char *) __get_current_time_locale(loc)->ampm_fmt;
break;
case AM_STR:
- ret = (char *) __get_current_time_locale()->am;
+ ret = (char *) __get_current_time_locale(loc)->am;
break;
case PM_STR:
- ret = (char *) __get_current_time_locale()->pm;
+ ret = (char *) __get_current_time_locale(loc)->pm;
break;
case DAY_1: case DAY_2: case DAY_3:
case DAY_4: case DAY_5: case DAY_6: case DAY_7:
- ret = (char*) __get_current_time_locale()->weekday[_REL(DAY_1)];
+ ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)];
break;
case ABDAY_1: case ABDAY_2: case ABDAY_3:
case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
- ret = (char*) __get_current_time_locale()->wday[_REL(ABDAY_1)];
+ ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)];
break;
case MON_1: case MON_2: case MON_3: case MON_4:
case MON_5: case MON_6: case MON_7: case MON_8:
case MON_9: case MON_10: case MON_11: case MON_12:
- ret = (char*) __get_current_time_locale()->month[_REL(MON_1)];
+ ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)];
break;
case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
- ret = (char*) __get_current_time_locale()->mon[_REL(ABMON_1)];
+ ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)];
break;
case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4:
case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8:
case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12:
ret = (char*)
- __get_current_time_locale()->alt_month[_REL(ALTMON_1)];
+ __get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)];
break;
case ERA:
/* XXX: need to be implemented */
@@ -120,16 +126,16 @@ nl_langinfo(nl_item item)
ret = "";
break;
case RADIXCHAR:
- ret = (char*) __get_current_numeric_locale()->decimal_point;
+ ret = (char*) __get_current_numeric_locale(loc)->decimal_point;
break;
case THOUSEP:
- ret = (char*) __get_current_numeric_locale()->thousands_sep;
+ ret = (char*) __get_current_numeric_locale(loc)->thousands_sep;
break;
case YESEXPR:
- ret = (char*) __get_current_messages_locale()->yesexpr;
+ ret = (char*) __get_current_messages_locale(loc)->yesexpr;
break;
case NOEXPR:
- ret = (char*) __get_current_messages_locale()->noexpr;
+ ret = (char*) __get_current_messages_locale(loc)->noexpr;
break;
/*
* YESSTR and NOSTR items marked with LEGACY are available, but not
@@ -137,45 +143,51 @@ nl_langinfo(nl_item item)
* they're subject to remove in future specification editions.
*/
case YESSTR: /* LEGACY */
- ret = (char*) __get_current_messages_locale()->yesstr;
+ ret = (char*) __get_current_messages_locale(loc)->yesstr;
break;
case NOSTR: /* LEGACY */
- ret = (char*) __get_current_messages_locale()->nostr;
+ ret = (char*) __get_current_messages_locale(loc)->nostr;
break;
/*
* SUSv2 special formatted currency string
*/
case CRNCYSTR:
ret = "";
- cs = (char*) __get_current_monetary_locale()->currency_symbol;
+ cs = (char*) __get_current_monetary_locale(loc)->currency_symbol;
if (*cs != '\0') {
- char pos = localeconv()->p_cs_precedes;
+ char pos = localeconv_l(loc)->p_cs_precedes;
- if (pos == localeconv()->n_cs_precedes) {
+ if (pos == localeconv_l(loc)->n_cs_precedes) {
char psn = '\0';
if (pos == CHAR_MAX) {
- if (strcmp(cs, __get_current_monetary_locale()->mon_decimal_point) == 0)
+ if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0)
psn = '.';
} else
psn = pos ? '-' : '+';
if (psn != '\0') {
int clen = strlen(cs);
- if ((csym = reallocf(csym, clen + 2)) != NULL) {
- *csym = psn;
- strcpy(csym + 1, cs);
- ret = csym;
+ if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) {
+ *loc->csym = psn;
+ strcpy(loc->csym + 1, cs);
+ ret = loc->csym;
}
}
}
}
break;
case D_MD_ORDER: /* FreeBSD local extension */
- ret = (char *) __get_current_time_locale()->md_order;
+ ret = (char *) __get_current_time_locale(loc)->md_order;
break;
default:
ret = "";
}
return (ret);
}
+
+char *
+nl_langinfo(nl_item item)
+{
+ return nl_langinfo_l(item, __get_locale());
+}
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
index 22fcd20..75adffa 100644
--- a/lib/libc/locale/none.c
+++ b/lib/libc/locale/none.c
@@ -6,6 +6,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -64,17 +69,17 @@ int __mb_cur_max = 1;
int __mb_sb_limit = 256; /* Expected to be <= _CACHED_RUNES */
int
-_none_init(_RuneLocale *rl)
+_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _none_mbrtowc;
- __mbsinit = _none_mbsinit;
- __mbsnrtowcs = _none_mbsnrtowcs;
- __wcrtomb = _none_wcrtomb;
- __wcsnrtombs = _none_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 1;
- __mb_sb_limit = 256;
+ l->__mbrtowc = _none_mbrtowc;
+ l->__mbsinit = _none_mbsinit;
+ l->__mbsnrtowcs = _none_mbsnrtowcs;
+ l->__wcrtomb = _none_wcrtomb;
+ l->__wcsnrtombs = _none_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 256;
return(0);
}
@@ -192,3 +197,26 @@ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict) =
size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
size_t, size_t, mbstate_t * __restrict) = _none_wcsnrtombs;
+struct xlocale_ctype __xlocale_global_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
+
+const struct xlocale_ctype __xlocale_C_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3
new file mode 100644
index 0000000..ceb4da0
--- /dev/null
+++ b/lib/libc/locale/querylocale.3
@@ -0,0 +1,57 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17 2011
+.Dt QUERYLOCALE 3
+.Os
+.Sh NAME
+.Nm querylocale
+.Nd Look up the locale name for a specified category.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft const char *
+.Fn querylocale "int mask" "locale_t locale"
+.Sh DESCRIPTION
+Returns the name of the locale for the category specified by
+.Fa mask.
+This possible values for the mask are the same as those in
+.Xr newlocale 3 . If more than one bit in the mask is set, the returned value
+is undefined.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
diff --git a/lib/libc/locale/runetype.c b/lib/libc/locale/runetype.c
index 5765b85..a0da47b 100644
--- a/lib/libc/locale/runetype.c
+++ b/lib/libc/locale/runetype.c
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,12 +41,15 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
unsigned long
-___runetype(__ct_rune_t c)
+___runetype_l(__ct_rune_t c, locale_t locale)
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
+ FIX_LOCALE(locale);
+ _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext);
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -64,3 +72,18 @@ ___runetype(__ct_rune_t c)
return(0L);
}
+unsigned long
+___runetype(__ct_rune_t c)
+{
+ return ___runetype_l(c, __get_locale());
+}
+
+int ___mb_cur_max(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->__mb_cur_max;
+}
+int ___mb_cur_max_l(locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return XLOCALE_CTYPE(locale)->__mb_cur_max;
+}
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
index d6db181..8cf8fd4 100644
--- a/lib/libc/locale/setlocale.c
+++ b/lib/libc/locale/setlocale.c
@@ -95,7 +95,7 @@ static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
static char *currentlocale(void);
static char *loadlocale(int);
-static const char *__get_locale_env(int);
+const char *__get_locale_env(int);
char *
setlocale(category, locale)
@@ -278,13 +278,14 @@ loadlocale(category)
if (func(new) != _LDP_ERROR) {
(void)strcpy(old, new);
+ (void)strcpy(__xlocale_global_locale.components[category-1]->locale, new);
return (old);
}
return (NULL);
}
-static const char *
+const char *
__get_locale_env(category)
int category;
{
diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c
index 36d2894..61ce5d9 100644
--- a/lib/libc/locale/setrunelocale.c
+++ b/lib/libc/locale/setrunelocale.c
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -49,68 +54,46 @@ extern int __mb_sb_limit;
extern _RuneLocale *_Read_RuneMagi(FILE *);
-static int __setrunelocale(const char *);
+static int __setrunelocale(struct xlocale_ctype *l, const char *);
+
+#define __collate_load_error (table->__collate_load_error)
+#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial)
+#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr)
+#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr)
+#define __collate_chain_pri_table (table->__collate_chain_pri_table)
+
+
+static void destruct_ctype(void *v)
+{
+ struct xlocale_ctype *l = v;
+ if (strcmp(l->runes->__encoding, "EUC") == 0)
+ free(l->runes->__variable);
+ if (&_DefaultRuneLocale != l->runes)
+ free(l->runes);
+ free(l);
+}
+_RuneLocale *__getCurrentRuneLocale(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->runes;
+}
static int
-__setrunelocale(const char *encoding)
+__setrunelocale(struct xlocale_ctype *l, const char *encoding)
{
FILE *fp;
char name[PATH_MAX];
_RuneLocale *rl;
int saverr, ret;
- size_t (*old__mbrtowc)(wchar_t * __restrict,
- const char * __restrict, size_t, mbstate_t * __restrict);
- size_t (*old__wcrtomb)(char * __restrict, wchar_t,
- mbstate_t * __restrict);
- int (*old__mbsinit)(const mbstate_t *);
- size_t (*old__mbsnrtowcs)(wchar_t * __restrict,
- const char ** __restrict, size_t, size_t, mbstate_t * __restrict);
- size_t (*old__wcsnrtombs)(char * __restrict,
- const wchar_t ** __restrict, size_t, size_t,
- mbstate_t * __restrict);
- static char ctype_encoding[ENCODING_LEN + 1];
- static _RuneLocale *CachedRuneLocale;
- static int Cached__mb_cur_max;
- static int Cached__mb_sb_limit;
- static size_t (*Cached__mbrtowc)(wchar_t * __restrict,
- const char * __restrict, size_t, mbstate_t * __restrict);
- static size_t (*Cached__wcrtomb)(char * __restrict, wchar_t,
- mbstate_t * __restrict);
- static int (*Cached__mbsinit)(const mbstate_t *);
- static size_t (*Cached__mbsnrtowcs)(wchar_t * __restrict,
- const char ** __restrict, size_t, size_t, mbstate_t * __restrict);
- static size_t (*Cached__wcsnrtombs)(char * __restrict,
- const wchar_t ** __restrict, size_t, size_t,
- mbstate_t * __restrict);
+ struct xlocale_ctype saved = *l;
/*
* The "C" and "POSIX" locale are always here.
*/
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
- (void) _none_init(&_DefaultRuneLocale);
+ (void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
return (0);
}
- /*
- * If the locale name is the same as our cache, use the cache.
- */
- if (CachedRuneLocale != NULL &&
- strcmp(encoding, ctype_encoding) == 0) {
- _CurrentRuneLocale = CachedRuneLocale;
- __mb_cur_max = Cached__mb_cur_max;
- __mb_sb_limit = Cached__mb_sb_limit;
- __mbrtowc = Cached__mbrtowc;
- __mbsinit = Cached__mbsinit;
- __mbsnrtowcs = Cached__mbsnrtowcs;
- __wcrtomb = Cached__wcrtomb;
- __wcsnrtombs = Cached__wcsnrtombs;
- return (0);
- }
-
- /*
- * Slurp the locale file into the cache.
- */
-
/* Range checking not needed, encoding length already checked before */
(void) strcpy(name, _PathLocale);
(void) strcat(name, "/");
@@ -127,63 +110,47 @@ __setrunelocale(const char *encoding)
}
(void)fclose(fp);
- old__mbrtowc = __mbrtowc;
- old__mbsinit = __mbsinit;
- old__mbsnrtowcs = __mbsnrtowcs;
- old__wcrtomb = __wcrtomb;
- old__wcsnrtombs = __wcsnrtombs;
-
- __mbrtowc = NULL;
- __mbsinit = NULL;
- __mbsnrtowcs = __mbsnrtowcs_std;
- __wcrtomb = NULL;
- __wcsnrtombs = __wcsnrtombs_std;
+ l->__mbrtowc = NULL;
+ l->__mbsinit = NULL;
+ l->__mbsnrtowcs = __mbsnrtowcs_std;
+ l->__wcrtomb = NULL;
+ l->__wcsnrtombs = __wcsnrtombs_std;
rl->__sputrune = NULL;
rl->__sgetrune = NULL;
if (strcmp(rl->__encoding, "NONE") == 0)
- ret = _none_init(rl);
+ ret = _none_init(l, rl);
else if (strcmp(rl->__encoding, "ASCII") == 0)
- ret = _ascii_init(rl);
+ ret = _ascii_init(l, rl);
else if (strcmp(rl->__encoding, "UTF-8") == 0)
- ret = _UTF8_init(rl);
+ ret = _UTF8_init(l, rl);
else if (strcmp(rl->__encoding, "EUC") == 0)
- ret = _EUC_init(rl);
+ ret = _EUC_init(l, rl);
else if (strcmp(rl->__encoding, "GB18030") == 0)
- ret = _GB18030_init(rl);
+ ret = _GB18030_init(l, rl);
else if (strcmp(rl->__encoding, "GB2312") == 0)
- ret = _GB2312_init(rl);
+ ret = _GB2312_init(l, rl);
else if (strcmp(rl->__encoding, "GBK") == 0)
- ret = _GBK_init(rl);
+ ret = _GBK_init(l, rl);
else if (strcmp(rl->__encoding, "BIG5") == 0)
- ret = _BIG5_init(rl);
+ ret = _BIG5_init(l, rl);
else if (strcmp(rl->__encoding, "MSKanji") == 0)
- ret = _MSKanji_init(rl);
+ ret = _MSKanji_init(l, rl);
else
ret = EFTYPE;
if (ret == 0) {
- if (CachedRuneLocale != NULL) {
- /* See euc.c */
- if (strcmp(CachedRuneLocale->__encoding, "EUC") == 0)
- free(CachedRuneLocale->__variable);
- free(CachedRuneLocale);
+ /* Free the old runes if it exists. */
+ /* FIXME: The "EUC" check here is a hideous abstraction violation. */
+ if ((saved.runes != &_DefaultRuneLocale) && (saved.runes)) {
+ if (strcmp(saved.runes->__encoding, "EUC") == 0) {
+ free(saved.runes->__variable);
+ }
+ free(saved.runes);
}
- CachedRuneLocale = _CurrentRuneLocale;
- Cached__mb_cur_max = __mb_cur_max;
- Cached__mb_sb_limit = __mb_sb_limit;
- Cached__mbrtowc = __mbrtowc;
- Cached__mbsinit = __mbsinit;
- Cached__mbsnrtowcs = __mbsnrtowcs;
- Cached__wcrtomb = __wcrtomb;
- Cached__wcsnrtombs = __wcsnrtombs;
- (void)strcpy(ctype_encoding, encoding);
} else {
- __mbrtowc = old__mbrtowc;
- __mbsinit = old__mbsinit;
- __mbsnrtowcs = old__mbsnrtowcs;
- __wcrtomb = old__wcrtomb;
- __wcsnrtombs = old__wcsnrtombs;
+ /* Restore the saved version if this failed. */
+ memcpy(l, &saved, sizeof(struct xlocale_ctype));
free(rl);
}
@@ -193,12 +160,24 @@ __setrunelocale(const char *encoding)
int
__wrap_setrunelocale(const char *locale)
{
- int ret = __setrunelocale(locale);
+ int ret = __setrunelocale(&__xlocale_global_ctype, locale);
if (ret != 0) {
errno = ret;
return (_LDP_ERROR);
}
+ __mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
+ __mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
return (_LDP_LOADED);
}
-
+void *__ctype_load(const char *locale, locale_t unused)
+{
+ struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
+ l->header.header.destructor = destruct_ctype;
+ if (__setrunelocale(l, locale))
+ {
+ free(l);
+ return NULL;
+ }
+ return l;
+}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
index e1f49d1..8c876e9 100644
--- a/lib/libc/locale/table.c
+++ b/lib/libc/locale/table.c
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,7 +46,7 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#include "mblocal.h"
-_RuneLocale _DefaultRuneLocale = {
+const _RuneLocale _DefaultRuneLocale = {
_RUNE_MAGIC_1,
"NONE",
NULL,
@@ -245,5 +250,14 @@ _RuneLocale _DefaultRuneLocale = {
},
};
-_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+#undef _CurrentRuneLocale
+_RuneLocale *_CurrentRuneLocale = (_RuneLocale*)&_DefaultRuneLocale;
+_RuneLocale *
+__runes_for_locale(locale_t locale, int *mb_sb_limit)
+{
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *c = XLOCALE_CTYPE(locale);
+ *mb_sb_limit = c->__mb_sb_limit;
+ return c->runes;
+}
diff --git a/lib/libc/locale/tolower.c b/lib/libc/locale/tolower.c
index 82a78cf..f2eb483 100644
--- a/lib/libc/locale/tolower.c
+++ b/lib/libc/locale/tolower.c
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,13 +41,17 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___tolower(c)
+___tolower_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__maplower_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -62,3 +71,9 @@ ___tolower(c)
return(c);
}
+__ct_rune_t
+___tolower(c)
+ __ct_rune_t c;
+{
+ return ___tolower_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/toupper.c b/lib/libc/locale/toupper.c
index 4870e8e..d3a4fa3 100644
--- a/lib/libc/locale/toupper.c
+++ b/lib/libc/locale/toupper.c
@@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -36,13 +41,17 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
__ct_rune_t
-___toupper(c)
+___toupper_l(c, l)
__ct_rune_t c;
+ locale_t l;
{
size_t lim;
- _RuneRange *rr = &_CurrentRuneLocale->__mapupper_ext;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
@@ -53,7 +62,9 @@ ___toupper(c)
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= c && c <= re->__max)
+ {
return (re->__map + c - re->__min);
+ }
else if (c > re->__max) {
base = re + 1;
lim--;
@@ -62,3 +73,9 @@ ___toupper(c)
return(c);
}
+__ct_rune_t
+___toupper(c)
+ __ct_rune_t c;
+{
+ return ___toupper_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/uselocale.3 b/lib/libc/locale/uselocale.3
new file mode 100644
index 0000000..a7068b4
--- /dev/null
+++ b/lib/libc/locale/uselocale.3
@@ -0,0 +1,59 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17 2011
+.Dt USELOCALE 3
+.Os
+.Sh NAME
+.Nm uselocale
+.Nd Sets a thread-local locale.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Ft locale_t
+.Fn uselocale "locale_t locale"
+.Sh DESCRIPTION
+Specifies the locale for this thread to use. Specifying
+.Fa LC_GLOBAL_LOCALE
+disables the per-thread locale, while NULL returns the current locale without
+setting a new one.
+.Sh RETURN VALUES
+Returns the previous locale, or LC_GLOBAL_LOCALE if this thread has no locale
+associated with it.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function, conforms to
+.St -p1003.1-2008
diff --git a/lib/libc/locale/utf8.c b/lib/libc/locale/utf8.c
index 0ccadd3..40f0e17 100644
--- a/lib/libc/locale/utf8.c
+++ b/lib/libc/locale/utf8.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -55,22 +60,22 @@ typedef struct {
} _UTF8State;
int
-_UTF8_init(_RuneLocale *rl)
+_UTF8_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
- __mbrtowc = _UTF8_mbrtowc;
- __wcrtomb = _UTF8_wcrtomb;
- __mbsinit = _UTF8_mbsinit;
- __mbsnrtowcs = _UTF8_mbsnrtowcs;
- __wcsnrtombs = _UTF8_wcsnrtombs;
- _CurrentRuneLocale = rl;
- __mb_cur_max = 6;
+ l->__mbrtowc = _UTF8_mbrtowc;
+ l->__wcrtomb = _UTF8_wcrtomb;
+ l->__mbsinit = _UTF8_mbsinit;
+ l->__mbsnrtowcs = _UTF8_mbsnrtowcs;
+ l->__wcsnrtombs = _UTF8_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 6;
/*
* UCS-4 encoding used as the internal representation, so
* slots 0x0080-0x00FF are occuped and must be excluded
* from the single byte ctype by setting the limit.
*/
- __mb_sb_limit = 128;
+ l->__mb_sb_limit = 128;
return (0);
}
diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c
index ef75b78..32d4df2 100644
--- a/lib/libc/locale/wcrtomb.c
+++ b/lib/libc/locale/wcrtomb.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -31,11 +36,17 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
-wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+wcrtomb_l(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps,
+ locale_t locale)
{
- static mbstate_t mbs;
-
+ FIX_LOCALE(locale);
if (ps == NULL)
- ps = &mbs;
- return (__wcrtomb(s, wc, ps));
+ ps = &locale->wcrtomb;
+ return (XLOCALE_CTYPE(locale)->__wcrtomb(s, wc, ps));
+}
+
+size_t
+wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ return wcrtomb_l(s, wc, ps, __get_locale());
}
diff --git a/lib/libc/locale/wcsftime.c b/lib/libc/locale/wcsftime.c
index a546dc6..c4f6b2e 100644
--- a/lib/libc/locale/wcsftime.c
+++ b/lib/libc/locale/wcsftime.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <time.h>
#include <wchar.h>
+#include "xlocale_private.h"
/*
* Convert date and time to a wide-character string.
@@ -47,8 +53,9 @@ __FBSDID("$FreeBSD$");
* format specifications in the format string.
*/
size_t
-wcsftime(wchar_t * __restrict wcs, size_t maxsize,
- const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+wcsftime_l(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -57,6 +64,7 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
const wchar_t *formatp;
size_t n, sflen;
int sverrno;
+ FIX_LOCALE(locale);
sformat = dst = NULL;
@@ -66,13 +74,13 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
*/
mbs = initial;
formatp = format;
- sflen = wcsrtombs(NULL, &formatp, 0, &mbs);
+ sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale);
if (sflen == (size_t)-1)
goto error;
if ((sformat = malloc(sflen + 1)) == NULL)
goto error;
mbs = initial;
- wcsrtombs(sformat, &formatp, sflen + 1, &mbs);
+ wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale);
/*
* Allocate memory for longest multibyte sequence that will fit
@@ -87,11 +95,11 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize,
}
if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
goto error;
- if (strftime(dst, maxsize, sformat, timeptr) == 0)
+ if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0)
goto error;
dstp = dst;
mbs = initial;
- n = mbsrtowcs(wcs, &dstp, maxsize, &mbs);
+ n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale);
if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
goto error;
@@ -106,3 +114,9 @@ error:
errno = sverrno;
return (0);
}
+size_t
+wcsftime(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+{
+ return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c
index e899698..2f3bf1e 100644
--- a/lib/libc/locale/wcsnrtombs.c
+++ b/lib/libc/locale/wcsnrtombs.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,16 +39,22 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
+wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsnrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, nwc, len, ps));
+}
+size_t
wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
size_t len, mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__wcsnrtombs(dst, src, nwc, len, ps));
+ return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale());
}
+
size_t
__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps)
@@ -53,13 +64,14 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
const wchar_t *s;
size_t nbytes;
size_t nb;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(__get_locale());
s = *src;
nbytes = 0;
if (dst == NULL) {
while (nwc-- > 0) {
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1)
+ if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1)
/* Invalid character - wcrtomb() sets errno. */
return ((size_t)-1);
else if (*s == L'\0')
@@ -73,7 +85,7 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
while (len > 0 && nwc-- > 0) {
if (len > (size_t)MB_CUR_MAX) {
/* Enough space to translate in-place. */
- if ((nb = __wcrtomb(dst, *s, ps)) == (size_t)-1) {
+ if ((nb = l->__wcrtomb(dst, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
@@ -86,7 +98,7 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
* character is too long for the buffer.
*/
mbsbak = *ps;
- if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) {
+ if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
diff --git a/lib/libc/locale/wcsrtombs.c b/lib/libc/locale/wcsrtombs.c
index f3b38b7..f6d1ca0 100644
--- a/lib/libc/locale/wcsrtombs.c
+++ b/lib/libc/locale/wcsrtombs.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -34,12 +39,18 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
+wcsrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+}
+
+size_t
wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
- static mbstate_t mbs;
-
- if (ps == NULL)
- ps = &mbs;
- return (__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+ return wcsrtombs_l(dst, src, len, ps, __get_locale());
}
diff --git a/lib/libc/locale/wcstod.c b/lib/libc/locale/wcstod.c
index 68df1ed..8bc46a7 100644
--- a/lib/libc/locale/wcstod.c
+++ b/lib/libc/locale/wcstod.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a double-precision number.
@@ -41,17 +47,22 @@ __FBSDID("$FreeBSD$");
* for at least the digits, radix character and letters.
*/
double
-wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
double val;
char *buf, *end;
- const wchar_t *wcp;
+ const wchar_t *wcp = nptr;
size_t len;
+ size_t spaces = 0;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
- nptr++;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
/*
* Convert the supplied numeric wide char. string to multibyte.
@@ -63,9 +74,8 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
* duplicates a lot of strtod()'s functionality and slows down the
* most common cases.
*/
- wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -73,10 +83,10 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
/* Let strtod() do most of the work for us. */
- val = strtod(buf, &end);
+ val = strtod_l(buf, &end, locale);
/*
* We only know where the number ended in the _multibyte_
@@ -84,11 +94,20 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
* where it ended, count multibyte characters to find the
* corresponding position in the wide char string.
*/
- if (endptr != NULL)
+ if (endptr != NULL) {
/* XXX Assume each wide char is one byte. */
*endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
+
free(buf);
return (val);
}
+double
+wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstod_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c
index ba238d4..93a5af8 100644
--- a/lib/libc/locale/wcstof.c
+++ b/lib/libc/locale/wcstof.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,12 +35,14 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
float
-wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
@@ -43,13 +50,14 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
char *buf, *end;
const wchar_t *wcp;
size_t len;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
+ while (iswspace_l(*nptr, locale))
nptr++;
wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -57,9 +65,9 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
- val = strtof(buf, &end);
+ val = strtof_l(buf, &end, locale);
if (endptr != NULL)
*endptr = (wchar_t *)nptr + (end - buf);
@@ -68,3 +76,8 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
return (val);
}
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstof_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c
index 66e692a..ce066a5 100644
--- a/lib/libc/locale/wcstoimax.c
+++ b/lib/libc/locale/wcstoimax.c
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an intmax_t integer.
*/
intmax_t
-wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -88,8 +95,8 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -122,3 +129,9 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+intmax_t
+wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoimax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c
index 294b6e0..2b21d12 100644
--- a/lib/libc/locale/wcstol.c
+++ b/lib/libc/locale/wcstol.c
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,18 +40,21 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a string to a long integer.
*/
long
-wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
+ base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == '-') {
neg = 1;
c = *s++;
@@ -81,8 +89,8 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -115,3 +123,8 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+long
+wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstol_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c
index cf9d874..fcfd48f 100644
--- a/lib/libc/locale/wcstold.c
+++ b/lib/libc/locale/wcstold.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,26 +35,32 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
long double
-wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
long double val;
char *buf, *end;
- const wchar_t *wcp;
+ const wchar_t *wcp = nptr;
size_t len;
+ size_t spaces = 0;
+ FIX_LOCALE(locale);
- while (iswspace(*nptr))
- nptr++;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
wcp = nptr;
mbs = initial;
- if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) {
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
@@ -57,14 +68,23 @@ wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
if ((buf = malloc(len + 1)) == NULL)
return (0.0);
mbs = initial;
- wcsrtombs(buf, &wcp, len + 1, &mbs);
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
- val = strtold(buf, &end);
+ val = strtold_l(buf, &end, locale);
- if (endptr != NULL)
+ if (endptr != NULL) {
+ /* XXX Assume each wide char is one byte. */
*endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
free(buf);
return (val);
}
+long double
+wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstold_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c
index 19b285f..f246502 100644
--- a/lib/libc/locale/wcstoll.c
+++ b/lib/libc/locale/wcstoll.c
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,18 +46,21 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a long long integer.
*/
long long
-wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoll for comments as to the logic used.
@@ -60,7 +68,7 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -87,8 +95,8 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -121,3 +129,8 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+long long
+wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoll_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstombs.c b/lib/libc/locale/wcstombs.c
index 250d2b9..8d4ae1c 100644
--- a/lib/libc/locale/wcstombs.c
+++ b/lib/libc/locale/wcstombs.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,21 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
size_t
-wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+wcstombs_l(char * __restrict s, const wchar_t * __restrict pwcs, size_t n,
+ locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const wchar_t *pwcsp;
+ FIX_LOCALE(locale);
mbs = initial;
pwcsp = pwcs;
- return (__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
+}
+size_t
+wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+{
+ return wcstombs_l(s, pwcs, n, __get_locale());
}
+
diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c
index f50e7a7..54e6b4f 100644
--- a/lib/libc/locale/wcstoul.c
+++ b/lib/libc/locale/wcstoul.c
@@ -2,6 +2,11 @@
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,18 +40,21 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long integer.
*/
unsigned long
-wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
@@ -54,7 +62,7 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -79,8 +87,8 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
cutlim = ULONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -113,3 +121,8 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long
+wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoul_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c
index d840424..c56ee77 100644
--- a/lib/libc/locale/wcstoull.c
+++ b/lib/libc/locale/wcstoull.c
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long long integer.
*/
unsigned long long
-wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoull for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -120,3 +127,9 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+unsigned long long
+wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoull_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c
index d643b0b..397c1e3 100644
--- a/lib/libc/locale/wcstoumax.c
+++ b/lib/libc/locale/wcstoumax.c
@@ -2,6 +2,11 @@
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
+#include "xlocale_private.h"
/*
* Convert a wide character string to a uintmax_t integer.
*/
uintmax_t
-wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
- int base)
+wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
+ FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
@@ -61,7 +68,7 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
s = nptr;
do {
c = *s++;
- } while (iswspace(c));
+ } while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
@@ -86,8 +93,8 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
cutlim = UINTMAX_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
- if (iswdigit(c))
- c = digittoint(c);
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
@@ -120,3 +127,9 @@ noconv:
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
+uintmax_t
+wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoumax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c
index cb39adc..96e8b73 100644
--- a/lib/libc/locale/wctob.c
+++ b/lib/libc/locale/wctob.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -33,13 +38,19 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
int
-wctob(wint_t c)
+wctob_l(wint_t c, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char buf[MB_LEN_MAX];
+ FIX_LOCALE(locale);
- if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1)
+ if (c == WEOF || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1)
return (EOF);
return ((unsigned char)*buf);
}
+int
+wctob(wint_t c)
+{
+ return wctob_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/wctomb.c b/lib/libc/locale/wctomb.c
index 77b9043..da3d263 100644
--- a/lib/libc/locale/wctomb.c
+++ b/lib/libc/locale/wctomb.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,18 +37,23 @@ __FBSDID("$FreeBSD$");
#include "mblocal.h"
int
-wctomb(char *s, wchar_t wchar)
+wctomb_l(char *s, wchar_t wchar, locale_t locale)
{
static const mbstate_t initial;
- static mbstate_t mbs;
size_t rval;
+ FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
- mbs = initial;
+ locale->wctomb = initial;
return (0);
}
- if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1)
+ if ((rval = XLOCALE_CTYPE(locale)->__wcrtomb(s, wchar, &locale->wctomb)) == (size_t)-1)
return (-1);
return ((int)rval);
}
+int
+wctomb(char *s, wchar_t wchar)
+{
+ return wctomb_l(s, wchar, __get_locale());
+}
diff --git a/lib/libc/locale/wctrans.c b/lib/libc/locale/wctrans.c
index 6813e33..0831146 100644
--- a/lib/libc/locale/wctrans.c
+++ b/lib/libc/locale/wctrans.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <string.h>
#include <wctype.h>
+#include "xlocale_private.h"
enum {
_WCT_ERROR = 0,
@@ -38,15 +44,14 @@ enum {
};
wint_t
-towctrans(wint_t wc, wctrans_t desc)
+towctrans_l(wint_t wc, wctrans_t desc, locale_t locale)
{
-
switch (desc) {
case _WCT_TOLOWER:
- wc = towlower(wc);
+ wc = towlower_l(wc, locale);
break;
case _WCT_TOUPPER:
- wc = towupper(wc);
+ wc = towupper_l(wc, locale);
break;
case _WCT_ERROR:
default:
@@ -56,9 +61,18 @@ towctrans(wint_t wc, wctrans_t desc)
return (wc);
}
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+ return towctrans_l(wc, desc, __get_locale());
+}
+/*
+ * wctrans() calls this will a 0 locale. If this is ever modified to actually
+ * use the locale, wctrans() must be modified to call __get_locale().
+ */
wctrans_t
-wctrans(const char *charclass)
+wctrans_l(const char *charclass, locale_t locale)
{
struct {
const char *name;
@@ -78,3 +92,10 @@ wctrans(const char *charclass)
errno = EINVAL;
return (ccls[i].trans);
}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ return wctrans_l(charclass, 0);
+}
+
diff --git a/lib/libc/locale/wctype.c b/lib/libc/locale/wctype.c
index f94a735..5ffbb79 100644
--- a/lib/libc/locale/wctype.c
+++ b/lib/libc/locale/wctype.c
@@ -2,6 +2,11 @@
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,17 +35,27 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <string.h>
#include <wctype.h>
+#include <xlocale.h>
#undef iswctype
int
iswctype(wint_t wc, wctype_t charclass)
{
-
return (__istype(wc, charclass));
}
+int
+iswctype_l(wint_t wc, wctype_t charclass, locale_t locale)
+{
+ return __istype_l(wc, charclass, locale);
+}
+/*
+ * IMPORTANT: The 0 in the call to this function in wctype() must be changed to
+ * __get_locale() if wctype_l() is ever modified to actually use the locale
+ * parameter.
+ */
wctype_t
-wctype(const char *property)
+wctype_l(const char *property, locale_t locale)
{
static const struct {
const char *name;
@@ -72,3 +87,8 @@ wctype(const char *property)
return (props[i].mask);
}
+
+wctype_t wctype(const char *property)
+{
+ return wctype_l(property, 0);
+}
diff --git a/lib/libc/locale/wcwidth.c b/lib/libc/locale/wcwidth.c
index 7a5d2ed..9e74217 100644
--- a/lib/libc/locale/wcwidth.c
+++ b/lib/libc/locale/wcwidth.c
@@ -10,6 +10,11 @@
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,12 +44,18 @@
__FBSDID("$FreeBSD$");
#include <wchar.h>
+#include <wctype.h>
+#include <xlocale.h>
#undef wcwidth
int
wcwidth(wchar_t wc)
{
-
return (__wcwidth(wc));
}
+int
+wcwidth_l(wchar_t wc, locale_t locale)
+{
+ return (__wcwidth_l(wc, locale));
+}
diff --git a/lib/libc/locale/xlocale.3 b/lib/libc/locale/xlocale.3
new file mode 100644
index 0000000..ecfbb4c
--- /dev/null
+++ b/lib/libc/locale/xlocale.3
@@ -0,0 +1,270 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17 2011
+.Dt XLOCALE 3
+.Os
+.Sh NAME
+.Nm xlocale
+.Nd Thread-safe extended locale support.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Sh DESCRIPTION
+The extended locale support includes a set of functions for setting
+thread-local locales, as well convenience functions for performing locale-aware
+calls with a specified locale.
+.Pp
+The core of the xlocale API is the
+.Fa locale_t
+type. This is an opaque type encapsulating a locale. Instances of this can be
+either set as the locale for a specific thread or passed directly to the
+.Fa _l
+suffixed variants of various standard C functions. Two special
+.Fa locale_t
+values are available:
+.Bl -bullet -offset indent
+.It
+NULL refers to the current locale for the thread, or to the global locale if no
+locale has been set for this thread.
+.It
+LC_GLOBAL_LOCALE refers to the global locale.
+.El
+.Pp
+The global locale is the locale set with the
+.Xr setlocale 3
+function.
+.Sh CAVEATS
+The
+.Xr setlocale 3
+function, and others in the family, refer to the global locale. Other
+functions that depend on the locale, however, will take the thread-local locale
+if one has been set. This means that the idiom of setting the locale using
+.Xr setlocale 3 ,
+calling a locale-dependent function, and then restoring the locale will not
+have the expected behavior if the current thread has had a locale set using
+.Xr uselocale 3 .
+You should avoid this idiom and prefer to use the
+.Fa _l
+suffixed versions instead.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Sh CONVENIENCE FUNCTIONS
+The xlocale API includes a number of
+.Fa _l
+suffixed convenience functions. These are variants of standard C functions
+that have been modified to take an explicit
+.Fa locale_t
+parameter as the final argument or, in the case of variadic functions, as an
+additional argument directly before the format string. Each of these functions
+accepts either NULL or LC_GLOBAL_LOCALE. In these functions, NULL refers to
+the C locale, rather than the thread's current locale. If you wish to use the
+thread's current locale, then use the unsuffixed version of the function.
+.Pp
+These functions are exposed by including
+.In xlocale.h
+.Em after
+including the relevant headers for the standard variant. For example, the
+.Xr strtol_l 3
+function is exposed by including
+.In xlocale.h
+after
+.In stdlib.h ,
+which defines
+.Xr strtol 3 .
+.Pp
+For reference, a complete list of the locale-aware functions that are available
+in this form, along with the headers that expose them, is provided here:
+.Pp
+.Bl -tag -width "<monetary.h> "
+.It In wctype.h
+.Xr iswalnum_l 3 ,
+.Xr iswalpha_l 3 ,
+.Xr iswcntrl_l 3 ,
+.Xr iswctype_l 3 ,
+.Xr iswdigit_l 3 ,
+.Xr iswgraph_l 3 ,
+.Xr iswlower_l 3 ,
+.Xr iswprint_l 3 ,
+.Xr iswpunct_l 3 ,
+.Xr iswspace_l 3 ,
+.Xr iswupper_l 3 ,
+.Xr iswxdigit_l 3 ,
+.Xr towlower_l 3 ,
+.Xr towupper_l 3 ,
+.Xr wctype_l 3 ,
+.It In ctype.h
+.Xr digittoint_l 3 ,
+.Xr isalnum_l 3 ,
+.Xr isalpha_l 3 ,
+.Xr isblank_l 3 ,
+.Xr iscntrl_l 3 ,
+.Xr isdigit_l 3 ,
+.Xr isgraph_l 3 ,
+.Xr ishexnumber_l 3 ,
+.Xr isideogram_l 3 ,
+.Xr islower_l 3 ,
+.Xr isnumber_l 3 ,
+.Xr isphonogram_l 3 ,
+.Xr isprint_l 3 ,
+.Xr ispunct_l 3 ,
+.Xr isrune_l 3 ,
+.Xr isspace_l 3 ,
+.Xr isspecial_l 3 ,
+.Xr isupper_l 3 ,
+.Xr isxdigit_l 3 ,
+.Xr tolower_l 3 ,
+.Xr toupper_l 3
+.It In inttypes.h
+.Xr strtoimax_l 3 ,
+.Xr strtoumax_l 3 ,
+.Xr wcstoimax_l 3 ,
+.Xr wcstoumax_l 3
+.It In langinfo.h
+.Xr nl_langinfo_l 3
+.It In monetary.h
+.Xr strfmon_l 3
+.It In stdio.h
+.Xr asprintf_l 3 ,
+.Xr fprintf_l 3 ,
+.Xr fscanf_l 3 ,
+.Xr printf_l 3 ,
+.Xr scanf_l 3 ,
+.Xr snprintf_l 3 ,
+.Xr sprintf_l 3 ,
+.Xr sscanf_l 3 ,
+.Xr vasprintf_l 3 ,
+.Xr vfprintf_l 3 ,
+.Xr vfscanf_l 3 ,
+.Xr vprintf_l 3 ,
+.Xr vscanf_l 3 ,
+.Xr vsnprintf_l 3 ,
+.Xr vsprintf_l 3 ,
+.Xr vsscanf_l 3
+.It In stdlib.h
+.Xr atof_l 3 ,
+.Xr atoi_l 3 ,
+.Xr atol_l 3 ,
+.Xr atoll_l 3 ,
+.Xr mblen_l 3 ,
+.Xr mbstowcs_l 3 ,
+.Xr mbtowc_l 3 ,
+.Xr strtod_l 3 ,
+.Xr strtof_l 3 ,
+.Xr strtol_l 3 ,
+.Xr strtold_l 3 ,
+.Xr strtoll_l 3 ,
+.Xr strtoq_l 3 ,
+.Xr strtoul_l 3 ,
+.Xr strtoull_l 3 ,
+.Xr strtouq_l 3 ,
+.Xr wcstombs_l 3 ,
+.Xr wctomb_l 3
+.It In string.h
+.Xr strcoll_l 3 ,
+.Xr strxfrm_l 3 ,
+.Xr strcasecmp_l 3 ,
+.Xr strcasestr_l 3 ,
+.Xr strncasecmp_l 3
+.It In time.h
+.Xr strftime_l 3
+.Xr strptime_l 3
+.It In wchar.h
+.Xr btowc_l 3 ,
+.Xr fgetwc_l 3 ,
+.Xr fgetws_l 3 ,
+.Xr fputwc_l 3 ,
+.Xr fputws_l 3 ,
+.Xr fwprintf_l 3 ,
+.Xr fwscanf_l 3 ,
+.Xr getwc_l 3 ,
+.Xr getwchar_l 3 ,
+.Xr mbrlen_l 3 ,
+.Xr mbrtowc_l 3 ,
+.Xr mbsinit_l 3 ,
+.Xr mbsnrtowcs_l 3 ,
+.Xr mbsrtowcs_l 3 ,
+.Xr putwc_l 3 ,
+.Xr putwchar_l 3 ,
+.Xr swprintf_l 3 ,
+.Xr swscanf_l 3 ,
+.Xr ungetwc_l 3 ,
+.Xr vfwprintf_l 3 ,
+.Xr vfwscanf_l 3 ,
+.Xr vswprintf_l 3 ,
+.Xr vswscanf_l 3 ,
+.Xr vwprintf_l 3 ,
+.Xr vwscanf_l 3 ,
+.Xr wcrtomb_l 3 ,
+.Xr wcscoll_l 3 ,
+.Xr wcsftime_l 3 ,
+.Xr wcsnrtombs_l 3 ,
+.Xr wcsrtombs_l 3 ,
+.Xr wcstod_l 3 ,
+.Xr wcstof_l 3 ,
+.Xr wcstol_l 3 ,
+.Xr wcstold_l 3 ,
+.Xr wcstoll_l 3 ,
+.Xr wcstoul_l 3 ,
+.Xr wcstoull_l 3 ,
+.Xr wcswidth_l 3 ,
+.Xr wcsxfrm_l 3 ,
+.Xr wctob_l 3 ,
+.Xr wcwidth_l 3 ,
+.Xr wprintf_l 3 ,
+.Xr wscanf_l 3
+.It In wctype.h
+.Xr iswblank_l 3 ,
+.Xr iswhexnumber_l 3 ,
+.Xr iswideogram_l 3 ,
+.Xr iswnumber_l 3 ,
+.Xr iswphonogram_l 3 ,
+.Xr iswrune_l 3 ,
+.Xr iswspecial_l 3 ,
+.Xr nextwctype_l 3 ,
+.Xr towctrans_l 3 ,
+.Xr wctrans_l 3
+.It In xlocale.h
+.Xr localeconv_l 3
+.El
+.Sh STANDARDS
+The functions
+conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The xlocale APIs first appeared in Darwin 8.0. This implementation was
+written by David Chisnall, under sponsorship from the FreeBSD Foundation and
+first appeared in
+.Fx 9.1 .
diff --git a/lib/libc/locale/xlocale.c b/lib/libc/locale/xlocale.c
new file mode 100644
index 0000000..f14f952
--- /dev/null
+++ b/lib/libc/locale/xlocale.c
@@ -0,0 +1,334 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions * are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include "libc_private.h"
+#include "xlocale_private.h"
+
+/**
+ * Each locale loader declares a global component. This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+/*
+ * And another version for the statically-allocated C locale. We only have
+ * components for the parts that are expected to be sensible.
+ */
+extern struct xlocale_component __xlocale_C_collate;
+extern struct xlocale_component __xlocale_C_ctype;
+/*
+ * Private functions in setlocale.c.
+ */
+const char *
+__get_locale_env(int category);
+int
+__detect_path_locale(void);
+
+struct _xlocale __xlocale_global_locale = {
+ {0},
+ {
+ &__xlocale_global_collate,
+ &__xlocale_global_ctype,
+ &__xlocale_global_monetary,
+ &__xlocale_global_numeric,
+ &__xlocale_global_time,
+ &__xlocale_global_messages
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+struct _xlocale __xlocale_C_locale = {
+ {0},
+ {
+ &__xlocale_C_collate,
+ &__xlocale_C_ctype,
+ 0, 0, 0, 0
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+ __collate_load,
+ __ctype_load,
+ __monetary_load,
+ __numeric_load,
+ __time_load,
+ __messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void init_key(void)
+{
+ pthread_key_create(&locale_info_key, xlocale_release);
+ pthread_setspecific(locale_info_key, (void*)42);
+ if (pthread_getspecific(locale_info_key) == (void*)42) {
+ pthread_setspecific(locale_info_key, 0);
+ } else {
+ fake_tls = 1;
+ }
+ __detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+ _once(&once_control, init_key);
+
+ return (fake_tls ? thread_local_locale :
+ pthread_getspecific(locale_info_key));
+}
+
+locale_t
+__get_locale(void)
+{
+ locale_t l = get_thread_locale();
+ return (l ? l : &__xlocale_global_locale);
+
+}
+
+static void
+set_thread_locale(locale_t loc)
+{
+ pthread_once(&once_control, init_key);
+
+ if (NULL != loc) {
+ xlocale_retain((struct xlocale_refcounted*)loc);
+ }
+ locale_t old = pthread_getspecific(locale_info_key);
+ if ((NULL != old) && (loc != old)) {
+ xlocale_release((struct xlocale_refcounted*)old);
+ }
+ if (fake_tls) {
+ thread_local_locale = loc;
+ } else {
+ pthread_setspecific(locale_info_key, loc);
+ }
+}
+
+/**
+ * Clean up a locale, once its reference count reaches zero. This function is
+ * called by xlocale_release(), it should not be called directly.
+ */
+static void
+destruct_locale(void *l)
+{
+ locale_t loc = l;
+ for (int type=0 ; type<XLC_LAST ; type++) {
+ if (loc->components[type]) {
+ xlocale_release(loc->components[type]);
+ }
+ }
+ if (loc->csym) {
+ free(loc->csym);
+ }
+ free(l);
+}
+
+/**
+ * Allocates a new, uninitialised, locale.
+ */
+static locale_t
+alloc_locale(void)
+{
+ locale_t new = calloc(sizeof(struct _xlocale), 1);
+ new->header.destructor = destruct_locale;
+ new->monetary_locale_changed = 1;
+ new->numeric_locale_changed = 1;
+ return (new);
+}
+static void
+copyflags(locale_t new, locale_t old)
+{
+ new->using_monetary_locale = old->using_monetary_locale;
+ new->using_numeric_locale = old->using_numeric_locale;
+ new->using_time_locale = old->using_time_locale;
+ new->using_messages_locale = old->using_messages_locale;
+}
+
+static int dupcomponent(int type, locale_t base, locale_t new)
+{
+ /* Always copy from the global locale, since it has mutable components. */
+ struct xlocale_component *src = base->components[type];
+ if (&__xlocale_global_locale == base) {
+ new->components[type] = constructors[type](src->locale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, src->locale, ENCODING_LEN);
+ }
+ } else {
+ new->components[type] = xlocale_retain(base->components[type]);
+ }
+ return (0 != new->components[type]);
+}
+
+/*
+ * Public interfaces. These are the five public functions described by the
+ * xlocale interface.
+ */
+
+locale_t newlocale(int mask, const char *locale, locale_t base)
+{
+ int type;
+ const char *realLocale = locale;
+ int useenv = 0;
+ int success = 1;
+
+ _once(&once_control, init_key);
+
+ locale_t new = alloc_locale();
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ if (NULL == locale) {
+ realLocale = "C";
+ } else if ('\0' == locale[0]) {
+ useenv = 1;
+ }
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ if (mask & 1) {
+ if (useenv) {
+ realLocale = __get_locale_env(type);
+ }
+ new->components[type] = constructors[type](realLocale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, realLocale, ENCODING_LEN);
+ } else {
+ success = 0;
+ break;
+ }
+ } else {
+ if (!dupcomponent(type, base, new)) {
+ success = 0;
+ break;
+ }
+ }
+ mask >>= 1;
+ }
+ if (0 == success) {
+ xlocale_release(new);
+ new = NULL;
+ }
+
+ return (new);
+}
+
+locale_t duplocale(locale_t base)
+{
+ locale_t new = alloc_locale();
+ int type;
+
+ _once(&once_control, init_key);
+
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ dupcomponent(type, base, new);
+ }
+
+ return (new);
+}
+
+/*
+ * Free a locale_t. This is quite a poorly named function. It actually
+ * disclaims a reference to a locale_t, rather than freeing it.
+ */
+int
+freelocale(locale_t loc)
+{
+ /* Fail if we're passed something that isn't a locale. */
+ if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) {
+ return (-1);
+ }
+ /* If we're passed the global locale, pretend that we freed it but don't
+ * actually do anything. */
+ if (&__xlocale_global_locale == loc) {
+ return (0);
+ }
+ xlocale_release(loc);
+ return (0);
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc)
+{
+ int type = ffs(mask) - 1;
+ FIX_LOCALE(loc);
+ if (type >= XLC_LAST)
+ return (NULL);
+ if (loc->components[type])
+ return (loc->components[type]->locale);
+ return "C";
+}
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t uselocale(locale_t loc)
+{
+ locale_t old = get_thread_locale();
+ if (NULL != loc) {
+ if (LC_GLOBAL_LOCALE == loc) {
+ loc = NULL;
+ }
+ set_thread_locale(loc);
+ }
+ return (old ? old : LC_GLOBAL_LOCALE);
+}
+
diff --git a/lib/libc/locale/xlocale_private.h b/lib/libc/locale/xlocale_private.h
new file mode 100644
index 0000000..272d15e
--- /dev/null
+++ b/lib/libc/locale/xlocale_private.h
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include "setlocale.h"
+
+enum {
+ XLC_COLLATE = 0,
+ XLC_CTYPE,
+ XLC_MONETARY,
+ XLC_NUMERIC,
+ XLC_TIME,
+ XLC_MESSAGES,
+ XLC_LAST
+};
+
+
+/**
+ * Header used for objects that are reference counted. Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure. Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0. When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+ /** Number of references to this component. */
+ long retain_count;
+ /** Function used to destroy this component, if one is required*/
+ void(*destructor)(void*);
+};
+/**
+ * Header for a locale component. All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+ struct xlocale_refcounted header;
+ /** Name of the locale used for this component. */
+ char locale[ENCODING_LEN+1];
+};
+
+/**
+ * xlocale structure, stores per-thread locale information.
+ */
+struct _xlocale {
+ struct xlocale_refcounted header;
+ /** Components for the locale. */
+ struct xlocale_component *components[XLC_LAST];
+ /** Flag indicating if components[XLC_MONETARY] has changed since the last
+ * call to localeconv_l() with this locale. */
+ int monetary_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MONETARY (1), or if it should use the C default instead (0). */
+ int using_monetary_locale;
+ /** Flag indicating if components[XLC_NUMERIC] has changed since the last
+ * call to localeconv_l() with this locale. */
+ int numeric_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_NUMERIC (1), or if it should use the C default instead (0). */
+ int using_numeric_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_TIME (1), or if it should use the C default instead (0). */
+ int using_time_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MESSAGES (1), or if it should use the C default instead (0). */
+ int using_messages_locale;
+ /** The structure to be returned from localeconv_l() for this locale. */
+ struct lconv lconv;
+ /** Persistent state used by mblen() calls. */
+ __mbstate_t mblen;
+ /** Persistent state used by mbrlen() calls. */
+ __mbstate_t mbrlen;
+ /** Persistent state used by mbrtowc() calls. */
+ __mbstate_t mbrtowc;
+ /** Persistent state used by mbsnrtowcs() calls. */
+ __mbstate_t mbsnrtowcs;
+ /** Persistent state used by mbsrtowcs() calls. */
+ __mbstate_t mbsrtowcs;
+ /** Persistent state used by mbtowc() calls. */
+ __mbstate_t mbtowc;
+ /** Persistent state used by wcrtomb() calls. */
+ __mbstate_t wcrtomb;
+ /** Persistent state used by wcsnrtombs() calls. */
+ __mbstate_t wcsnrtombs;
+ /** Persistent state used by wcsrtombs() calls. */
+ __mbstate_t wcsrtombs;
+ /** Persistent state used by wctomb() calls. */
+ __mbstate_t wctomb;
+ /** Buffer used by nl_langinfo_l() */
+ char *csym;
+};
+
+/**
+ * Increments the reference count of a reference-counted structure.
+ */
+__attribute__((unused)) static void*
+xlocale_retain(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ atomic_add_long(&(obj->retain_count), 1);
+ return (val);
+}
+/**
+ * Decrements the reference count of a reference-counted structure, freeing it
+ * if this is the last reference, calling its destructor if it has one.
+ */
+__attribute__((unused)) static void
+xlocale_release(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ long count = atomic_fetchadd_long(&(obj->retain_count), -1) - 1;
+ if (count < 0) {
+ if (0 != obj->destructor) {
+ obj->destructor(obj);
+ }
+ }
+}
+
+/**
+ * Load functions. Each takes the name of a locale and a pointer to the data
+ * to be initialised as arguments. Two special values are allowed for the
+ */
+extern void* __collate_load(const char*, locale_t);
+extern void* __ctype_load(const char*, locale_t);
+extern void* __messages_load(const char*, locale_t);
+extern void* __monetary_load(const char*, locale_t);
+extern void* __numeric_load(const char*, locale_t);
+extern void* __time_load(const char*, locale_t);
+
+extern struct _xlocale __xlocale_global_locale;
+extern struct _xlocale __xlocale_C_locale;
+
+/**
+ * Returns the current locale for this thread, or the global locale if none is
+ * set. The caller does not have to free the locale. The return value from
+ * this call is not guaranteed to remain valid after the locale changes. As
+ * such, this should only be called within libc functions.
+ */
+locale_t __get_locale(void);
+
+/**
+ * Two magic values are allowed for locale_t objects. NULL and -1. This
+ * function maps those to the real locales that they represent.
+ */
+static inline locale_t get_real_locale(locale_t locale)
+{
+ switch ((intptr_t)locale) {
+ case 0: return (&__xlocale_C_locale);
+ case -1: return (&__xlocale_global_locale);
+ default: return (locale);
+ }
+}
+
+/**
+ * Replace a placeholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
OpenPOWER on IntegriCloud