Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Sep 2011 20:28:54 +0100
From:      David Chisnall <theraven@theravensnest.org>
To:        hackers@freebsd.org
Subject:   Re: xlocale patch
Message-ID:  <C57AA994-0CB1-4875-8DB4-7D728B3E62AB@theravensnest.org>
In-Reply-To: <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org>
References:  <DCAF3E3D-B2E1-40EF-B654-23625A17C3F1@theravensnest.org> <20110919172214.GJ33993@hoeg.nl> <3A86EAEA-1861-43A6-95DC-FC700BE0E507@theravensnest.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

And here's an updated version of the patch.  I've fixed some other bugs, =
including where wcstod() and wcstodl() in trunk return the wrong value =
for any input string starting with spaces, wchar.h's violation of POSIX =
by not declaring FILE, and a few C++ incompatibilities in other headers =
(e.g. putchar being a macro, which breaks things like =
std::putchar(foo)).  All of my libcxxrt and libc++ changes have now been =
pushed upstream, so this should now be repeatable. =20

The libunwind port still has an irritating bug in the header, where the =
extern "C" {} block ends with a semicolon, which causes it to be =
rejected in any C++ program, but with that fixed you can compile =
libcxxrt (I used cmake .. -DCMAKE_CXX_FLAGS=3D"-I/usr/local/include =
-nostdlib -g" - hopefully I'll work out how to make CMake add these =
flags automatically soon...).  Libc++ should build out of the box with =
cmake.

The results are now:

****************************************************
Results for /root/libcxx/test:
using clang version 3.0 (trunk 140248)
Target: x86_64-unknown-freebsd9.0
Thread model: posix
with -std=3Dc++0x -stdlib=3Dlibc++ -pthread -I/root/libcxx/include =
-L/root/libcxx/build/lib
----------------------------------------------------
sections without tests   : 1
sections with failures   : 16
sections without failures: 1047
                       +   ----
total number of sections : 1064
----------------------------------------------------
number of tests failed   : 53
number of tests passed   : 4271
                       +   ----
total number of tests    : 4324
****************************************************

For comparison, the results on OS X are:
****************************************************
Results for /test:
using Apple clang version 3.0 (tags/Apple/clang-211.10.1) (based on LLVM =
3.0svn)
Target: x86_64-apple-darwin11.1.0
Thread model: posix
with -std=3Dc++0x -stdlib=3Dlibc++ =20
----------------------------------------------------
sections without tests   : 1
sections with failures   : 17
sections without failures: 1046
                       +   ----
total number of sections : 1064
----------------------------------------------------
number of tests failed   : 71
number of tests passed   : 4253
                       +   ----
total number of tests    : 4324
****************************************************

The remaining failures on FreeBSD are:

- 27 caused by clang not fully supporting the atomic operations yet
- 3 caused by clang not fully supporting the C++11 type-trait intrinsics
- 20 that I don't think are real failures - they're caused by the VM =
where I'm running the tests not having sufficiently fine-grained time =
reporting for the thread operation timeout tests to work properly
- 1 is caused by FreeBSD lacking the C1x quick_exit() APIs.
- 2 caused by FreeBSD lacking the uchar.h header

The first 30 of these should be fixed in clang soon.  The next 20 are =
probably not real bugs at all.  The remaining 3 are fairly minor.

David

--Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD
Content-Disposition: attachment;
	filename=xlocale.diff
Content-Type: application/octet-stream; x-unix-mode=0644; name="xlocale.diff"
Content-Transfer-Encoding: 7bit

Index: include/wctype.h
===================================================================
--- include/wctype.h	(revision 225653)
+++ include/wctype.h	(working copy)
@@ -89,6 +89,7 @@
 #endif
 __END_DECLS
 
+#ifndef __cplusplus
 #define	iswalnum(wc)		__istype((wc), _CTYPE_A|_CTYPE_D)
 #define	iswalpha(wc)		__istype((wc), _CTYPE_A)
 #define	iswblank(wc)		__istype((wc), _CTYPE_B)
@@ -113,6 +114,7 @@
 #define	iswphonogram(wc)	__istype((wc), _CTYPE_Q)
 #define	iswrune(wc)		__istype((wc), 0xFFFFFF00L)
 #define	iswspecial(wc)		__istype((wc), _CTYPE_T)
-#endif
+#endif /* __BSD_VISIBLE */
+#endif /* __cplusplus */
 
 #endif		/* _WCTYPE_H_ */
Index: include/Makefile
===================================================================
--- include/Makefile	(revision 225653)
+++ include/Makefile	(working copy)
@@ -23,8 +23,9 @@
 	stdbool.h stddef.h stdio.h stdlib.h string.h stringlist.h \
 	strings.h sysexits.h tar.h termios.h tgmath.h \
 	time.h timeconv.h timers.h ttyent.h \
+	uchar.h\
 	ulimit.h unistd.h utime.h utmpx.h uuid.h varargs.h vis.h \
-	wchar.h wctype.h wordexp.h
+	wchar.h wctype.h wordexp.h xlocale.h _xlocale_ctype.h
 
 MHDRS=	float.h floatingpoint.h stdarg.h
 
Index: include/xlocale.h
===================================================================
--- include/xlocale.h	(revision 0)
+++ include/xlocale.h	(revision 0)
@@ -0,0 +1,256 @@
+/*-
+ * 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.
+ */
+
+#ifndef _XLOCALE_H_
+#define _XLOCALE_H_
+
+#include <locale.h>
+
+__BEGIN_DECLS
+
+/*
+ * Extended locale versions of the locale-aware functions from string.h.
+ *
+ * Include <string.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STRING_H_
+int strcoll_l(const char *, const char *, locale_t);
+size_t strxfrm_l(char *, const char *, size_t, locale_t);
+int strcasecmp_l(const char *, const char *, locale_t);
+char *strcasestr_l(const char *, const char *, locale_t);
+int strncasecmp_l(const char *, const char *, size_t, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from inttypes.h.
+ *
+ * Include <inttypes.h> before <xlocale.h> to expose these.
+ */
+#ifdef _INTTYPES_H_
+intmax_t 
+strtoimax_l(const char * __restrict, char ** __restrict, int, locale_t);
+uintmax_t
+strtoumax_l(const char * __restrict, char ** __restrict, int, locale_t);
+intmax_t 
+wcstoimax_l(const wchar_t * __restrict, wchar_t ** __restrict, int , locale_t);
+uintmax_t
+wcstoumax_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from monetary.h.
+ *
+ * Include <monetary.h> before <xlocale.h> to expose these.
+ */
+#ifdef _MONETARY_H_
+ssize_t strfmon_l(char *, size_t, locale_t, const char *, ...)
+#	if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+	__attribute__((__format__ (__strfmon__, 4, 5)))
+#	endif
+	;
+#endif
+
+/*
+ * Extended locale versions of the locale-aware functions from stdlib.h.
+ *
+ * Include <stdlib.h> before <xlocale.h> to expose these.
+ */
+#ifdef _STDLIB_H_
+double atof_l(const char *, locale_t);
+int atoi_l(const char *, locale_t);
+long atol_l(const char *, locale_t);
+long long atoll_l(const char *, locale_t);
+int mblen_l(const char *, size_t, locale_t);
+size_t
+mbstowcs_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+int
+mbtowc_l(wchar_t * __restrict, const char * __restrict, size_t, locale_t);
+double strtod_l(const char *, char **, locale_t);
+float strtof_l(const char *, char **, locale_t);
+long strtol_l(const char *, char **, int, locale_t);
+long double strtold_l(const char *, char **, locale_t);
+long long strtoll_l(const char *, char **, int, locale_t);
+unsigned long strtoul_l(const char *, char **, int, locale_t);
+unsigned long long strtoull_l(const char *, char **, int, locale_t);
+size_t
+wcstombs_l(char * __restrict, const wchar_t * __restrict, size_t, locale_t);
+int wctomb_l(char *, wchar_t, locale_t);
+
+int ___mb_cur_max_l(locale_t);
+#define MB_CUR_MAX_L(x) (___mb_cur_max_l(x))
+
+#endif
+/*
+ * Extended locale versions of the locale-aware functions from time.h.
+ *
+ * Include <time.h> before <xlocale.h> to expose these.
+ */
+#ifdef _TIME_H_
+size_t
+strftime_l(char * __restrict, size_t, const char * __restrict, const
+           struct tm * __restrict, locale_t)
+#	if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+	__attribute__((__format__ (__strftime__, 3, 0)))
+#	endif
+	;
+char *
+strptime_l(const char * __restrict, const char * __restrict,
+           struct tm * __restrict, locale_t);
+#endif
+#ifdef _LANGINFO_H_
+char *nl_langinfo_l(nl_item, locale_t);
+#endif
+#ifdef _CTYPE_H_
+#include <_xlocale_ctype.h>
+#endif
+#ifdef _WCTYPE_H_
+#define XLOCALE_WCTYPES 1
+#include <_xlocale_ctype.h>
+#endif
+
+#ifdef _STDIO_H_
+int fprintf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+		__printflike(3, 4);
+int fscanf_l(FILE * __restrict, locale_t, const char * __restrict, ...)
+		__scanflike(3, 4);
+int printf_l(locale_t, const char * __restrict, ...) __printflike(2, 3);
+int scanf_l(locale_t, const char * __restrict, ...) __scanflike(2, 3);
+int sprintf_l(char * __restrict, locale_t, const char * __restrict, ...)
+		__printflike(3, 4);
+int sscanf_l(const char * __restrict, locale_t, const char * __restrict, ...)
+		__scanflike(3, 4);
+int vfprintf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+int vprintf_l(locale_t, const char * __restrict, __va_list) __printflike(2, 0);
+int vsprintf_l(char * __restrict, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+
+int snprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+		...) __printflike(4, 5);
+int vfscanf_l(FILE * __restrict, locale_t, const char * __restrict, __va_list)
+		__scanflike(3, 0);
+int vscanf_l(locale_t, const char * __restrict, __va_list) __scanflike(2, 0);
+int vsnprintf_l(char * __restrict, size_t, locale_t, const char * __restrict,
+		va_list) __printflike(4, 0);
+int vsscanf_l(const char * __restrict, locale_t, const char * __restrict,
+		va_list) __scanflike(3, 0);
+int dprintf_l(int, locale_t, const char * __restrict, ...) __printflike(3, 4);
+int vdprintf_l(int, locale_t, const char * __restrict, __va_list)
+		__printflike(3, 0);
+int asprintf_l(char **, locale_t, const char *, ...) __printflike(3, 4);
+int vasprintf_l(char **, locale_t, const char *, __va_list) __printflike(3, 0);
+#endif
+#ifdef _WCHAR_H_
+wint_t btowc_l(int, locale_t);
+wint_t fgetwc_l(struct __sFILE *, locale_t);
+wchar_t *
+fgetws_l(wchar_t * __restrict, int, struct __sFILE * __restrict, locale_t);
+wint_t fputwc_l(wchar_t, struct __sFILE *, locale_t);
+int
+fputws_l(const wchar_t * __restrict, struct __sFILE * __restrict, locale_t);
+int
+fwprintf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+		...);
+int
+fwscanf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict, ...);
+wint_t getwc_l(struct __sFILE *, locale_t);
+wint_t getwchar_l(locale_t);
+size_t
+mbrlen_l(const char * __restrict, size_t, mbstate_t * __restrict, locale_t);
+size_t
+mbrtowc_l(wchar_t * __restrict, const char * __restrict, size_t,
+		mbstate_t * __restrict, locale_t);
+int mbsinit_l(const mbstate_t *, locale_t);
+size_t
+mbsrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t,
+		mbstate_t * __restrict, locale_t);
+wint_t putwc_l(wchar_t, struct __sFILE *, locale_t);
+wint_t putwchar_l(wchar_t, locale_t);
+int
+swprintf_l(wchar_t * __restrict, size_t n, locale_t,
+		const wchar_t * __restrict, ...);
+int
+swscanf_l(const wchar_t * __restrict, locale_t, const wchar_t * __restrict,
+		...);
+wint_t ungetwc_l(wint_t, struct __sFILE *, locale_t);
+int
+vfwprintf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+		__va_list);
+int
+vswprintf_l(wchar_t * __restrict, size_t n, locale_t,
+		const wchar_t * __restrict, __va_list);
+int vwprintf_l(locale_t, const wchar_t * __restrict, __va_list);
+size_t
+wcrtomb_l(char * __restrict, wchar_t, mbstate_t * __restrict, locale_t);
+int wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
+size_t
+wcsftime_l(wchar_t * __restrict, size_t, const wchar_t * __restrict,
+		const struct tm * __restrict, locale_t);
+size_t 
+wcsrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t,
+		mbstate_t * __restrict, locale_t);
+double wcstod_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long
+wcstol_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+unsigned long
+wcstoul_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+int wcswidth_l(const wchar_t *, size_t, locale_t);
+size_t
+wcsxfrm_l(wchar_t * __restrict, const wchar_t * __restrict, size_t, locale_t);
+int wctob_l(wint_t, locale_t);
+int wcwidth_l(wchar_t, locale_t);
+int wprintf_l(locale_t, const wchar_t * __restrict, ...);
+int wscanf_l(locale_t, const wchar_t * __restrict, ...);
+
+int
+vfwscanf_l(struct __sFILE * __restrict, locale_t, const wchar_t * __restrict,
+		__va_list);
+int vswscanf_l(const wchar_t * __restrict, locale_t,
+const wchar_t * __restrict, __va_list);
+int vwscanf_l(locale_t, const wchar_t * __restrict, __va_list);
+float wcstof_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long double
+wcstold_l(const wchar_t * __restrict, wchar_t ** __restrict, locale_t);
+long long
+wcstoll_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+unsigned long long
+wcstoull_l(const wchar_t * __restrict, wchar_t ** __restrict, int, locale_t);
+size_t
+mbsnrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t, size_t,
+		mbstate_t * __restrict, locale_t);
+int wcscasecmp_l(const wchar_t *, const wchar_t *, locale_t);
+int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t n, locale_t);
+size_t
+wcsnrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t, size_t,
+		mbstate_t * __restrict, locale_t);
+
+#endif
+
+struct lconv *
+localeconv_l(locale_t loc);
+__END_DECLS
+
+#endif
Index: include/locale.h
===================================================================
--- include/locale.h	(revision 225653)
+++ include/locale.h	(working copy)
@@ -79,4 +79,48 @@
 char		*setlocale(int, const char *);
 __END_DECLS
 
+#if __POSIX_VISIBLE >= 200809
+
+#define LC_COLLATE_MASK  (1<<0)
+#define LC_CTYPE_MASK    (1<<1)
+#define LC_MESSAGES_MASK (1<<2)
+#define LC_MONETARY_MASK (1<<3)
+#define LC_NUMERIC_MASK  (1<<4)
+#define LC_TIME_MASK     (1<<5)
+#define LC_ALL_MASK      (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | \
+		LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+
+#define LC_GLOBAL_LOCALE ((locale_t)-1)
+
+__BEGIN_DECLS
+
+typedef struct _xlocale *locale_t;
+/**
+ * Creates a new locale.
+ */
+locale_t newlocale(int mask, const char *locale, locale_t base);
+
+locale_t duplocale(locale_t base);
+/*
+ * 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);
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc);
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t uselocale(locale_t loc);
+
+__END_DECLS
+
+#endif /* __POSIX_VISIBLE >= 200809 */
+
+
 #endif /* _LOCALE_H_ */
Index: include/iso646.h
===================================================================
--- include/iso646.h	(revision 225653)
+++ include/iso646.h	(working copy)
@@ -29,6 +29,7 @@
 #ifndef _ISO646_H_
 #define	_ISO646_H_
 
+#ifndef __cplusplus
 #define	and	&&
 #define	and_eq	&=
 #define	bitand	&
@@ -40,5 +41,6 @@
 #define	or_eq	|=
 #define	xor	^
 #define	xor_eq	^=
+#endif
 
 #endif /* !_ISO646_H_ */
Index: include/_xlocale_ctype.h
===================================================================
--- include/_xlocale_ctype.h	(revision 0)
+++ include/_xlocale_ctype.h	(revision 0)
@@ -0,0 +1,160 @@
+/*-
+ * 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.
+ */
+#ifndef _XLOCALE_H_
+#error This header should only be included by <xlocale.h>, never directly.
+#endif
+
+#ifndef _XLOCALE_CTYPE_H_
+__BEGIN_DECLS
+unsigned long	___runetype_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t	___tolower_l(__ct_rune_t, locale_t) __pure;
+__ct_rune_t	___toupper_l(__ct_rune_t, locale_t) __pure;
+_RuneLocale *__runes_for_locale(locale_t, int*);
+__END_DECLS
+#endif
+
+#ifndef _XLOCALE_INLINE
+#	if __GNUC__ && !__GNUC_STDC_INLINE__
+#		define _XLOCALE_INLINE extern inline
+#	else
+#		define _XLOCALE_INLINE inline
+#	endif
+#endif
+
+#ifdef XLOCALE_WCTYPES
+static __inline int
+__maskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (_c < 0 || _c >= _CACHED_RUNES) ? ___runetype_l(_c, locale) :
+	       runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__istype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	return (!!__maskrune_l(_c, _f, locale));
+}
+
+#	define XLOCALE_ISCTYPE(fname, cat) \
+		_XLOCALE_INLINE int isw##fname##_l(int c, locale_t l)\
+		{ return __istype_l(c, cat, l); }
+#else
+static __inline int
+__sbmaskrune_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (_c < 0 || _c >= mb_sb_limit) ? 0 :
+	       runes->__runetype[_c] & _f;
+}
+
+static __inline int
+__sbistype_l(__ct_rune_t _c, unsigned long _f, locale_t locale)
+{
+	return (!!__sbmaskrune_l(_c, _f, locale));
+}
+
+#	define XLOCALE_ISCTYPE(fname, cat) \
+		_XLOCALE_INLINE int is##fname##_l(int c, locale_t l)\
+		{ return __sbistype_l(c, cat, l); }
+#endif
+
+XLOCALE_ISCTYPE(alnum, _CTYPE_A|_CTYPE_D)
+XLOCALE_ISCTYPE(alpha, _CTYPE_A)
+XLOCALE_ISCTYPE(blank, _CTYPE_B)
+XLOCALE_ISCTYPE(cntrl, _CTYPE_C)
+XLOCALE_ISCTYPE(digit, _CTYPE_D)
+XLOCALE_ISCTYPE(graph, _CTYPE_G)
+XLOCALE_ISCTYPE(hexnumber, _CTYPE_X)
+XLOCALE_ISCTYPE(ideogram, _CTYPE_I)
+XLOCALE_ISCTYPE(lower, _CTYPE_L)
+XLOCALE_ISCTYPE(number, _CTYPE_D)
+XLOCALE_ISCTYPE(phonogram, _CTYPE_Q)
+XLOCALE_ISCTYPE(print, _CTYPE_R)
+XLOCALE_ISCTYPE(punct, _CTYPE_P)
+XLOCALE_ISCTYPE(rune, 0xFFFFFF00L)
+XLOCALE_ISCTYPE(space, _CTYPE_S)
+XLOCALE_ISCTYPE(special, _CTYPE_T)
+XLOCALE_ISCTYPE(upper, _CTYPE_U)
+XLOCALE_ISCTYPE(xdigit, _CTYPE_X)
+#undef XLOCALE_ISCTYPE
+
+#ifdef XLOCALE_WCTYPES
+_XLOCALE_INLINE int towlower_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= _CACHED_RUNES) ? ___tolower_l(c, locale) :
+	       runes->__maplower[c];
+}
+_XLOCALE_INLINE int towupper_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= _CACHED_RUNES) ? ___toupper_l(c, locale) :
+	       runes->__mapupper[c];
+}
+_XLOCALE_INLINE int
+__wcwidth_l(__ct_rune_t _c, locale_t locale)
+{
+	unsigned int _x;
+
+	if (_c == 0)
+		return (0);
+	_x = (unsigned int)__maskrune_l(_c, _CTYPE_SWM|_CTYPE_R, locale);
+	if ((_x & _CTYPE_SWM) != 0)
+		return ((_x & _CTYPE_SWM) >> _CTYPE_SWS);
+	return ((_x & _CTYPE_R) != 0 ? 1 : -1);
+}
+int iswctype_l(wint_t wc, wctype_t charclass, locale_t locale);
+wctype_t wctype_l(const char *property, locale_t locale);
+wint_t towctrans_l(wint_t wc, wctrans_t desc, locale_t locale);
+wint_t nextwctype_l(wint_t wc, wctype_t wct, locale_t locale);
+wctrans_t wctrans_l(const char *charclass, locale_t locale);
+#undef XLOCALE_WCTYPES
+#else
+_XLOCALE_INLINE int digittoint_l(int c, locale_t locale)
+{ return __sbmaskrune_l((c), 0xFF, locale); }
+
+_XLOCALE_INLINE int tolower_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= mb_sb_limit) ? c :
+	       runes->__maplower[c];
+}
+_XLOCALE_INLINE int toupper_l(int c, locale_t locale)
+{
+	int mb_sb_limit;
+	_RuneLocale *runes = __runes_for_locale(locale, &mb_sb_limit);
+	return (c < 0 || c >= mb_sb_limit) ? c :
+	       runes->__mapupper[c];
+}
+#endif
Index: include/runetype.h
===================================================================
--- include/runetype.h	(revision 225653)
+++ include/runetype.h	(working copy)
@@ -83,8 +83,14 @@
 } _RuneLocale;
 
 #define	_RUNE_MAGIC_1	"RuneMagi"	/* Indicates version 0 of RuneLocale */
-
-extern _RuneLocale _DefaultRuneLocale;
+__BEGIN_DECLS
+extern const _RuneLocale _DefaultRuneLocale;
+__attribute__((deprecated))
 extern _RuneLocale *_CurrentRuneLocale;
+/* TODO: This is called quite a lot, so we should use a __thread variable when
+ * it's available. */
+extern _RuneLocale *__getCurrentRuneLocale(void);
+#define _CurrentRuneLocale (__getCurrentRuneLocale())
+__END_DECLS
 
 #endif	/* !_RUNETYPE_H_ */
Index: include/stdlib.h
===================================================================
--- include/stdlib.h	(revision 225653)
+++ include/stdlib.h	(working copy)
@@ -71,10 +71,11 @@
 
 #define	RAND_MAX	0x7fffffff
 
+__BEGIN_DECLS
 extern int __mb_cur_max;
-#define	MB_CUR_MAX	__mb_cur_max
+extern int ___mb_cur_max(void);
+#define	MB_CUR_MAX	(___mb_cur_max())
 
-__BEGIN_DECLS
 void	 abort(void) __dead2;
 int	 abs(int) __pure2;
 int	 atexit(void (*)(void));
Index: include/stdio.h
===================================================================
--- include/stdio.h	(revision 225653)
+++ include/stdio.h	(working copy)
@@ -107,7 +107,7 @@
  * inline functions.  To preserve ABI compat, these members must not
  * be disturbed.  These members are marked below with (*).
  */
-typedef	struct __sFILE {
+struct __sFILE {
 	unsigned char *_p;	/* (*) current position in (some) buffer */
 	int	_r;		/* (*) read space left for getc() */
 	int	_w;		/* (*) write space left for putc() */
@@ -144,8 +144,11 @@
 	int	_fl_count;	/* recursive lock count */
 	int	_orientation;	/* orientation for fwide() */
 	__mbstate_t _mbstate;	/* multibyte conversion state */
-} FILE;
-
+};
+#ifndef _STDFILE_DECLARED
+#define _STDFILE_DECLARED
+typedef struct __sFILE FILE;
+#endif
 #ifndef _STDSTREAM_DECLARED
 __BEGIN_DECLS
 extern FILE *__stdinp;
@@ -454,7 +457,6 @@
 	else
 		return (__swbuf(_c, _p));
 }
-#else
 /*
  * This has been tuned to generate reasonable code on the vax using pcc.
  */
@@ -467,6 +469,7 @@
 			__swbuf((int)(c), p) : \
 		(*(p)->_p = (c), (int)*(p)->_p++))
 #endif
+#ifndef __cplusplus
 
 #define	__sfeof(p)	(((p)->_flags & __SEOF) != 0)
 #define	__sferror(p)	(((p)->_flags & __SERR) != 0)
@@ -506,6 +509,7 @@
 #define	getchar_unlocked()	getc_unlocked(stdin)
 #define	putchar_unlocked(x)	putc_unlocked(x, stdout)
 #endif
+#endif /* __cplusplus */
 
 __END_DECLS
 #endif /* !_STDIO_H_ */
Index: include/wchar.h
===================================================================
--- include/wchar.h	(revision 225653)
+++ include/wchar.h	(working copy)
@@ -97,7 +97,10 @@
 #define	WEOF 	((wint_t)-1)
 #endif
 
-struct __sFILE;
+#ifndef _STDFILE_DECLARED
+#define _STDFILE_DECLARED
+typedef struct __sFILE FILE;
+#endif
 struct tm;
 
 __BEGIN_DECLS
Index: include/ctype.h
===================================================================
--- include/ctype.h	(revision 225653)
+++ include/ctype.h	(working copy)
@@ -80,6 +80,7 @@
 #endif
 __END_DECLS
 
+#ifndef __cplusplus
 #define	isalnum(c)	__sbistype((c), _CTYPE_A|_CTYPE_D)
 #define	isalpha(c)	__sbistype((c), _CTYPE_A)
 #define	iscntrl(c)	__sbistype((c), _CTYPE_C)
@@ -93,6 +94,7 @@
 #define	isxdigit(c)	__isctype((c), _CTYPE_X) /* ANSI -- locale independent */
 #define	tolower(c)	__sbtolower(c)
 #define	toupper(c)	__sbtoupper(c)
+#endif /* !__cplusplus */
 
 #if __XSI_VISIBLE
 /*
@@ -112,7 +114,7 @@
 #define	toascii(c)	((c) & 0x7F)
 #endif
 
-#if __ISO_C_VISIBLE >= 1999
+#if __ISO_C_VISIBLE >= 1999 && (!defined(__cplusplus))
 #define	isblank(c)	__sbistype((c), _CTYPE_B)
 #endif
 
Index: contrib/gdtoa/gdtoaimp.h
===================================================================
--- contrib/gdtoa/gdtoaimp.h	(revision 225653)
+++ contrib/gdtoa/gdtoaimp.h	(working copy)
@@ -201,6 +201,7 @@
 #include "namespace.h"
 #include <pthread.h>
 #include "un-namespace.h"
+#include "xlocale_private.h"
 
 #ifdef KR_headers
 #define Char char
@@ -526,10 +527,13 @@
 #define	strtoIx		__strtoIx
 #define	strtoIxL	__strtoIxL
 #define	strtord		__strtord
+#define	strtord_l		__strtord_l
 #define	strtordd	__strtordd
 #define	strtorf		__strtorf
 #define	strtorQ		__strtorQ
+#define	strtorQ_l		__strtorQ_l
 #define	strtorx		__strtorx
+#define	strtorx_l		__strtorx_l
 #define	strtorxL	__strtorxL
 #define	strtodI		__strtodI
 #define	strtopd		__strtopd
@@ -635,6 +639,7 @@
  extern Bigint *set_ones ANSI((Bigint*, int));
  extern char *strcp ANSI((char*, const char*));
  extern int strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+ extern int strtodg_l ANSI((CONST char*, char**, FPI*, Long*, ULong*, locale_t));
 
  extern int strtoId ANSI((CONST char *, char **, double *, double *));
  extern int strtoIdd ANSI((CONST char *, char **, double *, double *));
@@ -644,6 +649,7 @@
  extern int strtoIx ANSI((CONST char *, char **, void *, void *));
  extern int strtoIxL ANSI((CONST char *, char **, void *, void *));
  extern double strtod ANSI((const char *s00, char **se));
+ extern double strtod_l ANSI((const char *s00, char **se, locale_t));
  extern int strtopQ ANSI((CONST char *, char **, Void *));
  extern int strtopf ANSI((CONST char *, char **, float *));
  extern int strtopd ANSI((CONST char *, char **, double *));
@@ -651,10 +657,13 @@
  extern int strtopx ANSI((CONST char *, char **, Void *));
  extern int strtopxL ANSI((CONST char *, char **, Void *));
  extern int strtord ANSI((CONST char *, char **, int, double *));
+ extern int strtord_l ANSI((CONST char *, char **, int, double *, locale_t));
  extern int strtordd ANSI((CONST char *, char **, int, double *));
  extern int strtorf ANSI((CONST char *, char **, int, float *));
  extern int strtorQ ANSI((CONST char *, char **, int, void *));
+ extern int strtorQ_l ANSI((CONST char *, char **, int, void *, locale_t));
  extern int strtorx ANSI((CONST char *, char **, int, void *));
+ extern int strtorx_l ANSI((CONST char *, char **, int, void *, locale_t));
  extern int strtorxL ANSI((CONST char *, char **, int, void *));
  extern Bigint *sum ANSI((Bigint*, Bigint*));
  extern int trailz ANSI((Bigint*));
Index: contrib/gdtoa/strtopQ.c
===================================================================
--- contrib/gdtoa/strtopQ.c	(revision 225653)
+++ contrib/gdtoa/strtopQ.c	(working copy)
@@ -56,7 +56,7 @@
 strtopQ(CONST char *s, char **sp, void *V)
 #endif
 {
-	static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI };
+	static const FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI };
 	ULong bits[4];
 	Long exp;
 	int k;
Index: contrib/gdtoa/strtorQ.c
===================================================================
--- contrib/gdtoa/strtorQ.c	(revision 225653)
+++ contrib/gdtoa/strtorQ.c	(working copy)
@@ -103,9 +103,10 @@
 
  int
 #ifdef KR_headers
-strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorQ_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
 #else
-strtorQ(CONST char *s, char **sp, int rounding, void *L)
+strtorQ_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
 #endif
 {
 	static FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI };
@@ -120,7 +121,17 @@
 		fpi1.rounding = rounding;
 		fpi = &fpi1;
 		}
-	k = strtodg(s, sp, fpi, &exp, bits);
+	k = strtodg_l(s, sp, fpi, &exp, bits, locale);
 	ULtoQ((ULong*)L, bits, exp, k);
 	return k;
 	}
+
+ int
+#ifdef KR_headers
+strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+#else
+strtorQ(CONST char *s, char **sp, int rounding, void *L)
+#endif
+{
+	return strtorQ_l(s, sp, rounding, L, __get_locale());
+}
Index: contrib/gdtoa/strtodg.c
===================================================================
--- contrib/gdtoa/strtodg.c	(revision 225653)
+++ contrib/gdtoa/strtodg.c	(working copy)
@@ -34,6 +34,7 @@
 #ifdef USE_LOCALE
 #include "locale.h"
 #endif
+#include "xlocale_private.h"
 
  static CONST int
 fivesbits[] = {	 0,  3,  5,  7, 10, 12, 14, 17, 19, 21,
@@ -313,12 +314,12 @@
 	}
 
  int
-strtodg
+strtodg_l
 #ifdef KR_headers
-	(s00, se, fpi, exp, bits)
-	CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits;
+	(s00, se, fpi, exp, bits, l)
+	CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; locale_t l;
 #else
-	(CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits)
+	(CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits, locale_t l)
 #endif
 {
 	int abe, abits, asub;
@@ -334,14 +335,14 @@
 	Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
 #ifdef USE_LOCALE /*{{*/
 #ifdef NO_LOCALE_CACHE
-	char *decimalpoint = localeconv()->decimal_point;
+	char *decimalpoint = localeconv_l(l)->decimal_point;
 	int dplen = strlen(decimalpoint);
 #else
 	char *decimalpoint;
 	static char *decimalpoint_cache;
 	static int dplen;
 	if (!(s0 = decimalpoint_cache)) {
-		s0 = localeconv()->decimal_point;
+		s0 = localeconv_l(l)->decimal_point;
 		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
 			strcpy(decimalpoint_cache, s0);
 			s0 = decimalpoint_cache;
@@ -1063,3 +1064,15 @@
 		}
 	return irv;
 	}
+
+ int
+strtodg
+#ifdef KR_headers
+	(s00, se, fpi, exp, bits)
+	CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits;
+#else
+	(CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits)
+#endif
+{
+	return strtodg_l(s00, se, fpi, exp, bits, __get_locale());
+}
Index: contrib/gdtoa/strtord.c
===================================================================
--- contrib/gdtoa/strtord.c	(revision 225653)
+++ contrib/gdtoa/strtord.c	(working copy)
@@ -70,9 +70,10 @@
 
  int
 #ifdef KR_headers
-strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d;
+strtord_l(s, sp, rounding, d, locale) CONST char *s; char **sp; int rounding;
+double *d; locale_t locale;
 #else
-strtord(CONST char *s, char **sp, int rounding, double *d)
+strtord_l(CONST char *s, char **sp, int rounding, double *d, locale_t locale)
 #endif
 {
 	static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
@@ -87,7 +88,17 @@
 		fpi1.rounding = rounding;
 		fpi = &fpi1;
 		}
-	k = strtodg(s, sp, fpi, &exp, bits);
+	k = strtodg_l(s, sp, fpi, &exp, bits, locale);
 	ULtod((ULong*)d, bits, exp, k);
 	return k;
 	}
+ int
+#ifdef KR_headers
+strtord(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L;
+#else
+strtord(CONST char *s, char **sp, int rounding, double *d)
+#endif
+{
+	return strtord_l(s, sp, rounding, d, __get_locale());
+}
Index: contrib/gdtoa/strtod.c
===================================================================
--- contrib/gdtoa/strtod.c	(revision 225653)
+++ contrib/gdtoa/strtod.c	(working copy)
@@ -39,6 +39,7 @@
 #ifdef USE_LOCALE
 #include "locale.h"
 #endif
+#include "xlocale_private.h"
 
 #ifdef IEEE_Arith
 #ifndef NO_IEEE_Scale
@@ -82,11 +83,11 @@
 #endif /*}*/
 
  double
-strtod
+strtod_l
 #ifdef KR_headers
-	(s00, se) CONST char *s00; char **se;
+	(s00, se, l) CONST char *s00; char **se; locale_t l
 #else
-	(CONST char *s00, char **se)
+	(CONST char *s00, char **se, locale_t l)
 #endif
 {
 #ifdef Avoid_Underflow
@@ -108,14 +109,14 @@
 #endif
 #ifdef USE_LOCALE /*{{*/
 #ifdef NO_LOCALE_CACHE
-	char *decimalpoint = localeconv()->decimal_point;
+	char *decimalpoint = localeconv_l(l)->decimal_point;
 	int dplen = strlen(decimalpoint);
 #else
 	char *decimalpoint;
 	static char *decimalpoint_cache;
 	static int dplen;
 	if (!(s0 = decimalpoint_cache)) {
-		s0 = localeconv()->decimal_point;
+		s0 = localeconv_l(l)->decimal_point;
 		if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
 			strcpy(decimalpoint_cache, s0);
 			s0 = decimalpoint_cache;
@@ -168,7 +169,7 @@
 	if (*s == '0') {
 #ifndef NO_HEX_FP /*{*/
 		{
-		static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
+		static const FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
 		Long exp;
 		ULong bits[2];
 		switch(s[1]) {
@@ -295,7 +296,7 @@
 #ifdef INFNAN_CHECK
 			/* Check for Nan and Infinity */
 			ULong bits[2];
-			static FPI fpinan =	/* only 52 explicit bits */
+			static const FPI fpinan =	/* only 52 explicit bits */
 				{ 52, 1-1023-53+1, 2046-1023-53+1, 1, SI };
 			if (!decpt)
 			 switch(c) {
@@ -1074,3 +1075,13 @@
 	return sign ? -dval(&rv) : dval(&rv);
 	}
 
+ double
+strtod
+#ifdef KR_headers
+	(s00, se, l) CONST char *s00; char **se; locale_t
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+	return strtod_l(s00, se, __get_locale());
+}
Index: contrib/gdtoa/strtof.c
===================================================================
--- contrib/gdtoa/strtof.c	(revision 225653)
+++ contrib/gdtoa/strtof.c	(working copy)
@@ -32,15 +32,16 @@
 /* $FreeBSD$ */
 
 #include "gdtoaimp.h"
+#include "xlocale_private.h"
 
  float
 #ifdef KR_headers
-strtof(s, sp) CONST char *s; char **sp;
+strtof_l(s, sp, l) CONST char *s; char **sp; locale_t l;
 #else
-strtof(CONST char *s, char **sp)
+strtof_l(CONST char *s, char **sp, locale_t l)
 #endif
 {
-	static FPI fpi0 = { 24, 1-127-24+1,  254-127-24+1, 1, SI };
+	static const FPI fpi0 = { 24, 1-127-24+1,  254-127-24+1, 1, SI };
 	ULong bits[1];
 	Long exp;
 	int k;
@@ -51,7 +52,7 @@
 #define fpi &fpi0
 #endif
 
-	k = strtodg(s, sp, fpi, &exp, bits);
+	k = strtodg_l(s, sp, fpi, &exp, bits, l);
 	switch(k & STRTOG_Retmask) {
 	  case STRTOG_NoNumber:
 	  case STRTOG_Zero:
@@ -82,3 +83,13 @@
 		u.L[0] |= 0x80000000L;
 	return u.f;
 	}
+
+ float
+#ifdef KR_headers
+strtof(s, sp) CONST char *s; char **sp;
+#else
+strtof(CONST char *s, char **sp)
+#endif
+{
+	return strtof_l(s, sp, __get_locale());
+}
Index: contrib/gdtoa/strtorx.c
===================================================================
--- contrib/gdtoa/strtorx.c	(revision 225653)
+++ contrib/gdtoa/strtorx.c	(working copy)
@@ -106,9 +106,10 @@
 
  int
 #ifdef KR_headers
-strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+strtorx_l(s, sp, rounding, L, locale) CONST char *s; char **sp; int rounding;
+void *L; locale_t locale;
 #else
-strtorx(CONST char *s, char **sp, int rounding, void *L)
+strtorx_l(CONST char *s, char **sp, int rounding, void *L, locale_t locale)
 #endif
 {
 	static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI };
@@ -123,7 +124,16 @@
 		fpi1.rounding = rounding;
 		fpi = &fpi1;
 		}
-	k = strtodg(s, sp, fpi, &exp, bits);
+	k = strtodg_l(s, sp, fpi, &exp, bits, locale);
 	ULtox((UShort*)L, bits, exp, k);
 	return k;
 	}
+ int
+#ifdef KR_headers
+strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L;
+#else
+strtorx(CONST char *s, char **sp, int rounding, void *L)
+#endif
+{
+	return strtorx_l(s, sp, rounding, L, __get_locale());
+}
Index: share/monetdef/zh_CN.UTF-8.src
===================================================================
--- share/monetdef/zh_CN.UTF-8.src	(revision 225653)
+++ share/monetdef/zh_CN.UTF-8.src	(working copy)
@@ -18,9 +18,9 @@
 # negative_sign
 -
 # int_frac_digits
-0
+2
 # frac_digits
-0
+2
 # p_cs_precedes
 1
 # p_sep_by_space
Index: lib/msun/Symbol.map
===================================================================
--- lib/msun/Symbol.map	(revision 225653)
+++ lib/msun/Symbol.map	(working copy)
@@ -227,4 +227,21 @@
 	cexpf;
 	log2;
 	log2f;
+	coshl;
+	asinhl;
+	atanhl;
+	acoshl;
+	erfcl;
+	erfl;
+	expl;
+	expm1l;
+	lgammal;
+	log10l;
+	log1pl;
+	log2l;
+	logl;
+	tanhl;
+	sinhl;
+	tgammal;
+	powl;
 };
Index: lib/msun/src/math.h
===================================================================
--- lib/msun/src/math.h	(revision 225653)
+++ lib/msun/src/math.h	(working copy)
@@ -230,8 +230,13 @@
 double	fma(double, double, double);
 double	hypot(double, double);
 int	ilogb(double) __pure2;
+#ifdef __cplusplus
+bool	(isinf)(double) __pure2;
+bool	(isnan)(double) __pure2;
+#else
 int	(isinf)(double) __pure2;
 int	(isnan)(double) __pure2;
+#endif
 double	lgamma(double);
 long long llrint(double);
 long long llround(double);
@@ -398,32 +403,32 @@
  * long double versions of ISO/POSIX math functions
  */
 #if __ISO_C_VISIBLE >= 1999
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	acoshl(long double);
 #endif
 long double	acosl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	asinhl(long double);
 #endif
 long double	asinl(long double);
 long double	atan2l(long double, long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	atanhl(long double);
 #endif
 long double	atanl(long double);
 long double	cbrtl(long double);
 long double	ceill(long double);
 long double	copysignl(long double, long double) __pure2;
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	coshl(long double);
 #endif
 long double	cosl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	erfcl(long double);
 long double	erfl(long double);
 #endif
 long double	exp2l(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	expl(long double);
 long double	expm1l(long double);
 #endif
@@ -438,18 +443,18 @@
 long double	hypotl(long double, long double);
 int		ilogbl(long double) __pure2;
 long double	ldexpl(long double, int);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	lgammal(long double);
 #endif
 long long	llrintl(long double);
 long long	llroundl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	log10l(long double);
 long double	log1pl(long double);
 long double	log2l(long double);
 #endif
 long double	logbl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	logl(long double);
 #endif
 long		lrintl(long double);
@@ -461,7 +466,7 @@
 double		nexttoward(double, long double);
 float		nexttowardf(float, long double);
 long double	nexttowardl(long double, long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	powl(long double, long double);
 #endif
 long double	remainderl(long double, long double);
@@ -470,16 +475,16 @@
 long double	roundl(long double);
 long double	scalblnl(long double, long);
 long double	scalbnl(long double, int);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	sinhl(long double);
 #endif
 long double	sinl(long double);
 long double	sqrtl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	tanhl(long double);
 #endif
 long double	tanl(long double);
-#if 0
+#if !__NO_IMPRECISE_LIBM_FUNCTIONS
 long double	tgammal(long double);
 #endif
 long double	truncl(long double);
Index: lib/msun/src/stubs.c
===================================================================
--- lib/msun/src/stubs.c	(revision 0)
+++ lib/msun/src/stubs.c	(revision 0)
@@ -0,0 +1,22 @@
+#include <math.h>
+
+#define LIBCXX_LONG_DOUBLE_STUB(fn) __attribute__((weak)) long double fn ## l(long double x) { return fn(x); }
+#define LIBCXX_LONG_DOUBLE_STUB2(fn) __attribute__((weak)) long double fn ## l(long double x, long double y) { return fn(x, y); }
+
+LIBCXX_LONG_DOUBLE_STUB(cosh)
+LIBCXX_LONG_DOUBLE_STUB(asinh)
+LIBCXX_LONG_DOUBLE_STUB(atanh)
+LIBCXX_LONG_DOUBLE_STUB(acosh)
+LIBCXX_LONG_DOUBLE_STUB(erfc)
+LIBCXX_LONG_DOUBLE_STUB(erf)
+LIBCXX_LONG_DOUBLE_STUB(exp)
+LIBCXX_LONG_DOUBLE_STUB(expm1)
+LIBCXX_LONG_DOUBLE_STUB(lgamma)
+LIBCXX_LONG_DOUBLE_STUB(log10)
+LIBCXX_LONG_DOUBLE_STUB(log1p)
+LIBCXX_LONG_DOUBLE_STUB(log2)
+LIBCXX_LONG_DOUBLE_STUB(log)
+LIBCXX_LONG_DOUBLE_STUB(tanh)
+LIBCXX_LONG_DOUBLE_STUB(sinh)
+LIBCXX_LONG_DOUBLE_STUB(tgamma)
+LIBCXX_LONG_DOUBLE_STUB2(pow)
Index: lib/msun/Makefile
===================================================================
--- lib/msun/Makefile	(revision 225653)
+++ lib/msun/Makefile	(working copy)
@@ -70,7 +70,7 @@
 	s_scalbln.c s_scalbn.c s_scalbnf.c s_signbit.c \
 	s_signgam.c s_significand.c s_significandf.c s_sin.c s_sinf.c \
 	s_tan.c s_tanf.c s_tanh.c s_tanhf.c s_tgammaf.c s_trunc.c s_truncf.c \
-	w_cabs.c w_cabsf.c w_drem.c w_dremf.c
+	w_cabs.c w_cabsf.c w_drem.c w_dremf.c stubs.c
 
 # Location of fpmath.h and _fpmath.h
 LIBCDIR=	${.CURDIR}/../libc
Index: lib/libc/stdlib/Symbol.map
===================================================================
--- lib/libc/stdlib/Symbol.map	(revision 225653)
+++ lib/libc/stdlib/Symbol.map	(working copy)
@@ -90,6 +90,21 @@
 	tfind;
 	tsearch;
 	twalk;
+	atof_l;
+	atoi_l;
+	atol_l;
+	atoll_l;
+	strtod_l;
+	strtol_l;
+	strtoll_l;
+	strtof_l;
+	strtoimax_l;
+	strtold_l;
+	strtoq_l;
+	strtoul_l;
+	strtoull_l;
+	strtoumax_l;
+	strtouq_l;
 };
 
 FBSDprivate_1.0 {
Index: lib/libc/stdlib/atoll.c
===================================================================
--- lib/libc/stdlib/atoll.c	(revision 225653)
+++ lib/libc/stdlib/atoll.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1988, 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:
@@ -31,6 +36,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <stdlib.h>
+#include <xlocale.h>
 
 long long
 atoll(str)
@@ -38,3 +44,11 @@
 {
 	return strtoll(str, (char **)NULL, 10);
 }
+
+long long
+atoll_l(str, locale)
+	const char *str;
+	locale_t locale;
+{
+	return strtoll_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdlib/strfmon.c
===================================================================
--- lib/libc/stdlib/strfmon.c	(revision 225653)
+++ lib/libc/stdlib/strfmon.c	(working copy)
@@ -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:
@@ -38,6 +43,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "xlocale_private.h"
 
 /* internal flags */
 #define	NEED_GROUPING		0x01	/* print digits grouped (default) */
@@ -92,11 +98,10 @@
 static int __calc_left_pad(int, char *);
 static char *__format_grouped_double(double, int *, int, int, int);
 
-ssize_t
-strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
-    ...)
+static ssize_t
+vstrfmon_l(char * __restrict s, size_t maxsize, locale_t loc,
+		const char * __restrict format, va_list ap)
 {
-	va_list		ap;
 	char 		*dst;		/* output destination pointer */
 	const char 	*fmt;		/* current format poistion pointer */
 	struct lconv 	*lc;		/* pointer to lconv structure */
@@ -119,10 +124,10 @@
 
 	char		*tmpptr;	/* temporary vars */
 	int		sverrno;
+	FIX_LOCALE(loc);
 
-        va_start(ap, format);
 
-	lc = localeconv();
+	lc = localeconv_l(loc);
 	dst = s;
 	fmt = format;
 	asciivalue = NULL;
@@ -380,7 +385,6 @@
 	}
 
 	PRINT('\0');
-	va_end(ap);
 	free(asciivalue);
 	free(currency_symbol);
 	return (dst - s - 1);	/* return size of put data except trailing '\0' */
@@ -399,10 +403,34 @@
 	if (currency_symbol != NULL)
 		free(currency_symbol);
 	errno = sverrno;
-	va_end(ap);
 	return (-1);
 }
+ssize_t
+strfmon_l(char * __restrict s, size_t maxsize, locale_t loc, const char * __restrict format,
+    ...)
+{
+	size_t ret;
+	va_list ap;
+	FIX_LOCALE(loc);
+	va_start(ap, format);
+	ret = vstrfmon_l(s, maxsize, loc, format, ap);
+	va_end(ap);
+	return ret;
+}
 
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
+    ...)
+{
+	size_t ret;
+	va_list ap;
+	va_start(ap, format);
+	ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap);
+	va_end(ap);
+	return ret;
+}
+
+
 static void
 __setup_vars(int flags, char *cs_precedes, char *sep_by_space,
 		char *sign_posn, char **signstr) {
Index: lib/libc/stdlib/atof.c
===================================================================
--- lib/libc/stdlib/atof.c	(revision 225653)
+++ lib/libc/stdlib/atof.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1988, 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:
@@ -34,6 +39,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <stdlib.h>
+#include <xlocale.h>
 
 double
 atof(ascii)
@@ -41,3 +47,11 @@
 {
 	return strtod(ascii, (char **)NULL);
 }
+
+double
+atof_l(ascii, locale)
+	const char *ascii;
+	locale_t locale;
+{
+	return strtod_l(ascii, (char **)NULL, locale);
+}
Index: lib/libc/stdlib/strtoimax.c
===================================================================
--- lib/libc/stdlib/strtoimax.c	(revision 225653)
+++ lib/libc/stdlib/strtoimax.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <inttypes.h>
+#include "xlocale_private.h"
 
 /*
  * Convert a string to an intmax_t integer.
@@ -45,13 +51,15 @@
  * alphabets and digits are each contiguous.
  */
 intmax_t
-strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+		locale_t locale)
 {
 	const char *s;
 	uintmax_t acc;
 	char c;
 	uintmax_t cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * Skip white space and pick up leading +/- sign if any.
@@ -61,7 +69,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -138,3 +146,8 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtoimax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/atol.c
===================================================================
--- lib/libc/stdlib/atol.c	(revision 225653)
+++ lib/libc/stdlib/atol.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1988, 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:
@@ -34,6 +39,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <stdlib.h>
+#include <xlocale.h>
 
 long
 atol(str)
@@ -41,3 +47,11 @@
 {
 	return strtol(str, (char **)NULL, 10);
 }
+
+long
+atol_l(str, locale)
+	const char *str;
+	locale_t locale;
+{
+	return strtol_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdlib/strtoumax.c
===================================================================
--- lib/libc/stdlib/strtoumax.c	(revision 225653)
+++ lib/libc/stdlib/strtoumax.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <inttypes.h>
+#include "xlocale_private.h"
 
 /*
  * Convert a string to a uintmax_t integer.
@@ -45,13 +51,15 @@
  * alphabets and digits are each contiguous.
  */
 uintmax_t
-strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+		locale_t locale)
 {
 	const char *s;
 	uintmax_t acc;
 	char c;
 	uintmax_t cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * See strtoimax for comments as to the logic used.
@@ -59,7 +67,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -116,3 +124,8 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtoumax_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoul.c
===================================================================
--- lib/libc/stdlib/strtoul.c	(revision 225653)
+++ lib/libc/stdlib/strtoul.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
+#include "xlocale_private.h"
 
 /*
  * Convert a string to an unsigned long integer.
@@ -45,13 +51,14 @@
  * alphabets and digits are each contiguous.
  */
 unsigned long
-strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale)
 {
 	const char *s;
 	unsigned long acc;
 	char c;
 	unsigned long cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * See strtol for comments as to the logic used.
@@ -59,7 +66,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -116,3 +123,8 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtoul_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoull.c
===================================================================
--- lib/libc/stdlib/strtoull.c	(revision 225653)
+++ lib/libc/stdlib/strtoull.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <stdlib.h>
+#include "xlocale_private.h"
 
 /*
  * Convert a string to an unsigned long long integer.
@@ -45,13 +51,15 @@
  * alphabets and digits are each contiguous.
  */
 unsigned long long
-strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+		locale_t locale)
 {
 	const char *s;
 	unsigned long long acc;
 	char c;
 	unsigned long long cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * See strtoq for comments as to the logic used.
@@ -59,7 +67,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -116,3 +124,8 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+unsigned long long
+strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtoull_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtoll.c
===================================================================
--- lib/libc/stdlib/strtoll.c	(revision 225653)
+++ lib/libc/stdlib/strtoll.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <stdlib.h>
+#include <xlocale_private.h>
 
 /*
  * Convert a string to a long long integer.
@@ -45,13 +51,15 @@
  * alphabets and digits are each contiguous.
  */
 long long
-strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+		locale_t locale)
 {
 	const char *s;
 	unsigned long long acc;
 	char c;
 	unsigned long long cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * Skip white space and pick up leading +/- sign if any.
@@ -61,7 +69,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -138,3 +146,8 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+long long
+strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtoll_l(nptr, endptr, base, __get_locale());
+}
Index: lib/libc/stdlib/strtol.c
===================================================================
--- lib/libc/stdlib/strtol.c	(revision 225653)
+++ lib/libc/stdlib/strtol.c	(working copy)
@@ -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:
@@ -37,6 +42,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
+#include "xlocale_private.h"
 
 
 /*
@@ -46,13 +52,15 @@
  * alphabets and digits are each contiguous.
  */
 long
-strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+		locale_t locale)
 {
 	const char *s;
 	unsigned long acc;
 	char c;
 	unsigned long cutoff;
 	int neg, any, cutlim;
+	FIX_LOCALE(locale);
 
 	/*
 	 * Skip white space and pick up leading +/- sign if any.
@@ -62,7 +70,7 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (isspace((unsigned char)c));
+	} while (isspace_l((unsigned char)c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -138,3 +146,13 @@
 		*endptr = (char *)(any ? s - 1 : nptr);
 	return (acc);
 }
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+	return strtol_l(nptr, endptr, base, __get_locale());
+}
+long double
+strtold(const char * __restrict nptr, char ** __restrict endptr)
+{
+	return strtold_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/stdlib/atoi.c
===================================================================
--- lib/libc/stdlib/atoi.c	(revision 225653)
+++ lib/libc/stdlib/atoi.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1988, 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:
@@ -34,6 +39,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <stdlib.h>
+#include <xlocale.h>
 
 int
 atoi(str)
@@ -41,3 +47,11 @@
 {
 	return (int)strtol(str, (char **)NULL, 10);
 }
+
+int
+atoi_l(str, locale)
+	const char *str;
+	locale_t locale;
+{
+	return (int)strtol_l(str, (char **)NULL, 10, locale);
+}
Index: lib/libc/stdio/putwc.c
===================================================================
--- lib/libc/stdio/putwc.c	(revision 225653)
+++ lib/libc/stdio/putwc.c	(working copy)
@@ -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:
@@ -33,6 +38,7 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 #undef putwc
 
@@ -41,8 +47,13 @@
  * macro, may evaluate `fp' more than once.
  */
 wint_t
+putwc_l(wchar_t wc, FILE *fp, locale_t locale)
+{
+	FIX_LOCALE(locale);
+	return (fputwc_l(wc, fp, locale));
+}
+wint_t
 putwc(wchar_t wc, FILE *fp)
 {
-
-	return (fputwc(wc, fp));
+	return putwc_l(wc, fp, __get_locale());
 }
Index: lib/libc/stdio/printf.c
===================================================================
--- lib/libc/stdio/printf.c	(revision 225653)
+++ lib/libc/stdio/printf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -38,6 +43,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <xlocale.h>
 
 int
 printf(char const * __restrict fmt, ...)
@@ -50,3 +56,14 @@
 	va_end(ap);
 	return (ret);
 }
+int
+printf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vfprintf_l(stdout, locale, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/getwchar.c
===================================================================
--- lib/libc/stdio/getwchar.c	(revision 225653)
+++ lib/libc/stdio/getwchar.c	(working copy)
@@ -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 @@
 #include "namespace.h"
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
@@ -42,6 +48,10 @@
 wint_t
 getwchar(void)
 {
-
 	return (fgetwc(stdin));
 }
+wint_t
+getwchar_l(locale_t locale)
+{
+	return (fgetwc_l(stdin, locale));
+}
Index: lib/libc/stdio/Symbol.map
===================================================================
--- lib/libc/stdio/Symbol.map	(revision 225653)
+++ lib/libc/stdio/Symbol.map	(working copy)
@@ -108,6 +108,43 @@
 	__swbuf;
 	wprintf;
 	wscanf;
+	asprintf_l;
+	fprintf_l;
+	fwprintf_l;
+	printf_l;
+	snprintf_l;
+	sprintf_l;
+	swprintf_l;
+	vasprintf_l;
+	vfprintf_l;
+	vfwprintf_l;
+	vprintf_l;
+	vsnprintf_l;
+	vsprintf_l;
+	vswprintf_l;
+	vwprintf_l;
+	wprintf_l;
+	fgetwc_l;
+	fputwc_l;
+	ungetwc_l;
+	vfwscanf_l;
+	vswscanf_l;
+	fscanf_l;
+	fwscanf_l;
+	scanf_l;
+	sscanf_l;
+	swscanf_l;
+	vfscanf_l;
+	vscanf_l;
+	vsscanf_l;
+	vwscanf_l;
+	wscanf_l;
+	fgetws_l;
+	fputws_l;
+	getwc_l;
+	getwchar_l;
+	putwc_l;
+	putwchar_l;
 };
 
 FBSD_1.1 {
Index: lib/libc/stdio/fgetwln.c
===================================================================
--- lib/libc/stdio/fgetwln.c	(revision 225653)
+++ lib/libc/stdio/fgetwln.c	(working copy)
@@ -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,18 +38,20 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 wchar_t *
-fgetwln(FILE * __restrict fp, size_t *lenp)
+fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
 {
 	wint_t wc;
 	size_t len;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
 
 	len = 0;
-	while ((wc = __fgetwc(fp)) != WEOF) {
+	while ((wc = __fgetwc(fp, locale)) != WEOF) {
 #define	GROW	512
 		if (len * sizeof(wchar_t) >= fp->_lb._size &&
 		    __slbexpand(fp, (len + GROW) * sizeof(wchar_t)))
@@ -65,3 +72,8 @@
 	*lenp = 0;
 	return (NULL);
 }
+wchar_t *
+fgetwln(FILE * __restrict fp, size_t *lenp)
+{
+	return fgetwln_l(fp, lenp, __get_locale());
+}
Index: lib/libc/stdio/getwc.c
===================================================================
--- lib/libc/stdio/getwc.c	(revision 225653)
+++ lib/libc/stdio/getwc.c	(working copy)
@@ -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 @@
 #include "namespace.h"
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
@@ -43,6 +49,10 @@
 wint_t
 getwc(FILE *fp)
 {
-
 	return (fgetwc(fp));
 }
+wint_t
+getwc_l(FILE *fp, locale_t locale)
+{
+	return (fgetwc_l(fp, locale));
+}
Index: lib/libc/stdio/vsnprintf.c
===================================================================
--- lib/libc/stdio/vsnprintf.c	(revision 225653)
+++ lib/libc/stdio/vsnprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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,15 +44,17 @@
 #include <limits.h>
 #include <stdio.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 int
-vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
-    __va_list ap)
+vsnprintf_l(char * __restrict str, size_t n, locale_t locale, 
+		const char * __restrict fmt, __va_list ap)
 {
 	size_t on;
 	int ret;
 	char dummy[2];
 	FILE f = FAKE_FILE;
+	FIX_LOCALE(locale);
 
 	on = n;
 	if (n != 0)
@@ -64,8 +71,14 @@
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
-	ret = __vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, locale, fmt, ap);
 	if (on > 0)
 		*f._p = '\0';
 	return (ret);
 }
+int
+vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
+    __va_list ap)
+{
+	return vsnprintf_l(str, n, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/putwchar.c
===================================================================
--- lib/libc/stdio/putwchar.c	(revision 225653)
+++ lib/libc/stdio/putwchar.c	(working copy)
@@ -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:
@@ -33,6 +38,7 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 #undef putwchar
 
@@ -40,8 +46,13 @@
  * Synonym for fputwc(wc, stdout).
  */
 wint_t
+putwchar_l(wchar_t wc, locale_t locale)
+{
+	FIX_LOCALE(locale);
+	return (fputwc_l(wc, stdout, locale));
+}
+wint_t
 putwchar(wchar_t wc)
 {
-
-	return (fputwc(wc, stdout));
+	return putwchar_l(wc, __get_locale());
 }
Index: lib/libc/stdio/vswprintf.c
===================================================================
--- lib/libc/stdio/vswprintf.c	(revision 225653)
+++ lib/libc/stdio/vswprintf.c	(working copy)
@@ -4,6 +4,11 @@
  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
  * 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:
@@ -38,10 +43,11 @@
 #include <stdlib.h>
 #include <wchar.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 int
-vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
-    __va_list ap)
+vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+		const wchar_t * __restrict fmt, __va_list ap)
 {
 	static const mbstate_t initial;
 	mbstate_t mbs;
@@ -49,6 +55,7 @@
 	char *mbp;
 	int ret, sverrno;
 	size_t nwc;
+	FIX_LOCALE(locale);
 
 	if (n == 0) {
 		errno = EINVAL;
@@ -62,7 +69,7 @@
 		return (-1);
 	}
 	f._bf._size = f._w = 127;		/* Leave room for the NUL */
-	ret = __vfwprintf(&f, fmt, ap);
+	ret = __vfwprintf(&f, locale, fmt, ap);
 	if (ret < 0) {
 		sverrno = errno;
 		free(f._bf._base);
@@ -76,7 +83,7 @@
 	 * fputwc() did in __vfwprintf().
 	 */
 	mbs = initial;
-	nwc = mbsrtowcs(s, (const char **)&mbp, n, &mbs);
+	nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
 	free(f._bf._base);
 	if (nwc == (size_t)-1) {
 		errno = EILSEQ;
@@ -90,3 +97,9 @@
 
 	return (ret);
 }
+int
+vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
+    __va_list ap)
+{
+	return vswprintf_l(s, n, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vsscanf.c
===================================================================
--- lib/libc/stdio/vsscanf.c	(revision 225653)
+++ lib/libc/stdio/vsscanf.c	(working copy)
@@ -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.
+ *
  * This code is derived from software contributed to Berkeley by
  * Donn Seeley at UUNET Technologies, Inc.
  *
@@ -39,6 +44,7 @@
 #include <stdio.h>
 #include <string.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 static int
 eofread(void *, char *, int);
@@ -52,14 +58,21 @@
 }
 
 int
-vsscanf(const char * __restrict str, const char * __restrict fmt,
-	__va_list ap)
+vsscanf_l(const char * __restrict str, locale_t locale,
+		const char * __restrict fmt, __va_list ap)
 {
 	FILE f = FAKE_FILE;
+	FIX_LOCALE(locale);
 
 	f._flags = __SRD;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._r = strlen(str);
 	f._read = eofread;
-	return (__svfscanf(&f, fmt, ap));
+	return (__svfscanf(&f, locale, fmt, ap));
 }
+int
+vsscanf(const char * __restrict str, const char * __restrict fmt,
+	__va_list ap)
+{
+	return vsscanf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/snprintf.c
===================================================================
--- lib/libc/stdio/snprintf.c	(revision 225653)
+++ lib/libc/stdio/snprintf.c	(working copy)
@@ -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.
+ *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
@@ -39,6 +44,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include "xlocale_private.h"
 
 #include "local.h"
 
@@ -59,9 +65,34 @@
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = n;
-	ret = __vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, __get_locale(), fmt, ap);
 	if (on > 0)
 		*f._p = '\0';
 	va_end(ap);
 	return (ret);
 }
+int
+snprintf_l(char * __restrict str, size_t n, locale_t locale,
+		char const * __restrict fmt, ...)
+{
+	size_t on;
+	int ret;
+	va_list ap;
+	FILE f = FAKE_FILE;
+	FIX_LOCALE(locale);
+
+	on = n;
+	if (n != 0)
+		n--;
+	if (n > INT_MAX)
+		n = INT_MAX;
+	va_start(ap, fmt);
+	f._flags = __SWR | __SSTR;
+	f._bf._base = f._p = (unsigned char *)str;
+	f._bf._size = f._w = n;
+	ret = __vfprintf(&f, locale, fmt, ap);
+	if (on > 0)
+		*f._p = '\0';
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/ungetwc.c
===================================================================
--- lib/libc/stdio/ungetwc.c	(revision 225653)
+++ lib/libc/stdio/ungetwc.c	(working copy)
@@ -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:
@@ -37,19 +42,21 @@
 #include "libc_private.h"
 #include "local.h"
 #include "mblocal.h"
+#include "xlocale_private.h"
 
 /*
  * Non-MT-safe version.
  */
 wint_t
-__ungetwc(wint_t wc, FILE *fp)
+__ungetwc(wint_t wc, FILE *fp, locale_t locale)
 {
 	char buf[MB_LEN_MAX];
 	size_t len;
+	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
 
 	if (wc == WEOF)
 		return (WEOF);
-	if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+	if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
 		fp->_flags |= __SERR;
 		return (WEOF);
 	}
@@ -64,14 +71,20 @@
  * MT-safe version.
  */
 wint_t
-ungetwc(wint_t wc, FILE *fp)
+ungetwc_l(wint_t wc, FILE *fp, locale_t locale)
 {
 	wint_t r;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
-	r = __ungetwc(wc, fp);
+	r = __ungetwc(wc, fp, locale);
 	FUNLOCKFILE(fp);
 
 	return (r);
 }
+wint_t
+ungetwc(wint_t wc, FILE *fp)
+{
+	return ungetwc_l(wc, fp, __get_locale());
+}
Index: lib/libc/stdio/swprintf.c
===================================================================
--- lib/libc/stdio/swprintf.c	(revision 225653)
+++ lib/libc/stdio/swprintf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@
 
 	return (ret);
 }
+int
+swprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+		const wchar_t * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vswprintf_l(s, n, locale, fmt, ap);
+	va_end(ap);
+
+	return (ret);
+}
Index: lib/libc/stdio/wscanf.c
===================================================================
--- lib/libc/stdio/wscanf.c	(revision 225653)
+++ lib/libc/stdio/wscanf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 wscanf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
 
 	return (r);
 }
+int
+wscanf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+	va_list ap;
+	int r;
+
+	va_start(ap, fmt);
+	r = vfwscanf_l(stdin, locale, fmt, ap);
+	va_end(ap);
+
+	return (r);
+}
Index: lib/libc/stdio/fscanf.c
===================================================================
--- lib/libc/stdio/fscanf.c	(revision 225653)
+++ lib/libc/stdio/fscanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -42,6 +47,7 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 int
 fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
@@ -51,8 +57,22 @@
 
 	va_start(ap, fmt);
 	FLOCKFILE(fp);
-	ret = __svfscanf(fp, fmt, ap);
+	ret = __svfscanf(fp, __get_locale(), fmt, ap);
 	va_end(ap);
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+int
+fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+	FIX_LOCALE(locale);
+
+	va_start(ap, fmt);
+	FLOCKFILE(fp);
+	ret = __svfscanf(fp, locale, fmt, ap);
+	va_end(ap);
+	FUNLOCKFILE(fp);
+	return (ret);
+}
Index: lib/libc/stdio/fprintf.c
===================================================================
--- lib/libc/stdio/fprintf.c	(revision 225653)
+++ lib/libc/stdio/fprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -38,6 +43,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include "xlocale_private.h"
 
 int
 fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
@@ -46,7 +52,19 @@
 	va_list ap;
 
 	va_start(ap, fmt);
-	ret = vfprintf(fp, fmt, ap);
+	ret = vfprintf_l(fp, __get_locale(), fmt, ap);
 	va_end(ap);
 	return (ret);
 }
+int
+fprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+	FIX_LOCALE(locale);
+
+	va_start(ap, fmt);
+	ret = vfprintf_l(fp, locale, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/vscanf.c
===================================================================
--- lib/libc/stdio/vscanf.c	(revision 225653)
+++ lib/libc/stdio/vscanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Donn Seeley at UUNET Technologies, Inc.
  *
+ * 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,16 +46,26 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 int
-vscanf(fmt, ap)
+vscanf_l(locale, fmt, ap)
+	locale_t locale;
 	const char * __restrict fmt;
 	__va_list ap;
 {
 	int retval;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(stdin);
-	retval = __svfscanf(stdin, fmt, ap);
+	retval = __svfscanf(stdin, locale, fmt, ap);
 	FUNLOCKFILE(stdin);
 	return (retval);
 }
+int
+vscanf(fmt, ap)
+	const char * __restrict fmt;
+	__va_list ap;
+{
+	return vscanf_l(__get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/printfcommon.h
===================================================================
--- lib/libc/stdio/printfcommon.h	(revision 225653)
+++ lib/libc/stdio/printfcommon.h	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -79,14 +84,14 @@
  * remain valid until io_flush() is called.
  */
 static inline int
-io_print(struct io_state *iop, const CHAR * __restrict ptr, int len)
+io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale)
 {
 
 	iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
 	iop->iov[iop->uio.uio_iovcnt].iov_len = len;
 	iop->uio.uio_resid += len;
 	if (++iop->uio.uio_iovcnt >= NIOV)
-		return (__sprint(iop->fp, &iop->uio));
+		return (__sprint(iop->fp, &iop->uio, locale));
 	else
 		return (0);
 }
@@ -107,13 +112,14 @@
  * or the zeroes array.
  */
 static inline int
-io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
+io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with,
+		locale_t locale)
 {
 	int n;
 
 	while (howmany > 0) {
 		n = (howmany >= PADSIZE) ? PADSIZE : howmany;
-		if (io_print(iop, with, n))
+		if (io_print(iop, with, n, locale))
 			return (-1);
 		howmany -= n;
 	}
@@ -126,7 +132,7 @@
  */
 static inline int
 io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
-	       int len, const CHAR * __restrict with)
+	       int len, const CHAR * __restrict with, locale_t locale)
 {
 	int p_len;
 
@@ -134,19 +140,19 @@
 	if (p_len > len)
 		p_len = len;
 	if (p_len > 0) {
-		if (io_print(iop, p, p_len))
+		if (io_print(iop, p, p_len, locale))
 			return (-1);
 	} else {
 		p_len = 0;
 	}
-	return (io_pad(iop, len - p_len, with));
+	return (io_pad(iop, len - p_len, with, locale));
 }
 
 static inline int
-io_flush(struct io_state *iop)
+io_flush(struct io_state *iop, locale_t locale)
 {
 
-	return (__sprint(iop->fp, &iop->uio));
+	return (__sprint(iop->fp, &iop->uio, locale));
 }
 
 /*
Index: lib/libc/stdio/sprintf.c
===================================================================
--- lib/libc/stdio/sprintf.c	(revision 225653)
+++ lib/libc/stdio/sprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -40,6 +45,7 @@
 #include <stdarg.h>
 #include <limits.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 int
 sprintf(char * __restrict str, char const * __restrict fmt, ...)
@@ -52,3 +58,16 @@
 	va_end(ap);
 	return (ret);
 }
+int
+sprintf_l(char * __restrict str, locale_t locale, char const * __restrict fmt,
+		...)
+{
+	int ret;
+	va_list ap;
+	FIX_LOCALE(locale);
+
+	va_start(ap, fmt);
+	ret = vsprintf_l(str, locale, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/vprintf.c
===================================================================
--- lib/libc/stdio/vprintf.c	(revision 225653)
+++ lib/libc/stdio/vprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -37,10 +42,15 @@
 __FBSDID("$FreeBSD$");
 
 #include <stdio.h>
+#include <xlocale.h>
 
 int
 vprintf(const char * __restrict fmt, __va_list ap)
 {
-
 	return (vfprintf(stdout, fmt, ap));
 }
+int
+vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
+{
+	return (vfprintf_l(stdout, locale, fmt, ap));
+}
Index: lib/libc/stdio/wprintf.c
===================================================================
--- lib/libc/stdio/wprintf.c	(revision 225653)
+++ lib/libc/stdio/wprintf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 wprintf(const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
 
 	return (ret);
 }
+int
+wprintf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vfwprintf_l(stdout, locale, fmt, ap);
+	va_end(ap);
+
+	return (ret);
+}
Index: lib/libc/stdio/vfwprintf.c
===================================================================
--- lib/libc/stdio/vfwprintf.c	(revision 225653)
+++ lib/libc/stdio/vfwprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -65,10 +70,11 @@
 #include "local.h"
 #include "fvwrite.h"
 #include "printflocal.h"
+#include "xlocale_private.h"
 
-static int	__sprint(FILE *, struct __suio *);
-static int	__sbprintf(FILE *, const wchar_t *, va_list) __noinline;
-static wint_t	__xfputwc(wchar_t, FILE *);
+static int	__sprint(FILE *, struct __suio *, locale_t);
+static int	__sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline;
+static wint_t	__xfputwc(wchar_t, FILE *, locale_t);
 static wchar_t	*__mbsconv(char *, int);
 
 #define	CHAR	wchar_t
@@ -85,28 +91,28 @@
 static const mbstate_t initial_mbs;
 
 static inline wchar_t
-get_decpt(void)
+get_decpt(locale_t locale)
 {
 	mbstate_t mbs;
 	wchar_t decpt;
 	int nconv;
 
 	mbs = initial_mbs;
-	nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+	nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs);
 	if (nconv == (size_t)-1 || nconv == (size_t)-2)
 		decpt = '.';    /* failsafe */
 	return (decpt);
 }
 
 static inline wchar_t
-get_thousep(void)
+get_thousep(locale_t locale)
 {
 	mbstate_t mbs;
 	wchar_t thousep;
 	int nconv;
 
 	mbs = initial_mbs;
-	nconv = mbrtowc(&thousep, localeconv()->thousands_sep,
+	nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep,
 	    MB_CUR_MAX, &mbs);
 	if (nconv == (size_t)-1 || nconv == (size_t)-2)
 		thousep = '\0';    /* failsafe */
@@ -119,11 +125,11 @@
  * of wide characters that will be printed.
  */
 static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t locale)
 {
 
-	gs->grouping = localeconv()->grouping;
-	gs->thousands_sep = get_thousep();
+	gs->grouping = localeconv_l(locale)->grouping;
+	gs->thousands_sep = get_thousep(locale);
 
 	gs->nseps = gs->nrepeats = 0;
 	gs->lead = ndigits;
@@ -145,11 +151,11 @@
  */
 static int
 grouping_print(struct grouping_state *gs, struct io_state *iop,
-	       const CHAR *cp, const CHAR *ep)
+	       const CHAR *cp, const CHAR *ep, locale_t locale)
 {
 	const CHAR *cp0 = cp;
 
-	if (io_printandpad(iop, cp, ep, gs->lead, zeroes))
+	if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
 		return (-1);
 	cp += gs->lead;
 	while (gs->nseps > 0 || gs->nrepeats > 0) {
@@ -159,9 +165,9 @@
 			gs->grouping--;
 			gs->nseps--;
 		}
-		if (io_print(iop, &gs->thousands_sep, 1))
+		if (io_print(iop, &gs->thousands_sep, 1, locale))
 			return (-1);
-		if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes))
+		if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
 			return (-1);
 		cp += *gs->grouping;
 	}
@@ -180,7 +186,7 @@
  * string eclipses the benefits of buffering.
  */
 static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
 {
 	struct __siov *iov;
 	wchar_t *p;
@@ -191,7 +197,7 @@
 		p = (wchar_t *)iov->iov_base;
 		len = iov->iov_len;
 		for (i = 0; i < len; i++) {
-			if (__xfputwc(p[i], fp) == WEOF)
+			if (__xfputwc(p[i], fp, locale) == WEOF)
 				return (-1);
 		}
 	}
@@ -205,7 +211,7 @@
  * worries about ungetc buffers and so forth.
  */
 static int
-__sbprintf(FILE *fp, const wchar_t *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap)
 {
 	int ret;
 	FILE fake;
@@ -229,7 +235,7 @@
 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
 
 	/* do the work, then copy any error status */
-	ret = __vfwprintf(&fake, fmt, ap);
+	ret = __vfwprintf(&fake, locale, fmt, ap);
 	if (ret >= 0 && __fflush(&fake))
 		ret = WEOF;
 	if (fake._flags & __SERR)
@@ -242,7 +248,7 @@
  * File must already be locked.
  */
 static wint_t
-__xfputwc(wchar_t wc, FILE *fp)
+__xfputwc(wchar_t wc, FILE *fp, locale_t locale)
 {
 	mbstate_t mbs;
 	char buf[MB_LEN_MAX];
@@ -251,7 +257,7 @@
 	size_t len;
 
 	if ((fp->_flags & __SSTR) == 0)
-		return (__fputwc(wc, fp));
+		return (__fputwc(wc, fp, locale));
 
 	mbs = initial_mbs;
 	if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
@@ -343,21 +349,27 @@
  * MT-safe version
  */
 int
-vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+vfwprintf_l(FILE * __restrict fp, locale_t locale,
+		const wchar_t * __restrict fmt0, va_list ap)
 
 {
 	int ret;
-
+	FIX_LOCALE(locale);
 	FLOCKFILE(fp);
 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
 	    fp->_file >= 0)
-		ret = __sbprintf(fp, fmt0, ap);
+		ret = __sbprintf(fp, locale, fmt0, ap);
 	else
-		ret = __vfwprintf(fp, fmt0, ap);
+		ret = __vfwprintf(fp, locale, fmt0, ap);
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+int
+vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+{
+	return vfwprintf_l(fp, __get_locale(), fmt0, ap);
+}
 
 /*
  * The size of the buffer we use as scratch space for integer
@@ -374,7 +386,7 @@
  * Non-MT-safe version
  */
 int
-__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap)
+__vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap)
 {
 	wchar_t *fmt;		/* format string */
 	wchar_t ch;		/* character from fmt */
@@ -437,19 +449,19 @@
 
 	/* BEWARE, these `goto error' on error. */
 #define	PRINT(ptr, len)	do {			\
-	if (io_print(&io, (ptr), (len)))	\
+	if (io_print(&io, (ptr), (len), locale))	\
 		goto error; \
 } while (0)
 #define	PAD(howmany, with) { \
-	if (io_pad(&io, (howmany), (with))) \
+	if (io_pad(&io, (howmany), (with), locale)) \
 		goto error; \
 }
 #define	PRINTANDPAD(p, ep, len, with) {	\
-	if (io_printandpad(&io, (p), (ep), (len), (with))) \
+	if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
 		goto error; \
 }
 #define	FLUSH() { \
-	if (io_flush(&io)) \
+	if (io_flush(&io, locale)) \
 		goto error; \
 }
 
@@ -529,7 +541,7 @@
 	io_init(&io, fp);
 	ret = 0;
 #ifndef NO_FLOATING_POINT
-	decimal_point = get_decpt();
+	decimal_point = get_decpt(locale);
 #endif
 
 	/*
@@ -816,7 +828,7 @@
 				if (prec || flags & ALT)
 					size += prec + 1;
 				if ((flags & GROUPING) && expt > 0)
-					size += grouping_init(&gs, expt);
+					size += grouping_init(&gs, expt, locale);
 			}
 			break;
 #endif /* !NO_FLOATING_POINT */
@@ -955,7 +967,7 @@
 			if (size > BUF)	/* should never happen */
 				abort();
 			if ((flags & GROUPING) && size != 0)
-				size += grouping_init(&gs, size);
+				size += grouping_init(&gs, size, locale);
 			break;
 		default:	/* "%?" prints ?, unless ? is NUL */
 			if (ch == '\0')
@@ -1018,7 +1030,7 @@
 			/* leading zeroes from decimal precision */
 			PAD(dprec - size, zeroes);
 			if (gs.grouping) {
-				if (grouping_print(&gs, &io, cp, buf+BUF) < 0)
+				if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
 					goto error;
 			} else {
 				PRINT(cp, size);
@@ -1036,7 +1048,7 @@
 				} else {
 					if (gs.grouping) {
 						n = grouping_print(&gs, &io,
-						    cp, convbuf + ndig);
+						    cp, convbuf + ndig, locale);
 						if (n < 0)
 							goto error;
 						cp += n;
Index: lib/libc/stdio/vdprintf.c
===================================================================
--- lib/libc/stdio/vdprintf.c	(revision 225653)
+++ lib/libc/stdio/vdprintf.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 2009 David Schultz <das@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,6 +40,7 @@
 #include "un-namespace.h"
 
 #include "local.h"
+#include "xlocale_private.h"
 
 int
 vdprintf(int fd, const char * __restrict fmt, va_list ap)
@@ -57,7 +63,7 @@
 	f._bf._base = buf;
 	f._bf._size = sizeof(buf);
 
-	if ((ret = __vfprintf(&f, fmt, ap)) < 0)
+	if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
 		return (ret);
 
 	return (__fflush(&f) ? EOF : ret);
Index: lib/libc/stdio/vfprintf.c
===================================================================
--- lib/libc/stdio/vfprintf.c	(revision 225653)
+++ lib/libc/stdio/vfprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -57,6 +62,7 @@
 #include <printf.h>
 
 #include <stdarg.h>
+#include "xlocale_private.h"
 #include "un-namespace.h"
 
 #include "libc_private.h"
@@ -64,8 +70,8 @@
 #include "fvwrite.h"
 #include "printflocal.h"
 
-static int	__sprint(FILE *, struct __suio *);
-static int	__sbprintf(FILE *, const char *, va_list) __printflike(2, 0)
+static int	__sprint(FILE *, struct __suio *, locale_t);
+static int	__sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0)
 	__noinline;
 static char	*__wcsconv(wchar_t *, int);
 
@@ -87,11 +93,11 @@
  * of bytes that will be needed.
  */
 static int
-grouping_init(struct grouping_state *gs, int ndigits)
+grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
 {
 	struct lconv *locale;
 
-	locale = localeconv();
+	locale = localeconv_l(loc);
 	gs->grouping = locale->grouping;
 	gs->thousands_sep = locale->thousands_sep;
 	gs->thousep_len = strlen(gs->thousands_sep);
@@ -116,11 +122,11 @@
  */
 static int
 grouping_print(struct grouping_state *gs, struct io_state *iop,
-	       const CHAR *cp, const CHAR *ep)
+	       const CHAR *cp, const CHAR *ep, locale_t locale)
 {
 	const CHAR *cp0 = cp;
 
-	if (io_printandpad(iop, cp, ep, gs->lead, zeroes))
+	if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
 		return (-1);
 	cp += gs->lead;
 	while (gs->nseps > 0 || gs->nrepeats > 0) {
@@ -130,9 +136,9 @@
 			gs->grouping--;
 			gs->nseps--;
 		}
-		if (io_print(iop, gs->thousands_sep, gs->thousep_len))
+		if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
 			return (-1);
-		if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes))
+		if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
 			return (-1);
 		cp += *gs->grouping;
 	}
@@ -146,7 +152,7 @@
  * then reset it so that it can be reused.
  */
 static int
-__sprint(FILE *fp, struct __suio *uio)
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
 {
 	int err;
 
@@ -166,7 +172,7 @@
  * worries about ungetc buffers and so forth.
  */
 static int
-__sbprintf(FILE *fp, const char *fmt, va_list ap)
+__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
 {
 	int ret;
 	FILE fake = FAKE_FILE;
@@ -190,7 +196,7 @@
 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
 
 	/* do the work, then copy any error status */
-	ret = __vfprintf(&fake, fmt, ap);
+	ret = __vfprintf(&fake, locale, fmt, ap);
 	if (ret >= 0 && __fflush(&fake))
 		ret = EOF;
 	if (fake._flags & __SERR)
@@ -261,21 +267,27 @@
  * MT-safe version
  */
 int
-vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
-
+vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
+		va_list ap)
 {
 	int ret;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
 	    fp->_file >= 0)
-		ret = __sbprintf(fp, fmt0, ap);
+		ret = __sbprintf(fp, locale, fmt0, ap);
 	else
-		ret = __vfprintf(fp, fmt0, ap);
+		ret = __vfprintf(fp, locale, fmt0, ap);
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+int
+vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+{
+	return vfprintf_l(fp, __get_locale(), fmt0, ap);
+}
 
 /*
  * The size of the buffer we use as scratch space for integer
@@ -292,7 +304,7 @@
  * Non-MT-safe version
  */
 int
-__vfprintf(FILE *fp, const char *fmt0, va_list ap)
+__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
 {
 	char *fmt;		/* format string */
 	int ch;			/* character from fmt */
@@ -357,19 +369,19 @@
 
 	/* BEWARE, these `goto error' on error. */
 #define	PRINT(ptr, len) { \
-	if (io_print(&io, (ptr), (len)))	\
+	if (io_print(&io, (ptr), (len), locale))	\
 		goto error; \
 }
 #define	PAD(howmany, with) { \
-	if (io_pad(&io, (howmany), (with))) \
+	if (io_pad(&io, (howmany), (with), locale)) \
 		goto error; \
 }
 #define	PRINTANDPAD(p, ep, len, with) {	\
-	if (io_printandpad(&io, (p), (ep), (len), (with))) \
+	if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
 		goto error; \
 }
 #define	FLUSH() { \
-	if (io_flush(&io)) \
+	if (io_flush(&io, locale)) \
 		goto error; \
 }
 
@@ -454,7 +466,7 @@
 	ret = 0;
 #ifndef NO_FLOATING_POINT
 	dtoaresult = NULL;
-	decimal_point = localeconv()->decimal_point;
+	decimal_point = localeconv_l(locale)->decimal_point;
 	/* The overwhelmingly common case is decpt_len == 1. */
 	decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
 #endif
@@ -750,7 +762,7 @@
 				if (prec || flags & ALT)
 					size += prec + decpt_len;
 				if ((flags & GROUPING) && expt > 0)
-					size += grouping_init(&gs, expt);
+					size += grouping_init(&gs, expt, locale);
 			}
 			break;
 #endif /* !NO_FLOATING_POINT */
@@ -887,7 +899,7 @@
 			if (size > BUF)	/* should never happen */
 				abort();
 			if ((flags & GROUPING) && size != 0)
-				size += grouping_init(&gs, size);
+				size += grouping_init(&gs, size, locale);
 			break;
 		default:	/* "%?" prints ?, unless ? is NUL */
 			if (ch == '\0')
@@ -950,7 +962,7 @@
 			/* leading zeroes from decimal precision */
 			PAD(dprec - size, zeroes);
 			if (gs.grouping) {
-				if (grouping_print(&gs, &io, cp, buf+BUF) < 0)
+				if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
 					goto error;
 			} else {
 				PRINT(cp, size);
@@ -968,7 +980,7 @@
 				} else {
 					if (gs.grouping) {
 						n = grouping_print(&gs, &io,
-						    cp, dtoaend);
+						    cp, dtoaend, locale);
 						if (n < 0)
 							goto error;
 						cp += n;
Index: lib/libc/stdio/local.h
===================================================================
--- lib/libc/stdio/local.h	(revision 225653)
+++ lib/libc/stdio/local.h	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -37,6 +42,7 @@
 #include <pthread.h>
 #include <string.h>
 #include <wchar.h>
+#include <locale.h>
 
 /*
  * Information local to this implementation of stdio,
@@ -50,8 +56,8 @@
 extern int	_fseeko(FILE *, off_t, int, int);
 extern int	__fflush(FILE *fp);
 extern void	__fcloseall(void);
-extern wint_t	__fgetwc(FILE *);
-extern wint_t	__fputwc(wchar_t, FILE *);
+extern wint_t	__fgetwc(FILE *, locale_t);
+extern wint_t	__fputwc(wchar_t, FILE *, locale_t);
 extern int	__sflush(FILE *);
 extern FILE	*__sfp(void);
 extern int	__slbexpand(FILE *, size_t);
@@ -65,15 +71,15 @@
 extern void	__smakebuf(FILE *);
 extern int	__swhatbuf(FILE *, size_t *, int *);
 extern int	_fwalk(int (*)(FILE *));
-extern int	__svfscanf(FILE *, const char *, __va_list);
+extern int	__svfscanf(FILE *, locale_t, const char *, __va_list);
 extern int	__swsetup(FILE *);
 extern int	__sflags(const char *, int *);
 extern int	__ungetc(int, FILE *);
-extern wint_t	__ungetwc(wint_t, FILE *);
-extern int	__vfprintf(FILE *, const char *, __va_list);
+extern wint_t	__ungetwc(wint_t, FILE *, locale_t);
+extern int	__vfprintf(FILE *, locale_t, const char *, __va_list);
 extern int	__vfscanf(FILE *, const char *, __va_list);
-extern int	__vfwprintf(FILE *, const wchar_t *, __va_list);
-extern int	__vfwscanf(FILE * __restrict, const wchar_t * __restrict,
+extern int	__vfwprintf(FILE *, locale_t, const wchar_t *, __va_list);
+extern int	__vfwscanf(FILE * __restrict, locale_t, const wchar_t * __restrict,
 		    __va_list);
 extern size_t	__fread(void * __restrict buf, size_t size, size_t count,
 		FILE * __restrict fp);
Index: lib/libc/stdio/fwprintf.c
===================================================================
--- lib/libc/stdio/fwprintf.c	(revision 225653)
+++ lib/libc/stdio/fwprintf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
 
 	return (ret);
 }
+int
+fwprintf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vfwprintf_l(fp, locale, fmt, ap);
+	va_end(ap);
+
+	return (ret);
+}
Index: lib/libc/stdio/fputwc.c
===================================================================
--- lib/libc/stdio/fputwc.c	(revision 225653)
+++ lib/libc/stdio/fputwc.c	(working copy)
@@ -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:
@@ -42,10 +47,11 @@
  * Non-MT-safe version.
  */
 wint_t
-__fputwc(wchar_t wc, FILE *fp)
+__fputwc(wchar_t wc, FILE *fp, locale_t locale)
 {
 	char buf[MB_LEN_MAX];
 	size_t i, len;
+	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
 
 	if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
 		/*
@@ -56,7 +62,7 @@
 		*buf = (unsigned char)wc;
 		len = 1;
 	} else {
-		if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+		if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
 			fp->_flags |= __SERR;
 			return (WEOF);
 		}
@@ -73,14 +79,20 @@
  * MT-safe version.
  */
 wint_t
-fputwc(wchar_t wc, FILE *fp)
+fputwc_l(wchar_t wc, FILE *fp, locale_t locale)
 {
 	wint_t r;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
-	r = __fputwc(wc, fp);
+	r = __fputwc(wc, fp, locale);
 	FUNLOCKFILE(fp);
 
 	return (r);
 }
+wint_t
+fputwc(wchar_t wc, FILE *fp)
+{
+	return fputwc_l(wc, fp, __get_locale());
+}
Index: lib/libc/stdio/vsprintf.c
===================================================================
--- lib/libc/stdio/vsprintf.c	(revision 225653)
+++ lib/libc/stdio/vsprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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,17 +44,25 @@
 #include <stdio.h>
 #include <limits.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 int
-vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+vsprintf_l(char * __restrict str, locale_t locale,
+		const char * __restrict fmt, __va_list ap)
 {
 	int ret;
 	FILE f = FAKE_FILE;
+	FIX_LOCALE(locale);
 
 	f._flags = __SWR | __SSTR;
 	f._bf._base = f._p = (unsigned char *)str;
 	f._bf._size = f._w = INT_MAX;
-	ret = __vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, locale, fmt, ap);
 	*f._p = 0;
 	return (ret);
 }
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+	return vsprintf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vwprintf.c
===================================================================
--- lib/libc/stdio/vwprintf.c	(revision 225653)
+++ lib/libc/stdio/vwprintf.c	(working copy)
@@ -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,10 +35,15 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 vwprintf(const wchar_t * __restrict fmt, va_list ap)
 {
-
 	return (vfwprintf(stdout, fmt, ap));
 }
+int
+vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+	return (vfwprintf_l(stdout, locale, fmt, ap));
+}
Index: lib/libc/stdio/fwscanf.c
===================================================================
--- lib/libc/stdio/fwscanf.c	(revision 225653)
+++ lib/libc/stdio/fwscanf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,15 @@
 
 	return (r);
 }
+int
+fwscanf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+	va_list ap;
+	int r;
+
+	va_start(ap, fmt);
+	r = vfwscanf_l(fp, locale, fmt, ap);
+	va_end(ap);
+
+	return (r);
+}
Index: lib/libc/stdio/fputws.c
===================================================================
--- lib/libc/stdio/fputws.c	(revision 225653)
+++ lib/libc/stdio/fputws.c	(working copy)
@@ -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,13 +44,15 @@
 #include "mblocal.h"
 
 int
-fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale)
 {
 	size_t nbytes;
 	char buf[BUFSIZ];
 	struct __suio uio;
 	struct __siov iov;
 	const wchar_t *wsp;
+	FIX_LOCALE(locale);
+	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
@@ -56,7 +63,7 @@
 	iov.iov_base = buf;
 	do {
 		wsp = ws;
-		nbytes = __wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
+		nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
 		    &fp->_mbstate);
 		if (nbytes == (size_t)-1)
 			goto error;
@@ -71,3 +78,9 @@
 	FUNLOCKFILE(fp);
 	return (-1);
 }
+
+int
+fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+{
+	return fputws_l(ws, fp, __get_locale());
+}
Index: lib/libc/stdio/scanf.c
===================================================================
--- lib/libc/stdio/scanf.c	(revision 225653)
+++ lib/libc/stdio/scanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -42,6 +47,7 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 int
 scanf(char const * __restrict fmt, ...)
@@ -51,8 +57,22 @@
 
 	va_start(ap, fmt);
 	FLOCKFILE(stdin);
-	ret = __svfscanf(stdin, fmt, ap);
+	ret = __svfscanf(stdin, __get_locale(), fmt, ap);
 	FUNLOCKFILE(stdin);
 	va_end(ap);
 	return (ret);
 }
+int
+scanf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+	FIX_LOCALE(locale);
+
+	va_start(ap, fmt);
+	FLOCKFILE(stdin);
+	ret = __svfscanf(stdin, locale, fmt, ap);
+	FUNLOCKFILE(stdin);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/swscanf.c
===================================================================
--- lib/libc/stdio/swscanf.c	(revision 225653)
+++ lib/libc/stdio/swscanf.c	(working copy)
@@ -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 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
@@ -43,3 +49,16 @@
 
 	return (r);
 }
+int
+swscanf_l(const wchar_t * __restrict str, locale_t locale,
+		const wchar_t * __restrict fmt, ...)
+{
+	va_list ap;
+	int r;
+
+	va_start(ap, fmt);
+	r = vswscanf_l(str, locale, fmt, ap);
+	va_end(ap);
+
+	return (r);
+}
Index: lib/libc/stdio/vwscanf.c
===================================================================
--- lib/libc/stdio/vwscanf.c	(revision 225653)
+++ lib/libc/stdio/vwscanf.c	(working copy)
@@ -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,10 +35,15 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
 vwscanf(const wchar_t * __restrict fmt, va_list ap)
 {
-
 	return (vfwscanf(stdin, fmt, ap));
 }
+int
+vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+	return (vfwscanf_l(stdin, locale, fmt, ap));
+}
Index: lib/libc/stdio/sscanf.c
===================================================================
--- lib/libc/stdio/sscanf.c	(revision 225653)
+++ lib/libc/stdio/sscanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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,6 +44,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include <xlocale.h>
 #include "local.h"
 
 int
@@ -52,3 +58,15 @@
 	va_end(ap);
 	return (ret);
 }
+int
+sscanf_l(const char * __restrict str, locale_t locale,
+		char const * __restrict fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vsscanf_l(str, locale, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/fgetwc.c
===================================================================
--- lib/libc/stdio/fgetwc.c	(revision 225653)
+++ lib/libc/stdio/fgetwc.c	(working copy)
@@ -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:
@@ -36,31 +41,39 @@
 #include "libc_private.h"
 #include "local.h"
 #include "mblocal.h"
+#include "xlocale_private.h"
 
 /*
  * MT-safe version.
  */
 wint_t
-fgetwc(FILE *fp)
+fgetwc_l(FILE *fp, locale_t locale)
 {
 	wint_t r;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
-	r = __fgetwc(fp);
+	r = __fgetwc(fp, locale);
 	FUNLOCKFILE(fp);
 
 	return (r);
 }
+wint_t
+fgetwc(FILE *fp)
+{
+	return fgetwc_l(fp, __get_locale());
+}
 
 /*
  * Non-MT-safe version.
  */
 wint_t
-__fgetwc(FILE *fp)
+__fgetwc(FILE *fp, locale_t locale)
 {
 	wchar_t wc;
 	size_t nconv;
+	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
 
 	if (fp->_r <= 0 && __srefill(fp))
 		return (WEOF);
@@ -71,7 +84,7 @@
 		return (wc);
 	}
 	do {
-		nconv = __mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate);
+		nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate);
 		if (nconv == (size_t)-1)
 			break;
 		else if (nconv == (size_t)-2)
Index: lib/libc/stdio/vfscanf.c
===================================================================
--- lib/libc/stdio/vfscanf.c	(revision 225653)
+++ lib/libc/stdio/vfscanf.c	(working copy)
@@ -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.
+ *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
@@ -51,6 +56,7 @@
 #include "collate.h"
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
 #ifndef NO_FLOATING_POINT
 #include <locale.h>
@@ -95,11 +101,12 @@
 
 static const u_char *__sccl(char *, const u_char *);
 #ifndef NO_FLOATING_POINT
-static int parsefloat(FILE *, char *, char *);
+static int parsefloat(FILE *, char *, char *, locale_t);
 #endif
 
 __weak_reference(__vfscanf, vfscanf);
 
+
 /*
  * __vfscanf - MT-safe version
  */
@@ -109,16 +116,27 @@
 	int ret;
 
 	FLOCKFILE(fp);
-	ret = __svfscanf(fp, fmt0, ap);
+	ret = __svfscanf(fp, __get_locale(), fmt0, ap);
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+int
+vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
+{
+	int ret;
+	FIX_LOCALE(locale);
 
+	FLOCKFILE(fp);
+	ret = __svfscanf(fp, locale, fmt0, ap);
+	FUNLOCKFILE(fp);
+	return (ret);
+}
+
 /*
  * __svfscanf - non-MT-safe version of __vfscanf
  */
 int
-__svfscanf(FILE *fp, const char *fmt0, va_list ap)
+__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
 {
 	const u_char *fmt = (const u_char *)fmt0;
 	int c;			/* character from format, or conversion */
@@ -455,8 +473,7 @@
 						    !ccltab[wctob(*wcp)]) {
 							while (n != 0) {
 								n--;
-								__ungetc(buf[n],
-								    fp);
+								__ungetc(buf[n], fp);
 							}
 							break;
 						}
@@ -555,8 +572,7 @@
 						if (iswspace(*wcp)) {
 							while (n != 0) {
 								n--;
-								__ungetc(buf[n],
-								    fp);
+								__ungetc(buf[n], fp);
 							}
 							break;
 						}
@@ -733,9 +749,9 @@
 
 				*p = 0;
 				if ((flags & UNSIGNED) == 0)
-				    res = strtoimax(buf, (char **)NULL, base);
+				    res = strtoimax_l(buf, (char **)NULL, base, locale);
 				else
-				    res = strtoumax(buf, (char **)NULL, base);
+				    res = strtoumax_l(buf, (char **)NULL, base, locale);
 				if (flags & POINTER)
 					*va_arg(ap, void **) =
 							(void *)(uintptr_t)res;
@@ -766,17 +782,17 @@
 			/* scan a floating point number as if by strtod */
 			if (width == 0 || width > sizeof(buf) - 1)
 				width = sizeof(buf) - 1;
-			if ((width = parsefloat(fp, buf, buf + width)) == 0)
+			if ((width = parsefloat(fp, buf, buf + width, locale)) == 0)
 				goto match_failure;
 			if ((flags & SUPPRESS) == 0) {
 				if (flags & LONGDBL) {
-					long double res = strtold(buf, &p);
+					long double res = strtold_l(buf, &p, locale);
 					*va_arg(ap, long double *) = res;
 				} else if (flags & LONG) {
-					double res = strtod(buf, &p);
+					double res = strtod_l(buf, &p, locale);
 					*va_arg(ap, double *) = res;
 				} else {
-					float res = strtof(buf, &p);
+					float res = strtof_l(buf, &p, locale);
 					*va_arg(ap, float *) = res;
 				}
 				nassigned++;
@@ -805,6 +821,8 @@
 	const u_char *fmt;
 {
 	int c, n, v, i;
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
 
 	/* first `clear' the whole table */
 	c = *fmt++;		/* first char hat => negated scanset */
@@ -858,8 +876,8 @@
 			 */
 			n = *fmt;
 			if (n == ']'
-			    || (__collate_load_error ? n < c :
-				__collate_range_cmp (n, c) < 0
+			    || (table->__collate_load_error ? n < c :
+				__collate_range_cmp (table, n, c) < 0
 			       )
 			   ) {
 				c = '-';
@@ -867,14 +885,14 @@
 			}
 			fmt++;
 			/* fill in the range */
-			if (__collate_load_error) {
+			if (table->__collate_load_error) {
 				do {
 					tab[++c] = v;
 				} while (c < n);
 			} else {
 				for (i = 0; i < 256; i ++)
-					if (   __collate_range_cmp (c, i) < 0
-					    && __collate_range_cmp (i, n) <= 0
+					if (   __collate_range_cmp (table, c, i) < 0
+					    && __collate_range_cmp (table, i, n) <= 0
 					   )
 						tab[i] = v;
 			}
@@ -908,7 +926,7 @@
 
 #ifndef NO_FLOATING_POINT
 static int
-parsefloat(FILE *fp, char *buf, char *end)
+parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
 {
 	char *commit, *p;
 	int infnanpos = 0, decptpos = 0;
@@ -917,7 +935,7 @@
 		S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
 	} state = S_START;
 	unsigned char c;
-	const char *decpt = localeconv()->decimal_point;
+	const char *decpt = localeconv_l(locale)->decimal_point;
 	_Bool gotmantdig = 0, ishex = 0;
 
 	/*
Index: lib/libc/stdio/fgetws.c
===================================================================
--- lib/libc/stdio/fgetws.c	(revision 225653)
+++ lib/libc/stdio/fgetws.c	(working copy)
@@ -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:
@@ -38,12 +43,14 @@
 #include "mblocal.h"
 
 wchar_t *
-fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale)
 {
 	wchar_t *wsp;
 	size_t nconv;
 	const char *src;
 	unsigned char *nl;
+	FIX_LOCALE(locale);
+	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
@@ -60,7 +67,7 @@
 	do {
 		src = fp->_p;
 		nl = memchr(fp->_p, '\n', fp->_r);
-		nconv = __mbsnrtowcs(wsp, &src,
+		nconv = l->__mbsnrtowcs(wsp, &src,
 		    nl != NULL ? (nl - fp->_p + 1) : fp->_r,
 		    n - 1, &fp->_mbstate);
 		if (nconv == (size_t)-1)
@@ -86,7 +93,7 @@
 	if (wsp == ws)
 		/* EOF */
 		goto error;
-	if (!__mbsinit(&fp->_mbstate))
+	if (!l->__mbsinit(&fp->_mbstate))
 		/* Incomplete character */
 		goto error;
 	*wsp = L'\0';
@@ -98,3 +105,8 @@
 	FUNLOCKFILE(fp);
 	return (NULL);
 }
+wchar_t *
+fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+{
+	return fgetws_l(ws, n, fp, __get_locale());
+}
Index: lib/libc/stdio/vasprintf.c
===================================================================
--- lib/libc/stdio/vasprintf.c	(revision 225653)
+++ lib/libc/stdio/vasprintf.c	(working copy)
@@ -4,6 +4,11 @@
  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
  * 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,15 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
+#include "xlocale_private.h"
 #include "local.h"
 
 int
-vasprintf(char **str, const char *fmt, __va_list ap)
+vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
 {
 	FILE f = FAKE_FILE;
 	int ret;
+	FIX_LOCALE(locale);
 
 	f._flags = __SWR | __SSTR | __SALC;
 	f._bf._base = f._p = malloc(128);
@@ -49,7 +56,7 @@
 		return (-1);
 	}
 	f._bf._size = f._w = 127;		/* Leave room for the NUL */
-	ret = __vfprintf(&f, fmt, ap);
+	ret = __vfprintf(&f, locale, fmt, ap);
 	if (ret < 0) {
 		free(f._bf._base);
 		*str = NULL;
@@ -60,3 +67,8 @@
 	*str = (char *)f._bf._base;
 	return (ret);
 }
+int
+vasprintf(char **str, const char *fmt, __va_list ap)
+{
+	return vasprintf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/stdio/vfwscanf.c
===================================================================
--- lib/libc/stdio/vfwscanf.c	(revision 225653)
+++ lib/libc/stdio/vfwscanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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:
@@ -53,11 +58,8 @@
 
 #include "libc_private.h"
 #include "local.h"
+#include "xlocale_private.h"
 
-#ifndef NO_FLOATING_POINT
-#include <locale.h>
-#endif
-
 #define	BUF		513	/* Maximum length of numeric string. */
 
 /*
@@ -96,7 +98,7 @@
 #define	CT_FLOAT	4	/* %[efgEFG] conversion */
 
 #ifndef NO_FLOATING_POINT
-static int parsefloat(FILE *, wchar_t *, wchar_t *);
+static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t);
 #endif
 
 #define	INCCL(_c)	\
@@ -109,22 +111,30 @@
  * MT-safe version.
  */
 int
-vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+vfwscanf_l(FILE * __restrict fp, locale_t locale,
+		const wchar_t * __restrict fmt, va_list ap)
 {
 	int ret;
+	FIX_LOCALE(locale);
 
 	FLOCKFILE(fp);
 	ORIENT(fp, 1);
-	ret = __vfwscanf(fp, fmt, ap);
+	ret = __vfwscanf(fp, locale, fmt, ap);
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+int
+vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+{
+	return vfwscanf_l(fp, __get_locale(), fmt, ap);
+}
 
 /*
  * Non-MT-safe version.
  */
 int
-__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+__vfwscanf(FILE * __restrict fp, locale_t locale,
+		const wchar_t * __restrict fmt, va_list ap)
 {
 	wint_t c;		/* character from format, or conversion */
 	size_t width;		/* field width, or 0 */
@@ -159,11 +169,11 @@
 		if (c == 0)
 			return (nassigned);
 		if (iswspace(c)) {
-			while ((c = __fgetwc(fp)) != WEOF &&
-			    iswspace(c))
+			while ((c = __fgetwc(fp, locale)) != WEOF &&
+			    iswspace_l(c, locale))
 				;
 			if (c != WEOF)
-				__ungetwc(c, fp);
+				__ungetwc(c, fp, locale);
 			continue;
 		}
 		if (c != '%')
@@ -178,10 +188,10 @@
 		switch (c) {
 		case '%':
 literal:
-			if ((wi = __fgetwc(fp)) == WEOF)
+			if ((wi = __fgetwc(fp, locale)) == WEOF)
 				goto input_failure;
 			if (wi != c) {
-				__ungetwc(wi, fp);
+				__ungetwc(wi, fp, locale);
 				goto input_failure;
 			}
 			nread++;
@@ -341,11 +351,11 @@
 		 * that suppress this.
 		 */
 		if ((flags & NOSKIP) == 0) {
-			while ((wi = __fgetwc(fp)) != WEOF && iswspace(wi))
+			while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi))
 				nread++;
 			if (wi == WEOF)
 				goto input_failure;
-			__ungetwc(wi, fp);
+			__ungetwc(wi, fp, locale);
 		}
 
 		/*
@@ -362,7 +372,7 @@
 					p = va_arg(ap, wchar_t *);
 				n = 0;
 				while (width-- != 0 &&
-				    (wi = __fgetwc(fp)) != WEOF) {
+				    (wi = __fgetwc(fp, locale)) != WEOF) {
 					if (!(flags & SUPPRESS))
 						*p++ = (wchar_t)wi;
 					n++;
@@ -378,7 +388,7 @@
 				n = 0;
 				mbs = initial_mbs;
 				while (width != 0 &&
-				    (wi = __fgetwc(fp)) != WEOF) {
+				    (wi = __fgetwc(fp, locale)) != WEOF) {
 					if (width >= MB_CUR_MAX &&
 					    !(flags & SUPPRESS)) {
 						nconv = wcrtomb(mbp, wi, &mbs);
@@ -390,7 +400,7 @@
 						if (nconv == (size_t)-1)
 							goto input_failure;
 						if (nconv > width) {
-							__ungetwc(wi, fp);
+							__ungetwc(wi, fp, locale);
 							break;
 						}
 						if (!(flags & SUPPRESS))
@@ -418,20 +428,20 @@
 			/* take only those things in the class */
 			if ((flags & SUPPRESS) && (flags & LONG)) {
 				n = 0;
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width-- != 0 && INCCL(wi))
 					n++;
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 				if (n == 0)
 					goto match_failure;
 			} else if (flags & LONG) {
 				p0 = p = va_arg(ap, wchar_t *);
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width-- != 0 && INCCL(wi))
 					*p++ = (wchar_t)wi;
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 				n = p - p0;
 				if (n == 0)
 					goto match_failure;
@@ -442,7 +452,7 @@
 					mbp = va_arg(ap, char *);
 				n = 0;
 				mbs = initial_mbs;
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width != 0 && INCCL(wi)) {
 					if (width >= MB_CUR_MAX &&
 					   !(flags & SUPPRESS)) {
@@ -466,7 +476,7 @@
 					n++;
 				}
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 				if (!(flags & SUPPRESS)) {
 					*mbp = 0;
 					nassigned++;
@@ -481,29 +491,29 @@
 			if (width == 0)
 				width = (size_t)~0;
 			if ((flags & SUPPRESS) && (flags & LONG)) {
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width-- != 0 &&
 				    !iswspace(wi))
 					nread++;
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 			} else if (flags & LONG) {
 				p0 = p = va_arg(ap, wchar_t *);
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width-- != 0 &&
 				    !iswspace(wi)) {
 					*p++ = (wchar_t)wi;
 					nread++;
 				}
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 				*p = '\0';
 				nassigned++;
 			} else {
 				if (!(flags & SUPPRESS))
 					mbp = va_arg(ap, char *);
 				mbs = initial_mbs;
-				while ((wi = __fgetwc(fp)) != WEOF &&
+				while ((wi = __fgetwc(fp, locale)) != WEOF &&
 				    width != 0 &&
 				    !iswspace(wi)) {
 					if (width >= MB_CUR_MAX &&
@@ -528,7 +538,7 @@
 					nread++;
 				}
 				if (wi != WEOF)
-					__ungetwc(wi, fp);
+					__ungetwc(wi, fp, locale);
 				if (!(flags & SUPPRESS)) {
 					*mbp = 0;
 					nassigned++;
@@ -544,7 +554,7 @@
 				width = sizeof(buf) / sizeof(*buf) - 1;
 			flags |= SIGNOK | NDIGITS | NZDIGITS;
 			for (p = buf; width; width--) {
-				c = __fgetwc(fp);
+				c = __fgetwc(fp, locale);
 				/*
 				 * Switch on the character; `goto ok'
 				 * if we accept it as a part of number.
@@ -628,7 +638,7 @@
 				 * for a number.  Stop accumulating digits.
 				 */
 				if (c != WEOF)
-					__ungetwc(c, fp);
+					__ungetwc(c, fp, locale);
 				break;
 		ok:
 				/*
@@ -644,13 +654,13 @@
 			 */
 			if (flags & NDIGITS) {
 				if (p > buf)
-					__ungetwc(*--p, fp);
+					__ungetwc(*--p, fp, locale);
 				goto match_failure;
 			}
 			c = p[-1];
 			if (c == 'x' || c == 'X') {
 				--p;
-				__ungetwc(c, fp);
+				__ungetwc(c, fp, locale);
 			}
 			if ((flags & SUPPRESS) == 0) {
 				uintmax_t res;
@@ -691,7 +701,7 @@
 			if (width == 0 || width > sizeof(buf) /
 			    sizeof(*buf) - 1)
 				width = sizeof(buf) / sizeof(*buf) - 1;
-			if ((width = parsefloat(fp, buf, buf + width)) == 0)
+			if ((width = parsefloat(fp, buf, buf + width, locale)) == 0)
 				goto match_failure;
 			if ((flags & SUPPRESS) == 0) {
 				if (flags & LONGDBL) {
@@ -720,7 +730,7 @@
 
 #ifndef NO_FLOATING_POINT
 static int
-parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
+parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale)
 {
 	mbstate_t mbs;
 	size_t nconv;
@@ -751,7 +761,7 @@
 	commit = buf - 1;
 	c = WEOF;
 	for (p = buf; p < end; ) {
-		if ((c = __fgetwc(fp)) == WEOF)
+		if ((c = __fgetwc(fp, locale)) == WEOF)
 			break;
 reswitch:
 		switch (state) {
@@ -871,9 +881,9 @@
 
 parsedone:
 	if (c != WEOF)
-		__ungetwc(c, fp);
+		__ungetwc(c, fp, locale);
 	while (commit < --p)
-		__ungetwc(*p, fp);
+		__ungetwc(*p, fp, locale);
 	*++commit = '\0';
 	return (commit - buf);
 }
Index: lib/libc/stdio/asprintf.c
===================================================================
--- lib/libc/stdio/asprintf.c	(revision 225653)
+++ lib/libc/stdio/asprintf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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,6 +40,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <xlocale.h>
 
 int
 asprintf(char ** __restrict s, char const * __restrict fmt, ...)
@@ -47,3 +53,15 @@
 	va_end(ap);
 	return (ret);
 }
+int
+asprintf_l(char ** __restrict s, locale_t locale, char const * __restrict fmt,
+		...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vasprintf_l(s, locale, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
Index: lib/libc/stdio/vswscanf.c
===================================================================
--- lib/libc/stdio/vswscanf.c	(revision 225653)
+++ lib/libc/stdio/vswscanf.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Donn Seeley at UUNET Technologies, Inc.
  *
+ * 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:
@@ -46,6 +51,7 @@
 #include <string.h>
 #include <wchar.h>
 #include "local.h"
+#include "xlocale_private.h"
 
 static int	eofread(void *, char *, int);
 
@@ -57,8 +63,8 @@
 }
 
 int
-vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
-    va_list ap)
+vswscanf_l(const wchar_t * __restrict str, locale_t locale,
+		const wchar_t * __restrict fmt, va_list ap)
 {
 	static const mbstate_t initial;
 	mbstate_t mbs;
@@ -67,6 +73,7 @@
 	size_t mlen;
 	int r;
 	const wchar_t *strp;
+	FIX_LOCALE(locale);
 
 	/*
 	 * XXX Convert the wide character string to multibyte, which
@@ -76,7 +83,7 @@
 		return (EOF);
 	mbs = initial;
 	strp = str;
-	if ((mlen = wcsrtombs(mbstr, &strp, SIZE_T_MAX, &mbs)) == (size_t)-1) {
+	if ((mlen = wcsrtombs_l(mbstr, &strp, SIZE_T_MAX, &mbs, locale)) == (size_t)-1) {
 		free(mbstr);
 		return (EOF);
 	}
@@ -84,8 +91,14 @@
 	f._bf._base = f._p = (unsigned char *)mbstr;
 	f._bf._size = f._r = mlen;
 	f._read = eofread;
-	r = __vfwscanf(&f, fmt, ap);
+	r = __vfwscanf(&f, locale, fmt, ap);
 	free(mbstr);
 
 	return (r);
 }
+int
+vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
+    va_list ap)
+{
+	return vswscanf_l(str, __get_locale(), fmt, ap);
+}
Index: lib/libc/locale/collate.c
===================================================================
--- lib/libc/locale/collate.c	(revision 225653)
+++ lib/libc/locale/collate.c	(working copy)
@@ -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 @@
 
 #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
+};
+
+static struct xlocale_collate 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 &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 @@
 		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 @@
 	      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 @@
 }
 
 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 @@
 }
 
 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;
 
Index: lib/libc/locale/xlocale.c
===================================================================
--- lib/libc/locale/xlocale.c	(revision 0)
+++ lib/libc/locale/xlocale.c	(revision 0)
@@ -0,0 +1,312 @@
+/*-
+ * 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.
+ */
+
+#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;
+/*
+ * 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
+};
+
+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;
+			}
+		} else {
+			if (!dupcomponent(type, base, new)) {
+				success = 0;
+			}
+		}
+		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)
+{
+	FIX_LOCALE(loc);
+	for (int type=0 ; type<XLC_LAST ; type++) {
+		if (mask & 1) {
+			return loc->components[type]->locale;
+		}
+		mask >>= 1;
+	}
+	return NULL;
+}
+
+/*
+ * 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;
+}
+
Index: lib/libc/locale/ascii.c
===================================================================
--- lib/libc/locale/ascii.c	(revision 225653)
+++ lib/libc/locale/ascii.c	(working copy)
@@ -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 @@
 		    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);
 }
 
Index: lib/libc/locale/collate.h
===================================================================
--- lib/libc/locale/collate.h	(revision 225653)
+++ lib/libc/locale/collate.h	(working copy)
@@ -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 @@
 	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
Index: lib/libc/locale/wcstoumax.c
===================================================================
--- lib/libc/locale/wcstoumax.c	(revision 225653)
+++ lib/libc/locale/wcstoumax.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == L'-') {
 		neg = 1;
 		c = *s++;
@@ -86,8 +93,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/mbtowc.c
===================================================================
--- lib/libc/locale/mbtowc.c	(revision 225653)
+++ lib/libc/locale/mbtowc.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/wcstoul.c
===================================================================
--- lib/libc/locale/wcstoul.c	(revision 225653)
+++ lib/libc/locale/wcstoul.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == L'-') {
 		neg = 1;
 		c = *s++;
@@ -79,8 +87,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/gb2312.c
===================================================================
--- lib/libc/locale/gb2312.c	(revision 225653)
+++ lib/libc/locale/gb2312.c	(working copy)
@@ -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 @@
 #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 @@
 } _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);
 }
 
Index: lib/libc/locale/Symbol.map
===================================================================
--- lib/libc/locale/Symbol.map	(revision 225653)
+++ lib/libc/locale/Symbol.map	(working copy)
@@ -99,6 +99,98 @@
 	iswctype;
 	wctype;
 	wcwidth;
+	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 {
Index: lib/libc/locale/mblocal.h
===================================================================
--- lib/libc/locale/mblocal.h	(revision 225653)
+++ lib/libc/locale/mblocal.h	(working copy)
@@ -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_ */
Index: lib/libc/locale/DESIGN.xlocale
===================================================================
--- lib/libc/locale/DESIGN.xlocale	(revision 0)
+++ lib/libc/locale/DESIGN.xlocale	(revision 0)
@@ -0,0 +1,157 @@
+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.
Index: lib/libc/locale/mbsrtowcs.c
===================================================================
--- lib/libc/locale/mbsrtowcs.c	(revision 225653)
+++ lib/libc/locale/mbsrtowcs.c	(working copy)
@@ -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 @@
 #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());
 }
Index: lib/libc/locale/utf8.c
===================================================================
--- lib/libc/locale/utf8.c	(revision 225653)
+++ lib/libc/locale/utf8.c	(working copy)
@@ -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 @@
 } _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);
 }
Index: lib/libc/locale/collcmp.c
===================================================================
--- lib/libc/locale/collcmp.c	(revision 225653)
+++ lib/libc/locale/collcmp.c	(working copy)
@@ -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));
 }
Index: lib/libc/locale/Makefile.inc
===================================================================
--- lib/libc/locale/Makefile.inc	(revision 225653)
+++ lib/libc/locale/Makefile.inc	(working copy)
@@ -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 @@
 	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
 
Index: lib/libc/locale/wcstof.c
===================================================================
--- lib/libc/locale/wcstof.c	(revision 225653)
+++ lib/libc/locale/wcstof.c	(working copy)
@@ -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 @@
 #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 @@
 	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 @@
 	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 @@
 
 	return (val);
 }
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+	return wcstof_l(nptr, endptr, __get_locale());
+}
Index: lib/libc/locale/localeconv.3
===================================================================
--- lib/libc/locale/localeconv.3	(revision 225653)
+++ lib/libc/locale/localeconv.3	(working copy)
@@ -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
 .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 @@
 .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
Index: lib/libc/locale/mbsinit.c
===================================================================
--- lib/libc/locale/mbsinit.c	(revision 225653)
+++ lib/libc/locale/mbsinit.c	(working copy)
@@ -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 @@
 #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());
 }
Index: lib/libc/locale/wcwidth.c
===================================================================
--- lib/libc/locale/wcwidth.c	(revision 225653)
+++ lib/libc/locale/wcwidth.c	(working copy)
@@ -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));
+}
Index: lib/libc/locale/setlocale.c
===================================================================
--- lib/libc/locale/setlocale.c	(revision 225653)
+++ lib/libc/locale/setlocale.c	(working copy)
@@ -95,7 +95,7 @@
 
 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 @@
 
 	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;
 {
Index: lib/libc/locale/runetype.c
===================================================================
--- lib/libc/locale/runetype.c	(revision 225653)
+++ lib/libc/locale/runetype.c	(working copy)
@@ -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 @@
 #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 @@
 
 	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;
+}
Index: lib/libc/locale/btowc.c
===================================================================
--- lib/libc/locale/btowc.c	(revision 225653)
+++ lib/libc/locale/btowc.c	(working copy)
@@ -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 @@
 #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 @@
 	 * 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());
+}
Index: lib/libc/locale/mbrlen.c
===================================================================
--- lib/libc/locale/mbrlen.c	(revision 225653)
+++ lib/libc/locale/mbrlen.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/lmessages.c
===================================================================
--- lib/libc/locale/lmessages.c	(revision 225653)
+++ lib/libc/locale/lmessages.c	(working copy)
@@ -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 @@
 #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 @@
 	"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);
 }
 
Index: lib/libc/locale/big5.c
===================================================================
--- lib/libc/locale/big5.c	(revision 225653)
+++ lib/libc/locale/big5.c	(working copy)
@@ -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 @@
 } _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);
 }
 
Index: lib/libc/locale/lmessages.h
===================================================================
--- lib/libc/locale/lmessages.h	(revision 225653)
+++ lib/libc/locale/lmessages.h	(working copy)
@@ -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 @@
 	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_ */
Index: lib/libc/locale/duplocale.3
===================================================================
--- lib/libc/locale/duplocale.3	(revision 0)
+++ lib/libc/locale/duplocale.3	(revision 0)
@@ -0,0 +1,76 @@
+.\" 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.
+.\"
+.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
Index: lib/libc/locale/uselocale.3
===================================================================
--- lib/libc/locale/uselocale.3	(revision 0)
+++ lib/libc/locale/uselocale.3	(revision 0)
@@ -0,0 +1,60 @@
+.\" 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.
+.\"
+.\"     @(#)ctype.3	8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: head/lib/libc/locale/ctype.3 196820 2009-09-04 07:44:58Z des $
+.\"
+.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
Index: lib/libc/locale/freelocale.3
===================================================================
--- lib/libc/locale/freelocale.3	(revision 0)
+++ lib/libc/locale/freelocale.3	(revision 0)
@@ -0,0 +1,60 @@
+.\" 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.
+.\"
+.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 .
Index: lib/libc/locale/wcsrtombs.c
===================================================================
--- lib/libc/locale/wcsrtombs.c	(revision 225653)
+++ lib/libc/locale/wcsrtombs.c	(working copy)
@@ -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 @@
 #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());
 }
Index: lib/libc/locale/localeconv.c
===================================================================
--- lib/libc/locale/localeconv.c	(revision 225653)
+++ lib/libc/locale/localeconv.c	(working copy)
@@ -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 @@
  * 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 @@
 	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());
+}
Index: lib/libc/locale/wcsnrtombs.c
===================================================================
--- lib/libc/locale/wcsnrtombs.c	(revision 225653)
+++ lib/libc/locale/wcsnrtombs.c	(working copy)
@@ -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 @@
 #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 @@
 	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 @@
 	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 @@
 			 * 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);
 			}
Index: lib/libc/locale/gbk.c
===================================================================
--- lib/libc/locale/gbk.c	(revision 225653)
+++ lib/libc/locale/gbk.c	(working copy)
@@ -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 @@
 } _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);
 }
 
Index: lib/libc/locale/querylocale.3
===================================================================
--- lib/libc/locale/querylocale.3	(revision 0)
+++ lib/libc/locale/querylocale.3	(revision 0)
@@ -0,0 +1,55 @@
+.\" 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.
+.\"
+.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
Index: lib/libc/locale/wctype.c
===================================================================
--- lib/libc/locale/wctype.c	(revision 225653)
+++ lib/libc/locale/wctype.c	(working copy)
@@ -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 @@
 #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() ie 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 @@
 
 	return (props[i].mask);
 }
+
+wctype_t wctype(const char *property)
+{
+	return wctype_l(property, 0);
+}
Index: lib/libc/locale/lnumeric.c
===================================================================
--- lib/libc/locale/lnumeric.c	(revision 225653)
+++ lib/libc/locale/lnumeric.c	(working copy)
@@ -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 @@
 #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 @@
 	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);
+}
 
-int
-__numeric_load_locale(const char *name)
+struct xlocale_numeric __xlocale_global_numeric;
+
+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);
 }
 
Index: lib/libc/locale/wcstoimax.c
===================================================================
--- lib/libc/locale/wcstoimax.c	(revision 225653)
+++ lib/libc/locale/wcstoimax.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == L'-') {
 		neg = 1;
 		c = *s++;
@@ -88,8 +95,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/lnumeric.h
===================================================================
--- lib/libc/locale/lnumeric.h	(revision 225653)
+++ lib/libc/locale/lnumeric.h	(working copy)
@@ -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_ */
Index: lib/libc/locale/wctomb.c
===================================================================
--- lib/libc/locale/wctomb.c	(revision 225653)
+++ lib/libc/locale/wctomb.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/toupper.c
===================================================================
--- lib/libc/locale/toupper.c	(revision 225653)
+++ lib/libc/locale/toupper.c	(working copy)
@@ -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 @@
 #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 @@
 	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 @@
 
 	return(c);
 }
+__ct_rune_t
+___toupper(c)
+	__ct_rune_t c;
+{
+	return ___toupper_l(c, __get_locale());
+}
Index: lib/libc/locale/wcstombs.c
===================================================================
--- lib/libc/locale/wcstombs.c	(revision 225653)
+++ lib/libc/locale/wcstombs.c	(working copy)
@@ -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 @@
 #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());
+}
+
Index: lib/libc/locale/wcstoull.c
===================================================================
--- lib/libc/locale/wcstoull.c	(revision 225653)
+++ lib/libc/locale/wcstoull.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == L'-') {
 		neg = 1;
 		c = *s++;
@@ -86,8 +93,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/euc.c
===================================================================
--- lib/libc/locale/euc.c	(revision 225653)
+++ lib/libc/locale/euc.c	(working copy)
@@ -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 @@
 } _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 @@
 	}
 	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);
 }
 
Index: lib/libc/locale/wctob.c
===================================================================
--- lib/libc/locale/wctob.c	(revision 225653)
+++ lib/libc/locale/wctob.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/wcstold.c
===================================================================
--- lib/libc/locale/wcstold.c	(revision 225653)
+++ lib/libc/locale/wcstold.c	(working copy)
@@ -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 @@
 #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 @@
 	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());
+}
Index: lib/libc/locale/wctrans.c
===================================================================
--- lib/libc/locale/wctrans.c	(revision 225653)
+++ lib/libc/locale/wctrans.c	(working copy)
@@ -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 @@
 #include <errno.h>
 #include <string.h>
 #include <wctype.h>
+#include "xlocale_private.h"
 
 enum {
 	_WCT_ERROR	= 0,
@@ -38,15 +44,14 @@
 };
 
 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 @@
 
 	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 @@
 		errno = EINVAL;
 	return (ccls[i].trans);
 }
+
+wctrans_t
+wctrans(const char *charclass)
+{
+	return wctrans_l(charclass, 0);
+}
+
Index: lib/libc/locale/gb18030.c
===================================================================
--- lib/libc/locale/gb18030.c	(revision 225653)
+++ lib/libc/locale/gb18030.c	(working copy)
@@ -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 @@
 #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 @@
 } _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);
 }
Index: lib/libc/locale/nl_langinfo.c
===================================================================
--- lib/libc/locale/nl_langinfo.c	(revision 225653)
+++ lib/libc/locale/nl_langinfo.c	(working copy)
@@ -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 @@
 #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 @@
 		}
 		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 @@
 		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 @@
 	 * 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());
+}
Index: lib/libc/locale/table.c
===================================================================
--- lib/libc/locale/table.c	(revision 225653)
+++ lib/libc/locale/table.c	(working copy)
@@ -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 @@
 #include <wchar.h>
 #include "mblocal.h"
 
-_RuneLocale _DefaultRuneLocale = {
+const _RuneLocale _DefaultRuneLocale = {
     _RUNE_MAGIC_1,
     "NONE",
     NULL,
@@ -245,5 +250,14 @@
     },
 };
 
-_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;
+}
Index: lib/libc/locale/wcstoll.c
===================================================================
--- lib/libc/locale/wcstoll.c	(revision 225653)
+++ lib/libc/locale/wcstoll.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == L'-') {
 		neg = 1;
 		c = *s++;
@@ -87,8 +95,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/tolower.c
===================================================================
--- lib/libc/locale/tolower.c	(revision 225653)
+++ lib/libc/locale/tolower.c	(working copy)
@@ -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 @@
 #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 @@
 
 	return(c);
 }
+__ct_rune_t
+___tolower(c)
+	__ct_rune_t c;
+{
+	return ___tolower_l(c, __get_locale());
+}
Index: lib/libc/locale/mskanji.c
===================================================================
--- lib/libc/locale/mskanji.c	(revision 225653)
+++ lib/libc/locale/mskanji.c	(working copy)
@@ -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 @@
 } _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);
 }
 
Index: lib/libc/locale/mblen.c
===================================================================
--- lib/libc/locale/mblen.c	(revision 225653)
+++ lib/libc/locale/mblen.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/none.c
===================================================================
--- lib/libc/locale/none.c	(revision 225653)
+++ lib/libc/locale/none.c	(working copy)
@@ -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_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,14 @@
 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 */
+};
Index: lib/libc/locale/mbstowcs.c
===================================================================
--- lib/libc/locale/mbstowcs.c	(revision 225653)
+++ lib/libc/locale/mbstowcs.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/wcstod.c
===================================================================
--- lib/libc/locale/wcstod.c	(revision 225653)
+++ lib/libc/locale/wcstod.c	(working copy)
@@ -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 @@
 #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 @@
  * 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 @@
 	 * 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 @@
 	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 @@
 	 * 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());
+}
Index: lib/libc/locale/setrunelocale.c
===================================================================
--- lib/libc/locale/setrunelocale.c	(revision 225653)
+++ lib/libc/locale/setrunelocale.c	(working copy)
@@ -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 _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 @@
 	}
 	(void)fclose(fp);
 
-	old__mbrtowc = __mbrtowc;
-	old__mbsinit = __mbsinit;
-	old__mbsnrtowcs = __mbsnrtowcs;
-	old__wcrtomb = __wcrtomb;
-	old__wcsnrtombs = __wcsnrtombs;
+	l->__mbrtowc = NULL;
+	l->__mbsinit = NULL;
+	l->__mbsnrtowcs = __mbsnrtowcs_std;
+	l->__wcrtomb = NULL;
+	l->__wcsnrtombs = __wcsnrtombs_std;
 
-	__mbrtowc = NULL;
-	__mbsinit = NULL;
-	__mbsnrtowcs = __mbsnrtowcs_std;
-	__wcrtomb = NULL;
-	__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 @@
 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;
+}
Index: lib/libc/locale/lmonetary.c
===================================================================
--- lib/libc/locale/lmonetary.c	(revision 225653)
+++ lib/libc/locale/lmonetary.c	(working copy)
@@ -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 @@
 #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 @@
 	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 @@
 	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 @@
 		 */
 #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 @@
 	}
 	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);
 }
 
Index: lib/libc/locale/nextwctype.c
===================================================================
--- lib/libc/locale/nextwctype.c	(revision 225653)
+++ lib/libc/locale/nextwctype.c	(working copy)
@@ -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 @@
 #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 @@
 	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 @@
 	}
 	return (-1);
 }
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+	return nextwctype_l(wc, wct, __get_locale());
+}
Index: lib/libc/locale/wcstol.c
===================================================================
--- lib/libc/locale/wcstol.c	(revision 225653)
+++ lib/libc/locale/wcstol.c	(working copy)
@@ -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 @@
 #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 @@
 	s = nptr;
 	do {
 		c = *s++;
-	} while (iswspace(c));
+	} while (iswspace_l(c, locale));
 	if (c == '-') {
 		neg = 1;
 		c = *s++;
@@ -81,8 +89,8 @@
 	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 @@
 		*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());
+}
Index: lib/libc/locale/wcrtomb.c
===================================================================
--- lib/libc/locale/wcrtomb.c	(revision 225653)
+++ lib/libc/locale/wcrtomb.c	(working copy)
@@ -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 @@
 #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());
+}
Index: lib/libc/locale/lmonetary.h
===================================================================
--- lib/libc/locale/lmonetary.h	(revision 225653)
+++ lib/libc/locale/lmonetary.h	(working copy)
@@ -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 @@
 	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_ */
Index: lib/libc/locale/wcsftime.c
===================================================================
--- lib/libc/locale/wcsftime.c	(revision 225653)
+++ lib/libc/locale/wcsftime.c	(working copy)
@@ -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 @@
 #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 @@
  * 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 @@
 	const wchar_t *formatp;
 	size_t n, sflen;
 	int sverrno;
+	FIX_LOCALE(locale);
 
 	sformat = dst = NULL;
 
@@ -66,13 +74,13 @@
 	 */
 	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 @@
 	}
 	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 @@
 	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());
+}
Index: lib/libc/locale/xlocale_private.h
===================================================================
--- lib/libc/locale/xlocale_private.h	(revision 0)
+++ lib/libc/locale/xlocale_private.h	(revision 0)
@@ -0,0 +1,199 @@
+/*-
+ * 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.
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.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.  
+ *
+ * Note: We could save a few bytes by using a bitfield for the flags at the end
+ * of this structure.  I imagine that most programs will not have more than
+ * half a dozen locales though, so this doesn't seem worthwhile.
+ */
+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;
+	__sync_fetch_and_add(&(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 = __sync_sub_and_fetch(&(obj->retain_count), 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;
+
+/**
+ * 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_global_locale;
+		case -1: return __get_locale();
+		default: return locale;
+	}
+}
+
+/**
+ * Replace a plaecholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
Index: lib/libc/locale/newlocale.3
===================================================================
--- lib/libc/locale/newlocale.3	(revision 0)
+++ lib/libc/locale/newlocale.3	(revision 0)
@@ -0,0 +1,108 @@
+.\" 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.
+.\"
+.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
Index: lib/libc/locale/mbsnrtowcs.c
===================================================================
--- lib/libc/locale/mbsnrtowcs.c	(revision 225653)
+++ lib/libc/locale/mbsnrtowcs.c	(working copy)
@@ -1,6 +1,11 @@
 /*-
  * 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
  * modification, are permitted provided that the following conditions
@@ -34,14 +39,19 @@
 #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 @@
 	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 @@
 	}
 
 	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) {
Index: lib/libc/locale/xlocale.3
===================================================================
--- lib/libc/locale/xlocale.3	(revision 0)
+++ lib/libc/locale/xlocale.3	(revision 0)
@@ -0,0 +1,265 @@
+.\" 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.
+.\"
+.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 opqaue 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.  
+.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 .
Index: lib/libc/locale/mbrtowc.c
===================================================================
--- lib/libc/locale/mbrtowc.c	(revision 225653)
+++ lib/libc/locale/mbrtowc.c	(working copy)
@@ -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 @@
 #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());
 }
Index: lib/libc/locale/ctype.c
===================================================================
--- lib/libc/locale/ctype.c	(revision 0)
+++ lib/libc/locale/ctype.c	(revision 0)
@@ -0,0 +1,31 @@
+/*-
+ * 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.
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
Index: lib/libc/stdtime/timelocal.h
===================================================================
--- lib/libc/stdtime/timelocal.h	(revision 225653)
+++ lib/libc/stdtime/timelocal.h	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1997-2002 FreeBSD Project.
  * 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 _TIMELOCAL_H_
 #define	_TIMELOCAL_H_
+#include "xlocale_private.h"
 
 /*
  * Private header file for the strftime and strptime localization
@@ -49,7 +55,7 @@
 	const char	*ampm_fmt;
 };
 
-struct lc_time_T *__get_current_time_locale(void);
+struct lc_time_T *__get_current_time_locale(locale_t);
 int	__time_load_locale(const char *);
 
 #endif /* !_TIMELOCAL_H_ */
Index: lib/libc/stdtime/strptime.c
===================================================================
--- lib/libc/stdtime/strptime.c	(revision 225653)
+++ lib/libc/stdtime/strptime.c	(working copy)
@@ -22,6 +22,11 @@
 /*
  * Copyright (c) 1994 Powerdog Industries.  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:
@@ -72,19 +77,20 @@
 #include "libc_private.h"
 #include "timelocal.h"
 
-static char * _strptime(const char *, const char *, struct tm *, int *);
+static char * _strptime(const char *, const char *, struct tm *, int *, locale_t);
 
 #define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
 
 static char *
-_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
+_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
+		locale_t locale)
 {
 	char	c;
 	const char *ptr;
 	int	i,
 		len;
 	int Ealternative, Oalternative;
-	struct lc_time_T *tptr = __get_current_time_locale();
+	struct lc_time_T *tptr = __get_current_time_locale(locale);
 
 	ptr = fmt;
 	while (*ptr != 0) {
@@ -94,8 +100,8 @@
 		c = *ptr++;
 
 		if (c != '%') {
-			if (isspace((unsigned char)c))
-				while (*buf != 0 && isspace((unsigned char)*buf))
+			if (isspace_l((unsigned char)c, locale))
+				while (*buf != 0 && isspace_l((unsigned char)*buf, locale))
 					buf++;
 			else if (c != *buf++)
 				return 0;
@@ -114,18 +120,18 @@
 			break;
 
 		case '+':
-			buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
+			buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'C':
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			/* XXX This will break for 3-digit centuries. */
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -137,13 +143,13 @@
 			break;
 
 		case 'c':
-			buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
+			buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'D':
-			buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
+			buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
@@ -161,47 +167,47 @@
 			goto label;
 
 		case 'F':
-			buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
+			buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'R':
-			buf = _strptime(buf, "%H:%M", tm, GMTp);
+			buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'r':
-			buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
+			buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'T':
-			buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
+			buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'X':
-			buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
+			buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'x':
-			buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
+			buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
 			if (buf == 0)
 				return 0;
 			break;
 
 		case 'j':
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 3;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -214,14 +220,14 @@
 
 		case 'M':
 		case 'S':
-			if (*buf == 0 || isspace((unsigned char)*buf))
+			if (*buf == 0 || isspace_l((unsigned char)*buf, locale))
 				break;
 
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -237,8 +243,8 @@
 				tm->tm_sec = i;
 			}
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -254,11 +260,11 @@
 			 * XXX The %l specifier may gobble one too many
 			 * digits if used incorrectly.
 			 */
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -271,8 +277,8 @@
 
 			tm->tm_hour = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -282,7 +288,7 @@
 			 * specifiers.
 			 */
 			len = strlen(tptr->am);
-			if (strncasecmp(buf, tptr->am, len) == 0) {
+			if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
 				if (tm->tm_hour > 12)
 					return 0;
 				if (tm->tm_hour == 12)
@@ -292,7 +298,7 @@
 			}
 
 			len = strlen(tptr->pm);
-			if (strncasecmp(buf, tptr->pm, len) == 0) {
+			if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
 				if (tm->tm_hour > 12)
 					return 0;
 				if (tm->tm_hour != 12)
@@ -307,12 +313,12 @@
 		case 'a':
 			for (i = 0; i < asizeof(tptr->weekday); i++) {
 				len = strlen(tptr->weekday[i]);
-				if (strncasecmp(buf, tptr->weekday[i],
-						len) == 0)
+				if (strncasecmp_l(buf, tptr->weekday[i],
+						len, locale) == 0)
 					break;
 				len = strlen(tptr->wday[i]);
-				if (strncasecmp(buf, tptr->wday[i],
-						len) == 0)
+				if (strncasecmp_l(buf, tptr->wday[i],
+						len, locale) == 0)
 					break;
 			}
 			if (i == asizeof(tptr->weekday))
@@ -330,11 +336,11 @@
 			 * point to calculate a real value, so just check the
 			 * range for now.
 			 */
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -342,13 +348,13 @@
 			if (i > 53)
 				return 0;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
 		case 'w':
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			i = *buf - '0';
@@ -357,8 +363,8 @@
 
 			tm->tm_wday = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -372,11 +378,11 @@
 			 * XXX The %e specifier may gobble one too many
 			 * digits if used incorrectly.
 			 */
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -386,8 +392,8 @@
 
 			tm->tm_mday = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -398,15 +404,15 @@
 				if (Oalternative) {
 					if (c == 'B') {
 						len = strlen(tptr->alt_month[i]);
-						if (strncasecmp(buf,
+						if (strncasecmp_l(buf,
 								tptr->alt_month[i],
-								len) == 0)
+								len, locale) == 0)
 							break;
 					}
 				} else {
 					len = strlen(tptr->month[i]);
-					if (strncasecmp(buf, tptr->month[i],
-							len) == 0)
+					if (strncasecmp_l(buf, tptr->month[i],
+							len, locale) == 0)
 						break;
 				}
 			}
@@ -417,8 +423,8 @@
 			if (i == asizeof(tptr->month) && !Oalternative) {
 				for (i = 0; i < asizeof(tptr->month); i++) {
 					len = strlen(tptr->mon[i]);
-					if (strncasecmp(buf, tptr->mon[i],
-							len) == 0)
+					if (strncasecmp_l(buf, tptr->mon[i],
+							len, locale) == 0)
 						break;
 				}
 			}
@@ -430,11 +436,11 @@
 			break;
 
 		case 'm':
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -444,8 +450,8 @@
 
 			tm->tm_mon = i - 1;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -458,7 +464,7 @@
 
 			sverrno = errno;
 			errno = 0;
-			n = strtol(buf, &cp, 10);
+			n = strtol_l(buf, &cp, 10, locale);
 			if (errno == ERANGE || (long)(t = n) != n) {
 				errno = sverrno;
 				return 0;
@@ -472,14 +478,14 @@
 
 		case 'Y':
 		case 'y':
-			if (*buf == 0 || isspace((unsigned char)*buf))
+			if (*buf == 0 || isspace_l((unsigned char)*buf, locale))
 				break;
 
-			if (!isdigit((unsigned char)*buf))
+			if (!isdigit_l((unsigned char)*buf, locale))
 				return 0;
 
 			len = (c == 'Y') ? 4 : 2;
-			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+			for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, locale); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -493,8 +499,8 @@
 
 			tm->tm_year = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 && !isspace((unsigned char)*ptr))
+			if (*buf != 0 && isspace_l((unsigned char)*buf, locale))
+				while (*ptr != 0 && !isspace_l((unsigned char)*ptr, locale))
 					ptr++;
 			break;
 
@@ -503,7 +509,7 @@
 			const char *cp;
 			char *zonestr;
 
-			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
+			for (cp = buf; *cp && isupper_l((unsigned char)*cp, locale); ++cp) {/*empty*/}
 			if (cp - buf) {
 				zonestr = alloca(cp - buf + 1);
 				strncpy(zonestr, buf, cp - buf);
@@ -537,7 +543,7 @@
 			buf++;
 			i = 0;
 			for (len = 4; len > 0; len--) {
-				if (isdigit((unsigned char)*buf)) {
+				if (isdigit_l((unsigned char)*buf, locale)) {
 					i *= 10;
 					i += *buf - '0';
 					buf++;
@@ -557,14 +563,15 @@
 
 
 char *
-strptime(const char * __restrict buf, const char * __restrict fmt,
-    struct tm * __restrict tm)
+strptime_l(const char * __restrict buf, const char * __restrict fmt,
+    struct tm * __restrict tm, locale_t loc)
 {
 	char *ret;
 	int gmt;
+	FIX_LOCALE(loc);
 
 	gmt = 0;
-	ret = _strptime(buf, fmt, tm, &gmt);
+	ret = _strptime(buf, fmt, tm, &gmt, loc);
 	if (ret && gmt) {
 		time_t t = timegm(tm);
 		localtime_r(&t, tm);
@@ -572,3 +579,9 @@
 
 	return (ret);
 }
+char *
+strptime(const char * __restrict buf, const char * __restrict fmt,
+    struct tm * __restrict tm)
+{
+	return strptime_l(buf, fmt, tm, __get_locale());
+}
Index: lib/libc/stdtime/timelocal.c
===================================================================
--- lib/libc/stdtime/timelocal.c	(revision 225653)
+++ lib/libc/stdtime/timelocal.c	(working copy)
@@ -3,6 +3,11 @@
  * Copyright (c) 1997 FreeBSD Inc.
  * 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,10 +38,14 @@
 #include "ldpart.h"
 #include "timelocal.h"
 
-static struct lc_time_T _time_locale;
-static int _time_using_locale;
-static char *time_locale_buf;
+struct xlocale_time {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_time_T locale;
+};
 
+struct xlocale_time __xlocale_global_time;
+
 #define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
 
 static const struct lc_time_T	_C_time_locale = {
@@ -99,19 +108,47 @@
 	"%I:%M:%S %p"
 };
 
+static void destruct_time(void *v)
+{
+	struct xlocale_time *l = v;
+	if (l->buffer)
+		free(l->buffer);
+	free(l);
+}
+
+#include <stdio.h>
 struct lc_time_T *
-__get_current_time_locale(void)
+__get_current_time_locale(locale_t loc)
 {
-	return (_time_using_locale
-		? &_time_locale
+	return (loc->using_time_locale
+		? &((struct xlocale_time *)loc->components[XLC_TIME])->locale
 		: (struct lc_time_T *)&_C_time_locale);
 }
 
+static int
+time_load_locale(struct xlocale_time *l, int *using_locale, const char *name)
+{
+	struct lc_time_T *time_locale = &l->locale;
+	return (__part_load_locale(name, using_locale,
+			&l->buffer, "LC_TIME",
+			LCTIME_SIZE, LCTIME_SIZE,
+			(const char **)time_locale));
+}
 int
 __time_load_locale(const char *name)
 {
-	return (__part_load_locale(name, &_time_using_locale,
-			&time_locale_buf, "LC_TIME",
-			LCTIME_SIZE, LCTIME_SIZE,
-			(const char **)&_time_locale));
+	return time_load_locale(&__xlocale_global_time,
+			&__xlocale_global_locale.using_time_locale, name);
 }
+extern void* __time_load(const char* name, locale_t loc)
+{
+	struct xlocale_time *new = calloc(sizeof(struct xlocale_time), 1);
+	new->header.header.destructor = destruct_time;
+	if (time_load_locale(new, &loc->using_time_locale, name) == _LDP_ERROR)
+	{
+		xlocale_release(new);
+		return NULL;
+	}
+	return new;
+}
+
Index: lib/libc/stdtime/strftime.c
===================================================================
--- lib/libc/stdtime/strftime.c	(revision 225653)
+++ lib/libc/stdtime/strftime.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1989 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 are permitted
  * provided that the above copyright notice and this paragraph are
  * duplicated in all such forms and that any documentation,
@@ -43,7 +48,7 @@
 static char *	_add(const char *, char *, const char *);
 static char *	_conv(int, const char *, char *, const char *);
 static char *	_fmt(const char *, const struct tm *, char *, const char *,
-			int *);
+			int *, locale_t);
 static char *	_yconv(int, int, int, int, char *, const char *);
 
 extern char *	tzname[];
@@ -82,29 +87,30 @@
 };
 
 size_t
-strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
-    const struct tm * __restrict t)
+strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,
+    const struct tm * __restrict t, locale_t loc)
 {
 	char *	p;
 	int	warn;
+	FIX_LOCALE(loc);
 
 	tzset();
 	warn = IN_NONE;
-	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
+	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);
 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
 	if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
-		(void) fprintf(stderr, "\n");
+		(void) fprintf_l(stderr, loc, "\n");
 		if (format == NULL)
-			(void) fprintf(stderr, "NULL strftime format ");
-		else	(void) fprintf(stderr, "strftime format \"%s\" ",
+			(void) fprintf_l(stderr, loc, "NULL strftime format ");
+		else	(void) fprintf_l(stderr, loc, "strftime format \"%s\" ",
 				format);
-		(void) fprintf(stderr, "yields only two digits of years in ");
+		(void) fprintf_l(stderr, loc, "yields only two digits of years in ");
 		if (warn == IN_SOME)
-			(void) fprintf(stderr, "some locales");
+			(void) fprintf_l(stderr, loc, "some locales");
 		else if (warn == IN_THIS)
-			(void) fprintf(stderr, "the current locale");
-		else	(void) fprintf(stderr, "all locales");
-		(void) fprintf(stderr, "\n");
+			(void) fprintf_l(stderr, loc, "the current locale");
+		else	(void) fprintf_l(stderr, loc, "all locales");
+		(void) fprintf_l(stderr, loc, "\n");
 	}
 #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
 	if (p == s + maxsize)
@@ -113,16 +119,24 @@
 	return p - s;
 }
 
+size_t
+strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
+    const struct tm * __restrict t)
+{
+	return strftime_l(s, maxsize, format, t, __get_locale());
+}
+
 static char *
-_fmt(format, t, pt, ptlim, warnp)
+_fmt(format, t, pt, ptlim, warnp, loc)
 const char *		format;
 const struct tm * const	t;
 char *			pt;
 const char * const	ptlim;
 int *			warnp;
+locale_t	loc;
 {
 	int Ealternative, Oalternative, PadIndex;
-	struct lc_time_T *tptr = __get_current_time_locale();
+	struct lc_time_T *tptr = __get_current_time_locale(loc);
 
 	for ( ; *format; ++format) {
 		if (*format == '%') {
@@ -175,7 +189,7 @@
 				{
 				int warn2 = IN_SOME;
 
-				pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2);
+				pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc);
 				if (warn2 == IN_ALL)
 					warn2 = IN_THIS;
 				if (warn2 > *warnp)
@@ -183,7 +197,7 @@
 				}
 				continue;
 			case 'D':
-				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
+				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc);
 				continue;
 			case 'd':
 				pt = _conv(t->tm_mday, fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
@@ -216,7 +230,7 @@
 					fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex], pt, ptlim);
 				continue;
 			case 'F':
-				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
+				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc);
 				continue;
 			case 'H':
 				pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
@@ -285,11 +299,11 @@
 					pt, ptlim);
 				continue;
 			case 'R':
-				pt = _fmt("%H:%M", t, pt, ptlim, warnp);
+				pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);
 				continue;
 			case 'r':
 				pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
-					warnp);
+					warnp, loc);
 				continue;
 			case 'S':
 				pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
@@ -313,7 +327,7 @@
 				}
 				continue;
 			case 'T':
-				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
+				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc);
 				continue;
 			case 't':
 				pt = _add("\t", pt, ptlim);
@@ -428,7 +442,7 @@
 				** "date as dd-bbb-YYYY"
 				** (ado, 1993-05-24)
 				*/
-				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
+				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc);
 				continue;
 			case 'W':
 				pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -441,13 +455,13 @@
 				pt = _conv(t->tm_wday, "%d", pt, ptlim);
 				continue;
 			case 'X':
-				pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp);
+				pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc);
 				continue;
 			case 'x':
 				{
 				int	warn2 = IN_SOME;
 
-				pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2);
+				pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc);
 				if (warn2 == IN_ALL)
 					warn2 = IN_THIS;
 				if (warn2 > *warnp)
@@ -534,7 +548,7 @@
 				continue;
 			case '+':
 				pt = _fmt(tptr->date_fmt, t, pt, ptlim,
-					warnp);
+					warnp, loc);
 				continue;
 			case '-':
 				if (PadIndex != PAD_DEFAULT)
Index: lib/libc/gen/glob.c
===================================================================
--- lib/libc/gen/glob.c	(revision 225653)
+++ lib/libc/gen/glob.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Guido van Rossum.
  *
+ * 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:
@@ -751,6 +756,8 @@
 {
 	int ok, negate_range;
 	Char c, k;
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
 
 	while (pat < patend) {
 		c = *pat++;
@@ -775,10 +782,10 @@
 				++pat;
 			while (((c = *pat++) & M_MASK) != M_END)
 				if ((*pat & M_MASK) == M_RNG) {
-					if (__collate_load_error ?
+					if (table->__collate_load_error ?
 					    CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
-					       __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
-					    && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
+					       __collate_range_cmp(table, CHAR(c), CHAR(k)) <= 0
+					    && __collate_range_cmp(table, CHAR(k), CHAR(pat[1])) <= 0
 					   )
 						ok = 1;
 					pat += 2;
Index: lib/libc/gen/fnmatch.c
===================================================================
--- lib/libc/gen/fnmatch.c	(revision 225653)
+++ lib/libc/gen/fnmatch.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Guido van Rossum.
  *
+ * 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:
@@ -222,6 +227,8 @@
 	wchar_t c, c2;
 	size_t pclen;
 	const char *origpat;
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
 
 	/*
 	 * A bracket expression starting with an unquoted circumflex
@@ -276,10 +283,10 @@
 			if (flags & FNM_CASEFOLD)
 				c2 = towlower(c2);
 
-			if (__collate_load_error ?
+			if (table->__collate_load_error ?
 			    c <= test && test <= c2 :
-			       __collate_range_cmp(c, test) <= 0
-			    && __collate_range_cmp(test, c2) <= 0
+			       __collate_range_cmp(table, c, test) <= 0
+			    && __collate_range_cmp(table, test, c2) <= 0
 			   )
 				ok = 1;
 		} else if (c == test)
Index: lib/libc/regex/regcomp.c
===================================================================
--- lib/libc/regex/regcomp.c	(revision 225653)
+++ lib/libc/regex/regcomp.c	(working copy)
@@ -3,9 +3,19 @@
  * Copyright (c) 1992, 1993, 1994
  *	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.
+ *
  * This code is derived from software contributed to Berkeley by
  * Henry Spencer.
  *
+ * 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:
@@ -730,6 +740,8 @@
 	char c;
 	wint_t start, finish;
 	wint_t i;
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
 
 	/* classify what we've got */
 	switch ((MORE()) ? PEEK() : '\0') {
@@ -778,14 +790,14 @@
 		if (start == finish)
 			CHadd(p, cs, start);
 		else {
-			if (__collate_load_error) {
+			if (table->__collate_load_error) {
 				(void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE);
 				CHaddrange(p, cs, start, finish);
 			} else {
-				(void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE);
+				(void)REQUIRE(__collate_range_cmp(table, start, finish) <= 0, REG_ERANGE);
 				for (i = 0; i <= UCHAR_MAX; i++) {
-					if (   __collate_range_cmp(start, i) <= 0
-					    && __collate_range_cmp(i, finish) <= 0
+					if (   __collate_range_cmp(table, start, i) <= 0
+					    && __collate_range_cmp(table, i, finish) <= 0
 					   )
 						CHadd(p, cs, i);
 				}
Index: lib/libc/Makefile
===================================================================
--- lib/libc/Makefile	(revision 225653)
+++ lib/libc/Makefile	(working copy)
@@ -3,6 +3,9 @@
 
 SHLIBDIR?= /lib
 
+DEBUG_CFLAGS+=-g
+CFLAGS+=-g
+
 .include <bsd.own.mk>
 
 # Pick the current architecture directory for libc. In general, this is
@@ -36,6 +39,7 @@
 CFLAGS+=${CANCELPOINTS_CFLAGS}
 .endif
 
+
 #
 # Only link with static libgcc.a (no libgcc_eh.a).
 #
Index: lib/libc/gdtoa/machdep_ldisd.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisd.c	(revision 225653)
+++ lib/libc/gdtoa/machdep_ldisd.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das@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,10 +39,10 @@
 __FBSDID("$FreeBSD$");
 
 #include "gdtoaimp.h"
+#undef strtold_l
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
-
-	return strtod(s, sp);
+	return __strtod_l(s, sp, locale);
 }
Index: lib/libc/gdtoa/machdep_ldisx.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisx.c	(revision 225653)
+++ lib/libc/gdtoa/machdep_ldisx.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das@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:
@@ -38,10 +43,11 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
 	long double result;
+	FIX_LOCALE(locale);
 
-	strtorx(s, sp, FLT_ROUNDS, &result);
+	strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
 	return result;
 }
Index: lib/libc/gdtoa/machdep_ldisQ.c
===================================================================
--- lib/libc/gdtoa/machdep_ldisQ.c	(revision 225653)
+++ lib/libc/gdtoa/machdep_ldisQ.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 2003 David Schultz <das@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:
@@ -38,10 +43,10 @@
 #include "gdtoaimp.h"
 
 long double
-strtold(const char * __restrict s, char ** __restrict sp)
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
 {
 	long double result;
 
-	strtorQ(s, sp, FLT_ROUNDS, &result);
+	strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
 	return result;
 }
Index: lib/libc/string/strcasecmp.c
===================================================================
--- lib/libc/string/strcasecmp.c	(revision 225653)
+++ lib/libc/string/strcasecmp.c	(working copy)
@@ -2,6 +2,11 @@
  * Copyright (c) 1987, 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,36 +40,50 @@
 
 #include <strings.h>
 #include <ctype.h>
+#include "xlocale_private.h"
 
 typedef unsigned char u_char;
 
 int
-strcasecmp(const char *s1, const char *s2)
+strcasecmp_l(const char *s1, const char *s2, locale_t locale)
 {
 	const u_char
 			*us1 = (const u_char *)s1,
 			*us2 = (const u_char *)s2;
+	FIX_LOCALE(locale);
 
-	while (tolower(*us1) == tolower(*us2++))
+	while (tolower_l(*us1, locale) == tolower_l(*us2++, locale))
 		if (*us1++ == '\0')
 			return (0);
-	return (tolower(*us1) - tolower(*--us2));
+	return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
 }
+int
+strcasecmp(const char *s1, const char *s2)
+{
+	return strcasecmp_l(s1, s2, __get_locale());
+}
 
 int
-strncasecmp(const char *s1, const char *s2, size_t n)
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
 {
+	FIX_LOCALE(locale);
 	if (n != 0) {
 		const u_char
 				*us1 = (const u_char *)s1,
 				*us2 = (const u_char *)s2;
 
 		do {
-			if (tolower(*us1) != tolower(*us2++))
-				return (tolower(*us1) - tolower(*--us2));
+			if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
+				return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
 			if (*us1++ == '\0')
 				break;
 		} while (--n != 0);
 	}
 	return (0);
 }
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	return strncasecmp_l(s1, s2, n, __get_locale());
+}
Index: lib/libc/string/wcscoll.c
===================================================================
--- lib/libc/string/wcscoll.c	(revision 225653)
+++ lib/libc/string/wcscoll.c	(working copy)
@@ -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:
@@ -41,12 +46,15 @@
  * with extended character sets.
  */
 int
-wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale)
 {
 	char *mbs1, *mbs2;
 	int diff, sverrno;
+	FIX_LOCALE(locale);
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)locale->components[XLC_COLLATE];
 
-	if (__collate_load_error || MB_CUR_MAX > 1)
+	if (table->__collate_load_error || MB_CUR_MAX > 1)
 		/*
 		 * Locale has no special collating order, could not be
 		 * loaded, or has an extended character set; do a fast binary
@@ -67,7 +75,7 @@
 		return (wcscmp(ws1, ws2));
 	}
 
-	diff = strcoll(mbs1, mbs2);
+	diff = strcoll_l(mbs1, mbs2, locale);
 	sverrno = errno;
 	free(mbs1);
 	free(mbs2);
@@ -76,6 +84,12 @@
 	return (diff);
 }
 
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+	return wcscoll_l(ws1, ws2, __get_locale());
+}
+
 static char *
 __mbsdup(const wchar_t *ws)
 {
Index: lib/libc/string/wcswidth.c
===================================================================
--- lib/libc/string/wcswidth.c	(revision 225653)
+++ lib/libc/string/wcswidth.c	(working copy)
@@ -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,19 +44,26 @@
 __FBSDID("$FreeBSD$");
 
 #include <wchar.h>
+#include "xlocale_private.h"
 
 int
-wcswidth(const wchar_t *pwcs, size_t n)
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale)
 {
 	wchar_t wc;
 	int len, l;
+	FIX_LOCALE(locale);
 
 	len = 0;
 	while (n-- > 0 && (wc = *pwcs++) != L'\0') {
-		if ((l = wcwidth(wc)) < 0)
+		if ((l = wcwidth_l(wc, locale)) < 0)
 			return (-1);
 		len += l;
 	}
 	return (len);
 }
 
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+	return wcswidth_l(pwcs, n, __get_locale());
+}
Index: lib/libc/string/Symbol.map
===================================================================
--- lib/libc/string/Symbol.map	(revision 225653)
+++ lib/libc/string/Symbol.map	(working copy)
@@ -75,6 +75,11 @@
 	wmemcpy;
 	wmemmove;
 	wmemset;
+	strcasecmp_l;
+	strcasestr_l;
+	strncasecmp_l;
+	wcswidth_l;
+	wcwidth_l;
 };
 
 FBSD_1.1 {
Index: lib/libc/string/strcoll.c
===================================================================
--- lib/libc/string/strcoll.c	(revision 225653)
+++ lib/libc/string/strcoll.c	(working copy)
@@ -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:
@@ -32,21 +37,26 @@
 #include <string.h>
 #include "collate.h"
 
+#include <stdio.h>
+
 int
-strcoll(const char *s, const char *s2)
+strcoll_l(const char *s, const char *s2, locale_t locale)
 {
 	int len, len2, prim, prim2, sec, sec2, ret, ret2;
 	const char *t, *t2;
 	char *tt, *tt2;
+	FIX_LOCALE(locale);
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)locale->components[XLC_COLLATE];
 
-	if (__collate_load_error)
+	if (table->__collate_load_error)
 		return strcmp(s, s2);
 
 	len = len2 = 1;
 	ret = ret2 = 0;
-	if (__collate_substitute_nontrivial) {
-		t = tt = __collate_substitute(s);
-		t2 = tt2 = __collate_substitute(s2);
+	if (table->__collate_substitute_nontrivial) {
+		t = tt = __collate_substitute(table, s);
+		t2 = tt2 = __collate_substitute(table, s2);
 	} else {
 		tt = tt2 = NULL;
 		t = s;
@@ -55,11 +65,11 @@
 	while(*t && *t2) {
 		prim = prim2 = 0;
 		while(*t && !prim) {
-			__collate_lookup(t, &len, &prim, &sec);
+			__collate_lookup(table, t, &len, &prim, &sec);
 			t += len;
 		}
 		while(*t2 && !prim2) {
-			__collate_lookup(t2, &len2, &prim2, &sec2);
+			__collate_lookup(table, t2, &len2, &prim2, &sec2);
 			t2 += len2;
 		}
 		if(!prim || !prim2)
@@ -83,3 +93,10 @@
 
 	return ret;
 }
+
+int
+strcoll(const char *s, const char *s2)
+{
+	return strcoll_l(s, s2, __get_locale());
+}
+
Index: lib/libc/string/wcsxfrm.c
===================================================================
--- lib/libc/string/wcsxfrm.c	(revision 225653)
+++ lib/libc/string/wcsxfrm.c	(working copy)
@@ -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:
@@ -43,11 +48,14 @@
  * the logic used.
  */
 size_t
-wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len, locale_t locale)
 {
 	int prim, sec, l;
 	size_t slen;
 	char *mbsrc, *s, *ss;
+	FIX_LOCALE(locale);
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)locale->components[XLC_COLLATE];
 
 	if (*src == L'\0') {
 		if (len != 0)
@@ -55,7 +63,7 @@
 		return (0);
 	}
 
-	if (__collate_load_error || MB_CUR_MAX > 1) {
+	if (table->__collate_load_error || MB_CUR_MAX > 1) {
 		slen = wcslen(src);
 		if (len > 0) {
 			if (slen < len)
@@ -71,10 +79,10 @@
 	mbsrc = __mbsdup(src);
 	slen = 0;
 	prim = sec = 0;
-	ss = s = __collate_substitute(mbsrc);
+	ss = s = __collate_substitute(table, mbsrc);
 	while (*s != '\0') {
 		while (*s != '\0' && prim == 0) {
-			__collate_lookup(s, &l, &prim, &sec);
+			__collate_lookup(table, s, &l, &prim, &sec);
 			s += l;
 		}
 		if (prim != 0) {
@@ -93,6 +101,11 @@
 
 	return (slen);
 }
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+{
+	return wcsxfrm_l(dest, src, len, __get_locale());
+}
 
 static char *
 __mbsdup(const wchar_t *ws)
Index: lib/libc/string/strcasestr.c
===================================================================
--- lib/libc/string/strcasestr.c	(revision 225653)
+++ lib/libc/string/strcasestr.c	(working copy)
@@ -5,6 +5,11 @@
  * This code is derived from software contributed to Berkeley by
  * Chris Torek.
  *
+ * 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,26 +40,33 @@
 
 #include <ctype.h>
 #include <string.h>
+#include "xlocale_private.h"
 
 /*
  * Find the first occurrence of find in s, ignore case.
  */
 char *
-strcasestr(const char *s, const char *find)
+strcasestr_l(const char *s, const char *find, locale_t locale)
 {
 	char c, sc;
 	size_t len;
+	FIX_LOCALE(locale);
 
 	if ((c = *find++) != 0) {
-		c = tolower((unsigned char)c);
+		c = tolower_l((unsigned char)c, locale);
 		len = strlen(find);
 		do {
 			do {
 				if ((sc = *s++) == 0)
 					return (NULL);
-			} while ((char)tolower((unsigned char)sc) != c);
-		} while (strncasecmp(s, find, len) != 0);
+			} while ((char)tolower_l((unsigned char)sc, locale) != c);
+		} while (strncasecmp_l(s, find, len, locale) != 0);
 		s--;
 	}
 	return ((char *)s);
 }
+char *
+strcasestr(const char *s, const char *find)
+{
+	return strcasestr_l(s, find, __get_locale());
+}
Index: lib/libc/string/strxfrm.c
===================================================================
--- lib/libc/string/strxfrm.c	(revision 225653)
+++ lib/libc/string/strxfrm.c	(working copy)
@@ -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,11 +38,22 @@
 #include "collate.h"
 
 size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t loc);
+size_t
 strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
 {
+	return strxfrm_l(dest, src, len, __get_locale());
+}
+
+size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t locale)
+{
 	int prim, sec, l;
 	size_t slen;
 	char *s, *ss;
+	FIX_LOCALE(locale);
+	struct xlocale_collate *table =
+		(struct xlocale_collate*)locale->components[XLC_COLLATE];
 
 	if (!*src) {
 		if (len > 0)
@@ -45,15 +61,15 @@
 		return 0;
 	}
 
-	if (__collate_load_error)
+	if (table->__collate_load_error)
 		return strlcpy(dest, src, len);
 
 	slen = 0;
 	prim = sec = 0;
-	ss = s = __collate_substitute(src);
+	ss = s = __collate_substitute(table, src);
 	while (*s) {
 		while (*s && !prim) {
-			__collate_lookup(s, &l, &prim, &sec);
+			__collate_lookup(table, s, &l, &prim, &sec);
 			s += l;
 		}
 		if (prim) {
Index: sys/amd64/include/_stdint.h
===================================================================
--- sys/amd64/include/_stdint.h	(revision 225653)
+++ sys/amd64/include/_stdint.h	(working copy)
@@ -150,8 +150,8 @@
 #define	PTRDIFF_MAX	INT64_MAX
 
 /* Limits of sig_atomic_t. */
-#define	SIG_ATOMIC_MIN	INT32_MIN
-#define	SIG_ATOMIC_MAX	INT32_MAX
+#define	SIG_ATOMIC_MIN	LONG_MIN
+#define	SIG_ATOMIC_MAX	LONG_MAX
 
 /* Limit of size_t. */
 #define	SIZE_MAX	UINT64_MAX
Index: sys/sys/cdefs.h
===================================================================
--- sys/sys/cdefs.h	(revision 225653)
+++ sys/sys/cdefs.h	(working copy)
@@ -253,6 +253,17 @@
 #define	__LONG_LONG_SUPPORTED
 #endif
 
+/* C++11 exposes a load of C99 stuff */
+#if __cplusplus >= 201103L
+#	define	__LONG_LONG_SUPPORTED
+#	ifndef __STDC_LIMIT_MACROS
+#		define __STDC_LIMIT_MACROS
+#	endif
+#	ifndef __STDC_CONSTANT_MACROS
+#		define __STDC_CONSTANT_MACROS
+#	endif
+#endif
+
 /*
  * GCC 2.95 provides `__restrict' as an extension to C90 to support the
  * C99-specific `restrict' type qualifier.  We happen to use `__restrict' as

--Apple-Mail=_D1FEC970-512C-409C-B503-1C81695F7BCD--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?C57AA994-0CB1-4875-8DB4-7D728B3E62AB>