diff options
author | Matthew Dempsky <matthew@cvs.openbsd.org> | 2012-06-06 16:58:03 +0000 |
---|---|---|
committer | Matthew Dempsky <matthew@cvs.openbsd.org> | 2012-06-06 16:58:03 +0000 |
commit | e6b7baa38b9c9d4730b74744f6795b2ae0941a06 (patch) | |
tree | aac2a5956a548f193a19189cb947c38b617f1a90 /lib | |
parent | 64e66057c29657d2722c956cc3dbdd149aac406e (diff) |
Add support for mbsnrtowcs() and wcsnrtombs() to libc.
Bulk build test by naddy.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/citrus/citrus_ctype_local.h | 32 | ||||
-rw-r--r-- | lib/libc/citrus/citrus_none.c | 112 | ||||
-rw-r--r-- | lib/libc/citrus/citrus_utf8.c | 197 | ||||
-rw-r--r-- | lib/libc/locale/multibyte_citrus.c | 36 | ||||
-rw-r--r-- | lib/libc/shlib_version | 2 |
5 files changed, 204 insertions, 175 deletions
diff --git a/lib/libc/citrus/citrus_ctype_local.h b/lib/libc/citrus/citrus_ctype_local.h index 8ada0ef3d2c..4536261df12 100644 --- a/lib/libc/citrus/citrus_ctype_local.h +++ b/lib/libc/citrus/citrus_ctype_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: citrus_ctype_local.h,v 1.2 2010/07/27 16:59:03 stsp Exp $ */ +/* $OpenBSD: citrus_ctype_local.h,v 1.3 2012/06/06 16:58:02 matthew Exp $ */ /* $NetBSD: citrus_ctype_local.h,v 1.2 2003/03/05 20:18:15 tshiozak Exp $ */ /*- @@ -36,43 +36,45 @@ size_t _citrus_##_e_##_ctype_mbrtowc(wchar_t * __restrict, \ 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" diff --git a/lib/libc/citrus/citrus_none.c b/lib/libc/citrus/citrus_none.c index e0dfafdecd0..9699bf88038 100644 --- a/lib/libc/citrus/citrus_none.c +++ b/lib/libc/citrus/citrus_none.c @@ -1,4 +1,4 @@ -/* $OpenBSD: citrus_none.c,v 1.2 2010/08/03 11:23:37 stsp Exp $ */ +/* $OpenBSD: citrus_none.c,v 1.3 2012/06/06 16:58:02 matthew Exp $ */ /* $NetBSD: citrus_none.c,v 1.18 2008/06/14 16:01:07 tnozaki Exp $ */ /*- @@ -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 * __restrict pspriv) 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 * __restrict s, /* 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); } diff --git a/lib/libc/citrus/citrus_utf8.c b/lib/libc/citrus/citrus_utf8.c index 895ca6a27fb..5b37b267e21 100644 --- a/lib/libc/citrus/citrus_utf8.c +++ b/lib/libc/citrus/citrus_utf8.c @@ -1,4 +1,4 @@ -/* $OpenBSD: citrus_utf8.c,v 1.4 2011/04/21 00:16:06 yasuoka Exp $ */ +/* $OpenBSD: citrus_utf8.c,v 1.5 2012/06/06 16:58:02 matthew Exp $ */ /*- * Copyright (c) 2002-2004 Tim J. Robbins @@ -186,53 +186,44 @@ _citrus_utf8_ctype_mbsinit(const void * __restrict pspriv) 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 * __restrict pwcs, * 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); + r = _citrus_utf8_ctype_mbrtowc(dst + o, *src + i, + nmc - i, us); + if (r == (size_t)-1) { + *src += i; + return (r); } - if (nb == (size_t)-2) { - *s = src; - return (nchr); + if (r == (size_t)-2) { + *src += nmc; + return (o); } - if (nb == 0) { - *s = NULL; - return (nchr); + 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 * __restrict s, 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 * __restrict s, 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); } diff --git a/lib/libc/locale/multibyte_citrus.c b/lib/libc/locale/multibyte_citrus.c index 9993e67fe15..3352c7bdbc2 100644 --- a/lib/libc/locale/multibyte_citrus.c +++ b/lib/libc/locale/multibyte_citrus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: multibyte_citrus.c,v 1.1 2010/07/27 16:59:04 stsp Exp $ */ +/* $OpenBSD: multibyte_citrus.c,v 1.2 2012/06/06 16:58:02 matthew Exp $ */ /* $NetBSD: multibyte_amd1.c,v 1.7 2009/01/11 02:46:28 christos Exp $ */ /*- @@ -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, size_t n, mbstate_t *ps) } 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, size_t n, mbstate_t *ps) 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 *ps) } 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, size_t n, mbstate_t *ps) 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)); } diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index da350fdb8a2..56a8145c9df 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,4 +1,4 @@ major=64 -minor=1 +minor=2 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then libpthread must also be updated. |