| /** |
| * This file has no copyright assigned and is placed in the Public Domain. |
| * This file is part of the mingw-w64 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 <locale.h> |
| #include <wchar.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <windows.h> |
| |
| size_t mbrtowc ( |
| wchar_t *__restrict__ wc, |
| const char *__restrict__ mbs, |
| size_t count, |
| mbstate_t *__restrict__ state |
| ) { |
| /* Use private `mbstate_t` if caller did not supply one */ |
| if (state == NULL) { |
| static mbstate_t state_mbrtowc = {0}; |
| state = &state_mbrtowc; |
| } |
| |
| /* Set `state` to initial state */ |
| if (mbs == NULL) { |
| *state = 0; |
| return 0; |
| } |
| |
| /* Detect invalid conversion state */ |
| if ((unsigned) *state > 0xFF) { |
| goto einval; |
| } |
| |
| /* Both ISO C and POSIX do not mention this case */ |
| if (count == 0) { |
| return (size_t) -2; |
| } |
| |
| /* Code page used by current locale */ |
| unsigned cp = ___lc_codepage_func (); |
| |
| /* Maximum character length used by current locale */ |
| int mb_cur_max = ___mb_cur_max_func (); |
| |
| /* Treat `state` as an array of bytes */ |
| union { |
| mbstate_t state; |
| char bytes[4]; |
| } conversion_state = {.state = *state}; |
| |
| /* For SBCS code pages `state` must always be in initial state */ |
| if (mb_cur_max == 1 && conversion_state.bytes[0]) { |
| goto einval; |
| } |
| |
| /* Handle "C" locale */ |
| if (cp == 0) { |
| if (wc != NULL) { |
| *wc = (unsigned char) mbs[0]; |
| } |
| return !!mbs[0]; |
| } |
| |
| /* Length of potential multibyte character */ |
| int length = 1; |
| |
| if (conversion_state.bytes[0]) { |
| conversion_state.bytes[1] = mbs[0]; |
| length = 2; |
| } else if (mb_cur_max == 2 && isleadbyte (mbs[0])) { |
| conversion_state.bytes[0] = mbs[0]; |
| |
| /* We need to examine mbs[1] */ |
| if (count < 2) { |
| *state = conversion_state.state; |
| return (size_t) -2; |
| } |
| |
| conversion_state.bytes[1] = mbs[1]; |
| length = 2; |
| } else { |
| conversion_state.bytes[0] = mbs[0]; |
| } |
| |
| /* Store terminating '\0' */ |
| if (conversion_state.bytes[0] == '\0') { |
| if (wc != NULL) { |
| *wc = L'\0'; |
| *state = 0; |
| } |
| return 0; |
| } |
| |
| /* Truncated multibyte character */ |
| if (length == 2 && conversion_state.bytes[1] == '\0') { |
| goto eilseq; |
| } |
| |
| /* Converted wide character */ |
| wchar_t wcOut = WEOF; |
| |
| int ret = MultiByteToWideChar ( |
| cp, MB_ERR_INVALID_CHARS, conversion_state.bytes, length, &wcOut, 1 |
| ); |
| |
| if (ret != 1) { |
| goto eilseq; |
| } |
| |
| if (wc != NULL) { |
| *wc = wcOut; |
| *state = 0; |
| } |
| |
| return length; |
| |
| eilseq: |
| errno = EILSEQ; |
| return (size_t) -1; |
| |
| einval: |
| errno = EINVAL; |
| return (size_t) -1; |
| } |
| |
| size_t mbrlen ( |
| const char *__restrict__ mbs, |
| size_t count, |
| mbstate_t *__restrict__ state |
| ) { |
| /* Use private `mbstate_t` if caller did not supply one */ |
| if (state == NULL) { |
| static mbstate_t state_mbrlen = {0}; |
| state = &state_mbrlen; |
| } |
| wchar_t wc = WEOF; |
| return mbrtowc (&wc, mbs, count, state); |
| } |
| |
| size_t mbsrtowcs ( |
| wchar_t *wcs, |
| const char **__restrict__ mbs, |
| size_t count, |
| mbstate_t *__restrict__ state |
| ) { |
| /* Use private `mbstate_t` if caller did not supply one */ |
| if (state == NULL) { |
| static mbstate_t state_mbsrtowcs = {0}; |
| state = &state_mbsrtowcs; |
| } |
| |
| /* Treat `state` as array of bytes */ |
| union { |
| mbstate_t state; |
| char bytes[4]; |
| } conversion_state = {.state = *state}; |
| |
| /* Total number of wide character written to `wcs` */ |
| size_t wcConverted = 0; |
| /* Converted wide character */ |
| wchar_t wc = 0; |
| |
| /* Next multibyte character to convert */ |
| const char *mbc = *mbs; |
| |
| /* Maximum character length in `cp` */ |
| int mb_cur_max = ___mb_cur_max_func(); |
| |
| while (1) { |
| const size_t length = mbrtowc ( |
| &wc, mbc, mb_cur_max, &conversion_state.state |
| ); |
| |
| /* Conversion failed */ |
| if (length == (size_t) -1) { |
| if (wcs != NULL) { |
| *mbs = mbc; |
| *state = conversion_state.state; |
| } |
| return (size_t) -1; |
| } |
| |
| /* POSIX and ISO C are silent about this */ |
| if (wcs != NULL && count == 0) { |
| return 0; |
| } |
| |
| /* Store terminating L'\0' and stop */ |
| if (length == 0) { |
| if (wcs != NULL) { |
| *wcs = L'\0'; |
| *mbs = NULL; |
| } |
| break; |
| } |
| |
| /* Store converted `wc` in `wcs` */ |
| if (wcs != NULL) { |
| *wcs = wc; |
| wcs += 1; |
| } |
| |
| wcConverted += 1; |
| mbc += length; |
| |
| /* `count` wide characters have been stored in `wcs`, stop */ |
| if (wcs != NULL && wcConverted == count) { |
| *mbs = mbc; |
| break; |
| } |
| } |
| |
| if (wcs != NULL) { |
| *state = conversion_state.state; |
| } |
| |
| return wcConverted; |
| } |