summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/head/Makefile7
-rw-r--r--usr/src/head/uchar.h74
-rw-r--r--usr/src/lib/libc/amd64/Makefile4
-rw-r--r--usr/src/lib/libc/i386/Makefile.com4
-rw-r--r--usr/src/lib/libc/port/locale/big5.c4
-rw-r--r--usr/src/lib/libc/port/locale/c16rtomb.c78
-rw-r--r--usr/src/lib/libc/port/locale/c32rtomb.c50
-rw-r--r--usr/src/lib/libc/port/locale/euc.c6
-rw-r--r--usr/src/lib/libc/port/locale/gb18030.c6
-rw-r--r--usr/src/lib/libc/port/locale/gb2312.c6
-rw-r--r--usr/src/lib/libc/port/locale/gbk.c4
-rw-r--r--usr/src/lib/libc/port/locale/mblocal.h58
-rw-r--r--usr/src/lib/libc/port/locale/mbrtoc16.c91
-rw-r--r--usr/src/lib/libc/port/locale/mbrtoc32.c46
-rw-r--r--usr/src/lib/libc/port/locale/mbsinit.c18
-rw-r--r--usr/src/lib/libc/port/locale/mskanji.c4
-rw-r--r--usr/src/lib/libc/port/locale/unicode.h68
-rw-r--r--usr/src/lib/libc/port/locale/utf8.c6
-rw-r--r--usr/src/lib/libc/port/mapfile-vers8
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com4
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com4
-rw-r--r--usr/src/man/man3c/Makefile20
-rw-r--r--usr/src/man/man3c/c16rtomb.3c285
-rw-r--r--usr/src/man/man3c/mbrtoc16.3c397
-rw-r--r--usr/src/man/man3c/mbrtowc.3c231
-rw-r--r--usr/src/man/man3c/wcrtomb.3c146
-rw-r--r--usr/src/man/man3head/Makefile177
-rw-r--r--usr/src/man/man3head/uchar.h.3head95
-rw-r--r--usr/src/pkg/manifests/system-header.mf2
-rw-r--r--usr/src/pkg/manifests/system-library.man3c.inc12
-rw-r--r--usr/src/pkg/manifests/system-test-libctest.mf2
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run2
-rw-r--r--usr/src/test/libc-tests/tests/Makefile3
-rw-r--r--usr/src/test/libc-tests/tests/uchar.c789
-rw-r--r--usr/src/uts/common/sys/int_types.h3
35 files changed, 2199 insertions, 515 deletions
diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile
index e9beffdf71..bc9c57a6a6 100644
--- a/usr/src/head/Makefile
+++ b/usr/src/head/Makefile
@@ -198,6 +198,7 @@ HDRS= $($(MACH)_HDRS) \
time.h \
tiuser.h \
tzfile.h \
+ uchar.h \
ucontext.h \
ucred.h \
ulimit.h \
@@ -227,7 +228,7 @@ ISOHDRS = \
locale_iso.h \
math_c99.h \
math_iso.h \
- setjmp_iso.h \
+ setjmp_iso.h \
signal_iso.h \
stdarg_c99.h \
stdarg_iso.h \
@@ -243,7 +244,7 @@ ISOHDRS = \
wchar_iso.h \
wctype_iso.h
-ARPAHDRS = \
+ARPAHDRS = \
ftp.h \
inet.h \
nameser.h \
@@ -410,7 +411,7 @@ $(ROOT)/usr/include/%: %
.PARALLEL: $(ROOTHDRS) $(CHECKHDRS)
-install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(SYMHDRASSERT) $(SYMHDRERRNO) \
+install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(SYMHDRASSERT) $(SYMHDRERRNO) \
$(SYMHDRFLOAT) $(SYMHDRISO646)
check: $(CHECKHDRS)
diff --git a/usr/src/head/uchar.h b/usr/src/head/uchar.h
new file mode 100644
index 0000000000..83d998b4a1
--- /dev/null
+++ b/usr/src/head/uchar.h
@@ -0,0 +1,74 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+#ifndef _UCHAR_H
+#define _UCHAR_H
+
+/*
+ * C11 Unicode utilities support.
+ *
+ * Note, we do not define either __STDC_UTF_16__ or __STDC_UTF_32__. While the
+ * functions that are implemented work in that fashion, the ability to represent
+ * any UTF-16 or UTF-32 code point depends on the current locale. Though in
+ * practice they function that way.
+ */
+
+#include <sys/isa_defs.h>
+#include <sys/feature_tests.h>
+#include <wchar_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_SIZE_T) || __cplusplus >= 199711L
+#define _SIZE_T
+#if defined(_LP64) || defined(_I32LPx)
+typedef unsigned long size_t; /* size of something in bytes */
+#else
+typedef unsigned int size_t; /* (historical version) */
+#endif
+#endif /* _SIZE_T */
+
+#if !defined(_MBSTATE_T) || __cplusplus >= 199711L
+#define _MBSTATE_T
+typedef __mbstate_t mbstate_t;
+#endif /* _MBSTATE_T */
+
+/*
+ * These types must match the uint_least16_t and uint_least32_t. They are
+ * defined in terms of the same type so as to minimize the needed includes.
+ * C++11 also defines these types and they are considered built in, so we should
+ * not define them in that context.
+ */
+#if __cplusplus < 2011103L
+typedef unsigned short char16_t;
+typedef unsigned int char32_t;
+#endif
+
+extern size_t mbrtoc16(char16_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+ size_t, mbstate_t *_RESTRICT_KYWD);
+extern size_t mbrtoc32(char32_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+ size_t, mbstate_t *_RESTRICT_KYWD);
+extern size_t c16rtomb(char *_RESTRICT_KYWD, char16_t,
+ mbstate_t *_RESTRICT_KYWD);
+extern size_t c32rtomb(char *_RESTRICT_KYWD, char32_t,
+ mbstate_t *_RESTRICT_KYWD);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UCHAR_H */
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index 25ae31284c..d1e6809d83 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -747,6 +747,8 @@ PORTI18N_COND= \
PORTLOCALE= \
big5.o \
btowc.o \
+ c16rtomb.o \
+ c32rtomb.o \
collate.o \
collcmp.o \
euc.o \
@@ -772,6 +774,8 @@ PORTLOCALE= \
mbftowc.o \
mblen.o \
mbrlen.o \
+ mbrtoc16.o \
+ mbrtoc32.o \
mbrtowc.o \
mbsinit.o \
mbsnrtowcs.o \
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index 17bd421383..526c2fbc6f 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -794,6 +794,8 @@ PORTI18N_COND= \
PORTLOCALE= \
big5.o \
btowc.o \
+ c16rtomb.o \
+ c32rtomb.o \
collate.o \
collcmp.o \
euc.o \
@@ -819,6 +821,8 @@ PORTLOCALE= \
mbftowc.o \
mblen.o \
mbrlen.o \
+ mbrtoc16.o \
+ mbrtoc32.o \
mbrtowc.o \
mbsinit.o \
mbsnrtowcs.o \
diff --git a/usr/src/lib/libc/port/locale/big5.c b/usr/src/lib/libc/port/locale/big5.c
index 889b182de5..53b3a31f59 100644
--- a/usr/src/lib/libc/port/locale/big5.c
+++ b/usr/src/lib/libc/port/locale/big5.c
@@ -55,10 +55,6 @@ 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;
-
void
_BIG5_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/locale/c16rtomb.c b/usr/src/lib/libc/port/locale/c16rtomb.c
new file mode 100644
index 0000000000..050f06206e
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/c16rtomb.c
@@ -0,0 +1,78 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+/*
+ * C11 c16rtomb(3C) support.
+ *
+ * Convert a series of char16_t values into a series of multi-byte characters.
+ * We may be given a surrogate value, so we need to potentially store that in
+ * the interim.
+ */
+
+#include <uchar.h>
+#include <errno.h>
+#include "mblocal.h"
+#include "unicode.h"
+
+static mbstate_t c16rtomb_state;
+
+size_t
+c16rtomb(char *restrict str, char16_t c16, mbstate_t *restrict ps)
+{
+ char32_t c32;
+ _CHAR16State *c16s;
+
+ if (ps == NULL) {
+ ps = &c16rtomb_state;
+ }
+
+ if (str == NULL) {
+ c16 = L'\0';
+ }
+
+ c16s = (_CHAR16State *)ps;
+ if (c16s->c16_surrogate != 0) {
+ if (c16 > UNICODE_SUR_MAX || c16 < UNICODE_SUR_MIN ||
+ (c16 & UNICODE_SUR_LOWER) != UNICODE_SUR_LOWER) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ c32 = UNICODE_SUR_UVALUE(c16s->c16_surrogate) |
+ UNICODE_SUR_LVALUE(c16);
+ c32 += UNICODE_SUP_START;
+ c16s->c16_surrogate = 0;
+ } else if (c16 >= UNICODE_SUR_MIN && c16 <= UNICODE_SUR_MAX) {
+ /*
+ * The lower surrogate pair mask (dc00) overlaps the upper mask
+ * (d800), hence why we do a binary and with the upper mask.
+ */
+ if ((c16 & UNICODE_SUR_LOWER) != UNICODE_SUR_UPPER) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ c16s->c16_surrogate = c16;
+ return (0);
+ } else {
+ c32 = c16;
+ }
+
+ /*
+ * Call c32rtomb() and not wcrtomb() so that way all of the unicode code
+ * point validation is performed.
+ */
+ return (c32rtomb(str, c32, ps));
+}
diff --git a/usr/src/lib/libc/port/locale/c32rtomb.c b/usr/src/lib/libc/port/locale/c32rtomb.c
new file mode 100644
index 0000000000..a4d7a591f1
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/c32rtomb.c
@@ -0,0 +1,50 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+/*
+ * C11 c32rtomb(3C) support.
+ *
+ * The char32_t type is designed to represent a UTF-32 value, which is what we
+ * can represent with a wchar_t. This is basically a wrapper around wcrtomb().
+ */
+
+#include <locale.h>
+#include <wchar.h>
+#include <xlocale.h>
+#include <uchar.h>
+#include <errno.h>
+#include "unicode.h"
+
+static mbstate_t c32rtomb_state;
+
+size_t
+c32rtomb(char *restrict str, char32_t c32, mbstate_t *restrict ps)
+{
+ if ((c32 >= UNICODE_SUR_MIN && c32 <= UNICODE_SUR_MAX) ||
+ c32 > UNICODE_SUP_MAX) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ if (ps == NULL) {
+ ps = &c32rtomb_state;
+ }
+
+ if (str == NULL) {
+ c32 = L'\0';
+ }
+
+ return (wcrtomb_l(str, (wchar_t)c32, ps, uselocale((locale_t)0)));
+}
diff --git a/usr/src/lib/libc/port/locale/euc.c b/usr/src/lib/libc/port/locale/euc.c
index 1d1d25b17b..97c7bc3bea 100644
--- a/usr/src/lib/libc/port/locale/euc.c
+++ b/usr/src/lib/libc/port/locale/euc.c
@@ -101,12 +101,6 @@ static size_t _EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD,
static int _EUC_mbsinit(const mbstate_t *);
-typedef struct {
- wchar_t ch;
- int set;
- int want;
-} _EucState;
-
int
_EUC_mbsinit(const mbstate_t *ps)
{
diff --git a/usr/src/lib/libc/port/locale/gb18030.c b/usr/src/lib/libc/port/locale/gb18030.c
index 36c48c5cc5..3901270a8d 100644
--- a/usr/src/lib/libc/port/locale/gb18030.c
+++ b/usr/src/lib/libc/port/locale/gb18030.c
@@ -55,12 +55,6 @@ 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;
-
void
_GB18030_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/locale/gb2312.c b/usr/src/lib/libc/port/locale/gb2312.c
index bfb6c0177b..9b42060d10 100644
--- a/usr/src/lib/libc/port/locale/gb2312.c
+++ b/usr/src/lib/libc/port/locale/gb2312.c
@@ -50,12 +50,6 @@ 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;
-
void
_GB2312_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/locale/gbk.c b/usr/src/lib/libc/port/locale/gbk.c
index f422ce8fb5..6202091f87 100644
--- a/usr/src/lib/libc/port/locale/gbk.c
+++ b/usr/src/lib/libc/port/locale/gbk.c
@@ -55,10 +55,6 @@ 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;
-
void
_GBK_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/locale/mblocal.h b/usr/src/lib/libc/port/locale/mblocal.h
index 3d958e364e..2873962944 100644
--- a/usr/src/lib/libc/port/locale/mblocal.h
+++ b/usr/src/lib/libc/port/locale/mblocal.h
@@ -31,6 +31,64 @@
#include "runetype.h"
#include "lctype.h"
+#include <uchar.h>
+
+/*
+ * Actual implementation structures for mbstate_t data.
+ *
+ * All of the conversion states are independent of one another, with the
+ * exception of that used for mbrtoc16(). That needs to encode data not as a
+ * wide-character but as UTF-16 data, which means handling surrogate pairs. To
+ * minimize the amount of state in each locale, we instead have a conversion
+ * state for this which includes all the other conversion states, plus extra
+ * data to accomodate this.
+ */
+typedef struct {
+ wchar_t ch;
+} _BIG5State;
+
+typedef struct {
+ wchar_t ch;
+ int set;
+ int want;
+} _EucState;
+
+typedef struct {
+ int count;
+ uchar_t bytes[4];
+} _GB18030State;
+
+typedef struct {
+ int count;
+ uchar_t bytes[2];
+} _GB2312State;
+
+typedef struct {
+ wchar_t ch;
+} _GBKState;
+
+typedef struct {
+ wchar_t ch;
+} _MSKanjiState;
+
+typedef struct {
+ wchar_t ch;
+ int want;
+ wchar_t lbound;
+} _UTF8State;
+
+typedef struct {
+ union {
+ _BIG5State c16_big5;
+ _EucState c16_euc;
+ _GB18030State c16_gb18030;
+ _GB2312State c16_gb2312;
+ _GBKState c16_gbk;
+ _MSKanjiState c16_mskanji;
+ _UTF8State c16_utf8;
+ } c16_state;
+ char16_t c16_surrogate;
+} _CHAR16State;
/*
* Rune initialization function prototypes.
diff --git a/usr/src/lib/libc/port/locale/mbrtoc16.c b/usr/src/lib/libc/port/locale/mbrtoc16.c
new file mode 100644
index 0000000000..a8e6e8119b
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/mbrtoc16.c
@@ -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 2020 Robert Mustacchi
+ */
+
+/*
+ * C11 mbrtoc16(3C) support.
+ *
+ * The char16_t represents a UTF-16 encoding. This means that we have to deal
+ * with surrogate pairs.
+ */
+
+#include <locale.h>
+#include <wchar.h>
+#include <xlocale.h>
+#include <uchar.h>
+#include "mblocal.h"
+#include "unicode.h"
+
+#include <sys/debug.h>
+
+/*
+ * Ensure that we never cause our save state to ever exceed that of the
+ * mbstate_t. See the block comment in mblocal.h.
+ */
+CTASSERT(sizeof (_CHAR16State) <= sizeof (mbstate_t));
+
+static mbstate_t mbrtoc16_state;
+
+size_t
+mbrtoc16(char16_t *restrict pc16, const char *restrict str, size_t len,
+ mbstate_t *restrict ps)
+{
+ wchar_t wc;
+ size_t ret;
+ char16_t out;
+ _CHAR16State *c16s;
+
+ if (ps == NULL) {
+ ps = &mbrtoc16_state;
+ }
+
+ if (str == NULL) {
+ pc16 = NULL;
+ str = "";
+ len = 1;
+ }
+
+ c16s = (_CHAR16State *)ps;
+ if (c16s->c16_surrogate != 0) {
+ if (pc16 != NULL) {
+ *pc16 = c16s->c16_surrogate;
+ }
+ c16s->c16_surrogate = 0;
+ return ((size_t)-3);
+ }
+
+ ret = mbrtowc_l(&wc, str, len, ps, uselocale(NULL));
+ if ((ssize_t)ret < 0) {
+ return (ret);
+ }
+
+ /*
+ * If this character is not in the basic multilingual plane then we need
+ * a surrogate character to represent it in UTF-16 and we will need to
+ * write that out on the next iteration.
+ */
+ if (wc >= UNICODE_SUP_START) {
+ wc -= UNICODE_SUP_START;
+ c16s->c16_surrogate = UNICODE_SUR_LOWER | UNICODE_SUR_LMASK(wc);
+ out = UNICODE_SUR_UPPER | UNICODE_SUR_UMASK(wc);
+ } else {
+ out = (char16_t)wc;
+ }
+
+ if (pc16 != NULL) {
+ *pc16 = out;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libc/port/locale/mbrtoc32.c b/usr/src/lib/libc/port/locale/mbrtoc32.c
new file mode 100644
index 0000000000..46df3fb1f0
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/mbrtoc32.c
@@ -0,0 +1,46 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+/*
+ * C11 mbrtoc32(3C) support.
+ *
+ * The char32_t type is designed to represent UTF-32. Conveniently, the wchar_t
+ * is as well. In this case, we can just pass this directly to mbrtowc_l().
+ */
+
+#include <locale.h>
+#include <wchar.h>
+#include <xlocale.h>
+#include <uchar.h>
+
+static mbstate_t mbrtoc32_state;
+
+size_t
+mbrtoc32(char32_t *restrict pc32, const char *restrict str, size_t len,
+ mbstate_t *restrict ps)
+{
+ if (ps == NULL) {
+ ps = &mbrtoc32_state;
+ }
+
+ if (str == NULL) {
+ pc32 = NULL;
+ str = "";
+ len = 1;
+ }
+
+ return (mbrtowc_l((wchar_t *)pc32, str, len, ps,
+ uselocale((locale_t)0)));
+}
diff --git a/usr/src/lib/libc/port/locale/mbsinit.c b/usr/src/lib/libc/port/locale/mbsinit.c
index ae956d0f15..e6227ee62e 100644
--- a/usr/src/lib/libc/port/locale/mbsinit.c
+++ b/usr/src/lib/libc/port/locale/mbsinit.c
@@ -17,10 +17,28 @@
#include <locale.h>
#include "localeimpl.h"
#include "lctype.h"
+#include "mblocal.h"
int
mbsinit_l(const mbstate_t *s, locale_t loc)
{
+
+ /*
+ * To implement support for the C11 char16_t conversion functions
+ * (mbrtoc16() and c16rtomb()) we opted to leverage all of the existing
+ * conversion infrastructure, including the per-locale conversion
+ * structures. The char16_t conversion functions tack an extra member in
+ * the mbstate_t that occurs after all others have placed their data.
+ * Therefore, before we go to the per-locale backend we need to see if
+ * there is any outstanding state in the char16_t specific state.
+ */
+ if (s != NULL) {
+ const _CHAR16State *c16s = (const _CHAR16State *)s;
+ if (c16s->c16_surrogate != 0) {
+ return (0);
+ }
+ }
+
return (loc->ctype->lc_mbsinit(s));
}
diff --git a/usr/src/lib/libc/port/locale/mskanji.c b/usr/src/lib/libc/port/locale/mskanji.c
index 69955e5afa..a0a1f193ce 100644
--- a/usr/src/lib/libc/port/locale/mskanji.c
+++ b/usr/src/lib/libc/port/locale/mskanji.c
@@ -57,10 +57,6 @@ 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;
-
void
_MSKanji_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/locale/unicode.h b/usr/src/lib/libc/port/locale/unicode.h
new file mode 100644
index 0000000000..558ef2be13
--- /dev/null
+++ b/usr/src/lib/libc/port/locale/unicode.h
@@ -0,0 +1,68 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+#ifndef _UNICODE_H
+#define _UNICODE_H
+
+/*
+ * Common definitions for dealing with Unicode.
+ *
+ * UTF-16 encodes data as a series of two byte values. However, there are more
+ * than 16-bit of code points. Code points inside of the first 16-bits are
+ * referred to as existing in the 'basic multilingual plane' (BMP). Those
+ * outside of it are in the 'supplementary plane'. When such a code point is
+ * encountered, it is encoded as a series of two uint16_t values.
+ *
+ * A value which is up to 20 bits (the current limit of the unicode code point
+ * space) is encoded by splitting it into two 10-bit values. The upper 10 bits
+ * are ORed with 0xd800 and the lower 10 bits are ORed with 0xdc00.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Range of Unicode code points reserved for surrogate characters.
+ */
+#define UNICODE_SUR_MIN 0xd800
+#define UNICODE_SUR_MAX 0xdfff
+
+/*
+ * Range of Unicode code points in supplementary planes.
+ */
+#define UNICODE_SUP_START 0x10000
+#define UNICODE_SUP_MAX 0x10ffff
+
+/*
+ * Starting constants for surrogate pairs.
+ */
+#define UNICODE_SUR_UPPER 0xd800
+#define UNICODE_SUR_LOWER 0xdc00
+
+/*
+ * Macros to extract the value from a surrogate pair and to take a code point
+ * and transform it into the surrogate version.
+ */
+#define UNICODE_SUR_UVALUE(x) (((x) & 0x3ff) << 10)
+#define UNICODE_SUR_LVALUE(x) ((x) & 0x3ff)
+#define UNICODE_SUR_UMASK(x) (((x) >> 10) & 0x3ff)
+#define UNICODE_SUR_LMASK(x) ((x) & 0x3ff)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNICODE_H */
diff --git a/usr/src/lib/libc/port/locale/utf8.c b/usr/src/lib/libc/port/locale/utf8.c
index a6e037d94e..133bd3bf01 100644
--- a/usr/src/lib/libc/port/locale/utf8.c
+++ b/usr/src/lib/libc/port/locale/utf8.c
@@ -48,12 +48,6 @@ static size_t _UTF8_wcsnrtombs(char *_RESTRICT_KYWD,
const wchar_t **_RESTRICT_KYWD,
size_t, size_t, mbstate_t *_RESTRICT_KYWD);
-typedef struct {
- wchar_t ch;
- int want;
- wchar_t lbound;
-} _UTF8State;
-
void
_UTF8_init(struct lc_ctype *lct)
{
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 4e24603312..8cb88fb884 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -78,6 +78,14 @@ $if _x86 && _ELF64
$add amd64
$endif
+SYMBOL_VERSION ILLUMOS_0.33 {
+ protected:
+ c16rtomb;
+ c32rtomb;
+ mbrtoc16;
+ mbrtoc32;
+} ILLUMOS_0.32;
+
SYMBOL_VERSION ILLUMOS_0.32 {
protected:
fmemopen;
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 3fb4e21fe4..7d5155b373 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -823,6 +823,8 @@ PORTI18N_COND= \
PORTLOCALE= \
big5.o \
btowc.o \
+ c16rtomb.o \
+ c32rtomb.o \
collate.o \
collcmp.o \
euc.o \
@@ -848,6 +850,8 @@ PORTLOCALE= \
mbftowc.o \
mblen.o \
mbrlen.o \
+ mbrtoc16.o \
+ mbrtoc32.o \
mbrtowc.o \
mbsinit.o \
mbsnrtowcs.o \
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index afe2c70fa7..782f72d8e1 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -766,6 +766,8 @@ PORTI18N_COND= \
PORTLOCALE= \
big5.o \
btowc.o \
+ c16rtomb.o \
+ c32rtomb.o \
collate.o \
collcmp.o \
euc.o \
@@ -791,6 +793,8 @@ PORTLOCALE= \
mbftowc.o \
mblen.o \
mbrlen.o \
+ mbrtoc16.o \
+ mbrtoc32.o \
mbrtowc.o \
mbsinit.o \
mbsnrtowcs.o \
diff --git a/usr/src/man/man3c/Makefile b/usr/src/man/man3c/Makefile
index 958b23075a..1728df06e3 100644
--- a/usr/src/man/man3c/Makefile
+++ b/usr/src/man/man3c/Makefile
@@ -62,6 +62,7 @@ MANFILES= __fbufsize.3c \
bstring.3c \
btowc.3c \
byteorder.3c \
+ c16rtomb.3c \
call_once.3c \
catgets.3c \
catopen.3c \
@@ -238,7 +239,7 @@ MANFILES= __fbufsize.3c \
malloc.3c \
mblen.3c \
mbrlen.3c \
- mbrtowc.3c \
+ mbrtoc16.3c \
mbsinit.3c \
mbsrtowcs.3c \
mbstowcs.3c \
@@ -540,7 +541,6 @@ MANFILES= __fbufsize.3c \
waitpid.3c \
walkcontext.3c \
wcpcpy.3c \
- wcrtomb.3c \
wcscasecmp.3c \
wcscoll.3c \
wcsdup.3c \
@@ -726,6 +726,7 @@ MANLINKS= FD_CLR.3c \
bindtextdomain.3c \
btowc_l.3c \
bzero.3c \
+ c32rtomb.3c \
calloc.3c \
canonicalize_file_name.3c \
catclose.3c \
@@ -1003,6 +1004,8 @@ MANLINKS= FD_CLR.3c \
major.3c \
mblen_l.3c \
mbrlen_l.3c \
+ mbrtoc32.3c \
+ mbrtowc.3c \
mbrtowc_l.3c \
mbsinit_l.3c \
mbsnrtowcs.3c \
@@ -1382,6 +1385,7 @@ MANLINKS= FD_CLR.3c \
watol.3c \
watoll.3c \
wcpncpy.3c \
+ wcrtomb.3c \
wcrtomb_l.3c \
wcscasecmp_l.3c \
wcscat.3c \
@@ -1596,6 +1600,10 @@ ntohl.3c := LINKSRC = byteorder.3c
ntohll.3c := LINKSRC = byteorder.3c
ntohs.3c := LINKSRC = byteorder.3c
+c32rtomb.3c := LINKSRC = c16rtomb.3c
+wcrtomb.3c := LINKSRC = c16rtomb.3c
+wcrtomb_l.3c := LINKSRC = c16rtomb.3c
+
canonicalize_file_name.3c := LINKSRC = realpath.3c
catclose.3c := LINKSRC = catopen.3c
@@ -2009,10 +2017,12 @@ mblen_l.3c := LINKSRC = mblen.3c
mbrlen_l.3c := LINKSRC = mbrlen.3c
-mbrtowc_l.3c := LINKSRC = mbrtowc.3c
-
mbsinit_l.3c := LINKSRC = mbsinit.3c
+mbrtoc32.3c := LINKSRC = mbrtoc16.3c
+mbrtowc.3c := LINKSRC = mbrtoc16.3c
+mbrtowc_l.3c := LINKSRC = mbrtoc16.3c
+
mbsnrtowcs.3c := LINKSRC = mbsrtowcs.3c
mbsnrtowcs_l.3c := LINKSRC = mbsrtowcs.3c
mbsrtowcs_l.3c := LINKSRC = mbsrtowcs.3c
@@ -2506,8 +2516,6 @@ printstack.3c := LINKSRC = walkcontext.3c
wcpncpy.3c := LINKSRC = wcpcpy.3c
-wcrtomb_l.3c := LINKSRC = wcrtomb.3c
-
wcscasecmp_l.3c := LINKSRC = wcscasecmp.3c
wcsncasecmp.3c := LINKSRC = wcscasecmp.3c
wcsncasecmp_l.3c := LINKSRC = wcscasecmp.3c
diff --git a/usr/src/man/man3c/c16rtomb.3c b/usr/src/man/man3c/c16rtomb.3c
new file mode 100644
index 0000000000..33c6189dd3
--- /dev/null
+++ b/usr/src/man/man3c/c16rtomb.3c
@@ -0,0 +1,285 @@
+.\"
+.\" 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 2020 Robert Mustacchi
+.\"
+.Dd April 23, 2020
+.Dt C16RTOMB 3C
+.Os
+.Sh NAME
+.Nm c16rtomb ,
+.Nm c32rtomb ,
+.Nm wcrtomb ,
+.Nm wcrtomb_l
+.Nd convert wide-characters to character sequences
+.Sh SYNOPSIS
+.In uchar.h
+.Ft size_t
+.Fo c16rtomb
+.Fa "char *restrict str"
+.Fa "char16_t c16"
+.Fa "mbstate_t *restrict ps"
+.Fc
+.Ft size_t
+.Fo c32rtomb
+.Fa "char *restrict str"
+.Fa "char32_t c32"
+.Fa "mbstate_t *restrict ps"
+.Fc
+.In stdio.h
+.Ft size_t
+.Fo wcrtomb
+.Fa "char *restrict str"
+.Fa "wchar_t wc"
+.Fa "mbstate_t *restrict ps"
+.Fc
+.In stdio.h
+.In xlocale.h
+.Ft size_t
+.Fo wcrtomb_l
+.Fa "char *restrict str"
+.Fa "wchar_t wc"
+.Fa "mbstate_t *restrict ps"
+.Fa "locale_t loc"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn c16rtomb ,
+.Fn c32rtomb ,
+.Fn wcrtomb ,
+and
+.Fn wcrtomb_l
+functions convert wide-character sequences into a series of multi-byte
+characters.
+The functions work in the following formats:
+.Bl -tag -width wcrtomb_l
+.It Fn c16rtomb
+A UTF-16 code sequence, where every code point is represented by one or
+two
+.Vt char16_t .
+The UTF-16 encoding will encode certain Unicode code points as a pair of
+two 16-bit code sequences, commonly referred to as a surrogate pair.
+.It Fn c32rtomb
+A UTF-32 code sequence, where every code point is represented by a
+single
+.Vt char32_t .
+It is illegal to pass reserved Unicode code points.
+.It Fn wcrtomb , Fn wcrtomb_l
+Wide characters, being a 32-bit value where every code point is
+represented by a single
+.Vt wchar_t .
+While the
+.Vt wchar_t
+and
+.Vt char32_t
+are different types, in this implementation, they are similar encodings.
+.El
+.Pp
+The functions all work by looking at the passed in wide-character
+.Po
+.Fa c16 ,
+.Fa c32 ,
+.Fa wc
+.Pc
+and appending it to the current conversion state,
+.Fa ps .
+Once a valid code point, based on the current locale, is found, then it
+will be converted into a series of characters that are stored in
+.Fa str .
+Up to
+.Dv MB_CUR_MAX
+bytes will be stored in
+.Fa str .
+It is the caller's responsibility to ensure that there is sufficient
+space in
+.Fa str .
+.Pp
+The functions are all influenced by the
+.Dv LC_CTYPE
+category of the current locale for determining what is considered a
+valid character.
+For example, in the
+.Sy C
+locale,
+only ASCII characters are recognized, while in a
+.Sy UTF-8
+based locale like
+.Sy en_us.UTF-8 ,
+all valid Unicode code points are recognized and will be converted into
+the corresponding multi-byte sequence.
+The
+.Fn wcrtomb_l
+function uses the locale passed in
+.Fa loc
+rather than the locale of the current thread.
+.Pp
+The
+.Fa ps
+argument represents a multi-byte conversion state which can be used
+across multiple calls to a given function
+.Pq but not mixed between functions .
+These allow for characters to be consumed from subsequent buffers, e.g.
+different values of
+.Fa str .
+The functions may be called from multiple threads as long as they use
+unique values for
+.Fa ps .
+If
+.Fa ps
+is
+.Dv NULL ,
+then a function-specific buffer will be used for the conversion state;
+however, this is stored between all threads and its use is not
+recommended.
+.Pp
+The functions all have a special behavior when
+.Dv NULL
+is passed for
+.Fa str .
+They instead will treat it as though a the NULL wide-character was
+passed in
+.Fa c16 ,
+.Fa c32 ,
+or
+.Fa wc
+and an internal buffer
+.Pq buf
+will be used to write out the results of the
+converstion.
+In other words, the functions would be called as:
+.Bd -literal -offset indent
+c16rtomb(buf, L'\\0', ps)
+c32rtomb(buf, L'\\0', ps)
+wcrtomb(buf, L'\\0', ps)
+wcrtomb_l(buf, L'\\0', ps, loc)
+.Ed
+.Ss Locale Details
+Not all locales in the system are Unicode based locales.
+For example, ISO 8859 family locales have code points with values that
+do not match their counterparts in Unicode.
+When using these functions with non-Unicode based locales, the code
+points returned will be those determined by the locale.
+They will not be converted from the corresponding Unicode code point.
+For example, if using the Euro sign in ISO 8859-15, these functions
+will not encode the Unicode value 0x20ac into the ISO 8859-15 value
+0xa4.
+.Pp
+Regardless of the locale, the characters returned will be encoded as
+though the code point were the corresponding value in Unicode.
+This means that when using UTF-16, if the corresponding code point were
+in the range for surorgate pairs, then the
+.Fn c16rtomb
+function will expect to receive that code point in that fashion.
+.Pp
+This behavior of the
+.Fn c16rtomb
+and
+.Fn c32rtomb
+functions should not be relied upon, is not portable, and subject to
+change for non-Unicode locales.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn c16rtomb ,
+.Fn c32rtomb ,
+.Fn wcrtomb ,
+and
+.Fn wcrtomb_l
+functions return the number of bytes stored in
+.Fa str .
+Otherwise,
+.Sy (size_t)-1
+is returned to indicate an encoding error and
+.Va errno
+is set.
+.Sh EXAMPLES
+.Sy Example 1
+Converting a UTF-32 character into a multi-byte character sequence.
+.Bd -literal
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <stdio.h>
+#include <uchar.h>
+
+int
+main(void)
+{
+ mbstate_t mbs;
+ size_t ret;
+ char buf[MB_CUR_MAX];
+ char32_t val = 0x5149;
+ const char *uchar_exp = "\exe5\ex85\ex89";
+
+ (void) memset(&mbs, 0, sizeof (mbs));
+ (void) setlocale(LC_CTYPE, "en_US.UTF-8");
+ ret = c32rtomb(buf, val, &mbs);
+ if (ret != strlen(uchar_exp)) {
+ errx(EXIT_FAILURE, "failed to convert string, got %zd",
+ ret);
+ }
+
+ if (strncmp(buf, uchar_exp, ret) != 0) {
+ errx(EXIT_FAILURE, "converted char32_t does not match "
+ "expected value");
+ }
+
+ return (0);
+}
+.Ed
+.Sh ERRORS
+The
+.Fn c16rtomb ,
+.Fn c32rtomb ,
+.Fn wcrtomb ,
+and
+.Fn wcrtomb_l
+functions will fail if:
+.Bl -tag -width Er
+.It Er EINVAL
+The conversion state in
+.Fa ps
+is invalid.
+.It Er EILSEQ
+An invalid character sequence has been detected.
+.El
+.Sh MT-LEVEL
+The
+.Fn c16rtomb ,
+.Fn c32rtomb ,
+.Fn wcrtomb ,
+and
+.Fn wcrtomb_l
+functions are
+.Sy MT-Safe
+as long as different
+.Vt mbstate_t
+structures are passed in
+.Fa ps .
+If
+.Fa ps
+is
+.Dv NULL
+or different threads use the same value for
+.Fa ps ,
+then the functions are
+.Sy Unsafe .
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh SEE ALSO
+.Xr mbrtoc16 3C ,
+.Xr mbrtoc32 3C ,
+.Xr mbrtowc 3C ,
+.Xr newlocale 3C ,
+.Xr setlocale 3C ,
+.Xr uselocale 3C ,
+.Xr uchar.h 3HEAD ,
+.Xr environ 5
diff --git a/usr/src/man/man3c/mbrtoc16.3c b/usr/src/man/man3c/mbrtoc16.3c
new file mode 100644
index 0000000000..d1b3ab478b
--- /dev/null
+++ b/usr/src/man/man3c/mbrtoc16.3c
@@ -0,0 +1,397 @@
+.\"
+.\" 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 2020 Robert Mustacchi
+.\"
+.Dd April 23, 2020
+.Dt MBRTOC16 3C
+.Os
+.Sh NAME
+.Nm mbrtoc16 ,
+.Nm mbrtoc32 ,
+.Nm mbrtowc ,
+.Nm mbrtowc_l
+.Nd convert characters to wide characters
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fo mbrtowc
+.Fa "wchar_t *restrict pwc"
+.Fa "const char *restrict str"
+.Fa "size_t len"
+.Fa "mstate_t *restrict ps"
+.Fc
+.In wchar.h
+.In xlocale.h
+.Ft size_t
+.Fo mbrtowc
+.Fa "wchar_t *restrict pwc"
+.Fa "const char *restrict str"
+.Fa "size_t len"
+.Fa "mstate_t *restrict ps"
+.Fa "locale_t loc"
+.Fc
+.In uchar.h
+.Ft size_t
+.Fo mbrtoc16
+.Fa "char16_t *restrict p16c"
+.Fa "const char *restrict str"
+.Fa "size_t len"
+.Fa "mbstate_t *restrict ps"
+.Fc
+.Ft size_t
+.Fo mbrtoc32
+.Fa "char32_t *restrict p32c"
+.Fa "const char *restrict str"
+.Fa "size_t len"
+.Fa "mbstate_t *restrict ps"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbrtoc16 ,
+.Fn mbrtoc32 ,
+.Fn mbrtowc ,
+and
+.Fn mbrtowc_l
+functions convert character sequences, which may contain multi-byte
+characters, into different character formats.
+The functions work in the following formats:
+.Bl -tag -width mbrtowc_l
+.It Fn mbrtoc16
+A UTF-16 code sequence, where every code point is represented by one or
+two
+.Vt char16_t .
+The UTF-16 encoding will encode certain Unicode code points as a pair of
+two 16-bit code sequences, commonly referred to as a surrogate pair.
+.It Fn mbrtoc32
+A UTF-32 code sequence, where every code point is represented by a
+single
+.Vt char32_t .
+.It Fn mbrtowc , Fn mbrtowc_l
+Wide characters, being a 32-bit value where every code point is
+represented by a single
+.Vt wchar_t .
+While the
+.Vt wchar_t
+and
+.Vt char32_t
+are different types, in this implementation, they are similar encodings.
+.El
+.Pp
+The functions consume up to
+.Fa len
+characters from the string
+.Fa str
+and accumulate them in
+.Fa ps
+until a valid character is found, which is influenced by
+the
+.Dv LC_CTYPE
+category of the current locale.
+For example, in the
+.Sy C
+locale, only ASCII characters are recognized, while in a
+.Sy UTF-8
+based locale like
+.Sy en_US.UTF-8 ,
+UTF-8 multi-byte character sequences that represent Unicode code points
+are recognized.
+The
+.Fn mbrtowc_l
+function uses the locale passed in
+.Fa loc
+rather than the locale of the current thread.
+.Pp
+When a valid character sequence has been found, it is converted to
+either a 16-bit character sequence for
+.Fn mbrtoc16
+or a 32-bit character sequence for
+.Fn mbrtoc32
+and will be stored in
+.Fa p16c
+and
+.Fa p32c
+respectively.
+.Pp
+The
+.Fa ps
+argument represents a multi-byte conversion state which can be used
+across multiple calls to a given function
+.Pq but not mixed between functions .
+These allow for characters to be consumed from subsequent buffers, e.g.
+different values of
+.Fa str .
+The functions may be called from multiple threads as long as they use
+unique values for
+.Fa ps .
+If
+.Fa ps
+is
+.Dv NULL ,
+then a function-specific buffer will be used for the conversion state;
+however, this is stored between all threads and its use is not
+recommended.
+.Pp
+When using these functions, more than one character may be output for a
+given set of consumed input characters.
+An example of this is when a given code point is represented as a set of
+surrogate pairs in UTF-16, which require two 16-bit characters to
+represent a code point.
+When this occurs, the functions return the special return value
+.Sy -3 .
+.Pp
+The functions all have a special behavior when
+.Dv NULL
+is passed for
+.Fa str .
+They instead will treat it as though
+.Fa pwc ,
+.Fa p16c ,
+or
+.Fa p32c
+were
+.Dv NULL ,
+.Fa str
+had been passed as the empty string, "" and the length,
+.Fa len ,
+would appear as the value 1.
+In other words, the functions would be called as:
+.Bd -literal -offset indent
+mbrtowc(NULL, "", 1, ps)
+mbrtowc_l(NULL, "", 1, ps)
+mbrtoc16(NULL, "", 1, ps)
+mbrtoc32(NULL, "", 1, ps)
+.Ed
+.Ss Locale Details
+Not all locales in the system are Unicode based locales.
+For example, ISO 8859 family locales have code points with values that
+do not match their counterparts in Unicode.
+When using these functions with non-Unicode based locales, the code
+points returned will be those determined by the locale.
+They will not be converted to the corresponding Unicode code point.
+For example, if using the Euro sign in ISO 8859-15, these functions
+might return the code point 0xa4 and not the Unicode value 0x20ac.
+.Pp
+Regardless of the locale, the characters returned will be encoded as
+though the code point were the corresponding value in Unicode.
+This means that if a locale returns a value that would be a surrogate
+pair in the UTF-16 encoding, it will still be encoded as a UTF-16
+character.
+.Pp
+This behavior of the
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions should not be relied upon, is not portable, and subject to
+change for non-Unicode locales.
+.Sh RETURN VALUES
+The
+.Fn mbrtoc16 ,
+.Fn mbrtoc32 ,
+.Fn mbrtowc ,
+and
+.Fn mbrtowc_l
+functions return the following values:
+.Bl -tag -width (size_t)-3
+.It Sy 0
+.Fa len
+or fewer bytes of
+.Fa str
+were consumed and the null wide character was written into the wide
+character buffer
+.Po
+.Fa pwc ,
+.Fa p16c ,
+.Fa p32c
+.Pc .
+.It Sy between 1 and len
+The specified number of bytes were consumed and a single character was
+written into the wide character buffer
+.Po
+.Fa pwc ,
+.Fa p16c ,
+.Fa p32c
+.Pc .
+.It Sy (size_t)-1
+An encoding error has occurred.
+The next
+.Fa len
+bytes of
+.Fa str
+do not contribute to a valid character.
+.Va errno
+has been set to
+.Er EILSEQ .
+No data was written into the wide character buffer
+.Po
+.Fa pwc ,
+.Fa p16c ,
+.Fa p32c
+.Pc .
+.It Sy (size_t)-2
+.Fa len
+bytes of
+.Fa str
+were consumed, but a complete multi-byte character sequence has not been
+found and no data was written into the wide character buffer
+.Po
+.Fa pwc ,
+.Fa p16c ,
+.Fa p32c
+.Pc .
+.It Sy (size_t)-3
+A character has been written into the wide character buffer
+.Po
+.Fa pwc ,
+.Fa p16c ,
+.Fa p32c
+.Pc .
+This character was from a previous call (such as another part of a
+UTF-16 surrogate pair) and no input was consumed.
+This is limited to the
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions.
+.El
+.Sh EXAMPLES
+.Sy Example 1
+Using the
+.Fn mbrtoc32
+function to convert a multibyte string.
+.Bd -literal
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <stdio.h>
+#include <uchar.h>
+
+int
+main(void)
+{
+ mbstate_t mbs;
+ char32_t out;
+ size_t ret;
+ const char *uchar_str = "\exe5\ex85\ex89";
+
+ (void) memset(&mbs, 0, sizeof (mbs));
+ (void) setlocale(LC_CTYPE, "en_US.UTF-8");
+ ret = mbrtoc32(&out, uchar_str, strlen(uchar_str), &mbs);
+ if (ret != strlen(uchar_str)) {
+ errx(EXIT_FAILURE, "failed to convert string, got %zd",
+ ret);
+ }
+
+ (void) printf("Converted %zu bytes into UTF-32 character "
+ "0x%x\n", ret, out);
+ return (0);
+}
+.Ed
+.Pp
+When compiled and run, this produces:
+.Bd -literal -offset indent
+$ ./a.out
+Converted 3 bytes into UTF-32 character 0x5149
+.Ed
+.Pp
+.Sy Example 2
+Handling surrogate pairs from the
+.Fn mbrtoc16
+function.
+.Bd -literal
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <stdio.h>
+#include <uchar.h>
+
+int
+main(void)
+{
+ mbstate_t mbs;
+ char16_t first, second;
+ size_t ret;
+ const char *uchar_str = "\exf0\ex9f\ex92\exa9";
+
+ (void) memset(&mbs, '\0', sizeof (mbs));
+ (void) setlocale(LC_CTYPE, "en_US.UTF-8");
+ ret = mbrtoc16(&first, uchar_str, strlen(uchar_str), &mbs);
+ if (ret != strlen(uchar_str)) {
+ errx(EXIT_FAILURE, "failed to convert string, got %zd",
+ ret);
+ }
+
+ ret = mbrtoc16(&second, "", 0, &mbs);
+ if (ret != (size_t)-3) {
+ errx(EXIT_FAILURE, "didn't get second surrogate pair, "
+ "got %zd", ret);
+ }
+
+ (void) printf("UTF-16 surrogates: 0x%x 0x%x\n", first, second);
+ return (0);
+}
+.Ed
+.Pp
+When compiled and run, this produces:
+.Bd -literal -offset indent
+$ ./a.out
+UTF-16 surrogates: 0xd83d 0xdca9
+.Ed
+.Sh ERRORS
+The
+.Fn mbrtoc16 ,
+.Fn mbrtoc32 ,
+.Fn mbrtowc ,
+and
+.Fn mbrtowc_l
+functions will fail if:
+.Bl -tag -width Er
+.It Er EINVAL
+The conversion state in
+.Fa ps
+is invalid.
+.It Er EILSEQ
+An invalid character sequence has been detected.
+.El
+.Sh MT-LEVEL
+The
+.Fn mbrtoc16 ,
+.Fn mbrtoc32 ,
+.Fn mbrtowc ,
+and
+.Fn mbrtowc_l
+functions are
+.Sy MT-Safe
+as long as different
+.Vt mbstate_t
+structures are passed in
+.Fa ps .
+If
+.Fa ps
+is
+.Dv NULL
+or different threads use the same value for
+.Fa ps ,
+then the functions are
+.Sy Unsafe .
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh SEE ALSO
+.Xr c16rtomb 3C ,
+.Xr c32rtomb 3C ,
+.Xr newlocale 3C ,
+.Xr setlocale 3C ,
+.Xr uselocale 3C ,
+.Xr wcrtomb 3C ,
+.Xr uchar.h 3HEAD ,
+.Xr environ 5
diff --git a/usr/src/man/man3c/mbrtowc.3c b/usr/src/man/man3c/mbrtowc.3c
deleted file mode 100644
index 70fe73d25e..0000000000
--- a/usr/src/man/man3c/mbrtowc.3c
+++ /dev/null
@@ -1,231 +0,0 @@
-.\"
-.\" 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/.
-.\"
-.\" The Institute of Electrical and Electronics Engineers and The Open
-.\" Group, have given us permission to reprint portions of their
-.\" documentation.
-.\"
-.\" In the following statement, the phrase ``this text'' refers to portions
-.\" of the system documentation.
-.\"
-.\" Portions of this text are reprinted and reproduced in electronic form
-.\" in the SunOS Reference Manual, from IEEE Std 1003.1, 2004 Edition,
-.\" Standard for Information Technology -- Portable Operating System
-.\" Interface (POSIX), The Open Group Base Specifications Issue 6,
-.\" Copyright (C) 2001-2004 by the Institute of Electrical and Electronics
-.\" Engineers, Inc and The Open Group. In the event of any discrepancy
-.\" between these versions and the original IEEE and The Open Group
-.\" Standard, the original IEEE and The Open Group Standard is the referee
-.\" document. The original Standard can be obtained online at
-.\" http://www.opengroup.org/unix/online.html.
-.\"
-.\" This notice shall appear on any product containing this material.
-.\"
-.\" 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]
-.\"
-.\"
-.\" Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.
-.\" Portions Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved.
-.\" Copyright 2014 Garrett D'Amore <garrett@damore.org>
-.\"
-.TH MBRTOWC 3C "Jun 23, 2014"
-.SH NAME
-mbrtowc, mbrtowc_l \- convert a character to a wide-character code (restartable)
-.SH SYNOPSIS
-.LP
-.nf
-#include <wchar.h>
-
-\fBsize_t\fR \fBmbrtowc\fR(\fBwchar_t *restrict\fR \fIpwc\fR, \fBconst char *restrict\fR \fIs\fR, \fBsize_t\fR \fIn\fR,
- \fBmbstate_t *restrict\fR \fIps\fR);
-.fi
-.LP
-.nf
-#include <wchar.h>
-#include <xlocale.h>
-
-\fBsize_t\fR \fBmbrtowc_l\fR(\fBwchar_t *restrict\fR \fIpwc\fR, \fBconst char *restrict\fR \fIs\fR, \fBsize_t\fR \fIn\fR,
- \fBmbstate_t *restrict\fR \fIps\fR, \fBlocale_t\fR \fIloc\fR);
-.fi
-.SH DESCRIPTION
-.LP
-If
-.I s
-is a null pointer, the
-.B mbrtowc()
-function is equivalent to the call:
-.sp
-.in +2
-.nf
-\fBmbrtowc\fR(NULL, "", 1, \fIps\fR)
-.fi
-.in -2
-.LP
-Likewise, if
-.I s
-is a null pointer, the
-.B mbrtowc_l()
-function is equivalent to the call:
-.sp
-.in +2
-.nf
-\fBmbrtowc_l\fR(NULL, "", 1, \fIps\fR, \fIloc\fR);
-.fi
-.in -2
-.LP
-In these cases, the values of the arguments
-.I pwc
-and
-.I n
-are ignored.
-.LP
-If
-.I s
-is not a null pointer, these functions inspect at most
-.I n
-bytes beginning at the byte pointed to by
-.I s
-to determine the number of bytes needed to complete the next character
-(including any shift sequences). If the functions determine that the next
-character is completed,
-they determine the value of the corresponding wide-character and then, if
-.I pwc
-is not a null pointer, stores that value in the object pointed to by
-.IR pwc .
-If the corresponding wide-character is the null wide-character, the
-resulting state described is the initial conversion state.
-.LP
-If
-.I ps
-is a null pointer, these functions use their own
-internal
-.B mbstate_t
-object, which is initialized at program startup to the
-initial conversion state. Otherwise, the
-.B mbstate_t
-object pointed to by
-.I ps
-is used to completely describe the current conversion state of the
-associated character sequence. The system will behave as if no function defined
-in the Reference Manual calls
-.B mbrtowc()
-or
-.BR Bmbrtowc_l() .
-.LP
-The behavior of
-.B mbrtowc()
-is affected by the
-.B LC_CTYPE
-category of the current locale. The
-.B mbrtowc_l()
-function is affected by the
-.B LC_CTYPE
-category of the specified
-.I loc
-locale object. See
-.B environ (5).
-.SH RETURN VALUES
-.LP
-The
-.B mbrtowc()
-and
-.B mbrtowc_l()
-functions return the first of the following that applies:
-.IP \fB0\fR
-If the next
-.I n
-or fewer bytes complete the character that corresponds to
-the null wide-character (which is the value stored).
-.IP \fBpositive\fR
-If the next
-.I n
-or fewer bytes complete a valid character (which is the
-value stored); the value returned is the number of bytes that complete the
-character.
-.IP \fB(size_t)\(mi2\fR
-If the next
-.I n
-bytes contribute to an incomplete but potentially valid
-character, and all
-.I n
-bytes have been processed (no value is stored).
-When
-.I n
-has at least the value of the
-.B MB_CUR_MAX
-macro, this case can only occur if
-.I s
-points at a sequence of redundant shift sequences
-(for implementations with state-dependent encodings).
-.IP \fB(size_t)\(mi1\fR
-If an encoding error occurs, in which case the next \fIn\fR or fewer bytes do
-not contribute to a complete and valid character (no value is stored). In
-this case,
-.B EILSEQ
-is stored in
-.B errno
-and the conversion state is undefined.
-.SH ERRORS
-.LP
-The
-.B mbrtowc()
-and
-.B mbrtowc_l()
-functions may fail if:
-.IP \fBEINVAL\fR
-The
-.I ps
-argument points to an object that contains an invalid conversion
-state.
-.IP \fBEILSEQ\fR
-Invalid character sequence is detected.
-.SH ATTRIBUTES
-.LP
-See \fBattributes\fR(5) for descriptions of the following attributes:
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability See below.
-_
-MT-Level See below.
-.TE
-
-.LP
-The
-.B mbrtowc()
-function is Standard. The
-.B mbrtowc_l()
-function is Uncommitted.
-.LP
-If
-.I ps
-is a null pointer, these functions are Unsafe for use in
-multithreaded applications. Otherwise they are MT-Safe.
-.SH SEE ALSO
-.LP
-.BR mbsinit (3C),
-.BR newlocale (3C),
-.BR setlocale (3C),
-.BR uselocale (3C),
-.BR attributes (5),
-.BR environ (5),
-.BR standards (5)
diff --git a/usr/src/man/man3c/wcrtomb.3c b/usr/src/man/man3c/wcrtomb.3c
deleted file mode 100644
index 9a3478cb07..0000000000
--- a/usr/src/man/man3c/wcrtomb.3c
+++ /dev/null
@@ -1,146 +0,0 @@
-.\"
-.\" 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/.
-.\"
-.\" The Institute of Electrical and Electronics Engineers and The Open
-.\" Group, have given us permission to reprint portions of their
-.\" documentation.
-.\"
-.\" In the following statement, the phrase ``this text'' refers to portions
-.\" of the system documentation.
-.\"
-.\" Portions of this text are reprinted and reproduced in electronic form
-.\" in the SunOS Reference Manual, from IEEE Std 1003.1, 2004 Edition,
-.\" Standard for Information Technology -- Portable Operating System
-.\" Interface (POSIX), The Open Group Base Specifications Issue 6,
-.\" Copyright (C) 2001-2004 by the Institute of Electrical and Electronics
-.\" Engineers, Inc and The Open Group. In the event of any discrepancy
-.\" between these versions and the original IEEE and The Open Group
-.\" Standard, the original IEEE and The Open Group Standard is the referee
-.\" document. The original Standard can be obtained online at
-.\" http://www.opengroup.org/unix/online.html.
-.\"
-.\" This notice shall appear on any product containing this material.
-.\"
-.\" 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]
-.\"
-.\"
-.\" Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.
-.\" Portions Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved.
-.\" Copyright 2014 Garrett D'Amore <garrett@damore.org>
-.\"
-.TH WCRTOMB 3C "Jun 24, 2014"
-.SH NAME
-wcrtomb, wcrtomb_l \- convert a wide-character code to a character (restartable)
-.SH SYNOPSIS
-.LP
-.nf
-#include <stdio.h>
-
-\fBsize_t\fR \fBwcrtomb\fR(\fBchar *restrict\fR \fIs\fR, \fBwchar_t\fR \fIwc\fR, \fBmbstate_t *restrict\fR \fIps\fR);
-.fi
-.LP
-.nf
-#include <stdio.h>
-#include <xlocale.h>
-
-\fBsize_t\fR \fBwcrtomb_l\fR(\fBchar *restrict\fR \fIs\fR, \fBwchar_t\fR \fIwc\fR, \fBmbstate_t *restrict\fR \fIps\fR,
- \fBlocale_t\fR \fIloc\fR);
-.fi
-.SH DESCRIPTION
-.LP
-If \fIs\fR is a null pointer, the \fBwcrtomb()\fR function is equivalent to the
-call:
-.IP
-\fBwcrtomb\fR(\fIbuf\fR, L'\e0', \fIps\fR);
-.LP
-where \fIbuf\fR is an internal buffer.
-.LP
-If \fIs\fR is not a null pointer, the \fBwcrtomb()\fR function determines the
-number of bytes needed to represent the character that corresponds to the
-wide-character given by \fIwc\fR (including any shift sequences), and stores
-the resulting bytes in the array whose first element is pointed to by \fIs\fR.
-At most \fBMB_CUR_MAX\fR bytes are stored. If \fIwc\fR is a null
-wide-character, a null byte is stored, preceded by any shift sequence needed to
-restore the initial shift state. The resulting state described is the initial
-conversion state.
-.LP
-If \fIps\fR is a null pointer, the \fBwcrtomb()\fR function uses its 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
-associated character sequence. The system will behave as if no function
-defined in the Reference Manual calls \fBwcrtomb()\fR.
-.LP
-The behavior of \fBwcrtomb()\fR is affected by the \fBLC_CTYPE\fR category of the
-current locale. See \fBenviron\fR(5). The function \fBwcrtomb_l()\fR behaves
-identically to \fBwcrtomb()\fR, except instead of operating in the current
-locale, it operates in the locale specified by \fIloc\fR.
-.SH RETURN VALUES
-.LP
-The \fBwcrtomb()\fR function returns the number of bytes stored in the array
-object (including any shift sequences). When \fIwc\fR is not a valid
-wide-character, an encoding error occurs. In this case, the function stores
-the value of the macros \fBEILSEQ\fR in \fBerrno\fR and returns
-\fB(size_t)\(mi1\fR; the conversion state is undefined.
-.SH ERRORS
-.LP
-The \fBwcrtomb()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 10n
-The \fIps\fR argument points to an object that contains an invalid conversion
-state.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEILSEQ\fR\fR
-.ad
-.RS 10n
-Invalid wide-character code is detected.
-.RE
-.SH ATTRIBUTES
-.LP
-See \fBattributes\fR(5) for descriptions of the following attributes:
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability See below.
-_
-MT-Level See below.
-.TE
-
-.LP
-The \fBwcrtomb()\fR function is Standard. The
-\fBwcrtomb_l()\fR function is 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.
-.SH SEE ALSO
-.LP
-\fBmbsinit\fR(3C), \fBnewlocale\fR(3C), \fBsetlocale\fR(3C),
-\fBuselocale\fR(3C), \fBattributes\fR(5),
-\fBstandards\fR(5), \fBenviron\fR(5)
diff --git a/usr/src/man/man3head/Makefile b/usr/src/man/man3head/Makefile
index e212c67457..fdc94ef4ef 100644
--- a/usr/src/man/man3head/Makefile
+++ b/usr/src/man/man3head/Makefile
@@ -17,98 +17,99 @@
include $(SRC)/Makefile.master
-MANSECT= 3head
+MANSECT= 3head
MANFILES= acct.h.3head \
- aio.h.3head \
- ar.h.3head \
- archives.h.3head \
- assert.h.3head \
- complex.h.3head \
- cpio.h.3head \
- dirent.h.3head \
+ aio.h.3head \
+ ar.h.3head \
+ archives.h.3head \
+ assert.h.3head \
+ complex.h.3head \
+ cpio.h.3head \
+ dirent.h.3head \
endian.h.3head \
- errno.h.3head \
- fcntl.h.3head \
- fenv.h.3head \
- float.h.3head \
- floatingpoint.h.3head \
- fmtmsg.h.3head \
- fnmatch.h.3head \
- ftw.h.3head \
- glob.h.3head \
- grp.h.3head \
- iconv.h.3head \
- if.h.3head \
- in.h.3head \
- inet.h.3head \
- inttypes.h.3head \
- ipc.h.3head \
- iso646.h.3head \
- langinfo.h.3head \
- libgen.h.3head \
- libintl.h.3head \
- limits.h.3head \
- locale.h.3head \
- math.h.3head \
- mman.h.3head \
- monetary.h.3head \
- mqueue.h.3head \
- msg.h.3head \
- ndbm.h.3head \
- netdb.h.3head \
- nl_types.h.3head \
- poll.h.3head \
- pthread.h.3head \
- pwd.h.3head \
+ errno.h.3head \
+ fcntl.h.3head \
+ fenv.h.3head \
+ float.h.3head \
+ floatingpoint.h.3head \
+ fmtmsg.h.3head \
+ fnmatch.h.3head \
+ ftw.h.3head \
+ glob.h.3head \
+ grp.h.3head \
+ iconv.h.3head \
+ if.h.3head \
+ in.h.3head \
+ inet.h.3head \
+ inttypes.h.3head \
+ ipc.h.3head \
+ iso646.h.3head \
+ langinfo.h.3head \
+ libgen.h.3head \
+ libintl.h.3head \
+ limits.h.3head \
+ locale.h.3head \
+ math.h.3head \
+ mman.h.3head \
+ monetary.h.3head \
+ mqueue.h.3head \
+ msg.h.3head \
+ ndbm.h.3head \
+ netdb.h.3head \
+ nl_types.h.3head \
+ poll.h.3head \
+ pthread.h.3head \
+ pwd.h.3head \
queue.h.3head \
- regex.h.3head \
- resource.h.3head \
- sched.h.3head \
- search.h.3head \
- select.h.3head \
- sem.h.3head \
- semaphore.h.3head \
- setjmp.h.3head \
- shm.h.3head \
- siginfo.h.3head \
- signal.h.3head \
- socket.h.3head \
- spawn.h.3head \
- stat.h.3head \
- statvfs.h.3head \
- stdbool.h.3head \
- stddef.h.3head \
- stdint.h.3head \
- stdio.h.3head \
- stdlib.h.3head \
- string.h.3head \
- strings.h.3head \
- stropts.h.3head \
- syslog.h.3head \
- tar.h.3head \
- tcp.h.3head \
- termios.h.3head \
- tgmath.h.3head \
- time.h.3head \
- timeb.h.3head \
- times.h.3head \
- types.h.3head \
- types32.h.3head \
- ucontext.h.3head \
- uio.h.3head \
- ulimit.h.3head \
- un.h.3head \
- unistd.h.3head \
- utime.h.3head \
- utmpx.h.3head \
- utsname.h.3head \
- values.h.3head \
- wait.h.3head \
- wchar.h.3head \
- wctype.h.3head \
- wordexp.h.3head \
- xlocale.h.3head
+ regex.h.3head \
+ resource.h.3head \
+ sched.h.3head \
+ search.h.3head \
+ select.h.3head \
+ sem.h.3head \
+ semaphore.h.3head \
+ setjmp.h.3head \
+ shm.h.3head \
+ siginfo.h.3head \
+ signal.h.3head \
+ socket.h.3head \
+ spawn.h.3head \
+ stat.h.3head \
+ statvfs.h.3head \
+ stdbool.h.3head \
+ stddef.h.3head \
+ stdint.h.3head \
+ stdio.h.3head \
+ stdlib.h.3head \
+ string.h.3head \
+ strings.h.3head \
+ stropts.h.3head \
+ syslog.h.3head \
+ tar.h.3head \
+ tcp.h.3head \
+ termios.h.3head \
+ tgmath.h.3head \
+ time.h.3head \
+ timeb.h.3head \
+ times.h.3head \
+ types.h.3head \
+ types32.h.3head \
+ uchar.h.3head \
+ ucontext.h.3head \
+ uio.h.3head \
+ ulimit.h.3head \
+ un.h.3head \
+ unistd.h.3head \
+ utime.h.3head \
+ utmpx.h.3head \
+ utsname.h.3head \
+ values.h.3head \
+ wait.h.3head \
+ wchar.h.3head \
+ wctype.h.3head \
+ wordexp.h.3head \
+ xlocale.h.3head
MANLINKS= \
LIST_CLASS_ENTRY.3head \
diff --git a/usr/src/man/man3head/uchar.h.3head b/usr/src/man/man3head/uchar.h.3head
new file mode 100644
index 0000000000..cb34b7f69a
--- /dev/null
+++ b/usr/src/man/man3head/uchar.h.3head
@@ -0,0 +1,95 @@
+.\"
+.\" 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 2020 Robert Mustacchi
+.\"
+.Dd April 22, 2020
+.Dt UCHAR.H 3HEAD
+.Os
+.Sh NAME
+.Nm uchar.h
+.Nd unicode utilities header
+.Sh SYNOPSIS
+.In uchar.h
+.Sh DESCRIPTION
+The
+.In uchar.h
+header provides support for the C11 Unicode utilities.
+The types and functions provide means for working with data encoded as
+UTF-16 and UTF-32.
+When working in non-Unicode locales, these types may not represent
+Unicode code points.
+.Pp
+The
+.In uchar.h
+header defines the following types:
+.Bl -tag -width Vt
+.It Vt char16_t
+An unsigned integer that can represent 16-bit characters, generally a
+single single UTF-16 code unit.
+A Unicode code point may be one or two UTF-16 code units due to
+surrogate pairs.
+.It Vt char32_t
+An unsigned integer that can represent 32-bit characters, generally a
+single UTF-32 code unit.
+.It Vt size_t
+An unsigned integer that represents the size of various objects.
+This can hold the result of the
+.Sy sizeof
+operator.
+See also
+.Xr stddef.h 3HEAD .
+.It Vt mbstate_t
+An object that holds the state for converting between character
+sequences and wide characters
+.Po
+.Vt wchar_t ,
+.Vt char16_t ,
+.Vt char32_t
+.Pc .
+See also,
+.Xr wchar.h 3HEAD .
+.El
+The
+.In uchar.h
+header also defines the following functions which are used to convert
+between
+.Vt char16_t
+and
+.Vt char32_t
+sequences and other character sequences:
+.Bl -tag -width cr16rtomb
+.It Xr c16rtomb 3C
+Convert
+.Vt char16_t
+sequences to multi-byte character sequences.
+.It Xr c32rtomb 3C
+Convert
+.Vt char32_t
+sequences to multi-byte character sequences.
+.It Xr mbrtoc16 3C
+Convert multi-byte character sequences to
+.Vt char16_t
+sequences.
+.It Xr mbrtoc32 3C
+Convert multi-byte character sequences to
+.Vt char32_t
+sequences.
+.El
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh SEE ALSO
+.Xr c16rtomb 3C ,
+.Xr c32rtomb 3C ,
+.Xr mbrtoc16 3C ,
+.Xr mbrtoc32 3C ,
+.Xr stddef.h 3HEAD ,
+.Xr wchar.h 3HEAD
diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf
index 5098ae075a..8a5436aba7 100644
--- a/usr/src/pkg/manifests/system-header.mf
+++ b/usr/src/pkg/manifests/system-header.mf
@@ -1604,6 +1604,7 @@ file path=usr/include/time.h
file path=usr/include/tiuser.h
file path=usr/include/tsol/label.h
file path=usr/include/tzfile.h
+file path=usr/include/uchar.h
file path=usr/include/ucontext.h
file path=usr/include/ucred.h
file path=usr/include/uid_stp.h
@@ -1910,6 +1911,7 @@ file path=usr/share/man/man3head/timeb.h.3head
file path=usr/share/man/man3head/times.h.3head
file path=usr/share/man/man3head/types.h.3head
file path=usr/share/man/man3head/types32.h.3head
+file path=usr/share/man/man3head/uchar.h.3head
file path=usr/share/man/man3head/ucontext.h.3head
file path=usr/share/man/man3head/uio.h.3head
file path=usr/share/man/man3head/ulimit.h.3head
diff --git a/usr/src/pkg/manifests/system-library.man3c.inc b/usr/src/pkg/manifests/system-library.man3c.inc
index 7317e92fce..ce6056ce82 100644
--- a/usr/src/pkg/manifests/system-library.man3c.inc
+++ b/usr/src/pkg/manifests/system-library.man3c.inc
@@ -58,6 +58,7 @@ file path=usr/share/man/man3c/bsearch.3c
file path=usr/share/man/man3c/bstring.3c
file path=usr/share/man/man3c/btowc.3c
file path=usr/share/man/man3c/byteorder.3c
+file path=usr/share/man/man3c/c16rtomb.3c
file path=usr/share/man/man3c/call_once.3c
file path=usr/share/man/man3c/catgets.3c
file path=usr/share/man/man3c/catopen.3c
@@ -234,7 +235,7 @@ file path=usr/share/man/man3c/makedev.3c
file path=usr/share/man/man3c/malloc.3c
file path=usr/share/man/man3c/mblen.3c
file path=usr/share/man/man3c/mbrlen.3c
-file path=usr/share/man/man3c/mbrtowc.3c
+file path=usr/share/man/man3c/mbrtoc16.3c
file path=usr/share/man/man3c/mbsinit.3c
file path=usr/share/man/man3c/mbsrtowcs.3c
file path=usr/share/man/man3c/mbstowcs.3c
@@ -536,7 +537,6 @@ file path=usr/share/man/man3c/wait3.3c
file path=usr/share/man/man3c/waitpid.3c
file path=usr/share/man/man3c/walkcontext.3c
file path=usr/share/man/man3c/wcpcpy.3c
-file path=usr/share/man/man3c/wcrtomb.3c
file path=usr/share/man/man3c/wcscasecmp.3c
file path=usr/share/man/man3c/wcscoll.3c
file path=usr/share/man/man3c/wcsdup.3c
@@ -722,6 +722,7 @@ link path=usr/share/man/man3c/bind_textdomain_codeset.3c target=gettext.3c
link path=usr/share/man/man3c/bindtextdomain.3c target=gettext.3c
link path=usr/share/man/man3c/btowc_l.3c target=btowc.3c
link path=usr/share/man/man3c/bzero.3c target=bstring.3c
+link path=usr/share/man/man3c/c32rtomb.3c target=c16rtomb.3c
link path=usr/share/man/man3c/calloc.3c target=malloc.3c
link path=usr/share/man/man3c/canonicalize_file_name.3c target=realpath.3c
link path=usr/share/man/man3c/catclose.3c target=catopen.3c
@@ -1006,7 +1007,9 @@ link path=usr/share/man/man3c/lrand48.3c target=drand48.3c
link path=usr/share/man/man3c/major.3c target=makedev.3c
link path=usr/share/man/man3c/mblen_l.3c target=mblen.3c
link path=usr/share/man/man3c/mbrlen_l.3c target=mbrlen.3c
-link path=usr/share/man/man3c/mbrtowc_l.3c target=mbrtowc.3c
+link path=usr/share/man/man3c/mbrtoc32.3c target=mbrtoc16.3c
+link path=usr/share/man/man3c/mbrtowc.3c target=mbrtoc16.3c
+link path=usr/share/man/man3c/mbrtowc_l.3c target=mbrtoc16.3c
link path=usr/share/man/man3c/mbsinit_l.3c target=mbsinit.3c
link path=usr/share/man/man3c/mbsnrtowcs.3c target=mbsrtowcs.3c
link path=usr/share/man/man3c/mbsnrtowcs_l.3c target=mbsrtowcs.3c
@@ -1457,7 +1460,8 @@ link path=usr/share/man/man3c/watoi.3c target=wcstol.3c
link path=usr/share/man/man3c/watol.3c target=wcstol.3c
link path=usr/share/man/man3c/watoll.3c target=wcstol.3c
link path=usr/share/man/man3c/wcpncpy.3c target=wcpcpy.3c
-link path=usr/share/man/man3c/wcrtomb_l.3c target=wcrtomb.3c
+link path=usr/share/man/man3c/wcrtomb.3c target=c16rtomb.3c
+link path=usr/share/man/man3c/wcrtomb_l.3c target=c16rtomb.3c
link path=usr/share/man/man3c/wcscasecmp_l.3c target=wcscasecmp.3c
link path=usr/share/man/man3c/wcscat.3c target=wcstring.3c
link path=usr/share/man/man3c/wcschr.3c target=wcstring.3c
diff --git a/usr/src/pkg/manifests/system-test-libctest.mf b/usr/src/pkg/manifests/system-test-libctest.mf
index 67594901aa..91c272f9b9 100644
--- a/usr/src/pkg/manifests/system-test-libctest.mf
+++ b/usr/src/pkg/manifests/system-test-libctest.mf
@@ -183,6 +183,8 @@ file path=opt/libc-tests/tests/symbols/symbols_test.$(ARCH64) mode=0555
file path=opt/libc-tests/tests/thread_name mode=0555
file path=opt/libc-tests/tests/timespec_get.32 mode=0555
file path=opt/libc-tests/tests/timespec_get.64 mode=0555
+file path=opt/libc-tests/tests/uchar.32 mode=0555
+file path=opt/libc-tests/tests/uchar.64 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7344.32 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7344.64 mode=0555
file path=opt/libc-tests/tests/wcsncasecmp-7350.32 mode=0555
diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run
index 0af74f8780..e59f1b104e 100644
--- a/usr/src/test/libc-tests/runfiles/default.run
+++ b/usr/src/test/libc-tests/runfiles/default.run
@@ -112,6 +112,8 @@ timeout = 600
[/opt/libc-tests/tests/thread_name]
[/opt/libc-tests/tests/timespec_get.32]
[/opt/libc-tests/tests/timespec_get.64]
+[/opt/libc-tests/tests/uchar.32]
+[/opt/libc-tests/tests/uchar.64]
[/opt/libc-tests/tests/pthread_attr_get_np]
diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile
index 1b7b4723e4..c4db6695ce 100644
--- a/usr/src/test/libc-tests/tests/Makefile
+++ b/usr/src/test/libc-tests/tests/Makefile
@@ -50,7 +50,8 @@ PROGS = \
timespec_get \
wcsncasecmp \
wcsncasecmp-7344 \
- wcsncasecmp-7350
+ wcsncasecmp-7350 \
+ uchar
SCRIPTS = \
quick_exit \
diff --git a/usr/src/test/libc-tests/tests/uchar.c b/usr/src/test/libc-tests/tests/uchar.c
new file mode 100644
index 0000000000..895711fe5e
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/uchar.c
@@ -0,0 +1,789 @@
+/*
+ * 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 2020 Robert Mustacchi
+ */
+
+/*
+ * Test the implementation of various pieces of uchar.h(3HEAD) functionality.
+ */
+
+#include <locale.h>
+#include <err.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <wchar.h>
+#include <uchar.h>
+#include <errno.h>
+
+static const char *uchar_wide = "光";
+static const char32_t uchar_value = 0x5149;
+static const char *uchar_hello = "hello";
+
+static void
+update_locale(const char *loc)
+{
+ const char *newloc = setlocale(LC_CTYPE, loc);
+ if (newloc == NULL) {
+ err(EXIT_FAILURE, "TEST FAILED: failed to update locale to %s",
+ loc);
+ }
+
+ if (strcmp(newloc, loc) != 0) {
+ errx(EXIT_FAILURE, "TEST FAILED: locale set to %s, but got %s",
+ loc, newloc);
+ }
+}
+
+static boolean_t
+mbrtoc32_ascii(mbstate_t *mbs)
+{
+ char32_t out;
+ size_t len;
+ boolean_t ret = B_TRUE;
+
+ if ((len = mbrtoc32(&out, uchar_hello, 5, mbs)) != 1) {
+ warnx("expected mbrtoc32 to return 1, returned %zu", len);
+ ret = B_FALSE;
+ }
+
+ if (out != 'h') {
+ warnx("got bad char32_t, expected 0x%x, found 0x%x\n", 'h',
+ out);
+ ret = B_FALSE;
+ }
+
+ if ((len = mbrtoc32(&out, uchar_hello + 1, 4, mbs)) != 1) {
+ warnx("expected mbrtoc32 to return 1, returned %zu", len);
+ ret = B_FALSE;
+ }
+
+ if (out != 'e') {
+ warnx("got bad char32_t, expected 0x%x, found 0x%x\n", 'h',
+ out);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_ascii_internal(void)
+{
+ return (mbrtoc32_ascii(NULL));
+}
+
+static boolean_t
+mbrtoc32_ascii_mbstate(void)
+{
+ mbstate_t mbs;
+
+ bzero(&mbs, sizeof (mbs));
+ return (mbrtoc32_ascii(&mbs));
+}
+
+static boolean_t
+mbrtoc32_badseq_utf8(void)
+{
+ mbstate_t mbs;
+ size_t len;
+ char32_t out;
+ boolean_t ret = B_TRUE;
+ char *badstr;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, "\xa9", 1, &mbs);
+ if (len != (size_t)-1) {
+ warnx("mbrtoc32 returned %zu, not %zu", len, (size_t)-1);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("found bad errno, expected %d, found %d\n", errno,
+ EILSEQ);
+ ret = B_FALSE;
+ }
+
+ badstr = strdup(uchar_wide);
+ if (badstr == NULL) {
+ warn("failed to duplicate uchar_wide");
+ return (B_FALSE);
+ }
+
+ badstr[1] = '?';
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, badstr, strlen(badstr), &mbs);
+ free(badstr);
+ if (len != (size_t)-1) {
+ warnx("mbrtoc32 returned %zu, not %zu", len, (size_t)-1);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("found bad errno, expected %d, found %d\n", errno,
+ EILSEQ);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_roundtrip(void)
+{
+ char32_t out;
+ size_t len, clen;
+ mbstate_t mbs;
+ char buf[MB_CUR_MAX];
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, uchar_wide, strlen(uchar_wide), &mbs);
+ if (len != 3) {
+ warnx("mbrtoc32 returned %zu, expected %u", len, 3);
+ ret = B_FALSE;
+ }
+
+ if (out != uchar_value) {
+ warnx("mbrtoc32 converted character to 0x%x not 0x%x",
+ out, uchar_value);
+ ret = B_FALSE;
+ }
+
+ clen = c32rtomb(buf, out, &mbs);
+ if (clen != len) {
+ warnx("c32rtomb returned %d bytes, but we originally used %d",
+ clen, len);
+ ret = B_FALSE;
+ }
+
+ if (strncmp(buf, uchar_wide, len) != 0) {
+ warnx("round trip string comparison failed");
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_partial(void)
+{
+ char32_t out;
+ size_t len, i;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ for (i = 0; i < strlen(uchar_wide) - 1; i++) {
+ len = mbrtoc32(&out, uchar_wide + i, 1, &mbs);
+ if (len != (size_t)-2) {
+ warnx("partial mbrtoc32 returned %zu, not -2", len);
+ ret = B_FALSE;
+ }
+ }
+
+ len = mbrtoc32(&out, uchar_wide + i, 1, &mbs);
+ if (len != 1) {
+ warnx("partial mbrtoc32 returned %zu, not 1", len);
+ ret = B_FALSE;
+ }
+
+ if (out != uchar_value) {
+ warnx("mbrtoc32 converted character to 0x%x not 0x%x",
+ out, uchar_value);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_zero(void)
+{
+ char32_t out, exp = L'\0';
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, "", 1, &mbs);
+ if (len != 0) {
+ warnx("partial mbrtoc32 returned %zu, not 0", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc32 converted character to 0x%x not 0x%x",
+ out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_zero_len(void)
+{
+ char32_t out = 0x12345, exp = 0x12345;
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, uchar_wide, 0, &mbs);
+ if (len != (size_t)-2) {
+ warnx("partial mbrtoc32 returned %zu, not -2", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc32 incorrectly wrote to char32_t value with "
+ "zero string, found 0x%x not 0x%x", out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc32_null(void)
+{
+ char32_t out = 0x123456, exp = 0x123456;
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc32(&out, NULL, 1, &mbs);
+ if (len != 0) {
+ warnx("partial mbrtoc32 returned %zu, not 0", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc32 incorrectly wrote to char32_t value with "
+ "null string, found 0x%x not 0x%x", out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_ascii(mbstate_t *mbs)
+{
+ char16_t out;
+ size_t len;
+ boolean_t ret = B_TRUE;
+
+ if ((len = mbrtoc16(&out, uchar_hello, 5, mbs)) != 1) {
+ warnx("expected mbrtoc16 to return 1, returned %zu", len);
+ ret = B_FALSE;
+ }
+
+ if (out != 'h') {
+ warnx("got bad char16_t, expected 0x%x, found 0x%x\n", 'h',
+ out);
+ ret = B_FALSE;
+ }
+
+ if ((len = mbrtoc16(&out, uchar_hello + 1, 4, mbs)) != 1) {
+ warnx("expected mbrtoc16 to return 1, returned %zu", len);
+ ret = B_FALSE;
+ }
+
+ if (out != 'e') {
+ warnx("got bad char16_t, expected 0x%x, found 0x%x\n", 'h',
+ out);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_ascii_internal(void)
+{
+ return (mbrtoc16_ascii(NULL));
+}
+
+static boolean_t
+mbrtoc16_ascii_mbstate(void)
+{
+ mbstate_t mbs;
+
+ bzero(&mbs, sizeof (mbs));
+ return (mbrtoc16_ascii(&mbs));
+}
+
+static boolean_t
+mbrtoc16_null(void)
+{
+ char16_t out = 0x1234, exp = 0x1234;
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc16(&out, NULL, 1, &mbs);
+ if (len != 0) {
+ warnx("partial mbrtoc16 returned %zu, not 0", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc16 incorrectly wrote to char16_t value with "
+ "null string, found 0x%x not 0x%x", out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_zero(void)
+{
+ char16_t out, exp = L'\0';
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc16(&out, "", 1, &mbs);
+ if (len != 0) {
+ warnx("partial mbrtoc16 returned %zu, not 0", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc16 converted character to 0x%x not 0x%x",
+ out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_zero_len(void)
+{
+ char16_t out = 0x5432, exp = 0x5432;
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc16(&out, uchar_wide, 0, &mbs);
+ if (len != (size_t)-2) {
+ warnx("partial mbrtoc16 returned %zu, not -2", len);
+ ret = B_FALSE;
+ }
+
+ if (out != exp) {
+ warnx("mbrtoc16 incorrectly wrote to char16_t value with "
+ "zero length string, found 0x%x not 0x%x", out, exp);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_roundtrip(void)
+{
+ char16_t out;
+ size_t len, clen;
+ mbstate_t mbs;
+ char buf[MB_CUR_MAX];
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc16(&out, uchar_wide, strlen(uchar_wide), &mbs);
+ if (len != 3) {
+ warnx("mbrtoc16 returned %zu, expected %u", len, 3);
+ ret = B_FALSE;
+ }
+
+ if (out != uchar_value) {
+ warnx("mbrtoc16 converted character to 0x%x not 0x%x",
+ out, uchar_value);
+ ret = B_FALSE;
+ }
+
+ clen = c16rtomb(buf, out, &mbs);
+ if (clen != len) {
+ warnx("c16rtomb returned %d bytes, but we originally used %d",
+ clen, len);
+ ret = B_FALSE;
+ }
+
+ if (strncmp(buf, uchar_wide, len) != 0) {
+ warnx("round trip string comparison failed");
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_partial(void)
+{
+ char16_t out;
+ size_t len, i;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ for (i = 0; i < strlen(uchar_wide) - 1; i++) {
+ len = mbrtoc16(&out, uchar_wide + i, 1, &mbs);
+ if (len != (size_t)-2) {
+ warnx("partial mbrtoc16 returned %zu, not -2", len);
+ ret = B_FALSE;
+ }
+ }
+
+ len = mbrtoc16(&out, uchar_wide + i, 1, &mbs);
+ if (len != 1) {
+ warnx("partial mbrtoc16 returned %zu, not 1", len);
+ ret = B_FALSE;
+ }
+
+ if (out != uchar_value) {
+ warnx("mbrtoc16 converted character to 0x%x not 0x%x",
+ out, uchar_value);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+mbrtoc16_surrogate(void)
+{
+ char16_t out0, out1;
+ size_t len, clen;
+ mbstate_t mbs;
+ const char *surrogate = "\xF0\x9F\x92\xA9";
+ char16_t exp0 = 0xd83d, exp1 = 0xdca9;
+ size_t slen = strlen(surrogate);
+ boolean_t ret = B_TRUE;
+ char buf[MB_CUR_MAX];
+
+ bzero(&mbs, sizeof (mbs));
+ len = mbrtoc16(&out0, surrogate, slen, &mbs);
+ if (len != slen) {
+ warnx("mbrtoc16 returned %zu, expected %u", len, slen);
+ ret = B_FALSE;
+ }
+
+ if (out0 != exp0) {
+ warnx("mbrtoc16 converted character to 0x%x not 0x%x",
+ out0, exp0);
+ ret = B_FALSE;
+ }
+
+ if (mbsinit(&mbs) != 0) {
+ warnx("mb state with a surrogate character is somehow in the "
+ "initial state");
+ ret = B_FALSE;
+ }
+
+ len = mbrtoc16(&out1, uchar_wide, strlen(uchar_wide), &mbs);
+ if (len != (size_t)-3) {
+ warnx("mbrtoc16 returned %zu, expected -3", len);
+ ret = B_FALSE;
+ }
+
+ if (mbsinit(&mbs) == 0) {
+ warnx("mb state with after both surrogate characters isn't "
+ "in initial state");
+ ret = B_FALSE;
+ }
+
+ if (out1 != exp1) {
+ warnx("mbrtoc32 converted character to 0x%x not 0x%x",
+ out1, exp1);
+ ret = B_FALSE;
+ }
+
+ clen = c16rtomb(buf, out0, &mbs);
+ if (clen != 0) {
+ warnx("c16rtomb returned %d bytes, but expected zero for the "
+ "first surrogate", clen);
+ ret = B_FALSE;
+ }
+
+ if (mbsinit(&mbs) != 0) {
+ warnx("mb state with a surrogate character is somehow in the "
+ "initial state");
+ ret = B_FALSE;
+ }
+
+ clen = c16rtomb(buf, out1, &mbs);
+ if (clen != slen) {
+ warnx("c16rtomb returned %zd, expected %u", len, slen);
+ ret = B_FALSE;
+ }
+
+ if (mbsinit(&mbs) == 0) {
+ warnx("mb state with after both surrogate characters isn't "
+ "in initial state");
+ ret = B_FALSE;
+ }
+
+ if (strncmp(buf, surrogate, slen) != 0) {
+ warnx("round trip string comparison failed");
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c32rtomb_eilseq_iso8859(void)
+{
+ char buf[MB_CUR_MAX];
+ mbstate_t mbs;
+ size_t len;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = c32rtomb(buf, uchar_value, &mbs);
+ if (len != (size_t)-1) {
+ warnx("c32rtomb returned %zd, expected -1\n", len);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("expected errno set to %d was %d", EILSEQ, errno);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c16rtomb_eilseq_iso8859(void)
+{
+ char buf[MB_CUR_MAX];
+ mbstate_t mbs;
+ size_t len;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = c32rtomb(buf, (char16_t)uchar_value, &mbs);
+ if (len != (size_t)-1) {
+ warnx("c32rtomb returned %zd, expected -1\n", len);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("expected errno set to %d was %d", EILSEQ, errno);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c32rtomb_eilseq_utf8(void)
+{
+ char buf[MB_CUR_MAX];
+ mbstate_t mbs;
+ size_t len;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = c32rtomb(buf, UINT32_MAX, &mbs);
+ if (len != (size_t)-1) {
+ warnx("c32rtomb returned %zd, expected -1\n", len);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("expected errno set to %d was %d", EILSEQ, errno);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c16rtomb_bad_first(void)
+{
+ char buf[MB_CUR_MAX];
+ mbstate_t mbs;
+ size_t len, i;
+ char16_t first = 0xd83d;
+ char16_t bad[] = { 0x0, 0xd7ff, 0xd83d, 0xd900, 0xffff };
+ boolean_t ret = B_TRUE;
+
+ for (i = 0; i < ARRAY_SIZE(bad); i++) {
+ bzero(&mbs, sizeof (mbs));
+ len = c16rtomb(buf, first, &mbs);
+ if (len != 0) {
+ warnx("c16rtomb returned %zd, expected 0\n", len);
+ ret = B_FALSE;
+ }
+
+ len = c16rtomb(buf, bad[i], &mbs);
+ if (len != (size_t)-1) {
+ warnx("c16rtomb surrogate %x returned %zd, expected "
+ "-1\n", bad[i], len);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("expected errno set to %d was %d", EILSEQ, errno);
+ ret = B_FALSE;
+ }
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c16rtomb_bad_second(void)
+{
+ char buf[MB_CUR_MAX];
+ mbstate_t mbs;
+ size_t len, i;
+ char16_t bad[] = { 0xdc00, 0xdd34, 0xdfff };
+ boolean_t ret = B_TRUE;
+
+ for (i = 0; i < ARRAY_SIZE(bad); i++) {
+ bzero(&mbs, sizeof (mbs));
+ len = c16rtomb(buf, bad[i], &mbs);
+ if (len != (size_t)-1) {
+ warnx("c16rtomb surrogate %x returned %zd, expected "
+ "-1\n", bad[i], len);
+ ret = B_FALSE;
+ }
+
+ if (errno != EILSEQ) {
+ warnx("expected errno set to %d was %d", EILSEQ, errno);
+ ret = B_FALSE;
+ }
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c32rtomb_null(void)
+{
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = c32rtomb(NULL, uchar_value, &mbs);
+ if (len != 1) {
+ warnx("c32rtomb returned %zd, expected %zd", len, 1);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+static boolean_t
+c16rtomb_null(void)
+{
+ size_t len;
+ mbstate_t mbs;
+ boolean_t ret = B_TRUE;
+
+ bzero(&mbs, sizeof (mbs));
+ len = c16rtomb(NULL, uchar_value, &mbs);
+ if (len != 1) {
+ warnx("c16rtomb returned %zd, expected %zd", len, 1);
+ ret = B_FALSE;
+ }
+
+ return (ret);
+}
+
+typedef boolean_t (*uchar_test_f)(void);
+
+typedef struct uchar_test {
+ uchar_test_f ut_func;
+ const char *ut_test;
+ const char *ut_locale;
+} uchar_test_t;
+
+static const uchar_test_t uchar_tests[] = {
+ { mbrtoc32_ascii_mbstate, "mbrtoc32: ascii conversion" },
+ { mbrtoc32_ascii_internal, "mbrtoc32: ascii conversion (internal "
+ "mbstate_t)" },
+ { mbrtoc32_badseq_utf8, "mbrtoc32: bad locale sequence (UTF-8)" },
+ { mbrtoc32_roundtrip, "mbrtoc32: round trip conversion" },
+ { mbrtoc32_partial, "mbrtoc32: correctly consume partial sequences" },
+ { mbrtoc32_zero, "mbrtoc32: correctly handle L'\\0'" },
+ { mbrtoc32_zero_len, "mbrtoc32: correctly handle length of zero" },
+ { mbrtoc32_null, "mbrtoc32: correctly handle null string" },
+ { mbrtoc16_ascii_mbstate, "mbrtoc16: ascii conversion" },
+ { mbrtoc16_ascii_internal, "mbrtoc16: ascii conversion (internal "
+ "mbstate_t)" },
+ { mbrtoc16_null, "mbrtoc16: correctly handle null string" },
+ { mbrtoc16_zero, "mbrtoc16: correctly handle L'\\0'" },
+ { mbrtoc16_zero_len, "mbrtoc16: correctly handle length of zero" },
+ { mbrtoc16_roundtrip, "mbrtoc16: round trip conversion" },
+ { mbrtoc16_partial, "mbrtoc16: correctly consume partial sequences" },
+ { mbrtoc16_surrogate, "mbrtoc16: correctly generate surrogate pairs "
+ "and round trip conversion" },
+ { c32rtomb_eilseq_iso8859, "c32rtomb: character outside of locale is "
+ "caught", "en_US.ISO8859-1" },
+ { c16rtomb_eilseq_iso8859, "c16rtomb: character outside of locale is "
+ "caught", "en_US.ISO8859-1" },
+ { c32rtomb_eilseq_utf8, "c32rtomb: character outside of locale is "
+ "caught" },
+ { c16rtomb_bad_first, "c16rtomb: bad first surrogate pair" },
+ { c16rtomb_bad_second, "c16rtomb: bad second surrogate pair" },
+ { c32rtomb_null, "c32rtomb: correctly handle null buffer" },
+ { c16rtomb_null, "c16rtomb: correctly handle null buffer" },
+};
+
+int
+main(void)
+{
+ uint_t i;
+ uint_t passes = 0;
+ uint_t ntests = ARRAY_SIZE(uchar_tests);
+
+ for (i = 0; i < ntests; i++) {
+ boolean_t r;
+
+ /*
+ * Default to a standard UTF-8 locale if none is requested by
+ * the test.
+ */
+ if (uchar_tests[i].ut_locale != NULL) {
+ update_locale(uchar_tests[i].ut_locale);
+ } else {
+ update_locale("en_US.UTF-8");
+ }
+
+ r = uchar_tests[i].ut_func();
+ (void) fprintf(stderr, "TEST %s: %s\n", r ? "PASSED" : "FAILED",
+ uchar_tests[i].ut_test);
+ if (r) {
+ passes++;
+ }
+ }
+
+ (void) printf("%d/%d test%s passed\n", passes, ntests,
+ passes > 1 ? "s" : "");
+ return (passes == ntests ? EXIT_SUCCESS : EXIT_FAILURE);
+
+}
diff --git a/usr/src/uts/common/sys/int_types.h b/usr/src/uts/common/sys/int_types.h
index e57d6f8b75..8f7c423643 100644
--- a/usr/src/uts/common/sys/int_types.h
+++ b/usr/src/uts/common/sys/int_types.h
@@ -173,6 +173,9 @@ typedef long long int_least64_t;
#endif
#endif
+/*
+ * If these are changed, please update char16_t and char32_t in head/uchar.h.
+ */
typedef unsigned char uint_least8_t;
typedef unsigned short uint_least16_t;
typedef unsigned int uint_least32_t;