| #include "internal.h" |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <wchar.h> |
| |
| int mbtowc(wchar_t* restrict wc, const char* restrict src, size_t n) { |
| unsigned c; |
| const unsigned char* s = (const void*)src; |
| wchar_t dummy; |
| |
| if (!s) |
| return 0; |
| if (!n) |
| goto ilseq; |
| if (!wc) |
| wc = &dummy; |
| |
| if (*s < 0x80) |
| return !!(*wc = *s); |
| if (MB_CUR_MAX == 1) |
| return (*wc = CODEUNIT(*s)), 1; |
| if (*s - SA > SB - SA) |
| goto ilseq; |
| c = bittab[*s++ - SA]; |
| |
| /* Avoid excessive checks against n: If shifting the state n-1 |
| * times does not clear the high bit, then the value of n is |
| * insufficient to read a character */ |
| if (n < 4 && ((c << (6 * n - 6)) & (1U << 31))) |
| goto ilseq; |
| |
| if (OOB(c, *s)) |
| goto ilseq; |
| c = c << 6 | (*s++ - 0x80); |
| if (!(c & (1U << 31))) { |
| *wc = c; |
| return 2; |
| } |
| |
| if (*s - 0x80u >= 0x40) |
| goto ilseq; |
| c = c << 6 | (*s++ - 0x80); |
| if (!(c & (1U << 31))) { |
| *wc = c; |
| return 3; |
| } |
| |
| if (*s - 0x80u >= 0x40) |
| goto ilseq; |
| *wc = c << 6 | (*s++ - 0x80); |
| return 4; |
| |
| ilseq: |
| errno = EILSEQ; |
| return -1; |
| } |