--- old/usr/src/head/iso/locale_iso.h	2013-07-11 12:26:10.253733077 +0000
+++ new/usr/src/head/iso/locale_iso.h	2013-07-11 12:26:10.261636058 +0000
@@ -43,8 +43,6 @@
 #ifndef	_ISO_LOCALE_ISO_H
 #define	_ISO_LOCALE_ISO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 
 #ifdef __cplusplus
@@ -115,6 +113,28 @@
 extern struct lconv	*localeconv();
 #endif
 
+#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)
+
+/* XXX */
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct	_xlocale *locale_t;
+#endif
+
+locale_t	duplocale(locale_t);
+int		freelocale(locale_t);
+locale_t	newlocale(int, const char *, locale_t);
+const char	*querylocale(int, locale_t);
+locale_t	uselocale(locale_t);
+
 #if __cplusplus >= 199711L
 }
 #endif /* end of namespace std */
--- old/usr/src/head/langinfo.h	2013-07-11 12:26:10.515169749 +0000
+++ new/usr/src/head/langinfo.h	2013-07-11 12:26:10.522037702 +0000
@@ -31,8 +31,6 @@
 #ifndef	_LANGINFO_H
 #define	_LANGINFO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.2	*/
-
 #include <sys/feature_tests.h>
 #include <nl_types.h>
 
@@ -141,13 +139,20 @@
 #define	MAXSTRMSG	58 /* Maximum number of strings in langinfo */
 #endif /* defined(__EXTENSIONS__) || !defined(_XOPEN_SOURCE) */
 
+#ifndef _LOCALE_T_DEFINED
+#define _LOCALE_T_DEFINED
+typedef struct	_xlocale *locale_t;
+#endif
+
 /*
  * and the definitions of functions langinfo(3C)
  */
 #if defined(__STDC__)
-char   *nl_langinfo(nl_item);	/* get a string from the database	*/
+char	*nl_langinfo(nl_item);	/* get a string from the database	*/
+char	*nl_langinfo_l(nl_item, locale_t);
 #else
-char   *nl_langinfo();		/* get a string from the database	*/
+char	*nl_langinfo();		/* get a string from the database	*/
+char	*nl_langinfo_l();
 #endif
 
 #ifdef	__cplusplus
--- old/usr/src/lib/libc/amd64/Makefile	2013-07-11 12:26:10.718746826 +0000
+++ new/usr/src/lib/libc/amd64/Makefile	2013-07-11 12:26:10.725504882 +0000
@@ -774,7 +774,8 @@
 	wctrans.o		\
 	wctype.o		\
 	wcwidth.o		\
-	wscol.o
+	wscol.o			\
+	xlocale.o
 
 AIOOBJS=			\
 	aio.o			\
--- old/usr/src/lib/libc/i386/Makefile.com	2013-07-11 12:26:10.952931345 +0000
+++ new/usr/src/lib/libc/i386/Makefile.com	2013-07-11 12:26:10.960557715 +0000
@@ -816,7 +816,8 @@
 	wctrans.o		\
 	wctype.o		\
 	wcwidth.o		\
-	wscol.o
+	wscol.o			\
+	xlocale.o
 
 AIOOBJS=			\
 	aio.o			\
--- old/usr/src/lib/libc/port/locale/collate.c	2013-07-11 12:26:11.201001023 +0000
+++ new/usr/src/lib/libc/port/locale/collate.c	2013-07-11 12:26:11.207840336 +0000
@@ -65,6 +65,38 @@
 collate_info_t			*_collate_info;
 int _collate_load_error = 1;
 
+struct xlocale_collate __xlocale_global_collate = {
+	{{0}, "C"}, 1, 0
+};
+
+struct xlocale_collate __xlocale_C_collate = {
+	{{0}, "C"}, 1, 0
+};
+
+static void
+destruct_collate(void *t)
+{
+	struct xlocale_collate *table = t;
+
+	/* XXX */;
+}
+
+void *
+__collate_load(const char *encoding, locale_t unused)
+{
+	struct xlocale_collate *table;
+
+	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+		return &__xlocale_C_collate;
+	}
+
+	table = calloc(sizeof(struct xlocale_collate), 1);
+	if (table == NULL) {
+		/* XXX */
+	}
+
+	return (table);
+}
 
 int
 _collate_load_tables(const char *encoding)
--- old/usr/src/lib/libc/port/locale/collate.h	2013-07-11 12:26:11.428952729 +0000
+++ new/usr/src/lib/libc/port/locale/collate.h	2013-07-11 12:26:11.436101918 +0000
@@ -32,6 +32,8 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include "xlocale_private.h"
+
 #define	COLLATE_STR_LEN		24		/* should be 64-bit multiple */
 #define	COLLATE_VERSION		"IllumosCollate2\n"
 
@@ -92,6 +94,14 @@
 	int32_t pri[COLLATE_STR_LEN];
 } collate_subst_t;
 
+struct xlocale_collate {
+	struct xlocale_component header;
+	int __collate_load_error;
+	int __collate_substitute_nontrivial;
+
+	/* XXX */
+};
+
 int	_collate_load_tables(const char *);
 void	_collate_lookup(const wchar_t *, int *, int *, int, int **);
 size_t	_collate_wxfrm(const wchar_t *, wchar_t *, size_t);
--- old/usr/src/lib/libc/port/locale/lmessages.c	2013-07-11 12:26:11.630203743 +0000
+++ new/usr/src/lib/libc/port/locale/lmessages.c	2013-07-11 12:26:11.636904636 +0000
@@ -3,6 +3,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:
@@ -27,6 +32,7 @@
 
 #include "lint.h"
 #include <stddef.h>
+#include <stdlib.h>
 #include "ldpart.h"
 #include "lmessages.h"
 
@@ -34,6 +40,8 @@
 #define	LCMESSAGES_SIZE_MIN \
 	(offsetof(struct lc_messages_T, yesstr) / sizeof (char *))
 
+struct xlocale_messages __xlocale_global_messages;
+
 static char empty[] = "";
 
 static const struct lc_messages_T _C_messages_locale = {
@@ -43,31 +51,66 @@
 	"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;
 
-int
-__messages_load_locale(const char *name)
+	if (l->buffer != NULL)
+		free(l->buffer);
+
+	free(l);
+}
+
+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;
+
+	new = calloc(sizeof(struct xlocale_messages), 1);
+	/* XXX */
+	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 :
-	    (struct lc_messages_T *)&_C_messages_locale);
+	return (loc->using_messages_locale
+	    ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale
+	    : (struct lc_messages_T *)&_C_messages_locale);
 }
--- old/usr/src/lib/libc/port/locale/lmessages.h	2013-07-11 12:26:11.837515305 +0000
+++ new/usr/src/lib/libc/port/locale/lmessages.h	2013-07-11 12:26:11.845261562 +0000
@@ -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:
@@ -27,6 +32,8 @@
 #ifndef _LMESSAGES_H_
 #define	_LMESSAGES_H_
 
+#include "xlocale_private.h"
+
 struct	lc_messages_T {
 	const char	*yesexpr;
 	const char	*noexpr;
@@ -34,7 +41,13 @@
 	const char	*nostr;
 };
 
-struct lc_messages_T *__get_current_messages_locale(void);
+struct xlocale_messages {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_messages_T locale;
+};
+
+struct lc_messages_T *__get_current_messages_locale(locale_t);
 int	__messages_load_locale(const char *);
 
 #endif /* !_LMESSAGES_H_ */
--- old/usr/src/lib/libc/port/locale/lmonetary.c	2013-07-11 12:26:12.070748940 +0000
+++ new/usr/src/lib/libc/port/locale/lmonetary.c	2013-07-11 12:26:12.077792345 +0000
@@ -3,6 +3,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,10 +34,10 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+
 #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 *))
@@ -70,6 +75,8 @@
 static int	_monetary_using_locale;
 static char	*_monetary_locale_buf;
 
+struct xlocale_monetary __xlocale_global_monetary;
+
 static char
 cnv(const char *str)
 {
@@ -80,24 +87,37 @@
 	return ((char)i);
 }
 
-int
-__monetary_load_locale(const char *name)
+static void
+destruct_monetary(void *v)
+{
+	struct xlocale_monetary *l = v;
+
+	if (l->buffer != NULL)
+		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))
+		(((char *)l->NAME)[0] = \
+			cnv(l->NAME))
 
 		M_ASSIGN_CHAR(int_frac_digits);
 		M_ASSIGN_CHAR(frac_digits);
@@ -114,11 +134,13 @@
 		 * reading FreeBSD LC_MONETARY data files.
 		 */
 #define	M_ASSIGN_ICHAR(NAME)					\
-		if (_monetary_locale.int_##NAME == NULL)	\
-			_monetary_locale.int_##NAME =		\
-			    _monetary_locale.NAME;		\
-		else						\
-			M_ASSIGN_CHAR(int_##NAME);
+		do {						\
+			if (l->int_##NAME == NULL)		\
+				l->int_##NAME =			\
+				    l->NAME;			\
+			else					\
+				M_ASSIGN_CHAR(int_##NAME);	\
+		} while (0)
 
 		M_ASSIGN_ICHAR(p_cs_precedes);
 		M_ASSIGN_ICHAR(n_cs_precedes);
@@ -130,9 +152,37 @@
 	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 loc)
+{
+	struct xlocale_monetary *new;
+
+	new = calloc(sizeof(struct xlocale_monetary), 1);
+	if (new == NULL)
+		return (NULL);
+
+	new->header.header.destructor = destruct_monetary;
+	if (monetary_load_locale_l(new, &loc->using_monetary_locale,
+	    &loc->monetary_locale_changed, name) == _LDP_ERROR) {
+		xlocale_release(new);
+		return (NULL);
+	}
+
+	return (NULL);
+}
+
 struct lc_monetary_T *
-__get_current_monetary_locale(void)
+__get_current_monetary_locale(locale_t loc)
 {
-	return (_monetary_using_locale ? &_monetary_locale :
-	    (struct lc_monetary_T *)&_C_monetary_locale);
+	return (loc->using_monetary_locale
+	    ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale
+	    : (struct lc_monetary_T *)&_C_monetary_locale);
 }
--- old/usr/src/lib/libc/port/locale/lmonetary.h	2013-07-11 12:26:12.280877070 +0000
+++ new/usr/src/lib/libc/port/locale/lmonetary.h	2013-07-11 12:26:12.287506419 +0000
@@ -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:
@@ -27,6 +32,8 @@
 #ifndef _LMONETARY_H_
 #define	_LMONETARY_H_
 
+#include "xlocale_private.h"
+
 struct lc_monetary_T {
 	const char	*int_curr_symbol;
 	const char	*currency_symbol;
@@ -51,7 +58,13 @@
 	const char	*int_n_sign_posn;
 };
 
-struct lc_monetary_T *__get_current_monetary_locale(void);
+struct xlocale_monetary {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_monetary_T locale;
+};
+
+struct lc_monetary_T *__get_current_monetary_locale(locale_t);
 int	__monetary_load_locale(const char *);
 
 #endif /* !_LMONETARY_H_ */
--- old/usr/src/lib/libc/port/locale/lnumeric.c	2013-07-11 12:26:12.483954191 +0000
+++ new/usr/src/lib/libc/port/locale/lnumeric.c	2013-07-11 12:26:12.490789526 +0000
@@ -3,6 +3,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:
@@ -31,7 +36,6 @@
 #include "lnumeric.h"
 #include "../i18n/_locale.h"
 
-extern int __nlocale_changed;
 extern const char *__fix_locale_grouping_str(const char *);
 
 #define	LCNUMERIC_SIZE (sizeof (struct lc_numeric_T) / sizeof (char *))
@@ -44,42 +48,80 @@
 	numempty	/* grouping */
 };
 
-static struct lc_numeric_T _numeric_locale;
-static int	_numeric_using_locale;
-static char	*_numeric_locale_buf;
-
-int
-__numeric_load_locale(const char *name)
+static void
+destruct_numeric(void *v)
 {
-	const struct lc_numeric_T *leg = &_C_numeric_locale;
+	struct xlocale_numeric *l = v;
+
+	if (l->buffer != NULL)
+		free(l->buffer);
 
+	free(l);
+}
+
+struct xlocale_numeric __xlocale_global_numeric;
+
+static int
+numeric_load_locale(struct xlocale_numeric *loc, int *using_locale,
+    int *changed, const char *name)
+{
+	int leg;
 	int ret;
+	struct lc_numeric_T *l = &loc->locale;
 
-	ret = __part_load_locale(name, &_numeric_using_locale,
-	    &_numeric_locale_buf, "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE,
-	    (const char **)&_numeric_locale);
-	if (ret == _LDP_ERROR)
-		return (_LDP_ERROR);
+	ret = __part_load_locale(name, using_locale,
+	    &loc->buffer, "LC_NUMERIC",
+	    LCNUMERIC_SIZE, LCNUMERIC_SIZE,
+	    (const char **)l);
+	if (ret != _LDP_ERROR)
+		*changed = 1;
 
-	__nlocale_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);
-		leg = (const struct lc_numeric_T *)&_numeric_locale;
+		l->grouping =
+		    __fix_locale_grouping_str(l->grouping);
+		// XXX leg = (const struct lc_numeric_T *)&_numeric_locale;
 	}
 	/* This is Solaris legacy, required for ABI compatability */
-	_numeric[0] = *leg->decimal_point;
-	_numeric[1] = *leg->grouping;
+	// _numeric[0] = *leg->decimal_point;
+	// _numeric[1] = *leg->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;
+
+	new = calloc(sizeof(struct xlocale_numeric), 1);
+	if (new == NULL)
+		return (NULL);
+
+	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 :
-	    (struct lc_numeric_T *)&_C_numeric_locale);
+	return (loc->using_numeric_locale
+	    ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale
+	    : (struct lc_numeric_T *)&_C_numeric_locale);
 }
--- old/usr/src/lib/libc/port/locale/lnumeric.h	2013-07-11 12:26:12.692310669 +0000
+++ new/usr/src/lib/libc/port/locale/lnumeric.h	2013-07-11 12:26:12.699249689 +0000
@@ -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:
@@ -27,13 +32,21 @@
 #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 lc_numeric_T *__get_current_numeric_locale(void);
+struct xlocale_numeric {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_numeric_T locale;
+};
+
+struct lc_numeric_T *__get_current_numeric_locale(locale_t);
 int	__numeric_load_locale(const char *);
 
 #endif /* !_LNUMERIC_H_ */
--- old/usr/src/lib/libc/port/locale/localeconv.c	2013-07-11 12:26:12.894317712 +0000
+++ new/usr/src/lib/libc/port/locale/localeconv.c	2013-07-11 12:26:12.902357305 +0000
@@ -4,6 +4,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:
@@ -47,25 +52,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(void)
+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);
@@ -87,21 +91,27 @@
 		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()));
 }
--- old/usr/src/lib/libc/port/locale/mblocal.h	2013-07-11 12:26:13.104542844 +0000
+++ new/usr/src/lib/libc/port/locale/mblocal.h	2013-07-11 12:26:13.112044284 +0000
@@ -3,6 +3,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:
@@ -29,11 +34,32 @@
 #define	_MBLOCAL_H_
 
 #include "runetype.h"
+#include "xlocale_private.h"
+
+/*
+ * Conversion function pointers for current encoding.
+ */
+struct xlocale_ctype {
+	struct xlocale_component header;
+	_RuneLocale *runes;
+	size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+	    size_t, mbstate_t *_RESTRICT_KYWD);
+	int (*__mbsinit)(const mbstate_t *);
+	size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
+	    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+	size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t, mbstate_t *_RESTRICT_KYWD);
+	size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
+	    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+	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;
 
 /*
  * Rune initialization function prototypes.
  */
-int	_none_init(_RuneLocale *);
+int	_none_init(struct xlocale_ctype *, _RuneLocale *);
 int	_UTF8_init(_RuneLocale *);
 int	_EUC_CN_init(_RuneLocale *);
 int	_EUC_JP_init(_RuneLocale *);
--- old/usr/src/lib/libc/port/locale/nl_langinfo.c	2013-07-11 12:26:13.304209029 +0000
+++ new/usr/src/lib/libc/port/locale/nl_langinfo.c	2013-07-11 12:26:13.311100137 +0000
@@ -3,6 +3,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:
@@ -39,15 +44,15 @@
 
 #define	_REL(BASE) ((int)item-BASE)
 
-#define	MONETARY	(__get_current_monetary_locale())
-#define	TIME		(__get_current_time_locale())
-#define	MESSAGES	(__get_current_messages_locale())
-#define	NUMERIC		(__get_current_numeric_locale())
+#define	MONETARY	(__get_current_monetary_locale(loc))
+#define	TIME		(__get_current_time_locale(loc))
+#define	MESSAGES	(__get_current_messages_locale(loc))	/* XXX */
+#define	NUMERIC		(__get_current_numeric_locale(loc))
 
 #pragma weak _nl_langinfo = nl_langinfo
 
 char *
-nl_langinfo(nl_item item)
+nl_langinfo_l(nl_item item, locale_t loc)
 {
 	char *ret, *s, *cs;
 	static char *csym = NULL;
@@ -194,3 +199,9 @@
 	}
 	return (ret);
 }
+
+char *
+nl_langinfo(nl_item item)
+{
+	return (nl_langinfo_l(item, __get_locale()));
+}
--- old/usr/src/lib/libc/port/locale/none.c	2013-07-11 12:26:13.510343191 +0000
+++ new/usr/src/lib/libc/port/locale/none.c	2013-07-11 12:26:13.517099699 +0000
@@ -7,6 +7,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:
@@ -60,16 +65,17 @@
 /* setup defaults */
 
 int
-_none_init(_RuneLocale *rl)
+_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
 {
-	charset_is_ascii = 1;
+	charset_is_ascii = 1;	/* XXX */
 
-	__mbrtowc = _none_mbrtowc;
-	__mbsinit = _none_mbsinit;
-	__mbsnrtowcs = _none_mbsnrtowcs;
-	__wcrtomb = _none_wcrtomb;
-	__wcsnrtombs = _none_wcsnrtombs;
-	_CurrentRuneLocale = rl;
+	l->__mbrtowc = _none_mbrtowc;
+	l->__mbsinit = _none_mbsinit;
+	l->__mbsnrtowcs = _none_mbsnrtowcs;
+	l->__wcrtomb = _none_wcrtomb;
+	l->__wcsnrtombs = _none_wcsnrtombs;
+	l->runes = rl;
+	/* XXX */
 	return (0);
 }
 
@@ -197,3 +203,27 @@
 
 size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
     size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_wcsnrtombs;
+
+struct xlocale_ctype __xlocale_global_ctype = {
+	{{0}, "C"},
+	(_RuneLocale*)&_DefaultRuneLocale,
+	_none_mbrtowc,
+	_none_mbsinit,
+	_none_mbsnrtowcs,
+	_none_wcrtomb,
+	_none_wcsnrtombs,
+	1,	/* __mb_cur_max */
+	256	/* __mb_sb_limit */
+};
+
+const struct xlocale_ctype __xlocale_C_ctype = {
+	{{0}, "C"},
+	(_RuneLocale*)&_DefaultRuneLocale,
+	_none_mbrtowc,
+	_none_mbsinit,
+	_none_mbsnrtowcs,
+	_none_wcrtomb,
+	_none_wcsnrtombs,
+	1,	/* __mb_cur_max */
+	256	/* __mb_sb_limit */
+};
--- old/usr/src/lib/libc/port/locale/setlocale.c	2013-07-11 12:26:13.716154565 +0000
+++ new/usr/src/lib/libc/port/locale/setlocale.c	2013-07-11 12:26:13.723114126 +0000
@@ -94,7 +94,6 @@
 
 static char	*currentlocale(void);
 static char	*loadlocale(int);
-static const char *__get_locale_env(int);
 
 char *
 setlocale(int category, const char *locale)
@@ -305,7 +304,7 @@
 	return (NULL);
 }
 
-static const char *
+const char *
 __get_locale_env(int category)
 {
 	const char *env;
@@ -327,3 +326,14 @@
 
 	return (env);
 }
+
+/*
+ * Detect locale storage location and store its value to _PathLocale variable
+ */
+int
+__detect_path_locale(void)
+{
+	/* XXX */
+
+	return (0);
+}
--- old/usr/src/lib/libc/port/locale/setlocale.h	2013-07-11 12:26:13.929475069 +0000
+++ new/usr/src/lib/libc/port/locale/setlocale.h	2013-07-11 12:26:13.936510838 +0000
@@ -33,6 +33,7 @@
 
 extern char *_PathLocale;
 
+const char *__get_locale_env(int);
 int	__detect_path_locale(void);
 int	__wrap_setrunelocale(const char *);
 
--- old/usr/src/lib/libc/port/locale/setrunelocale.c	2013-07-11 12:26:14.133727161 +0000
+++ new/usr/src/lib/libc/port/locale/setrunelocale.c	2013-07-11 12:26:14.140590920 +0000
@@ -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:
@@ -47,18 +52,24 @@
 #include "_ctype.h"
 #include "../i18n/_locale.h"
 
+/*
+ * A cached version of the runes for this thread.  Used by ctype.h
+ */
+__thread const _RuneLocale *_ThreadRuneLocale;
+
 extern _RuneLocale	*_Read_RuneMagi(FILE *);
 extern unsigned char	__ctype_C[];
 
-static int		__setrunelocale(const char *);
+static int		__setrunelocale(struct xlocale_ctype *, const char *);
 
 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;
+	struct xlocale_ctype saved = *l; /* XXX DOUBLE NOT USED */
 	size_t (*old__mbrtowc)(wchar_t *_RESTRICT_KYWD,
 	    const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
 	size_t (*old__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
@@ -98,7 +109,7 @@
 			__trans_lower[i] = _DefaultRuneLocale.__maplower[i];
 		}
 
-		(void) _none_init(&_DefaultRuneLocale);
+		(void) _none_init(l, &_DefaultRuneLocale);
 		return (0);
 	}
 
@@ -107,12 +118,12 @@
 	 */
 	if (CachedRuneLocale != NULL &&
 	    strcmp(encoding, ctype_encoding) == 0) {
-		_CurrentRuneLocale = CachedRuneLocale;
-		__mbrtowc = Cached__mbrtowc;
-		__mbsinit = Cached__mbsinit;
-		__mbsnrtowcs = Cached__mbsnrtowcs;
-		__wcrtomb = Cached__wcrtomb;
-		__wcsnrtombs = Cached__wcsnrtombs;
+		l->runes = CachedRuneLocale;
+		l->__mbrtowc = Cached__mbrtowc;
+		l->__mbsinit = Cached__mbsinit;
+		l->__mbsnrtowcs = Cached__mbsnrtowcs;
+		l->__wcrtomb = Cached__wcrtomb;
+		l->__wcsnrtombs = Cached__wcsnrtombs;
 		return (0);
 	}
 
@@ -139,14 +150,14 @@
 	old__wcrtomb = __wcrtomb;
 	old__wcsnrtombs = __wcsnrtombs;
 
-	__mbrtowc = NULL;
-	__mbsinit = NULL;
-	__mbsnrtowcs = __mbsnrtowcs_std;
-	__wcrtomb = NULL;
-	__wcsnrtombs = __wcsnrtombs_std;
+	l->__mbrtowc = NULL;
+	l->__mbsinit = NULL;
+	l->__mbsnrtowcs = __mbsnrtowcs_std;
+	l->__wcrtomb = NULL;
+	l->__wcsnrtombs = __wcsnrtombs_std;
 
 	if (strcmp(rl->__encoding, "NONE") == 0)
-		ret = _none_init(rl);
+		ret = _none_init(l, rl);
 	else if (strcmp(rl->__encoding, "UTF-8") == 0)
 		ret = _UTF8_init(rl);
 	else if (strcmp(rl->__encoding, "EUC-CN") == 0)
@@ -174,12 +185,12 @@
 		if (CachedRuneLocale != NULL) {
 			free(CachedRuneLocale);
 		}
-		CachedRuneLocale = _CurrentRuneLocale;
-		Cached__mbrtowc = __mbrtowc;
-		Cached__mbsinit = __mbsinit;
-		Cached__mbsnrtowcs = __mbsnrtowcs;
-		Cached__wcrtomb = __wcrtomb;
-		Cached__wcsnrtombs = __wcsnrtombs;
+		CachedRuneLocale = l->runes;
+		Cached__mbrtowc = l->__mbrtowc;
+		Cached__mbsinit = l->__mbsinit;
+		Cached__mbsnrtowcs = l->__mbsnrtowcs;
+		Cached__wcrtomb = l->__wcrtomb;
+		Cached__wcsnrtombs = l->__wcsnrtombs;
 		(void) strcpy(ctype_encoding, encoding);
 
 		/*
@@ -228,11 +239,11 @@
 		 * the CSWIDTH array (__ctype[514-520]) properly.
 		 */
 	} else {
-		__mbrtowc = old__mbrtowc;
-		__mbsinit = old__mbsinit;
-		__mbsnrtowcs = old__mbsnrtowcs;
-		__wcrtomb = old__wcrtomb;
-		__wcsnrtombs = old__wcsnrtombs;
+		l->__mbrtowc = old__mbrtowc;
+		l->__mbsinit = old__mbsinit;
+		l->__mbsnrtowcs = old__mbsnrtowcs;
+		l->__wcrtomb = old__wcrtomb;
+		l->__wcsnrtombs = old__wcsnrtombs;
 		free(rl);
 	}
 
@@ -242,11 +253,37 @@
 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);
 	}
+	/* XXX */
+//	__mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
+//	__mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
+	_CurrentRuneLocale = __xlocale_global_ctype.runes;
 	return (_LDP_LOADED);
 }
+
+void
+__set_thread_rune_locale(locale_t loc)
+{
+
+	if (loc == NULL) {
+		_ThreadRuneLocale = &_DefaultRuneLocale;
+	} else {
+		_ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
+	}
+}
+
+void *
+__ctype_load(const char *locale, locale_t unused)
+{
+	struct xlocale_ctype *l;
+
+	l = calloc(sizeof(struct xlocale_ctype), 1);
+	/* XXX */
+
+	return (l);
+}
--- old/usr/src/lib/libc/port/locale/strftime.c	2013-07-11 12:26:14.346342075 +0000
+++ new/usr/src/lib/libc/port/locale/strftime.c	2013-07-11 12:26:14.353264868 +0000
@@ -3,6 +3,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,
@@ -26,7 +31,8 @@
 
 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 * const);
+static char *_fmt(const char *, const struct tm *, char *, const char * const,
+    int *, locale_t);
 static char *_yconv(int, int, int, int, char *, const char *);
 
 extern char *tzname[];
@@ -62,24 +68,38 @@
 
 
 size_t
-strftime(char *_RESTRICT_KYWD s, size_t maxsize,
-    const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t)
+strftime_l(char *_RESTRICT_KYWD s, size_t maxsize,
+    const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t,
+    locale_t loc)
 {
-	char *p;
+	char 	*p;
+	int	warn;
+	FIX_LOCALE(loc);
 
 	tzset();
-	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize);
+	warn = IN_NONE;
+	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize,
+	    &warn, loc);
+	/* XXX YEAR_2000 */
 	if (p == s + maxsize)
 		return (0);
 	*p = '\0';
 	return (p - s);
 }
 
+size_t
+strftime(char *_RESTRICT_KYWD s, size_t maxsize,
+    const char *_RESTRICT_KYWD format, const struct tm *_RESTRICT_KYWD t)
+{
+	return (strftime_l(s, maxsize, format, t, __get_locale()));
+}
+
 static char *
-_fmt(const char *format, const struct tm *t, char *pt, const char * const ptlim)
+_fmt(const char *format, const struct tm *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);
 
 #define	PADDING(x)	fmt_padding[x][PadIndex]
 
@@ -130,10 +150,17 @@
 				    pt, ptlim);
 				continue;
 			case 'c':
-				pt = _fmt(tptr->c_fmt, t, pt, ptlim);
+			{
+				int warn2 = IN_SOME;
+
+				pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2,
+				    loc);
+				/* XXX */
+			}
 				continue;
 			case 'D':
-				pt = _fmt("%m/%d/%y", t, pt, ptlim);
+				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp,
+				    loc);
 				continue;
 			case 'd':
 				pt = _conv(t->tm_mday,
@@ -163,7 +190,8 @@
 				    PADDING(PAD_FMT_SDAYOFMONTH), pt, ptlim);
 				continue;
 			case 'F':
-				pt = _fmt("%Y-%m-%d", t, pt, ptlim);
+				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp,
+				    loc);
 				continue;
 			case 'H':
 				pt = _conv(t->tm_hour, PADDING(PAD_FMT_HMS),
@@ -223,10 +251,11 @@
 				    tptr->pm : tptr->am, pt, ptlim);
 				continue;
 			case 'R':
-				pt = _fmt("%H:%M", t, pt, ptlim);
+				pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);
 				continue;
 			case 'r':
-				pt = _fmt(tptr->ampm_fmt, t, pt, ptlim);
+				pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
+				    warnp, loc);
 				continue;
 			case 'S':
 				pt = _conv(t->tm_sec, PADDING(PAD_FMT_HMS),
@@ -237,15 +266,15 @@
 			{
 				struct tm tm;
 				char *buf;
-
+/* XXX */
 				tm = *t;
 				(void) asprintf(&buf, "%ld", mktime(&tm));
 				pt = _add(buf, pt, ptlim);
-				continue;
 			}
-
+				continue;
 			case 'T':
-				pt = _fmt("%H:%M:%S", t, pt, ptlim);
+				pt = _fmt("%H:%M:%S", t, pt, ptlim,
+				    warnp, loc);
 				continue;
 			case 't':
 				pt = _add("\t", pt, ptlim);
@@ -357,7 +386,8 @@
 				 * "date as dd-bbb-YYYY"
 				 * (ado, 1993-05-24)
 				 */
-				pt = _fmt("%e-%b-%Y", t, pt, ptlim);
+				pt = _fmt("%e-%b-%Y", t, pt, ptlim,
+				    warnp, loc);
 				continue;
 			case 'W':
 				pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -371,10 +401,16 @@
 				pt = _conv(t->tm_wday, "%d", pt, ptlim);
 				continue;
 			case 'X':
-				pt = _fmt(tptr->X_fmt, t, pt, ptlim);
+				pt = _fmt(tptr->X_fmt, t, pt, ptlim,
+				    warnp, loc);
 				continue;
 			case 'x':
-				pt = _fmt(tptr->x_fmt, t, pt, ptlim);
+			{
+				int	warn2 = IN_SOME;
+
+				pt = _fmt(tptr->x_fmt, t, pt, ptlim,
+				    &warn2, loc);
+			}
 				continue;
 			case 'y':
 				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
@@ -438,7 +474,8 @@
 				}
 				continue;
 			case '+':
-				pt = _fmt(tptr->date_fmt, t, pt, ptlim);
+				pt = _fmt(tptr->date_fmt, t, pt, ptlim,
+				    warnp, loc);
 				continue;
 			case '-':
 				if (PadIndex != PAD_DEFAULT)
--- old/usr/src/lib/libc/port/locale/strptime.c	2013-07-11 12:26:14.579620187 +0000
+++ new/usr/src/lib/libc/port/locale/strptime.c	2013-07-11 12:26:14.586678813 +0000
@@ -2,6 +2,11 @@
  * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.
  * 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:
@@ -48,13 +53,14 @@
 #define	F_RECURSE	(1 << 2)
 
 static char *
-__strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
+__strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp,
+    int *GMTp, locale_t locale)
 {
 	char	c;
 	const char *ptr;
 	int	i, len, recurse = 0;
 	int Ealternative, Oalternative;
-	struct lc_time_T *tptr = __get_current_time_locale();
+	struct lc_time_T *tptr = __get_current_time_locale(locale);
 
 	if (*flagsp & F_RECURSE)
 		recurse = 1;
@@ -92,7 +98,8 @@
 			break;
 
 		case '+':
-			buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->date_fmt, tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -115,13 +122,15 @@
 			break;
 
 		case 'c':
-			buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->c_fmt, tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'D':
-			buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
+			buf = __strptime(buf, "%m/%d/%y", tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -139,37 +148,43 @@
 			goto label;
 
 		case 'F':
-			buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
+			buf = __strptime(buf, "%Y-%m-%d", tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'R':
-			buf = __strptime(buf, "%H:%M", tm, flagsp);
+			buf = __strptime(buf, "%H:%M", tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'r':
-			buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'T':
-			buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
+			buf = __strptime(buf, "%H:%M:%S", tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'X':
-			buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->X_fmt, tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'x':
-			buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->x_fmt, tm, flagsp,
+			    GMTp, locale);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -535,11 +550,31 @@
 }
 
 char *
+strptime_l(const char * __restrict buf, const char * __restrict fmt,
+    struct tm * __restrict tm, locale_t loc)
+{
+	char *ret;
+	int gmt;
+	int flags = F_ZERO;
+	FIX_LOCALE(loc);
+
+	gmt = 0;
+	ret = __strptime(buf, fmt, tm, &flags, &gmt, loc);
+	if (ret && gmt) {
+		time_t t = timegm(tm);
+		localtime_r(&t, tm);
+	}
+
+	return (ret);
+}
+
+char *
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
 	int	flags = F_ZERO;
 
-	return (__strptime(buf, fmt, tm, &flags));
+	return (strptime_l(buf, fmt, tm, __get_locale()));
+	// XXX return (__strptime(buf, fmt, tm, &flags));
 }
 
 /*
@@ -550,6 +585,8 @@
 __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
 {
 	int	flags = 0;
+	int	gmt = 0;
 
-	return (__strptime(buf, fmt, tm, &flags));
+	return (__strptime(buf, fmt, tm, &flags, &gmt, __get_locale()));
+	/* XXX */
 }
--- old/usr/src/lib/libc/port/locale/timelocal.c	2013-07-11 12:26:14.799963703 +0000
+++ new/usr/src/lib/libc/port/locale/timelocal.c	2013-07-11 12:26:14.807297804 +0000
@@ -35,6 +35,8 @@
 static int _time_using_locale;
 static char *time_locale_buf;
 
+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 = {
@@ -84,17 +86,58 @@
 	"%I:%M:%S %p"
 };
 
+static void
+destruct_time(void *v)
+{
+	struct xlocale_time *l = v;
+
+	if (l->buffer != NULL)
+		free(l->buffer);
+
+	free(l);
+}
+
 struct lc_time_T *
-__get_current_time_locale(void)
+__get_current_time_locale(locale_t loc)
 {
-	return (_time_using_locale ? &_time_locale :
-	    (struct lc_time_T *)&_C_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));
+}
+
+void *
+__time_load(const char* name, locale_t loc)
+{
+	struct xlocale_time *new;
+
+	new = calloc(sizeof(struct xlocale_time), 1);
+	if (new == NULL)
+		return (NULL);
+
+	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);
 }
--- old/usr/src/lib/libc/port/locale/timelocal.h	2013-07-11 12:26:15.006237031 +0000
+++ new/usr/src/lib/libc/port/locale/timelocal.h	2013-07-11 12:26:15.013365384 +0000
@@ -3,6 +3,10 @@
  * 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
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -28,6 +32,8 @@
 #ifndef _TIMELOCAL_H_
 #define	_TIMELOCAL_H_
 
+#include "xlocale_private.h"
+
 /*
  * Private header file for the strftime and strptime localization
  * stuff.
@@ -46,7 +52,13 @@
 	const char	*ampm_fmt;
 };
 
-struct lc_time_T *__get_current_time_locale(void);
+struct xlocale_time {
+	struct xlocale_component header;
+	char *buffer;
+	struct lc_time_T locale;
+};
+
+struct lc_time_T *__get_current_time_locale(locale_t);
 int	__time_load_locale(const char *);
 
 #endif /* !_TIMELOCAL_H_ */
--- old/usr/src/lib/libc/port/locale/wcwidth.c	2013-07-11 12:26:15.213182064 +0000
+++ new/usr/src/lib/libc/port/locale/wcwidth.c	2013-07-11 12:26:15.219935448 +0000
@@ -65,6 +65,13 @@
 
 #pragma weak _scrwidth = scrwidth
 
+int
+wcwidth(wchar_t wc, locale_t locale)
+{
+	/* XXX */
+	return (0);
+}
+
 /*
  * This is a Solaris extension.  It never returns a negative width, even for
  * non-printable characters.  It is used internally by the printf
--- /dev/null	2013-07-11 12:26:15.000000000 +0000
+++ new/usr/src/lib/libc/port/locale/xlocale.c	2013-07-11 12:26:15.425487139 +0000
@@ -0,0 +1,363 @@
+/*
+ * 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 "runetype.h"
+#include "xlocale_private.h"
+
+/*
+ * Each locale loader declares a global component.  This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+
+/*
+ * And another version for the statically-allocated C locale.  We only have
+ * components for the parts that are expected to be sensible.
+ */
+extern struct xlocale_component __xlocale_C_collate;
+extern struct xlocale_component __xlocale_C_ctype;
+
+/*
+ * The locale for this thread.
+ */
+__thread locale_t __thread_locale;
+
+/*
+ * Flag indicating that one or more per-thread locales exist.
+ */
+int __has_thread_locale;
+
+struct _xlocale __xlocale_global_locale = {
+	{0},
+	{
+		&__xlocale_global_collate,
+		&__xlocale_global_ctype,
+		&__xlocale_global_monetary,
+		&__xlocale_global_numeric,
+		&__xlocale_global_time,
+		&__xlocale_global_messages
+	},
+	1,
+	0,
+	1,
+	0
+};
+
+struct _xlocale __xlocale_C_locale = {
+	{0},
+	{
+		&__xlocale_C_collate,
+		&__xlocale_C_ctype,
+		0, 0, 0, 0
+	},
+	1,
+	0,
+	1,
+	0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+	__collate_load,
+	__ctype_load,
+	__monetary_load,
+	__numeric_load,
+	__time_load,
+	__messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void
+init_key(void)
+{
+	pthread_key_create(&locale_info_key, xlocale_release);
+	pthread_setspecific(locale_info_key, (void*)42);
+	if (pthread_getspecific(locale_info_key) == (void*)42) {
+		pthread_setspecific(locale_info_key, 0);
+	} else {
+		fake_tls = 1;
+	}
+	/* At least one per-thread locale has now been set. */
+	__has_thread_locale = 1;
+	__detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+
+	// XXX	_once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+	
+	return (fake_tls ? thread_local_locale :
+	    pthread_getspecific(locale_info_key));
+}
+
+static void
+set_thread_locale(locale_t loc)
+{
+
+	// XXX _once(&once_control, init_key);
+	(void) 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);
+	}
+	__thread_locale = loc;
+	__set_thread_rune_locale(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 if (base->components[type]) {
+		new->components[type] = xlocale_retain(base->components[type]);
+	} else {
+		/*
+		 * If the component was NULL, return success - if base is a
+		 * valid locale then the flag indicating that this isn't
+		 * present should be set.  If it isn't a valid locale, then
+		 * we're stuck anyway.
+		 */
+		return (1);
+	}
+	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;
+
+	// XXX _once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+
+	locale_t new = alloc_locale();
+	if (NULL == new) {
+		return (NULL);
+	}
+
+	FIX_LOCALE(base);
+	copyflags(new, base);
+
+	if (NULL == locale) {
+		realLocale = "C";
+	} else if ('\0' == locale[0]) {
+		useenv = 1;
+	}
+
+	for (type = 0; type < XLC_LAST; type++) {
+		if (mask & 1) {
+			if (useenv) {
+				realLocale = __get_locale_env(type);
+			}
+			new->components[type] =
+			     constructors[type](realLocale, new);
+			if (new->components[type]) {
+				strncpy(new->components[type]->locale,
+				     realLocale, ENCODING_LEN);
+			} else {
+				success = 0;
+				break;
+			}
+		} else {
+			if (!dupcomponent(type, base, new)) {
+				success = 0;
+				break;
+			}
+		}
+		mask >>= 1;
+	}
+	if (0 == success) {
+		xlocale_release(new);
+		new = NULL;
+	}
+
+	return (new);
+}
+
+locale_t
+duplocale(locale_t base)
+{
+	locale_t new = alloc_locale();
+	int type;
+
+	// XXX _once(&once_control, init_key);
+	(void) pthread_once(&once_control, init_key);
+
+	if (NULL == new) {
+		return (NULL);
+	}
+	
+	FIX_LOCALE(base);
+	copyflags(new, base);
+
+	for (type=0 ; type<XLC_LAST ; type++) {
+		dupcomponent(type, base, new);
+	}
+
+	return (new);
+}
+
+/*
+ * Free a locale_t.  This is quite a poorly named function.  It actually
+ * disclaims a reference to a locale_t, rather than freeing it.  
+ */
+int
+freelocale(locale_t loc)
+{
+	/* Fail if we're passed something that isn't a locale. */
+	if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) {
+		return (-1);
+	}
+	/*
+	 * If we're passed the global locale, pretend that we freed it but don't
+	 * actually do anything.
+	 */
+	if (&__xlocale_global_locale == loc) {
+		return (0);
+	}
+	xlocale_release(loc);
+	return (0);
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *
+querylocale(int mask, locale_t loc)
+{
+	int type = ffs(mask) - 1;
+	FIX_LOCALE(loc);
+	if (type >= XLC_LAST)
+		return (NULL);
+	if (loc->components[type])
+		return (loc->components[type]->locale);
+	return ("C");
+}
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t
+uselocale(locale_t loc)
+{
+	locale_t old = get_thread_locale();
+	if (NULL != loc) {
+		if (LC_GLOBAL_LOCALE == loc) {
+			loc = NULL;
+		}
+		set_thread_locale(loc);
+	}
+	return (old ? old : LC_GLOBAL_LOCALE);
+}
--- /dev/null	2013-07-11 12:26:15.000000000 +0000
+++ new/usr/src/lib/libc/port/locale/xlocale_private.h	2013-07-11 12:26:15.526366516 +0000
@@ -0,0 +1,241 @@
+/*
+ * 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> /* XXX */
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include "setlocale.h"
+#include <wchar_impl.h>	/* XXX */
+
+enum {
+	XLC_COLLATE = 0,
+	XLC_CTYPE,
+	XLC_MONETARY,
+	XLC_NUMERIC,
+	XLC_TIME,
+	XLC_MESSAGES,
+	XLC_LAST
+};
+
+
+/*
+ * Header used for objects that are reference counted.  Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure.  Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0.  When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+	/* Number of references to this component. */
+	long retain_count;
+	/* Function used to destroy this component, if one is required */
+	void(*destructor)(void*);
+};
+
+/*
+ * Header for a locale component.  All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+	struct xlocale_refcounted header;
+	/* Name of the locale used for this component. */
+	char locale[ENCODING_LEN+1];
+};
+
+/*
+ * xlocale structure, stores per-thread locale information.  
+ */
+struct _xlocale {
+	struct xlocale_refcounted header;
+	/* Components for the locale. */
+	struct xlocale_component *components[XLC_LAST];
+	/*
+	 * Flag indicating if components[XLC_MONETARY] has changed since the
+	 * last call to localeconv_l() with this locale.
+	 */
+	int monetary_locale_changed;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_MONETARY (1), or if it should use the C default instead (0). */
+	int using_monetary_locale;
+	/** Flag indicating if components[XLC_NUMERIC] has changed since the
+	 * last call to localeconv_l() with this locale. */
+	int numeric_locale_changed;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_NUMERIC (1), or if it should use the C default instead (0). */
+	int using_numeric_locale;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_TIME (1), or if it should use the C default instead (0). */
+	int using_time_locale;
+	/** Flag indicating whether this locale is actually using a locale for
+	 * LC_MESSAGES (1), or if it should use the C default instead (0). */
+	int using_messages_locale;
+	/** The structure to be returned from localeconv_l() for this locale. */
+	struct lconv lconv;
+	/** Persistent state used by mblen() calls. */
+	__mbstate_t mblen;
+	/** Persistent state used by mbrlen() calls. */
+	__mbstate_t mbrlen;
+	/** Persistent state used by mbrtoc16() calls. */
+	__mbstate_t mbrtoc16;
+	/** Persistent state used by mbrtoc32() calls. */
+	__mbstate_t mbrtoc32;
+	/** 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 c16rtomb() calls. */
+	__mbstate_t c16rtomb;
+	/** Persistent state used by c32rtomb() calls. */
+	__mbstate_t c32rtomb;
+	/** 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;
+};
+
+/*
+ * XXX freebsd-head/include/xlocale/_ctype.h
+ */
+// typedef struct _xlocale *locale_t;
+#define	LC_GLOBAL_LOCALE	((locale_t)-1)
+
+/*
+ * Increments the reference count of a reference-counted structure.
+ */
+__attribute__((unused)) static void*
+xlocale_retain(void *val)
+{
+	struct xlocale_refcounted *obj = val;
+	//atomic_add_long(&(obj->retain_count), 1); /* XXX */
+	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 = 0; // atomic_fetchadd_long(&(obj->retain_count), -1) - 1; /* XXX */
+	if (count < 0) {
+		if (0 != obj->destructor) {
+			obj->destructor(obj);
+		}
+	}
+}
+
+/**
+ * Load functions.  Each takes the name of a locale and a pointer to the data
+ * to be initialised as arguments.  Two special values are allowed for the 
+ */
+extern void	*__collate_load(const char*, locale_t);
+extern void	*__ctype_load(const char*, locale_t);
+extern void	*__messages_load(const char*, locale_t);
+extern void	*__monetary_load(const char*, locale_t);
+extern void	*__numeric_load(const char*, locale_t);
+extern void	*__time_load(const char*, locale_t);
+
+extern struct _xlocale __xlocale_global_locale;
+extern struct _xlocale __xlocale_C_locale;
+
+/**
+ * Caches the rune table in TLS for fast access.
+ */
+void __set_thread_rune_locale(locale_t loc);
+/**
+ * Flag indicating whether a per-thread locale has been set.  If no per-thread
+ * locale has ever been set, then we always use the global locale.
+ */
+extern int __has_thread_locale;
+
+#ifndef __NO_TLS
+/*
+ * The per-thread locale.  Avoids the need to use pthread lookup functions when
+ * getting the per-thread locale.
+ */
+extern __thread locale_t __thread_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.
+ */
+static inline locale_t __get_locale(void)
+{
+
+	if (!__has_thread_locale) {
+		return (&__xlocale_global_locale);
+	}
+	return (__thread_locale ? __thread_locale : &__xlocale_global_locale);
+}
+#else
+locale_t __get_locale(void);
+#endif
+
+/**
+ * Two magic values are allowed for locale_t objects.  NULL and -1.  This
+ * function maps those to the real locales that they represent.
+ */
+static inline locale_t get_real_locale(locale_t locale)
+{
+	switch ((intptr_t)locale) {
+		case 0: return (&__xlocale_C_locale);
+		case -1: return (&__xlocale_global_locale);
+		default: return (locale);
+	}
+}
+
+/**
+ * Replace a placeholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
--- old/usr/src/lib/libc/port/mapfile-vers	2013-07-11 12:26:15.622910156 +0000
+++ new/usr/src/lib/libc/port/mapfile-vers	2013-07-11 12:26:15.630734579 +0000
@@ -90,6 +90,17 @@
 $add amd64
 $endif
 
+SYMBOL_VERSION ILLUMOS_0.5 {	# Illumos additions
+    protected:
+	strftime_l;
+	nl_langinfo_l;
+	duplocale;
+	freelocale;
+	newlocale;
+	querylocale;
+	uselocale;
+} ILLUMOS_0.4;
+
 SYMBOL_VERSION ILLUMOS_0.4 {	# Illumos additions
     protected:
         pipe2;
--- old/usr/src/test/os-tests/tests/Makefile	2013-07-11 12:26:15.923020495 +0000
+++ new/usr/src/test/os-tests/tests/Makefile	2013-07-11 12:26:15.930733701 +0000
@@ -13,6 +13,6 @@
 # Copyright (c) 2012 by Delphix. All rights reserved.
 #
 
-SUBDIRS = poll
+SUBDIRS = poll xlocale
 
 include $(SRC)/test/Makefile.com
--- /dev/null	2013-07-11 12:26:16.000000000 +0000
+++ new/usr/src/test/os-tests/tests/xlocale/Makefile	2013-07-11 12:26:16.132145119 +0000
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = xlocale_test
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+
+#LDLIBS += -lsocket
+C99MODE = -xc99=%all
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+	$(POST_PROCESS)
+
+%.o: ../%.c
+	$(COMPILE.c) $<
+
+install: all $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+	-$(RM) $(PROG)
+
+clean:
+	-$(RM) $(OBJS)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+	$(INS.dir)
+
+$(TESTDIR)/%: %
+	$(INS.file)
--- /dev/null	2013-07-11 12:26:16.000000000 +0000
+++ new/usr/src/test/os-tests/tests/xlocale/xlocale_test.c	2013-07-11 12:26:16.230586614 +0000
@@ -0,0 +1,42 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2013 David Hoeppner.  All rights reserved.
+ */
+
+#include <locale.h>
+#include <stdlib.h>
+
+static void
+newlocale_test(void)
+{
+	locale_t	new_loc = NULL;
+
+	new_loc = newlocale(LC_CTYPE_MASK, "loc1", (locale_t)NULL);
+	if (new_loc == (locale_t)NULL)
+		return;
+}
+
+static void
+run_tests(void)
+{
+	newlocale_test();
+}
+
+int
+main(int argc, char * const argv[])
+{
+
+	run_tests();
+
+	exit(0);
+}
