X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fmbrtowc.c;h=0fec5f1c9fac3c67af2fde58774c55b44bd97dcf;hb=825d4b05a9f432fa39078a91b24d05da759a5ad6;hp=e5ae0bcc357dcfa6d8afd93265455184a958e7e1;hpb=97020df1c106f5f06f2e06ca4d27c7c7dd878087;p=gnulib.git diff --git a/lib/mbrtowc.c b/lib/mbrtowc.c index e5ae0bcc3..0fec5f1c9 100644 --- a/lib/mbrtowc.c +++ b/lib/mbrtowc.c @@ -1,5 +1,5 @@ /* Convert multibyte character to wide character. - Copyright (C) 1999-2002, 2005-2008 Free Software Foundation, Inc. + Copyright (C) 1999-2002, 2005-2009 Free Software Foundation, Inc. Written by Bruno Haible , 2008. This program is free software: you can redistribute it and/or modify @@ -20,12 +20,15 @@ /* Specification. */ #include -#include -#include +#if GNULIB_defined_mbstate_t +/* Implement mbrtowc() on top of mbtowc(). */ -#include "localcharset.h" -#include "streq.h" -#include "verify.h" +# include +# include + +# include "localcharset.h" +# include "streq.h" +# include "verify.h" verify (sizeof (mbstate_t) >= 4); @@ -86,12 +89,12 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) return (size_t)(-1); } - /* Here 0 < m ≤ 4. */ + /* Here m > 0. */ -#if __GLIBC__ +# if __GLIBC__ /* Work around bug */ mbtowc (NULL, NULL, 0); -#endif +# endif { int res = mbtowc (pwc, p, m); @@ -115,7 +118,7 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) lack mbrtowc(), we use the second approach. The possible encodings are: - 8-bit encodings, - - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, SJIS, + - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, GB18030, SJIS, - UTF-8. Use specialized code for each. */ if (m >= 4 || m >= MB_CUR_MAX) @@ -235,6 +238,39 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) } goto invalid; } + if (STREQ (encoding, "GB18030", 'G', 'B', '1', '8', '0', '3', '0', 0, 0)) + { + if (m == 1) + { + unsigned char c = (unsigned char) p[0]; + + if ((c >= 0x90 && c <= 0xe3) || (c >= 0xf8 && c <= 0xfe)) + goto incomplete; + } + else /* m == 2 || m == 3 */ + { + unsigned char c = (unsigned char) p[0]; + + if (c >= 0x90 && c <= 0xe3) + { + unsigned char c2 = (unsigned char) p[1]; + + if (c2 >= 0x30 && c2 <= 0x39) + { + if (m == 2) + goto incomplete; + else /* m == 3 */ + { + unsigned char c3 = (unsigned char) p[2]; + + if (c3 >= 0x81 && c3 <= 0xfe) + goto incomplete; + } + } + } + } + goto invalid; + } if (STREQ (encoding, "SJIS", 'S', 'J', 'I', 'S', 0, 0, 0, 0, 0)) { if (m == 1) @@ -255,10 +291,14 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) incomplete: { size_t k = nstate; - /* Here 0 < k < m < 4. */ + /* Here 0 <= k < m < 4. */ pstate[++k] = s[0]; if (k < m) - pstate[++k] = s[1]; + { + pstate[++k] = s[1]; + if (k < m) + pstate[++k] = s[2]; + } if (k != m) abort (); } @@ -272,3 +312,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