| /** |
| * This file has no copyright assigned and is placed in the Public Domain. |
| * This file is part of the w64 mingw-runtime package. |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. |
| */ |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif |
| #include "mb_wc_common.h" |
| #include <wchar.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <windows.h> |
| |
| static int __MINGW_ATTRIB_NONNULL(1) __MINGW_ATTRIB_NONNULL(4) |
| __mbrtowc_cp (wchar_t * __restrict__ pwc, const char * __restrict__ s, |
| size_t n, mbstate_t* __restrict__ ps, |
| const unsigned int cp, const unsigned int mb_max) |
| { |
| union { |
| mbstate_t val; |
| char mbcs[4]; |
| } shift_state; |
| |
| /* Do the prelim checks */ |
| if (s == NULL) |
| return 0; |
| |
| if (n == 0) |
| /* The standard doesn't mention this case explicitly. Tell |
| caller that the conversion from a non-null s is incomplete. */ |
| return -2; |
| |
| /* Save the current shift state, in case we need it in DBCS case. */ |
| shift_state.val = *ps; |
| *ps = 0; |
| |
| if (!*s) |
| { |
| *pwc = 0; |
| return 0; |
| } |
| |
| if (mb_max > 1) |
| { |
| if (shift_state.mbcs[0] != 0) |
| { |
| /* Complete the mb char with the trailing byte. */ |
| shift_state.mbcs[1] = *s; /* the second byte */ |
| if (MultiByteToWideChar(cp, MB_ERR_INVALID_CHARS, |
| shift_state.mbcs, 2, pwc, 1) |
| == 0) |
| { |
| /* An invalid trailing byte */ |
| errno = EILSEQ; |
| return -1; |
| } |
| return 2; |
| } |
| else if (IsDBCSLeadByteEx (cp, *s)) |
| { |
| /* If told to translate one byte, just save the leadbyte |
| in *ps. */ |
| if (n < 2) |
| { |
| ((char*) ps)[0] = *s; |
| return -2; |
| } |
| /* Else translate the first two bytes */ |
| else if (MultiByteToWideChar (cp, MB_ERR_INVALID_CHARS, |
| s, 2, pwc, 1) |
| == 0) |
| { |
| errno = EILSEQ; |
| return -1; |
| } |
| return 2; |
| } |
| } |
| |
| /* Fall through to single byte char */ |
| if (cp == 0) |
| *pwc = (wchar_t)(unsigned char)*s; |
| |
| else if (MultiByteToWideChar (cp, MB_ERR_INVALID_CHARS, s, 1, pwc, 1) |
| == 0) |
| { |
| errno = EILSEQ; |
| return -1; |
| } |
| |
| return 1; |
| } |
| |
| size_t |
| mbrtowc (wchar_t * __restrict__ pwc, const char * __restrict__ s, |
| size_t n, mbstate_t* __restrict__ ps) |
| { |
| static mbstate_t internal_mbstate = 0; |
| wchar_t byte_bucket = 0; |
| wchar_t* dst = pwc ? pwc : &byte_bucket; |
| |
| return (size_t) __mbrtowc_cp (dst, s, n, ps ? ps : &internal_mbstate, |
| __mingw_get_codepage(), MB_CUR_MAX); |
| } |
| |
| |
| size_t |
| mbsrtowcs (wchar_t* __restrict__ dst, const char ** __restrict__ src, |
| size_t len, mbstate_t* __restrict__ ps) |
| { |
| int ret =0 ; |
| size_t n = 0; |
| static mbstate_t internal_mbstate = 0; |
| mbstate_t* internal_ps = ps ? ps : &internal_mbstate; |
| const unsigned int cp = __mingw_get_codepage(); |
| const unsigned int mb_max = MB_CUR_MAX; |
| |
| if (src == NULL || *src == NULL) /* undefined behavior */ |
| return 0; |
| |
| if (dst != NULL) |
| { |
| while (n < len |
| && (ret = __mbrtowc_cp(dst, *src, len - n, |
| internal_ps, cp, mb_max)) |
| > 0) |
| { |
| ++dst; |
| *src += ret; |
| n += ret; |
| } |
| |
| if (n < len && ret == 0) |
| *src = (char *)NULL; |
| } |
| else |
| { |
| wchar_t byte_bucket = 0; |
| while (n < len |
| && (ret = __mbrtowc_cp (&byte_bucket, *src, mb_max, |
| internal_ps, cp, mb_max)) |
| > 0) |
| { |
| *src += ret; |
| n += ret; |
| } |
| } |
| return n; |
| } |
| |
| size_t |
| mbrlen (const char * __restrict__ s, size_t n, |
| mbstate_t * __restrict__ ps) |
| { |
| static mbstate_t s_mbstate = 0; |
| wchar_t byte_bucket = 0; |
| return __mbrtowc_cp (&byte_bucket, s, n, (ps) ? ps : &s_mbstate, |
| __mingw_get_codepage(), MB_CUR_MAX); |
| } |