--- old/usr/src/cmd/localedef/messages.c	Tue May 20 07:58:43 2014
+++ new/usr/src/cmd/localedef/messages.c	Tue May 20 07:58:43 2014
@@ -10,6 +10,7 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  */
 
@@ -28,7 +29,7 @@
 #include "parser.tab.h"
 #include "lmessages.h"
 
-static struct lc_messages_T msgs;
+static struct lc_messages msgs;
 
 void
 init_messages(void)
--- old/usr/src/cmd/localedef/monetary.c	Tue May 20 07:58:43 2014
+++ new/usr/src/cmd/localedef/monetary.c	Tue May 20 07:58:43 2014
@@ -10,6 +10,7 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  */
 
@@ -27,7 +28,7 @@
 #include "parser.tab.h"
 #include "lmonetary.h"
 
-static struct lc_monetary_T mon;
+static struct lc_monetary mon;
 
 void
 init_monetary(void)
--- old/usr/src/cmd/localedef/numeric.c	Tue May 20 07:58:44 2014
+++ new/usr/src/cmd/localedef/numeric.c	Tue May 20 07:58:44 2014
@@ -10,6 +10,7 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  */
 
@@ -27,7 +28,7 @@
 #include "parser.tab.h"
 #include "lnumeric.h"
 
-static struct lc_numeric_T numeric;
+static struct lc_numeric numeric;
 
 void
 init_numeric(void)
--- old/usr/src/cmd/localedef/time.c	Tue May 20 07:58:44 2014
+++ new/usr/src/cmd/localedef/time.c	Tue May 20 07:58:44 2014
@@ -10,6 +10,7 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  */
 
@@ -27,7 +28,7 @@
 #include "parser.tab.h"
 #include "timelocal.h"
 
-struct lc_time_T tm;
+struct lc_time tm;
 
 void
 init_time(void)
--- old/usr/src/cmd/mdb/common/kmdb/mapfile_skel	Tue May 20 07:58:44 2014
+++ new/usr/src/cmd/mdb/common/kmdb/mapfile_skel	Tue May 20 07:58:44 2014
@@ -44,10 +44,19 @@
 		 * Secret additions to the module API
 		 */
 
-		/* Implementation detail of the ctype macros */
-		__ctype;	/* variable */
 		/* There should be only one - ours */
 		errno;		/* variable */
+		isprint;
+		isalnum;
+		isalpha;
+		isgraph;
+		iscntrl;
+		isdigit;
+		isxdigit;
+		isupper;
+		islower;
+		ispunct;
+		isspace;
 
 		mdb_tgt_aread;
 		mdb_dis_create;
--- old/usr/src/cmd/mdb/common/libstand/ctype.c	Tue May 20 07:58:44 2014
+++ new/usr/src/cmd/mdb/common/libstand/ctype.c	Tue May 20 07:58:44 2014
@@ -1,50 +1,97 @@
 /*
- * CDDL HEADER START
+ * 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.
  *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * ASCII versions of ctype character classification functions.  This avoids
+ * pulling in the entire locale framework that is in libc.
+ */
 
-#include <ctype.h>
+int
+isdigit(int c)
+{
+	return ((c >= '0' && c <= '9') ? 1 : 0);
+}
 
-unsigned char __ctype[129] =
+int
+isupper(int c)
 {
-	0, /* EOF */
-	_C,	_C,	_C,	_C,	_C,	_C,	_C,	_C,
-	_C,	_S|_C,	_S|_C,	_S|_C,	_S|_C,	_S|_C,	_C,	_C,
-	_C,	_C,	_C,	_C,	_C,	_C,	_C,	_C,
-	_C,	_C,	_C,	_C,	_C,	_C,	_C,	_C,
-	_S|_B,	_P,	_P,	_P,	_P,	_P,	_P,	_P,
-	_P,	_P,	_P,	_P,	_P,	_P,	_P,	_P,
-	_N|_X,	_N|_X,	_N|_X,	_N|_X,	_N|_X,	_N|_X,	_N|_X,	_N|_X,
-	_N|_X,	_N|_X,	_P,	_P,	_P,	_P,	_P,	_P,
-	_P,	_U|_X,	_U|_X,	_U|_X,	_U|_X,	_U|_X,	_U|_X,	_U,
-	_U,	_U,	_U,	_U,	_U,	_U,	_U,	_U,
-	_U,	_U,	_U,	_U,	_U,	_U,	_U,	_U,
-	_U,	_U,	_U,	_P,	_P,	_P,	_P,	_P,
-	_P,	_L|_X,	_L|_X,	_L|_X,	_L|_X,	_L|_X,	_L|_X,	_L,
-	_L,	_L,	_L,	_L,	_L,	_L,	_L,	_L,
-	_L,	_L,	_L,	_L,	_L,	_L,	_L,	_L,
-	_L,	_L,	_L,	_P,	_P,	_P,	_P,	_C,
-};
+	return ((c >= 'A' && c <= 'Z') ? 1 : 0);
+}
+
+
+int
+islower(int c)
+{
+	return ((c >= 'a' && c <= 'z') ? 1 : 0);
+}
+
+int
+isspace(int c)
+{
+	return (((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n') ||
+	    (c == '\v') || (c == '\f')) ? 1 : 0);
+}
+
+int
+isxdigit(int c)
+{
+	return ((isdigit(c) || (c >= 'A' && c <= 'F') ||
+	    (c >= 'a' && c <= 'f')) ? 1 : 0);
+}
+
+int
+isalpha(int c)
+{
+	return ((isupper(c) || islower(c)) ? 1 : 0);
+}
+
+
+int
+isalnum(int c)
+{
+	return ((isalpha(c) || isdigit(c)) ? 1 : 0);
+}
+
+int
+ispunct(int c)
+{
+	return (((c >= '!') && (c <= '/')) ||
+	    ((c >= ':') && (c <= '@')) ||
+	    ((c >= '[') && (c <= '`')) ||
+	    ((c >= '{') && (c <= '~')));
+}
+
+int
+iscntrl(int c)
+{
+	return ((c < 0x20) || (c == 0x7f));
+}
+
+int
+isprint(int c)
+{
+	/*
+	 * Almost the inverse of iscntrl, but be careful that c > 0x7f
+	 * returns false for everything.
+	 */
+	return ((c >= ' ') && (c <= '~'));
+}
+
+int
+isgraph(int c)
+{
+	/* isgraph is like is print, but excludes <space> */
+	return ((c >= '!') && (c <= '~'));
+}
--- old/usr/src/cmd/sgs/rtld/common/external.c	Tue May 20 07:58:44 2014
+++ new/usr/src/cmd/sgs/rtld/common/external.c	Tue May 20 07:58:44 2014
@@ -668,3 +668,52 @@
 	extern ssize_t __write(int, const void *, size_t);
 	return (__write(fd, buf, size));
 }
+
+/*
+ * ASCII versions of ctype character classification functions.  This avoids
+ * pulling in the entire locale framework that is in libc.
+ */
+
+int
+isdigit(int c)
+{
+	return ((c >= '0' && c <= '9') ? 1 : 0);
+}
+
+int
+isupper(int c)
+{
+	return ((c >= 'A' && c <= 'Z') ? 1 : 0);
+}
+
+int
+islower(int c)
+{
+	return ((c >= 'a' && c <= 'z') ? 1 : 0);
+}
+
+int
+isspace(int c)
+{
+	return (((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n') ||
+	    (c == '\v') || (c == '\f')) ? 1 : 0);
+}
+
+int
+isxdigit(int c)
+{
+	return ((isdigit(c) || (c >= 'A' && c <= 'F') ||
+	    (c >= 'a' && c <= 'f')) ? 1 : 0);
+}
+
+int
+isalpha(int c)
+{
+	return ((isupper(c) || islower(c)) ? 1 : 0);
+}
+
+int
+isalnum(int c)
+{
+	return ((isalpha(c) || isdigit(c)) ? 1 : 0);
+}
--- old/usr/src/head/Makefile	Tue May 20 07:58:44 2014
+++ new/usr/src/head/Makefile	Tue May 20 07:58:44 2014
@@ -22,6 +22,8 @@
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
+#
 # head/Makefile
 #
 # include global definitions
@@ -203,12 +205,12 @@
 	wctype.h	\
 	widec.h		\
 	wordexp.h	\
+	xlocale.h	\
 	xti.h		\
 	xti_inet.h	\
 	zone.h
 
 ISOHDRS = \
-	ctype_c99.h	\
 	ctype_iso.h	\
 	limits_iso.h	\
 	locale_iso.h	\
@@ -225,7 +227,6 @@
 	time_iso.h	\
 	wchar_c99.h	\
 	wchar_iso.h	\
-	wctype_c99.h	\
 	wctype_iso.h
 
 ARPAHDRS = 		\
--- old/usr/src/head/ctype.h	Tue May 20 07:58:44 2014
+++ new/usr/src/head/ctype.h	Tue May 20 07:58:44 2014
@@ -27,14 +27,14 @@
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
 
 #ifndef _CTYPE_H
 #define	_CTYPE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <iso/ctype_iso.h>
-#include <iso/ctype_c99.h>
 
 /*
  * Allow global visibility for symbols defined in
@@ -54,7 +54,10 @@
 using std::isxdigit;
 using std::tolower;
 using std::toupper;
+#if _cplusplus >= 201103L
+using std::isblank;
 #endif
+#endif
 
 #ifdef	__cplusplus
 extern "C" {
@@ -80,25 +83,42 @@
 	defined(_XOPEN_SOURCE)) || defined(__XPG4_CHAR_CLASS__)
 #define	isascii(c)	(!(((int)(c)) & ~0177))
 #define	toascii(c)	(((int)(c)) & 0177)
-#if defined(__XPG4_CHAR_CLASS__) || defined(_XPG4)
-#define	_toupper(c)	(__trans_upper[(int)(c)])
-#define	_tolower(c)	(__trans_lower[(int)(c)])
-#else
-#define	_toupper(c)	((__ctype + 258)[(int)(c)])
-#define	_tolower(c)	((__ctype + 258)[(int)(c)])
-#endif /* defined(__XPG4_CHAR_CLASS__) || defined(_XPG4) */
+#define	_toupper(c)	(toupper(c))
+#define	_tolower(c)	(tolower(c))
 
 #endif /* defined(__EXTENSIONS__) || ((!defined(_STRICT_STDC) ... */
 
 #endif	/* !defined(__lint) */
 
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+
+#ifndef _LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+extern int isalnum_l(int, locale_t);
+extern int isalpha_l(int, locale_t);
+extern int isblank_l(int, locale_t);
+extern int iscntrl_l(int, locale_t);
+extern int isdigit_l(int, locale_t);
+extern int isgraph_l(int, locale_t);
+extern int islower_l(int, locale_t);
+extern int isprint_l(int, locale_t);
+extern int ispunct_l(int, locale_t);
+extern int isspace_l(int, locale_t);
+extern int isupper_l(int, locale_t);
+extern int isxdigit_l(int, locale_t);
+
+#endif /* defined(_XPG7) || !defined(_STRICT_SYMBOLS) */
+
 #else	/* defined(__STDC__) */
 
 #if !defined(__lint)
 
 #define	isascii(c)	(!(((int)(c)) & ~0177))
-#define	_toupper(c)	((_ctype + 258)[(int)(c)])
-#define	_tolower(c)	((_ctype + 258)[(int)(c)])
+#define	_toupper(c)	(isascii(c) ? __trans_upper[(int)(c)] : toupper(c))
+#define	_tolower(c)	(isascii(c) ? __trans_lower[(int)(c)] : tolower(c))
 #define	toascii(c)	(((int)(c)) & 0177)
 
 #endif	/* !defined(__lint) */
--- old/usr/src/head/iso/ctype_c99.h	Tue May 20 07:58:44 2014
+++ /dev/null	Tue May 20 07:58:19 2014
@@ -1,86 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * An application should not include this header directly.  Instead it
- * should be included only through the inclusion of <ctype.h>.
- *
- * The contents of this header is limited to identifiers specified in
- * the C99 standard and in conflict with the C++ implementation of the
- * standard header.  The C++ standard may adopt the C99 standard at
- * which point it is expected that the symbols included here will
- * become part of the C++ std namespace.
- */
-
-#ifndef _ISO_CTYPE_C99_H
-#define	_ISO_CTYPE_C99_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * The following have been added as a result of the ISO/IEC 9899:1999
- * standard. For a strictly conforming C application, visibility is
- * contingent on the value of __STDC_VERSION__ (see sys/feature_tests.h).
- * For non-strictly conforming C applications, there are no restrictions
- * on the C namespace.
- */
-
-#if defined(__STDC__)
-
-#if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
-	defined(_XPG6) || defined(_STDC_C99) || defined(__EXTENSIONS__)
-extern int isblank(int);
-#endif
-
-#if !defined(__lint)
-
-#if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
-	defined(_XPG6) || defined(_STDC_C99) || \
-	defined(__XPG4_CHAR_CLASS__) || defined(__EXTENSIONS__)
-#define	isblank(c)	(__ctype_mask[(int)(c)] & _ISBLANK)
-#endif
-
-#endif	/* !defined(__lint) */
-
-#else	/* defined(__STDC__) */
-
-#if !defined(__lint)
-
-#define	isblank(c)	((_ctype + 1)[(int)(c)] & _B)
-
-#endif	/* !defined(__lint) */
-
-#endif	/* defined(__STDC__) */
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _ISO_CTYPE_C99_H */
--- old/usr/src/head/iso/ctype_iso.h	Tue May 20 07:58:44 2014
+++ new/usr/src/head/iso/ctype_iso.h	Tue May 20 07:58:44 2014
@@ -27,6 +27,9 @@
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
 
 /*
  * An application should not include this header directly.  Instead it
@@ -43,8 +46,6 @@
 #ifndef _ISO_CTYPE_ISO_H
 #define	_ISO_CTYPE_ISO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 
 #ifdef	__cplusplus
@@ -73,11 +74,24 @@
 #define	_ISPRINT	0x00008000
 #define	_ISALNUM	(_ISALPHA | _ISDIGIT)
 
+extern unsigned char	__ctype[];
+extern unsigned int	*__ctype_mask;
+extern int		*__trans_upper;
+extern int		*__trans_lower;
 
 #if defined(__STDC__)
 
-#if __cplusplus < 199711L  /* Use inline functions instead for ANSI C++ */
+#if __cplusplus >= 199711L
+namespace std {
+#endif
 
+/*
+ * These used to be macros, which while more efficient, precludes operation
+ * with thread specific locales.  The old macros will still work, but new
+ * code compiles to use functions.  This is specifically permitted by the
+ * various standards.  Only _tolower and _toupper were required to be
+ * delivered in macro form.
+ */
 extern int isalnum(int);
 extern int isalpha(int);
 extern int iscntrl(int);
@@ -89,11 +103,8 @@
 extern int isspace(int);
 extern int isupper(int);
 extern int isxdigit(int);
-
-#endif /* __cplusplus < 199711L */
-
-#if __cplusplus >= 199711L
-namespace std {
+#if defined(_XPG6) || defined(_STDC_C99) || !defined(_STRICT_SYMBOLS)
+extern int isblank(int);
 #endif
 
 extern int tolower(int);
@@ -103,96 +114,22 @@
 } /* end of namespace std */
 #endif
 
-extern unsigned char	__ctype[];
-extern unsigned int	*__ctype_mask;
-extern int		*__trans_upper;
-extern int		*__trans_lower;
-
-#if !defined(__lint)
-
-#if __cplusplus >= 199711L
-namespace std {
-
-#if defined(__XPG4_CHAR_CLASS__) || defined(_XPG4)
-
-inline int isalpha(int c) { return (__ctype_mask[c] & _ISALPHA); }
-inline int isupper(int c) { return (__ctype_mask[c] & _ISUPPER); }
-inline int islower(int c) { return (__ctype_mask[c] & _ISLOWER); }
-inline int isdigit(int c) { return (__ctype_mask[c] & _ISDIGIT); }
-inline int isxdigit(int c) { return (__ctype_mask[c] & _ISXDIGIT); }
-inline int isalnum(int c) { return (__ctype_mask[c] & _ISALNUM); }
-inline int isspace(int c) { return (__ctype_mask[c] & _ISSPACE); }
-inline int ispunct(int c) { return (__ctype_mask[c] & _ISPUNCT); }
-inline int isprint(int c) { return (__ctype_mask[c] & _ISPRINT); }
-inline int isgraph(int c) { return (__ctype_mask[c] & _ISGRAPH); }
-inline int iscntrl(int c) { return (__ctype_mask[c] & _ISCNTRL); }
-#else
-inline int isalpha(int c) { return ((__ctype + 1)[c] & (_U | _L)); }
-inline int isupper(int c) { return ((__ctype + 1)[c] & _U); }
-inline int islower(int c) { return ((__ctype + 1)[c] & _L); }
-inline int isdigit(int c) { return ((__ctype + 1)[c] & _N); }
-inline int isxdigit(int c) { return ((__ctype + 1)[c] & _X); }
-inline int isalnum(int c) { return ((__ctype + 1)[c] & (_U | _L | _N)); }
-inline int isspace(int c) { return ((__ctype + 1)[c] & _S); }
-inline int ispunct(int c) { return ((__ctype + 1)[c] & _P); }
-inline int isprint(int c) {
-	return ((__ctype + 1)[c] & (_P | _U | _L | _N | _B)); }
-inline int isgraph(int c) { return ((__ctype + 1)[c] & (_P | _U | _L | _N)); }
-inline int iscntrl(int c) { return ((__ctype + 1)[c] & _C); }
-#endif  /* defined(__XPG4_CHAR_CLASS__) || defined(_XPG4) */
-
-} /* end of namespace std */
-
-#else /* __cplusplus >= 199711L */
-
-#if defined(__XPG4_CHAR_CLASS__) || defined(_XPG4)
-#define	isalpha(c)	(__ctype_mask[(int)(c)] & _ISALPHA)
-#define	isupper(c)	(__ctype_mask[(int)(c)] & _ISUPPER)
-#define	islower(c)	(__ctype_mask[(int)(c)] & _ISLOWER)
-#define	isdigit(c)	(__ctype_mask[(int)(c)] & _ISDIGIT)
-#define	isxdigit(c)	(__ctype_mask[(int)(c)] & _ISXDIGIT)
-#define	isalnum(c)	(__ctype_mask[(int)(c)] & _ISALNUM)
-#define	isspace(c)	(__ctype_mask[(int)(c)] & _ISSPACE)
-#define	ispunct(c)	(__ctype_mask[(int)(c)] & _ISPUNCT)
-#define	isprint(c)	(__ctype_mask[(int)(c)] & _ISPRINT)
-#define	isgraph(c)	(__ctype_mask[(int)(c)] & _ISGRAPH)
-#define	iscntrl(c)	(__ctype_mask[(int)(c)] & _ISCNTRL)
-#else
-#define	isalpha(c)	((__ctype + 1)[(int)(c)] & (_U | _L))
-#define	isupper(c)	((__ctype + 1)[(int)(c)] & _U)
-#define	islower(c)	((__ctype + 1)[(int)(c)] & _L)
-#define	isdigit(c)	((__ctype + 1)[(int)(c)] & _N)
-#define	isxdigit(c)	((__ctype + 1)[(int)(c)] & _X)
-#define	isalnum(c)	((__ctype + 1)[(int)(c)] & (_U | _L | _N))
-#define	isspace(c)	((__ctype + 1)[(int)(c)] & _S)
-#define	ispunct(c)	((__ctype + 1)[(int)(c)] & _P)
-#define	isprint(c)	((__ctype + 1)[(int)(c)] & (_P | _U | _L | _N | _B))
-#define	isgraph(c)	((__ctype + 1)[(int)(c)] & (_P | _U | _L | _N))
-#define	iscntrl(c)	((__ctype + 1)[(int)(c)] & _C)
-
-#endif  /* defined(__XPG4_CHAR_CLASS__) || defined(_XPG4) */
-
-#endif	/* __cplusplus >= 199711L */
-
-#endif	/* !defined(__lint) */
-
 #else	/* defined(__STDC__) */
 
-extern unsigned char	_ctype[];
-
 #if !defined(__lint)
 
-#define	isalpha(c)	((_ctype + 1)[(int)(c)] & (_U | _L))
-#define	isupper(c)	((_ctype + 1)[(int)(c)] & _U)
-#define	islower(c)	((_ctype + 1)[(int)(c)] & _L)
-#define	isdigit(c)	((_ctype + 1)[(int)(c)] & _N)
-#define	isxdigit(c)	((_ctype + 1)[(int)(c)] & _X)
-#define	isalnum(c)	((_ctype + 1)[(int)(c)] & (_U | _L | _N))
-#define	isspace(c)	((_ctype + 1)[(int)(c)] & _S)
-#define	ispunct(c)	((_ctype + 1)[(int)(c)] & _P)
-#define	isprint(c)	((_ctype + 1)[(int)(c)] & (_P | _U | _L | _N | _B))
-#define	isgraph(c)	((_ctype + 1)[(int)(c)] & (_P | _U | _L | _N))
-#define	iscntrl(c)	((_ctype + 1)[(int)(c)] & _C)
+extern int isalpha();
+extern int isupper();
+extern int islower();
+extern int isdigit();
+extern int isxdigit();
+extern int isalnum();
+extern int isspace();
+extern int ispunct();
+extern int isprint();
+extern int isgraph();
+extern int iscntrl();
+extern int isblank();
 
 #endif	/* !defined(__lint) */
 
--- old/usr/src/head/iso/stdlib_iso.h	Tue May 20 07:58:44 2014
+++ new/usr/src/head/iso/stdlib_iso.h	Tue May 20 07:58:44 2014
@@ -23,6 +23,9 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
 
 /*	Copyright (c) 1988 AT&T	*/
 /*	  All Rights Reserved  	*/
@@ -50,12 +53,13 @@
 #endif
 
 #if defined(__STDC__)
-extern unsigned char	__ctype[];
-#define	MB_CUR_MAX	__ctype[520]
+unsigned char __mb_cur_max(void);
 #else
-extern unsigned char	_ctype[];
-#define	MB_CUR_MAX	_ctype[520]
+unsigned char __mb_cur_max();
 #endif
+#ifndef MB_CUR_MAX
+#define	MB_CUR_MAX	(__mb_cur_max())
+#endif
 
 #if __cplusplus >= 199711L
 namespace std {
--- old/usr/src/head/iso/wctype_c99.h	Tue May 20 07:58:44 2014
+++ /dev/null	Tue May 20 07:58:19 2014
@@ -1,79 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * An application should not include this header directly.  Instead it
- * should be included only through the inclusion of other Sun headers.
- *
- * The contents of this header is limited to identifiers specified in
- * the C99 standard and in conflict with the C++ implementation of the
- * standard header.  The C++ standard may adopt the C99 standard at
- * which point it is expected that the symbols included here will
- * become part of the C++ std namespace.
- */
-
-#ifndef _ISO_WCTYPE_C99_H
-#define	_ISO_WCTYPE_C99_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * The following have been added as a result of the ISO/IEC 9899:1999
- * standard. For a strictly conforming C application, visibility is
- * contingent on the value of __STDC_VERSION__ (see sys/feature_tests.h).
- * For non-strictly conforming C applications, there are no restrictions
- * on the C namespace.
- */
-
-/*
- * Visibility of the iswblank() function is not allowed in the X/Open
- * or POSIX namespace prior to SUSv3.  However, since SUSv3 aligns
- * with the C99 standard, visibility is controlled by the version of
- * the C standard as indicated by the value of __STDC_VERSION__ (see
- * sys/feature_tests.h and _STDC_C99) rather than if the X/Open or POSIX
- * feature test macros are used.  Conforming SUSv3 applications are
- * required to use c99, therefore, iswblank() will be made visible by
- * default.
- */
-
-#if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
-	defined(_STDC_C99) || defined(__EXTENSIONS__)
-#ifdef __STDC__
-extern int iswblank(wint_t);
-#else
-extern int iswblank();
-#endif
-#endif /* defined(__EXTENSIONS__)... */
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _ISO_WCTYPE_C99_H */
--- old/usr/src/head/iso/wctype_iso.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/iso/wctype_iso.h	Tue May 20 07:58:45 2014
@@ -27,6 +27,9 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
 
 /*
  * An application should not include this header directly.  Instead it
@@ -43,8 +46,6 @@
 #ifndef	_ISO_WCTYPE_ISO_H
 #define	_ISO_WCTYPE_ISO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 
 #ifdef	__cplusplus
@@ -94,6 +95,12 @@
 extern	int iswspace(wint_t);
 extern	int iswupper(wint_t);
 extern	int iswxdigit(wint_t);
+
+#if (__cplusplus >= 201103L) || defined(_STDC_C99) || defined(_XPG6) || \
+	!defined(_STRICT_SYMBOLS)
+extern	int iswblank(wint_t);
+#endif
+
 /* tow* also become functions */
 extern	wint_t towlower(wint_t);
 extern	wint_t towupper(wint_t);
@@ -101,7 +108,7 @@
 extern	wint_t towctrans(wint_t, wctrans_t);
 extern  int iswctype(wint_t, wctype_t);
 extern  wctype_t wctype(const char *);
-#else
+#else	/* __STDC__ */
 extern  int iswalnum();
 extern  int iswalpha();
 extern  int iswcntrl();
@@ -120,7 +127,10 @@
 extern	wint_t towctrans();
 extern  int iswctype();
 extern  wctype_t wctype();
+#if defined(_XPG6) || !defined(_STRICT_SYMBOLS)
+extern  int iswblank();
 #endif
+#endif	/* __STDC__ */
 
 /* bit definition for character class */
 
--- old/usr/src/head/langinfo.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/langinfo.h	Tue May 20 07:58:45 2014
@@ -27,12 +27,14 @@
 /*	Copyright (c) 1988 AT&T	*/
 /*	  All Rights Reserved  	*/
 
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
 
+
 #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>
 
@@ -150,6 +152,19 @@
 char   *nl_langinfo();		/* get a string from the database	*/
 #endif
 
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+#if defined(__STDC__)
+char	*nl_langinfo_l(nl_item, locale_t);
+#else
+char	*nl_langinfo_l();
+#endif
+#endif
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/head/locale.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/locale.h	Tue May 20 07:58:45 2014
@@ -24,11 +24,20 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ *
+ * Portions of this file developed by Garrett D'Amore are licensed
+ * under the terms of the Common Development and Distribution License (CDDL)
+ * version 1.0 only.  The use of subsequent versions of the License are
+ * is specifically prohibited unless those terms are not in conflict with
+ * version 1.0 of the License.  You can find this license on-line at
+ * http://www.illumos.org/license/CDDL
+ */
+
 #ifndef _LOCALE_H
 #define	_LOCALE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <iso/locale_iso.h>
 
 #if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
@@ -56,6 +65,42 @@
 	(((int)(c) >= LC_CTYPE) && ((int)(c) <= _LastCategory) || \
 	((int)c == LC_ALL))
 
+
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+
+/*
+ * These were added in POSIX 2008 as part of the newlocale() specification.
+ */
+#define	LC_CTYPE_MASK		(1 << LC_CTYPE)
+#define	LC_NUMERIC_MASK		(1 << LC_NUMERIC)
+#define	LC_TIME_MASK		(1 << LC_TIME)
+#define	LC_COLLATE_MASK		(1 << LC_COLLATE)
+#define	LC_MONETARY_MASK	(1 << LC_MONETARY)
+#define	LC_MESSAGES_MASK	(1 << LC_MESSAGES)
+#define	LC_ALL_MASK		(0x3f)
+
+#ifndef _LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+#if	defined(__STDC__)
+locale_t	duplocale(locale_t);
+void		freelocale(locale_t);
+locale_t	newlocale(int, const char *, locale_t);
+locale_t	uselocale(locale_t);
+#else	/* __STDC__ */
+locale_t	duplocale();
+void		freelocale();
+locale_t	newlocale();
+locale_t	uselocale();
+#endif	/* __STDC__ */
+
+#define	LC_GLOBAL_LOCALE	__global_locale
+extern locale_t			__global_locale;
+
+#endif	/* defined(_XPG7) || !defined(_STRICT_SYMBOLS) */
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/head/monetary.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/monetary.h	Tue May 20 07:58:45 2014
@@ -23,12 +23,13 @@
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
 
 #ifndef	_MONETARY_H
 #define	_MONETARY_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 #include <sys/types.h>
 
@@ -39,8 +40,21 @@
 #if defined(__STDC__)
 extern ssize_t	strfmon(char *_RESTRICT_KYWD, size_t,
 			const char *_RESTRICT_KYWD, ...);
+
+#if defined(_XPG7) || (!defined(_STRICT_STRICT_SYMBOLS))
+
+#ifndef _LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+extern ssize_t strfmon_l(char *_RESTRICT_KYWD, size_t, locale_t,
+		const char *_RESTRICT_KYWD, ...);
+#endif
+
 #else
 extern ssize_t	strfmon();
+extern ssize_t	strfmon_l();
 #endif
 
 #ifdef __cplusplus
--- old/usr/src/head/string.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/string.h	Tue May 20 07:58:45 2014
@@ -20,6 +20,7 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
@@ -86,20 +87,30 @@
 		int, size_t);
 #endif
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
-	/* || defined(_XPG7) */
-extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, size_t);
+#if !defined(_STRICT_SYMBOLS) || defined(_XPG7)
+
 extern char *stpcpy(char *_RESTRICT_KYWD, const char *_RESTRICT_KYWD);
 extern char *stpncpy(char *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, size_t);
 extern char *strndup(const char *, size_t);
 extern size_t strnlen(const char *, size_t);
 extern char *strsignal(int);
+
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
 #endif
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
+extern int strcoll_l(const char *, const char *, locale_t);
+extern size_t strxfrm_l(char *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+    size_t, locale_t);
+extern int strcasecmp_l(const char *, const char *, locale_t);
+extern int strncasecmp_l(const char *, const char *, size_t, locale_t);
+
+#endif /* defined(_STRICT_SYMBOLS) || defined(_XPG7) */
+
+#if !defined(_STRICT_SYMBOLS)
+
+/* Note that some of these are also declared in strings.h for XPG4_2+ */
 extern int uucopy(const void *_RESTRICT_KYWD, void *_RESTRICT_KYWD, size_t);
 extern int uucopystr(const void *_RESTRICT_KYWD, void *_RESTRICT_KYWD, size_t);
 extern int ffs(int);
@@ -115,6 +126,9 @@
 extern size_t strlcat(char *, const char *, size_t);
 extern char *strsep(char **stringp, const char *delim);
 extern char *strchrnul(const char *, int);
+extern char *strcasestr_l(const char *, const char *, locale_t);
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, size_t);
 #endif /* defined(__EXTENSIONS__)... */
 
 #if defined(__EXTENSIONS__) || \
@@ -194,11 +208,11 @@
 extern void *memccpy();
 #endif
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
-	/* || defined(_XPG7) */
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
 extern int strcasecmp();
 extern int strncasecmp();
+extern int strcasecmp_l();
+extern int strncasecmp_l();
 extern char *stpcpy();
 extern char *stpncpy();
 extern char *strndup();
@@ -206,8 +220,7 @@
 extern char *strsignal();
 #endif
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
+#if !defined(_STRICT_SYMBOLS)
 extern int uucopy();
 extern int uucopystr();
 extern int ffs();
@@ -217,17 +230,23 @@
 extern int flsl();
 extern int flsll();
 extern char *strcasestr();
+extern char *strcasestr_l();
 extern char *strnstr();
 extern size_t strlcpy();
 extern size_t strlcat();
 extern char *strsep();
 extern char *strchrnul();
-#endif /* defined(__EXTENSIONS__) ... */
+#endif /* _STRICT_SYMBOLS */
 
 #if defined(__EXTENSIONS__) || !defined(__XOPEN_OR_POSIX) || defined(_XPG4_2)
 extern char *strdup();
 #endif
 
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+extern size_t strcoll_l();
+extern size_t strxfrm_l();
+#endif
+
 #endif	/* __STDC__ */
 
 #ifdef	__cplusplus
--- old/usr/src/head/strings.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/strings.h	Tue May 20 07:58:45 2014
@@ -23,12 +23,13 @@
  * Copyright (c) 1995, 1996, by Sun Microsystems, Inc.
  * All rights reserved.
  */
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
 
 #ifndef	_STRINGS_H
 #define	_STRINGS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/feature_tests.h>
 
@@ -63,6 +64,14 @@
 extern int ffs(int);
 extern int strcasecmp(const char *, const char *);
 extern int strncasecmp(const char *, const char *, size_t);
+#if defined(_XPG7)
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+extern int strcasecmp_l(const char *, const char *, locale_t);
+extern int strncasecmp_l(const char *, const char *, size_t, locale_t);
+#endif	/* defined(_XPG7) */
 #endif	/* defined(_XPG4_2) && !defined(__EXTENSIONS__) */
 
 #else
@@ -78,6 +87,10 @@
 extern int ffs();
 extern int strcasecmp();
 extern int strncasecmp();
+#if defined(_XPG7)
+extern int strcasecmp_l();
+extern int strncasecmp_l();
+#endif
 #endif /* defined(_XPG4_2) && !defined(__EXTENSIONS__) */
 
 #endif	/* __STDC__ */
--- old/usr/src/head/time.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/time.h	Tue May 20 07:58:45 2014
@@ -28,6 +28,7 @@
  */
 /*
  * Copyright 2010 Nexenta Systems, Inc.  Al rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  */
 
 #ifndef _TIME_H
@@ -371,6 +372,23 @@
 
 #endif /* defined(__EXTENSIONS__) || defined(_REENTRANT)... */
 
+
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+#if	defined(__STDC__)
+extern size_t strftime_l(char *_RESTRICT_KYWD, size_t,
+	const char *_RESTRICT_KYWD, const struct tm *_RESTRICT_KYWD, locale_t);
+#else /* __STDC__ */
+extern size_t strftime_l();
+#endif /* __STDC__ */
+
+#endif /* defined(_XPG7) || !defined(_STRICT_SYMBOLS) */
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/head/wchar.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/wchar.h	Tue May 20 07:58:45 2014
@@ -20,6 +20,7 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
@@ -167,18 +168,30 @@
 #endif
 #endif /* !defined(_STRICT_STDC) || defined(_XOPEN_SOURCE)... */
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
-	/* || defined(_XPG7) */
-extern wchar_t *wcsdup(const wchar_t *);
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+
+#ifndef _LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
 extern size_t wcsnlen(const wchar_t *, size_t);
 extern wchar_t *wcpcpy(wchar_t *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD);
 extern wchar_t *wcpncpy(wchar_t *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD,
     size_t);
+extern size_t wcsxfrm_l(wchar_t *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD,
+    size_t, locale_t);
+extern int wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
+extern wchar_t *wcsdup(const wchar_t *);
 extern int wcscasecmp(const wchar_t *, const wchar_t *);
+extern int wcscasecmp_l(const wchar_t *, const wchar_t *, locale_t);
 extern int wcsncasecmp(const wchar_t *, const wchar_t *, size_t);
-#endif
+extern int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t, locale_t);
+extern size_t mbsnrtowcs(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
 
+#endif	/* defined(_XPG7) || !defined(_STRICT_SYMBOLS) */
+
 #else /* __STDC__ */
 
 #if !defined(_STRICT_STDC) || defined(_XOPEN_SOURCE) || defined(__EXTENSIONS__)
@@ -202,15 +215,18 @@
 extern wctype_t wctype();
 #endif /* !defined(_STRICT_STDC) || defined(_XOPEN_SOURCE)... */
 
-#if defined(__EXTENSIONS__) || \
-	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
-	/* || defined(_XPG7) */
-extern wchar_t *wcsdup();
+#if defined(_XGP7) || !defined(_STRICT_SYMBOLS)
 extern size_t wcsnlen();
 extern wchar_t *wcpcpy();
 extern wchar_t *wcpncpy();
+extern size_t wcsxfrm_l();
+extern int wcscoll_l();
+extern wchar_t *wcsdup();
 extern int wcscasecmp();
+extern int wcscasecmp_l();
 extern int wcsncasecmp();
+extern int wcsncasecmp_l();
+extern size_t mbsnrtowcs();
 #endif
 
 #endif /* __STDC__ */
--- old/usr/src/head/wctype.h	Tue May 20 07:58:45 2014
+++ new/usr/src/head/wctype.h	Tue May 20 07:58:45 2014
@@ -24,6 +24,7 @@
 /*	definitions for international functions	*/
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -31,11 +32,9 @@
 #ifndef	_WCTYPE_H
 #define	_WCTYPE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+#include <sys/feature_tests.h>
 #include <iso/wctype_iso.h>
-#if !defined(__XOPEN_OR_POSIX) && !defined(_STRICT_STDC) || \
-	defined(__EXTENSIONS__)
+#ifndef _STRICT_SYMBOLS
 #include <ctype.h>
 #include <wchar.h>
 #endif
@@ -64,22 +63,17 @@
 using std::towctrans;
 using std::iswctype;
 using std::wctype;
+#if __cplusplus >= 201103L
+using std::iswblank;
 #endif
+#endif
 
-/*
- * This header needs to be included here because it relies on the global
- * visibility of wint_t in the C++ environment.
- */
-
-#include <iso/wctype_c99.h>
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 /* do not allow any of the following in a strictly conforming application */
-#if !defined(__XOPEN_OR_POSIX) && !defined(_STRICT_STDC) || \
-	defined(__EXTENSIONS__)
+#ifndef _STRICT_SYMBOLS
 
 /*
  * data structure for supplementary code set
@@ -111,8 +105,6 @@
 /* isw*, except iswascii(), are not macros any more.  They become functions */
 #ifdef __STDC__
 
-extern	unsigned _iswctype(wchar_t, int);
-extern	wchar_t _trwctype(wchar_t, int);
 /* is* also become functions */
 extern	int isphonogram(wint_t);
 extern	int isideogram(wint_t);
@@ -119,10 +111,14 @@
 extern	int isenglish(wint_t);
 extern	int isnumber(wint_t);
 extern	int isspecial(wint_t);
-#else
+/* From BSD/MacOS */
+extern	int iswideogram(wint_t);
+extern	int iswphonogram(wint_t);
+extern	int iswnumber(wint_t);
+extern	int iswspecial(wint_t);
 
-extern  unsigned _iswctype();
-extern  wchar_t _trwctype();
+#else	/* __STDC__ */
+
 /* is* also become functions */
 extern  int isphonogram();
 extern  int isideogram();
@@ -129,6 +125,11 @@
 extern  int isenglish();
 extern  int isnumber();
 extern  int isspecial();
+/* From BSD/MacOS */
+extern	int iswideogram();
+extern	int iswphonogram();
+extern	int iswnumber();
+extern	int iswspecial();
 #endif
 
 #define	iscodeset0(c)	isascii(c)
@@ -136,8 +137,56 @@
 #define	iscodeset2(c)	(((c) & WCHAR_CSMASK) == WCHAR_CS2)
 #define	iscodeset3(c)	(((c) & WCHAR_CSMASK) == WCHAR_CS3)
 
-#endif /* !defined(__XOPEN_OR_POSIX)... */
+#endif /* !defined(_STRICT_SYMBOLS)... */
 
+
+/* XPG7 extended locale support */
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+#if	defined(__STDC__)
+extern wint_t towlower_l(wint_t, locale_t);
+extern wint_t towupper_l(wint_t, locale_t);
+extern wint_t towctrans_l(wint_t, wctrans_t, locale_t);
+extern int iswctype_l(wint_t, wctype_t, locale_t);
+extern int iswalnum_l(wint_t, locale_t);
+extern int iswalpha_l(wint_t, locale_t);
+extern int iswcntrl_l(wint_t, locale_t);
+extern int iswdigit_l(wint_t, locale_t);
+extern int iswgraph_l(wint_t, locale_t);
+extern int iswlower_l(wint_t, locale_t);
+extern int iswprint_l(wint_t, locale_t);
+extern int iswpunct_l(wint_t, locale_t);
+extern int iswspace_l(wint_t, locale_t);
+extern int iswupper_l(wint_t, locale_t);
+extern int iswxdigit_l(wint_t, locale_t);
+extern wctrans_t wctrans_l(const char *, locale_t);
+extern wctype_t wctype_l(const char *, locale_t);
+#else	/* __STDC__ */
+extern wint_t towlower_l();
+extern wint_t towupper_l();
+extern wint_t towctrans_l();
+extern int iswctype_l();
+extern int iswalnum_l();
+extern int iswalpha_l();
+extern int iswcntrl_l();
+extern int iswdigit_l();
+extern int iswgraph_l();
+extern int iswlower_l();
+extern int iswprint_l();
+extern int iswpunct_l();
+extern int iswspace_l();
+extern int iswupper_l();
+extern int iswxdigit_l();
+extern wctrans_t wctrans_l();
+extern wctype_t wctype_l();
+#endif	/* __STDC__ */
+#endif /* defined(_XPG7) || !defined(_STRICT_SYMBOLS) */
+
 #ifdef	__cplusplus
 }
 #endif
--- /dev/null	Tue May 20 07:58:45 2014
+++ new/usr/src/head/xlocale.h	Tue May 20 07:58:45 2014
@@ -0,0 +1,113 @@
+/*
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ */
+
+#ifndef _XLOCALE_H
+#define	_XLOCALE_H
+
+/*
+ * This file supplies declarations for extended locale routines, as
+ * originally delivered by MacOS X.  Many of these things are now
+ * officially part of XPG7.  (Note that while the interfaces are the
+ * same as MacOS X, there is no shared implementation.)
+ *
+ * Those declarations that are part of XPG7 are provided for the in the
+ * XPG7-specified location.  This file lists just the declarations that
+ * were not part of the standard.  These will be useful in their own right,
+ * and will aid porting programs that don't strictly follow the standard.
+ *
+ * Note that it is an error to include this file in a program with strict
+ * symbol visibilty rules (under strict ANSI or POSIX_C_SOURCE rules.)
+ * If this is done, the symbols defined here will indeed be exposed to your
+ * program, but those symbols that are part of the related standards might
+ * not be.
+ */
+
+#include <sys/feature_tests.h>
+#include <wchar.h>
+#include <locale.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef	_LOCALE_T
+#define	_LOCALE_T
+typedef struct locale *locale_t;
+#endif
+
+int mbsinit_l(const mbstate_t *, locale_t);
+
+size_t mbsrtowcs_l(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
+    size_t, mbstate_t *_RESTRICT_KYWD, locale_t);
+
+size_t mbsnrtowcs_l(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD, locale_t);
+
+char *strptime_l(const char *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+    struct tm *_RESTRICT_KYWD, locale_t);
+
+int wcwidth_l(wchar_t, locale_t);
+
+int wcswidth_l(const wchar_t *, size_t, locale_t);
+
+int iswspecial_l(wint_t, locale_t);
+int iswnumber_l(wint_t, locale_t);
+int iswhexnumber_l(wint_t, locale_t);
+int iswideogram_l(wint_t, locale_t);
+int iswphonogram_l(wint_t, locale_t);
+
+wint_t btowc_l(int, locale_t);
+int wctob_l(wint_t, locale_t);
+size_t mbrtowc_l(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, size_t,
+    mbstate_t *_RESTRICT_KYWD, locale_t);
+size_t mbstowcs_l(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, size_t,
+    locale_t);
+int mblen_l(const char *, size_t, locale_t);
+size_t mbrlen_l(const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD,
+    locale_t);
+int mbtowc_l(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, size_t,
+    locale_t);
+size_t wcsrtombs_l(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
+    size_t len, mbstate_t *_RESTRICT_KYWD, locale_t);
+size_t wcrtomb_l(char *_RESTRICT_KYWD, wchar_t, mbstate_t *_RESTRICT_KYWD,
+    locale_t);
+size_t wcstombs_l(char *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD, size_t,
+    locale_t);
+int wctomb_l(char *, wchar_t, locale_t);
+
+unsigned char __mb_cur_max_l(locale_t);
+#ifndef	MB_CUR_MAX_L
+#define	MB_CUR_MAX_L(l)	(__mb_cur_max_l(l))
+#endif
+
+
+#if defined(_XPG4) && !defined(_FILEDEFED) || __cplusplus >= 199711L
+#define	_FILEDEFED
+typedef __FILE FILE;
+#endif
+
+wint_t fgetwc_l(FILE *, locale_t);
+wint_t getwc_l(FILE *, locale_t);
+
+#ifndef getwchar_l
+#define	getwchar_l(l)	fgetwc_l(stdin, (l))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XLOCALE_H */
--- old/usr/src/lib/libc/amd64/Makefile	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/amd64/Makefile	Tue May 20 07:58:46 2014
@@ -23,6 +23,7 @@
 # Copyright (c) 2012, Joyent, Inc. All rights reserved.
 #
 # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
 # Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
@@ -655,9 +656,6 @@
 	getwchar.o		\
 	putwchar.o		\
 	putws.o			\
-	strcasecmp.o		\
-	strcasestr.o		\
-	strncasecmp.o		\
 	strtows.o		\
 	wcsnlen.o		\
 	wcsstr.o		\
@@ -670,7 +668,6 @@
 	wmemcpy.o		\
 	wmemmove.o		\
 	wmemset.o		\
-	wscasecmp.o		\
 	wscat.o			\
 	wschr.o			\
 	wscmp.o			\
@@ -678,7 +675,6 @@
 	wscspn.o		\
 	wsdup.o			\
 	wslen.o			\
-	wsncasecmp.o		\
 	wsncat.o		\
 	wsncmp.o		\
 	wsncpy.o		\
@@ -696,7 +692,6 @@
 	gettext_gnu.o		\
 	gettext_real.o		\
 	gettext_util.o		\
-	isdigit.o		\
 	plural_parser.o		\
 	wdresolve.o		\
 	_ctype.o		\
@@ -724,6 +719,7 @@
 	gb2312.o		\
 	gbk.o			\
 	getdate.o		\
+	isdigit.o		\
 	iswctype.o		\
 	ldpart.o		\
 	lmessages.o		\
@@ -730,6 +726,7 @@
 	lnumeric.o		\
 	lmonetary.o		\
 	localeconv.o		\
+	localeimpl.o		\
 	mbftowc.o		\
 	mblen.o			\
 	mbrlen.o		\
@@ -751,9 +748,12 @@
 	runetype.o		\
 	setlocale.o		\
 	setrunelocale.o		\
+	strcasecmp.o		\
+	strcasestr.o		\
 	strcoll.o		\
 	strfmon.o		\
 	strftime.o		\
+	strncasecmp.o		\
 	strptime.o		\
 	strxfrm.o		\
 	table.o			\
@@ -763,6 +763,7 @@
 	ungetwc.o		\
 	utf8.o			\
 	wcrtomb.o		\
+	wcscasecmp.o		\
 	wcscoll.o		\
 	wcsftime.o		\
 	wcsnrtombs.o		\
--- old/usr/src/lib/libc/i386/Makefile.com	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/i386/Makefile.com	Tue May 20 07:58:46 2014
@@ -22,6 +22,7 @@
 # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright (c) 2013, Joyent, Inc.  All rights reserved.
 # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
 #
 # Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -697,9 +698,6 @@
 	getwchar.o		\
 	putwchar.o		\
 	putws.o			\
-	strcasecmp.o		\
-	strcasestr.o		\
-	strncasecmp.o		\
 	strtows.o		\
 	wcsnlen.o		\
 	wcsstr.o		\
@@ -712,7 +710,6 @@
 	wmemcpy.o		\
 	wmemmove.o		\
 	wmemset.o		\
-	wscasecmp.o		\
 	wscat.o			\
 	wschr.o			\
 	wscmp.o			\
@@ -720,7 +717,6 @@
 	wscspn.o		\
 	wsdup.o			\
 	wslen.o			\
-	wsncasecmp.o		\
 	wsncat.o		\
 	wsncmp.o		\
 	wsncpy.o		\
@@ -738,7 +734,6 @@
 	gettext_gnu.o		\
 	gettext_real.o		\
 	gettext_util.o		\
-	isdigit.o		\
 	plural_parser.o		\
 	wdresolve.o		\
 	_ctype.o		\
@@ -766,6 +761,7 @@
 	gb2312.o		\
 	gbk.o			\
 	getdate.o		\
+	isdigit.o		\
 	iswctype.o		\
 	ldpart.o		\
 	lmessages.o		\
@@ -772,6 +768,7 @@
 	lnumeric.o		\
 	lmonetary.o		\
 	localeconv.o		\
+	localeimpl.o		\
 	mbftowc.o		\
 	mblen.o			\
 	mbrlen.o		\
@@ -793,9 +790,12 @@
 	runetype.o		\
 	setlocale.o		\
 	setrunelocale.o		\
+	strcasecmp.o		\
+	strcasestr.o		\
 	strcoll.o		\
 	strfmon.o		\
 	strftime.o		\
+	strncasecmp.o		\
 	strptime.o		\
 	strxfrm.o		\
 	table.o			\
@@ -805,6 +805,7 @@
 	ungetwc.o		\
 	utf8.o			\
 	wcrtomb.o		\
+	wcscasecmp.o		\
 	wcscoll.o		\
 	wcsftime.o		\
 	wcsnrtombs.o		\
--- old/usr/src/lib/libc/port/i18n/isdigit.c	Tue May 20 07:58:46 2014
+++ /dev/null	Tue May 20 07:58:45 2014
@@ -1,148 +0,0 @@
-/*
- * 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 2010 Nexenta Systems, Inc.  All rights reserved.
- */
-
-/*
- * This file contains the implementation of various functional forms
- * of the ctype tests, specifically the required by ISO C.  These are defined
- * in the "C" (POSIX) locale.
- */
-
-#include "lint.h"
-#include <ctype.h>
-
-/*
- * We are supplying functional forms, so make sure to suppress any macros
- * we might have imported.
- */
-
-#ifdef isblank
-#undef isblank
-#endif
-
-int
-isblank(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISBLANK));
-}
-
-#ifdef isupper
-#undef isupper
-#endif
-
-int
-isupper(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISUPPER));
-}
-
-#ifdef islower
-#undef islower
-#endif
-
-int
-islower(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISLOWER));
-}
-
-#ifdef isdigit
-#undef isdigit
-#endif
-
-int
-isdigit(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISDIGIT));
-}
-
-#ifdef isxdigit
-#undef isxdigit
-#endif
-
-int
-isxdigit(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISXDIGIT));
-}
-
-#ifdef isalpha
-#undef isalpha
-#endif
-
-int
-isalpha(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISALPHA));
-}
-
-#ifdef isalnum
-#undef isalnum
-#endif
-
-int
-isalnum(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISALNUM));
-}
-
-#ifdef isspace
-#undef isspace
-#endif
-
-int
-isspace(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISSPACE));
-}
-
-#ifdef iscntrl
-#undef iscntrl
-#endif
-
-int
-iscntrl(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISCNTRL));
-}
-
-#ifdef isgraph
-#undef isgraph
-#endif
-
-int
-isgraph(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISGRAPH));
-}
-
-#ifdef ispunct
-#undef ispunct
-#endif
-
-int
-ispunct(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISPUNCT));
-}
-
-#ifdef isprint
-#undef isprint
-#endif
-
-int
-isprint(int c)
-{
-	return (((unsigned)c > 255) ? 0 : (__ctype_mask[c] & _ISPRINT));
-}
--- old/usr/src/lib/libc/port/i18n/wscasecmp.c	Tue May 20 07:58:46 2014
+++ /dev/null	Tue May 20 07:58:45 2014
@@ -1,55 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * Compare strings ignoring case difference.
- *	returns:  s1>s2: >0  s1==s2: 0  s1<s2: <0
- * All letters are converted to the lowercase and compared.
- */
-
-#pragma weak _wscasecmp = wscasecmp
-
-#include "lint.h"
-#include <stdlib.h>
-#include <widec.h>
-#include "libc.h"
-
-int
-wcscasecmp(const wchar_t *s1, const wchar_t *s2)
-{
-	if (s1 == s2)
-		return (0);
-
-	while (towlower(*s1) == towlower(*s2++))
-		if (*s1++ == 0)
-			return (0);
-	return (towlower(*s1) - towlower(*(s2 - 1)));
-}
-
-int
-wscasecmp(const wchar_t *s1, const wchar_t *s2)
-{
-	return (wcscasecmp(s1, s2));
-}
--- old/usr/src/lib/libc/port/i18n/wsncasecmp.c	Tue May 20 07:58:46 2014
+++ /dev/null	Tue May 20 07:58:45 2014
@@ -1,56 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * Compare strings ignoring case difference.
- *	returns:  s1>s2: >0  s1==s2: 0  s1<s2: <0
- * All letters are converted to the lowercase and compared.
- */
-
-#pragma weak _wsncasecmp = wsncasecmp
-
-#include "lint.h"
-#include <stdlib.h>
-#include <widec.h>
-#include "libc.h"
-
-int
-wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
-{
-	if (s1 == s2)
-		return (0);
-
-	n++;
-	while (--n > 0 && towlower(*s1) == towlower(*s2++))
-		if (*s1++ == 0)
-			return (0);
-	return ((n == 0) ? 0 : (towlower(*s1) - towlower(*(s2 - 1))));
-}
-
-int
-wsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
-{
-	return (wcsncasecmp(s1, s2, n));
-}
--- old/usr/src/lib/libc/port/locale/_ctype.h	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/_ctype.h	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -79,6 +80,4 @@
 #define	_CTYPE_SWM	0xe0000000U		/* Mask for screen width data */
 #define	_CTYPE_SWS	30			/* Bits to shift to get width */
 
-unsigned int	___runetype(int);
-
 #endif /* !__CTYPE_H_ */
--- old/usr/src/lib/libc/port/locale/big5.c	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/big5.c	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
  * Copyright (c) 1993
@@ -35,11 +36,11 @@
 #include "lint.h"
 #include <sys/types.h>
 #include <errno.h>
-#include "runetype.h"
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
@@ -47,22 +48,27 @@
 static int	_BIG5_mbsinit(const mbstate_t *);
 static size_t	_BIG5_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_BIG5_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_BIG5_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
 
 typedef struct {
 	wchar_t	ch;
 } _BIG5State;
 
-int
-_BIG5_init(_RuneLocale *rl)
+void
+_BIG5_init(struct lc_ctype *lct)
 {
-
-	__mbrtowc = _BIG5_mbrtowc;
-	__wcrtomb = _BIG5_wcrtomb;
-	__mbsinit = _BIG5_mbsinit;
-	_CurrentRuneLocale = rl;
-	__ctype[520] = 2;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_mbrtowc = _BIG5_mbrtowc;
+	lct->lc_wcrtomb = _BIG5_wcrtomb;
+	lct->lc_mbsnrtowcs = _BIG5_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _BIG5_wcsnrtombs;
+	lct->lc_mbsinit = _BIG5_mbsinit;
+	lct->lc_max_mblen = 2;
+	lct->lc_is_ascii = 0;
 }
 
 static int
@@ -163,4 +169,18 @@
 	}
 	*s = wc & 0xff;
 	return (1);
+}
+
+static size_t
+_BIG5_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _BIG5_mbrtowc));
+}
+
+static size_t
+_BIG5_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _BIG5_wcrtomb));
 }
--- old/usr/src/lib/libc/port/locale/btowc.c	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/btowc.c	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002, 2003 Tim J. Robbins.
  * All rights reserved.
@@ -28,10 +29,12 @@
 #include "lint.h"
 #include <stdio.h>
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
 
 wint_t
-btowc(int c)
+btowc_l(int c, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	mbstate_t mbs = initial;
@@ -46,7 +49,13 @@
 	 * counts.
 	 */
 	cc = (char)c;
-	if (__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+	if (mbrtowc_l(&wc, &cc, 1, &mbs, loc) > 1)
 		return (WEOF);
 	return (wc);
+}
+
+wint_t
+btowc(int c)
+{
+	return (btowc_l(c, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/collate.c	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/collate.c	Tue May 20 07:58:46 2014
@@ -1,5 +1,6 @@
 /*
- * Copright 2010 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
  *		at Electronni Visti IA, Kiev, Ukraine.
  *			All rights reserved.
@@ -44,7 +45,6 @@
 
 #include "collate.h"
 #include "setlocale.h"
-#include "ldpart.h"
 
 /*
  * See the comments in usr/src/cmd/localedef/collate.c for further
@@ -53,21 +53,22 @@
  * handy (www.opengroup.org).
  */
 
-static collate_subst_t		*subst_table[COLL_WEIGHTS_MAX];
-static collate_char_t		*char_pri_table;
-static collate_large_t		*large_pri_table;
-static collate_chain_t		*chain_pri_table;
-static char			*cache = NULL;
-static size_t			cachesz;
-static char			collate_encoding[ENCODING_LEN + 1];
+/*
+ * POSIX uses empty tables and falls down to strcmp.
+ */
+struct lc_collate lc_collate_posix = {
+	.lc_is_posix = 1,
+};
 
-/* Exposed externally to other parts of libc. */
-collate_info_t			*_collate_info;
-int _collate_load_error = 1;
+struct locdata __posix_collate_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_collate_posix }
+};
 
 
-int
-_collate_load_tables(const char *encoding)
+struct locdata *
+__lc_collate_load(const char *locname)
 {
 	int i, chains, z;
 	char buf[PATH_MAX];
@@ -76,49 +77,41 @@
 	collate_info_t *info;
 	struct stat sbuf;
 	int fd;
+	struct locdata *ldata;
+	struct lc_collate *lcc;
 
-	/* 'encoding' must be already checked. */
-	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
-		_collate_load_error = 1;
-		return (_LDP_CACHE);
-	}
-
 	/*
-	 * If the locale name is the same as our cache, use the cache.
-	 */
-	if (cache && (strncmp(encoding, collate_encoding, ENCODING_LEN) == 0)) {
-		_collate_load_error = 0;
-		return (_LDP_CACHE);
-	}
-
-	/*
 	 * Slurp the locale file into the cache.
 	 */
 
 	(void) snprintf(buf, sizeof (buf), "%s/%s/LC_COLLATE/LCL_DATA",
-	    _PathLocale, encoding);
+	    _PathLocale, locname);
 
-	if ((fd = open(buf, O_RDONLY)) < 0)
-		return (_LDP_ERROR);
+	if ((fd = open(buf, O_RDONLY)) < 0) {
+		errno = EINVAL;
+		return (NULL);
+	}
 	if (fstat(fd, &sbuf) < 0) {
 		(void) close(fd);
-		return (_LDP_ERROR);
+		errno = EINVAL;
+		return (NULL);
 	}
 	if (sbuf.st_size < (COLLATE_STR_LEN + sizeof (info))) {
 		(void) close(fd);
 		errno = EINVAL;
-		return (_LDP_ERROR);
+		return (NULL);
 	}
 	map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 	(void) close(fd);
 	if ((TMP = map) == NULL) {
-		return (_LDP_ERROR);
+		errno = EINVAL;
+		return (NULL);
 	}
 
 	if (strncmp(TMP, COLLATE_VERSION, COLLATE_STR_LEN) != 0) {
 		(void) munmap(map, sbuf.st_size);
 		errno = EINVAL;
-		return (_LDP_ERROR);
+		return (NULL);
 	}
 	TMP += COLLATE_STR_LEN;
 
@@ -130,72 +123,84 @@
 	    ((chains = info->chain_count) < 0)) {
 		(void) munmap(map, sbuf.st_size);
 		errno = EINVAL;
-		return (_LDP_ERROR);
+		return (NULL);
 	}
 
 	i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
 	    (sizeof (collate_chain_t) * chains) +
 	    (sizeof (collate_large_t) * info->large_count);
-	for (z = 0; z < (info->directive_count); z++) {
+	for (z = 0; z < info->directive_count; z++) {
 		i += sizeof (collate_subst_t) * info->subst_count[z];
 	}
 	if (i != (sbuf.st_size - (TMP - map))) {
 		(void) munmap(map, sbuf.st_size);
 		errno = EINVAL;
-		return (_LDP_ERROR);
+		return (NULL);
 	}
 
-	char_pri_table = (void *)TMP;
+
+	if ((ldata = __locdata_alloc(locname, sizeof (*lcc))) == NULL) {
+		(void) munmap(map, sbuf.st_size);
+		return (NULL);
+	}
+	lcc = ldata->l_data[0];
+	ldata->l_map = map;
+	ldata->l_map_len = sbuf.st_size;
+
+	lcc->lc_info = info;
+	lcc->lc_directive_count = info->directive_count;
+	lcc->lc_large_count = info->large_count;
+
+	for (z = 0; z < COLL_WEIGHTS_MAX; z++) {
+		lcc->lc_directive[z] = info->directive[z];
+		lcc->lc_subst_count[z] = info->subst_count[z];
+		lcc->lc_pri_count[z] = info->pri_count[z];
+		lcc->lc_undef_pri[z] = info->undef_pri[z];
+	}
+
+	lcc->lc_char_table = (void *)TMP;
 	TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
 
-	for (z = 0; z < info->directive_count; z++) {
-		if (info->subst_count[z] > 0) {
-			subst_table[z] = (void *)TMP;
-			TMP += info->subst_count[z] * sizeof (collate_subst_t);
+	for (z = 0; z < lcc->lc_directive_count; z++) {
+		int count;
+		if ((count = lcc->lc_subst_count[z]) > 0) {
+			lcc->lc_subst_table[z] = (void *)TMP;
+			TMP += count * sizeof (collate_subst_t);
 		} else {
-			subst_table[z] = NULL;
+			lcc->lc_subst_table[z] = NULL;
 		}
 	}
 
 	if (chains > 0) {
-		chain_pri_table = (void *)TMP;
+		lcc->lc_chain_table = (void *)TMP;
 		TMP += chains * sizeof (collate_chain_t);
 	} else
-		chain_pri_table = NULL;
-	if (info->large_count > 0)
-		large_pri_table = (void *)TMP;
+		lcc->lc_chain_table = NULL;
+	lcc->lc_chain_count = chains;
+	if (lcc->lc_large_count > 0)
+		lcc->lc_large_table = (void *)TMP;
 	else
-		large_pri_table = NULL;
+		lcc->lc_large_table = NULL;
 
-	(void) strlcpy(collate_encoding, encoding, ENCODING_LEN);
-	_collate_info = info;
-
-	if (cache)
-		(void) munmap(cache, cachesz);
-
-	cache = map;
-	cachesz = sbuf.st_size;
-	_collate_load_error = 0;
-
-	return (_LDP_LOADED);
+	return (ldata);
 }
 
-static int32_t *
-substsearch(const wchar_t key, int pass)
+static const int32_t *
+substsearch(const struct lc_collate *lcc, const wchar_t key, int pass)
 {
-	collate_subst_t *p;
-	int n = _collate_info->subst_count[pass];
+	const collate_subst_t *p;
+	int n = lcc->lc_subst_count[pass];
 
 	if (n == 0)
 		return (NULL);
 
-	if (pass >= _collate_info->directive_count)
+	if (pass >= lcc->lc_directive_count)
 		return (NULL);
 
 	if (!(key & COLLATE_SUBST_PRIORITY))
 		return (NULL);
 
-	p = subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
+	p = lcc->lc_subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
 	assert(p->key == key);
 	return (p->pri);
 }
@@ -206,7 +211,7 @@
  */
 
 static collate_chain_t *
-chainsearch(const wchar_t *key, int *len)
+chainsearch(const struct lc_collate *lcc, const wchar_t *key, int *len)
 {
 	int low;
 	int high;
@@ -214,12 +219,12 @@
 	collate_chain_t *p;
 	collate_chain_t *tab;
 
-	if (_collate_info->chain_count == 0)
+	if (lcc->lc_info->chain_count == 0)
 		return (NULL);
 
 	low = 0;
-	high = _collate_info->chain_count - 1;
-	tab = chain_pri_table;
+	high = lcc->lc_info->chain_count - 1;
+	tab = lcc->lc_chain_table;
 
 	while (low <= high) {
 		next = (low + high) / 2;
@@ -242,15 +247,15 @@
 }
 
 static collate_large_t *
-largesearch(const wchar_t key)
+largesearch(const struct lc_collate *lcc, const wchar_t key)
 {
 	int low = 0;
-	int high = _collate_info->large_count - 1;
+	int high = lcc->lc_info->large_count - 1;
 	int next, compar;
 	collate_large_t *p;
-	collate_large_t *tab = large_pri_table;
+	collate_large_t *tab = lcc->lc_large_table;
 
-	if (_collate_info->large_count == 0)
+	if (lcc->lc_info->large_count == 0)
 		return (NULL);
 
 	while (low <= high) {
@@ -268,19 +273,19 @@
 }
 
 void
-_collate_lookup(const wchar_t *t, int *len, int *pri, int which, int **state)
+_collate_lookup(const struct lc_collate *lcc, const wchar_t *t,
+    int *len, int *pri, int which, const int **state)
 {
 	collate_chain_t *p2;
 	collate_large_t *match;
-	collate_info_t *info = _collate_info;
 	int p, l;
-	int *sptr;
+	const int *sptr;
 
 	/*
 	 * If this is the "last" pass for the UNDEFINED, then
 	 * we just return the priority itself.
 	 */
-	if (which >= info->directive_count) {
+	if (which >= lcc->lc_directive_count) {
 		*pri = *t;
 		*len = 1;
 		*state = NULL;
@@ -306,7 +311,7 @@
 	 * Check for composites such as dipthongs that collate as a
 	 * single element (aka chains or collating-elements).
 	 */
-	if (((p2 = chainsearch(t, &l)) != NULL) &&
+	if (((p2 = chainsearch(lcc, t, &l)) != NULL) &&
 	    ((p = p2->pri[which]) >= 0)) {
 
 		*len = l;
@@ -318,10 +323,10 @@
 		 * Character is a small (8-bit) character.
 		 * We just look these up directly for speed.
 		 */
-		*pri = char_pri_table[*t].pri[which];
+		*pri = lcc->lc_char_table[*t].pri[which];
 
-	} else if ((info->large_count > 0) &&
-	    ((match = largesearch(*t)) != NULL)) {
+	} else if ((lcc->lc_info->large_count > 0) &&
+	    ((match = largesearch(lcc, *t)) != NULL)) {
 
 		/*
 		 * Character was found in the extended table.
@@ -332,11 +337,11 @@
 		/*
 		 * Character lacks a specific definition.
 		 */
-		if (info->directive[which] & DIRECTIVE_UNDEFINED) {
+		if (lcc->lc_directive[which] & DIRECTIVE_UNDEFINED) {
 			/* Mask off sign bit to prevent ordering confusion. */
 			*pri = (*t & COLLATE_MAX_PRIORITY);
 		} else {
-			*pri = info->undef_pri[which];
+			*pri = lcc->lc_undef_pri[which];
 		}
 		/* No substitutions for undefined characters! */
 		return;
@@ -354,7 +359,7 @@
 	 * to be substituted be unique for that level.  The localedef
 	 * code ensures this for us.
 	 */
-	if ((sptr = substsearch(*pri, which)) != NULL) {
+	if ((sptr = substsearch(lcc, *pri, which)) != NULL) {
 		if ((*pri = *sptr) != 0) {
 			sptr++;
 			*state = *sptr ? sptr : NULL;
@@ -368,7 +373,8 @@
  * NOT NULL terminate.  That is left to the caller.
  */
 size_t
-_collate_wxfrm(const wchar_t *src, wchar_t *xf, size_t room)
+_collate_wxfrm(const struct lc_collate *lcc, const wchar_t *src, wchar_t *xf,
+    size_t room)
 {
 	int		pri;
 	int		len;
@@ -376,13 +382,14 @@
 	wchar_t		*tr = NULL;
 	int		direc;
 	int		pass;
-	int32_t 	*state;
+	const int32_t 	*state;
 	size_t		want = 0;
 	size_t		need = 0;
+	int		ndir = lcc->lc_directive_count;
 
 	assert(src);
 
-	for (pass = 0; pass <= _collate_info->directive_count; pass++) {
+	for (pass = 0; pass <= ndir; pass++) {
 
 		state = NULL;
 
@@ -396,10 +403,10 @@
 		}
 
 		/* special pass for undefined */
-		if (pass == _collate_info->directive_count) {
+		if (pass == ndir) {
 			direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
 		} else {
-			direc = _collate_info->directive[pass];
+			direc = lcc->lc_directive[pass];
 		}
 
 		t = src;
@@ -424,7 +431,8 @@
 
 		if (direc & DIRECTIVE_POSITION) {
 			while (*t || state) {
-				_collate_lookup(t, &len, &pri, pass, &state);
+				_collate_lookup(lcc, t, &len, &pri, pass,
+				    &state);
 				t += len;
 				if (pri <= 0) {
 					if (pri < 0) {
@@ -442,7 +450,8 @@
 			}
 		} else {
 			while (*t || state) {
-				_collate_lookup(t, &len, &pri, pass, &state);
+				_collate_lookup(lcc, t, &len, &pri, pass,
+				    &state);
 				t += len;
 				if (pri <= 0) {
 					if (pri < 0) {
@@ -497,10 +506,10 @@
 #define	XFRM_SEP	('.')	/* chosen to be less than XFRM_OFFSET */
 
 static int
-xfrm(unsigned char *p, int pri, int pass)
+xfrm(locale_t loc, unsigned char *p, int pri, int pass)
 {
 	/* we use unsigned to ensure zero fill on right shift */
-	uint32_t val = (uint32_t)_collate_info->pri_count[pass];
+	uint32_t val = (uint32_t)loc->collate->lc_pri_count[pass];
 	int nc = 0;
 
 	while (val) {
@@ -514,7 +523,7 @@
 }
 
 size_t
-_collate_sxfrm(const wchar_t *src, char *xf, size_t room)
+_collate_sxfrm(const wchar_t *src, char *xf, size_t room, locale_t loc)
 {
 	int		pri;
 	int		len;
@@ -522,15 +531,17 @@
 	wchar_t		*tr = NULL;
 	int		direc;
 	int		pass;
-	int32_t 	*state;
+	const int32_t 	*state;
 	size_t		want = 0;
 	size_t		need = 0;
 	int		b;
 	uint8_t		buf[XFRM_BYTES];
+	const struct lc_collate *lcc = loc->collate;
+	int		ndir = lcc->lc_directive_count;
 
 	assert(src);
 
-	for (pass = 0; pass <= _collate_info->directive_count; pass++) {
+	for (pass = 0; pass <= ndir; pass++) {
 
 		state = NULL;
 
@@ -544,10 +555,10 @@
 		}
 
 		/* special pass for undefined */
-		if (pass == _collate_info->directive_count) {
+		if (pass == ndir) {
 			direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
 		} else {
-			direc = _collate_info->directive[pass];
+			direc = lcc->lc_directive[pass];
 		}
 
 		t = src;
@@ -573,7 +584,8 @@
 		if (direc & DIRECTIVE_POSITION) {
 			while (*t || state) {
 
-				_collate_lookup(t, &len, &pri, pass, &state);
+				_collate_lookup(lcc, t, &len, &pri, pass,
+				    &state);
 				t += len;
 				if (pri <= 0) {
 					if (pri < 0) {
@@ -583,7 +595,7 @@
 					pri = COLLATE_MAX_PRIORITY;
 				}
 
-				b = xfrm(buf, pri, pass);
+				b = xfrm(loc, buf, pri, pass);
 				want += b;
 				if (room) {
 					while (b) {
@@ -598,7 +610,8 @@
 			}
 		} else {
 			while (*t || state) {
-				_collate_lookup(t, &len, &pri, pass, &state);
+				_collate_lookup(lcc, t, &len, &pri, pass,
+				    &state);
 				t += len;
 				if (pri <= 0) {
 					if (pri < 0) {
@@ -608,7 +621,7 @@
 					continue;
 				}
 
-				b = xfrm(buf, pri, pass);
+				b = xfrm(loc, buf, pri, pass);
 				want += b;
 				if (room) {
 
--- old/usr/src/lib/libc/port/locale/collate.h	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/collate.h	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systmes, Inc.  All rights reserved.
  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
  *		at Electronni Visti IA, Kiev, Ukraine.
@@ -31,6 +32,8 @@
 
 #include <sys/types.h>
 #include <limits.h>
+#include <locale.h>
+#include "localeimpl.h"
 
 #define	COLLATE_STR_LEN		24		/* should be 64-bit multiple */
 #define	COLLATE_VERSION		"IllumosCollate2\n"
@@ -92,14 +95,30 @@
 	int32_t pri[COLLATE_STR_LEN];
 } collate_subst_t;
 
-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);
-size_t	_collate_sxfrm(const wchar_t *, char *, size_t);
-int	_collate_range_cmp(wchar_t, wchar_t);
+struct lc_collate {
+	int		lc_is_posix;
 
-extern int _collate_load_error;
-extern int _collate_substitute_nontrivial;
-extern collate_info_t *_collate_info;
+	uint8_t		lc_directive_count;
+	uint8_t		lc_directive[COLL_WEIGHTS_MAX];
+	int32_t		lc_pri_count[COLL_WEIGHTS_MAX];
+	int32_t		lc_flags;
+	int32_t		lc_chain_count;
+	int32_t		lc_large_count;
+	int32_t		lc_subst_count[COLL_WEIGHTS_MAX];
+	int32_t		lc_undef_pri[COLL_WEIGHTS_MAX];
 
+	collate_info_t	*lc_info;
+	collate_char_t	*lc_char_table;
+	collate_large_t	*lc_large_table;
+	collate_chain_t	*lc_chain_table;
+	collate_subst_t	*lc_subst_table[COLL_WEIGHTS_MAX];
+};
+
+void	_collate_lookup(const struct lc_collate *, const wchar_t *,
+    int *, int *, int, const int **);
+size_t	_collate_wxfrm(const struct lc_collate *, const wchar_t *,
+    wchar_t *, size_t);
+size_t	_collate_sxfrm(const wchar_t *, char *, size_t, locale_t);
+int	_collate_range_cmp(wchar_t, wchar_t, locale_t);
+
 #endif /* !_COLLATE_H_ */
--- old/usr/src/lib/libc/port/locale/collcmp.c	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/collcmp.c	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
  * All rights reserved.
  *
@@ -30,15 +31,17 @@
 #include "collate.h"
 
 /*
- * Compare two characters using collate
+ * Compare two characters using collate - thread safe.
  */
 
 int
-_collate_range_cmp(wchar_t c1, wchar_t c2)
+_collate_range_cmp(wchar_t c1, wchar_t c2, locale_t loc)
 {
-	static wchar_t s1[2], s2[2];
+	wchar_t s1[2], s2[2];
 
 	s1[0] = c1;
+	s1[1] = 0;
 	s2[0] = c2;
-	return (wcscoll(s1, s2));
+	s2[1] = 0;
+	return (wcscoll_l(s1, s2, loc));
 }
--- old/usr/src/lib/libc/port/locale/euc.c	Tue May 20 07:58:46 2014
+++ new/usr/src/lib/libc/port/locale/euc.c	Tue May 20 07:58:46 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
  * Copyright (c) 1993
@@ -40,8 +41,8 @@
 #include <wchar.h>
 #include <sys/types.h>
 #include <sys/euc.h>
-#include "runetype.h"
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD,
     const char *_RESTRICT_KYWD,
@@ -61,6 +62,7 @@
 static size_t	_EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
 		    size_t, mbstate_t *_RESTRICT_KYWD);
+
 static size_t	_EUC_CN_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
 static size_t	_EUC_JP_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
@@ -69,6 +71,33 @@
 		    mbstate_t *_RESTRICT_KYWD);
 static size_t	_EUC_TW_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+
+static size_t	_EUC_CN_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_JP_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_KR_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_TW_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+
+static size_t	_EUC_CN_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_JP_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_KR_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+
 static int	_EUC_mbsinit(const mbstate_t *);
 
 typedef struct {
@@ -77,7 +106,7 @@
 	int	want;
 } _EucState;
 
-static int
+int
 _EUC_mbsinit(const mbstate_t *ps)
 {
 
@@ -87,18 +116,17 @@
 /*
  * EUC-CN uses CS0, CS1 and CS2 (4 bytes).
  */
-int
-_EUC_CN_init(_RuneLocale *rl)
+void
+_EUC_CN_init(struct lc_ctype *lct)
 {
-	__mbrtowc = _EUC_CN_mbrtowc;
-	__wcrtomb = _EUC_CN_wcrtomb;
-	__mbsinit = _EUC_mbsinit;
+	lct->lc_mbrtowc = _EUC_CN_mbrtowc;
+	lct->lc_wcrtomb = _EUC_CN_wcrtomb;
+	lct->lc_mbsnrtowcs = _EUC_CN_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _EUC_CN_wcsnrtombs;
+	lct->lc_mbsinit = _EUC_mbsinit;
 
-	_CurrentRuneLocale = rl;
-
-	__ctype[520] = 4;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_max_mblen = 4;
+	lct->lc_is_ascii = 0;
 }
 
 static size_t
@@ -109,6 +137,14 @@
 }
 
 static size_t
+_EUC_CN_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_CN_mbrtowc));
+}
+
+static size_t
 _EUC_CN_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
     mbstate_t *_RESTRICT_KYWD ps)
 {
@@ -115,21 +151,27 @@
 	return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
 }
 
+static size_t
+_EUC_CN_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+	size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_CN_wcrtomb));
+}
+
 /*
  * EUC-KR uses only CS0 and CS1.
  */
-int
-_EUC_KR_init(_RuneLocale *rl)
+void
+_EUC_KR_init(struct lc_ctype *lct)
 {
-	__mbrtowc = _EUC_KR_mbrtowc;
-	__wcrtomb = _EUC_KR_wcrtomb;
-	__mbsinit = _EUC_mbsinit;
+	lct->lc_mbrtowc = _EUC_KR_mbrtowc;
+	lct->lc_wcrtomb = _EUC_KR_wcrtomb;
+	lct->lc_mbsnrtowcs = _EUC_KR_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _EUC_KR_wcsnrtombs;
+	lct->lc_mbsinit = _EUC_mbsinit;
 
-	_CurrentRuneLocale = rl;
-
-	__ctype[520] = 2;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_max_mblen = 2;
+	lct->lc_is_ascii = 0;
 }
 
 static size_t
@@ -140,27 +182,41 @@
 }
 
 static size_t
+_EUC_KR_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_KR_mbrtowc));
+}
+
+static size_t
 _EUC_KR_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
-    mbstate_t *_RESTRICT_KYWD ps)
+	mbstate_t *_RESTRICT_KYWD ps)
 {
 	return (_EUC_wcrtomb_impl(s, wc, ps, 0, 0, 0, 0));
 }
 
+static size_t
+_EUC_KR_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+	size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_KR_wcrtomb));
+}
+
 /*
  * EUC-JP uses CS0, CS1, CS2, and CS3.
  */
-int
-_EUC_JP_init(_RuneLocale *rl)
+void
+_EUC_JP_init(struct lc_ctype *lct)
 {
-	__mbrtowc = _EUC_JP_mbrtowc;
-	__wcrtomb = _EUC_JP_wcrtomb;
-	__mbsinit = _EUC_mbsinit;
+	lct->lc_mbrtowc = _EUC_JP_mbrtowc;
+	lct->lc_wcrtomb = _EUC_JP_wcrtomb;
+	lct->lc_mbsnrtowcs = _EUC_JP_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _EUC_JP_wcsnrtombs;
+	lct->lc_mbsinit = _EUC_mbsinit;
 
-	_CurrentRuneLocale = rl;
-
-	__ctype[520] = 3;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_max_mblen = 3;
+	lct->lc_is_ascii = 0;
 }
 
 static size_t
@@ -171,6 +227,14 @@
 }
 
 static size_t
+_EUC_JP_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_JP_mbrtowc));
+}
+
+static size_t
 _EUC_JP_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
     mbstate_t *_RESTRICT_KYWD ps)
 {
@@ -177,37 +241,58 @@
 	return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 2, SS3, 3));
 }
 
+static size_t
+_EUC_JP_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+	size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_JP_wcrtomb));
+}
+
 /*
  * EUC-TW uses CS0, CS1, and CS2.
  */
-int
-_EUC_TW_init(_RuneLocale *rl)
+void
+_EUC_TW_init(struct lc_ctype *lct)
 {
-	__mbrtowc = _EUC_TW_mbrtowc;
-	__wcrtomb = _EUC_TW_wcrtomb;
-	__mbsinit = _EUC_mbsinit;
+	lct->lc_mbrtowc = _EUC_TW_mbrtowc;
+	lct->lc_wcrtomb = _EUC_TW_wcrtomb;
+	lct->lc_mbsnrtowcs = _EUC_TW_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _EUC_TW_wcsnrtombs;
+	lct->lc_mbsinit = _EUC_mbsinit;
 
-	_CurrentRuneLocale = rl;
-
-	__ctype[520] = 4;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_max_mblen = 4;
+	lct->lc_is_ascii = 0;
 }
 
 static size_t
 _EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
-    size_t n, mbstate_t *_RESTRICT_KYWD ps)
+	size_t n, mbstate_t *_RESTRICT_KYWD ps)
 {
 	return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
 }
 
 static size_t
+_EUC_TW_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+	const char **_RESTRICT_KYWD src,
+	size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_TW_mbrtowc));
+}
+
+static size_t
 _EUC_TW_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
-    mbstate_t *_RESTRICT_KYWD ps)
+	mbstate_t *_RESTRICT_KYWD ps)
 {
 	return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
 }
 
+static size_t
+_EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+	size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_TW_wcrtomb));
+}
+
 /*
  * Common EUC code.
  */
@@ -214,8 +299,8 @@
 
 static size_t
 _EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
-    size_t n, mbstate_t *_RESTRICT_KYWD ps,
-    uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
+	size_t n, mbstate_t *_RESTRICT_KYWD ps,
+	uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
 {
 	_EucState *es;
 	int i, want;
--- old/usr/src/lib/libc/port/locale/fgetwc.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/fgetwc.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -35,22 +36,26 @@
 #include <wchar.h>
 #include "mblocal.h"
 #include "stdiom.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 /*
  * Non-MT-safe version.
  */
 wint_t
-_fgetwc_unlocked(FILE *fp)
+_fgetwc_unlocked_l(FILE *fp, locale_t loc)
 {
 	wchar_t wc;
 	size_t nconv;
 	int	c;
 	mbstate_t	*statep;
+	const struct lc_ctype *lct;
 
 	if ((c = GETC(fp)) == EOF)
 		return (WEOF);
 
-	if (MB_CUR_MAX == 1) {
+	lct = loc->ctype;
+	if (lct->lc_max_mblen == 1) {
 		/* Fast path for single-byte encodings. */
 		return ((wint_t)c);
 	}
@@ -61,7 +66,7 @@
 	}
 	do {
 		char	x = (char)c;
-		nconv = __mbrtowc(&wc, &x, 1, statep);
+		nconv = lct->lc_mbrtowc(&wc, &x, 1, statep);
 		if (nconv == (size_t)-1) {
 			break;
 		} else if (nconv == (size_t)-2) {
@@ -89,51 +94,64 @@
 	return (WEOF);
 }
 
+wint_t
+_fgetwc_unlocked(FILE *fp)
+{
+	return (_fgetwc_unlocked_l(fp, uselocale(NULL)));
+}
 
+
 /*
  * MT safe version
  */
+#undef getwc
+#pragma weak getwc = fgetwc
 wint_t
 fgetwc(FILE *fp)
 {
 	wint_t		r;
 	rmutex_t	*l;
+	locale_t	loc = uselocale(NULL);
 
 	FLOCKFILE(l, fp);
-	r = _fgetwc_unlocked(fp);
+	r = _fgetwc_unlocked_l(fp, loc);
 	FUNLOCKFILE(l);
 
 	return (r);
 }
 
-#undef	getwc
-wint_t
-getwc(FILE *fp)
-{
-	return (getwc(fp));
-}
-
 /*
  * XPG5 version.
  */
+#undef	__getwc_xpg5
+#pragma weak __getwc_xpg5 = __fgetwc_xpg5
 wint_t
 __fgetwc_xpg5(FILE *fp)
 {
 	wint_t		r;
 	rmutex_t	*l;
+	locale_t	loc = uselocale(NULL);
 
 	FLOCKFILE(l, fp);
 	if (GET_NO_MODE(fp))
 		_setorientation(fp, _WC_MODE);
-	r = _fgetwc_unlocked(fp);
+	r = _fgetwc_unlocked_l(fp, loc);
 	FUNLOCKFILE(l);
 
 	return (r);
 }
 
-#undef	__getwc_xpg5
+#pragma weak getwc_l = fgetwc_l
 wint_t
-__getwc_xpg5(FILE *fp)
+fgetwc_l(FILE *fp, locale_t loc)
 {
-	return (__fgetwc_xpg5(fp));
+	wint_t		r;
+	rmutex_t	*l;
+	FLOCKFILE(l, fp);
+	if (GET_NO_MODE(fp))
+		_setorientation(fp, _WC_MODE);
+	r = _fgetwc_unlocked_l(fp, loc);
+	FUNLOCKFILE(l);
+
+	return (r);
 }
--- old/usr/src/lib/libc/port/locale/fnmatch.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/fnmatch.c	Tue May 20 07:58:47 2014
@@ -31,6 +31,7 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -56,8 +57,9 @@
 #include <limits.h>
 #include <string.h>
 #include <wchar.h>
+#include <xlocale.h>
 #include <wctype.h>
-
+#include "localeimpl.h"
 #include "collate.h"
 
 #define	EOS	'\0'
@@ -66,9 +68,10 @@
 #define	RANGE_NOMATCH	0
 #define	RANGE_ERROR	(-1)
 
-static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
+static int rangematch(const char *, wchar_t, int, char **, mbstate_t *,
+    locale_t);
 static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
-    mbstate_t);
+    mbstate_t, locale_t);
 
 int
 fnmatch(pattern, string, flags)
@@ -75,14 +78,16 @@
 	const char *pattern, *string;
 	int flags;
 {
+	locale_t loc = uselocale(NULL);
 	static const mbstate_t initial = { 0 };
 
-	return (fnmatch1(pattern, string, string, flags, initial, initial));
+	return (fnmatch1(pattern, string, string, flags, initial, initial,
+	    loc));
 }
 
 static int
 fnmatch1(const char *pattern, const char *string, const char *stringstart,
-    int flags, mbstate_t patmbs, mbstate_t strmbs)
+    int flags, mbstate_t patmbs, mbstate_t strmbs, locale_t loc)
 {
 	char *newp;
 	char c;
@@ -90,11 +95,11 @@
 	size_t pclen, sclen;
 
 	for (;;) {
-		pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
+		pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX, &patmbs, loc);
 		if (pclen == (size_t)-1 || pclen == (size_t)-2)
 			return (FNM_NOMATCH);
 		pattern += pclen;
-		sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs);
+		sclen = mbrtowc_l(&sc, string, MB_LEN_MAX, &strmbs, loc);
 		if (sclen == (size_t)-1 || sclen == (size_t)-2) {
 			sc = (unsigned char)*string;
 			sclen = 1;
@@ -145,10 +150,10 @@
 			/* General case, use recursion. */
 			while (sc != EOS) {
 				if (!fnmatch1(pattern, string, stringstart,
-				    flags, patmbs, strmbs))
+				    flags, patmbs, strmbs, loc))
 					return (0);
-				sclen = mbrtowc(&sc, string, MB_LEN_MAX,
-				    &strmbs);
+				sclen = mbrtowc_l(&sc, string, MB_LEN_MAX,
+				    &strmbs, loc);
 				if (sclen == (size_t)-1 ||
 				    sclen == (size_t)-2) {
 					sc = (unsigned char)*string;
@@ -172,7 +177,7 @@
 				return (FNM_NOMATCH);
 
 			switch (rangematch(pattern, sc, flags, &newp,
-			    &patmbs)) {
+			    &patmbs, loc)) {
 			case RANGE_ERROR:
 				goto norm;
 			case RANGE_MATCH:
@@ -185,8 +190,8 @@
 			break;
 		case '\\':
 			if (!(flags & FNM_NOESCAPE)) {
-				pclen = mbrtowc(&pc, pattern, MB_LEN_MAX,
-				    &patmbs);
+				pclen = mbrtowc_l(&pc, pattern, MB_LEN_MAX,
+				    &patmbs, loc);
 				if (pclen == (size_t)-1 || pclen == (size_t)-2)
 					return (FNM_NOMATCH);
 				if (pclen == 0)
@@ -200,7 +205,7 @@
 				string += sclen;
 
 			else if ((flags & FNM_IGNORECASE) &&
-			    (towlower(pc) == towlower(sc)))
+			    (towlower_l(pc, loc) == towlower_l(sc, loc)))
 				string += sclen;
 			else
 				return (FNM_NOMATCH);
@@ -212,12 +217,8 @@
 }
 
 static int
-rangematch(pattern, test, flags, newp, patmbs)
-	const char *pattern;
-	wchar_t test;
-	int flags;
-	char **newp;
-	mbstate_t *patmbs;
+rangematch(const char *pattern, wchar_t test, int flags, char **newp,
+    mbstate_t *patmbs, locale_t loc)
 {
 	int negate, ok;
 	wchar_t c, c2;
@@ -235,7 +236,7 @@
 		++pattern;
 
 	if (flags & FNM_IGNORECASE)
-		test = towlower(test);
+		test = towlower_l(test, loc);
 
 	/*
 	 * A right bracket shall lose its special meaning and represent
@@ -254,13 +255,13 @@
 			return (RANGE_NOMATCH);
 		} else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
 			pattern++;
-		pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
+		pclen = mbrtowc_l(&c, pattern, MB_LEN_MAX, patmbs, loc);
 		if (pclen == (size_t)-1 || pclen == (size_t)-2)
 			return (RANGE_NOMATCH);
 		pattern += pclen;
 
 		if (flags & FNM_IGNORECASE)
-			c = towlower(c);
+			c = towlower_l(c, loc);
 
 		if (*pattern == '-' && *(pattern + 1) != EOS &&
 		    *(pattern + 1) != ']') {
@@ -267,7 +268,8 @@
 			if (*++pattern == '\\' && !(flags & FNM_NOESCAPE))
 				if (*pattern != EOS)
 					pattern++;
-			pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs);
+			pclen = mbrtowc_l(&c2, pattern, MB_LEN_MAX, patmbs,
+			    loc);
 			if (pclen == (size_t)-1 || pclen == (size_t)-2)
 				return (RANGE_NOMATCH);
 			pattern += pclen;
@@ -275,12 +277,12 @@
 				return (RANGE_ERROR);
 
 			if (flags & FNM_IGNORECASE)
-				c2 = towlower(c2);
+				c2 = towlower_l(c2, loc);
 
-			if (_collate_load_error ?
+			if (loc->collate->lc_is_posix ?
 			    c <= test && test <= c2 :
-			    _collate_range_cmp(c, test) <= 0 &&
-			    _collate_range_cmp(test, c2) <= 0)
+			    _collate_range_cmp(c, test, loc) <= 0 &&
+			    _collate_range_cmp(test, c2, loc) <= 0)
 				ok = 1;
 		} else if (c == test)
 			ok = 1;
--- old/usr/src/lib/libc/port/locale/fputwc.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/fputwc.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
  *
@@ -72,8 +73,6 @@
 	if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
 		/*
 		 * Assume single-byte locale with no special encoding.
-		 * A more careful test would be to check
-		 * _CurrentRuneLocale->encoding.
 		 */
 		*buf = (unsigned char)wc;
 		len = 1;
--- old/usr/src/lib/libc/port/locale/gb18030.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/gb18030.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins
  * All rights reserved.
@@ -34,11 +35,11 @@
 #include "lint.h"
 #include <sys/types.h>
 #include <errno.h>
-#include "runetype.h"
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 
 static size_t	_GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD,
@@ -47,24 +48,30 @@
 static int	_GB18030_mbsinit(const mbstate_t *);
 static size_t	_GB18030_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GB18030_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
 
+
 typedef struct {
 	int	count;
 	uchar_t	bytes[4];
 } _GB18030State;
 
-int
-_GB18030_init(_RuneLocale *rl)
+void
+_GB18030_init(struct lc_ctype *lct)
 {
 
-	__mbrtowc = _GB18030_mbrtowc;
-	__wcrtomb = _GB18030_wcrtomb;
-	__mbsinit = _GB18030_mbsinit;
-	_CurrentRuneLocale = rl;
-	__ctype[520] = 4;
-	charset_is_ascii = 0;
-
-	return (0);
+	lct->lc_mbrtowc = _GB18030_mbrtowc;
+	lct->lc_wcrtomb = _GB18030_wcrtomb;
+	lct->lc_mbsinit = _GB18030_mbsinit;
+	lct->lc_mbsnrtowcs = _GB18030_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _GB18030_wcsnrtombs;
+	lct->lc_max_mblen = 4;
+	lct->lc_is_ascii = 0;
 }
 
 static int
@@ -220,4 +227,20 @@
 ilseq:
 	errno = EILSEQ;
 	return ((size_t)-1);
+}
+
+static size_t
+_GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+    mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB18030_mbrtowc));
+}
+
+static size_t
+_GB18030_wcsnrtombs(char *_RESTRICT_KYWD dst,
+    const wchar_t **_RESTRICT_KYWD src, size_t nwc, size_t len,
+    mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB18030_wcrtomb));
 }
--- old/usr/src/lib/libc/port/locale/gb2312.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/gb2312.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2004 Tim J. Robbins. All rights reserved.
  * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
@@ -34,6 +35,7 @@
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
@@ -41,23 +43,30 @@
 static int	_GB2312_mbsinit(const mbstate_t *);
 static size_t	_GB2312_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GB2312_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GB2312_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
 
+
 typedef struct {
 	int	count;
 	uchar_t	bytes[2];
 } _GB2312State;
 
-int
-_GB2312_init(_RuneLocale *rl)
+void
+_GB2312_init(struct lc_ctype *lct)
 {
 
-	_CurrentRuneLocale = rl;
-	__mbrtowc = _GB2312_mbrtowc;
-	__wcrtomb = _GB2312_wcrtomb;
-	__mbsinit = _GB2312_mbsinit;
-	__ctype[520] = 2;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_mbrtowc = _GB2312_mbrtowc;
+	lct->lc_wcrtomb = _GB2312_wcrtomb;
+	lct->lc_mbsinit = _GB2312_mbsinit;
+	lct->lc_mbsnrtowcs = _GB2312_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _GB2312_wcsnrtombs;
+	lct->lc_max_mblen = 2;
+	lct->lc_is_ascii = 0;
 }
 
 static int
@@ -154,4 +163,20 @@
 	}
 	*s = wc & 0xff;
 	return (1);
+}
+
+static size_t
+_GB2312_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+    mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB2312_mbrtowc));
+}
+
+static size_t
+_GB2312_wcsnrtombs(char *_RESTRICT_KYWD dst,
+    const wchar_t **_RESTRICT_KYWD src, size_t nwc, size_t len,
+    mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB2312_wcrtomb));
 }
--- old/usr/src/lib/libc/port/locale/gbk.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/gbk.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
  * Copyright (c) 1993
@@ -35,11 +36,11 @@
 #include "lint.h"
 #include <sys/types.h>
 #include <errno.h>
-#include "runetype.h"
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_GBK_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
@@ -47,22 +48,27 @@
 static int	_GBK_mbsinit(const mbstate_t *);
 static size_t	_GBK_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GBK_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_GBK_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
 
 typedef struct {
 	wchar_t	ch;
 } _GBKState;
 
-int
-_GBK_init(_RuneLocale *rl)
+void
+_GBK_init(struct lc_ctype *lct)
 {
-
-	__mbrtowc = _GBK_mbrtowc;
-	__wcrtomb = _GBK_wcrtomb;
-	__mbsinit = _GBK_mbsinit;
-	_CurrentRuneLocale = rl;
-	__ctype[520] = 2;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_mbrtowc = _GBK_mbrtowc;
+	lct->lc_wcrtomb = _GBK_wcrtomb;
+	lct->lc_mbsinit = _GBK_mbsinit;
+	lct->lc_mbsnrtowcs = _GBK_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _GBK_wcsnrtombs;
+	lct->lc_max_mblen = 2;
+	lct->lc_is_ascii = 0;
 }
 
 static int
@@ -163,4 +169,18 @@
 	}
 	*s = wc & 0xff;
 	return (1);
+}
+
+static size_t
+_GBK_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GBK_mbrtowc));
+}
+
+static size_t
+_GBK_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GBK_wcrtomb));
 }
--- /dev/null	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/isdigit.c	Tue May 20 07:58:47 2014
@@ -0,0 +1,91 @@
+/*
+ * 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 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*
+ * This file contains the implementation of various functional forms
+ * of the ctype tests, specifically the required by ISO C.  These are defined
+ * in the "C" (POSIX) locale.
+ */
+
+#include "lint.h"
+#include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "_ctype.h"
+#include "lctype.h"
+
+/*
+ * We are supplying functional forms, so make sure to suppress any macros
+ * we might have imported.
+ */
+
+/*
+ * Performance note: ASCII test is *much* faster, as we can avoid expensive
+ * function call overhead.  This is the hot case, so we try to do that
+ * whenever possible.  As far as we know, *every* encoding we support
+ * is a strict superset of ASCII.  So we can make things faster by trying
+ * ASCII first, and only then falling to locale specific checks.
+ */
+
+static int
+isctype_l(int c, int mask, locale_t loc)
+{
+	return ((unsigned)c > 255 ? 0 : (loc->ctype->lc_ctype_mask[c] & mask));
+}
+
+#define	ISTYPE_L(c, mask, loc)	\
+	(isascii(c) ? (__ctype_mask[c] & (mask)) : isctype_l(c, mask, loc))
+
+#define	ISTYPE(c, mask)	ISTYPE_L(c, mask, uselocale(NULL))
+
+#define	DEFN_ISTYPE(type, mask)		\
+int					\
+is##type##_l(int c, locale_t l)	\
+{					\
+	return (ISTYPE_L(c, mask, l));	\
+}					\
+					\
+int					\
+is##type(int c)				\
+{					\
+	return (ISTYPE(c, mask));	\
+}
+
+#undef	isblank
+#undef	isupper
+#undef	islower
+#undef	isdigit
+#undef	isxdigit
+#undef	isalpha
+#undef	isalnum
+#undef	isspace
+#undef	iscntrl
+#undef	isgraph
+#undef	ispunct
+#undef	isprint
+
+DEFN_ISTYPE(blank, _ISBLANK)
+DEFN_ISTYPE(upper, _ISUPPER)
+DEFN_ISTYPE(lower, _ISLOWER)
+DEFN_ISTYPE(digit, _ISDIGIT)
+DEFN_ISTYPE(xdigit, _ISXDIGIT)
+DEFN_ISTYPE(alpha, _ISALPHA)
+DEFN_ISTYPE(alnum, _ISALNUM)
+DEFN_ISTYPE(space, _ISSPACE)
+DEFN_ISTYPE(cntrl, _ISCNTRL)
+DEFN_ISTYPE(graph, _ISGRAPH)
+DEFN_ISTYPE(punct, _ISPUNCT)
+DEFN_ISTYPE(print, _ISPRINT)
--- old/usr/src/lib/libc/port/locale/iswctype.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/iswctype.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -38,44 +39,50 @@
 
 #include "lint.h"
 #include <wctype.h>
+#include <locale.h>
 #include "runefile.h"
 #include "runetype.h"
+#include "localeimpl.h"
 #include "_ctype.h"
 
 /*
- * We removed: iswascii, iswhexnumber, and iswnumber, as
- * these are not present on Solaris.  Note that the standard requires
- * iswascii to be a macro, so it is defined in our headers.
+ * Note that the standard requires iswascii to be a macro, so it is defined
+ * in our headers.
  *
- * We renamed (per Solaris) iswideogram, iswspecial, iswspecial to the
- * equivalent values without "w".  We added a new isnumber, that looks
- * for non-ASCII numbers.
+ * We aliased (per Solaris) iswideogram, iswspecial, iswspecial to the
+ * equivalent values without "w".  The Solaris specific function isenglish()
+ * is here, but does not get an isw* equivalent.
+ *
+ * Note that various code assumes that "numbers" (iswdigit, iswxdigit)
+ * only return true for characters in the portable set.  While the assumption
+ * is not technically correct, it turns out that for all of our locales this
+ * is true.  iswhexnumber is aliased to iswxdigit.
  */
 
 static int
-__istype(wint_t c, unsigned int f)
+__istype_l(locale_t loc, wint_t c, unsigned int f)
 {
 	unsigned int rt;
 
-	/* Fast path for single byte locales */
 	if (c < 0 || c >= _CACHED_RUNES)
-		rt =  ___runetype(c);
+		rt = __runetype(loc->runelocale, c);
 	else
-		rt = _CurrentRuneLocale->__runetype[c];
+		rt = loc->runelocale->__runetype[c];
 	return (rt & f);
 }
 
 static int
-__isctype(wint_t c, unsigned int f)
+__istype(wint_t c, unsigned int f)
 {
-	unsigned int rt;
+	return (__istype_l(uselocale(NULL), c, f));
+}
 
-	/* Fast path for single byte locales */
-	if (c < 0 || c >= _CACHED_RUNES)
-		return (0);
-	else
-		rt = _CurrentRuneLocale->__runetype[c];
-	return (rt & f);
+int
+iswctype_l(wint_t wc, wctype_t class, locale_t loc)
+{
+	if (iswascii(wc))
+		return (__ctype_mask[wc] & class);
+	return (__istype_l(loc, wc, class));
 }
 
 #undef iswctype
@@ -82,134 +89,83 @@
 int
 iswctype(wint_t wc, wctype_t class)
 {
+	/*
+	 * Note that we don't just call iswctype_l because we optimize for
+	 * the iswascii() case, so that most of the time we have no need to
+	 * call uselocale().
+	 */
+	if (iswascii(wc))
+		return (__ctype_mask[wc] & class);
 	return (__istype(wc, class));
 }
 
+/*
+ * This is a legacy version, baked into binaries.
+ */
 #undef _iswctype
 unsigned
 _iswctype(wchar_t wc, int class)
 {
+	if (iswascii(wc))
+		return (__ctype_mask[wc] & class);
 	return (__istype((wint_t)wc, (unsigned int)class));
 }
 
-#undef iswalnum
-int
-iswalnum(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_A|_CTYPE_D));
+#define	DEFN_ISWTYPE(type, mask)		\
+int						\
+isw##type##_l(wint_t wc, locale_t loc)		\
+{						\
+	return (iswascii(wc) ?			\
+		(__ctype_mask[wc] & (mask)) :	\
+		__istype_l(loc, wc, mask));	\
+}						\
+						\
+int						\
+isw##type(wint_t wc)				\
+{						\
+	return (iswascii(wc) ?			\
+		(__ctype_mask[wc] & (mask)) :	\
+		__istype(wc, mask));		\
 }
 
-#undef iswalpha
-int
-iswalpha(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_A));
-}
+/* kill off any macros */
+#undef	iswalnum
+#undef	iswalpha
+#undef	iswblank
 
-#undef iswblank
-int
-iswblank(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_B));
-}
+DEFN_ISWTYPE(alnum, _CTYPE_A|_CTYPE_D)
+DEFN_ISWTYPE(alpha, _CTYPE_A)
+DEFN_ISWTYPE(blank, _CTYPE_B)
+DEFN_ISWTYPE(cntrl, _CTYPE_C)
+DEFN_ISWTYPE(digit, _CTYPE_D)
+DEFN_ISWTYPE(graph, _CTYPE_D)
+DEFN_ISWTYPE(lower, _CTYPE_L)
+DEFN_ISWTYPE(upper, _CTYPE_U)
+DEFN_ISWTYPE(print, _CTYPE_R)
+DEFN_ISWTYPE(punct, _CTYPE_P)
+DEFN_ISWTYPE(space, _CTYPE_S)
+DEFN_ISWTYPE(xdigit, _CTYPE_X)
+DEFN_ISWTYPE(ideogram, _CTYPE_I)
+DEFN_ISWTYPE(phonogram, _CTYPE_Q)
+DEFN_ISWTYPE(special, _CTYPE_T)
+DEFN_ISWTYPE(number, _CTYPE_N)
 
-#undef iswcntrl
-int
-iswcntrl(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_C));
-}
 
-#undef iswdigit
-int
-iswdigit(wint_t wc)
-{
-	return (__isctype(wc, _CTYPE_D));
-}
+#undef iswhexnumber
+#pragma weak iswhexnumber = iswxdigit
+#pragma weak iswhexnumber_l = iswxdigit_l
 
-#undef iswgraph
-int
-iswgraph(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_G));
-}
-
 #undef isideogram
-int
-isideogram(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_I));
-}
+#pragma weak isideogram = iswideogram
 
-#undef iswlower
-int
-iswlower(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_L));
-}
-
 #undef isphonogram
-int
-isphonogram(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_Q));
-}
+#pragma weak isphonogram = iswphonogram
 
-#undef iswprint
-int
-iswprint(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_R));
-}
-
-#undef iswpunct
-int
-iswpunct(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_P));
-}
-
-#undef iswspace
-int
-iswspace(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_S));
-}
-
-#undef iswupper
-int
-iswupper(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_U));
-}
-
-#undef iswxdigit
-int
-iswxdigit(wint_t wc)
-{
-	return (__isctype(wc, _CTYPE_X));
-}
-
-#undef isenglish
-int
-isenglish(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_E));
-}
-
 #undef isspecial
-int
-isspecial(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_T));
-}
+#pragma weak isspecial = iswspecial
 
 #undef isnumber
-int
-isnumber(wint_t wc)
-{
-	return (__istype(wc, _CTYPE_N));
-}
+#pragma weak isnumber = iswnumber
 
 /*
  * FreeBSD has iswrune() for use by external programs, and this is used by
@@ -228,6 +184,21 @@
 	 * ctype values differently.  We can't do that (ctype is baked into
 	 * applications), but instead can just check if *any* bit is set in
 	 * the ctype.  Any bit being set indicates its a valid rune.
+	 *
+	 * NB: For ASCII all positions except NULL are runes.
 	 */
-	return (__istype(wc, 0xffffffffU));
+	return (wc == 0 ? 0 : iswascii(wc) ? 1 : __istype(wc, 0xffffffffU));
+}
+
+/*
+ * isenglish is a Solaris legacy.  No isw* equivalent.  Note that this most
+ * likely doesn't work, as the locale data we have doesn't include it.  It
+ * specifically is only valid for non-ASCII characters.  We're not sure this
+ * is in actual use in the wild.
+ */
+#undef isenglish
+int
+isenglish(wint_t wc)
+{
+	return (__istype(wc, _CTYPE_E));
 }
--- /dev/null	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/lctype.h	Tue May 20 07:58:47 2014
@@ -0,0 +1,66 @@
+/*
+ * 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 Garrett D'Amore <garrett@damore.org>
+ */
+
+#ifndef	_LCTYPE_H_
+#define	_LCTYPE_H_
+
+#include <wchar.h>
+
+/* private LC_CTYPE related structures */
+
+/* encoding callbacks */
+struct lc_ctype {
+
+	size_t (*lc_mbrtowc)(wchar_t *_RESTRICT_KYWD,
+	    const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+
+	int (*lc_mbsinit)(const mbstate_t *);
+
+	size_t (*lc_mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
+	    const char **_RESTRICT_KYWD, size_t, size_t,
+	    mbstate_t *_RESTRICT_KYWD);
+
+	size_t (*lc_wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
+	    mbstate_t *_RESTRICT_KYWD);
+
+	size_t (*lc_wcsnrtombs)(char *_RESTRICT_KYWD,
+	    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+	    mbstate_t *_RESTRICT_KYWD);
+
+	unsigned char lc_is_ascii;
+	unsigned char lc_max_mblen;
+
+	const int *lc_trans_upper;
+	const int *lc_trans_lower;
+	const unsigned *lc_ctype_mask;
+};
+
+/*
+ * Default implementation (C locale, i.e. ASCII).
+ */
+size_t	__mbrtowc_ascii(wchar_t *_RESTRICT_KYWD,
+    const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+int	__mbsinit_ascii(const mbstate_t *);
+size_t	__mbsnrtowcs_ascii(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src, size_t nms, size_t len,
+    mbstate_t *_RESTRICT_KYWD);
+size_t	__wcrtomb_ascii(char *_RESTRICT_KYWD, wchar_t,
+    mbstate_t *_RESTRICT_KYWD);
+size_t	__wcsnrtombs_ascii(char *_RESTRICT_KYWD,
+    const wchar_t **_RESTRICT_KYWD,
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+
+
+#endif /* !_LCTYPE_H_ */
--- old/usr/src/lib/libc/port/locale/ldpart.c	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/ldpart.c	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -43,7 +44,7 @@
 static int split_lines(char *, const char *);
 
 int
-__part_load_locale(const char *name, int *using_locale,
+__part_load_locale(const char *name,
     char **locale_buf, const char *category_filename,
     int locale_buf_size_max, int locale_buf_size_min,
     const char **dst_localebuf)
@@ -55,21 +56,7 @@
 	struct stat	st;
 	size_t		namesize, bufsize;
 
-	/* 'name' must be already checked. */
-	if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
-		*using_locale = 0;
-		return (_LDP_CACHE);
-	}
-
 	/*
-	 * If the locale name is the same as our cache, use the cache.
-	 */
-	if (*locale_buf != NULL && strcmp(name, *locale_buf) == 0) {
-		*using_locale = 1;
-		return (_LDP_CACHE);
-	}
-
-	/*
 	 * Slurp the locale file into the cache.
 	 */
 	namesize = strlen(name) + 1;
@@ -117,14 +104,11 @@
 	/*
 	 * Record the successful parse in the cache.
 	 */
-	if (*locale_buf != NULL)
-		free(*locale_buf);
 	*locale_buf = lbuf;
 	for (p = *locale_buf, i = 0; i < num_lines; i++)
 		dst_localebuf[i] = (p += strlen(p) + 1);
 	for (i = num_lines; i < locale_buf_size_max; i++)
 		dst_localebuf[i] = NULL;
-	*using_locale = 1;
 
 	return (_LDP_LOADED);
 
--- old/usr/src/lib/libc/port/locale/ldpart.h	Tue May 20 07:58:47 2014
+++ new/usr/src/lib/libc/port/locale/ldpart.h	Tue May 20 07:58:47 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
@@ -31,7 +32,7 @@
 #define	_LDP_ERROR  (-1)
 #define	_LDP_CACHE  1
 
-int	__part_load_locale(const char *, int *, char **, const char *,
+int	__part_load_locale(const char *, char **, const char *,
 		    int, int, const char **);
 
 #endif /* !_LDPART_H_ */
--- old/usr/src/lib/libc/port/locale/lmessages.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lmessages.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -27,16 +28,18 @@
 
 #include "lint.h"
 #include <stddef.h>
+#include <errno.h>
 #include "ldpart.h"
 #include "lmessages.h"
+#include "localeimpl.h"
 
-#define	LCMESSAGES_SIZE_FULL (sizeof (struct lc_messages_T) / sizeof (char *))
+#define	LCMESSAGES_SIZE_FULL (sizeof (struct lc_messages) / sizeof (char *))
 #define	LCMESSAGES_SIZE_MIN \
-	(offsetof(struct lc_messages_T, yesstr) / sizeof (char *))
+	(offsetof(struct lc_messages, yesstr) / sizeof (char *))
 
 static char empty[] = "";
 
-static const struct lc_messages_T _C_messages_locale = {
+struct lc_messages lc_messages_posix = {
 	"^[yY]",	/* yesexpr */
 	"^[nN]",	/* noexpr */
 	"yes",		/* yesstr */
@@ -43,31 +46,37 @@
 	"no"		/* nostr */
 };
 
-static struct lc_messages_T _messages_locale;
-static int	_messages_using_locale;
-static char	*_messages_locale_buf;
+struct locdata __posix_messages_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_messages_posix }
+};
 
-int
-__messages_load_locale(const char *name)
+struct locdata *
+__lc_messages_load(const char *name)
 {
+	struct locdata *ldata;
+	struct lc_messages *lmsgs;
 	int ret;
 
-	ret = __part_load_locale(name, &_messages_using_locale,
-	    &_messages_locale_buf, "LC_MESSAGES",
-	    LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
-	    (const char **)&_messages_locale);
-	if (ret == _LDP_LOADED) {
-		if (_messages_locale.yesstr == NULL)
-			_messages_locale.yesstr = empty;
-		if (_messages_locale.nostr == NULL)
-			_messages_locale.nostr = empty;
+	if ((ldata = __locdata_alloc(name, sizeof (*lmsgs))) == NULL)
+		return (NULL);
+	lmsgs = ldata->l_data[0];
+
+	ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+	    "LC_MESSAGES", LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
+	    (const char **)lmsgs);
+
+	if (ret != _LDP_LOADED) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
 	}
-	return (ret);
-}
 
-struct lc_messages_T *
-__get_current_messages_locale(void)
-{
-	return (_messages_using_locale ? &_messages_locale :
-	    (struct lc_messages_T *)&_C_messages_locale);
+	if (lmsgs->yesstr == NULL)
+		lmsgs->yesstr = empty;
+	if (lmsgs->nostr == NULL)
+		lmsgs->nostr = empty;
+
+	return (ldata);
 }
--- old/usr/src/lib/libc/port/locale/lmessages.h	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lmessages.h	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
@@ -27,7 +28,7 @@
 #ifndef _LMESSAGES_H_
 #define	_LMESSAGES_H_
 
-struct	lc_messages_T {
+struct	lc_messages {
 	const char	*yesexpr;
 	const char	*noexpr;
 	const char	*yesstr;
@@ -34,7 +35,4 @@
 	const char	*nostr;
 };
 
-struct lc_messages_T *__get_current_messages_locale(void);
-int	__messages_load_locale(const char *);
-
 #endif /* !_LMESSAGES_H_ */
--- old/usr/src/lib/libc/port/locale/lmonetary.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lmonetary.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -29,20 +30,23 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
 #include "ldpart.h"
 #include "lmonetary.h"
+#include "localeimpl.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 *))
+#define	LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary) / sizeof (char *))
 #define	LCMONETARY_SIZE_MIN \
-	(offsetof(struct lc_monetary_T, int_p_cs_precedes) / sizeof (char *))
+	(offsetof(struct lc_monetary, int_p_cs_precedes) / sizeof (char *))
 
 static char	empty[] = "";
 static char	numempty[] = { CHAR_MAX, '\0' };
 
-static const struct lc_monetary_T _C_monetary_locale = {
+struct lc_monetary lc_monetary_posix = {
 	empty,		/* int_curr_symbol */
 	empty,		/* currency_symbol */
 	empty,		/* mon_decimal_point */
@@ -63,12 +67,15 @@
 	numempty,	/* int_p_sep_by_space */
 	numempty,	/* int_n_sep_by_space */
 	numempty,	/* int_p_sign_posn */
-	numempty	/* int_n_sign_posn */
+	numempty,	/* int_n_sign_posn */
+	empty		/* crncystr */
 };
 
-static struct lc_monetary_T _monetary_locale;
-static int	_monetary_using_locale;
-static char	*_monetary_locale_buf;
+struct locdata __posix_monetary_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_monetary_posix }
+};
 
 static char
 cnv(const char *str)
@@ -80,59 +87,94 @@
 	return ((char)i);
 }
 
-int
-__monetary_load_locale(const char *name)
+struct locdata *
+__lc_monetary_load(const char *name)
 {
 	int ret;
+	int clen;
+	struct lc_monetary	*lmon;
+	struct locdata		*ldata;
 
-	ret = __part_load_locale(name, &_monetary_using_locale,
-	    &_monetary_locale_buf, "LC_MONETARY",
-	    LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
-	    (const char **)&_monetary_locale);
-	if (ret != _LDP_ERROR)
-		__mlocale_changed = 1;
-	if (ret == _LDP_LOADED) {
-		_monetary_locale.mon_grouping =
-		    __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+	if ((ldata = __locdata_alloc(name, sizeof (*lmon))) == NULL) {
+		return (NULL);
+	}
+	lmon = ldata->l_data[0];
 
+	ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+	    "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
+	    (const char **)lmon);
+
+	if (ret != _LDP_LOADED) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* special storage for currency string */
+	clen = strlen(lmon->currency_symbol) + 2;
+	ldata->l_data[2] = malloc(clen);
+	lmon->crncystr = ldata->l_data[2];
+	lmon->crncystr[0] = '\0';
+
+	lmon->mon_grouping = __fix_locale_grouping_str(lmon->mon_grouping);
+
 #define	M_ASSIGN_CHAR(NAME) \
-		(((char *)_monetary_locale.NAME)[0] = \
-			cnv(_monetary_locale.NAME))
+	(((char *)lmon->NAME)[0] = cnv(lmon->NAME))
 
-		M_ASSIGN_CHAR(int_frac_digits);
-		M_ASSIGN_CHAR(frac_digits);
-		M_ASSIGN_CHAR(p_cs_precedes);
-		M_ASSIGN_CHAR(p_sep_by_space);
-		M_ASSIGN_CHAR(n_cs_precedes);
-		M_ASSIGN_CHAR(n_sep_by_space);
-		M_ASSIGN_CHAR(p_sign_posn);
-		M_ASSIGN_CHAR(n_sign_posn);
+	M_ASSIGN_CHAR(int_frac_digits);
+	M_ASSIGN_CHAR(frac_digits);
+	M_ASSIGN_CHAR(p_cs_precedes);
+	M_ASSIGN_CHAR(p_sep_by_space);
+	M_ASSIGN_CHAR(n_cs_precedes);
+	M_ASSIGN_CHAR(n_sep_by_space);
+	M_ASSIGN_CHAR(p_sign_posn);
+	M_ASSIGN_CHAR(n_sign_posn);
 
-		/*
-		 * The six additional C99 international monetary formatting
-		 * parameters default to the national parameters when
-		 * 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);
+	/*
+	 * The six additional C99 international monetary formatting
+	 * parameters default to the national parameters when
+	 * reading FreeBSD LC_MONETARY data files.
+	 */
+#define	M_ASSIGN_ICHAR(NAME)				\
+	if (lmon->int_##NAME == NULL)			\
+		lmon->int_##NAME = lmon->NAME;		\
+	else						\
+		M_ASSIGN_CHAR(int_##NAME);
 
-		M_ASSIGN_ICHAR(p_cs_precedes);
-		M_ASSIGN_ICHAR(n_cs_precedes);
-		M_ASSIGN_ICHAR(p_sep_by_space);
-		M_ASSIGN_ICHAR(n_sep_by_space);
-		M_ASSIGN_ICHAR(p_sign_posn);
-		M_ASSIGN_ICHAR(n_sign_posn);
+	M_ASSIGN_ICHAR(p_cs_precedes);
+	M_ASSIGN_ICHAR(n_cs_precedes);
+	M_ASSIGN_ICHAR(p_sep_by_space);
+	M_ASSIGN_ICHAR(n_sep_by_space);
+	M_ASSIGN_ICHAR(p_sign_posn);
+	M_ASSIGN_ICHAR(n_sign_posn);
+
+	/*
+	 * Now calculate the currency string (CRNCYSTR) for nl_langinfo.
+	 * This is a legacy SUSv2 interface.
+	 */
+	if ((lmon->p_cs_precedes[0] == lmon->n_cs_precedes[0]) &&
+	    (lmon->currency_symbol[0] != '\0')) {
+		char sign = '\0';
+		switch (lmon->p_cs_precedes[0]) {
+		case 0:
+			sign = '-';
+			break;
+		case 1:
+			sign = '+';
+			break;
+		case CHAR_MAX:
+			/*
+			 * Substitute currency string for radix character.
+			 * To the best of my knowledge, no locale uses this.
+			 */
+			if (strcmp(lmon->mon_decimal_point,
+			    lmon->currency_symbol) == 0)
+				sign = '.';
+			break;
+		}
+		(void) snprintf(lmon->crncystr, clen, "%c%s", sign,
+		    lmon->currency_symbol);
 	}
-	return (ret);
-}
 
-struct lc_monetary_T *
-__get_current_monetary_locale(void)
-{
-	return (_monetary_using_locale ? &_monetary_locale :
-	    (struct lc_monetary_T *)&_C_monetary_locale);
+	return (ldata);
 }
--- old/usr/src/lib/libc/port/locale/lmonetary.h	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lmonetary.h	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
@@ -27,7 +28,7 @@
 #ifndef _LMONETARY_H_
 #define	_LMONETARY_H_
 
-struct lc_monetary_T {
+struct lc_monetary {
 	const char	*int_curr_symbol;
 	const char	*currency_symbol;
 	const char	*mon_decimal_point;
@@ -49,9 +50,9 @@
 	const char	*int_n_sep_by_space;
 	const char	*int_p_sign_posn;
 	const char	*int_n_sign_posn;
+	char		*crncystr;		/* nl_langinfo */
 };
 
-struct lc_monetary_T *__get_current_monetary_locale(void);
 int	__monetary_load_locale(const char *);
 
 #endif /* !_LMONETARY_H_ */
--- old/usr/src/lib/libc/port/locale/lnumeric.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lnumeric.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore.
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -27,59 +28,59 @@
 
 #include "lint.h"
 #include <limits.h>
+#include <errno.h>
 #include "ldpart.h"
 #include "lnumeric.h"
-#include "../i18n/_locale.h"
+#include "localeimpl.h"
 
-extern int __nlocale_changed;
 extern const char *__fix_locale_grouping_str(const char *);
 
-#define	LCNUMERIC_SIZE (sizeof (struct lc_numeric_T) / sizeof (char *))
+#define	LCNUMERIC_SIZE (sizeof (struct lc_numeric) / sizeof (char *))
 
 static char	numempty[] = { CHAR_MAX, '\0' };
 
-static const struct lc_numeric_T _C_numeric_locale = {
+struct lc_numeric lc_numeric_posix = {
 	".",		/* decimal_point */
 	"",		/* thousands_sep */
 	numempty	/* grouping */
 };
 
-static struct lc_numeric_T _numeric_locale;
-static int	_numeric_using_locale;
-static char	*_numeric_locale_buf;
+struct locdata __posix_numeric_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_numeric_posix }
+};
 
-int
-__numeric_load_locale(const char *name)
-{
-	const struct lc_numeric_T *leg = &_C_numeric_locale;
 
+/*
+ * Return the locale's numeric locdata structure, places a hold on it,
+ * which the caller must release.
+ */
+struct locdata *
+__lc_numeric_load(const char *name)
+{
+	struct locdata *ldata;
+	struct lc_numeric *lnum;
 	int ret;
 
-	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);
+	if ((ldata = __locdata_alloc(name, sizeof (*lnum))) == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+	lnum = ldata->l_data[0];
 
-	__nlocale_changed = 1;
-	if (ret == _LDP_LOADED) {
-		/* Can't be empty according to C99 */
-		if (*_numeric_locale.decimal_point == '\0')
-			_numeric_locale.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;
+	ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+	    "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE, (const char **)lnum);
+
+	if (ret != _LDP_LOADED) {
+		__locdata_release(ldata);
+		return (NULL);
 	}
-	/* This is Solaris legacy, required for ABI compatability */
-	_numeric[0] = *leg->decimal_point;
-	_numeric[1] = *leg->grouping;
-	return (ret);
-}
 
-struct lc_numeric_T *
-__get_current_numeric_locale(void)
-{
-	return (_numeric_using_locale ? &_numeric_locale :
-	    (struct lc_numeric_T *)&_C_numeric_locale);
+	/* Can't be empty according to C99 */
+	if (*lnum->decimal_point == '\0')
+		lnum->decimal_point = lc_numeric_posix.decimal_point;
+	lnum->grouping = __fix_locale_grouping_str(lnum->grouping);
+
+	return (ldata);
 }
--- old/usr/src/lib/libc/port/locale/lnumeric.h	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lnumeric.h	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
  *
@@ -27,13 +28,10 @@
 #ifndef _LNUMERIC_H_
 #define	_LNUMERIC_H_
 
-struct lc_numeric_T {
+struct lc_numeric {
 	const char	*decimal_point;
 	const char	*thousands_sep;
 	const char	*grouping;
 };
 
-struct lc_numeric_T *__get_current_numeric_locale(void);
-int	__numeric_load_locale(const char *);
-
 #endif /* !_LNUMERIC_H_ */
--- old/usr/src/lib/libc/port/locale/localeconv.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/localeconv.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * Copyright (c) 1991, 1993
@@ -37,35 +38,37 @@
 #include <locale.h>
 #include "lmonetary.h"
 #include "lnumeric.h"
+#include "localeimpl.h"
 
 /*
- * The localeconv() function constructs a struct lconv from the current
- * monetary and numeric locales.
+ * Return the current locale conversion.
  *
+ * Note that XPG7 specifically states that localeconv's return value may
+ * be invalidated if the application calls setlocale() or uselocale() within
+ * the same thread.
+ *
  * Because localeconv() may be called many times (especially by library
  * routines like printf() & strtod()), the approprate members of the
  * 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)
 {
-	static struct lconv ret;
+	struct lconv	*lconv;
+	locale_t	loc;
+	struct lc_monetary	*mptr;
+	struct lc_numeric	*nptr;
 
-	if (__mlocale_changed) {
-		/* LC_MONETARY part */
-		struct lc_monetary_T *mptr;
+	loc = uselocale(NULL);
+	lconv = &loc->lconv;
 
-#define	M_ASSIGN_STR(NAME) (ret.NAME = (char *)mptr->NAME)
-#define	M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0])
+	if (loc->loaded[LC_MONETARY] == 0) {
+		mptr = loc->locdata[LC_MONETARY]->l_data[0];
 
-		mptr = __get_current_monetary_locale();
+#define	M_ASSIGN_STR(NAME) (lconv->NAME = (char *)mptr->NAME)
+#define	M_ASSIGN_CHAR(NAME) (lconv->NAME = mptr->NAME[0])
+
 		M_ASSIGN_STR(int_curr_symbol);
 		M_ASSIGN_STR(currency_symbol);
 		M_ASSIGN_STR(mon_decimal_point);
@@ -87,21 +90,19 @@
 		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->loaded[LC_MONETARY] = 1;
 	}
 
-	if (__nlocale_changed) {
-		/* LC_NUMERIC part */
-		struct lc_numeric_T *nptr;
+	if (loc->loaded[LC_NUMERIC] == 0) {
+		nptr = loc->locdata[LC_NUMERIC]->l_data[0];
 
-#define	N_ASSIGN_STR(NAME) (ret.NAME = (char *)nptr->NAME)
+#define	N_ASSIGN_STR(NAME) (lconv->NAME = (char *)nptr->NAME)
 
-		nptr = __get_current_numeric_locale();
 		N_ASSIGN_STR(decimal_point);
 		N_ASSIGN_STR(thousands_sep);
 		N_ASSIGN_STR(grouping);
-		__nlocale_changed = 0;
+		loc->loaded[LC_NUMERIC] = 1;
 	}
 
-	return (&ret);
+	return (lconv);
 }
--- /dev/null	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/localeimpl.c	Tue May 20 07:58:48 2014
@@ -0,0 +1,470 @@
+/*
+ * 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 2014 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * This file implements the 2008 newlocale and friends handling.
+ */
+
+#ifndef	_LCONV_C99
+#define	_LCONV_C99
+#endif
+
+#include "lint.h"
+#include <atomic.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include "libc.h"
+#include "mtlib.h"
+#include "tsd.h"
+#include "localeimpl.h"
+#include "lctype.h"
+
+/*
+ * Big Theory of Locales:
+ *
+ * (It is recommended that readers familiarize themselves with the POSIX
+ * 2008 (XPG Issue 7) specifications for locales, first.)
+ *
+ * Historically, we had a bunch of global variables that stored locale
+ * data.  While this worked well, it limited applications to a single locale
+ * at a time.  This doesn't work well in certain server applications.
+ *
+ * Issue 7, X/Open introduced the concept of a locale_t object, along with
+ * versions of functions that can take this object as a parameter, along
+ * with functions to clone and manipulate these locale objects.  The new
+ * functions are named with a _l() suffix.
+ *
+ * Additionally uselocale() is introduced which can change the locale of
+ * of a single thread.  However, setlocale() can still be used to change
+ * the global locale.
+ *
+ * In our implementation, we use libc's TSD to store the locale data that
+ * was previously global.  We still have global data because some applications
+ * have had those global objects compiled into them.  (Such applications will
+ * be unable to benefit from uselocale(), btw.)  The legacy routines are
+ * reimplemented as wrappers that use the appropriate locale object by
+ * calling uselocale().  uselocale() when passed a NULL pointer returns the
+ * thread-specific locale object if one is present, or the global locale
+ * object otherwise.  Note that once the TSD data is set, the only way
+ * to revert to the global locale is to pass the global locale LC_GLOBAL_LOCALE
+ * to uselocale().
+ *
+ * We are careful to minimize performance impact of multiple calls to
+ * uselocale() or setlocale() by using a cache of locale data whenever possible.
+ * As a consequence of this, applications that iterate over all possible
+ * locales will burn through a lot of virtual memory, but we find such
+ * applications rare.  (locale -a might be an exception, but it is short lived.)
+ */
+
+/*
+ * NB: Each of the structures listed herein should have the refcnt
+ * set to -1, to ensure that posix locale information is never ever freed,
+ * even when changing the global locale.
+ */
+
+typedef struct locdata *(*loadfn_t)(const char *);
+
+static const loadfn_t loaders[LC_ALL] = {
+	__lc_ctype_load,
+	__lc_numeric_load,
+	__lc_time_load,
+	__lc_collate_load,
+	__lc_monetary_load,
+	__lc_messages_load,
+};
+
+extern struct lc_monetary lc_monetary_posix;
+extern struct lc_numeric lc_numeric_posix;
+extern struct lc_messages lc_messages_posix;
+extern struct lc_time lc_time_posix;
+extern struct lc_ctype lc_ctype_posix;
+extern struct lc_collate lc_collate_posix;
+
+static struct locale posix_locale = {
+	/* locdata */
+	.locdata = {
+		&__posix_ctype_locdata,
+		&__posix_numeric_locdata,
+		&__posix_time_locdata,
+		&__posix_collate_locdata,
+		&__posix_monetary_locdata,
+		&__posix_messages_locdata,
+	},
+	.ctype = &lc_ctype_posix,
+	.numeric = &lc_numeric_posix,
+	.collate = &lc_collate_posix,
+	.monetary = &lc_monetary_posix,
+	.messages = &lc_messages_posix,
+	.time = &lc_time_posix,
+	.runelocale = &_DefaultRuneLocale,
+};
+
+locale_t __global_locale = &posix_locale;
+
+/*
+ * Category names for getenv()  Note that this was modified
+ * for Solaris.  See <iso/locale_iso.h>.
+ */
+#define	NUM_CATS	7
+static char *categories[7] = {
+	"LC_CTYPE",
+	"LC_NUMERIC",
+	"LC_TIME",
+	"LC_COLLATE",
+	"LC_MONETARY",
+	"LC_MESSAGES",
+	"LC_ALL",
+};
+
+/*
+ * Prototypes.
+ */
+static const char *get_locale_env(int);
+static struct locdata *locdata_get(int, const const char *);
+static struct locdata *locdata_get_cache(int, const char *);
+static void locdata_set_cache(int, struct locdata *);
+
+/*
+ * Some utility routines.
+ */
+struct locdata *
+__locdata_hold(struct locdata *ld)
+{
+	if (ld != NULL && ld->l_refcnt != (uint32_t)-1)
+		atomic_inc_32(&ld->l_refcnt);
+	return (ld);
+}
+
+void
+__locdata_release(struct locdata *ld)
+{
+	if (ld->l_refcnt == (uint32_t)-1)
+		return;
+
+	if (atomic_dec_32_nv(&ld->l_refcnt) == 0) {
+		for (int i = 0; i < NLOCDATA; i++)
+			free(ld->l_data[i]);
+		if (ld->l_map && ld->l_map_len) {
+			(void) munmap(ld->l_map, ld->l_map_len);
+		}
+		free(ld);
+	}
+}
+
+struct locdata *
+__locdata_alloc(const char *name, size_t memsz)
+{
+	struct locdata *ldata;
+
+	if ((ldata = calloc(1, sizeof (*ldata))) == NULL) {
+		return (NULL);
+	}
+	if ((ldata->l_data[0] = calloc(1, memsz)) == NULL) {
+		free(ldata);
+		errno = ENOMEM;
+		return (NULL);
+	}
+	(void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
+	ldata->l_refcnt = 1;
+
+	return (ldata);
+}
+
+/*
+ * It turns out that for performance reasons we would really like to
+ * cache the most recently referenced locale data to avoid wasteful
+ * loading from files.
+ */
+
+static struct locdata *cache_data[LC_ALL];
+static mutex_t cache_lock = DEFAULTMUTEX;
+
+/*
+ * Returns the cached data if the locale name is the same.  If not,
+ * returns NULL (cache miss).  The locdata is returned with a hold on
+ * it, taken on behalf of the caller.  The caller should drop the hold
+ * when it is finished.
+ */
+static struct locdata *
+locdata_get_cache(int category, const char *locname)
+{
+	struct locdata *loc;
+
+	if (category < 0 || category >= LC_ALL)
+		return (NULL);
+
+	lmutex_lock(&cache_lock);
+	if ((loc = cache_data[category]) != NULL) {
+		if (strcmp(locname, loc->l_lname) == 0) {
+			loc = __locdata_hold(loc);
+		} else {
+			loc = NULL;
+		}
+	}
+	lmutex_unlock(&cache_lock);
+	return (loc);
+}
+
+/*
+ * Set the cache for the category to specific content.  An additional hold
+ * is taken for the data while it is in the cache, so the caller may drop
+ * its own hold once this is complete.  Also, releases the hold on any
+ * previously cached data.
+ */
+static void
+locdata_set_cache(int category, struct locdata *loc)
+{
+	struct locdata *old;
+
+	if (category < 0 || category >= LC_ALL)
+		return;
+
+	lmutex_lock(&cache_lock);
+	old = cache_data[category];
+	cache_data[category] = __locdata_hold(loc);
+	lmutex_unlock(&cache_lock);
+
+	/* drop our reference on the old data */
+	if (old)
+		__locdata_release(old);
+}
+
+/*
+ * Routine to get the locdata for a given category and locale.
+ * This includes retrieving it from cache, retrieving it from
+ * a file, etc.
+ */
+static struct locdata *
+locdata_get(int category, const char *locname)
+{
+	struct locdata *ldata;
+	char scratch[ENCODING_LEN + 1];
+	char *slash;
+	int cnt;
+	int len;
+
+	if (locname == NULL || *locname == 0) {
+		locname = get_locale_env(category);
+	}
+
+	/*
+	 * Extract the locale name for the category if it is a composite
+	 * locale.
+	 */
+	if ((slash = strchr(locname, '/')) != NULL) {
+		for (cnt = category; cnt && slash != NULL; cnt--) {
+			locname = slash + 1;
+			slash = strchr(locname, '/');
+		}
+		if (slash) {
+			len = slash - locname;
+			if (len >= sizeof (scratch)) {
+				len = sizeof (scratch);
+			}
+		} else {
+			len = sizeof (scratch);
+		}
+		(void) strlcpy(scratch, locname, len);
+		locname = scratch;
+	}
+
+	if ((strcmp(locname, "C") == 0) || (strcmp(locname, "POSIX") == 0))
+		return (__locdata_hold(posix_locale.locdata[category]));
+
+	ldata = locdata_get_cache(category, locname);
+	if (ldata != NULL)
+		return (ldata);
+
+	/* Otherwise load it */
+	ldata = (*loaders[category])(locname);
+	if (ldata != NULL) {
+		locdata_set_cache(category, ldata);
+	}
+	return (ldata);
+}
+
+/* tsd destructor */
+static void
+freelocptr(void *arg)
+{
+	locale_t *locptr = arg;
+	if (*locptr != NULL)
+		freelocale(*locptr);
+}
+
+static const char *
+get_locale_env(int category)
+{
+	const char *env;
+
+	/* 1. check LC_ALL. */
+	env = getenv(categories[LC_ALL]);
+
+	/* 2. check LC_* */
+	if (env == NULL || *env == '\0')
+		env = getenv(categories[category]);
+
+	/* 3. check LANG */
+	if (env == NULL || *env == '\0')
+		env = getenv("LANG");
+
+	/* 4. if none is set, fall to "C" */
+	if (env == NULL || *env == '\0')
+		env = "C";
+
+	return (env);
+}
+
+
+/*
+ * This routine is exposed via the MB_CUR_MAX macro.  Note that legacy
+ * code will continue to use _ctype[520], but we prefer this function as
+ * it is the only way to get thread-specific information.
+ */
+unsigned char
+__mb_cur_max_l(locale_t loc)
+{
+	return (loc->ctype->lc_max_mblen);
+}
+
+unsigned char
+__mb_cur_max(void)
+{
+	return (__mb_cur_max_l(uselocale(NULL)));
+}
+
+/*
+ * Public interfaces.
+ */
+
+locale_t
+duplocale(locale_t src)
+{
+	locale_t	loc;
+	int		i;
+
+	loc = calloc(1, sizeof (*loc));
+	if (loc == NULL) {
+		return (NULL);
+	}
+	for (i = 0; i < LC_ALL; i++) {
+		loc->locdata[i] = __locdata_hold(src->locdata[i]);
+		loc->loaded[i] = 0;
+	}
+	loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
+	loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
+	loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
+	loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
+	loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
+	loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
+	loc->time = loc->locdata[LC_TIME]->l_data[0];
+	return (loc);
+}
+
+void
+freelocale(locale_t loc)
+{
+	int i;
+	for (i = 0; i < LC_ALL; i++)
+		__locdata_release(loc->locdata[i]);
+	if (loc != &posix_locale)
+		free(loc);
+}
+
+locale_t
+newlocale(int catmask, const char *locname, locale_t base)
+{
+	locale_t loc;
+	int i, e;
+
+	if (catmask & ~(LC_ALL_MASK)) {
+		errno = EINVAL;
+		return (NULL);
+	}
+	loc = duplocale(base != NULL ? base : __global_locale);
+	if (loc == NULL) {
+		return (NULL);
+	}
+
+	for (i = 0; i < LC_ALL; i++) {
+		struct locdata *ldata;
+		loc->loaded[i] = 0;
+		if (((1 << i) & catmask) == 0) {
+			/* Default to base locale if not overriding */
+			continue;
+		}
+		ldata = locdata_get(i, locname);
+		if (ldata == NULL) {
+			e = errno;
+			freelocale(loc);
+			errno = e;
+			return (NULL);
+		}
+		__locdata_release(loc->locdata[i]);
+		loc->locdata[i] = ldata;
+	}
+	if (base && base != __global_locale) {
+		freelocale(base);
+	}
+	loc->collate = loc->locdata[LC_COLLATE]->l_data[0];
+	loc->ctype = loc->locdata[LC_CTYPE]->l_data[0];
+	loc->runelocale = loc->locdata[LC_CTYPE]->l_data[1];
+	loc->messages = loc->locdata[LC_MESSAGES]->l_data[0];
+	loc->monetary = loc->locdata[LC_MONETARY]->l_data[0];
+	loc->numeric = loc->locdata[LC_NUMERIC]->l_data[0];
+	loc->time = loc->locdata[LC_TIME]->l_data[0];
+	return (loc);
+}
+
+locale_t
+uselocale(locale_t loc)
+{
+	locale_t lastloc = __global_locale;
+	locale_t *locptr;
+
+	locptr = tsdalloc(_T_SETLOCALE, sizeof (locale_t), freelocptr);
+	/* Should never occur */
+	if (locptr == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	if (*locptr != NULL)
+		lastloc = *locptr;
+
+	/* Argument loc is NULL if we are just querying. */
+	if (loc != NULL) {
+		/*
+		 * Set it to LC_GLOBAL_LOCAL to return to using
+		 * the global locale (setlocale).
+		 */
+		if (loc == __global_locale) {
+			*locptr = NULL;
+		} else {
+			/* No validation of the provided locale at present */
+			*locptr = loc;
+		}
+	}
+
+	/*
+	 * The caller is responsible for freeing, of course it would be
+	 * gross error to call freelocale() on a locale object that is still
+	 * in use.
+	 */
+	return (lastloc);
+}
--- /dev/null	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/localeimpl.h	Tue May 20 07:58:48 2014
@@ -0,0 +1,103 @@
+/*
+ * 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 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * This file implements the 2008 newlocale and friends handling. It is
+ * private to libc.
+ */
+#ifndef	_LOCALEIMPL_H_
+#define	_LOCALEIMPL_H_
+
+#ifndef _LCONV_C99
+#define	_LCONV_C99	/* so we get all the extensions */
+#endif
+
+#include <sys/types.h>
+#include <locale.h>
+#include <xlocale.h>
+#include "setlocale.h"
+#include "runetype.h"
+
+/* private locale structures */
+
+/*
+ * Because some locale data is rather ahem.. large, we would like to keep
+ * reference counts on it.  We create an abstract header (locdata) structure
+ * which keeps a point to the opaque per-category data, along with a reference
+ * count to it.  To be threadsafe, we will use atomics when holding it or
+ * freeing it.  (This only occurs when locale objects are created or destroyed,
+ * so there should be no performance impact on hot code paths.  If your code
+ * uses locale_t creation/destruction on a hot code path, its broken.  But
+ * even so, the atomic and reference counting will probably *greatly* improve
+ * your life as bootstrapping locale data from files is quite expensive.
+ */
+
+#define	NLOCDATA	4
+struct locdata {
+	char		l_lname[ENCODING_LEN+1];	/* locale name */
+	void		*l_data[NLOCDATA];		/* storage area */
+	void		*l_map;				/* mapped file */
+	size_t		l_map_len;
+	uint32_t	l_refcnt;
+};
+
+
+struct locale {
+	struct locdata	*locdata[LC_ALL];
+
+	/*
+	 * Convenience pointers.
+	 */
+	const struct lc_ctype		*ctype;
+	const struct lc_collate		*collate;
+	const struct lc_messages	*messages;
+	const struct lc_monetary	*monetary;
+	const struct lc_numeric		*numeric;
+	const struct lc_time		*time;
+	const _RuneLocale		*runelocale;
+
+	/*
+	 * The loaded value is used for localeconv.  In paticular, when
+	 * when we change the value of one of the above categories, we will
+	 * also need to update the lconv structure.  The loaded bit indicates
+	 * that the lconv structure is "current" for that category.  It's
+	 * sort of an "inverse dirty" bit.
+	 */
+	int		loaded[LC_ALL];
+	struct lconv	lconv;
+};
+
+
+struct locdata *__locdata_alloc(const char *, size_t);
+struct locdata *__locdata_hold(struct locdata *);
+void __locdata_release(struct locdata *);
+struct locdata *__locdata_get_cache(int, const char *);
+void __locdata_set_cache(int, struct locdata *);
+
+struct locdata *__lc_numeric_load(const char *name);
+struct locdata *__lc_monetary_load(const char *name);
+struct locdata *__lc_messages_load(const char *name);
+struct locdata *__lc_time_load(const char *name);
+struct locdata *__lc_ctype_load(const char *name);
+struct locdata *__lc_collate_load(const char *name);
+
+extern struct locdata	__posix_numeric_locdata;
+extern struct locdata	__posix_monetary_locdata;
+extern struct locdata	__posix_messages_locdata;
+extern struct locdata	__posix_time_locdata;
+extern struct locdata	__posix_ctype_locdata;
+extern struct locdata	__posix_collate_locdata;
+
+#endif	/* _LOCALEIMPL_H_ */
--- old/usr/src/lib/libc/port/locale/mblen.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/mblen.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -28,10 +29,13 @@
 #include "lint.h"
 #include <stdlib.h>
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
+#include "localeimpl.h"
 
 int
-mblen(const char *s, size_t n)
+mblen_l(const char *s, size_t n, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	static mbstate_t mbs;
@@ -42,8 +46,14 @@
 		mbs = initial;
 		return (0);
 	}
-	rval = __mbrtowc(NULL, s, n, &mbs);
+	rval = mbrtowc_l(NULL, s, n, &mbs, loc);
 	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, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mblocal.h	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/mblocal.h	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2004 Tim J. Robbins.
  * All rights reserved.
@@ -29,43 +30,31 @@
 #define	_MBLOCAL_H_
 
 #include "runetype.h"
+#include "lctype.h"
 
 /*
  * Rune initialization function prototypes.
  */
-int	_none_init(_RuneLocale *);
-int	_UTF8_init(_RuneLocale *);
-int	_EUC_CN_init(_RuneLocale *);
-int	_EUC_JP_init(_RuneLocale *);
-int	_EUC_KR_init(_RuneLocale *);
-int	_EUC_TW_init(_RuneLocale *);
-int	_GB18030_init(_RuneLocale *);
-int	_GB2312_init(_RuneLocale *);
-int	_GBK_init(_RuneLocale *);
-int	_BIG5_init(_RuneLocale *);
-int	_MSKanji_init(_RuneLocale *);
+void	_none_init(struct lc_ctype *);
+void	_UTF8_init(struct lc_ctype *);
+void	_EUC_CN_init(struct lc_ctype *);
+void	_EUC_JP_init(struct lc_ctype *);
+void	_EUC_KR_init(struct lc_ctype *);
+void	_EUC_TW_init(struct lc_ctype *);
+void	_GB18030_init(struct lc_ctype *);
+void	_GB2312_init(struct lc_ctype *);
+void	_GBK_init(struct lc_ctype *);
+void	_BIG5_init(struct lc_ctype *);
+void	_MSKanji_init(struct lc_ctype *);
 
-/*
- * Conversion function pointers for current encoding.
- */
-extern size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD,
+typedef size_t (*mbrtowc_pfn_t)(wchar_t *_RESTRICT_KYWD,
     const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
-extern int (*__mbsinit)(const mbstate_t *);
-extern size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
-    const char **_RESTRICT_KYWD, size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-
-extern size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
+typedef size_t (*wcrtomb_pfn_t)(char *_RESTRICT_KYWD, wchar_t,
     mbstate_t *_RESTRICT_KYWD);
-
-extern size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD,
-    const wchar_t **_RESTRICT_KYWD, size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-
-extern int charset_is_ascii;
-
 size_t __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
-    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD, mbrtowc_pfn_t);
 size_t __wcsnrtombs_std(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
-    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD, wcrtomb_pfn_t);
 
 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
 
--- old/usr/src/lib/libc/port/locale/mbrlen.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbrlen.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -27,14 +28,23 @@
 
 #include "lint.h"
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
 
 size_t
-mbrlen(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps)
+mbrlen_l(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps,
+    locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__mbrtowc(NULL, s, n, ps));
+	return (mbrtowc_l(NULL, s, n, ps, loc));
+}
+
+size_t
+mbrlen(const char *_RESTRICT_KYWD s, size_t n, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (mbrlen_l(s, n, ps, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mbrtowc.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbrtowc.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -28,14 +29,23 @@
 #include "lint.h"
 #include <wchar.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
-mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
-    size_t n, mbstate_t *_RESTRICT_KYWD ps)
+mbrtowc_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+    size_t n, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__mbrtowc(pwc, s, n, ps));
+	return (loc->ctype->lc_mbrtowc(pwc, s, n, ps));
+}
+
+size_t
+mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+    size_t n, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (mbrtowc_l(pwc, s, n, ps, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mbsinit.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbsinit.c	Tue May 20 07:58:49 2014
@@ -1,37 +1,31 @@
 /*
- * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
- * Copyright (c) 2002-2004 Tim J. Robbins.
- * All rights reserved.
+ * 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.
  *
- * 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.
+ * 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 Garrett D'Amore <garrett@damore.org>
+ */
+
 #include "lint.h"
-#include <wchar.h>
-#include "mblocal.h"
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
 
 int
-mbsinit(const mbstate_t *ps)
+mbsinit_l(const mbstate_t *s, locale_t loc)
 {
+	return (loc->ctype->lc_mbsinit(s));
+}
 
-	return (__mbsinit(ps));
+int
+mbsinit(const mbstate_t *s)
+{
+	return (mbsinit_l(s, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mbsnrtowcs.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbsnrtowcs.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -31,22 +32,32 @@
 #include <stdlib.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
-mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
-    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+mbsnrtowcs_l(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__mbsnrtowcs(dst, src, nms, len, ps));
+	return (loc->ctype->lc_mbsnrtowcs(dst, src, nms, len, ps));
 }
 
 size_t
-__mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
     size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps)
 {
+	return (mbsnrtowcs_l(dst, src, nms, len, ps, uselocale(NULL)));
+}
+
+size_t
+__mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+    size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD ps,
+    mbrtowc_pfn_t pmbrtowc)
+{
 	const char *s;
 	size_t nchr;
 	wchar_t wc;
@@ -57,7 +68,7 @@
 
 	if (dst == NULL) {
 		for (;;) {
-			if ((nb = __mbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+			if ((nb = pmbrtowc(&wc, s, nms, ps)) == (size_t)-1)
 				/* Invalid sequence - mbrtowc() sets errno. */
 				return ((size_t)-1);
 			else if (nb == 0 || nb == (size_t)-2)
@@ -70,7 +81,7 @@
 	}
 
 	while (len-- > 0) {
-		if ((nb = __mbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+		if ((nb = pmbrtowc(dst, s, nms, ps)) == (size_t)-1) {
 			*src = s;
 			return ((size_t)-1);
 		} else if (nb == (size_t)-2) {
--- old/usr/src/lib/libc/port/locale/mbsrtowcs.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbsrtowcs.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -26,19 +27,24 @@
  */
 
 #include "lint.h"
-#include <errno.h>
+#include <locale.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
+mbsrtowcs_l(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+    size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
+{
+	return (loc->ctype->lc_mbsnrtowcs(dst, src, ULONG_MAX, len, ps));
+}
+
+size_t
 mbsrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
     size_t len, mbstate_t *_RESTRICT_KYWD ps)
 {
-	static mbstate_t mbs;
-
-	if (ps == NULL)
-		ps = &mbs;
-	return (__mbsnrtowcs(dst, src, ULONG_MAX, len, ps));
+	return (mbsrtowcs_l(dst, src, len, ps, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mbstowcs.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbstowcs.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -29,10 +30,14 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <wchar.h>
+#include <locale.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
-mbstowcs(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s, size_t n)
+mbstowcs_l(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s,
+    size_t n, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	mbstate_t mbs;
@@ -40,5 +45,11 @@
 
 	mbs = initial;
 	sp = s;
-	return (__mbsnrtowcs(pwcs, &sp, ULONG_MAX, n, &mbs));
+	return (loc->ctype->lc_mbsnrtowcs(pwcs, &sp, ULONG_MAX, n, &mbs));
+}
+
+size_t
+mbstowcs(wchar_t *_RESTRICT_KYWD pwcs, const char *_RESTRICT_KYWD s, size_t n)
+{
+	return (mbstowcs_l(pwcs, s, n, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mbtowc.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mbtowc.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -28,10 +29,13 @@
 #include "lint.h"
 #include <stdlib.h>
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
 
 int
-mbtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n)
+mbtowc_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n,
+    locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	static mbstate_t mbs;
@@ -42,8 +46,14 @@
 		mbs = initial;
 		return (0);
 	}
-	rval = __mbrtowc(pwc, s, n, &mbs);
+	rval = mbrtowc_l(pwc, s, n, &mbs, loc);
 	if (rval == (size_t)-1 || rval == (size_t)-2)
 		return (-1);
 	return ((int)rval);
+}
+
+int
+mbtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, size_t n)
+{
+	return (mbtowc_l(pwc, s, n, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/mskanji.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/mskanji.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
  *
@@ -37,11 +38,11 @@
 #include "lint.h"
 #include <sys/types.h>
 #include <errno.h>
-#include "runetype.h"
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
@@ -49,22 +50,28 @@
 static int	_MSKanji_mbsinit(const mbstate_t *);
 static size_t	_MSKanji_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
 		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_MSKanji_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
+		    const char **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
+static size_t	_MSKanji_wcsnrtombs(char *_RESTRICT_KYWD,
+		    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
+		    mbstate_t *_RESTRICT_KYWD);
 
 typedef struct {
 	wchar_t	ch;
 } _MSKanjiState;
 
-int
-_MSKanji_init(_RuneLocale *rl)
+void
+_MSKanji_init(struct lc_ctype *lct)
 {
 
-	__mbrtowc = _MSKanji_mbrtowc;
-	__wcrtomb = _MSKanji_wcrtomb;
-	__mbsinit = _MSKanji_mbsinit;
-	_CurrentRuneLocale = rl;
-	__ctype[520] = 2;
-	charset_is_ascii = 0;
-	return (0);
+	lct->lc_mbrtowc = _MSKanji_mbrtowc;
+	lct->lc_wcrtomb = _MSKanji_wcrtomb;
+	lct->lc_mbsnrtowcs = _MSKanji_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _MSKanji_wcsnrtombs;
+	lct->lc_mbsinit = _MSKanji_mbsinit;
+	lct->lc_max_mblen = 2;
+	lct->lc_is_ascii = 0;
 }
 
 static int
@@ -153,4 +160,20 @@
 	for (i = len; i-- > 0; )
 		*s++ = wc >> (i << 3);
 	return (len);
+}
+
+static size_t
+_MSKanji_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
+    const char **_RESTRICT_KYWD src, size_t nms,
+    size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__mbsnrtowcs_std(dst, src, nms, len, ps, _MSKanji_mbrtowc));
+}
+
+static size_t
+_MSKanji_wcsnrtombs(char *_RESTRICT_KYWD dst,
+    const wchar_t **_RESTRICT_KYWD src, size_t nwc,
+    size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (__wcsnrtombs_std(dst, src, nwc, len, ps, _MSKanji_wcrtomb));
 }
--- old/usr/src/lib/libc/port/locale/nextwctype.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/nextwctype.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 2004 Tim J. Robbins.
  * All rights reserved.
  *
@@ -28,20 +29,32 @@
 #include "runetype.h"
 #include <wchar.h>
 #include <wctype.h>
+#include "localeimpl.h"
 
-wint_t
-__nextwctype(wint_t wc, wctype_t wct)
+/*
+ * nextwctype, while exposed on *BSD/MacOS X, is considered "consolidation
+ * private" for illumos.  Hence, we keep the _l version static for now.
+ * If we decide to make this public, just remove the static keyword and
+ * put it in the headers and mapfile.  (Should fix up the underscore prefix
+ * to __nextwctype() as well.)
+ */
+static wint_t
+nextwctype_l(wint_t wc, wctype_t wct, locale_t loc)
 {
 	size_t lim;
-	_RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
-	_RuneEntry *base, *re;
+	const _RuneLocale *rl;
+	const _RuneRange *rr;
+	const _RuneEntry *base, *re;
 	int noinc;
 
+	rl = loc->runelocale;
+	rr = &rl->__runetype_ext;
+
 	noinc = 0;
 	if (wc < _CACHED_RUNES) {
 		wc++;
 		while (wc < _CACHED_RUNES) {
-			if (_CurrentRuneLocale->__runetype[wc] & wct)
+			if (rl->__runetype[wc] & wct)
 				return (wc);
 			wc++;
 		}
@@ -85,4 +98,13 @@
 			return (wc);
 	}
 	return (-1);
+}
+
+/*
+ * External, but consolidation private routine.
+ */
+wint_t
+__nextwctype(wint_t wc, wctype_t wct)
+{
+	return (nextwctype_l(wc, wct, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/nl_langinfo.c	Tue May 20 07:58:49 2014
+++ new/usr/src/lib/libc/port/locale/nl_langinfo.c	Tue May 20 07:58:49 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -36,21 +37,21 @@
 #include "lmessages.h"
 #include "lmonetary.h"
 #include "timelocal.h"
+#include "localeimpl.h"
 
 #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())
-
 #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;
+	struct locdata *ldata;
+	const struct lc_monetary *lmon = loc->monetary;
+	const struct lc_numeric *lnum = loc->numeric;
+	const struct lc_messages *lmsgs = loc->messages;
+	const struct lc_time *ltime = loc->time;
 
 	switch (item) {
 	case CODESET:
@@ -57,12 +58,17 @@
 		ret = "";
 		/*
 		 * The codeset is the suffix of a locale, for most it will
-		 * will be UTF-8, as in "en.UTF-8".  Short form locales are
+		 * will be UTF-8, as in "en_US.UTF-8".  Short form locales are
 		 * not supported.  Note also that although FreeBSD uses
 		 * US-ASCII, Solaris historically has reported "646" for the
 		 * C locale.
+		 *
+		 * Note that this code will need to change if we ever support
+		 * POSIX defined locale variants (suffixes with an @ sign)
 		 */
-		if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
+		ldata = loc->locdata[LC_CTYPE];
+		s = ldata ? ldata->l_lname : NULL;
+		if (s != NULL) {
 			if ((cs = strchr(s, '.')) != NULL)
 				ret = cs + 1;
 			else if (strcmp(s, "C") == 0 || strcmp(s, "POSIX") == 0)
@@ -70,40 +76,40 @@
 		}
 		break;
 	case D_T_FMT:
-		ret = (char *)TIME->c_fmt;
+		ret = (char *)ltime->c_fmt;
 		break;
 	case D_FMT:
-		ret = (char *)TIME->x_fmt;
+		ret = (char *)ltime->x_fmt;
 		break;
 	case T_FMT:
-		ret = (char *)TIME->X_fmt;
+		ret = (char *)ltime->X_fmt;
 		break;
 	case T_FMT_AMPM:
-		ret = (char *)TIME->ampm_fmt;
+		ret = (char *)ltime->ampm_fmt;
 		break;
 	case AM_STR:
-		ret = (char *)TIME->am;
+		ret = (char *)ltime->am;
 		break;
 	case PM_STR:
-		ret = (char *)TIME->pm;
+		ret = (char *)ltime->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 *)TIME->weekday[_REL(DAY_1)];
+		ret = (char *)ltime->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 *)TIME->wday[_REL(ABDAY_1)];
+		ret = (char *)ltime->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 *)TIME->month[_REL(MON_1)];
+		ret = (char *)ltime->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 *)TIME->mon[_REL(ABMON_1)];
+		ret = (char *)ltime->mon[_REL(ABMON_1)];
 		break;
 	case ERA:
 		/* XXX: need to be implemented  */
@@ -126,64 +132,37 @@
 		ret = "";
 		break;
 	case RADIXCHAR:
-		ret = (char *)NUMERIC->decimal_point;
+		ret = (char *)lnum->decimal_point;
 		break;
 	case THOUSEP:
-		ret = (char *)NUMERIC->thousands_sep;
+		ret = (char *)lnum->thousands_sep;
 		break;
 	case YESEXPR:
-		ret = (char *)MESSAGES->yesexpr;
+		ret = (char *)lmsgs->yesexpr;
 		break;
 	case NOEXPR:
-		ret = (char *)MESSAGES->noexpr;
+		ret = (char *)lmsgs->noexpr;
 		break;
 	/*
-	 * YESSTR and NOSTR items marked with LEGACY are available, but not
-	 * recomended by SUSv2 to be used in portable applications since
-	 * they're subject to remove in future specification editions.
+	 * YESSTR and NOSTR items were removed from Issue 7.  But
+	 * older applications might still need them.  Their use is
+	 * discouraged.
 	 */
 	case YESSTR:	/* LEGACY  */
-		ret = (char *)MESSAGES->yesstr;
+		ret = (char *)lmsgs->yesstr;
 		break;
 	case NOSTR:	/* LEGACY  */
-		ret = (char *)MESSAGES->nostr;
+		ret = (char *)lmsgs->nostr;
 		break;
 	/*
 	 * SUSv2 special formatted currency string
 	 */
 	case CRNCYSTR:
-		ret = "";
-		cs = (char *)MONETARY->currency_symbol;
-		if (*cs != '\0') {
-			char pos = localeconv()->p_cs_precedes;
-
-			if (pos == localeconv()->n_cs_precedes) {
-				char psn = '\0';
-
-				if (pos == CHAR_MAX) {
-					if (strcmp(cs,
-					    MONETARY->mon_decimal_point) == 0)
-						psn = '.';
-				} else
-					psn = pos ? '-' : '+';
-				if (psn != '\0') {
-					int clen = strlen(cs);
-					char *newc;
-
-					newc = realloc(csym, clen + 2);
-					if (newc != NULL) {
-						free(csym);
-						csym = newc;
-						*csym = psn;
-						(void) strcpy(csym + 1, cs);
-						ret = csym;
-					}
-				}
-			}
-		}
+		ret = lmon->crncystr;
 		break;
+
 	case _DATE_FMT:		/* Solaris specific extension */
-		ret = (char *)TIME->date_fmt;
+		ret = (char *)ltime->date_fmt;
 		break;
 	/*
 	 * Note that FreeBSD also had a private D_MD_ORDER, but that appears
@@ -193,4 +172,10 @@
 		ret = "";
 	}
 	return (ret);
+}
+
+char *
+nl_langinfo(nl_item item)
+{
+	return (nl_langinfo_l(item, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/none.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/none.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
  * Copyright (c) 1993
@@ -41,40 +42,25 @@
 #include <string.h>
 #include <wchar.h>
 #include <note.h>
-#include "runetype.h"
 #include "mblocal.h"
+#include "lctype.h"
 
-static size_t	_none_mbrtowc(wchar_t *_RESTRICT_KYWD,
-    const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
-
-static int	_none_mbsinit(const mbstate_t *);
-static size_t	_none_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst,
-    const char **_RESTRICT_KYWD src, size_t nms, size_t len,
-    mbstate_t *_RESTRICT_KYWD);
-static size_t	_none_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
-    mbstate_t *_RESTRICT_KYWD);
-static size_t	_none_wcsnrtombs(char *_RESTRICT_KYWD,
-    const wchar_t **_RESTRICT_KYWD,
-    size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-
 /* setup defaults */
 
-int
-_none_init(_RuneLocale *rl)
+void
+_none_init(struct lc_ctype *lct)
 {
-	charset_is_ascii = 1;
-
-	__mbrtowc = _none_mbrtowc;
-	__mbsinit = _none_mbsinit;
-	__mbsnrtowcs = _none_mbsnrtowcs;
-	__wcrtomb = _none_wcrtomb;
-	__wcsnrtombs = _none_wcsnrtombs;
-	_CurrentRuneLocale = rl;
-	return (0);
+	lct->lc_is_ascii = 1;
+	lct->lc_mbrtowc = __mbrtowc_ascii;
+	lct->lc_mbsinit = __mbsinit_ascii;
+	lct->lc_mbsnrtowcs = __mbsnrtowcs_ascii;
+	lct->lc_wcrtomb = __wcrtomb_ascii;
+	lct->lc_wcsnrtombs = __wcsnrtombs_ascii;
+	lct->lc_max_mblen = 1;
 }
 
-static int
-_none_mbsinit(const mbstate_t *unused)
+int
+__mbsinit_ascii(const mbstate_t *unused)
 {
 	_NOTE(ARGUNUSED(unused));
 
@@ -85,8 +71,8 @@
 	return (1);
 }
 
-static size_t
-_none_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+size_t
+__mbrtowc_ascii(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
     size_t n, mbstate_t *_RESTRICT_KYWD unused)
 {
 	_NOTE(ARGUNUSED(unused));
@@ -102,8 +88,8 @@
 	return (*s == '\0' ? 0 : 1);
 }
 
-static size_t
-_none_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc,
+size_t
+__wcrtomb_ascii(char *_RESTRICT_KYWD s, wchar_t wc,
     mbstate_t *_RESTRICT_KYWD unused)
 {
 	_NOTE(ARGUNUSED(unused));
@@ -119,8 +105,8 @@
 	return (1);
 }
 
-static size_t
-_none_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
+size_t
+__mbsnrtowcs_ascii(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
     size_t nms, size_t len, mbstate_t *_RESTRICT_KYWD unused)
 {
 	const char *s;
@@ -146,8 +132,8 @@
 	return (nchr);
 }
 
-static size_t
-_none_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+size_t
+__wcsnrtombs_ascii(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
     size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD unused)
 {
 	const wchar_t *s;
@@ -181,19 +167,3 @@
 	*src = s;
 	return (nchr);
 }
-
-/* setup defaults */
-
-size_t (*__mbrtowc)(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
-    size_t, mbstate_t *_RESTRICT_KYWD) = _none_mbrtowc;
-
-int (*__mbsinit)(const mbstate_t *) = _none_mbsinit;
-
-size_t (*__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
-    size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_mbsnrtowcs;
-
-size_t (*__wcrtomb)(char *_RESTRICT_KYWD, wchar_t, mbstate_t *_RESTRICT_KYWD) =
-    _none_wcrtomb;
-
-size_t (*__wcsnrtombs)(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
-    size_t, size_t, mbstate_t *_RESTRICT_KYWD) = _none_wcsnrtombs;
--- old/usr/src/lib/libc/port/locale/regcomp.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/regcomp.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2012 Milan Jurik. All rights reserved.
  * Copyright (c) 1992, 1993, 1994 Henry Spencer.
@@ -725,6 +726,7 @@
 	char c;
 	wint_t start, finish;
 	wint_t i;
+	locale_t loc = uselocale(NULL);
 
 	/* classify what we've got */
 	switch ((MORE()) ? PEEK() : '\0') {
@@ -772,16 +774,18 @@
 		if (start == finish)
 			CHadd(p, cs, start);
 		else {
-			if (_collate_load_error) {
+			if (loc->collate->lc_is_posix) {
 				(void) REQUIRE((uch)start <= (uch)finish,
 				    REG_ERANGE);
 				CHaddrange(p, cs, start, finish);
 			} else {
 				(void) REQUIRE(_collate_range_cmp(start,
-				    finish) <= 0, REG_ERANGE);
+				    finish, loc) <= 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(start, i, loc)
+					    <= 0 &&
+					    _collate_range_cmp(i, finish, loc)
+					    <= 0)
 						CHadd(p, cs, i);
 				}
 			}
@@ -1367,6 +1371,7 @@
 	char buf[MB_LEN_MAX];
 	size_t clen;
 	mbstate_t mbs;
+	locale_t loc = uselocale(NULL);
 
 	/* avoid making error situations worse */
 	if (p->error != 0)
@@ -1378,7 +1383,7 @@
 	 * UTF-8 (see RFC 3629).
 	 */
 	if (MB_CUR_MAX > 1 &&
-	    strcmp(_CurrentRuneLocale->__encoding, "UTF-8") != 0)
+	    strcmp(loc->runelocale->__encoding, "UTF-8") != 0)
 		return;
 
 	/* find the longest OCHAR sequence in strip */
--- old/usr/src/lib/libc/port/locale/rune.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/rune.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -39,14 +40,15 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "runetype.h"
 #include "runefile.h"
 
-_RuneLocale *_Read_RuneMagi(FILE *);
-
 _RuneLocale *
-_Read_RuneMagi(FILE *fp)
+_Read_RuneMagi(const char *fname)
 {
 	char *fdata, *data;
 	void *lastp;
@@ -61,31 +63,30 @@
 	_FileRuneEntry *maplower_ext_ranges;
 	_FileRuneEntry *mapupper_ext_ranges;
 	int runetype_ext_len = 0;
+	int fd;
 
-	if (fstat(fileno(fp), &sb) < 0)
+	if ((fd = open(fname, O_RDONLY)) < 0) {
+		errno = EINVAL;
 		return (NULL);
+	}
 
-	if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
+	if (fstat(fd, &sb) < 0) {
+		(void) close(fd);
 		errno = EINVAL;
 		return (NULL);
 	}
 
-	if ((fdata = malloc(sb.st_size)) == NULL)
+	if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
+		(void) close(fd);
+		errno = EINVAL;
 		return (NULL);
-
-	errno = 0;
-	rewind(fp); /* Someone might have read the magic number once already */
-	if (errno) {
-		saverr = errno;
-		free(fdata);
-		errno = saverr;
-		return (NULL);
 	}
 
-	if (fread(fdata, sb.st_size, 1, fp) != 1) {
-		saverr = errno;
-		free(fdata);
-		errno = saverr;
+
+	fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	(void) close(fd);
+	if (fdata == NULL) {
+		errno = EINVAL;
 		return (NULL);
 	}
 
@@ -95,33 +96,25 @@
 	variable = frl + 1;
 
 	if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
-		free(fdata);
-		errno = EINVAL;
-		return (NULL);
+		goto invalid;
 	}
 
 	runetype_ext_ranges = (_FileRuneEntry *)variable;
 	variable = runetype_ext_ranges + frl->runetype_ext_nranges;
 	if (variable > lastp) {
-		free(fdata);
-		errno = EINVAL;
-		return (NULL);
+		goto invalid;
 	}
 
 	maplower_ext_ranges = (_FileRuneEntry *)variable;
 	variable = maplower_ext_ranges + frl->maplower_ext_nranges;
 	if (variable > lastp) {
-		free(fdata);
-		errno = EINVAL;
-		return (NULL);
+		goto invalid;
 	}
 
 	mapupper_ext_ranges = (_FileRuneEntry *)variable;
 	variable = mapupper_ext_ranges + frl->mapupper_ext_nranges;
 	if (variable > lastp) {
-		free(fdata);
-		errno = EINVAL;
-		return (NULL);
+		goto invalid;
 	}
 
 	frr = runetype_ext_ranges;
@@ -134,17 +127,13 @@
 			variable = types + len;
 			runetype_ext_len += len;
 			if (variable > lastp) {
-				free(fdata);
-				errno = EINVAL;
-				return (NULL);
+				goto invalid;
 			}
 		}
 	}
 
 	if ((char *)variable + frl->variable_len > (char *)lastp) {
-		free(fdata);
-		errno = EINVAL;
-		return (NULL);
+		goto invalid;
 	}
 
 	/*
@@ -157,7 +146,7 @@
 	    frl->variable_len);
 	if (data == NULL) {
 		saverr = errno;
-		free(fdata);
+		(void) munmap(fdata, sb.st_size);
 		errno = saverr;
 		return (NULL);
 	}
@@ -229,7 +218,7 @@
 	}
 
 	(void) memcpy(rl->__variable, variable, rl->__variable_len);
-	free(fdata);
+	(void) munmap(fdata, sb.st_size);
 
 	/*
 	 * Go out and zero pointers that should be zero.
@@ -247,4 +236,9 @@
 		rl->__mapupper_ext.__ranges = NULL;
 
 	return (rl);
+
+invalid:
+	(void) munmap(fdata, sb.st_size);
+	errno = EINVAL;
+	return (NULL);
 }
--- old/usr/src/lib/libc/port/locale/runetype.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/runetype.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -37,11 +38,11 @@
 #include "runetype.h"
 
 unsigned int
-___runetype(__ct_rune_t c)
+__runetype(const _RuneLocale *rl, __ct_rune_t c)
 {
 	size_t lim;
-	_RuneRange *rr = &_CurrentRuneLocale->__runetype_ext;
-	_RuneEntry *base, *re;
+	const _RuneRange *rr = &rl->__runetype_ext;
+	const _RuneEntry *base, *re;
 
 	if (c < 0 || c == EOF)
 		return (0L);
--- old/usr/src/lib/libc/port/locale/runetype.h	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/runetype.h	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -110,7 +111,7 @@
 
 typedef struct {
 	char		__magic[8];	/* Magic saying what version we are */
-	char		__encoding[32];	/* ASCII name of this encoding */
+	char		__encoding[32];	/* ASCII name of encoding */
 
 	unsigned int	__runetype[_CACHED_RUNES];
 	__rune_t	__maplower[_CACHED_RUNES];
@@ -132,6 +133,7 @@
 #define	_RUNE_MAGIC_1	"RuneMagi"	/* Indicates version 0 of RuneLocale */
 
 extern _RuneLocale _DefaultRuneLocale;
-extern _RuneLocale *_CurrentRuneLocale;
 
+unsigned int __runetype(const _RuneLocale *, int);
+
 #endif	/* !_RUNETYPE_H_ */
--- old/usr/src/lib/libc/port/locale/setlocale.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/setlocale.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1996 - 2002 FreeBSD Project
  * Copyright (c) 1991, 1993
@@ -41,194 +42,72 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <alloca.h>
 #include <stdio.h>
 #include "collate.h"
-#include "lmonetary.h"	/* for __monetary_load_locale() */
-#include "lnumeric.h"	/* for __numeric_load_locale() */
-#include "lmessages.h"	/* for __messages_load_locale() */
+#include "lnumeric.h"	/* for struct lc_numeric */
+#include "lctype.h"	/* for struct lc_ctype */
 #include "setlocale.h"
-#include "ldpart.h"
-#include "timelocal.h" /* for __time_load_locale() */
 #include "../i18n/_loc_path.h"
+#include "localeimpl.h"
+#include "../i18n/_locale.h"
 
 /*
- * Category names for getenv()  Note that this was modified
- * for Solaris.  See <iso/locale_iso.h>.
- */
-#define	NUM_CATS	7
-static char *categories[7] = {
-	"LC_CTYPE",
-	"LC_NUMERIC",
-	"LC_TIME",
-	"LC_COLLATE",
-	"LC_MONETARY",
-	"LC_MESSAGES",
-	"LC_ALL",
-};
-
-/*
- * Current locales for each category
- */
-static char current_categories[NUM_CATS][ENCODING_LEN + 1] = {
-	"C",
-	"C",
-	"C",
-	"C",
-	"C",
-	"C",
-	"C",
-};
-
-/*
  * Path to locale storage directory.  See ../i18n/_loc_path.h
  */
 char	*_PathLocale = _DFLT_LOC_PATH;
 
-/*
- * The locales we are going to try and load
- */
-static char new_categories[NUM_CATS][ENCODING_LEN + 1];
-static char saved_categories[NUM_CATS][ENCODING_LEN + 1];
-static char current_locale_string[NUM_CATS * (ENCODING_LEN + 1 + 1)];
+static char	*current_locale(locale_t, int);
+static void	install_legacy(locale_t, int);
 
-static char	*currentlocale(void);
-static char	*loadlocale(int);
-static const char *__get_locale_env(int);
-
 char *
-setlocale(int category, const char *locale)
+setlocale(int category, const char *locname)
 {
-	int i, j, saverr;
-	const char *env, *r;
+	locale_t oldloc;
+	locale_t newloc;
+	int mask;
 
-	if (category < 0 || category >= NUM_CATS) {
+	if (category < 0 || category > LC_ALL) {
 		errno = EINVAL;
 		return (NULL);
 	}
 
-	if (locale == NULL)
-		return (category != LC_ALL ?
-		    current_categories[category] : currentlocale());
+	if (locname == NULL)
+		return (current_locale(__global_locale, category));
 
-	/*
-	 * Default to the current locale for everything.
-	 */
-	for (i = 0; i < NUM_CATS; ++i)
-		(void) strcpy(new_categories[i], current_categories[i]);
+	if ((oldloc = duplocale(__global_locale)) == NULL)
+		return (NULL);
 
-	/*
-	 * Now go fill up new_categories from the locale argument
-	 */
-	if (!*locale) {
-		if (category == LC_ALL) {
-			for (i = 0; i < NUM_CATS; ++i) {
-				if (i == LC_ALL)
-					continue;
-				env = __get_locale_env(i);
-				if (strlen(env) > ENCODING_LEN) {
-					errno = EINVAL;
-					return (NULL);
-				}
-				(void) strcpy(new_categories[i], env);
-			}
-		} else {
-			env = __get_locale_env(category);
-			if (strlen(env) > ENCODING_LEN) {
-				errno = EINVAL;
-				return (NULL);
-			}
-			(void) strcpy(new_categories[category], env);
-		}
-	} else if (category != LC_ALL) {
-		if (strlen(locale) > ENCODING_LEN) {
-			errno = EINVAL;
-			return (NULL);
-		}
-		(void) strcpy(new_categories[category], locale);
-	} else {
-		if ((r = strchr(locale, '/')) == NULL) {
-			if (strlen(locale) > ENCODING_LEN) {
-				errno = EINVAL;
-				return (NULL);
-			}
-			for (i = 0; i < NUM_CATS; ++i)
-				(void) strcpy(new_categories[i], locale);
-		} else {
-			char	*buf;
-			char	*save;
+	mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
 
-			buf = alloca(strlen(locale) + 1);
-			(void) strcpy(buf, locale);
-
-			save = NULL;
-			r = strtok_r(buf, "/", &save);
-			for (i = 0;  i < NUM_CATS; i++) {
-				if (i == LC_ALL)
-					continue;
-				if (r == NULL) {
-					/*
-					 * Composite Locale is inadequately
-					 * specified!   (Or with empty fields.)
-					 * The old code would fill fields
-					 * out from the last one, but I think
-					 * this is suboptimal.
-					 */
-					errno = EINVAL;
-					return (NULL);
-				}
-				(void) strlcpy(new_categories[i], r,
-				    ENCODING_LEN);
-				r = strtok_r(NULL, "/", &save);
-			}
-			if (r != NULL) {
-				/*
-				 * Too many components - we had left over
-				 * data in the LC_ALL.  It is malformed.
-				 */
-				errno = EINVAL;
-				return (NULL);
-			}
-		}
+	newloc = newlocale(mask, locname, oldloc);
+	if (newloc == NULL) {
+		freelocale(oldloc);
+		return (NULL);
 	}
 
-	if (category != LC_ALL)
-		return (loadlocale(category));
+	oldloc = __global_locale;
+	__global_locale = newloc;
 
-	for (i = 0; i < NUM_CATS; ++i) {
-		(void) strcpy(saved_categories[i], current_categories[i]);
-		if (i == LC_ALL)
-			continue;
-		if (loadlocale(i) == NULL) {
-			saverr = errno;
-			for (j = 0; j < i; j++) {
-				(void) strcpy(new_categories[j],
-				    saved_categories[j]);
-				if (i == LC_ALL)
-					continue;
-				if (loadlocale(j) == NULL) {
-					(void) strcpy(new_categories[j], "C");
-					(void) loadlocale(j);
-				}
-			}
-			errno = saverr;
-			return (NULL);
-		}
-	}
-	return (currentlocale());
+	install_legacy(newloc, mask);
+
+	freelocale(oldloc);
+	return (current_locale(newloc, category));
 }
 
 static char *
-currentlocale(void)
+current_locale(locale_t loc, int cat)
 {
-	int i;
 	int composite = 0;
+	static char buf[LC_ALL * (ENCODING_LEN + 1 + 1)];
 
+	if (cat != LC_ALL) {
+		return (loc->locdata[cat]->l_lname);
+	}
+
 	/* Look to see if any category is different */
-	for (i = 1; i < NUM_CATS; ++i) {
-		if (i == LC_ALL)
-			continue;
-		if (strcmp(current_categories[0], current_categories[i])) {
+	for (int i = 1; i < LC_ALL; ++i) {
+		if (strcmp(loc->locdata[0]->l_lname,
+		    loc->locdata[i]->l_lname) != 0) {
 			composite = 1;
 			break;
 		}
@@ -240,90 +119,63 @@
 		 * if the order is changed, then setlocale() will need
 		 * to be changed as well.
 		 */
-		(void) snprintf(current_locale_string,
-		    sizeof (current_locale_string),
+		(void) snprintf(buf, sizeof (buf),
 		    "%s/%s/%s/%s/%s/%s",
-		    current_categories[LC_CTYPE],
-		    current_categories[LC_NUMERIC],
-		    current_categories[LC_TIME],
-		    current_categories[LC_COLLATE],
-		    current_categories[LC_MONETARY],
-		    current_categories[LC_MESSAGES]);
-	} else {
-		(void) strlcpy(current_locale_string, current_categories[0],
-		    sizeof (current_locale_string));
+		    loc->locdata[LC_CTYPE]->l_lname,
+		    loc->locdata[LC_NUMERIC]->l_lname,
+		    loc->locdata[LC_TIME]->l_lname,
+		    loc->locdata[LC_COLLATE]->l_lname,
+		    loc->locdata[LC_MONETARY]->l_lname,
+		    loc->locdata[LC_MESSAGES]->l_lname);
+		return (buf);
 	}
-	return (current_locale_string);
+
+	return (loc->locdata[0]->l_lname);
 }
 
-static char *
-loadlocale(int category)
+static void
+install_legacy(locale_t loc, int mask)
 {
-	char *new = new_categories[category];
-	char *old = current_categories[category];
-	int (*func)(const char *);
-
-	if ((new[0] == '.' &&
-	    (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
-	    strchr(new, '/') != NULL) {
-		errno = EINVAL;
-		return (NULL);
+	/*
+	 * Update the legacy fixed variables that may be baked into
+	 * legacy programs.  This is really unfortunate, but we can't
+	 * solve for them otherwise.  Note that such legacy programs
+	 * are only going to see the global locale settings, and cannot
+	 * benefit from uselocale().
+	 */
+	if (mask & LC_NUMERIC_MASK) {
+		struct lc_numeric *lnum;
+		lnum = loc->locdata[LC_NUMERIC]->l_data[0];
+		_numeric[0] = *lnum->decimal_point;
+		_numeric[1] = *lnum->thousands_sep;
 	}
 
-	switch (category) {
-	case LC_CTYPE:
-		func = __wrap_setrunelocale;
-		break;
-	case LC_COLLATE:
-		func = _collate_load_tables;
-		break;
-	case LC_TIME:
-		func = __time_load_locale;
-		break;
-	case LC_NUMERIC:
-		func = __numeric_load_locale;
-		break;
-	case LC_MONETARY:
-		func = __monetary_load_locale;
-		break;
-	case LC_MESSAGES:
-		func = __messages_load_locale;
-		break;
-	default:
-		errno = EINVAL;
-		return (NULL);
-	}
+	if (mask & LC_CTYPE_MASK) {
+		struct lc_ctype *lct;
+		lct = loc->locdata[LC_CTYPE]->l_data[0];
+		for (int i = 0; i < _CACHED_RUNES; i++) {
+			/* ctype can only encode the lower 8 bits. */
+			__ctype[i+1] = lct->lc_ctype_mask[i] & 0xff;
+			__ctype_mask[i] = lct->lc_ctype_mask[i];
+		}
 
-	if (strcmp(new, old) == 0)
-		return (old);
+		/* The bottom half is the toupper/lower array */
+		for (int i = 0; i < _CACHED_RUNES; i++) {
+			int u, l;
+			__ctype[258 + i] = i;
+			u = lct->lc_trans_upper[i];
+			l = lct->lc_trans_lower[i];
+			if (u && u != i)
+				__ctype[258+i] = u;
+			if (l && l != i)
+				__ctype[258+i] = l;
 
-	if (func(new) != _LDP_ERROR) {
-		(void) strcpy(old, new);
-		return (old);
-	}
+			/* Don't forget these annoyances either! */
+			__trans_upper[i] = u;
+			__trans_lower[i] = l;
+		}
 
-	return (NULL);
-}
-
-static const char *
-__get_locale_env(int category)
-{
-	const char *env;
-
-	/* 1. check LC_ALL. */
-	env = getenv(categories[LC_ALL]);
-
-	/* 2. check LC_* */
-	if (env == NULL || !*env)
-		env = getenv(categories[category]);
-
-	/* 3. check LANG */
-	if (env == NULL || !*env)
-		env = getenv("LANG");
-
-	/* 4. if none is set, fall to "C" */
-	if (env == NULL || !*env)
-		env = "C";
-
-	return (env);
+		/* Maximum mblen, cswidth, weird legacy */
+		__ctype[520] = lct->lc_max_mblen;
+	}
 }
--- old/usr/src/lib/libc/port/locale/setlocale.h	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/setlocale.h	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia.
  * All rights reserved.
  *
@@ -33,7 +34,4 @@
 
 extern char *_PathLocale;
 
-int	__detect_path_locale(void);
-int	__wrap_setrunelocale(const char *);
-
 #endif /* !_SETLOCALE_H_ */
--- old/usr/src/lib/libc/port/locale/setrunelocale.c	Tue May 20 07:58:50 2014
+++ new/usr/src/lib/libc/port/locale/setrunelocale.c	Tue May 20 07:58:50 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -45,208 +46,104 @@
 #include "mblocal.h"
 #include "setlocale.h"
 #include "_ctype.h"
-#include "../i18n/_locale.h"
+#include "lctype.h"
+#include "localeimpl.h"
 
-extern _RuneLocale	*_Read_RuneMagi(FILE *);
-extern unsigned char	__ctype_C[];
+extern _RuneLocale	*_Read_RuneMagi(const char *);
 
-static int		__setrunelocale(const char *);
+struct lc_ctype lc_ctype_posix = {
+	.lc_mbrtowc = __mbrtowc_ascii,
+	.lc_mbsinit = __mbsinit_ascii,
+	.lc_mbsnrtowcs = __mbsnrtowcs_ascii,
+	.lc_wcrtomb = __wcrtomb_ascii,
+	.lc_wcsnrtombs = __wcsnrtombs_ascii,
+	.lc_is_ascii = 1,
+	.lc_max_mblen = 1,
+	.lc_trans_upper = _DefaultRuneLocale.__mapupper,
+	.lc_trans_lower = _DefaultRuneLocale.__maplower,
+	.lc_ctype_mask = _DefaultRuneLocale.__runetype,
+};
 
-static int
-__setrunelocale(const char *encoding)
-{
-	FILE *fp;
-	char name[PATH_MAX];
-	_RuneLocale *rl;
-	int saverr, ret;
-	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,
-	    mbstate_t *_RESTRICT_KYWD);
-	int (*old__mbsinit)(const mbstate_t *);
-	size_t (*old__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
-	    const char **_RESTRICT_KYWD, size_t, size_t,
-	    mbstate_t *_RESTRICT_KYWD);
-	size_t (*old__wcsnrtombs)(char *_RESTRICT_KYWD,
-	    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
-	    mbstate_t *_RESTRICT_KYWD);
-	static char ctype_encoding[ENCODING_LEN + 1];
-	static _RuneLocale *CachedRuneLocale;
-	static size_t (*Cached__mbrtowc)(wchar_t *_RESTRICT_KYWD,
-	    const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
-	static size_t (*Cached__wcrtomb)(char *_RESTRICT_KYWD, wchar_t,
-	    mbstate_t *_RESTRICT_KYWD);
-	static int (*Cached__mbsinit)(const mbstate_t *);
-	static size_t (*Cached__mbsnrtowcs)(wchar_t *_RESTRICT_KYWD,
-	    const char **_RESTRICT_KYWD, size_t, size_t,
-	    mbstate_t *_RESTRICT_KYWD);
-	static size_t (*Cached__wcsnrtombs)(char *_RESTRICT_KYWD,
-	    const wchar_t **_RESTRICT_KYWD, size_t, size_t,
-	    mbstate_t *_RESTRICT_KYWD);
+struct locdata __posix_ctype_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_ctype_posix, &_DefaultRuneLocale }
+};
 
-	/*
-	 * The "C" and "POSIX" locale are always here.
-	 */
-	if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
-		int i;
 
-		(void) memcpy(__ctype, __ctype_C, SZ_TOTAL);
+/*
+ * Table of initializers for encodings.  When you add a new encoding type,
+ * this table should be updated.
+ */
+static struct {
+	const char *e_name;
+	void (*e_init)(struct lc_ctype *);
+} encodings[] = {
+	{ "NONE", _none_init },
+	{ "UTF-8",	_UTF8_init },
+	{ "EUC-CN",	_EUC_CN_init },
+	{ "EUC-JP",	_EUC_JP_init },
+	{ "EUC-KR",	_EUC_KR_init },
+	{ "EUC-TW",	_EUC_TW_init },
+	{ "GB18030",	_GB18030_init },
+	{ "GB2312",	_GB2312_init },
+	{ "GBK",	_GBK_init },
+	{ "BIG5",	_BIG5_init },
+	{ "MSKanji",	_MSKanji_init },
+	{ NULL,		NULL }
+};
 
-		for (i = 0; i < _CACHED_RUNES; i++) {
-			__ctype_mask[i] = _DefaultRuneLocale.__runetype[i];
-			__trans_upper[i] = _DefaultRuneLocale.__mapupper[i];
-			__trans_lower[i] = _DefaultRuneLocale.__maplower[i];
-		}
 
-		(void) _none_init(&_DefaultRuneLocale);
-		return (0);
-	}
+struct locdata *
+__lc_ctype_load(const char *name)
+{
+	struct locdata *ldata;
+	struct lc_ctype *lct;
+	_RuneLocale *rl;
+	int i;
+	char path[PATH_MAX];
 
+	if ((ldata = __locdata_alloc(name, sizeof (*lct))) == NULL)
+		return (NULL);
+	lct = ldata->l_data[0];
 	/*
-	 * If the locale name is the same as our cache, use the cache.
-	 */
-	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;
-		return (0);
-	}
-
-	/*
 	 * Slurp the locale file into the cache.
 	 */
 
-	(void) snprintf(name, sizeof (name), "%s/%s/LC_CTYPE/LCL_DATA",
-	    _PathLocale, encoding);
+	(void) snprintf(path, sizeof (path), "%s/%s/LC_CTYPE/LCL_DATA",
+	    _PathLocale, name);
 
-	if ((fp = fopen(name, "r")) == NULL)
-		return (errno == 0 ? ENOENT : errno);
-
-	if ((rl = _Read_RuneMagi(fp)) == NULL) {
-		saverr = (errno == 0 ? EINVAL : errno);
-		(void) fclose(fp);
-		return (saverr);
+	if ((rl = _Read_RuneMagi(path)) == NULL) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
 	}
-	(void) fclose(fp);
+	ldata->l_data[1] = rl;
 
-	old__mbrtowc = __mbrtowc;
-	old__mbsinit = __mbsinit;
-	old__mbsnrtowcs = __mbsnrtowcs;
-	old__wcrtomb = __wcrtomb;
-	old__wcsnrtombs = __wcsnrtombs;
+	lct->lc_mbrtowc = NULL;
+	lct->lc_mbsinit = NULL;
+	lct->lc_mbsnrtowcs = NULL;
+	lct->lc_wcrtomb = NULL;
+	lct->lc_wcsnrtombs = NULL;
+	lct->lc_ctype_mask = rl->__runetype;
+	lct->lc_trans_upper = rl->__mapupper;
+	lct->lc_trans_lower = rl->__maplower;
 
-	__mbrtowc = NULL;
-	__mbsinit = NULL;
-	__mbsnrtowcs = __mbsnrtowcs_std;
-	__wcrtomb = NULL;
-	__wcsnrtombs = __wcsnrtombs_std;
-
-	if (strcmp(rl->__encoding, "NONE") == 0)
-		ret = _none_init(rl);
-	else if (strcmp(rl->__encoding, "UTF-8") == 0)
-		ret = _UTF8_init(rl);
-	else if (strcmp(rl->__encoding, "EUC-CN") == 0)
-		ret = _EUC_CN_init(rl);
-	else if (strcmp(rl->__encoding, "EUC-JP") == 0)
-		ret = _EUC_JP_init(rl);
-	else if (strcmp(rl->__encoding, "EUC-KR") == 0)
-		ret = _EUC_KR_init(rl);
-	else if (strcmp(rl->__encoding, "EUC-TW") == 0)
-		ret = _EUC_TW_init(rl);
-	else if (strcmp(rl->__encoding, "GB18030") == 0)
-		ret = _GB18030_init(rl);
-	else if (strcmp(rl->__encoding, "GB2312") == 0)
-		ret = _GB2312_init(rl);
-	else if (strcmp(rl->__encoding, "GBK") == 0)
-		ret = _GBK_init(rl);
-	else if (strcmp(rl->__encoding, "BIG5") == 0)
-		ret = _BIG5_init(rl);
-	else if (strcmp(rl->__encoding, "MSKanji") == 0)
-		ret = _MSKanji_init(rl);
-	else
-		ret = EINVAL;
-
-	if (ret == 0) {
-		if (CachedRuneLocale != NULL) {
-			free(CachedRuneLocale);
+	/* set up the function pointers */
+	for (i = 0; encodings[i].e_name != NULL; i++) {
+		int l = strlen(encodings[i].e_name);
+		if ((strncmp(rl->__encoding, encodings[i].e_name, l) == 0) &&
+		    (rl->__encoding[l] == '\0' || rl->__encoding[l] == '@')) {
+			encodings[i].e_init(lct);
+			break;
 		}
-		CachedRuneLocale = _CurrentRuneLocale;
-		Cached__mbrtowc = __mbrtowc;
-		Cached__mbsinit = __mbsinit;
-		Cached__mbsnrtowcs = __mbsnrtowcs;
-		Cached__wcrtomb = __wcrtomb;
-		Cached__wcsnrtombs = __wcsnrtombs;
-		(void) strcpy(ctype_encoding, encoding);
-
-		/*
-		 * We need to overwrite the _ctype array.  This requires
-		 * some finagling.  This is because references to it may
-		 * have been baked into applications.
-		 *
-		 * Note that it is interesting that toupper/tolower only
-		 * produce defined results when the input is representable
-		 * as a byte.
-		 */
-
-		/*
-		 * The top half is the type mask array.  Because we
-		 * want to support both legacy Solaris code (which have
-		 * mask valeus baked in to them), and we want to be able
-		 * to import locale files from other sources (FreeBSD)
-		 * which probably uses different masks, we have to perform
-		 * a conversion here.  Ugh.  Note that the _CTYPE definitions
-		 * we use from FreeBSD are richer than the Solaris legacy.
-		 *
-		 * We have to cope with these limitations though, because the
-		 * inadequate Solaris definitions were baked into binaries.
-		 */
-		for (int i = 0; i < _CACHED_RUNES; i++) {
-			/* ctype can only encode the lower 8 bits. */
-			__ctype[i+1] = rl->__runetype[i] & 0xff;
-			__ctype_mask[i] = rl->__runetype[i];
-		}
-
-		/* The bottom half is the toupper/lower array */
-		for (int i = 0; i < _CACHED_RUNES; i++) {
-			__ctype[258 + i] = i;
-			if (rl->__mapupper[i] && rl->__mapupper[i] != i)
-				__ctype[258+i] = rl->__mapupper[i];
-			if (rl->__maplower[i] && rl->__maplower[i] != i)
-				__ctype[258+i] = rl->__maplower[i];
-
-			/* Don't forget these annoyances either! */
-			__trans_upper[i] = rl->__mapupper[i];
-			__trans_lower[i] = rl->__maplower[i];
-		}
-
-		/*
-		 * Note that we expect the init code will have populated
-		 * the CSWIDTH array (__ctype[514-520]) properly.
-		 */
-	} else {
-		__mbrtowc = old__mbrtowc;
-		__mbsinit = old__mbsinit;
-		__mbsnrtowcs = old__mbsnrtowcs;
-		__wcrtomb = old__wcrtomb;
-		__wcsnrtombs = old__wcsnrtombs;
-		free(rl);
 	}
+	if (encodings[i].e_name == NULL) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
+	}
 
-	return (ret);
-}
 
-int
-__wrap_setrunelocale(const char *locale)
-{
-	int ret = __setrunelocale(locale);
-
-	if (ret != 0) {
-		errno = ret;
-		return (_LDP_ERROR);
-	}
-	return (_LDP_LOADED);
+	return (ldata);
 }
--- old/usr/src/lib/libc/port/i18n/strcasecmp.c	Tue May 20 07:58:51 2014
+++ /dev/null	Tue May 20 07:58:48 2014
@@ -1,63 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-/*
- * Portions of this source code were derived from Berkeley 4.3 BSD
- * under license from the Regents of the University of California.
- */
-
-#include "lint.h"
-#include <sys/types.h>
-#include <strings.h>
-#include <ctype.h>
-
-int
-strcasecmp(const char *s1, const char *s2)
-{
-	extern int charset_is_ascii;
-	extern int ascii_strcasecmp(const char *s1, const char *s2);
-	int *cm;
-	const uchar_t *us1;
-	const uchar_t *us2;
-
-	/*
-	 * If we are in a locale that uses the ASCII character set
-	 * (C or POSIX), use the fast ascii_strcasecmp() function.
-	 */
-	if (charset_is_ascii)
-		return (ascii_strcasecmp(s1, s2));
-
-	cm = __trans_lower;
-	us1 = (const uchar_t *)s1;
-	us2 = (const uchar_t *)s2;
-
-	while (cm[*us1] == cm[*us2++])
-		if (*us1++ == '\0')
-			return (0);
-	return (cm[*us1] - cm[*(us2 - 1)]);
-}
--- /dev/null	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/strcasecmp.c	Tue May 20 07:58:51 2014
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include "lint.h"
+#include <sys/types.h>
+#include <strings.h>
+#include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
+
+int
+strcasecmp_l(const char *s1, const char *s2, locale_t loc)
+{
+	extern int ascii_strcasecmp(const char *s1, const char *s2);
+	const int *cm;
+	const uchar_t *us1;
+	const uchar_t *us2;
+	const struct lc_ctype *lct = loc->ctype;
+
+	/*
+	 * If we are in a locale that uses the ASCII character set
+	 * (C or POSIX), use the fast ascii_strcasecmp() function.
+	 */
+	if (lct->lc_is_ascii)
+		return (ascii_strcasecmp(s1, s2));
+
+	cm = lct->lc_trans_lower;
+	us1 = (const uchar_t *)s1;
+	us2 = (const uchar_t *)s2;
+
+	while (cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return (0);
+	return (cm[*us1] - cm[*(us2 - 1)]);
+}
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+	/* would be nice to avoid uselocale()... but I don't see how */
+	return (strcasecmp_l(s1, s2, uselocale(NULL)));
+}
--- old/usr/src/lib/libc/port/i18n/strcasestr.c	Tue May 20 07:58:51 2014
+++ /dev/null	Tue May 20 07:58:48 2014
@@ -1,69 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*	Copyright (c) 1988 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-#include "lint.h"
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-
-/*
- * strcasestr() locates the first occurrence in the string s1 of the
- * sequence of characters (excluding the terminating null character)
- * in the string s2, ignoring case.  strcasestr() returns a pointer
- * to the located string, or a null pointer if the string is not found.
- * If s2 is empty, the function returns s1.
- */
-
-char *
-strcasestr(const char *s1, const char *s2)
-{
-	int *cm = __trans_lower;
-	const uchar_t *us1 = (const uchar_t *)s1;
-	const uchar_t *us2 = (const uchar_t *)s2;
-	const uchar_t *tptr;
-	int c;
-
-	if (us2 == NULL || *us2 == '\0')
-		return ((char *)us1);
-
-	c = cm[*us2];
-	while (*us1 != '\0') {
-		if (c == cm[*us1++]) {
-			tptr = us1;
-			while (cm[c = *++us2] == cm[*us1++] && c != '\0')
-				continue;
-			if (c == '\0')
-				return ((char *)tptr - 1);
-			us1 = tptr;
-			us2 = (const uchar_t *)s2;
-			c = cm[*us2];
-		}
-	}
-
-	return (NULL);
-}
--- /dev/null	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/strcasestr.c	Tue May 20 07:58:51 2014
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*	Copyright (c) 1988 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+#include "lint.h"
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <locale.h>
+#include "lctype.h"
+#include "localeimpl.h"
+
+/*
+ * strcasestr() locates the first occurrence in the string s1 of the
+ * sequence of characters (excluding the terminating null character)
+ * in the string s2, ignoring case.  strcasestr() returns a pointer
+ * to the located string, or a null pointer if the string is not found.
+ * If s2 is empty, the function returns s1.
+ */
+
+char *
+strcasestr_l(const char *s1, const char *s2, locale_t loc)
+{
+	const int *cm = loc->ctype->lc_trans_lower;
+	const uchar_t *us1 = (const uchar_t *)s1;
+	const uchar_t *us2 = (const uchar_t *)s2;
+	const uchar_t *tptr;
+	int c;
+
+	if (us2 == NULL || *us2 == '\0')
+		return ((char *)us1);
+
+	c = cm[*us2];
+	while (*us1 != '\0') {
+		if (c == cm[*us1++]) {
+			tptr = us1;
+			while (cm[c = *++us2] == cm[*us1++] && c != '\0')
+				continue;
+			if (c == '\0')
+				return ((char *)tptr - 1);
+			us1 = tptr;
+			us2 = (const uchar_t *)s2;
+			c = cm[*us2];
+		}
+	}
+
+	return (NULL);
+}
+
+char *
+strcasestr(const char *s1, const char *s2)
+{
+	return (strcasestr_l(s1, s2, uselocale(NULL)));
+}
--- old/usr/src/lib/libc/port/locale/strcoll.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/strcoll.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
  *		at Electronni Visti IA, Kiev, Ukraine.
@@ -33,6 +34,8 @@
 #include <string.h>
 #include <errno.h>
 #include <wchar.h>
+#include <xlocale.h>
+#include "localeimpl.h"
 #include "collate.h"
 
 #define	ALLOCA_LIMIT	16
@@ -44,16 +47,20 @@
  * should check errno.
  */
 int
-strcoll(const char *s1, const char *s2)
+strcoll_l(const char *s1, const char *s2, locale_t loc)
 {
 	int ret;
 	wchar_t *t1 = NULL, *t2 = NULL;
 	wchar_t *w1 = NULL, *w2 = NULL;
 	size_t sz1, sz2;
+	const struct lc_collate *lcc = loc->collate;
 
-	if (_collate_load_error)
-		goto error;
+	mbstate_t mbs1 = { 0 };	/* initial states */
+	mbstate_t mbs2 = { 0 };
 
+	if (lcc->lc_is_posix)
+		return (strcmp(s1, s2));
+
 	sz1 = strlen(s1) + 1;
 	sz2 = strlen(s2) + 1;
 
@@ -82,13 +89,13 @@
 			goto error;
 	}
 
-	if ((mbstowcs(w1, s1, sz1)) == (size_t)-1)
+	if ((mbsrtowcs_l(w1, &s1, sz1, &mbs1, loc)) == (size_t)-1)
 		goto error;
 
-	if ((mbstowcs(w2, s2, sz2)) == (size_t)-1)
+	if ((mbsrtowcs_l(w2, &s2, sz2, &mbs2, loc)) == (size_t)-1)
 		goto error;
 
-	ret = wcscoll(w1, w2);
+	ret = wcscoll_l(w1, w2, loc);
 	if (t1)
 		free(t1);
 	if (t2)
@@ -102,4 +109,10 @@
 	if (t2)
 		free(t2);
 	return (strcmp(s1, s2));
+}
+
+int
+strcoll(const char *s1, const char *s2)
+{
+	return (strcoll_l(s1, s2, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/strfmon.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/strfmon.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -41,6 +42,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "localeimpl.h"
+#include "lmonetary.h"
+#include "lnumeric.h"
 
 /* internal flags */
 #define	NEED_GROUPING		0x01	/* print digits grouped (default) */
@@ -60,7 +64,7 @@
 }
 
 #define	PRINTS(STR) {						\
-	char *tmps = STR;					\
+	const char *tmps = STR;					\
 	while (*tmps != '\0')					\
 		PRINT(*tmps++);					\
 }
@@ -87,22 +91,23 @@
 }
 
 #define	GRPSEP {						\
-	*--bufend = thousands_sep;				\
+	bufend -= thousands_len;				\
+	(void) memcpy(bufend, thousands_sep, thousands_len);	\
 	groups++;						\
 }
 
-static void __setup_vars(int, char *, char *, char *, char **);
-static int __calc_left_pad(int, char *);
-static char *__format_grouped_double(double, int *, int, int, int);
+static void setup_vars(const struct lc_monetary *, int, char *, char *, char *,
+    const char **);
+static int calc_left_pad(const struct lc_monetary *, int, const char *);
+static char *format_grouped_double(const struct lc_monetary *,
+    const struct lc_numeric *, double, int *, int, int, int);
 
 ssize_t
-strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
-    const char *_RESTRICT_KYWD format, ...)
+strfmon_impl(char *_RESTRICT_KYWD s, size_t maxsize, locale_t loc,
+    const char *_RESTRICT_KYWD 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 */
 	char		*asciivalue;	/* formatted double pointer */
 
 	int		flags;		/* formatting options */
@@ -114,18 +119,20 @@
 	double		value;		/* just value */
 	char		space_char = ' '; /* space after currency */
 
-	char		cs_precedes;	/* values gathered from struct lconv */
+	char		cs_precedes;	/* values from struct lc_monetary */
 	char		sep_by_space;
 	char		sign_posn;
-	char		*signstr;
-	char		*currency_symbol;
+	const char	*signstr;
+	const char	*currency_symbol;
 
 	char		*tmpptr;	/* temporary vars */
 	int		sverrno;
+	const struct lc_monetary *lmon;		/* monetary structure */
+	const struct lc_numeric *lnum;		/* numeric structure */
 
-	va_start(ap, format);
+	lmon = loc->monetary;
+	lnum = loc->numeric;
 
-	lc = localeconv();
 	dst = s;
 	fmt = format;
 	asciivalue = NULL;
@@ -231,18 +238,14 @@
 				goto format_error;
 		}
 
-		if (currency_symbol != NULL)
-			free(currency_symbol);
 		if (flags & USE_INTL_CURRENCY) {
-			currency_symbol = strdup(lc->int_curr_symbol);
+			currency_symbol = lmon->int_curr_symbol;
+			/* by definition three letters followed by a space */
 			if (currency_symbol != NULL)
-				space_char = *(currency_symbol+3);
+				space_char = currency_symbol[3];
 		} else
-			currency_symbol = strdup(lc->currency_symbol);
+			currency_symbol = lmon->currency_symbol;
 
-		if (currency_symbol == NULL)
-			goto end_error;			/* ENOMEM. */
-
 		/* value itself */
 		value = va_arg(ap, double);
 
@@ -254,9 +257,9 @@
 
 		/* fill left_prec with amount of padding chars */
 		if (left_prec >= 0) {
-			pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
+			pad_size = calc_left_pad(lmon, (flags ^ IS_NEGATIVE),
 			    currency_symbol) -
-			    __calc_left_pad(flags, currency_symbol);
+			    calc_left_pad(lmon, flags, currency_symbol);
 			if (pad_size < 0)
 				pad_size = 0;
 		}
@@ -263,7 +266,7 @@
 
 		if (asciivalue != NULL)
 			free(asciivalue);
-		asciivalue = __format_grouped_double(value, &flags,
+		asciivalue = format_grouped_double(lmon, lnum, value, &flags,
 		    left_prec, right_prec, pad_char);
 		if (asciivalue == NULL)
 			goto end_error;		/* errno already set */
@@ -270,8 +273,8 @@
 						/* to ENOMEM by malloc() */
 
 		/* set some variables for later use */
-		__setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn,
-		    &signstr);
+		setup_vars(lmon, flags, &cs_precedes, &sep_by_space,
+		    &sign_posn, &signstr);
 
 		/*
 		 * Description of some LC_MONETARY's values:
@@ -315,7 +318,7 @@
 		if (cs_precedes == 1) {
 			if (sign_posn == 1 || sign_posn == 3) {
 				PRINTS(signstr);
-				if (sep_by_space == 2)		/* XXX: ? */
+				if (sep_by_space == 2)
 					PRINT(' ');
 			}
 
@@ -382,9 +385,7 @@
 	}
 
 	PRINT('\0');
-	va_end(ap);
 	free(asciivalue);
-	free(currency_symbol);
 	return (dst - s - 1);	/* size of put data except trailing '\0' */
 
 e2big_error:
@@ -398,45 +399,66 @@
 	sverrno = errno;
 	if (asciivalue != NULL)
 		free(asciivalue);
-	if (currency_symbol != NULL)
-		free(currency_symbol);
 	errno = sverrno;
-	va_end(ap);
 	return (-1);
 }
 
-static void
-__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
-    char *sign_posn, char **signstr)
+ssize_t
+strfmon(char *_RESTRICT_KYWD s, size_t maxsize,
+    const char *_RESTRICT_KYWD format, ...)
 {
+	va_list ap;
+	ssize_t ret;
 
-	struct lconv *lc = localeconv();
+	va_start(ap, format);
+	ret = strfmon_impl(s, maxsize, uselocale(NULL), format, ap);
+	va_end(ap);
+	return (ret);
+}
 
+ssize_t
+strfmon_l(char *_RESTRICT_KYWD s, size_t maxsize, locale_t loc,
+    const char *_RESTRICT_KYWD format, ...)
+{
+	ssize_t ret;
+	va_list ap;
+	va_start(ap, format);
+	ret = strfmon_impl(s, maxsize, loc, format, ap);
+	va_end(ap);
+	return (ret);
+}
+
+static void
+setup_vars(const struct lc_monetary *lmon, int flags, char *cs_precedes,
+    char *sep_by_space, char *sign_posn, const char **signstr)
+{
 	if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
-		*cs_precedes = lc->int_n_cs_precedes;
-		*sep_by_space = lc->int_n_sep_by_space;
-		*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
-		*signstr = (lc->negative_sign[0] == '\0') ? "-"
-		    : lc->negative_sign;
+		*cs_precedes = lmon->int_n_cs_precedes[0];
+		*sep_by_space = lmon->int_n_sep_by_space[0];
+		*sign_posn = (flags & PARENTH_POSN) ? 0 :
+		    lmon->int_n_sign_posn[0];
+		*signstr = (lmon->negative_sign[0] == '\0') ? "-" :
+		    lmon->negative_sign;
 	} else if (flags & USE_INTL_CURRENCY) {
-		*cs_precedes = lc->int_p_cs_precedes;
-		*sep_by_space = lc->int_p_sep_by_space;
-		*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
-		*signstr = lc->positive_sign;
+		*cs_precedes = lmon->int_p_cs_precedes[0];
+		*sep_by_space = lmon->int_p_sep_by_space[0];
+		*sign_posn = (flags & PARENTH_POSN) ? 0 :
+		    lmon->int_p_sign_posn[0];
+		*signstr = lmon->positive_sign;
 	} else if (flags & IS_NEGATIVE) {
-		*cs_precedes = lc->n_cs_precedes;
-		*sep_by_space = lc->n_sep_by_space;
-		*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
-		*signstr = (lc->negative_sign[0] == '\0') ? "-"
-		    : lc->negative_sign;
+		*cs_precedes = lmon->n_cs_precedes[0];
+		*sep_by_space = lmon->n_sep_by_space[0];
+		*sign_posn = (flags & PARENTH_POSN) ? 0 : lmon->n_sign_posn[0];
+		*signstr = (lmon->negative_sign[0] == '\0') ? "-" :
+		    lmon->negative_sign;
 	} else {
-		*cs_precedes = lc->p_cs_precedes;
-		*sep_by_space = lc->p_sep_by_space;
-		*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
-		*signstr = lc->positive_sign;
+		*cs_precedes = lmon->p_cs_precedes[0];
+		*sep_by_space = lmon->p_sep_by_space[0];
+		*sign_posn = (flags & PARENTH_POSN) ? 0 : lmon->p_sign_posn[0];
+		*signstr = lmon->positive_sign;
 	}
 
-	/* Set defult values for unspecified information. */
+	/* Set default values for unspecified information. */
 	if (*cs_precedes != 0)
 		*cs_precedes = 1;
 	if (*sep_by_space == CHAR_MAX)
@@ -446,13 +468,14 @@
 }
 
 static int
-__calc_left_pad(int flags, char *cur_symb)
+calc_left_pad(const struct lc_monetary *lmon, int flags, const char *cur_symb)
 {
-
-	char cs_precedes, sep_by_space, sign_posn, *signstr;
+	char cs_precedes, sep_by_space, sign_posn;
+	const char *signstr;
 	int left_chars = 0;
 
-	__setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
+	setup_vars(lmon, flags, &cs_precedes, &sep_by_space, &sign_posn,
+	    &signstr);
 
 	if (cs_precedes != 0) {
 		left_chars += strlen(cur_symb);
@@ -473,7 +496,7 @@
 }
 
 static int
-get_groups(int size, char *grouping)
+get_groups(int size, const char *grouping)
 {
 
 	int	chars = 0;
@@ -498,8 +521,9 @@
 
 /* convert double to ASCII */
 static char *
-__format_grouped_double(double value, int *flags,
-    int left_prec, int right_prec, int pad_char)
+format_grouped_double(const struct lc_monetary *lmon,
+    const struct lc_numeric *lnum,
+    double value, int *flags, int left_prec, int right_prec, int pad_char)
 {
 
 	char		*rslt;
@@ -512,21 +536,25 @@
 
 	int		padded;
 
-	struct lconv	*lc = localeconv();
-	char		*grouping;
-	char		decimal_point;
-	char		thousands_sep;
+	const char	*grouping;
+	const char	*decimal_point;
+	const char	*thousands_sep;
+	int		decimal_len;
+	int		thousands_len;
 
 	int groups = 0;
 
-	grouping = lc->mon_grouping;
-	decimal_point = *lc->mon_decimal_point;
-	if (decimal_point == '\0')
-		decimal_point = *lc->decimal_point;
-	thousands_sep = *lc->mon_thousands_sep;
-	if (thousands_sep == '\0')
-		thousands_sep = *lc->thousands_sep;
+	grouping = lmon->mon_grouping;
+	decimal_point = lmon->mon_decimal_point;
+	if (*decimal_point == '\0')
+		decimal_point = lnum->decimal_point;
+	thousands_sep = lmon->mon_thousands_sep;
+	if (*thousands_sep == '\0')
+		thousands_sep = lnum->thousands_sep;
 
+	decimal_len = strlen(decimal_point);	/* usually 1 */
+	thousands_len = strlen(thousands_sep);	/* 0 or 1 usually */
+
 	/* fill left_prec with default value */
 	if (left_prec == -1)
 		left_prec = 0;
@@ -534,9 +562,9 @@
 	/* fill right_prec with default value */
 	if (right_prec == -1) {
 		if (*flags & USE_INTL_CURRENCY)
-			right_prec = lc->int_frac_digits;
+			right_prec = lmon->int_frac_digits[0];
 		else
-			right_prec = lc->frac_digits;
+			right_prec = lmon->frac_digits[0];
 
 		if (right_prec == CHAR_MAX)	/* POSIX locale ? */
 			right_prec = 2;
@@ -552,7 +580,15 @@
 	if (avalue_size < 0)
 		return (NULL);
 
-	/* make sure that we've enough space for result string */
+	/*
+	 * Make sure that we've enough space for result string.
+	 * This assumes that digits take up at least much space as
+	 * grouping and radix characters.  The worst case currently known
+	 * is for Arabic, where two-byte UTF-8 sequences are used for both
+	 * decimal and thousands seperators, and groups can be a small as two
+	 * decimal digits.  This will do no worse than doubling the storage
+	 * requirement.
+	 */
 	bufsize = strlen(avalue)*2+1;
 	rslt = calloc(1, bufsize);
 	if (rslt == NULL) {
@@ -561,7 +597,7 @@
 	}
 	bufend = rslt + bufsize - 1;	/* reserve space for trailing '\0' */
 
-	/* skip spaces at beggining */
+	/* skip spaces at beginning */
 	padded = 0;
 	while (avalue[padded] == ' ') {
 		padded++;
@@ -572,12 +608,13 @@
 		bufend -= right_prec;
 		(void) memcpy(bufend, avalue + avalue_size+padded-right_prec,
 		    right_prec);
-		*--bufend = decimal_point;
-		avalue_size -= (right_prec + 1);
+		bufend -= decimal_len;
+		(void) memcpy(bufend, decimal_point, decimal_len);
+		avalue_size -= (right_prec + decimal_len);
 	}
 
 	if ((*flags & NEED_GROUPING) &&
-	    thousands_sep != '\0' &&	/* XXX: need investigation */
+	    thousands_len != 0 &&
 	    *grouping != CHAR_MAX &&
 	    *grouping > 0) {
 		while (avalue_size > (int)*grouping) {
--- old/usr/src/lib/libc/port/locale/strftime.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/strftime.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
@@ -22,11 +23,14 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <stdio.h>
+#include <locale.h>
 #include "timelocal.h"
+#include "localeimpl.h"
 
 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(locale_t, const char *, const struct tm *, char *,
+    const char * const);
 static char *_yconv(int, int, int, int, char *, const char *);
 
 extern char *tzname[];
@@ -62,13 +66,14 @@
 
 
 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;
 
 	tzset();
-	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize);
+	p = _fmt(loc, ((format == NULL) ? "%c" : format), t, s, s + maxsize);
 	if (p == s + maxsize)
 		return (0);
 	*p = '\0';
@@ -75,11 +80,19 @@
 	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, uselocale(NULL)));
+}
+
 static char *
-_fmt(const char *format, const struct tm *t, char *pt, const char * const ptlim)
+_fmt(locale_t loc, const char *format, const struct tm *t, char *pt,
+    const char * const ptlim)
 {
 	int Ealternative, Oalternative, PadIndex;
-	struct lc_time_T *tptr = __get_current_time_locale();
+	const struct lc_time *tptr = loc->time;
 
 #define	PADDING(x)	fmt_padding[x][PadIndex]
 
@@ -130,10 +143,10 @@
 				    pt, ptlim);
 				continue;
 			case 'c':
-				pt = _fmt(tptr->c_fmt, t, pt, ptlim);
+				pt = _fmt(loc, tptr->c_fmt, t, pt, ptlim);
 				continue;
 			case 'D':
-				pt = _fmt("%m/%d/%y", t, pt, ptlim);
+				pt = _fmt(loc, "%m/%d/%y", t, pt, ptlim);
 				continue;
 			case 'd':
 				pt = _conv(t->tm_mday,
@@ -163,7 +176,7 @@
 				    PADDING(PAD_FMT_SDAYOFMONTH), pt, ptlim);
 				continue;
 			case 'F':
-				pt = _fmt("%Y-%m-%d", t, pt, ptlim);
+				pt = _fmt(loc, "%Y-%m-%d", t, pt, ptlim);
 				continue;
 			case 'H':
 				pt = _conv(t->tm_hour, PADDING(PAD_FMT_HMS),
@@ -223,10 +236,10 @@
 				    tptr->pm : tptr->am, pt, ptlim);
 				continue;
 			case 'R':
-				pt = _fmt("%H:%M", t, pt, ptlim);
+				pt = _fmt(loc, "%H:%M", t, pt, ptlim);
 				continue;
 			case 'r':
-				pt = _fmt(tptr->ampm_fmt, t, pt, ptlim);
+				pt = _fmt(loc, tptr->ampm_fmt, t, pt, ptlim);
 				continue;
 			case 'S':
 				pt = _conv(t->tm_sec, PADDING(PAD_FMT_HMS),
@@ -245,7 +258,7 @@
 			}
 
 			case 'T':
-				pt = _fmt("%H:%M:%S", t, pt, ptlim);
+				pt = _fmt(loc, "%H:%M:%S", t, pt, ptlim);
 				continue;
 			case 't':
 				pt = _add("\t", pt, ptlim);
@@ -357,7 +370,7 @@
 				 * "date as dd-bbb-YYYY"
 				 * (ado, 1993-05-24)
 				 */
-				pt = _fmt("%e-%b-%Y", t, pt, ptlim);
+				pt = _fmt(loc, "%e-%b-%Y", t, pt, ptlim);
 				continue;
 			case 'W':
 				pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -371,10 +384,10 @@
 				pt = _conv(t->tm_wday, "%d", pt, ptlim);
 				continue;
 			case 'X':
-				pt = _fmt(tptr->X_fmt, t, pt, ptlim);
+				pt = _fmt(loc, tptr->X_fmt, t, pt, ptlim);
 				continue;
 			case 'x':
-				pt = _fmt(tptr->x_fmt, t, pt, ptlim);
+				pt = _fmt(loc, tptr->x_fmt, t, pt, ptlim);
 				continue;
 			case 'y':
 				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
@@ -438,7 +451,7 @@
 				}
 				continue;
 			case '+':
-				pt = _fmt(tptr->date_fmt, t, pt, ptlim);
+				pt = _fmt(loc, tptr->date_fmt, t, pt, ptlim);
 				continue;
 			case '-':
 				if (PadIndex != PAD_DEFAULT)
--- old/usr/src/lib/libc/port/i18n/strncasecmp.c	Tue May 20 07:58:51 2014
+++ /dev/null	Tue May 20 07:58:48 2014
@@ -1,65 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
-
-/*
- * Portions of this source code were derived from Berkeley 4.3 BSD
- * under license from the Regents of the University of California.
- */
-
-#include "lint.h"
-#include <sys/types.h>
-#include <strings.h>
-#include <ctype.h>
-
-int
-strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	extern int charset_is_ascii;
-	extern int ascii_strncasecmp(const char *s1, const char *s2, size_t n);
-	int *cm;
-	const uchar_t *us1;
-	const uchar_t *us2;
-
-	/*
-	 * If we are in a locale that uses the ASCII character set
-	 * (C or POSIX), use the fast ascii_strncasecmp() function.
-	 */
-	if (charset_is_ascii)
-		return (ascii_strncasecmp(s1, s2, n));
-
-	cm = __trans_lower;
-	us1 = (const uchar_t *)s1;
-	us2 = (const uchar_t *)s2;
-
-	while (n != 0 && cm[*us1] == cm[*us2++]) {
-		if (*us1++ == '\0')
-			return (0);
-		n--;
-	}
-	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
-}
--- /dev/null	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/strncasecmp.c	Tue May 20 07:58:51 2014
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include "lint.h"
+#include <sys/types.h>
+#include <strings.h>
+#include <ctype.h>
+#include <locale.h>
+#include "lctype.h"
+#include "localeimpl.h"
+
+int
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t loc)
+{
+	extern int ascii_strncasecmp(const char *s1, const char *s2, size_t n);
+	const int *cm;
+	const uchar_t *us1;
+	const uchar_t *us2;
+	const struct lc_ctype *lct = loc->ctype;
+
+	/*
+	 * If we are in a locale that uses the ASCII character set
+	 * (C or POSIX), use the fast ascii_strncasecmp() function.
+	 */
+	if (lct->lc_is_ascii)
+		return (ascii_strncasecmp(s1, s2, n));
+
+	cm = lct->lc_trans_lower;
+	us1 = (const uchar_t *)s1;
+	us2 = (const uchar_t *)s2;
+
+	while (n != 0 && cm[*us1] == cm[*us2++]) {
+		if (*us1++ == '\0')
+			return (0);
+		n--;
+	}
+	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	return (strncasecmp_l(s1, s2, n, uselocale(NULL)));
+}
--- old/usr/src/lib/libc/port/locale/strptime.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/strptime.c	Tue May 20 07:58:51 2014
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014 Gary Mills
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
  *
@@ -40,31 +41,30 @@
 #include <string.h>
 #include <pthread.h>
 #include <alloca.h>
+#include <locale.h>
 #include "timelocal.h"
+#include "localeimpl.h"
 
 #define	asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
 
 #define	F_GMT		(1 << 0)
-#define	F_ZERO		(1 << 1)
 #define	F_RECURSE	(1 << 2)
 
 static char *
-__strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
+__strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+    struct tm *_RESTRICT_KYWD tm, int *_RESTRICT_KYWD flagsp,
+    locale_t _RESTRICT_KYWD loc)
 {
 	char	c;
 	const char *ptr;
 	int	i, len, recurse = 0;
 	int Ealternative, Oalternative;
-	struct lc_time_T *tptr = __get_current_time_locale();
+	const struct lc_time *tptr = loc->time;
 
 	if (*flagsp & F_RECURSE)
 		recurse = 1;
 	*flagsp |= F_RECURSE;
 
-	if (*flagsp & F_ZERO)
-		(void) memset(tm, 0, sizeof (*tm));
-	*flagsp &= ~F_ZERO;
-
 	ptr = fmt;
 	while (*ptr != 0) {
 		if (*buf == 0)
@@ -93,7 +93,7 @@
 			break;
 
 		case '+':
-			buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->date_fmt, tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -116,13 +116,13 @@
 			break;
 
 		case 'c':
-			buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->c_fmt, tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'D':
-			buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
+			buf = __strptime(buf, "%m/%d/%y", tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -140,37 +140,37 @@
 			goto label;
 
 		case 'F':
-			buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
+			buf = __strptime(buf, "%Y-%m-%d", tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'R':
-			buf = __strptime(buf, "%H:%M", tm, flagsp);
+			buf = __strptime(buf, "%H:%M", tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'r':
-			buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'T':
-			buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
+			buf = __strptime(buf, "%H:%M:%S", tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'X':
-			buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->X_fmt, tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
 
 		case 'x':
-			buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
+			buf = __strptime(buf, tptr->x_fmt, tm, flagsp, loc);
 			if (buf == NULL)
 				return (NULL);
 			break;
@@ -519,11 +519,14 @@
 }
 
 char *
-strptime(const char *buf, const char *fmt, struct tm *tm)
+strptime(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+    struct tm *_RESTRICT_KYWD tm)
 {
-	int	flags = F_ZERO;
+	int	flags = 0;
 
-	return (__strptime(buf, fmt, tm, &flags));
+	(void) memset(tm, 0, sizeof (*tm));
+
+	return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
 }
 
 /*
@@ -531,9 +534,31 @@
  * incoming tm.  It is triggered by -D_STRPTIME_DONTZERO.
  */
 char *
-__strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
+__strptime_dontzero(const char *_RESTRICT_KYWD buf,
+    const char *_RESTRICT_KYWD fmt, struct tm *_RESTRICT_KYWD tm)
 {
 	int	flags = 0;
 
-	return (__strptime(buf, fmt, tm, &flags));
+	return (__strptime(buf, fmt, tm, &flags, uselocale(NULL)));
+}
+
+/*
+ * strptime_l is an extension that seems natural, and indeed, MacOS X
+ * includes it within their <xlocale.h> and it is part of GNU libc as well.
+ * For now we restrict it to the cases where strict namespaces are not
+ * included.  We expect to see it in a future version of POSIX.  locale_t is
+ * not a restrict, since the spec for it doesn't assume its a pointer.  We
+ * therefore pass it analagously to the way strftime_l is specified.
+ *
+ * We are not providing a non-zeroing version at this time.
+ */
+char *
+strptime_l(const char *_RESTRICT_KYWD buf, const char *_RESTRICT_KYWD fmt,
+    struct tm *_RESTRICT_KYWD tm, locale_t loc)
+{
+	int	flags =  0;
+
+	(void) memset(tm, 0, sizeof (*tm));
+
+	return (__strptime(buf, fmt, tm, &flags, loc));
 }
--- old/usr/src/lib/libc/port/locale/strxfrm.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/strxfrm.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
  *		at Electronni Visti IA, Kiev, Ukraine.
@@ -32,10 +33,12 @@
 #include <errno.h>
 #include <wchar.h>
 #include <assert.h>
+#include <xlocale.h>
 #include "collate.h"
 
 size_t
-strxfrm(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src, size_t dlen)
+strxfrm_l(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src,
+    size_t dlen, locale_t loc)
 {
 	size_t slen;
 	size_t xlen;
@@ -54,16 +57,16 @@
 	 */
 	slen = strlen(src);
 
-	if (_collate_load_error)
+	if (loc->collate->lc_is_posix)
 		goto error;
 
 	if ((wcs = malloc((slen + 1) * sizeof (wchar_t))) == NULL)
 		goto error;
 
-	if (mbstowcs(wcs, src, slen + 1) == (size_t)-1)
+	if (mbstowcs_l(wcs, src, slen + 1, loc) == (size_t)-1)
 		goto error;
 
-	if ((xlen = _collate_sxfrm(wcs, xf, dlen)) == (size_t)-1)
+	if ((xlen = _collate_sxfrm(wcs, xf, dlen, loc)) == (size_t)-1)
 		goto error;
 
 	if (wcs)
@@ -84,4 +87,10 @@
 	(void) strlcpy(xf, src, dlen);
 
 	return (slen);
+}
+
+size_t
+strxfrm(char *_RESTRICT_KYWD xf, const char *_RESTRICT_KYWD src, size_t dlen)
+{
+	return (strxfrm_l(xf, src, dlen, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/table.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/table.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -260,16 +261,8 @@
 	/* END CSTYLED */
 };
 
-_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
-
 /* Taken from former _ctype.c */
 unsigned int *__ctype_mask = _DefaultRuneLocale.__runetype;
 
 int *__trans_lower = _DefaultRuneLocale.__maplower;
 int *__trans_upper = _DefaultRuneLocale.__mapupper;
-
-/*
- * Used in various string routines to conditionalize versions optimized for
- * the ASCII case
- */
-int charset_is_ascii = 1;
--- old/usr/src/lib/libc/port/locale/timelocal.c	Tue May 20 07:58:51 2014
+++ new/usr/src/lib/libc/port/locale/timelocal.c	Tue May 20 07:58:51 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * Copyright (c) 1997 FreeBSD Inc.
@@ -28,16 +29,14 @@
 
 #include "lint.h"
 #include <stddef.h>
+#include <errno.h>
 #include "ldpart.h"
 #include "timelocal.h"
+#include "localeimpl.h"
 
-static struct lc_time_T _time_locale;
-static int _time_using_locale;
-static char *time_locale_buf;
+#define	LCTIME_SIZE (sizeof (struct lc_time) / sizeof (char *))
 
-#define	LCTIME_SIZE (sizeof (struct lc_time_T) / sizeof (char *))
-
-static const struct lc_time_T	_C_time_locale = {
+struct lc_time lc_time_posix = {
 	{
 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
@@ -84,17 +83,33 @@
 	"%I:%M:%S %p"
 };
 
-struct lc_time_T *
-__get_current_time_locale(void)
-{
-	return (_time_using_locale ? &_time_locale :
-	    (struct lc_time_T *)&_C_time_locale);
-}
+struct locdata __posix_time_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_time_posix }
+};
 
-int
-__time_load_locale(const char *name)
+struct locdata *
+__lc_time_load(const char *name)
 {
-	return (__part_load_locale(name, &_time_using_locale,
-	    &time_locale_buf, "LC_TIME", LCTIME_SIZE, LCTIME_SIZE,
-	    (const char **)&_time_locale));
+	struct locdata	*ldata;
+	struct lc_time	*ltime;
+	int ret;
+
+	if ((ldata = __locdata_alloc(name, sizeof (*ltime))) == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+	ltime = ldata->l_data[0];
+
+	ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+	    "LC_TIME", LCTIME_SIZE, LCTIME_SIZE, (const char **)ltime);
+
+	if (ret != _LDP_LOADED) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	return (ldata);
 }
--- old/usr/src/lib/libc/port/locale/timelocal.h	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/timelocal.h	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1997-2002 FreeBSD Project.
  * All rights reserved.
@@ -32,7 +33,7 @@
  * Private header file for the strftime and strptime localization
  * stuff.
  */
-struct lc_time_T {
+struct lc_time {
 	const char	*mon[12];
 	const char	*month[12];
 	const char	*wday[7];
@@ -46,7 +47,7 @@
 	const char	*ampm_fmt;
 };
 
-struct lc_time_T *__get_current_time_locale(void);
+struct lc_time *__get_current_time_locale(void);
 int	__time_load_locale(const char *);
 
 #endif /* !_TIMELOCAL_H_ */
--- old/usr/src/lib/libc/port/locale/tolower.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/tolower.c	Tue May 20 07:58:52 2014
@@ -10,22 +10,40 @@
  */
 
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  */
 #include "lint.h"
 #include <ctype.h>
+#include <locale.h>
+#include "localeimpl.h"
+#include "lctype.h"
 
 #pragma weak _tolower = tolower
 #pragma weak _toupper = toupper
 
 int
+tolower_l(int c, locale_t loc)
+{
+	return (((unsigned)c > 255) ? c : loc->ctype->lc_trans_lower[c]);
+}
+
+int
+toupper_l(int c, locale_t loc)
+{
+	return (((unsigned)c > 255) ? c : loc->ctype->lc_trans_upper[c]);
+}
+
+#undef tolower
+int
 tolower(int c)
 {
-	return (((unsigned)c > 255) ? c : __trans_lower[c]);
+	return (isascii(c) ? __trans_lower[c] : tolower_l(c, uselocale(NULL)));
 }
 
+#undef toupper
 int
 toupper(int c)
 {
-	return (((unsigned)c > 255) ? c : __trans_upper[c]);
+	return (isascii(c) ? __trans_upper[c] : toupper_l(c, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/towlower.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/towlower.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -39,21 +40,23 @@
 #include "lint.h"
 #include <wctype.h>
 #include <stdio.h>
+#include "localeimpl.h"
+#include "lctype.h"
 #include "runetype.h"
 
 static wint_t
-__change_case_ext(wint_t c, int lower)
+change_case_ext(locale_t loc, wint_t c, int lower)
 {
+	const _RuneLocale *rl;
+	const _RuneRange *rr;
+	const _RuneEntry *base, *re;
 	size_t lim;
-	_RuneRange *rr;
-	_RuneEntry *base, *re;
 
 	if (c < 0 || c == EOF)
 		return (c);
 
-	rr = lower ?
-	    &_CurrentRuneLocale->__maplower_ext :
-	    &_CurrentRuneLocale->__mapupper_ext;
+	rl = loc->runelocale;
+	rr = lower ? &rl->__maplower_ext : &rl->__mapupper_ext;
 	/* Binary search -- see bsearch.c for explanation. */
 	base = rr->__ranges;
 	for (lim = rr->__nranges; lim != 0; lim >>= 1) {
@@ -69,20 +72,40 @@
 	return (c);
 }
 
+wint_t
+towlower_l(wint_t wc, locale_t loc)
+{
+	return (iswascii(wc) ? __trans_lower[wc] :
+	    (wc < 0 || wc >= _CACHED_RUNES) ?
+	    change_case_ext(loc, wc, 1) :
+	    loc->runelocale->__maplower[wc]);
+}
+
 #undef towlower
 wint_t
 towlower(wint_t wc)
 {
-	return ((wc < 0 || wc >= _CACHED_RUNES) ?
-	    __change_case_ext(wc, 1) :
-	    _CurrentRuneLocale->__maplower[wc]);
+	return (iswascii(wc) ? __trans_lower[wc] :
+	    (wc < 0 || wc >= _CACHED_RUNES) ?
+	    change_case_ext(uselocale(NULL), wc, 1) :
+	    uselocale(NULL)->runelocale->__maplower[wc]);
 }
 
+wint_t
+towupper_l(wint_t wc, locale_t loc)
+{
+	return (iswascii(wc) ? __trans_upper[wc] :
+	    (wc < 0 || wc >= _CACHED_RUNES) ?
+	    change_case_ext(loc, wc, 0) :
+	    loc->runelocale->__mapupper[wc]);
+}
+
 #undef towupper
 wint_t
 towupper(wint_t wc)
 {
-	return ((wc < 0 || wc >= _CACHED_RUNES) ?
-	    __change_case_ext(wc, 0) :
-	    _CurrentRuneLocale->__mapupper[wc]);
+	return (iswascii(wc) ? __trans_upper[wc] :
+	    (wc < 0 || wc >= _CACHED_RUNES) ?
+	    change_case_ext(uselocale(NULL), wc, 0) :
+	    uselocale(NULL)->runelocale->__mapupper[wc]);
 }
--- old/usr/src/lib/libc/port/locale/utf8.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/utf8.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins
  * All rights reserved.
@@ -28,11 +29,11 @@
 #include "lint.h"
 #include <errno.h>
 #include <limits.h>
-#include "runetype.h"
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "lctype.h"
 
 static size_t	_UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD,
 		    const char *_RESTRICT_KYWD,
@@ -53,29 +54,16 @@
 	wchar_t	lbound;
 } _UTF8State;
 
-int
-_UTF8_init(_RuneLocale *rl)
+void
+_UTF8_init(struct lc_ctype *lct)
 {
-	__mbrtowc = _UTF8_mbrtowc;
-	__wcrtomb = _UTF8_wcrtomb;
-	__mbsinit = _UTF8_mbsinit;
-	__mbsnrtowcs = _UTF8_mbsnrtowcs;
-	__wcsnrtombs = _UTF8_wcsnrtombs;
-	_CurrentRuneLocale = rl;
-
-	charset_is_ascii = 0;
-
-	/*
-	 * In theory up to 6 bytes can be used for the encoding,
-	 * but only encodings with more than 4 bytes are illegal.
-	 */
-	__ctype[520] = 4;
-	/*
-	 * Note that the other CSWIDTH members are nonsensical for this
-	 * this coding.  They only are valid with EUC codings.
-	 */
-
-	return (0);
+	lct->lc_mbrtowc = _UTF8_mbrtowc;
+	lct->lc_wcrtomb = _UTF8_wcrtomb;
+	lct->lc_mbsinit = _UTF8_mbsinit;
+	lct->lc_mbsnrtowcs = _UTF8_mbsnrtowcs;
+	lct->lc_wcsnrtombs = _UTF8_wcsnrtombs;
+	lct->lc_is_ascii = 0;
+	lct->lc_max_mblen = 4;
 }
 
 static int
--- old/usr/src/lib/libc/port/locale/wcrtomb.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcrtomb.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -27,14 +28,25 @@
 
 #include "lint.h"
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
+#include "localeimpl.h"
+#include "lctype.h"
 #include "mblocal.h"
 
 size_t
-wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
+wcrtomb_l(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps,
+    locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__wcrtomb(s, wc, ps));
+	return (loc->ctype->lc_wcrtomb(s, wc, ps));
+}
+
+size_t
+wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (wcrtomb_l(s, wc, ps, uselocale(NULL)));
 }
--- /dev/null	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcscasecmp.c	Tue May 20 07:58:52 2014
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * Compare strings ignoring case difference.
+ *	returns:  s1>s2: >0  s1==s2: 0  s1<s2: <0
+ * All letters are converted to the lowercase and compared.
+ */
+
+#include "lint.h"
+#include <stdlib.h>
+#include <wchar.h>
+#include <locale.h>
+#include "libc.h"
+
+/* Legacy Sun interfaces */
+#pragma weak wscasecmp = wcscasecmp
+#pragma weak wsncasecmp = wcsncasecmp
+
+int
+wcscasecmp_l(const wchar_t *s1, const wchar_t *s2, locale_t loc)
+{
+	if (s1 == s2)
+		return (0);
+
+	while (towlower_l(*s1, loc) == towlower_l(*s2, loc)) {
+		if (*s1 == 0)
+			return (0);
+		s1++;
+		s2++;
+	}
+	return (towlower_l(*s1, loc) - towlower_l(*s2, loc));
+}
+
+int
+wcscasecmp(const wchar_t *s1, const wchar_t *s2)
+{
+	return (wcscasecmp_l(s1, s2, uselocale(NULL)));
+}
+
+int
+wcsncasecmp_l(const wchar_t *s1, const wchar_t *s2, size_t n, locale_t loc)
+{
+	if (s1 == s2)
+		return (0);
+
+	while ((towlower_l(*s1, loc) == towlower_l(*s2, loc)) && n--) {
+		if (*s1 == 0)
+			return (0);
+		s1++;
+		s2++;
+	}
+	return (towlower_l(*s1, loc) - towlower_l(*s2, loc));
+}
+
+int
+wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+{
+	return (wcsncasecmp_l(s1, s2, n, uselocale(NULL)));
+}
--- old/usr/src/lib/libc/port/locale/wcscoll.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcscoll.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002 Tim J. Robbins
  * All rights reserved.
@@ -32,17 +33,17 @@
 #include <wchar.h>
 #include <assert.h>
 #include "collate.h"
+#include "localeimpl.h"
 
 int
-wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc)
 {
 	int len1, len2, pri1, pri2, ret;
 	wchar_t *tr1 = NULL, *tr2 = NULL;
 	int direc, pass;
+	const struct lc_collate *lcc = loc->collate;
 
-	collate_info_t *info = _collate_info;
-
-	if (_collate_load_error)
+	if (lcc->lc_is_posix)
 		/*
 		 * Locale has no special collating order or could not be
 		 * loaded, do a fast binary comparison.
@@ -63,18 +64,18 @@
 	 * Note that we do one final extra pass at the end to pick
 	 * up UNDEFINED elements.  There is special handling for them.
 	 */
-	for (pass = 0; pass <= info->directive_count; pass++) {
+	for (pass = 0; pass <= lcc->lc_directive_count; pass++) {
 
-		int32_t *st1 = NULL;
-		int32_t *st2 = NULL;
+		const int32_t *st1 = NULL;
+		const int32_t *st2 = NULL;
 		const wchar_t	*w1 = ws1;
 		const wchar_t	*w2 = ws2;
 
 		/* special pass for UNDEFINED */
-		if (pass == info->directive_count) {
+		if (pass == lcc->lc_directive_count) {
 			direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
 		} else {
-			direc = info->directive[pass];
+			direc = lcc->lc_directive[pass];
 		}
 
 		if (direc & DIRECTIVE_BACKWARD) {
@@ -104,7 +105,8 @@
 		if (direc & DIRECTIVE_POSITION) {
 			while ((*w1 || st1) && (*w2 || st2)) {
 				pri1 = pri2 = 0;
-				_collate_lookup(w1, &len1, &pri1, pass, &st1);
+				_collate_lookup(lcc, w1, &len1, &pri1, pass,
+				    &st1);
 				if (pri1 <= 0) {
 					if (pri1 < 0) {
 						errno = EINVAL;
@@ -112,7 +114,8 @@
 					}
 					pri1 = COLLATE_MAX_PRIORITY;
 				}
-				_collate_lookup(w2, &len2, &pri2, pass, &st2);
+				_collate_lookup(lcc, w2, &len2, &pri2, pass,
+				    &st2);
 				if (pri2 <= 0) {
 					if (pri2 < 0) {
 						errno = EINVAL;
@@ -131,7 +134,7 @@
 			while ((*w1 || st1) && (*w2 || st2)) {
 				pri1 = pri2 = 0;
 				while (*w1) {
-					_collate_lookup(w1, &len1,
+					_collate_lookup(lcc, w1, &len1,
 					    &pri1, pass, &st1);
 					if (pri1 > 0)
 						break;
@@ -142,7 +145,7 @@
 					w1 += len1;
 				}
 				while (*w2) {
-					_collate_lookup(w2, &len2,
+					_collate_lookup(lcc, w2, &len2,
 					    &pri2, pass, &st2);
 					if (pri2 > 0)
 						break;
@@ -185,4 +188,11 @@
 fail:
 	ret = wcscmp(ws1, ws2);
 	goto end;
+}
+
+
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+	return (wcscoll_l(ws1, ws2, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wcsnrtombs.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcsnrtombs.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -29,24 +30,35 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <locale.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
-wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
-    size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
+wcsnrtombs_l(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__wcsnrtombs(dst, src, nwc, len, ps));
+	return (loc->ctype->lc_wcsnrtombs(dst, src, nwc, len, ps));
 }
 
 size_t
-__wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
     size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps)
 {
+	return (wcsnrtombs_l(dst, src, nwc, len, ps, uselocale(NULL)));
+}
+
+size_t
+__wcsnrtombs_std(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t nwc, size_t len, mbstate_t *_RESTRICT_KYWD ps,
+    wcrtomb_pfn_t pwcrtomb)
+{
 	mbstate_t mbsbak;
 	char buf[MB_LEN_MAX];
 	const wchar_t *s;
@@ -58,7 +70,7 @@
 
 	if (dst == NULL) {
 		while (nwc-- > 0) {
-			if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1)
+			if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1)
 				/* Invalid character - wcrtomb() sets errno. */
 				return ((size_t)-1);
 			else if (*s == L'\0')
@@ -72,7 +84,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 = pwcrtomb(dst, *s, ps)) == (size_t)-1) {
 				*src = s;
 				return ((size_t)-1);
 			}
@@ -85,7 +97,7 @@
 			 * character is too long for the buffer.
 			 */
 			mbsbak = *ps;
-			if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) {
+			if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1) {
 				*src = s;
 				return ((size_t)-1);
 			}
--- old/usr/src/lib/libc/port/locale/wcsrtombs.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcsrtombs.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -30,15 +31,24 @@
 #include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
+#include "localeimpl.h"
+#include "lctype.h"
 #include "mblocal.h"
 
 size_t
-wcsrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
-    size_t len, mbstate_t *_RESTRICT_KYWD ps)
+wcsrtombs_l(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t len, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
 {
 	static mbstate_t mbs;
 
 	if (ps == NULL)
 		ps = &mbs;
-	return (__wcsnrtombs(dst, src, ULONG_MAX, len, ps));
+	return (loc->ctype->lc_wcsnrtombs(dst, src, ULONG_MAX, len, ps));
+}
+
+size_t
+wcsrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
+    size_t len, mbstate_t *_RESTRICT_KYWD ps)
+{
+	return (wcsrtombs_l(dst, src, len, ps, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wcstombs.c	Tue May 20 07:58:52 2014
+++ new/usr/src/lib/libc/port/locale/wcstombs.c	Tue May 20 07:58:52 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -30,9 +31,12 @@
 #include <stdlib.h>
 #include <wchar.h>
 #include "mblocal.h"
+#include "localeimpl.h"
+#include "lctype.h"
 
 size_t
-wcstombs(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs, size_t n)
+wcstombs_l(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs,
+    size_t n, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	mbstate_t mbs;
@@ -40,5 +44,11 @@
 
 	mbs = initial;
 	pwcsp = pwcs;
-	return (__wcsnrtombs(s, &pwcsp, ULONG_MAX, n, &mbs));
+	return (loc->ctype->lc_wcsnrtombs(s, &pwcsp, ULONG_MAX, n, &mbs));
+}
+
+size_t
+wcstombs(char *_RESTRICT_KYWD s, const wchar_t *_RESTRICT_KYWD pwcs, size_t n)
+{
+	return (wcstombs_l(s, pwcs, n, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wcswidth.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wcswidth.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -37,10 +38,12 @@
  */
 
 #include "lint.h"
+#include <locale.h>
 #include <wchar.h>
+#include <xlocale.h>
 
 int
-wcswidth(const wchar_t *pwcs, size_t n)
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t loc)
 {
 	wchar_t wc;
 	int len, l;
@@ -47,9 +50,15 @@
 
 	len = 0;
 	while (n-- > 0 && (wc = *pwcs++) != L'\0') {
-		if ((l = wcwidth(wc)) < 0)
+		if ((l = wcwidth_l(wc, loc)) < 0)
 			return (-1);
 		len += l;
 	}
 	return (len);
+}
+
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+	return (wcswidth_l(pwcs, n, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wcsxfrm.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wcsxfrm.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
  *		at Electronni Visti IA, Kiev, Ukraine.
@@ -36,10 +37,11 @@
 #define	WCS_XFRM_OFFSET	1
 
 size_t
-wcsxfrm(wchar_t *_RESTRICT_KYWD dest,
-    const wchar_t *_RESTRICT_KYWD src, size_t len)
+wcsxfrm_l(wchar_t *_RESTRICT_KYWD dest,
+    const wchar_t *_RESTRICT_KYWD src, size_t len, locale_t loc)
 {
 	size_t slen;
+	const struct lc_collate *lcc = loc->collate;
 
 	if (*src == L'\0') {
 		if (len != 0)
@@ -47,8 +49,8 @@
 		return (0);
 	}
 
-	if ((_collate_load_error) ||
-	    ((slen = _collate_wxfrm(src, dest, len)) == (size_t)-1)) {
+	if ((lcc->lc_is_posix) ||
+	    ((slen = _collate_wxfrm(lcc, src, dest, len)) == (size_t)-1)) {
 		goto error;
 	}
 
@@ -70,4 +72,11 @@
 		dest[len - 1] = L'\0';
 	}
 	return (slen);
+}
+
+size_t
+wcsxfrm(wchar_t *_RESTRICT_KYWD dest,
+    const wchar_t *_RESTRICT_KYWD src, size_t len)
+{
+	return (wcsxfrm_l(dest, src, len, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wctob.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wctob.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -29,16 +30,24 @@
 #include <limits.h>
 #include <stdio.h>
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
 
 int
-wctob(wint_t c)
+wctob_l(wint_t c, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	mbstate_t mbs = initial;
 	char buf[MB_LEN_MAX];
 
-	if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1)
+	if (c == WEOF || wcrtomb_l(buf, c, &mbs, loc) != 1)
 		return (EOF);
 	return ((unsigned char)*buf);
+}
+
+int
+wctob(wint_t c)
+{
+	return (wctob_l(c, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wctomb.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wctomb.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -28,10 +29,12 @@
 #include "lint.h"
 #include <stdlib.h>
 #include <wchar.h>
+#include <locale.h>
+#include <xlocale.h>
 #include "mblocal.h"
 
 int
-wctomb(char *s, wchar_t wchar)
+wctomb_l(char *s, wchar_t wchar, locale_t loc)
 {
 	static const mbstate_t initial = { 0 };
 	static mbstate_t mbs;
@@ -42,7 +45,13 @@
 		mbs = initial;
 		return (0);
 	}
-	if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1)
+	if ((rval = wcrtomb_l(s, wchar, &mbs, loc)) == (size_t)-1)
 		return (-1);
 	return ((int)rval);
+}
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+	return (wctomb_l(s, wchar, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wctrans.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wctrans.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002 Tim J. Robbins.
  * All rights reserved.
@@ -26,9 +27,11 @@
  */
 
 #include "lint.h"
+#include <note.h>
 #include <errno.h>
 #include <string.h>
 #include <wctype.h>
+#include <locale.h>
 
 enum {
 	_WCT_ERROR	= 0,
@@ -37,15 +40,14 @@
 };
 
 wint_t
-towctrans(wint_t wc, wctrans_t desc)
+towctrans_l(wint_t wc, wctrans_t desc, locale_t loc)
 {
-
 	switch (desc) {
 	case _WCT_TOLOWER:
-		wc = towlower(wc);
+		wc = towlower_l(wc, loc);
 		break;
 	case _WCT_TOUPPER:
-		wc = towupper(wc);
+		wc = towupper_l(wc, loc);
 		break;
 	case _WCT_ERROR:
 	default:
@@ -56,8 +58,18 @@
 	return (wc);
 }
 
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+	return (towctrans_l(wc, desc, uselocale(NULL)));
+}
+
+/*
+ * For *now* we don't support locale sensitive transforms besides toupper
+ * and tolower.
+ */
 wctrans_t
-wctrans(const char *charclass)
+wctrans_l(const char *charclass, locale_t loc)
 {
 	struct {
 		const char	*name;
@@ -68,6 +80,7 @@
 		{ NULL,		_WCT_ERROR },		/* Default */
 	};
 	int i;
+	_NOTE(ARGUNUSED(loc));
 
 	i = 0;
 	while (ccls[i].name != NULL && strcmp(ccls[i].name, charclass) != 0)
@@ -76,4 +89,10 @@
 	if (ccls[i].trans == _WCT_ERROR)
 		errno = EINVAL;
 	return (ccls[i].trans);
+}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+	return (wctrans_l(charclass, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wctype.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wctype.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2002 Tim J. Robbins.
  * All rights reserved.
@@ -29,10 +30,17 @@
 #include <ctype.h>
 #include <string.h>
 #include <wctype.h>
+#include <note.h>
+#include <locale.h>
 #include "_ctype.h"
 
+/*
+ * For now, we don't support locale specific character classes.  This is
+ * a capability that needs to be added (locales should be able to define
+ * their own character classes.)
+ */
 wctype_t
-wctype(const char *property)
+wctype_l(const char *property, locale_t loc)
 {
 	static const struct {
 		const char	*name;
@@ -57,6 +65,7 @@
 		{ NULL,		0 },		/* Default */
 	};
 	int i;
+	_NOTE(ARGUNUSED(loc));
 
 	i = 0;
 	while (props[i].name != NULL && strcmp(props[i].name, property) != 0)
@@ -63,4 +72,10 @@
 		i++;
 
 	return (props[i].mask);
+}
+
+wctype_t
+wctype(const char *property)
+{
+	return (wctype_l(property, uselocale(NULL)));
 }
--- old/usr/src/lib/libc/port/locale/wcwidth.c	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/locale/wcwidth.c	Tue May 20 07:58:53 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  * (c) UNIX System Laboratories, Inc.
@@ -44,19 +45,21 @@
 #include <wchar.h>
 #include "_ctype.h"
 #include "runetype.h"
+#include "localeimpl.h"
 
 #undef wcwidth
 
 int
-wcwidth(wchar_t wc)
+wcwidth_l(wchar_t wc, locale_t loc)
 {
 	unsigned int x;
+	const _RuneLocale *rl = loc->runelocale;
 
 	if (wc == 0)
 		return (0);
 
-	x = ((wc < 0 || wc >= _CACHED_RUNES) ? ___runetype(wc) :
-	    _CurrentRuneLocale->__runetype[wc]) & (_CTYPE_SWM|_CTYPE_R);
+	x = ((wc < 0 || wc >= _CACHED_RUNES) ? __runetype(rl, wc) :
+	    rl->__runetype[wc]) & (_CTYPE_SWM|_CTYPE_R);
 
 	if ((x & _CTYPE_SWM) != 0)
 		return ((x & _CTYPE_SWM) >> _CTYPE_SWS);
@@ -63,6 +66,12 @@
 	return ((x & _CTYPE_R) != 0 ? 1 : -1);
 }
 
+int
+wcwidth(wchar_t wc)
+{
+	return (wcwidth_l(wc, uselocale(NULL)));
+}
+
 #pragma weak _scrwidth = scrwidth
 
 /*
--- old/usr/src/lib/libc/port/mapfile-vers	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/port/mapfile-vers	Tue May 20 07:58:53 2014
@@ -28,7 +28,7 @@
 # Copyright (c) 2012, Joyent, Inc.  All rights reserved.
 # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
 # Copyright (c) 2013 Gary Mills
-#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
 
 #
 # MAPFILE HEADER START
@@ -93,6 +93,86 @@
 $add amd64
 $endif
 
+SYMBOL_VERSION ILLUMOS_0.8 {	# POSIX 2008 newlocale and friends
+    protected:
+	__mb_cur_max;
+	btowc_l;
+	duplocale;
+	fgetwc_l;
+	freelocale;
+	getwc_l;
+	isalnum_l;
+	isalpha_l;
+	isblank_l;
+	iscntrl_l;
+	isdigit_l;
+	isgraph_l;
+	islower_l;
+	isprint_l;
+	ispunct_l;
+	isspace_l;
+	isupper_l;
+	iswideogram;
+	iswideogram_l;
+	iswnumber;
+	iswnumber_l;
+	iswhexnumber;
+	iswhexnumber_l;
+	iswphonogram;
+	iswphonogram_l;
+	iswspecial;
+	iswspecial_l;
+	iswalnum_l;
+	iswalpha_l;
+	iswblank_l;
+	iswcntrl_l;
+	iswctype_l;
+	iswdigit_l;
+	iswgraph_l;
+	iswlower_l;
+	iswprint_l;
+	iswpunct_l;
+	iswspace_l;
+	iswupper_l;
+	mblen_l;
+	mbrlen_l;
+	mbsinit_l;
+	mbsnrtowcs;
+	mbsnrtowcs_l;
+	mbsrtowcs_l;
+	mbstowcs_l;
+	mbtowc_l;
+	newlocale;
+	nl_langinfo_l;
+	strcasecmp_l;
+	strcasestr_l;
+	strcoll_l;
+	strfmon_l;
+	strftime_l;
+	strncasecmp_l;
+	strptime_l;
+	strxfrm_l;
+	tolower_l;
+	toupper_l;
+	towlower_l;
+	towupper_l;
+	towctrans_l;
+	uselocale;
+	wcrtomb_l;
+	wcscasecmp_l;
+	wcscoll_l;
+	wcsncasecmp_l;
+	wcsrtombs_l;
+	wcstombs_l;
+	wcswidth_l;
+	wcsxfrm_l;
+	wctob_l;
+	wctomb_l;
+	wctrans_l;
+	wctype_l;
+	wcwidth_l;
+} ILLUMOS_0.7;
+
 SYMBOL_VERSION ILLUMOS_0.7 {	# Illumos additions
     protected:
 	_glob_ext;
--- old/usr/src/lib/libc/sparc/Makefile.com	Tue May 20 07:58:53 2014
+++ new/usr/src/lib/libc/sparc/Makefile.com	Tue May 20 07:58:53 2014
@@ -22,6 +22,7 @@
 # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright (c) 2012, Joyent, Inc.  All rights reserved.
 # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
 #
 # Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -732,9 +733,6 @@
 	getwchar.o		\
 	putwchar.o		\
 	putws.o			\
-	strcasecmp.o		\
-	strcasestr.o		\
-	strncasecmp.o		\
 	strtows.o		\
 	wcsnlen.o		\
 	wcstoimax.o		\
@@ -741,7 +739,6 @@
 	wcstol.o		\
 	wcstoul.o		\
 	wcswcs.o		\
-	wscasecmp.o		\
 	wscat.o			\
 	wschr.o			\
 	wscmp.o			\
@@ -749,7 +746,6 @@
 	wscspn.o		\
 	wsdup.o			\
 	wslen.o			\
-	wsncasecmp.o		\
 	wsncat.o		\
 	wsncmp.o		\
 	wsncpy.o		\
@@ -777,7 +773,6 @@
 	wdresolve.o		\
 	_ctype.o		\
 	isascii.o		\
-	isdigit.o		\
 	toascii.o
 
 PORTI18N_COND=			\
@@ -801,11 +796,13 @@
 	gb2312.o		\
 	gbk.o			\
 	getdate.o		\
+	isdigit.o		\
 	iswctype.o		\
 	ldpart.o		\
 	lmessages.o		\
 	lnumeric.o		\
 	lmonetary.o		\
+	localeimpl.o		\
 	localeconv.o		\
 	mbftowc.o		\
 	mblen.o			\
@@ -828,9 +825,12 @@
 	runetype.o		\
 	setlocale.o		\
 	setrunelocale.o		\
+	strcasecmp.o		\
+	strcasestr.o		\
 	strcoll.o		\
 	strfmon.o		\
 	strftime.o		\
+	strncasecmp.o		\
 	strptime.o		\
 	strxfrm.o		\
 	table.o			\
@@ -840,6 +840,7 @@
 	ungetwc.o		\
 	utf8.o			\
 	wcrtomb.o		\
+	wcscasecmp.o		\
 	wcscoll.o		\
 	wcsftime.o		\
 	wcsnrtombs.o		\
--- old/usr/src/lib/libc/sparcv9/Makefile.com	Tue May 20 07:58:54 2014
+++ new/usr/src/lib/libc/sparcv9/Makefile.com	Tue May 20 07:58:54 2014
@@ -22,6 +22,7 @@
 # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright (c) 2012, Joyent, Inc.  All rights reserved.
 # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2013 Garrett D'Amore <garrett@damore.org>
 #
 # Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
 # Use is subject to license terms.
@@ -679,9 +680,6 @@
 	getwchar.o		\
 	putwchar.o		\
 	putws.o			\
-	strcasecmp.o		\
-	strcasestr.o		\
-	strncasecmp.o		\
 	strtows.o		\
 	wcsnlen.o		\
 	wcstoimax.o		\
@@ -688,7 +686,6 @@
 	wcstol.o		\
 	wcstoul.o		\
 	wcswcs.o		\
-	wscasecmp.o		\
 	wscat.o			\
 	wschr.o			\
 	wscmp.o			\
@@ -696,7 +693,6 @@
 	wscspn.o		\
 	wsdup.o			\
 	wslen.o			\
-	wsncasecmp.o		\
 	wsncat.o		\
 	wsncmp.o		\
 	wsncpy.o		\
@@ -724,7 +720,6 @@
 	wdresolve.o		\
 	_ctype.o		\
 	isascii.o		\
-	isdigit.o		\
 	toascii.o
 
 PORTI18N_COND=			\
@@ -748,6 +743,7 @@
 	gb2312.o		\
 	gbk.o			\
 	getdate.o		\
+	isdigit.o		\
 	iswctype.o		\
 	ldpart.o		\
 	lmessages.o		\
@@ -754,6 +750,7 @@
 	lnumeric.o		\
 	lmonetary.o		\
 	localeconv.o		\
+	localeimpl.o		\
 	mbftowc.o		\
 	mblen.o			\
 	mbrlen.o		\
@@ -775,9 +772,12 @@
 	runetype.o		\
 	setlocale.o		\
 	setrunelocale.o		\
+	strcasecmp.o		\
+	strcasestr.o		\
 	strcoll.o		\
 	strfmon.o		\
 	strftime.o		\
+	strncasecmp.o		\
 	strptime.o		\
 	strxfrm.o		\
 	table.o			\
@@ -787,6 +787,7 @@
 	ungetwc.o		\
 	utf8.o			\
 	wcrtomb.o		\
+	wcscasecmp.o		\
 	wcscoll.o		\
 	wcsftime.o		\
 	wcsnrtombs.o		\
--- old/usr/src/lib/libumem/common/stub_stand.c	Tue May 20 07:58:54 2014
+++ new/usr/src/lib/libumem/common/stub_stand.c	Tue May 20 07:58:54 2014
@@ -20,6 +20,7 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -145,4 +146,19 @@
 void
 _tmem_set_cleanup(void (*f)(int, void *))
 {
+}
+
+int
+isspace(int c)
+{
+	switch (c) {
+	case ' ':
+	case '\t':
+	case '\n':
+	case '\r':
+	case '\f':
+	case '\v':
+		return (1);
+	}
+	return (0);
 }
--- old/usr/src/man/man3c/ctype.3c	Tue May 20 07:58:54 2014
+++ new/usr/src/man/man3c/ctype.3c	Tue May 20 07:58:54 2014
@@ -1,4 +1,5 @@
 '\" te
+.\" Copyright 2013 Garrett D'Amore <garrett@damore.org>
 .\" Copyright 1989 AT&T.  Copyright (c) 1992, X/Open Company Limited  All Rights Reserved.  Portions Copyright (c) 2005, Sun Microsystems, Inc.  All Rights Reserved.
 .\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for permission to reproduce portions of its copyrighted documentation. Original documentation from The Open Group can be obtained online at
 .\" http://www.opengroup.org/bookstore/.
@@ -7,7 +8,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH CTYPE 3C "Jan 28, 2005"
+.TH CTYPE 3C "Sep 18, 2013"
 .SH NAME
 ctype, isalpha, isalnum, isascii, isblank, iscntrl, isdigit, islower, isprint,
 isspace, isupper, ispunct, isgraph, isxdigit \- character handling
@@ -100,23 +101,7 @@
 .LP
 Functions exist for all the macros defined below. To get the function form, the
 macro name must be undefined (for example, \fB#undef isdigit\fR).
-.sp
-.LP
-For macros described with \fBDefault\fR and \fBStandard conforming\fR versions,
-standard-conforming behavior is provided for standard-conforming applications
-(see \fBstandards\fR(5)) and for applications that define
-\fB__XPG4_CHAR_CLASS__\fR before including <\fBctype.h\fR>.
-.SS "Default"
-.sp
-.ne 2
-.na
-\fB\fBisalpha()\fR\fR
-.ad
-.RS 13n
-Tests for any character for which \fBisupper()\fR or \fBislower()\fR is true.
-.RE
 
-.SS "Standard conforming"
 .sp
 .ne 2
 .na
@@ -178,7 +163,6 @@
 Tests for any decimal-digit character.
 .RE
 
-.SS "Default"
 .sp
 .ne 2
 .na
@@ -185,17 +169,6 @@
 \fB\fBisgraph()\fR\fR
 .ad
 .RS 13n
-Tests for any character for which \fBispunct()\fR, \fBisupper()\fR,
-\fBislower()\fR, and \fBisdigit()\fR is true.
-.RE
-
-.SS "Standard conforming"
-.sp
-.ne 2
-.na
-\fB\fBisgraph()\fR\fR
-.ad
-.RS 13n
 Tests for any character for which \fBisalnum()\fR and \fBispunct()\fR are true,
 or any character in the current locale-defined "graph" class which is neither a
 space ("\|") nor a character for which \fBiscntrl()\fR is true.
@@ -214,7 +187,6 @@
 as lower-case \fBASCII\fR characters.
 .RE
 
-.SS "Default"
 .sp
 .ne 2
 .na
@@ -221,17 +193,6 @@
 \fB\fBisprint()\fR\fR
 .ad
 .RS 13n
-Tests for any character for which \fBispunct()\fR, \fBisupper()\fR,
-\fBislower()\fR, \fBisdigit()\fR, and the space character ("\|") is true.
-.RE
-
-.SS "Standard conforming"
-.sp
-.ne 2
-.na
-\fB\fBisprint()\fR\fR
-.ad
-.RS 13n
 Tests for any character for which \fBiscntrl()\fR is false, and
 \fBisalnum()\fR, \fBisgraph()\fR, \fBispunct()\fR, the space character ("\|"),
 and the characters in the current locale-defined "print" class are true.
@@ -272,20 +233,8 @@
 as upper-case \fBASCII\fR characters.
 .RE
 
-.SS "Default"
 .sp
 .ne 2
-.na
-\fB\fBisxdigit()\fR\fR
-.ad
-.RS 14n
-Tests for any hexadecimal-digit character (\fB[0\(mi9]\fR, \fB[A\(miF]\fR, or
-\fB[a\(mif]\fR).
-.RE
-
-.SS "Standard conforming"
-.sp
-.ne 2
 .na
 \fB\fBisxdigit()\fR\fR
 .ad
--- old/usr/src/pkg/manifests/system-header.mf	Tue May 20 07:58:54 2014
+++ new/usr/src/pkg/manifests/system-header.mf	Tue May 20 07:58:54 2014
@@ -440,7 +440,6 @@
 file path=usr/include/ipp/ipp_config.h
 file path=usr/include/ipp/ipp_impl.h
 file path=usr/include/ipp/ippctl.h
-file path=usr/include/iso/ctype_c99.h
 file path=usr/include/iso/ctype_iso.h
 file path=usr/include/iso/limits_iso.h
 file path=usr/include/iso/locale_iso.h
@@ -457,7 +456,6 @@
 file path=usr/include/iso/time_iso.h
 file path=usr/include/iso/wchar_c99.h
 file path=usr/include/iso/wchar_iso.h
-file path=usr/include/iso/wctype_c99.h
 file path=usr/include/iso/wctype_iso.h
 file path=usr/include/iso646.h
 file path=usr/include/kerberosv5/com_err.h
@@ -1681,6 +1679,7 @@
 file path=usr/include/wctype.h
 file path=usr/include/widec.h
 file path=usr/include/wordexp.h
+file path=usr/include/xlocale.h
 file path=usr/include/xti.h
 file path=usr/include/xti_inet.h
 file path=usr/include/zone.h
--- old/usr/src/uts/common/sys/feature_tests.h	Tue May 20 07:58:54 2014
+++ new/usr/src/uts/common/sys/feature_tests.h	Tue May 20 07:58:54 2014
@@ -23,6 +23,9 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ */
 
 #ifndef _SYS_FEATURE_TESTS_H
 #define	_SYS_FEATURE_TESTS_H
@@ -43,6 +46,7 @@
  *		199309L	    POSIX.1b-1993 compilation (Real Time)
  *		199506L	    POSIX.1c-1995 compilation (POSIX Threads)
  *		200112L	    POSIX.1-2001 compilation (Austin Group Revision)
+ *		200809L     POSIX.1-2008 compilation
  */
 #if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE)
 #define	_POSIX_C_SOURCE 1
@@ -49,9 +53,9 @@
 #endif
 
 /*
- * The feature test macros __XOPEN_OR_POSIX, _STRICT_STDC, and _STDC_C99
- * are Sun implementation specific macros created in order to compress
- * common standards specified feature test macros for easier reading.
+ * The feature test macros __XOPEN_OR_POSIX, _STRICT_STDC, _STRICT_SYMBOLS,
+ * and _STDC_C99 are Sun implementation specific macros created in order to
+ * compress common standards specified feature test macros for easier reading.
  * These macros should not be used by the application developer as
  * unexpected results may occur. Instead, the user should reference
  * standards(5) for correct usage of the standards feature test macros.
@@ -77,6 +81,10 @@
  *                      the C standard. A value of 199901L indicates a
  *                      compiler that complies with ISO/IEC 9899:1999, other-
  *                      wise known as the C99 standard.
+ *
+ * _STRICT_SYMBOLS	Used in cases where symbol visibility is restricted
+ *                      by the standards, and the user has not explicitly
+ *                      relaxed the strictness via __EXTENSIONS__.
  */
 
 #if defined(_XOPEN_SOURCE) || defined(_POSIX_C_SOURCE)
@@ -144,6 +152,14 @@
 #endif
 
 /*
+ * Use strict symbol visibility.
+ */
+#if (defined(_STRICT_STDC) || defined(__XOPEN_OR_POSIX)) && \
+	!defined(__EXTENSIONS__)
+#define	_STRICT_SYMBOLS
+#endif
+
+/*
  * Large file interfaces:
  *
  *	_LARGEFILE_SOURCE
@@ -222,6 +238,8 @@
  * X/Open CAE Specification, Issue 5 (XPG5)
  * Open Group Technical Standard, Issue 6 (XPG6), also referred to as
  *    IEEE Std. 1003.1-2001 and ISO/IEC 9945:2002.
+ * Open Group Technical Standard, Issue 7 (XPG7), also referred to as
+ *    IEEE Std. 1003.1-2008 and ISO/IEC 9945:2009.
  *
  * XPG4v2 is also referred to as UNIX 95 (SUS or SUSv1).
  * XPG5 is also referred to as UNIX 98 or the Single Unix Specification,
@@ -229,6 +247,7 @@
  * XPG6 is the result of a merge of the X/Open and POSIX specifications
  *     and as such is also referred to as IEEE Std. 1003.1-2001 in
  *     addition to UNIX 03 and SUSv3.
+ * XPG7 is also referred to as UNIX 08 and SUSv4.
  *
  * When writing a conforming X/Open application, as per the specification
  * requirements, the appropriate feature test macros must be defined at
@@ -241,6 +260,7 @@
  * _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED = 1           XPG4v2
  * _XOPEN_SOURCE = 500                                   XPG5
  * _XOPEN_SOURCE = 600  (or POSIX_C_SOURCE=200112L)      XPG6
+ * _XOPEN_SOURCE = 700  (or POSIX_C_SOURCE=200809L)      XPG7
  *
  * In order to simplify the guards within the headers, the following
  * implementation private test macros have been created. Applications
@@ -260,6 +280,7 @@
  * _XPG4_2  X/Open CAE Specification, Issue 4, Version 2 (XPG4v2/UNIX 95/SUS)
  * _XPG5    X/Open CAE Specification, Issue 5 (XPG5/UNIX 98/SUSv2)
  * _XPG6    Open Group Technical Standard, Issue 6 (XPG6/UNIX 03/SUSv3)
+ * _XPG7    Open Group Technical Standard, Issue 7 (XPG7/UNIX 08/SUSv4)
  */
 
 /* X/Open Portability Guide, Issue 3 */
@@ -294,6 +315,19 @@
 #define	_POSIX_C_SOURCE			200112L
 #undef	_XOPEN_SOURCE
 #define	_XOPEN_SOURCE			600
+
+/* Open Group Technical Standard, Issue 7 */
+#elif	(_XOPEN_SOURCE - 0 == 700) || (_POSIX_C_SOURCE - 0 == 200809L)
+#define	_XPG7
+#define	_XPG6
+#define	_XPG5
+#define	_XPG4_2
+#define	_XPG4
+#define	_XPG3
+#undef	_POSIX_C_SOURCE
+#define	_POSIX_C_SOURCE			200809L
+#undef	_XOPEN_SOURCE
+#define	_XOPEN_SOURCE			700
 #endif
 
 /*
@@ -304,12 +338,15 @@
  * with the value of 4 indicates an XPG4 or XPG4v2 (UNIX 95) application.
  * _XOPEN_VERSION  defined with a value of 500 indicates an XPG5 (UNIX 98)
  * application and with a value of 600 indicates an XPG6 (UNIX 03)
- * application.  The appropriate version is determined by the use of the
+ * application and with a value of 700 indicates an XPG7 (UNIX 08).
+ * The appropriate version is determined by the use of the
  * feature test macros described earlier.  The value of _XOPEN_VERSION
  * defaults to 3 otherwise indicating support for XPG3 applications.
  */
 #ifndef _XOPEN_VERSION
-#ifdef	_XPG6
+#if	defined(_XPG7)
+#define	_XOPEN_VERSION 700
+#elif	defined(_XPG6)
 #define	_XOPEN_VERSION 600
 #elif defined(_XPG5)
 #define	_XOPEN_VERSION 500
