--- old/usr/src/Makefile.master	Mon Jul 14 17:47:57 2014
+++ new/usr/src/Makefile.master	Mon Jul 14 17:47:57 2014
@@ -22,6 +22,7 @@
 #
 # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
 #
 
 #
@@ -657,8 +658,9 @@
 MAPFILE.INT =		mapfile-intf
 
 #
-# LDLIBS32 can be set in the environment to override the following assignment.
-# LDLIBS64 can be set to override the assignment made in Makefile.master.64.
+# LDLIBS32 and LDLIBS64 can be set in the environment to override the following
+# assignments.
+#
 # These environment settings make sure that no libraries are searched outside
 # of the local workspace proto area:
 #	LDLIBS32=-YP,$ROOT/lib:$ROOT/usr/lib
@@ -668,6 +670,12 @@
 LDLIBS32 +=	$(ADJUNCT_PROTO:%=-L%/usr/lib -L%/lib)
 LDLIBS.cmd = 	$(LDLIBS32)
 LDLIBS.lib =	$(LDLIBS32)
+
+LDLIBS64 =	$(ENVLDLIBS1:%=%/$(MACH64)) \
+		$(ENVLDLIBS2:%=%/$(MACH64)) \
+		$(ENVLDLIBS3:%=%/$(MACH64))
+LDLIBS64 +=     $(ADJUNCT_PROTO:%=-L%/usr/lib/$(MACH64) -L%/lib/$(MACH64))
+
 #
 # Define compilation macros.
 #
--- old/usr/src/Makefile.master.64	Mon Jul 14 17:47:58 2014
+++ new/usr/src/Makefile.master.64	Mon Jul 14 17:47:58 2014
@@ -20,6 +20,7 @@
 #
 #
 # Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
 #
 
 # rebind basic build macros to 64-bit versions
@@ -42,15 +43,6 @@
 OFFSETS_CREATE=	$(OFFSETS_CREATE64)
 
 #
-# Some library path hackery, to allow building of partial workspaces
-# and properly set the 64-bit library paths with 'ws'
-#
-LDLIBS1=	$(ENVLDLIBS1:%=%/$(MACH64))
-LDLIBS2=	$(ENVLDLIBS2:%=%/$(MACH64))
-LDLIBS3=	$(ENVLDLIBS3:%=%/$(MACH64))
-LDLIBS64 = 	$(LDLIBS1) $(LDLIBS2) $(LDLIBS3)
-LDLIBS64 +=	$(ADJUNCT_PROTO:%=-L%/usr/lib/$(MACH64) -L%/lib/$(MACH64))
-#
 # Moved these up to the top level here, so they can be overridden
 #
 LDLIBS.cmd =	$(LDLIBS64)
--- old/usr/src/head/iso/wchar_iso.h	Mon Jul 14 17:47:58 2014
+++ new/usr/src/head/iso/wchar_iso.h	Mon Jul 14 17:47:58 2014
@@ -25,6 +25,10 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
  * An application should not include this header directly.  Instead it
  * should be included only through the inclusion of other Sun headers.
  *
@@ -39,8 +43,6 @@
 #ifndef	_ISO_WCHAR_ISO_H
 #define	_ISO_WCHAR_ISO_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/feature_tests.h>
 #include <stdio_tag.h>
 #include <wchar_impl.h>
@@ -326,6 +328,10 @@
 			mbstate_t *_RESTRICT_KYWD);
 extern size_t	wcsrtombs(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
 			size_t, mbstate_t *_RESTRICT_KYWD);
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+extern size_t	wcsnrtombs(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
+			size_t, size_t, mbstate_t *_RESTRICT_KYWD);
+#endif
 extern int	wctob(wint_t);
 extern int	wmemcmp(const wchar_t *, const wchar_t *, size_t);
 extern wchar_t	*wmemcpy(wchar_t *_RESTRICT_KYWD,
@@ -420,6 +426,10 @@
 extern int	vswprintf();
 extern size_t	wcrtomb();
 extern size_t	wcsrtombs();
+#if defined(_XPG7) || !defined(_STRICT_SYMBOLS)
+extern size_t	wcsnrtombs();
+#endif
+
 extern wchar_t	*wcsstr();
 extern int	wctob();
 extern wchar_t	*wmemchr();
--- old/usr/src/head/xlocale.h	Mon Jul 14 17:47:58 2014
+++ new/usr/src/head/xlocale.h	Mon Jul 14 17:47:58 2014
@@ -81,7 +81,9 @@
 extern int mbtowc_l(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, size_t,
     locale_t);
 extern size_t wcsrtombs_l(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
-    size_t len, mbstate_t *_RESTRICT_KYWD, locale_t);
+    size_t, mbstate_t *_RESTRICT_KYWD, locale_t);
+extern size_t wcsnrtombs_l(char *_RESTRICT_KYWD, const wchar_t **_RESTRICT_KYWD,
+    size_t, size_t, mbstate_t *_RESTRICT_KYWD, locale_t);
 extern size_t wcrtomb_l(char *_RESTRICT_KYWD, wchar_t,
     mbstate_t *_RESTRICT_KYWD, locale_t);
 extern size_t wcstombs_l(char *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD,
--- old/usr/src/lib/libc/port/llib-lc	Mon Jul 14 17:47:58 2014
+++ new/usr/src/lib/libc/port/llib-lc	Mon Jul 14 17:47:58 2014
@@ -24,6 +24,7 @@
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved.
  * Copyright (c) 2013 Gary Mills
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  */
 
 /* LINTLIBRARY */
@@ -165,6 +166,7 @@
 #if defined(__amd64)
 #include <stack_unwind.h>
 #endif
+#include <xlocale.h>
 
 /*
  * This really comes from the crt*.s startup modules.
--- old/usr/src/lib/libc/port/locale/lmonetary.c	Mon Jul 14 17:47:58 2014
+++ new/usr/src/lib/libc/port/locale/lmonetary.c	Mon Jul 14 17:47:58 2014
@@ -156,10 +156,10 @@
 		char sign = '\0';
 		switch (lmon->p_cs_precedes[0]) {
 		case 0:
-			sign = '-';
+			sign = '+';
 			break;
 		case 1:
-			sign = '+';
+			sign = '-';
 			break;
 		case CHAR_MAX:
 			/*
--- old/usr/src/lib/libc/port/mapfile-vers	Mon Jul 14 17:47:58 2014
+++ new/usr/src/lib/libc/port/mapfile-vers	Mon Jul 14 17:47:58 2014
@@ -93,6 +93,12 @@
 $add amd64
 $endif
 
+SYMBOL_VERSION ILLUMOS_0.9 {
+    protected:
+	wcsnrtombs;
+	wcsnrtombs_l;
+} ILLUMOS_0.8;
+
 SYMBOL_VERSION ILLUMOS_0.8 {	# POSIX 2008 newlocale and friends
     protected:
 	__global_locale;
--- old/usr/src/man/man3c/Makefile	Mon Jul 14 17:47:59 2014
+++ new/usr/src/man/man3c/Makefile	Mon Jul 14 17:47:59 2014
@@ -1242,8 +1242,11 @@
 	 	wcsncat.3c				\
 	 	wcsncmp.3c				\
 	 	wcsncpy.3c				\
+		wcsnrtombs.3c				\
+		wcsnrtombs_l.3c				\
 	 	wcspbrk.3c				\
 	 	wcsrchr.3c				\
+		wcsrtombs_l.3c				\
 	 	wcsspn.3c				\
 	 	wcstof.3c				\
 	 	wcstok.3c				\
@@ -2226,6 +2229,10 @@
 wcscoll_l.3c				:= LINKSRC = wcscoll.3c
 wscoll.3c				:= LINKSRC = wcscoll.3c
 
+wcsnrtombs.3c				:= LINKSRC = wcsrtombs.3c
+wcsnrtombs_l.3c				:= LINKSRC = wcsrtombs.3c
+wcsrtombs_l.3c				:= LINKSRC = wcsrtombs.3c
+
 watof.3c				:= LINKSRC = wcstod.3c
 wcstof.3c				:= LINKSRC = wcstod.3c
 wcstold.3c				:= LINKSRC = wcstod.3c
--- old/usr/src/man/man3c/wcsrtombs.3c	Mon Jul 14 17:47:59 2014
+++ new/usr/src/man/man3c/wcsrtombs.3c	Mon Jul 14 17:47:59 2014
@@ -8,9 +8,9 @@
 .\" 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 WCSRTOMBS 3C "Jun 25, 2014"
+.TH WCSRTOMBS 3C "Jul 13, 2014"
 .SH NAME
-wcsrtombs, wcsrtombs_l \- convert a wide-character string to a character string
+wcsnrtombs, wcsnrtombs_l, wcsrtombs, wcsrtombs_l \- convert a wide-character string to a character string
 (restartable)
 .SH SYNOPSIS
 .LP
@@ -17,19 +17,26 @@
 .nf
 #include <wchar.h>
 
-\fBsize_t\fR \fBwcsrtombs\fR(\fBchar *restrict\fR \fIdst\fR,
-     \fBconst wchar_t **restrict\fR \fIsrc\fR, \fBsize_t\fR \fIlen\fR,
-     \fBmbstate_t *restrict\fR \fIps\fR);
+\fBsize_t\fR \fBwcsrtombs\fR(\fBchar *restrict\fR \fIdst\fR, \fBconst wchar_t **restrict\fR \fIsrc\fR,
+     \fBsize_t\fR \fIlen\fR, \fBmbstate_t *restrict\fR \fIps\fR);
 .fi
 .LP
 .nf
+\fBsize_t\fR \fBwcsnrtombs\fR(\fBchar *restrict\fR \fIdst\fR, \fBconst wchar_t **restrict\fR \fIsrc\fR,
+     \fBsize_t\fR \fInwc\fR, \fBsize_t\fR \fIlen\fR, \fBmbstate_t *restrict\fR \fIps\fR);
+.LP
+.nf
 #include <wchar.h>
 #include <xlocale.h>
 
-\fBsize_t\fR \fBwcsrtombs_l\fR(\fBchar *restrict\fR \fIdst\fR,
-     \fBconst wchar_t **restrict\fR \fIsrc\fR, \fBsize_t\fR \fIlen\fR,
-     \fBmbstate_t *restrict\fR \fIps\fR, \fBlocale_t\fR \fIloc\fR);
+\fBsize_t\fR \fBwcsrtombs_l\fR(\fBchar *restrict\fR \fIdst\fR, \fBconst wchar_t **restrict\fR \fIsrc\fR,
+     \fBsize_t\fR \fIlen\fR, \fBmbstate_t *restrict\fR \fIps\fR, \fBlocale_t\fR \fIloc\fR);
 .fi
+.LP
+.nf
+\fBsize_t\fR \fBwcsnrtombs_l\fR(\fBchar *restrict\fR \fIdst\fR, \fBconst wchar_t **restrict\fR \fIsrc\fR,
+     \fBsize_t\fR \fInwc\fR, \fBsize_t\fR \fIlen\fR, \fBmbstate_t *restrict\fR \fIps\fR, \fBlocale_t\fR \fIloc\fR);
+.fi
 .SH DESCRIPTION
 .LP
 The \fBwcsrtombs()\fR function converts a sequence of wide-characters from the
@@ -53,6 +60,13 @@
 stored in the array pointed to by \fIdst\fR (and \fIdst\fR is not a null
 pointer).
 .RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+In the case of \fBwcsnrtombs()\fR and \fBwcsnrtombs_l()\fR, when \fInwc\fR
+wide characters have been completely converted.
+.RE
 .LP
 Each conversion takes place as if by a call to the \fBwcrtomb()\fR function.
 .LP
@@ -63,7 +77,7 @@
 terminating null wide-character, the resulting state described is the initial
 conversion state.
 .LP
-If \fIps\fR is a null pointer, the \fBwcsrtombs()\fR function uses its own
+If \fIps\fR is a null pointer, these functions uses their own
 internal \fBmbstate_t\fR object, which is initialized at program startup to the
 initial conversion state.  Otherwise, the  \fBmbstate_t\fR object pointed to by
 \fIps\fR is used to completely describe the current conversion state of the
@@ -70,11 +84,12 @@
 associated character sequence. The system will behave as if no function defined
 in the Reference Manual calls any of these functions.
 .LP
-The behavior of \fBwcsrtombs()\fR is affected by the \fBLC_CTYPE\fR category of
-the current locale.  See \fBenviron\fR(5).
+The behavior of \fBwcsrtombs()\fR and \fBwcsnrtombs()\fR are affected by the
+\fBLC_CTYPE\fR category of the current locale.  See \fBenviron\fR(5).
 .LP
-The function \fBwcsrtombs_l()\fR behaves identically to \fBwcsrtombs\fR, except
-instead of operating in the current locale, it operates in the locale
+The \fBwcsrtombs_l()\fR and \fBwcsnrtombs_l()\fR functions behave identically
+to \fBwcsrtombs()\fR and \fBwcsnrtombs()\fR respectively, except
+that instead of operating in the current locale, they operate in the locale
 specified by \fIloc\fR.
 .SH RETURN VALUES
 .LP
@@ -86,7 +101,7 @@
 terminating null (if any).
 .SH ERRORS
 .LP
-The \fBwcsrtombs()\fR and \fBwcsrtombs_l()\fR functions may fail if:
+These functions may fail if:
 .sp
 .ne 2
 .na
@@ -120,8 +135,8 @@
 .TE
 
 .LP
-The \fBwcsrtombs()\fR function is Standard.  The \fBwcsrtombs_l()\fR
-function is Uncommitted.
+The \fBwcsrtombs()\fR and \fBwcsnrtombs()\fR functions are Standard.  The
+\fBwcsrtombs_l()\fR and \fBwcsnrtombs_l()\fR functions are Uncommitted.
 .LP
 If \fIps\fR is a null pointer, these functions should be considered Unsafe
 for use in multithreaded applications.  Otherwise, they are MT-Safe.
--- old/usr/src/man/man3lib/libc.3lib	Mon Jul 14 17:47:59 2014
+++ new/usr/src/man/man3lib/libc.3lib	Mon Jul 14 17:47:59 2014
@@ -778,6 +778,7 @@
 \fBwcscspn\fR	\fBwcsftime\fR
 \fBwcslen\fR	\fBwcsncat\fR
 \fBwcsncmp\fR	\fBwcsncpy\fR
+\fBwcsnrtombs\fR	\fBwcsnrtombs_l\fR
 \fBwcspbrk\fR	\fBwcsrchr\fR
 \fBwcsrtombs\fR	\fBwcsrtombs_l\fR
 \fBwcsspn\fR
--- old/usr/src/pkg/manifests/system-library.man3c.inc	Mon Jul 14 17:47:59 2014
+++ new/usr/src/pkg/manifests/system-library.man3c.inc	Mon Jul 14 17:47:59 2014
@@ -1312,8 +1312,11 @@
 link path=usr/share/man/man3c/wcsncat.3c target=wcstring.3c
 link path=usr/share/man/man3c/wcsncmp.3c target=wcstring.3c
 link path=usr/share/man/man3c/wcsncpy.3c target=wcstring.3c
+link path=usr/share/man/man3c/wcsnrtombs.3c target=wcsrtombs.3c
+link path=usr/share/man/man3c/wcsnrtombs_l.3c target=wcsrtombs.3c
 link path=usr/share/man/man3c/wcspbrk.3c target=wcstring.3c
 link path=usr/share/man/man3c/wcsrchr.3c target=wcstring.3c
+link path=usr/share/man/man3c/wcsrtombs_l.3c target=wcsrtombs.3c
 link path=usr/share/man/man3c/wcsspn.3c target=wcstring.3c
 link path=usr/share/man/man3c/wcstof.3c target=wcstod.3c
 link path=usr/share/man/man3c/wcstok.3c target=wcstring.3c
--- old/usr/src/pkg/manifests/system-test-libctest.mf	Mon Jul 14 17:48:00 2014
+++ new/usr/src/pkg/manifests/system-test-libctest.mf	Mon Jul 14 17:48:00 2014
@@ -29,9 +29,24 @@
 file path=opt/libc-tests/bin/libctest mode=0555
 file path=opt/libc-tests/runfiles/default.run mode=0444
 file path=opt/libc-tests/tests/newlocale_test mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/newlocale_test.amd64 mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/newlocale_test.i386 mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/newlocale_test.sparc mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/newlocale_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/nl_langinfo_test mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.amd64 mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.i386 mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.sparc mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/wcsrtombs_test mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.amd64 mode=0555
+$(i386_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.i386 mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.sparc mode=0555
+$(sparc_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.sparcv9 mode=0555
 license lic_CDDL license=lic_CDDL
 depend fmri=locale/de type=require
 depend fmri=locale/en type=require
+depend fmri=locale/en-extra type=require
 depend fmri=locale/ja type=require
 depend fmri=locale/ru type=require
 depend fmri=system/test/testrunner type=require
--- old/usr/src/test/libc-tests/doc/README	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/doc/README	Mon Jul 14 17:48:00 2014
@@ -25,7 +25,9 @@
 
 1. What this Unit Test Suite tests
 
-This Unit Test Suite is for testing various libc interfaces.
+This Unit Test Suite is for testing various libc interfaces.  The suite
+will test both 32 and 64 bit versions, provided that your kernel supports
+both.
 
 2. Building and installing this Unit Test Suite
 
@@ -55,12 +57,12 @@
 
 The pre-requisites for running the this Unit Test Suite are:
 	- Any user may perform these tests.
-	- The en_US.UTF-8, ja_JP.UTF-8, de_DE.UTF-8, and ru_RU.UTF-8 locales
-          must be installed.
+	- The en_US.UTF-8, en_GB.ISO8859-15, ja_JP.UTF-8, de_DE.UTF-8, and
+	  ru_RU.UTF-8 locales must be installed.
 
-Once the pre-requisites are satisfied, simply run the ostest script:
+Once the pre-requisites are satisfied, simply run the libctest script:
 
-	test_machine$ /opt/util-tests/bin/libctest
+	test_machine$ /opt/libc-tests/bin/libctest
 
 4. Test results
 
--- old/usr/src/test/libc-tests/runfiles/default.run	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/runfiles/default.run	Mon Jul 14 17:48:00 2014
@@ -23,3 +23,7 @@
 outputdir = /var/tmp/test_results
 
 [/opt/libc-tests/tests/newlocale_test]
+
+[/opt/libc-tests/tests/nl_langinfo_test]
+
+[/opt/libc-tests/tests/wcsrtombs_test]
--- old/usr/src/test/libc-tests/tests/Makefile	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/tests/Makefile	Mon Jul 14 17:48:00 2014
@@ -14,6 +14,7 @@
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 #
 
-SUBDIRS = newlocale
+SUBDIRS = newlocale nl_langinfo wcsrtombs
 
+include $(SRC)/Makefile.master
 include $(SRC)/test/Makefile.com
--- /dev/null	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/tests/Makefile.com	Mon Jul 14 17:48:00 2014
@@ -0,0 +1,89 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+include $(SRC)/Makefile.master
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+$(OBJS_OVERRIDE)OBJS = $(PROG).o test_common.o
+OBJS32 = $(OBJS:%.o=%.$(MACH).o)
+PROG32 = $(PROG).$(MACH)
+
+$(BUILD64) OBJS64 = $(OBJS:%.o=%.$(MACH64).o)
+$(BUILD64) PROG64= $(PROG).$(MACH64)
+
+$(OBJS_OVERRIDE)SRCS = $(PROG).c ../common/test_common.c
+
+C99MODE = -xc99=%all
+LINTFLAGS += -I../common -DARCH=\"ARCH\" -DLINT
+CPPFLAGS += -I../common
+
+ROOTOPTPKG = $(ROOT)/opt/libc-tests
+TESTDIR = $(ROOTOPTPKG)/tests
+
+CMDS = $(PROG32:%=$(TESTDIR)/%) $(PROG64:%=$(TESTDIR)/%) \
+	$(KSHPROG:%=$(TESTDIR)/%) $(ARCHPROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROG32) $(PROG64) $(KSHPROG) $(ARCHPROG) $(SUBDIRS)
+
+$(PROG32): $(OBJS32)
+	$(LINK.c) $(OBJS32) -o $@ $(LDLIBS)
+	$(POST_PROCESS)
+
+$(PROG64): $(OBJS64)
+	$(LINK64.c) $(OBJS64) -o $@ $(LDLIBS64)
+	$(POST_PROCESS)
+
+$(KSHPROG): $(KSHPROG).ksh
+	$(RM) $@
+	$(CP) $(KSHPROG).ksh $(@)
+	$(CHMOD) +x $@
+
+$(ARCHPROG): ../common/run_arch_tests.ksh
+	$(RM) $@
+	$(CP) ../common/run_arch_tests.ksh $(@)
+	$(CHMOD) +x $@
+
+%.$(MACH).o: %.c
+	$(COMPILE.c) -o $@ $(CFLAGS_$(MACH)) -DARCH=\"$(MACH)\" $<
+
+%.$(MACH).o: ../common/%.c
+	$(COMPILE.c) -o $@ $(CFLAGS_$(MACH)) -DARCH=\"$(MACH)\" $<
+
+%.$(MACH64).o: %.c
+	$(COMPILE64.c) -o $@ $(CFLAGS_$(MACH64)) -DARCH=\"$(MACH64)\" $<
+
+%.$(MACH64).o: ../common/%.c
+	$(COMPILE64.c) -o $@ $(CFLAGS_$(MACH64)) -DARCH=\"$(MACH64)\" $<
+
+install: $(SUBDIRS) $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+	-$(RM) $(PROG32) $(PROG64) $(KSHPROG) $(ARCHPROG)
+
+clean:
+	-$(RM) $(OBJS32) $(OBJS64)
+
+$(CMDS): $(TESTDIR) $(PROG32) $(PROG64) $(KSHPROG) $(ARCHPROG)
+
+$(TESTDIR):
+	$(INS.dir)
+
+$(TESTDIR)/%: %
+	$(INS.file)
--- /dev/null	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/tests/common/run_arch_tests.ksh	Mon Jul 14 17:48:00 2014
@@ -0,0 +1,65 @@
+#!/usr/bin/ksh
+#
+#
+# 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>
+#
+
+# First we set $dir to dirname $0, and $prog to basename $0 .ksh,
+# using efficient ksh builtins.
+case $0 in
+*/*)	
+	dir=${0%/*}
+	prog=${0##*/}
+	;;
+*)
+	dir=.
+	prog=${0}
+	;;
+esac
+prog=${prog%.ksh}
+
+for a in $* 
+do
+	if [[ $a == "-d" ]]
+	then
+		debug=yes
+	fi
+done
+
+# We look for architecture specific versions of the program,
+# searching in several candidate directories.  We run each one as
+# we find it.
+for f in $(/usr/bin/isainfo)
+do
+	found=
+	[[ -n $debug ]] && print "Checking for arch $f:"
+	for p in \
+		${dir}/${prog}.${f} \
+		${dir}/${f}/${prog}.${f} \
+		${dir}/${f}/${prog}
+	do
+		[[ -n $found ]] && continue
+		[[ -n $debug ]] && print -n "     $p"
+		if [[ -f $p ]]; then
+			[[ -n $debug ]] && print " FOUND"
+			[[ -n $debug ]] && print "Executing $p $*"
+			found=yes
+			$p $* || exit 1
+		else
+			[[ -n $debug ]] && print
+		fi
+	done
+	[[ -z $found ]] && [[ -n $debug ]] && print "NOT PRESENT"
+done
+exit 0
--- /dev/null	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/tests/common/test_common.c	Mon Jul 14 17:48:00 2014
@@ -0,0 +1,206 @@
+/*
+ * 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>
+ */
+
+/*
+ * Common handling for test programs.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include "test_common.h"
+
+static int debug = 0;
+static int force = 0;
+static pthread_mutex_t lk;
+
+struct test {
+	char		*name;
+	int		ntids;
+	pthread_t	*tids;
+	int		fails;
+	void		*arg;
+	void		(*func)(test_t t, void *);
+};
+
+void
+test_set_debug(void)
+{
+	debug++;
+}
+
+void
+test_set_force(void)
+{
+	force++;
+}
+
+test_t
+test_start(const char *format, ...)
+{
+	va_list args;
+	test_t t;
+	char *s;
+
+	t = calloc(1, sizeof (*t));
+	va_start(args, format);
+	(void) vasprintf(&s, format, args);
+	va_end(args);
+
+	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
+	free(s);
+
+	(void) pthread_mutex_lock(&lk);
+	(void) printf("TEST STARTING %s:\n", t->name);
+	(void) fflush(stdout);
+	(void) pthread_mutex_unlock(&lk);
+
+#ifdef	LINT
+	/* We inject references to make avoid name unused warnings */
+	test_run(0, NULL, NULL, NULL);
+	test_debugf(t, NULL);
+	test_failed(t, NULL);
+	test_passed(t);
+	test_set_debug();
+	test_set_force();
+#endif
+
+	return (t);
+
+}
+
+void
+test_failed(test_t t, const char *format, ...)
+{
+	va_list args;
+
+	(void) pthread_mutex_lock(&lk);
+	if (force || (t->ntids > 0)) {
+		(void) printf("TEST FAILING %s: ", t->name);
+	} else {
+		(void) printf("TEST FAILED %s: ", t->name);
+	}
+
+	va_start(args, format);
+	(void) vprintf(format, args);
+	va_end(args);
+	(void) printf("\n");
+	(void) fflush(stdout);
+	(void) pthread_mutex_unlock(&lk);
+
+	t->fails++;
+	if (!force) {
+		if (t->ntids > 0) {
+			pthread_exit(NULL);
+		} else {
+			(void) exit(EXIT_FAILURE);
+		}
+	}
+}
+
+void
+test_passed(test_t t)
+{
+	if (t->ntids > 0) {
+		if (debug) {
+			(void) pthread_mutex_lock(&lk);
+			(void) printf("TEST PASSING: %s\n", t->name);
+			(void) pthread_mutex_unlock(&lk);
+		}
+		return;
+	}
+	(void) pthread_mutex_lock(&lk);
+	if (t->fails == 0) {
+		(void) printf("TEST PASS: %s\n", t->name);
+	} else {
+		(void) printf("TEST FAILED: %d failures\n", t->fails);
+	}
+	(void) fflush(stdout);
+	(void) pthread_mutex_unlock(&lk);
+	free(t->name);
+	if (t->tids) {
+		free(t->tids);
+	}
+	free(t);
+}
+
+void
+test_debugf(test_t t, const char *format, ...)
+{
+	va_list args;
+
+	if (!debug)
+		return;
+
+	(void) pthread_mutex_lock(&lk);
+	(void) printf("TEST DEBUG %s: ", t->name);
+
+	va_start(args, format);
+	(void) vprintf(format, args);
+	va_end(args);
+	(void) printf("\n");
+	(void) fflush(stdout);
+	(void) pthread_mutex_unlock(&lk);
+}
+
+static void *
+test_thr_one(void *arg)
+{
+	test_t t = arg;
+	t->func(t, t->arg);
+	return (NULL);
+}
+
+void
+test_run(int nthr, void (*func)(test_t, void *), void *arg,
+    const char *tname, ...)
+{
+	test_t		t;
+	char		*s;
+	va_list		args;
+
+	t = calloc(1, sizeof (*t));
+	t->ntids = nthr;
+	t->tids = calloc(nthr, sizeof (pthread_t));
+	t->func = func;
+	t->arg = arg;
+
+	va_start(args, tname);
+	(void) vasprintf(&s, tname, args);
+	va_end(args);
+
+	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
+	free(s);
+
+	(void) pthread_mutex_lock(&lk);
+	(void) printf("TEST STARTING %s:\n", t->name);
+	(void) fflush(stdout);
+	(void) pthread_mutex_unlock(&lk);
+
+	test_debugf(t, "running %d threads", nthr);
+
+	for (int i = 0; i < nthr; i++) {
+		test_debugf(t, "started thread %d", i);
+		(void) pthread_create(&t->tids[i], NULL, test_thr_one, t);
+	}
+
+	for (int i = 0; i < nthr; i++) {
+		(void) pthread_join(t->tids[i], NULL);
+		test_debugf(t, "thread %d joined", i);
+		t->ntids--;
+	}
+	test_passed(t);
+}
--- /dev/null	Mon Jul 14 17:48:00 2014
+++ new/usr/src/test/libc-tests/tests/common/test_common.h	Mon Jul 14 17:48:00 2014
@@ -0,0 +1,41 @@
+/*
+ * 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>
+ */
+
+/*
+ * Common handling for test programs.
+ */
+
+#ifndef	_TEST_COMMON_H
+#define	_TEST_COMMON_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct test *test_t;
+typedef void (*test_func_t)(test_t, void *);
+
+extern void test_set_debug(void);
+extern void test_set_force(void);
+extern test_t test_start(const char *name, ...);
+extern void test_failed(test_t, const char *format, ...);
+extern void test_passed(test_t);
+extern void test_debugf(test_t, const char *format, ...);
+extern void test_run(int nthr, test_func_t, void *arg, const char *, ...);
+
+#ifdef	__cplusplus
+}
+#endif
+#endif	/* _TEST_COMMON_H */
--- old/usr/src/test/libc-tests/tests/newlocale/Makefile	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/newlocale/Makefile	Mon Jul 14 17:48:01 2014
@@ -10,48 +10,12 @@
 #
 
 #
-# Copyright (c) 2012 by Delphix. All rights reserved.
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 #
 
-include $(SRC)/cmd/Makefile.cmd
-include $(SRC)/test/Makefile.com
+include $(SRC)/Makefile.master
 
 PROG = newlocale_test
-OBJS = $(PROG:%=%.o)
-SRCS = $(OBJS:%.o=%.c)
+ARCHPROG = newlocale_test
 
-C99MODE = -xc99=%all
-
-ROOTOPTPKG = $(ROOT)/opt/libc-tests
-TESTDIR = $(ROOTOPTPKG)/tests
-
-CMDS = $(PROG:%=$(TESTDIR)/%)
-$(CMDS) := FILEMODE = 0555
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
-	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
-	$(POST_PROCESS)
-
-%.o: ../%.c
-	$(COMPILE.c) $<
-
-install: all $(CMDS)
-
-lint: lint_SRCS
-
-clobber: clean
-	-$(RM) $(PROG)
-
-clean:
-	-$(RM) $(OBJS)
-
-$(CMDS): $(TESTDIR) $(PROG)
-
-$(TESTDIR):
-	$(INS.dir)
-
-$(TESTDIR)/%: %
-	$(INS.file)
+include ../Makefile.com
--- old/usr/src/test/libc-tests/tests/newlocale/newlocale_test.c	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/newlocale/newlocale_test.c	Mon Jul 14 17:48:01 2014
@@ -29,9 +29,9 @@
 #include <err.h>
 #include <unistd.h>
 #include <pthread.h>
+#include <note.h>
+#include "test_common.h"
 
-int debug = 0;
-
 /*
  * Note that on some platforms, different symbols are used.  For example,
  * MacOS Mavericks uses "Eu" for Euro symbol, instead of €.  If the locale
@@ -53,47 +53,15 @@
 #define	NUMTHR	20
 #define	NUMITR	200
 
-static void
-test_start(const char *testName, const char *format, ...)
-{
-	va_list args;
+int extra_debug = 0;
 
-	(void) printf("TEST STARTING %s: ", testName);
-
-	va_start(args, format);
-	(void) vprintf(format, args);
-	va_end(args);
-	(void) fflush(stdout);
-}
-
-static void
-test_failed(const char *testName, const char *format, ...)
+void
+testlocale_thr_one(test_t t, void *arg)
 {
-	va_list args;
-
-	(void) printf("TEST FAILED %s: ", testName);
-
-	va_start(args, format);
-	(void) vprintf(format, args);
-	va_end(args);
-
-	(void) exit(-1);
-}
-
-static void
-test_passed(const char *testName)
-{
-	(void) printf("TEST PASS: %s\n", testName);
-	(void) fflush(stdout);
-}
-
-void *
-testlocale_thr(void *ptr)
-{
+	_NOTE(ARGUNUSED(arg));
 	locale_t	cloc, loc;
 	struct lconv	*lc;
 	char		*day;
-	char		*tname = ptr;
 
 	for (int i = 0; i < NUMITR; i++) {
 		struct ldata *l = &ldata[i % NUM_LDATA];
@@ -101,24 +69,24 @@
 
 		loc = newlocale(LC_ALL_MASK, l->locale, NULL);
 		if (loc == NULL) {
-			test_failed("newlocale %s failed", l->locale);
+			test_failed(t, "newlocale %s failed", l->locale);
 		}
 		day = nl_langinfo_l(DAY_1, loc);
 		if (strcmp(day, l->day1) != 0) {
-			test_failed(tname, "newlocale data mismatch (%s != %s)",
+			test_failed(t, "newlocale data mismatch (%s != %s)",
 			    day, l->day1);
 		}
-		if (debug)
-			(void) printf("DAY1: %s\n", day);
+		if (extra_debug)
+			test_debugf(t, "DAY1: %s", day);
 
 		day = nl_langinfo(DAY_1);
 		if (strcmp(day, "Sunday") != 0) {
-			test_failed(tname, "C locale day wrong %s != Sunday",
+			test_failed(t, "C locale day wrong %s != Sunday",
 			    day);
 		}
 		lc = localeconv();
 		if (strcmp(lc->currency_symbol, "") != 0) {
-			test_failed(tname, "C cursym mismatch (%s != %s)",
+			test_failed(t, "C cursym mismatch (%s != %s)",
 			    lc->currency_symbol, "");
 		}
 
@@ -128,68 +96,164 @@
 		(void) uselocale(loc);
 		day = nl_langinfo(DAY_1);
 		if (strcmp(day, l->day1) != 0) {
-			test_failed(tname, "uselocale data mismatch (%s != %s)",
+			test_failed(t, "uselocale data mismatch (%s != %s)",
 			    day, l->day1);
 		}
 
 		lc = localeconv();
 		if (strcmp(lc->currency_symbol, l->cursym) != 0) {
-			test_failed(tname, "uselocal cursym %s != %s",
+			test_failed(t, "uselocal cursym %s != %s",
 			    lc->currency_symbol, l->cursym);
 		}
-		if (debug)
-			(void) printf("CSYM: %s\n", lc->currency_symbol);
+		if (extra_debug)
+			test_debugf(t, "CSYM: %s", lc->currency_symbol);
 
 		/* we sleep a random bit to mix it up */
 		(void) usleep(rand() % 10);
 
 		if (uselocale(cloc) != loc) {
-			test_failed(tname, "revert old locale mismatch");
+			test_failed(t, "revert old locale mismatch");
 		}
 		freelocale(loc);
 		if (uselocale(LC_GLOBAL_LOCALE) != cloc) {
-			test_failed(tname, "revert GLOBAL_LOCALE mismatch");
+			test_failed(t, "revert GLOBAL_LOCALE mismatch");
 		}
 	}
-	return (NULL);
+	test_passed(t);
 }
 
 
 void
-testlocale(void)
+test_newlocale_threaded(void)
 {
-	char		*tname = "newlocale/uselocale";
-	pthread_t	tid[NUMTHR];
+	test_run(NUMTHR, testlocale_thr_one, NULL, "newlocale_threaded");
+}
 
-	test_start(tname, "running %d threads %d iterations\n", NUMTHR, NUMITR);
+void
+test_newlocale_negative(void)
+{
+	locale_t loc, bad;
+	char *day;
+	char *tname = "newlocale_negative";
+	test_t t;
 
-	for (int i = 0; i < NUMTHR; i++) {
-		(void) pthread_create(&tid[i], NULL, testlocale_thr, tname);
+	t = test_start(tname);
+	loc = newlocale(LC_ALL_MASK, "de_DE.UTF-8", NULL);
+	if (loc == NULL) {
+		test_failed(t, "cannot set de_DE.UTF-8");
 	}
+	day = nl_langinfo_l(DAY_1, loc);
+	if (strcmp(day, "Sonntag") != 0) {
+		test_failed(t, "incorrect Sonntag != %s", day);
+	}
 
-	for (int i = 0; i < NUMTHR; i++) {
-		(void) pthread_join(tid[i], NULL);
+	bad = newlocale(LC_ALL_MASK, "cn_US.BIZRRE", loc);
+	if (bad != NULL) {
+		test_failed(t, "passed setting bogus locale");
 	}
-	test_passed(tname);
+	day = nl_langinfo_l(DAY_1, loc);
+	if (strcmp(day, "Sonntag") != 0) {
+		test_failed(t, "incorrect Sonntag != %s", day);
+	}
+	test_passed(t);
 }
 
+void
+test_newlocale_categories(void)
+{
+	locale_t loc;
+	char *day, *cur, *yes;
+	char *tname = "newlocale_categories";
+	test_t t;
+
+	t = test_start(tname);
+
+	loc = NULL;
+	loc = newlocale(LC_TIME_MASK, "de_DE.UTF-8", loc);
+	loc = newlocale(LC_MESSAGES_MASK, "ru_RU.UTF-8", loc);
+	loc = newlocale(LC_MONETARY_MASK, "en_US.UTF-8", loc);
+
+	if (loc == NULL) {
+		test_failed(t, "failed to set locale");
+	}
+
+	day = nl_langinfo_l(DAY_1, loc);
+	if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) {
+		test_failed(t, "day1 mismatch %s != %s", day, "Sonntag");
+	}
+	yes = nl_langinfo_l(YESSTR, loc);
+	if ((yes == NULL) || (strcmp(yes, "да") != 0)) {
+		test_failed(t, "currency mismatch");
+	}
+	cur = nl_langinfo_l(CRNCYSTR, loc);
+	if ((cur == NULL) || (strcmp(cur, "-$") != 0)) {
+		test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$");
+	}
+
+	test_passed(t);
+}
+
+void
+test_newlocale_composite(void)
+{
+	locale_t loc;
+	char *day, *cur, *yes;
+	char *tname = "newlocale_composite";
+	test_t t;
+
+	t = test_start(tname);
+
+	/* order: CTYPE/NUMERIC/TIME/COLLATE/MONETARY/MESSAGES */
+	loc = newlocale(LC_ALL_MASK,
+	    "C/C/de_DE.UTF-8/C/en_US.UTF-8/ru_RU.UTF-8", NULL);
+
+	if (loc == NULL) {
+		test_failed(t, "failed to set composite locale");
+	}
+
+	day = nl_langinfo_l(DAY_1, loc);
+	if ((day == NULL) || (strcmp(day, "Sonntag") != 0)) {
+		test_failed(t, "day1 mismatch %s != %s", day, "Sonntag");
+	}
+	yes = nl_langinfo_l(YESSTR, loc);
+	if ((yes == NULL) || (strcmp(yes, "да") != 0)) {
+		test_failed(t, "currency mismatch");
+	}
+	cur = nl_langinfo_l(CRNCYSTR, loc);
+	if ((cur == NULL) || (strcmp(cur, "-$") != 0)) {
+		test_failed(t, "currency mismatch [%s] != [%s]", cur, "-$");
+	}
+
+	test_passed(t);
+}
+
 int
 main(int argc, char **argv)
 {
 	int optc;
 
-	while ((optc = getopt(argc, argv, "d")) != EOF) {
+	while ((optc = getopt(argc, argv, "Ddf")) != EOF) {
 		switch (optc) {
 		case 'd':
-			debug++;
+			test_set_debug();
 			break;
+		case 'f':
+			test_set_force();
+			break;
+		case 'D':
+			test_set_debug();
+			extra_debug++;
+			break;
 		default:
-			(void) fprintf(stderr, "Usage: %s [-d]\n", argv[0]);
+			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
 			exit(1);
 		}
 	}
 
-	testlocale();
+	test_newlocale_threaded();
+	test_newlocale_negative();
+	test_newlocale_categories();
+	test_newlocale_composite();
 
 	exit(0);
 }
--- /dev/null	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/nl_langinfo/Makefile	Mon Jul 14 17:48:01 2014
@@ -0,0 +1,21 @@
+#
+# 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>
+#
+
+include $(SRC)/Makefile.master
+
+PROG = nl_langinfo_test
+ARCHPROG = nl_langinfo_test
+
+include ../Makefile.com
--- /dev/null	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/nl_langinfo/nl_langinfo_test.c	Mon Jul 14 17:48:01 2014
@@ -0,0 +1,278 @@
+/*
+ * 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 program tests that newlocale and uselocale work properly in
+ * multi-threaded programs.  In order for it to work, it requires that
+ * some additional locales be installed.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <langinfo.h>
+#include <nl_types.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include "test_common.h"
+
+/*
+ * Note that on some platforms, different symbols are used.  For example,
+ * MacOS Mavericks uses "Eu" for Euro symbol, instead of €.  If the locale
+ * data changes, then this program will need to update to reflect that.
+ *
+ * Note also that this file is easiest edited with a UTF-8 capable editor,
+ * as there are embedded UTF-8 symbols in some of the strings.
+ */
+struct langinfo_test {
+	nl_item		param;
+	const char	*value;
+};
+
+struct langinfo_test C_data[] = {
+	{ CODESET,	"646" },
+	{ D_T_FMT,	"%a %b %e %H:%M:%S %Y" },
+	{ D_FMT,	"%m/%d/%y" },
+	{ T_FMT,	"%H:%M:%S" },
+	{ T_FMT_AMPM,	"%I:%M:%S %p" },
+	{ AM_STR,	"AM" },
+	{ PM_STR,	"PM" },
+	{ ERA,		"" },
+	{ ERA_D_FMT,	"" },
+	{ ERA_D_T_FMT,	"" },
+	{ ERA_T_FMT,	"" },
+	{ DAY_1,	"Sunday" },
+	{ DAY_7,	"Saturday" },
+	{ ABDAY_1,	"Sun" },
+	{ ABDAY_7,	"Sat" },
+	{ MON_1,	"January" },
+	{ MON_12,	"December" },
+	{ ABMON_1,	"Jan" },
+	{ ABMON_12,	"Dec" },
+	{ RADIXCHAR,	"." },
+	{ THOUSEP,	"" },
+	{ YESSTR,	"yes" },
+	{ NOSTR,	"no" },
+	{ YESEXPR,	"^[yY]" },
+	{ NOEXPR,	"^[nN]" },
+	{ CRNCYSTR,	"" },
+	{ -1,		NULL }
+};
+
+struct langinfo_test en_us_utf8_data[] = {
+	{ CODESET,	"UTF-8" },
+	{ D_T_FMT,	"%B %e, %Y %I:%M:%S %p %Z" },
+	{ D_FMT,	"%m/%e/%y" },
+	{ T_FMT,	"%I:%M:%S %p" },
+	{ T_FMT_AMPM,	"%I:%M:%S %p" },
+	{ AM_STR,	"AM" },
+	{ PM_STR,	"PM" },
+	{ ERA,		"" },
+	{ ERA_D_FMT,	"" },
+	{ ERA_D_T_FMT,	"" },
+	{ ERA_T_FMT,	"" },
+	{ DAY_1,	"Sunday" },
+	{ DAY_7,	"Saturday" },
+	{ ABDAY_1,	"Sun" },
+	{ ABDAY_7,	"Sat" },
+	{ MON_1,	"January" },
+	{ MON_12,	"December" },
+	{ ABMON_1,	"Jan" },
+	{ ABMON_12,	"Dec" },
+	{ RADIXCHAR,	"." },
+	{ THOUSEP,	"," },
+	{ YESSTR,	"yes" },
+	{ NOSTR,	"no" },
+	{ YESEXPR,	"^(([yY]([eE][sS])?))" },
+	{ NOEXPR,	"^(([nN]([oO])?))" },
+	{ CRNCYSTR,	"-$" },
+	{ -1,		NULL }
+};
+
+struct langinfo_test en_gb_latin15_data[] = {
+	{ CODESET,	"ISO8859-15" },
+	{ D_T_FMT,	"%e %B %Y %H:%M:%S %Z" },
+	{ D_FMT,	"%d/%m/%Y" },
+	{ T_FMT,	"%H:%M:%S" },
+	{ T_FMT_AMPM,	"%I:%M:%S %p" },
+	{ AM_STR,	"AM" },
+	{ PM_STR,	"PM" },
+	{ ERA,		"" },
+	{ ERA_D_FMT,	"" },
+	{ ERA_D_T_FMT,	"" },
+	{ ERA_T_FMT,	"" },
+	{ DAY_1,	"Sunday" },
+	{ DAY_7,	"Saturday" },
+	{ ABDAY_1,	"Sun" },
+	{ ABDAY_7,	"Sat" },
+	{ MON_1,	"January" },
+	{ MON_12,	"December" },
+	{ ABMON_1,	"Jan" },
+	{ ABMON_12,	"Dec" },
+	{ RADIXCHAR,	"." },
+	{ THOUSEP,	"," },
+	{ YESSTR,	"yes" },
+	{ NOSTR,	"no" },
+	{ YESEXPR,	"^(([yY]([eE][sS])?))" },
+	{ NOEXPR,	"^(([nN]([oO])?))" },
+	{ CRNCYSTR,	"-\243" },
+	{ -1,		NULL }
+};
+
+struct langinfo_test ru_ru_utf8_data[] = {
+	{ CODESET,	"UTF-8" },
+	{ D_T_FMT,	"%e %B %Y г. %H:%M:%S %Z"},
+	{ D_FMT,	"%d.%m.%y" },
+	{ T_FMT,	"%H:%M:%S" },
+	{ T_FMT_AMPM,	"%I:%M:%S %p" },
+	{ AM_STR,	"до полудня" },
+	{ PM_STR,	"после полудня" },
+	{ ERA,		"" },
+	{ ERA_D_FMT,	"" },
+	{ ERA_D_T_FMT,	"" },
+	{ ERA_T_FMT,	"" },
+	{ DAY_1,	"воскресенье" },
+	{ DAY_7,	"суббота" },
+	{ ABDAY_1,	"вс" },
+	{ ABDAY_7,	"сб" },
+	{ MON_1,	"января" },
+	{ MON_12,	"декабря" },
+	{ ABMON_1,	"янв" },
+	{ ABMON_12,	"дек" },
+	{ RADIXCHAR,	"," },
+	{ THOUSEP,	" " },
+	{ YESSTR,	"да" },
+	{ NOSTR,	"нет" },
+	{ YESEXPR,	"^(([дД]([аА])?)|([yY]([eE][sS])?))" },
+	{ NOEXPR,	"^(([нН]([еЕ][тТ])?)|([nN]([oO])?))" },
+	{ CRNCYSTR,	"+руб." },
+	{ -1,		NULL }
+};
+
+struct {
+	const char *locale;
+	struct langinfo_test *loctest;
+} locales[] =  {
+	{ "C",			C_data },
+	{ "en_US.UTF-8",	en_us_utf8_data },
+	{ "en_GB.ISO8859-15",	en_gb_latin15_data },
+	{ "ru_RU.UTF-8",	ru_ru_utf8_data },
+	{ NULL, 		NULL }
+};
+
+void
+test_nl_langinfo_1(const char *locale, struct langinfo_test *test)
+{
+	char 	tname[128];
+	char 	*v;
+	test_t	t;
+
+	(void) snprintf(tname, sizeof (tname), "nl_langinfo (locale %s)",
+	    locale);
+	t = test_start(tname);
+
+	v = setlocale(LC_ALL, locale);
+	if (v == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+	if (strcmp(v, locale) != 0) {
+		test_failed(t, "setlocale got %s instead of %s", v, locale);
+	}
+
+	for (int i = 0; test[i].value != NULL; i++) {
+		v = nl_langinfo(test[i].param);
+		test_debugf(t, "%d: expect [%s], got [%s]",
+		    test[i].param, test[i].value, v);
+		if (strcmp(v, test[i].value) != 0) {
+			test_failed(t,
+			    "param %d wrong, expected [%s], got [%s]",
+			    test[i].param, test[i].value, v);
+		}
+	}
+	test_passed(t);
+}
+
+void
+test_nl_langinfo_l(const char *locale, struct langinfo_test *test)
+{
+	char 		tname[128];
+	char 		*v;
+	test_t		t;
+	locale_t	loc;
+
+	(void) snprintf(tname, sizeof (tname), "nl_langinfo_l (locale %s)",
+	    locale);
+	t = test_start(tname);
+
+	v = setlocale(LC_ALL, "C");
+	if (v == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+	if (strcmp(v, "C") != 0) {
+		test_failed(t, "setlocale got %s instead of %s", v, "C");
+	}
+
+	loc = newlocale(LC_ALL_MASK, locale, NULL);
+	if (loc == NULL) {
+		test_failed(t, "newlocale failed: %s", strerror(errno));
+	}
+
+	for (int i = 0; test[i].value != NULL; i++) {
+		v = nl_langinfo_l(test[i].param, loc);
+		test_debugf(t, "%d: expect [%s], got [%s]",
+		    test[i].param, test[i].value, v);
+		if (strcmp(v, test[i].value) != 0) {
+			test_failed(t,
+			    "param %d wrong, expected [%s], got [%s]",
+			    test[i].param, test[i].value, v);
+		}
+	}
+	test_passed(t);
+}
+void
+test_nl_langinfo(void)
+{
+	for (int i = 0; locales[i].locale != NULL; i++) {
+		test_nl_langinfo_1(locales[i].locale, locales[i].loctest);
+		test_nl_langinfo_l(locales[i].locale, locales[i].loctest);
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int optc;
+
+	while ((optc = getopt(argc, argv, "df")) != EOF) {
+		switch (optc) {
+		case 'd':
+			test_set_debug();
+			break;
+		case 'f':
+			test_set_force();
+			break;
+		default:
+			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
+			exit(1);
+		}
+	}
+
+	test_nl_langinfo();
+
+	exit(0);
+}
--- /dev/null	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/wcsrtombs/Makefile	Mon Jul 14 17:48:01 2014
@@ -0,0 +1,21 @@
+#
+# 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>
+#
+
+include $(SRC)/Makefile.master
+
+PROG = wcsrtombs_test
+ARCHPROG = wcsrtombs_test
+
+include ../Makefile.com
--- /dev/null	Mon Jul 14 17:48:01 2014
+++ new/usr/src/test/libc-tests/tests/wcsrtombs/wcsrtombs_test.c	Mon Jul 14 17:48:01 2014
@@ -0,0 +1,388 @@
+/*
+ * 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 program tests that wcsrtombs and friends work properly.
+ * In order for it to work, it requires that some additional locales
+ * be installed.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <wchar.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <xlocale.h>
+#include <note.h>
+#include "test_common.h"
+
+int extra_debug = 0;
+
+#define	NUMTHR	300
+#define	NUMITR	300
+
+/*
+ * Note that this file is easiest edited with a UTF-8 capable editor,
+ * as there are embedded UTF-8 symbols in some of the strings.
+ */
+struct wcsrtombs_test {
+	char		mbs[32];
+	wchar_t		wcs[32];
+};
+
+#define	TESTING_MBS	"TESTING"
+#define	TESTING_WCS 	{ 'T', 'E', 'S', 'T', 'I', 'N', 'G', 0 }
+#define	HELLO_RU_MBS	"ПРИВЕТ"
+#define	HELLO_RU_WCS	{ 1055, 1056, 1048, 1042, 1045, 1058, 0 }
+#define	HELLO_EN_MBS	"HELLO"
+#define	HELLO_EN_WCS	{ 'H', 'E', 'L', 'L', 'O', 0 }
+
+/* Unicode values never have the high order bit set */
+#define	BAD_WCS		{ 'B', 'A', 'D', (wchar_t)0xf000f000, 'W', 'C', 'S' }
+
+struct wcsrtombs_test C_data[] = {
+	{ TESTING_MBS,	TESTING_WCS },
+	{ HELLO_EN_MBS,	HELLO_EN_WCS },
+	{ 0, 0 },
+};
+
+struct wcsrtombs_test utf8_data[] = {
+	{ TESTING_MBS,	TESTING_WCS },
+	{ HELLO_EN_MBS,	HELLO_EN_WCS },
+	{ HELLO_RU_MBS,	HELLO_RU_WCS },
+	{ 0, 0 },
+};
+
+struct {
+	const char *locale;
+	struct wcsrtombs_test *test;
+} locales[] =  {
+	{ "C",			C_data },
+	{ "en_US.UTF-8",	utf8_data },
+	{ NULL, 		NULL }
+};
+
+void
+test_wcsrtombs_1(const char *locale, struct wcsrtombs_test *test)
+{
+	test_t		t;
+	char 		*v;
+	mbstate_t	ms;
+
+	t = test_start("wcsrtombs (locale %s)", locale);
+
+	v = setlocale(LC_ALL, locale);
+	if (v == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+	if (strcmp(v, locale) != 0) {
+		test_failed(t, "setlocale got %s instead of %s", v, locale);
+	}
+
+	for (int i = 0; test[i].mbs[0] != 0; i++) {
+		char mbs[32];
+		const wchar_t *wcs = test[i].wcs;
+		size_t cnt;
+
+		(void) memset(&ms, 0, sizeof (ms));
+		(void) memset(mbs, 0, sizeof (mbs));
+		cnt = wcsrtombs(mbs, &wcs, sizeof (mbs), &ms);
+		if (cnt != strlen(test[i].mbs)) {
+			test_failed(t, "incorrect return value: %d != %d",
+			    cnt, strlen(test[i].mbs));
+		}
+		if (strcmp(mbs, test[i].mbs) != 0) {
+			test_failed(t, "wrong result: %s != %s",
+			    mbs, test[i].mbs);
+		}
+		if (extra_debug) {
+			test_debugf(t, "mbs is %s", mbs);
+		}
+	}
+	test_passed(t);
+}
+
+void
+test_wcsrtombs_l(const char *locale, struct wcsrtombs_test *test)
+{
+	test_t	t;
+	locale_t loc;
+	char 	*v;
+	mbstate_t	ms;
+
+	t = test_start("wcsrtombs_l (locale %s)", locale);
+
+	v = setlocale(LC_ALL, "C");
+	if (v == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+	if (strcmp(v, "C") != 0) {
+		test_failed(t, "setlocale got %s instead of %s", v, "C");
+	}
+
+	loc = newlocale(LC_ALL_MASK, locale, NULL);
+	if (loc == NULL) {
+		test_failed(t, "newlocale failed: %s", strerror(errno));
+	}
+
+	for (int i = 0; test[i].mbs[0] != 0; i++) {
+		char mbs[32];
+		const wchar_t *wcs = test[i].wcs;
+		size_t cnt;
+
+		(void) memset(&ms, 0, sizeof (ms));
+		(void) memset(mbs, 0, sizeof (mbs));
+		cnt = wcsrtombs_l(mbs, &wcs, sizeof (mbs), &ms, loc);
+		if (cnt != strlen(test[i].mbs)) {
+			test_failed(t, "incorrect return value: %d != %d",
+			    cnt, strlen(test[i].mbs));
+		}
+		if (strcmp(mbs, test[i].mbs) != 0) {
+			test_failed(t, "wrong result: %s != %s", mbs,
+			    test[i].mbs);
+		}
+		if (extra_debug) {
+			test_debugf(t, "mbs is %s", mbs);
+		}
+	}
+	test_passed(t);
+}
+
+void
+test_wcsrtombs_thr_iter(test_t t, const char *locale,
+    struct wcsrtombs_test *test)
+{
+	locale_t loc;
+	mbstate_t	ms;
+
+	loc = newlocale(LC_ALL_MASK, locale, NULL);
+	if (loc == NULL) {
+		test_failed(t, "newlocale failed: %s", strerror(errno));
+	}
+
+	for (int i = 0; test[i].mbs[0] != 0; i++) {
+		char mbs[32];
+		const wchar_t *wcs = test[i].wcs;
+		size_t cnt;
+
+		(void) memset(&ms, 0, sizeof (ms));
+		(void) memset(mbs, 0, sizeof (mbs));
+		cnt = wcsrtombs_l(mbs, &wcs, sizeof (mbs), &ms, loc);
+		if (cnt != strlen(test[i].mbs)) {
+			test_failed(t, "incorrect return value: %d != %d",
+			    cnt, strlen(test[i].mbs));
+		}
+		if (strcmp(mbs, test[i].mbs) != 0) {
+			test_failed(t, "wrong result: %s != %s", mbs,
+			    test[i].mbs);
+		}
+		if (extra_debug) {
+			test_debugf(t, "mbs is %s", mbs);
+		}
+	}
+
+	freelocale(loc);
+}
+
+void
+test_wcsrtombs_thr_work(test_t t, void *arg)
+{
+	_NOTE(ARGUNUSED(arg));
+	for (int j = 0; j < NUMITR; j++) {
+		test_debugf(t, "iteration %d", j);
+		for (int i = 0; locales[i].locale != NULL; i++) {
+			test_wcsrtombs_thr_iter(t, locales[i].locale,
+			    locales[i].test);
+		}
+	}
+	test_passed(t);
+}
+
+void
+test_wcsrtombs_threaded(void)
+{
+	(void) setlocale(LC_ALL, "C");
+	test_run(NUMTHR, test_wcsrtombs_thr_work, NULL, "wcsrtombs_threaded");
+}
+
+void
+test_wcsrtombs_partial(void)
+{
+	test_t		t;
+	mbstate_t	ms;
+	wchar_t		src[32] = HELLO_RU_WCS;
+	char		mbs[32];
+	char		*dst;
+	const wchar_t	*wcs;
+	size_t 		cnt;
+
+
+	(void) memset(&ms, 0, sizeof (ms));
+	t = test_start("wcsrtombs_partial");
+
+	if (setlocale(LC_ALL, "ru_RU.UTF-8") == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+
+	wcs = src;
+	dst = mbs;
+	cnt = wcsrtombs(dst, &wcs, 1, &ms);
+	if (cnt != 0) {
+		test_failed(t, "gave back a conversion cnt %d != 0", cnt);
+	}
+	if (wcs != src) {
+		test_failed(t, "incorrectly advanced wcs");
+	}
+
+	cnt = wcsrtombs(dst, &wcs, 2, &ms);
+	if (cnt != 2) {
+		test_failed(t, "gave back a conversion cnt %d != 2", cnt);
+	}
+	dst += cnt;
+
+	cnt = wcsrtombs(dst, &wcs, 4, &ms);
+	dst += cnt;
+
+	cnt = wcsrtombs(dst, &wcs, sizeof (mbs) - strlen(mbs), &ms);
+	if (extra_debug) {
+		test_debugf(t, "mbs is %s", mbs);
+	}
+	if (strcmp(mbs, HELLO_RU_MBS) != 0) {
+		test_failed(t, "wrong result: %s != %s", mbs, HELLO_RU_MBS);
+	}
+	test_passed(t);
+}
+
+void
+test_wcsrtombs_negative(void)
+{
+	mbstate_t	ms;
+	const wchar_t	*wcs;
+	char		mbs[32];
+	char		*dst;
+	int		e;
+	wchar_t		src[32] = BAD_WCS;
+	test_t		t;
+	int		cnt;
+
+	t = test_start("wcsrtombs_negative");
+
+	(void) memset(&ms, 0, sizeof (ms));
+	if (setlocale(LC_ALL, "ru_RU.UTF-8") == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+
+	wcs = src;
+	dst = mbs;
+	cnt = wcsrtombs(dst, &wcs, sizeof (mbs), &ms);
+	if (cnt != -1) {
+		test_failed(t, "bogus success (%d)", cnt);
+	}
+	if ((e = errno) != EILSEQ) {
+		test_failed(t, "wrong errno, wanted %d (EILSEQ), got %d: %s",
+		    EILSEQ, e, strerror(e));
+	}
+	test_passed(t);
+}
+
+void
+test_wcsnrtombs_partial(void)
+{
+	test_t		t;
+	mbstate_t	ms;
+	wchar_t		src[32] = HELLO_RU_WCS;
+	char		mbs[32];
+	char		*dst;
+	const wchar_t	*wcs;
+	size_t 		cnt;
+
+
+	(void) memset(&ms, 0, sizeof (ms));
+	t = test_start("wcsrntombs_partial");
+
+	if (setlocale(LC_ALL, "ru_RU.UTF-8") == NULL) {
+		test_failed(t, "setlocale failed: %s", strerror(errno));
+	}
+
+	wcs = src;
+	dst = mbs;
+	cnt = wcsnrtombs(dst, &wcs, 1, 1, &ms);
+	if (cnt != 0) {
+		test_failed(t, "gave back a conversion cnt %d != 0", cnt);
+	}
+	if (wcs != src) {
+		test_failed(t, "incorrectly advanced wcs");
+	}
+
+	/* we should get just 2 wide characters (expanding to 4 bytes) */
+	cnt = wcsnrtombs(dst, &wcs, 2, sizeof (mbs), &ms);
+	if (cnt != 4) {
+		test_failed(t, "gave back a conversion cnt %d != 4", cnt);
+	}
+	dst += cnt;
+
+	cnt = wcsnrtombs(dst, &wcs, 32, sizeof (mbs) - strlen(mbs), &ms);
+	if (extra_debug) {
+		test_debugf(t, "mbs is %s", mbs);
+	}
+	if (strcmp(mbs, HELLO_RU_MBS) != 0) {
+		test_failed(t, "wrong result: %s != %s", mbs, HELLO_RU_MBS);
+	}
+	test_passed(t);
+}
+
+void
+test_wcsrtombs(void)
+{
+	for (int i = 0; locales[i].locale != NULL; i++) {
+		test_wcsrtombs_1(locales[i].locale, locales[i].test);
+		test_wcsrtombs_l(locales[i].locale, locales[i].test);
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int optc;
+
+	while ((optc = getopt(argc, argv, "dfD")) != EOF) {
+		switch (optc) {
+		case 'd':
+			test_set_debug();
+			break;
+		case 'f':
+			test_set_force();
+			break;
+		case 'D':
+			test_set_debug();
+			extra_debug++;
+			break;
+		default:
+			(void) fprintf(stderr, "Usage: %s [-dfD]\n", argv[0]);
+			exit(1);
+		}
+	}
+
+	test_wcsrtombs();
+	test_wcsrtombs_partial();
+	test_wcsrtombs_negative();
+	test_wcsrtombs_threaded();
+	test_wcsnrtombs_partial();
+
+	exit(0);
+}
