diff options
author | Bruno Haible <bruno@clisp.org> | 2008-12-21 02:55:00 +0100 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2008-12-21 02:55:00 +0100 |
commit | 2c11b49f00662697a6b27da0beb86adb4b6fae97 (patch) | |
tree | da3a8a8eff9c5d5986a4dc400acf153d25f1b0cf /lib | |
parent | 6d65e7578f692b2d06574e25a848cef93b02ed25 (diff) | |
download | gnulib-2c11b49f00662697a6b27da0beb86adb4b6fae97.tar.gz |
Work around mbrtowc bugs on AIX, HP-UX, OSF/1, Solaris.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mbrtowc.c | 89 | ||||
-rw-r--r-- | lib/wchar.in.h | 15 |
2 files changed, 94 insertions, 10 deletions
diff --git a/lib/mbrtowc.c b/lib/mbrtowc.c index e5ae0bcc35..603f006093 100644 --- a/lib/mbrtowc.c +++ b/lib/mbrtowc.c @@ -20,12 +20,15 @@ /* Specification. */ #include <wchar.h> -#include <errno.h> -#include <stdlib.h> +#if GNULIB_defined_mbstate_t +/* Implement mbrtowc() on top of mbtowc(). */ -#include "localcharset.h" -#include "streq.h" -#include "verify.h" +# include <errno.h> +# include <stdlib.h> + +# include "localcharset.h" +# include "streq.h" +# include "verify.h" verify (sizeof (mbstate_t) >= 4); @@ -88,10 +91,10 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) /* Here 0 < m ≤ 4. */ -#if __GLIBC__ +# if __GLIBC__ /* Work around bug <http://sourceware.org/bugzilla/show_bug.cgi?id=9674> */ mbtowc (NULL, NULL, 0); -#endif +# endif { int res = mbtowc (pwc, p, m); @@ -272,3 +275,75 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) } } } + +#else +/* Override the system's mbrtowc() function. */ + +# undef mbrtowc + +size_t +rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) +{ +# if MBRTOWC_NULL_ARG_BUG || MBRTOWC_RETVAL_BUG + if (s == NULL) + { + pwc = NULL; + s = ""; + n = 1; + } +# endif + +# if MBRTOWC_RETVAL_BUG + { + static mbstate_t internal_state; + + /* Override mbrtowc's internal state. We can not call mbsinit() on the + hidden internal state, but we can call it on our variable. */ + if (ps == NULL) + ps = &internal_state; + + if (!mbsinit (ps)) + { + /* Parse the rest of the multibyte character byte for byte. */ + size_t count = 0; + for (; n > 0; s++, n--) + { + wchar_t wc; + size_t ret = mbrtowc (&wc, s, 1, ps); + + if (ret == (size_t)(-1)) + return (size_t)(-1); + count++; + if (ret != (size_t)(-2)) + { + /* The multibyte character has been completed. */ + if (pwc != NULL) + *pwc = wc; + return (wc == 0 ? 0 : count); + } + } + return (size_t)(-2); + } + } +# endif + +# if MBRTOWC_NUL_RETVAL_BUG + { + wchar_t wc; + size_t ret = mbrtowc (&wc, s, n, ps); + + if (ret != (size_t)(-1) && ret != (size_t)(-2)) + { + if (pwc != NULL) + *pwc = wc; + if (wc == 0) + ret = 0; + } + return ret; + } +# else + return mbrtowc (pwc, s, n, ps); +# endif +} + +#endif diff --git a/lib/wchar.in.h b/lib/wchar.in.h index e4647331e3..62844af72b 100644 --- a/lib/wchar.in.h +++ b/lib/wchar.in.h @@ -74,10 +74,11 @@ extern "C" { /* Override mbstate_t if it is too small. On IRIX 6.5, sizeof (mbstate_t) == 1, which is not sufficient for implementing mbrtowc for encodings like UTF-8. */ -#if !(@HAVE_MBSINIT@ && @HAVE_MBRTOWC@) +#if !(@HAVE_MBSINIT@ && @HAVE_MBRTOWC@) || @REPLACE_MBSTATE_T@ typedef int rpl_mbstate_t; # undef mbstate_t # define mbstate_t rpl_mbstate_t +# define GNULIB_defined_mbstate_t 1 #endif @@ -116,7 +117,11 @@ extern int wctob (wint_t wc); /* Test whether *PS is in the initial state. */ #if @GNULIB_MBSINIT@ -# if !@HAVE_MBSINIT@ +# if @REPLACE_MBSINIT@ +# undef mbsinit +# define mbsinit rpl_mbsinit +# endif +# if !@HAVE_MBSINIT@ || @REPLACE_MBSINIT@ extern int mbsinit (const mbstate_t *ps); # endif #elif defined GNULIB_POSIXCHECK @@ -130,7 +135,11 @@ extern int mbsinit (const mbstate_t *ps); /* Convert a multibyte character to a wide character. */ #if @GNULIB_MBRTOWC@ -# if !@HAVE_MBRTOWC@ +# if @REPLACE_MBRTOWC@ +# undef mbrtowc +# define mbrtowc rpl_mbrtowc +# endif +# if !@HAVE_MBRTOWC@ || @REPLACE_MBRTOWC@ extern size_t mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps); # endif #elif defined GNULIB_POSIXCHECK |