Diff below adds mbsnrtowcs() and wcsnrtombs(), which are new POSIX
2008 functions. I'd appreciate if someone could run this through a
bulk build and let me know if anything breaks or misbehaves.
Thanks!
Index: include/wchar.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/include/wchar.h,v
retrieving revision 1.22
diff -u -p -r1.22 wchar.h
--- include/wchar.h 5 Jan 2012 20:37:50 -0000 1.22
+++ include/wchar.h 25 May 2012 06:01:50 -0000
@@ -158,6 +158,11 @@ unsigned long int wcstoul(const wchar_t
wchar_t *wcsdup(const wchar_t *);
int wcscasecmp(const wchar_t *, const wchar_t *);
int wcsncasecmp(const wchar_t *, const wchar_t *, size_t);
+
+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);
#endif
#if __ISO_C_VISIBLE >= 1999
Index: lib/libc/locale/multibyte_citrus.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/locale/multibyte_citrus.c,v
retrieving revision 1.1
diff -u -p -r1.1 multibyte_citrus.c
--- lib/libc/locale/multibyte_citrus.c 27 Jul 2010 16:59:04 -0000 1.1
+++ lib/libc/locale/multibyte_citrus.c 25 May 2012 16:45:00 -0000
@@ -30,6 +30,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
+#include <limits.h>
#include <wchar.h>
#include "citrus_ctype.h"
@@ -65,7 +66,19 @@ mbrtowc(wchar_t *pwc, const char *s, siz
}
size_t
-mbsrtowcs(wchar_t *pwcs, const char **s, size_t n, mbstate_t *ps)
+mbsrtowcs(wchar_t *dst, const char **src, size_t len, mbstate_t *ps)
+{
+ static mbstate_t mbs;
+ struct _citrus_ctype_rec *cc;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (mbsnrtowcs(dst, src, SIZE_MAX, len, ps));
+}
+
+size_t
+mbsnrtowcs(wchar_t *dst, const char **src, size_t nmc, size_t len,
+ mbstate_t *ps)
{
static mbstate_t mbs;
struct _citrus_ctype_rec *cc;
@@ -73,7 +86,8 @@ mbsrtowcs(wchar_t *pwcs, const char **s,
if (ps == NULL)
ps = &mbs;
cc = _CurrentRuneLocale->rl_citrus_ctype;
- return (*cc->cc_ops->co_mbsrtowcs)(pwcs, s, n, _ps_to_private(ps));
+ return (*cc->cc_ops->co_mbsnrtowcs)(dst, src, nmc, len,
+ _ps_to_private(ps));
}
size_t
@@ -89,7 +103,18 @@ wcrtomb(char *s, wchar_t wc, mbstate_t *
}
size_t
-wcsrtombs(char *s, const wchar_t **ppwcs, size_t n, mbstate_t *ps)
+wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (wcsnrtombs(dst, src, SIZE_MAX, len, ps));
+}
+
+size_t
+wcsnrtombs(char *dst, const wchar_t **src, size_t nwc, size_t len,
+ mbstate_t *ps)
{
static mbstate_t mbs;
struct _citrus_ctype_rec *cc;
@@ -97,5 +122,6 @@ wcsrtombs(char *s, const wchar_t **ppwcs
if (ps == NULL)
ps = &mbs;
cc = _CurrentRuneLocale->rl_citrus_ctype;
- return (*cc->cc_ops->co_wcsrtombs)(s, ppwcs, n, _ps_to_private(ps));
+ return (*cc->cc_ops->co_wcsnrtombs)(dst, src, nwc, len,
+ _ps_to_private(ps));
}
Index: lib/libc/citrus/citrus_ctype_local.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/citrus/citrus_ctype_local.h,v
retrieving revision 1.2
diff -u -p -r1.2 citrus_ctype_local.h
--- lib/libc/citrus/citrus_ctype_local.h 27 Jul 2010 16:59:03 -0000
1.2
+++ lib/libc/citrus/citrus_ctype_local.h 25 May 2012 01:36:32 -0000
@@ -36,43 +36,45 @@ size_t _citrus_##_e_##_ctype_mbrtowc(wch
const char * __restrict, size_t, \
void * __restrict); \
int _citrus_##_e_##_ctype_mbsinit(const void * __restrict); \
-size_t _citrus_##_e_##_ctype_mbsrtowcs(wchar_t * __restrict, \
- const char ** __restrict, \
- size_t, void * __restrict); \
+size_t _citrus_##_e_##_ctype_mbsnrtowcs(wchar_t * __restrict, \
+ const char ** __restrict, \
+ size_t, size_t, \
+ void * __restrict); \
size_t _citrus_##_e_##_ctype_wcrtomb(char * __restrict, wchar_t, \
void * __restrict); \
-size_t _citrus_##_e_##_ctype_wcsrtombs(char * __restrict, \
- const wchar_t ** __restrict, \
- size_t, void * __restrict); \
+size_t _citrus_##_e_##_ctype_wcsnrtombs(char * __restrict, \
+ const wchar_t ** __restrict, \
+ size_t, size_t, \
+ void * __restrict); \
#define _CITRUS_CTYPE_DEF_OPS(_e_) \
struct _citrus_ctype_ops_rec _citrus_##_e_##_ctype_ops = { \
/* co_mbrtowc */ &_citrus_##_e_##_ctype_mbrtowc, \
/* co_mbsinit */ &_citrus_##_e_##_ctype_mbsinit, \
- /* co_mbsrtowcs */ &_citrus_##_e_##_ctype_mbsrtowcs, \
+ /* co_mbsnrtowcs */ &_citrus_##_e_##_ctype_mbsnrtowcs, \
/* co_wcrtomb */ &_citrus_##_e_##_ctype_wcrtomb, \
- /* co_wcsrtombs */ &_citrus_##_e_##_ctype_wcsrtombs, \
+ /* co_wcsnrtombs */ &_citrus_##_e_##_ctype_wcsnrtombs, \
}
typedef size_t (*_citrus_ctype_mbrtowc_t)
(wchar_t * __restrict, const char * __restrict,
size_t, void * __restrict);
typedef int (*_citrus_ctype_mbsinit_t) (const void * __restrict);
-typedef size_t (*_citrus_ctype_mbsrtowcs_t)
+typedef size_t (*_citrus_ctype_mbsnrtowcs_t)
(wchar_t * __restrict, const char ** __restrict,
- size_t, void * __restrict);
+ size_t, size_t, void * __restrict);
typedef size_t (*_citrus_ctype_wcrtomb_t)
(char * __restrict, wchar_t, void * __restrict);
-typedef size_t (*_citrus_ctype_wcsrtombs_t)
+typedef size_t (*_citrus_ctype_wcsnrtombs_t)
(char * __restrict, const wchar_t ** __restrict,
- size_t, void * __restrict);
+ size_t, size_t, void * __restrict);
struct _citrus_ctype_ops_rec {
_citrus_ctype_mbrtowc_t co_mbrtowc;
_citrus_ctype_mbsinit_t co_mbsinit;
- _citrus_ctype_mbsrtowcs_t co_mbsrtowcs;
+ _citrus_ctype_mbsnrtowcs_t co_mbsnrtowcs;
_citrus_ctype_wcrtomb_t co_wcrtomb;
- _citrus_ctype_wcsrtombs_t co_wcsrtombs;
+ _citrus_ctype_wcsnrtombs_t co_wcsnrtombs;
};
#define _CITRUS_DEFAULT_CTYPE_NAME "NONE"
Index: lib/libc/citrus/citrus_none.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/citrus/citrus_none.c,v
retrieving revision 1.2
diff -u -p -r1.2 citrus_none.c
--- lib/libc/citrus/citrus_none.c 3 Aug 2010 11:23:37 -0000 1.2
+++ lib/libc/citrus/citrus_none.c 25 May 2012 16:37:39 -0000
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <errno.h>
+#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,6 +43,19 @@
_CITRUS_CTYPE_DEF_OPS(none);
+/*
+ * Convert an unsigned char value into a char value without relying on
+ * signed overflow behavior.
+ */
+static inline char
+wrapv(unsigned char ch)
+{
+ if (ch >= 0x80)
+ return ((int)ch - 0x100);
+ else
+ return (ch);
+}
+
size_t
/*ARGSUSED*/
_citrus_none_ctype_mbrtowc(wchar_t * __restrict pwc,
@@ -70,30 +84,27 @@ _citrus_none_ctype_mbsinit(const void *
size_t
/*ARGSUSED*/
-_citrus_none_ctype_mbsrtowcs(wchar_t * __restrict pwcs,
- const char ** __restrict s, size_t n,
- void * __restrict pspriv)
+_citrus_none_ctype_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nmc, size_t len,
+ void * __restrict pspriv)
{
- int count = 0;
+ size_t i;
- /* pwcs may be NULL */
- /* s may be NULL */
+ /* dst may be NULL */
/* pspriv appears to be unused */
- if (!s || !*s)
- return 0;
+ if (dst == NULL)
+ return strnlen(*src, nmc);
- if (pwcs == NULL)
- return strlen(*s);
+ for (i = 0; i < nmc && i < len; i++)
+ if ((dst[i] = (wchar_t)(unsigned char)(*src)[i]) == L'\0') {
+ *src = NULL;
+ return (i);
+ }
- while (n > 0) {
- if ((*pwcs++ = (wchar_t)(unsigned char)*(*s)++) == 0)
- break;
- count++;
- n--;
- }
-
- return count;
+ *src += i;
+ return (i);
}
size_t
@@ -105,40 +116,55 @@ _citrus_none_ctype_wcrtomb(char * __rest
/* ps appears to be unused */
if (s == NULL)
- return 0;
+ return (0);
+
+ if (wc < 0 || wc > 0xff) {
+ errno = EILSEQ;
+ return (-1);
+ }
- *s = (char) wc;
- return 1;
+ *s = wrapv(wc);
+ return (1);
}
size_t
/*ARGSUSED*/
-_citrus_none_ctype_wcsrtombs(char * __restrict s,
- const wchar_t ** __restrict pwcs, size_t n,
- void * __restrict pspriv)
+_citrus_none_ctype_wcsnrtombs(char * __restrict dst,
+ const wchar_t ** __restrict src,
+ size_t nwc, size_t len,
+ void * __restrict pspriv)
{
- int count = 0;
+ size_t i;
- /* s may be NULL */
- /* pwcs may be NULL */
+ /* dst may be NULL */
/* pspriv appears to be unused */
- if (pwcs == NULL || *pwcs == NULL)
- return (0);
-
- if (s == NULL) {
- while (*(*pwcs)++ != 0)
- count++;
- return(count);
+ if (dst == NULL) {
+ for (i = 0; i < nwc; i++) {
+ wchar_t wc = (*src)[i];
+ if (wc < 0 || wc > 0xff) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ if (wc == L'\0')
+ return (i);
+ }
+ return (i);
}
- if (n != 0) {
- do {
- if ((*s++ = (char) *(*pwcs)++) == 0)
- break;
- count++;
- } while (--n != 0);
+ for (i = 0; i < nwc && i < len; i++) {
+ wchar_t wc = (*src)[i];
+ if (wc < 0 || wc > 0xff) {
+ *src += i;
+ errno = EILSEQ;
+ return (-1);
+ }
+ dst[i] = wrapv(wc);
+ if (wc == L'\0') {
+ *src = NULL;
+ return (i);
+ }
}
-
- return count;
+ *src += i;
+ return (i);
}
Index: lib/libc/citrus/citrus_utf8.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/lib/libc/citrus/citrus_utf8.c,v
retrieving revision 1.4
diff -u -p -r1.4 citrus_utf8.c
--- lib/libc/citrus/citrus_utf8.c 21 Apr 2011 00:16:06 -0000 1.4
+++ lib/libc/citrus/citrus_utf8.c 25 May 2012 17:03:00 -0000
@@ -186,53 +186,44 @@ _citrus_utf8_ctype_mbsinit(const void *
size_t
/*ARGSUSED*/
-_citrus_utf8_ctype_mbsrtowcs(wchar_t * __restrict pwcs,
- const char ** __restrict s, size_t n,
- void * __restrict pspriv)
+_citrus_utf8_ctype_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nmc, size_t len,
+ void * __restrict pspriv)
{
struct _utf8_state *us;
- const char *src;
- size_t nchr;
- wchar_t wc;
- size_t nb;
+ size_t i, o, r;
us = (struct _utf8_state *)pspriv;
- src = *s;
- nchr = 0;
- if (pwcs == NULL) {
+ if (dst == NULL) {
/*
* The fast path in the loop below is not safe if an ASCII
* character appears as anything but the first byte of a
* multibyte sequence. Check now to avoid doing it in the loop.
*/
- if (us->want > 0 && (signed char)*src > 0) {
+ if (nmc > 0 && us->want > 0 && (unsigned char)(*src)[0] < 0x80)
{
errno = EILSEQ;
return ((size_t)-1);
}
- for (;;) {
- if ((signed char)*src > 0) {
- /*
- * Fast path for plain ASCII characters
- * excluding NUL.
- */
- nb = 1;
+ for (i = o = 0; i < nmc; i += r, o++) {
+ if ((unsigned char)(*src)[i] < 0x80) {
+ /* Fast path for plain ASCII characters. */
+ if ((*src)[i] == '\0')
+ return (o);
+ r = 1;
} else {
- nb = _citrus_utf8_ctype_mbrtowc(&wc, src,
- _CITRUS_UTF8_MB_CUR_MAX, us);
- if (nb == (size_t)-1) {
- /* Invalid sequence. */
- return (nb);
- }
- if (nb == 0 || nb == (size_t)-2) {
- return (nchr);
- }
+ r = _citrus_utf8_ctype_mbrtowc(NULL, *src + i,
+ nmc - i, us);
+ if (r == (size_t)-1)
+ return (r);
+ if (r == (size_t)-2)
+ return (o);
+ if (r == 0)
+ return (o);
}
-
- src += nb;
- nchr++;
}
- /*NOTREACHED*/
+ return (o);
}
/*
@@ -240,40 +231,38 @@ _citrus_utf8_ctype_mbsrtowcs(wchar_t * _
* character appears as anything but the first byte of a
* multibyte sequence. Check now to avoid doing it in the loop.
*/
- if (n > 0 && us->want > 0 && (signed char)*src > 0) {
+ if (len > 0 && nmc > 0 && us->want > 0 && (unsigned char)(*src)[0] <
0x80) {
errno = EILSEQ;
return ((size_t)-1);
}
- while (n-- > 0) {
- if ((signed char)*src > 0) {
- /*
- * Fast path for plain ASCII characters
- * excluding NUL.
- */
- *pwcs = (wchar_t)*src;
- nb = 1;
+ for (i = o = 0; i < nmc && o < len; i += r, o++) {
+ if ((unsigned char)(*src)[i] < 0x80) {
+ /* Fast path for plain ASCII characters. */
+ dst[o] = (wchar_t)(unsigned char)(*src)[i];
+ if ((*src)[i] == '\0') {
+ *src = NULL;
+ return (o);
+ }
+ r = 1;
} else {
- nb = _citrus_utf8_ctype_mbrtowc(pwcs, src,
- _CITRUS_UTF8_MB_CUR_MAX, us);
- if (nb == (size_t)-1) {
- *s = src;
- return (nb);
- }
- if (nb == (size_t)-2) {
- *s = src;
- return (nchr);
- }
- if (nb == 0) {
- *s = NULL;
- return (nchr);
+ r = _citrus_utf8_ctype_mbrtowc(dst + o, *src + i,
+ nmc - i, us);
+ if (r == (size_t)-1) {
+ *src += i;
+ return (r);
+ }
+ if (r == (size_t)-2) {
+ *src += nmc;
+ return (o);
+ }
+ if (r == 0) {
+ *src = NULL;
+ return (o);
}
}
- src += nb;
- nchr++;
- pwcs++;
}
- *s = src;
- return (nchr);
+ *src += i;
+ return (o);
}
size_t
@@ -343,15 +332,14 @@ _citrus_utf8_ctype_wcrtomb(char * __rest
size_t
/*ARGSUSED*/
-_citrus_utf8_ctype_wcsrtombs(char * __restrict s,
- const wchar_t ** __restrict pwcs, size_t n,
- void * __restrict pspriv)
+_citrus_utf8_ctype_wcsnrtombs(char * __restrict dst,
+ const wchar_t ** __restrict src,
+ size_t nwc, size_t len,
+ void * __restrict pspriv)
{
struct _utf8_state *us;
char buf[_CITRUS_UTF8_MB_CUR_MAX];
- const wchar_t *src;
- size_t nbytes;
- size_t nb;
+ size_t i, o, r;
us = (struct _utf8_state *)pspriv;
@@ -360,65 +348,52 @@ _citrus_utf8_ctype_wcsrtombs(char * __re
return ((size_t)-1);
}
- src = *pwcs;
- nbytes = 0;
-
- if (s == NULL) {
- for (;;) {
- if (0 <= *src && *src < 0x80)
+ if (dst == NULL) {
+ for (i = o = 0; i < nwc; i++, o += r) {
+ wchar_t wc = (*src)[i];
+ if (wc >= 0 && wc < 0x80) {
/* Fast path for plain ASCII characters. */
- nb = 1;
- else {
- nb = _citrus_utf8_ctype_wcrtomb(buf, *src, us);
- if (nb == (size_t)-1) {
- /* Invalid character */
- return (nb);
- }
- }
- if (*src == L'\0') {
- return (nbytes + nb - 1);
+ if (wc == 0)
+ return (o);
+ r = 1;
+ } else {
+ r = _citrus_utf8_ctype_wcrtomb(buf, wc, us);
+ if (r == (size_t)-1)
+ return (r);
}
- src++;
- nbytes += nb;
}
- /*NOTREACHED*/
+ return (o);
}
- while (n > 0) {
- if (0 <= *src && *src < 0x80) {
+ for (i = o = 0; i < nwc && o < len; i++, o += r) {
+ wchar_t wc = (*src)[i];
+ if (wc >= 0 && wc < 0x80) {
/* Fast path for plain ASCII characters. */
- nb = 1;
- *s = *src;
- } else if (n > (size_t)_CITRUS_UTF8_MB_CUR_MAX) {
+ dst[o] = (wchar_t)wc;
+ if (wc == 0) {
+ *src = NULL;
+ return (o);
+ }
+ r = 1;
+ } else if (len - o >= _CITRUS_UTF8_MB_CUR_MAX) {
/* Enough space to translate in-place. */
- nb = _citrus_utf8_ctype_wcrtomb(s, *src, us);
- if (nb == (size_t)-1) {
- *pwcs = src;
- return (nb);
+ r = _citrus_utf8_ctype_wcrtomb(dst + o, wc, us);
+ if (r == (size_t)-1) {
+ *src += i;
+ return (r);
}
} else {
- /*
- * May not be enough space; use temp. buffer.
- */
- nb = _citrus_utf8_ctype_wcrtomb(buf, *src, us);
- if (nb == (size_t)-1) {
- *pwcs = src;
- return (nb);
+ /* May not be enough space; use temp buffer. */
+ r = _citrus_utf8_ctype_wcrtomb(buf, wc, us);
+ if (r == (size_t)-1) {
+ *src += i;
+ return (r);
}
- if (nb > n)
- /* MB sequence for character won't fit. */
+ if (r > len - o)
break;
- memcpy(s, buf, nb);
- }
- if (*src == L'\0') {
- *pwcs = NULL;
- return (nbytes + nb - 1);
+ memcpy(dst + o, buf, r);
}
- src++;
- s += nb;
- n -= nb;
- nbytes += nb;
}
- *pwcs = src;
- return (nbytes);
+ *src += i;
+ return (o);
}
----- End forwarded message -----