| #include <stdlib.h> |
| #include <wchar.h> |
| #include <errno.h> |
| #include "internal.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; |
| } |