tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: [PATCH] Support for mbsnrtowcs and wcsnrtomb



On Fri, Apr 26, 2013 at 12:12:44PM +0200, Antoine LECA wrote:
> > I'm not sure about that reading of the standard. 
> 
> You surely can! Seem others have other ideas than I, and they seem to
> have already move :-)

Attached is an updated patch.

Joerg
Index: distrib/sets/lists/debug/mi
===================================================================
RCS file: /home/joerg/repo/netbsd/src/distrib/sets/lists/debug/mi,v
retrieving revision 1.20
diff -u -p -r1.20 mi
--- distrib/sets/lists/debug/mi 22 Apr 2013 21:06:26 -0000      1.20
+++ distrib/sets/lists/debug/mi 26 Apr 2013 23:10:43 -0000
@@ -1543,6 +1543,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_io.debug               
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_mbrtowc.debug          
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_mbstowcs.debug         
tests-lib-debug         debug,atf
+./usr/libdata/debug/usr/tests/lib/libc/locale/t_mbsnrtowcs.debug       
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_mbtowc.debug           
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_wcscspn.debug          
tests-lib-debug         debug,atf
 ./usr/libdata/debug/usr/tests/lib/libc/locale/t_wcspbrk.debug          
tests-lib-debug         debug,atf
Index: distrib/sets/lists/tests/mi
===================================================================
RCS file: /home/joerg/repo/netbsd/src/distrib/sets/lists/tests/mi,v
retrieving revision 1.535
diff -u -p -r1.535 mi
--- distrib/sets/lists/tests/mi 22 Apr 2013 21:06:28 -0000      1.535
+++ distrib/sets/lists/tests/mi 26 Apr 2013 23:10:53 -0000
@@ -1942,6 +1942,7 @@
 ./usr/tests/lib/libc/locale/t_io               tests-lib-tests         atf
 ./usr/tests/lib/libc/locale/t_mbrtowc          tests-lib-tests         atf
 ./usr/tests/lib/libc/locale/t_mbstowcs         tests-lib-tests         atf
+./usr/tests/lib/libc/locale/t_mbsnrtowcs       tests-lib-tests         atf
 ./usr/tests/lib/libc/locale/t_mbtowc           tests-lib-tests         atf
 ./usr/tests/lib/libc/locale/t_wcscspn          tests-lib-tests         atf
 ./usr/tests/lib/libc/locale/t_wcspbrk          tests-lib-tests         atf
Index: include/wchar.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/include/wchar.h,v
retrieving revision 1.37
diff -u -p -r1.37 wchar.h
--- include/wchar.h     19 Apr 2013 23:45:15 -0000      1.37
+++ include/wchar.h     25 Apr 2013 14:00:44 -0000
@@ -212,6 +212,11 @@ typedef struct _locale             *locale_t;
 #  define __LOCALE_T_DECLARED
 #  endif
 __BEGIN_DECLS
+size_t mbsnrtowcs(wchar_t * __restrict, const char ** __restrict, size_t,
+           size_t, mbstate_t * __restrict);
+size_t wcsnrtombs(char * __restrict, const wchar_t ** __restrict, size_t,
+           size_t, mbstate_t * __restrict);
+
 int    wcscoll_l(const wchar_t *, const wchar_t *, locale_t);
 size_t wcsxfrm_l(wchar_t *, const wchar_t *, size_t, locale_t);
 int wcsncasecmp_l(const wchar_t *, const wchar_t *, size_t, locale_t);
@@ -246,9 +251,13 @@ size_t     mbrtowc_l(wchar_t * __restrict, c
 int    mbsinit_l(const mbstate_t *, locale_t);
 size_t mbsrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t,
            mbstate_t * __restrict, locale_t);
+size_t mbsnrtowcs_l(wchar_t * __restrict, const char ** __restrict, size_t,
+           size_t, mbstate_t * __restrict, locale_t);
 size_t wcrtomb_l(char * __restrict, wchar_t, mbstate_t * __restrict, locale_t);
 size_t wcsrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t,
            mbstate_t * __restrict, locale_t);
+size_t wcsnrtombs_l(char * __restrict, const wchar_t ** __restrict, size_t,
+           size_t, mbstate_t * __restrict, locale_t);
 int    wctob_l(wint_t, locale_t);
 
 int fwprintf_l(FILE * __restrict, locale_t, const wchar_t * __restrict, ...);
Index: lib/libc/citrus/citrus_ctype.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype.c,v
retrieving revision 1.6
diff -u -p -r1.6 citrus_ctype.c
--- lib/libc/citrus/citrus_ctype.c      19 Nov 2011 18:34:21 -0000      1.6
+++ lib/libc/citrus/citrus_ctype.c      26 Apr 2013 21:01:29 -0000
@@ -93,6 +93,8 @@ _initctypemodule(_citrus_ctype_t cc, cha
                /* FALLTHROUGH */
        case 0x00000002:
                /* FALLTHROUGH */
+               cc->cc_ops->co_mbsnrtowcs = &_citrus_ctype_mbsnrtowcs_fallback;
+               cc->cc_ops->co_wcsnrtombs = &_citrus_ctype_wcsnrtombs_fallback;
        default:
                break;
        }
@@ -106,10 +108,12 @@ _initctypemodule(_citrus_ctype_t cc, cha
            cc->cc_ops->co_mbrtowc == NULL ||
            cc->cc_ops->co_mbsinit == NULL ||
            cc->cc_ops->co_mbsrtowcs == NULL ||
+           cc->cc_ops->co_mbsnrtowcs == NULL ||
            cc->cc_ops->co_mbstowcs == NULL ||
            cc->cc_ops->co_mbtowc == NULL ||
            cc->cc_ops->co_wcrtomb == NULL ||
            cc->cc_ops->co_wcsrtombs == NULL ||
+           cc->cc_ops->co_wcsnrtombs == NULL ||
            cc->cc_ops->co_wcstombs == NULL ||
            cc->cc_ops->co_wctomb == NULL ||
            cc->cc_ops->co_btowc == NULL ||
Index: lib/libc/citrus/citrus_ctype.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype.h,v
retrieving revision 1.2
diff -u -p -r1.2 citrus_ctype.h
--- lib/libc/citrus/citrus_ctype.h      5 Mar 2003 20:18:15 -0000       1.2
+++ lib/libc/citrus/citrus_ctype.h      25 Apr 2013 16:36:53 -0000
@@ -95,6 +95,16 @@ _citrus_ctype_mbsrtowcs(_citrus_ctype_t 
 }
 
 static __inline int
+_citrus_ctype_mbsnrtowcs(_citrus_ctype_t cc, wchar_t *pwcs, const char **s,
+                       size_t in, size_t n, void *pspriv, size_t *nresult)
+{
+
+       _DIAGASSERT(cc && cc->cc_ops && cc->cc_ops->co_mbsnrtowcs && nresult);
+       return (*cc->cc_ops->co_mbsnrtowcs)(cc, pwcs, s, in, n,
+                                          pspriv, nresult);
+}
+
+static __inline int
 _citrus_ctype_mbstowcs(_citrus_ctype_t cc, wchar_t *pwcs, const char *s,
                       size_t n, size_t *nresult)
 {
@@ -133,6 +143,16 @@ _citrus_ctype_wcsrtombs(_citrus_ctype_t 
 }
 
 static __inline int
+_citrus_ctype_wcsnrtombs(_citrus_ctype_t cc, char *s, const wchar_t **ppwcs,
+                       size_t in, size_t n, void *pspriv, size_t *nresult)
+{
+
+       _DIAGASSERT(cc && cc->cc_ops && cc->cc_ops->co_wcsnrtombs && nresult);
+       return (*cc->cc_ops->co_wcsnrtombs)(cc, s, ppwcs, in, n,
+                                          pspriv, nresult);
+}
+
+static __inline int
 _citrus_ctype_wcstombs(_citrus_ctype_t cc, char *s, const wchar_t *wcs,
                       size_t n, size_t *nresult)
 {
Index: lib/libc/citrus/citrus_ctype_fallback.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype_fallback.c,v
retrieving revision 1.2
diff -u -p -r1.2 citrus_ctype_fallback.c
--- lib/libc/citrus/citrus_ctype_fallback.c     27 Jun 2003 14:52:25 -0000      
1.2
+++ lib/libc/citrus/citrus_ctype_fallback.c     26 Apr 2013 21:23:23 -0000
@@ -35,6 +35,7 @@ __RCSID("$NetBSD: citrus_ctype_fallback.
 
 #include <sys/types.h>
 #include <assert.h>
+#include <errno.h>
 #include <wchar.h>
 #include <stdio.h>
 #include <string.h>
@@ -108,3 +109,127 @@ _citrus_ctype_wctob_fallback(_citrus_cty
 
        return 0;
 }
+
+/*
+ * for ABI version >= 0x00000003
+ */ 
+
+#include <stddef.h>
+#include "runetype_local.h"
+#include "multibyte.h"
+int
+_citrus_ctype_mbsnrtowcs_fallback(_citrus_ctype_rec_t * __restrict cc,
+    wchar_t * __restrict pwcs, const char ** __restrict s, size_t in,
+    size_t n, void * __restrict psenc, size_t * __restrict nresult)
+{
+       int err;
+       size_t cnt, siz;
+       const char *s0, *se;
+       char state[_PRIVSIZE];
+
+       _DIAGASSERT(nresult != 0);
+       _DIAGASSERT(psenc != NULL);
+       _DIAGASSERT(s != NULL);
+       _DIAGASSERT(*s != NULL);
+
+       /* if pwcs is NULL, ignore n */
+       if (pwcs == NULL)
+               n = 1; /* arbitrary >0 value */
+
+       err = 0;
+       cnt = 0;
+       se = *s + in;
+       s0 = *s; /* to keep *s unchanged for now, use copy instead. */
+       while (s0 < se && n > 0) {
+               memcpy(state, psenc, sizeof(state));
+               err = _citrus_ctype_mbrtowc(cc, pwcs, s0, (size_t)(se - s0),
+                   psenc, &siz);
+               if (err) {
+                       cnt = (size_t)-1;
+                       goto bye;
+               }
+               if (siz == (size_t)-2) {
+                       memcpy(psenc, state, sizeof(state));
+                       s0 = *s + cnt;
+                       goto bye;
+               }
+               switch (siz) {
+               case 0:
+                       if (pwcs) {
+                               size_t dum;
+                               _citrus_ctype_mbrtowc(cc, NULL, NULL, 0, psenc,
+                                   &dum);
+                       }
+                       s0 = 0;
+                       goto bye;
+               default:
+                       if (pwcs) {
+                               pwcs++;
+                               n--;
+                       }
+                       s0 += siz;
+                       cnt++;
+                       break;
+               }
+       }
+bye:
+       if (pwcs)
+               *s = s0;
+
+       *nresult = cnt;
+
+       return err;
+}
+
+int
+_citrus_ctype_wcsnrtombs_fallback(_citrus_ctype_rec_t * __restrict cc,
+    char * __restrict s, const wchar_t ** __restrict pwcs, size_t in,
+    size_t n, void * __restrict psenc, size_t * __restrict nresult)
+{
+       size_t cnt = 0;
+       int err;
+       char buf[MB_LEN_MAX];
+       size_t siz;
+       const wchar_t* pwcs0;
+       mbstate_t state;
+
+       pwcs0 = *pwcs;
+
+       if (!s)
+               n = 1;
+
+       while (in > 0 && n > 0) {
+               memcpy(&state, psenc, sizeof(state));
+               err = _citrus_ctype_wcrtomb(cc, buf, *pwcs0, psenc, &siz);
+               if (siz == (size_t)-1) {
+                       *nresult = siz;
+                       return (err);
+               }
+
+               if (s) {
+                       if (n < siz) {
+                               memcpy(psenc, &state, sizeof(state));
+                               break;
+                       }
+                       memcpy(s, buf, siz);
+                       s += siz;
+                       n -= siz;
+               }
+               cnt += siz;
+               if (!*pwcs0) {
+                       if (s) {
+                               memset(psenc, 0, sizeof(state));
+                       }
+                       pwcs0 = 0;
+                       cnt--; /* don't include terminating null */
+                       break;
+               }
+               pwcs0++;
+               --in;
+       }
+       if (s)
+               *pwcs = pwcs0;
+
+       *nresult = cnt;
+       return (0);
+}
Index: lib/libc/citrus/citrus_ctype_fallback.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype_fallback.h,v
retrieving revision 1.1
diff -u -p -r1.1 citrus_ctype_fallback.h
--- lib/libc/citrus/citrus_ctype_fallback.h     5 Mar 2003 20:18:15 -0000       
1.1
+++ lib/libc/citrus/citrus_ctype_fallback.h     25 Apr 2013 16:40:36 -0000
@@ -35,4 +35,16 @@ int _citrus_ctype_btowc_fallback(_citrus
 int _citrus_ctype_wctob_fallback(_citrus_ctype_rec_t * __restrict,
                                 wint_t, int * __restrict);
 
+/* fallback functions for 0x00000003 */
+int _citrus_ctype_mbsnrtowcs_fallback(_citrus_ctype_rec_t * __restrict,
+                                     wchar_t * __restrict,
+                                     const char ** __restrict, size_t,
+                                     size_t, void * __restrict,
+                                     size_t * __restrict);
+int _citrus_ctype_wcsnrtombs_fallback(_citrus_ctype_rec_t * __restrict,
+                                    char * __restrict,
+                                    const wchar_t ** __restrict, size_t,
+                                    size_t, void * __restrict,
+                                    size_t * __restrict);
+
 #endif
Index: lib/libc/citrus/citrus_ctype_local.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype_local.h,v
retrieving revision 1.3
diff -u -p -r1.3 citrus_ctype_local.h
--- lib/libc/citrus/citrus_ctype_local.h        9 Feb 2008 14:56:20 -0000       
1.3
+++ lib/libc/citrus/citrus_ctype_local.h        26 Apr 2013 21:15:19 -0000
@@ -60,6 +60,11 @@ static int   _citrus_##_e_##_ctype_mbsrtow
                                         const char ** __restrict,            \
                                         size_t, void * __restrict,           \
                                         size_t * __restrict);                \
+static int     _citrus_##_e_##_ctype_mbsnrtowcs(_citrus_ctype_rec_t * 
__restrict, \
+                                        wchar_t * __restrict,                \
+                                        const char ** __restrict,            \
+                                        size_t, size_t, void * __restrict,   \
+                                        size_t * __restrict);                \
 static int     _citrus_##_e_##_ctype_mbstowcs(void * __restrict,             \
                                        wchar_t * __restrict,                 \
                                        const char * __restrict,              \
@@ -77,6 +82,11 @@ static int   _citrus_##_e_##_ctype_wcsrtom
                                         const wchar_t ** __restrict,         \
                                         size_t, void * __restrict,           \
                                         size_t * __restrict);                \
+static int     _citrus_##_e_##_ctype_wcsnrtombs(_citrus_ctype_rec_t * 
__restrict, \
+                                        char * __restrict,                   \
+                                        const wchar_t ** __restrict,         \
+                                        size_t, size_t, void * __restrict,   \
+                                        size_t * __restrict);                \
 static int     _citrus_##_e_##_ctype_wcstombs(void * __restrict,             \
                                        char * __restrict,                    \
                                        const wchar_t * __restrict,           \
@@ -107,7 +117,9 @@ _citrus_ctype_ops_rec_t _citrus_##_e_##_
        /* co_wcstombs */       &_citrus_##_e_##_ctype_wcstombs,        \
        /* co_wctomb */         &_citrus_##_e_##_ctype_wctomb,          \
        /* co_btowc */          &_citrus_##_e_##_ctype_btowc,           \
-       /* co_wctob */          &_citrus_##_e_##_ctype_wctob            \
+       /* co_wctob */          &_citrus_##_e_##_ctype_wctob,           \
+       /* co_mbsnrtowcs */     &_citrus_##_e_##_ctype_mbsnrtowcs,      \
+       /* co_wcsnrtombs */     &_citrus_##_e_##_ctype_wcsnrtombs,      \
 }
 
 typedef struct _citrus_ctype_ops_rec   _citrus_ctype_ops_rec_t;
@@ -129,7 +141,10 @@ typedef int        (*_citrus_ctype_mbsinit_t)
        (void * __restrict, const void * __restrict, int * __restrict);
 typedef int    (*_citrus_ctype_mbsrtowcs_t)
        (void * __restrict, wchar_t * __restrict, const char ** __restrict,
-        size_t, void * __restrict,
+        size_t, void * __restrict, size_t * __restrict);
+typedef int    (*_citrus_ctype_mbsnrtowcs_t)
+       (_citrus_ctype_rec_t * __restrict, wchar_t * __restrict,
+        const char ** __restrict, size_t, size_t, void * __restrict,
         size_t * __restrict);
 typedef int    (*_citrus_ctype_mbstowcs_t)
        (void * __restrict, wchar_t * __restrict, const char * __restrict,
@@ -143,6 +158,10 @@ typedef int        (*_citrus_ctype_wcrtomb_t)
 typedef int    (*_citrus_ctype_wcsrtombs_t)
        (void * __restrict, char * __restrict, const wchar_t ** __restrict,
         size_t, void * __restrict, size_t * __restrict);
+typedef int    (*_citrus_ctype_wcsnrtombs_t)
+       (_citrus_ctype_rec_t * __restrict, char * __restrict,
+        const wchar_t ** __restrict, size_t, size_t, void * __restrict,
+        size_t * __restrict);
 typedef int    (*_citrus_ctype_wcstombs_t)
        (void * __restrict, char * __restrict, const wchar_t * __restrict,
         size_t, size_t * __restrict);
@@ -152,16 +171,20 @@ typedef int       (*_citrus_ctype_btowc_t)
        (_citrus_ctype_rec_t * __restrict, int, wint_t * __restrict);
 typedef int    (*_citrus_ctype_wctob_t)
        (_citrus_ctype_rec_t * __restrict, wint_t, int * __restrict);
+#include "citrus_ctype_fallback.h"
 
 /*
  * ABI Version change log:
  *   0x00000001
  *     initial version
  *   0x00000002
- *     ops record:     btowc and wctob are added.
+ *     ops record:     btowc and wctob added.
+ *     ctype record:   unchanged.
+ *   0x00000003
+ *     ops record:     mbsnrtowcs and wcsnrtombs added.
  *     ctype record:   unchanged.
  */
-#define _CITRUS_CTYPE_ABI_VERSION      0x00000002
+#define _CITRUS_CTYPE_ABI_VERSION      0x00000003
 struct _citrus_ctype_ops_rec {
        uint32_t                        co_abi_version;
        /* version 0x00000001 */
@@ -182,6 +205,9 @@ struct _citrus_ctype_ops_rec {
        /* version 0x00000002 */
        _citrus_ctype_btowc_t           co_btowc;
        _citrus_ctype_wctob_t           co_wctob;
+       /* version 0x00000003 */
+       _citrus_ctype_mbsnrtowcs_t      co_mbsnrtowcs;
+       _citrus_ctype_wcsnrtombs_t      co_wcsnrtombs;
 };
 
 #define _CITRUS_DEFAULT_CTYPE_NAME     "NONE"
Index: lib/libc/citrus/citrus_ctype_template.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_ctype_template.h,v
retrieving revision 1.35
diff -u -p -r1.35 citrus_ctype_template.h
--- lib/libc/citrus/citrus_ctype_template.h     9 Feb 2008 14:56:20 -0000       
1.35
+++ lib/libc/citrus/citrus_ctype_template.h     26 Apr 2013 20:47:54 -0000
@@ -85,8 +85,10 @@
  *           mbrtowc
  *           mbtowc
  *           mbsrtowcs
+ *           mbsnrtowcs
  *           wcrtomb
  *           wcsrtombs
+ *           wcsnrtombs
  *           wctomb
  *     These need to be keeped in the ctype encoding information structure,
  *     pointed by "cei".
@@ -238,8 +240,8 @@ _FUNCNAME(mbsrtowcs_priv)(_ENCODING_INFO
        _DIAGASSERT(nresult != 0);
        _DIAGASSERT(ei != NULL);
        _DIAGASSERT(psenc != NULL);
-       _DIAGASSERT(s == NULL);
-       _DIAGASSERT(*s == NULL);
+       _DIAGASSERT(s != NULL);
+       _DIAGASSERT(*s != NULL);
 
        /* if pwcs is NULL, ignore n */
        if (pwcs == NULL)
@@ -282,6 +284,70 @@ bye:
        return err;
 }
 
+static int
+_FUNCNAME(mbsnrtowcs_priv)(_ENCODING_INFO * __restrict ei,
+                         wchar_t * __restrict pwcs,
+                         const char ** __restrict s, size_t in,
+                         size_t n, _ENCODING_STATE * __restrict psenc,
+                         size_t * __restrict nresult)
+{
+       int err;
+       size_t cnt, siz;
+       const char *s0, *se;
+       _ENCODING_STATE state;
+
+       _DIAGASSERT(nresult != 0);
+       _DIAGASSERT(ei != NULL);
+       _DIAGASSERT(psenc != NULL);
+       _DIAGASSERT(s != NULL);
+       _DIAGASSERT(*s != NULL);
+
+       /* if pwcs is NULL, ignore n */
+       if (pwcs == NULL)
+               n = 1; /* arbitrary >0 value */
+
+       err = 0;
+       cnt = 0;
+       se = *s + in;
+       s0 = *s; /* to keep *s unchanged for now, use copy instead. */
+       while (s0 < se && n > 0) {
+               state = *psenc;
+               err = _FUNCNAME(mbrtowc_priv)(ei, pwcs, &s0, se - s0,
+                                             psenc, &siz);
+               if (err) {
+                       cnt = (size_t)-1;
+                       goto bye;
+               }
+               if (siz == (size_t)-2) {
+                       *psenc = state;
+                       s0 = *s + cnt;
+                       goto bye;
+               }
+               switch (siz) {
+               case 0:
+                       if (pwcs) {
+                               _FUNCNAME(init_state)(ei, psenc);
+                       }
+                       s0 = 0;
+                       goto bye;
+               default:
+                       if (pwcs) {
+                               pwcs++;
+                               n--;
+                       }
+                       s0 = *s + cnt;
+                       cnt++;
+                       break;
+               }
+       }
+bye:
+       if (pwcs)
+               *s = s0;
+
+       *nresult = cnt;
+
+       return err;
+}
 
 static int
 _FUNCNAME(wcsrtombs_priv)(_ENCODING_INFO * __restrict ei, char * __restrict s,
@@ -289,6 +355,66 @@ _FUNCNAME(wcsrtombs_priv)(_ENCODING_INFO
                          size_t n, _ENCODING_STATE * __restrict psenc,
                          size_t * __restrict nresult)
 {
+       int err;
+       char buf[MB_LEN_MAX];
+       size_t cnt, siz;
+       const wchar_t* pwcs0;
+#if _ENCODING_IS_STATE_DEPENDENT
+       _ENCODING_STATE state;
+#endif
+
+       pwcs0 = *pwcs;
+
+       cnt = 0;
+       if (!s)
+               n = 1;
+
+       while (n > 0) {
+#if _ENCODING_IS_STATE_DEPENDENT
+               state = *psenc;
+#endif
+               err = _FUNCNAME(wcrtomb_priv)(ei, buf, sizeof(buf),
+                                             *pwcs0, psenc, &siz);
+               if (siz == (size_t)-1) {
+                       *nresult = siz;
+                       return (err);
+               }
+
+               if (s) {
+                       if (n < siz) {
+#if _ENCODING_IS_STATE_DEPENDENT
+                               *psenc = state;
+#endif
+                               break;
+                       }
+                       memcpy(s, buf, siz);
+                       s += siz;
+                       n -= siz;
+               }
+               cnt += siz;
+               if (!*pwcs0) {
+                       if (s) {
+                               _FUNCNAME(init_state)(ei, psenc);
+                       }
+                       pwcs0 = 0;
+                       cnt--; /* don't include terminating null */
+                       break;
+               }
+               pwcs0++;
+       }
+       if (s)
+               *pwcs = pwcs0;
+
+       *nresult = cnt;
+       return (0);
+}
+
+static int
+_FUNCNAME(wcsnrtombs_priv)(_ENCODING_INFO * __restrict ei, char * __restrict s,
+                         const wchar_t ** __restrict pwcs, size_t in,
+                         size_t n, _ENCODING_STATE * __restrict psenc,
+                         size_t * __restrict nresult)
+{
        int cnt = 0, err;
        char buf[MB_LEN_MAX];
        size_t siz;
@@ -302,7 +428,7 @@ _FUNCNAME(wcsrtombs_priv)(_ENCODING_INFO
        if (!s)
                n = 1;
 
-       while (n > 0) {
+       while (in > 0 && n > 0) {
 #if _ENCODING_IS_STATE_DEPENDENT
                state = *psenc;
 #endif
@@ -334,6 +460,7 @@ _FUNCNAME(wcsrtombs_priv)(_ENCODING_INFO
                        break;
                }
                pwcs0++;
+               --in;
        }
        if (s)
                *pwcs = pwcs0;
@@ -525,6 +652,27 @@ _FUNCNAME(ctype_mbsrtowcs)(void * __rest
        return (err);
 }
 
+static int __used
+_FUNCNAME(ctype_mbsnrtowcs)(_citrus_ctype_rec_t * __restrict cc, wchar_t * 
__restrict pwcs,
+                          const char ** __restrict s, size_t in, size_t n,
+                          void * __restrict pspriv,
+                          size_t * __restrict nresult)
+{
+       void *cl = cc->cc_closure;
+       _ENCODING_STATE *psenc;
+       _ENCODING_INFO *ei;
+       int err = 0;
+
+       _DIAGASSERT(cl != NULL);
+
+       ei = _CEI_TO_EI(_TO_CEI(cl));
+       _RESTART_BEGIN(mbsnrtowcs, _TO_CEI(cl), pspriv, psenc);
+       err = _FUNCNAME(mbsnrtowcs_priv)(ei, pwcs, s, in, n, psenc, nresult);
+       _RESTART_END(mbsnrtowcs, _TO_CEI(cl), pspriv, psenc);
+
+       return (err);
+}
+
 static int
 _FUNCNAME(ctype_mbstowcs)(void * __restrict cl, wchar_t * __restrict pwcs,
                          const char * __restrict s, size_t n,
@@ -637,6 +785,29 @@ _FUNCNAME(ctype_wcsrtombs)(void * __rest
        return err;
 }
 
+static int __used
+/*ARGSUSED*/
+_FUNCNAME(ctype_wcsnrtombs)(_citrus_ctype_rec_t * __restrict cc,
+                          char * __restrict s,
+                          const wchar_t ** __restrict pwcs, size_t in,
+                          size_t n, void * __restrict pspriv,
+                          size_t * __restrict nresult)
+{
+       void *cl = cc->cc_closure;
+       _ENCODING_STATE *psenc;
+       _ENCODING_INFO *ei;
+       int err = 0;
+
+       _DIAGASSERT(cl != NULL);
+
+       ei = _CEI_TO_EI(_TO_CEI(cl));
+       _RESTART_BEGIN(wcsnrtombs, _TO_CEI(cl), pspriv, psenc);
+       err = _FUNCNAME(wcsnrtombs_priv)(ei, s, pwcs, in, n, psenc, nresult);
+       _RESTART_END(wcsnrtombs, _TO_CEI(cl), pspriv, psenc);
+
+       return err;
+}
+
 static int
 /*ARGSUSED*/
 _FUNCNAME(ctype_wcstombs)(void * __restrict cl, char * __restrict s,
Index: lib/libc/citrus/citrus_none.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/citrus_none.c,v
retrieving revision 1.18
diff -u -p -r1.18 citrus_none.c
--- lib/libc/citrus/citrus_none.c       14 Jun 2008 16:01:07 -0000      1.18
+++ lib/libc/citrus/citrus_none.c       25 Apr 2013 18:48:35 -0000
@@ -185,6 +185,47 @@ _citrus_NONE_ctype_mbsrtowcs(void * __re
 }
 
 static int
+/*ARGSUSED*/
+_citrus_NONE_ctype_mbsnrtowcs(_citrus_ctype_rec_t * __restrict cc,
+                            wchar_t * __restrict pwcs,
+                            const char ** __restrict s, size_t in, size_t n,
+                            void * __restrict pspriv,
+                            size_t * __restrict nresult)
+{
+       int cnt;
+       const char *s0;
+
+       /* if pwcs is NULL, ignore n */
+       if (pwcs == NULL)
+               n = 1; /* arbitrary >0 value */
+
+       cnt = 0;
+       s0 = *s; /* to keep *s unchanged for now, use copy instead. */
+       while (in > 0 && n > 0) {
+               if (pwcs != NULL) {
+                       *pwcs = (wchar_t)(unsigned char)*s0;
+               }
+               if (*s0 == '\0') {
+                       s0 = NULL;
+                       break;
+               }
+               s0++;
+               --in;
+               if (pwcs != NULL) {
+                       pwcs++;
+                       n--;
+               }
+               cnt++;
+       }
+       if (pwcs)
+               *s = s0;
+
+       *nresult = (size_t)cnt;
+
+       return (0);
+}
+
+static int
 _citrus_NONE_ctype_mbstowcs(void * __restrict cl, wchar_t * __restrict wcs,
                            const char * __restrict s, size_t n,
                            size_t * __restrict nresult)
@@ -282,6 +323,48 @@ _citrus_NONE_ctype_wcsrtombs(void * __re
 }
 
 static int
+/*ARGSUSED*/
+_citrus_NONE_ctype_wcsnrtombs(_citrus_ctype_rec_t * __restrict cc,
+                            char * __restrict s,
+                            const wchar_t ** __restrict pwcs, size_t in,
+                            size_t n, void * __restrict pspriv,
+                            size_t * __restrict nresult)
+{
+       size_t count;
+       const wchar_t *pwcs0;
+
+       pwcs0 = *pwcs;
+       count = 0;
+
+       if (s == NULL)
+               n = 1;
+
+       while (in > 0 && n > 0) {
+               if ((*pwcs0 & ~0xFFU) != 0) {
+                       *nresult = (size_t)-1;
+                       return (EILSEQ);
+               }
+               if (s != NULL) {
+                       *s++ = (char)*pwcs0;
+                       n--;
+               }
+               if (*pwcs0 == L'\0') {
+                       pwcs0 = NULL;
+                       break;
+               }
+               count++;
+               pwcs0++;
+               --in;
+       }
+       if (s != NULL)
+               *pwcs = pwcs0;
+
+       *nresult = count;
+
+       return (0);
+}
+
+static int
 _citrus_NONE_ctype_wcstombs(void * __restrict cl, char * __restrict s,
                            const wchar_t * __restrict pwcs, size_t n,
                            size_t * __restrict nresult)
Index: lib/libc/citrus/modules/citrus_big5.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_big5.c,v
retrieving revision 1.13
diff -u -p -r1.13 citrus_big5.c
--- lib/libc/citrus/modules/citrus_big5.c       23 May 2011 14:53:46 -0000      
1.13
+++ lib/libc/citrus/modules/citrus_big5.c       25 Apr 2013 14:00:44 -0000
@@ -115,8 +115,10 @@ typedef struct {
                _BIG5State      s_mbrtowc;
                _BIG5State      s_mbtowc;
                _BIG5State      s_mbsrtowcs;
+               _BIG5State      s_mbsnrtowcs;
                _BIG5State      s_wcrtomb;
                _BIG5State      s_wcsrtombs;
+               _BIG5State      s_wcsnrtombs;
                _BIG5State      s_wctomb;
        } states;
 } _BIG5CTypeInfo;
Index: lib/libc/citrus/modules/citrus_dechanyu.c
===================================================================
RCS file: 
/home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_dechanyu.c,v
retrieving revision 1.4
diff -u -p -r1.4 citrus_dechanyu.c
--- lib/libc/citrus/modules/citrus_dechanyu.c   19 Nov 2011 18:20:13 -0000      
1.4
+++ lib/libc/citrus/modules/citrus_dechanyu.c   25 Apr 2013 14:00:44 -0000
@@ -71,8 +71,10 @@ typedef struct {
                _DECHanyuState  s_mbrtowc;
                _DECHanyuState  s_mbtowc;
                _DECHanyuState  s_mbsrtowcs;
+               _DECHanyuState  s_mbsnrtowcs;
                _DECHanyuState  s_wcrtomb;
                _DECHanyuState  s_wcsrtombs;
+               _DECHanyuState  s_wcsnrtombs;
                _DECHanyuState  s_wctomb;
        } states;
 } _DECHanyuCTypeInfo;
Index: lib/libc/citrus/modules/citrus_euc.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_euc.c,v
retrieving revision 1.14
diff -u -p -r1.14 citrus_euc.c
--- lib/libc/citrus/modules/citrus_euc.c        11 Jan 2009 02:46:24 -0000      
1.14
+++ lib/libc/citrus/modules/citrus_euc.c        25 Apr 2013 14:00:44 -0000
@@ -107,8 +107,10 @@ typedef struct {
                _EUCState       s_mbrtowc;
                _EUCState       s_mbtowc;
                _EUCState       s_mbsrtowcs;
+               _EUCState       s_mbsnrtowcs;
                _EUCState       s_wcrtomb;
                _EUCState       s_wcsrtombs;
+               _EUCState       s_wcsnrtombs;
                _EUCState       s_wctomb;
        } states;
 } _EUCCTypeInfo;
Index: lib/libc/citrus/modules/citrus_euctw.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_euctw.c,v
retrieving revision 1.11
diff -u -p -r1.11 citrus_euctw.c
--- lib/libc/citrus/modules/citrus_euctw.c      14 Jun 2008 16:01:07 -0000      
1.11
+++ lib/libc/citrus/modules/citrus_euctw.c      25 Apr 2013 14:00:44 -0000
@@ -98,8 +98,10 @@ typedef struct {
                _EUCTWState     s_mbrtowc;
                _EUCTWState     s_mbtowc;
                _EUCTWState     s_mbsrtowcs;
+               _EUCTWState     s_mbsnrtowcs;
                _EUCTWState     s_wcrtomb;
                _EUCTWState     s_wcsrtombs;
+               _EUCTWState     s_wcsnrtombs;
                _EUCTWState     s_wctomb;
        } states;
 } _EUCTWCTypeInfo;
Index: lib/libc/citrus/modules/citrus_gbk2k.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_gbk2k.c,v
retrieving revision 1.7
diff -u -p -r1.7 citrus_gbk2k.c
--- lib/libc/citrus/modules/citrus_gbk2k.c      14 Jun 2008 16:01:07 -0000      
1.7
+++ lib/libc/citrus/modules/citrus_gbk2k.c      25 Apr 2013 14:00:44 -0000
@@ -72,8 +72,10 @@ typedef struct {
                _GBK2KState     s_mbrtowc;
                _GBK2KState     s_mbtowc;
                _GBK2KState     s_mbsrtowcs;
+               _GBK2KState     s_mbsnrtowcs;
                _GBK2KState     s_wcrtomb;
                _GBK2KState     s_wcsrtombs;
+               _GBK2KState     s_wcsnrtombs;
                _GBK2KState     s_wctomb;
        } states;
 } _GBK2KCTypeInfo;
Index: lib/libc/citrus/modules/citrus_hz.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_hz.c,v
retrieving revision 1.2
diff -u -p -r1.2 citrus_hz.c
--- lib/libc/citrus/modules/citrus_hz.c 14 Jun 2008 16:01:07 -0000      1.2
+++ lib/libc/citrus/modules/citrus_hz.c 25 Apr 2013 14:00:44 -0000
@@ -143,8 +143,10 @@ typedef struct {
                _HZState        s_mbrtowc;
                _HZState        s_mbtowc;
                _HZState        s_mbsrtowcs;
+               _HZState        s_mbsnrtowcs;
                _HZState        s_wcrtomb;
                _HZState        s_wcsrtombs;
+               _HZState        s_wcsnrtombs;
                _HZState        s_wctomb;
        } states;
 } _HZCTypeInfo;
Index: lib/libc/citrus/modules/citrus_iso2022.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_iso2022.c,v
retrieving revision 1.22
diff -u -p -r1.22 citrus_iso2022.c
--- lib/libc/citrus/modules/citrus_iso2022.c    10 Oct 2011 22:45:45 -0000      
1.22
+++ lib/libc/citrus/modules/citrus_iso2022.c    25 Apr 2013 14:00:44 -0000
@@ -133,8 +133,10 @@ typedef struct {
                _ISO2022State   s_mbrtowc;
                _ISO2022State   s_mbtowc;
                _ISO2022State   s_mbsrtowcs;
+               _ISO2022State   s_mbsnrtowcs;
                _ISO2022State   s_wcrtomb;
                _ISO2022State   s_wcsrtombs;
+               _ISO2022State   s_wcsnrtombs;
                _ISO2022State   s_wctomb;
        } states;
 } _ISO2022CTypeInfo;
Index: lib/libc/citrus/modules/citrus_johab.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_johab.c,v
retrieving revision 1.4
diff -u -p -r1.4 citrus_johab.c
--- lib/libc/citrus/modules/citrus_johab.c      14 Jun 2008 16:01:07 -0000      
1.4
+++ lib/libc/citrus/modules/citrus_johab.c      25 Apr 2013 14:00:44 -0000
@@ -71,8 +71,10 @@ typedef struct {
                _JOHABState     s_mbrtowc;
                _JOHABState     s_mbtowc;
                _JOHABState     s_mbsrtowcs;
+               _JOHABState     s_mbsnrtowcs;
                _JOHABState     s_wcrtomb;
                _JOHABState     s_wcsrtombs;
+               _JOHABState     s_wcsnrtombs;
                _JOHABState     s_wctomb;
        } states;
 } _JOHABCTypeInfo;
Index: lib/libc/citrus/modules/citrus_mskanji.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_mskanji.c,v
retrieving revision 1.13
diff -u -p -r1.13 citrus_mskanji.c
--- lib/libc/citrus/modules/citrus_mskanji.c    14 Jun 2008 16:01:08 -0000      
1.13
+++ lib/libc/citrus/modules/citrus_mskanji.c    25 Apr 2013 14:00:44 -0000
@@ -107,8 +107,10 @@ typedef struct {
                _MSKanjiState   s_mbrtowc;
                _MSKanjiState   s_mbtowc;
                _MSKanjiState   s_mbsrtowcs;
+               _MSKanjiState   s_mbsnrtowcs;
                _MSKanjiState   s_wcrtomb;
                _MSKanjiState   s_wcsrtombs;
+               _MSKanjiState   s_wcsnrtombs;
                _MSKanjiState   s_wctomb;
        } states;
 } _MSKanjiCTypeInfo;
Index: lib/libc/citrus/modules/citrus_ues.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_ues.c,v
retrieving revision 1.3
diff -u -p -r1.3 citrus_ues.c
--- lib/libc/citrus/modules/citrus_ues.c        12 Feb 2012 13:51:29 -0000      
1.3
+++ lib/libc/citrus/modules/citrus_ues.c        25 Apr 2013 14:00:44 -0000
@@ -68,8 +68,10 @@ typedef struct {
                _UESState       s_mbrtowc;
                _UESState       s_mbtowc;
                _UESState       s_mbsrtowcs;
+               _UESState       s_mbsnrtowcs;
                _UESState       s_wcrtomb;
                _UESState       s_wcsrtombs;
+               _UESState       s_wcsnrtombs;
                _UESState       s_wctomb;
        } states;
 } _UESCTypeInfo;
Index: lib/libc/citrus/modules/citrus_utf7.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_utf7.c,v
retrieving revision 1.5
diff -u -p -r1.5 citrus_utf7.c
--- lib/libc/citrus/modules/citrus_utf7.c       23 Aug 2006 12:57:24 -0000      
1.5
+++ lib/libc/citrus/modules/citrus_utf7.c       25 Apr 2013 14:00:44 -0000
@@ -79,8 +79,10 @@ typedef struct {
                _UTF7State      s_mbrtowc;
                _UTF7State      s_mbtowc;
                _UTF7State      s_mbsrtowcs;
+               _UTF7State      s_mbsnrtowcs;
                _UTF7State      s_wcrtomb;
                _UTF7State      s_wcsrtombs;
+               _UTF7State      s_wcsnrtombs;
                _UTF7State      s_wctomb;
        } states;
 } _UTF7CTypeInfo;
Index: lib/libc/citrus/modules/citrus_utf8.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_utf8.c,v
retrieving revision 1.17
diff -u -p -r1.17 citrus_utf8.c
--- lib/libc/citrus/modules/citrus_utf8.c       14 Jun 2008 16:01:08 -0000      
1.17
+++ lib/libc/citrus/modules/citrus_utf8.c       25 Apr 2013 14:00:44 -0000
@@ -111,8 +111,10 @@ typedef struct {
                _UTF8State      s_mbrtowc;
                _UTF8State      s_mbtowc;
                _UTF8State      s_mbsrtowcs;
+               _UTF8State      s_mbsnrtowcs;
                _UTF8State      s_wcrtomb;
                _UTF8State      s_wcsrtombs;
+               _UTF8State      s_wcsnrtombs;
                _UTF8State      s_wctomb;
        } states;
 } _UTF8CTypeInfo;
Index: lib/libc/citrus/modules/citrus_viqr.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_viqr.c,v
retrieving revision 1.5
diff -u -p -r1.5 citrus_viqr.c
--- lib/libc/citrus/modules/citrus_viqr.c       19 Nov 2011 18:20:13 -0000      
1.5
+++ lib/libc/citrus/modules/citrus_viqr.c       25 Apr 2013 14:00:44 -0000
@@ -234,8 +234,10 @@ typedef struct {
                _VIQRState      s_mbrtowc;
                _VIQRState      s_mbtowc;
                _VIQRState      s_mbsrtowcs;
+               _VIQRState      s_mbsnrtowcs;
                _VIQRState      s_wcrtomb;
                _VIQRState      s_wcsrtombs;
+               _VIQRState      s_wcsnrtombs;
                _VIQRState      s_wctomb;
        } states;
 } _VIQRCTypeInfo;
Index: lib/libc/citrus/modules/citrus_zw.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/citrus/modules/citrus_zw.c,v
retrieving revision 1.4
diff -u -p -r1.4 citrus_zw.c
--- lib/libc/citrus/modules/citrus_zw.c 14 Jun 2008 16:01:08 -0000      1.4
+++ lib/libc/citrus/modules/citrus_zw.c 25 Apr 2013 14:00:44 -0000
@@ -77,8 +77,10 @@ typedef struct {
                _ZWState        s_mbrtowc;
                _ZWState        s_mbtowc;
                _ZWState        s_mbsrtowcs;
+               _ZWState        s_mbsnrtowcs;
                _ZWState        s_wcrtomb;
                _ZWState        s_wcsrtombs;
+               _ZWState        s_wcsnrtombs;
                _ZWState        s_wctomb;
        } states;
 } _ZWCTypeInfo;
Index: lib/libc/locale/multibyte_amd1.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/lib/libc/locale/multibyte_amd1.c,v
retrieving revision 1.11
diff -u -p -r1.11 multibyte_amd1.c
--- lib/libc/locale/multibyte_amd1.c    19 Apr 2013 14:35:33 -0000      1.11
+++ lib/libc/locale/multibyte_amd1.c    25 Apr 2013 14:21:09 -0000
@@ -163,6 +163,32 @@ mbsrtowcs(wchar_t *pwcs, const char **s,
 }
 
 size_t
+mbsnrtowcs_l(wchar_t *pwcs, const char **s, size_t in, size_t n, mbstate_t *ps,
+    locale_t loc)
+{
+       size_t ret;
+       int err0;
+
+       if (loc == NULL)
+               loc = _C_locale;
+
+       _fixup_ps(_RUNE_LOCALE(loc), ps, s == NULL);
+
+       err0 = _citrus_ctype_mbsnrtowcs(_ps_to_ctype(ps), pwcs, s, in, n,
+                                       _ps_to_private(ps), &ret);
+       if (err0)
+               errno = err0;
+
+       return ret;
+}
+
+size_t
+mbsnrtowcs(wchar_t *pwcs, const char **s, size_t in, size_t n, mbstate_t *ps)
+{
+       return mbsnrtowcs_l(pwcs, s, in, n, ps, *_current_locale());
+}
+
+size_t
 wcrtomb_l(char *s, wchar_t wc, mbstate_t *ps, locale_t loc)
 {
        size_t ret;
@@ -213,6 +239,32 @@ wcsrtombs(char *s, const wchar_t **ppwcs
        return wcsrtombs_l(s, ppwcs, n, ps, *_current_locale());
 }
 
+size_t
+wcsnrtombs_l(char *s, const wchar_t **ppwcs, size_t in, size_t n, mbstate_t 
*ps,
+    locale_t loc)
+{
+       size_t ret;
+       int err0;
+
+       if (loc == NULL)
+               loc = _C_locale;
+
+       _fixup_ps(_RUNE_LOCALE(loc), ps, s == NULL);
+
+       err0 = _citrus_ctype_wcsnrtombs(_ps_to_ctype(ps), s, ppwcs, in, n,
+                                       _ps_to_private(ps), &ret);
+       if (err0)
+               errno = err0;
+
+       return ret;
+}
+
+size_t
+wcsnrtombs(char *s, const wchar_t **ppwcs, size_t in, size_t n, mbstate_t *ps)
+{
+       return wcsnrtombs_l(s, ppwcs, in, n, ps, *_current_locale());
+}
+
 wint_t
 btowc_l(int c, locale_t loc)
 {
Index: tests/lib/libc/locale/Makefile
===================================================================
RCS file: /home/joerg/repo/netbsd/src/tests/lib/libc/locale/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- tests/lib/libc/locale/Makefile      28 Feb 2013 21:52:02 -0000      1.5
+++ tests/lib/libc/locale/Makefile      26 Apr 2013 19:30:52 -0000
@@ -6,6 +6,7 @@ TESTSDIR=       ${TESTSBASE}/lib/libc/locale
 
 TESTS_C+=      t_mbrtowc
 TESTS_C+=      t_mbstowcs
+TESTS_C+=      t_mbsnrtowcs
 TESTS_C+=      t_mbtowc
 TESTS_C+=      t_wcscspn
 TESTS_C+=      t_wcspbrk
Index: tests/lib/libc/locale/t_mbsnrtowcs.c
===================================================================
RCS file: tests/lib/libc/locale/t_mbsnrtowcs.c
diff -N tests/lib/libc/locale/t_mbsnrtowcs.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tests/lib/libc/locale/t_mbsnrtowcs.c        26 Apr 2013 19:50:38 -0000
@@ -0,0 +1,98 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <locale.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static const struct test {
+       const char *locale;
+       const char *data;
+       size_t limit;
+       const wchar_t output1[64];
+       size_t len1;
+       size_t input_processed;
+       const wchar_t output2[64];
+       size_t len2;
+} tests[] = {
+       { "C", "ABCD0123", 4, { 0x41, 0x42, 0x43, 0x44 }, 4, 4,
+                           { 0x30, 0x31, 0x32, 0x33, 0x0 }, 4, },
+       { "en_US.UTF-8", "ABCD0123", 4, { 0x41, 0x42, 0x43, 0x44 }, 4, 4,
+                           { 0x30, 0x31, 0x32, 0x33, 0x0 }, 4, },
+       { "en_US.UTF-8", "ABC\303\2440123", 4, { 0x41, 0x42, 0x43, }, 3, 3,
+                           { 0xe4, 0x30, 0x31, 0x32, 0x33, 0x0 }, 5, },
+};
+
+ATF_TC(mbsnrtowcs);
+ATF_TC_HEAD(mbsnrtowcs, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+               "Checks mbsnrtowc(3) with different locales");
+}
+ATF_TC_BODY(mbsnrtowcs, tc)
+{
+       size_t i;
+       const struct test *t;
+       mbstate_t state;
+       wchar_t buf[64];
+       const char *src;
+       size_t len;
+
+       for (i = 0; i < __arraycount(tests); ++i) {
+               t = &tests[i];
+               ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C");
+               ATF_REQUIRE(setlocale(LC_CTYPE, t->locale) != NULL);
+               memset(&state, 0, sizeof(state));
+               src = t->data;
+               len = mbsnrtowcs(buf, &src, t->limit,
+                   __arraycount(buf), &state);
+               ATF_REQUIRE_EQ(len, t->len1);
+               ATF_REQUIRE(wmemcmp(t->output1, buf, len) == 0);
+               ATF_REQUIRE_EQ(src, t->data + t->input_processed);
+               len = mbsnrtowcs(buf, &src, strlen(src) + 1,
+                   __arraycount(buf), &state);
+               ATF_REQUIRE_EQ(len, t->len2);
+               ATF_REQUIRE(wmemcmp(t->output2, buf, len + 1) == 0);
+               ATF_REQUIRE_EQ(src, NULL);
+       }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+       ATF_TP_ADD_TC(tp, mbsnrtowcs);
+
+       return atf_no_error();
+}


Home | Main Index | Thread Index | Old Index