1041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner/* 2041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner * This code was written by Rich Felker in 2010; no copyright is claimed. 3041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner * This code is in the public domain. Attribution is appreciated but 4041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner * unnecessary. 5041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner */ 6041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 7041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner#include <wchar.h> 8041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner#include <errno.h> 9041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner#include "internal.h" 10041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 11041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turnersize_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st) 12041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner{ 13041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner static unsigned internal_state; 14041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner unsigned c; 15041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner const unsigned char *s = (const void *)src; 16041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner const unsigned N = n; 17041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 18041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (!st) st = (void *)&internal_state; 19041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner c = *(unsigned *)st; 20041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 21041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (!s) { 22041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (c) goto ilseq; 23041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner return 0; 24041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner } else if (!wc) wc = (void *)&wc; 25041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 26041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (!n) return -2; 27041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (!c) { 28041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (*s < 0x80) return !!(*wc = *s); 29041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (*s-SA > SB-SA) goto ilseq; 30041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner c = bittab[*s++-SA]; n--; 31041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner } 32041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 33041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (n) { 34041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (OOB(c,*s)) goto ilseq; 35041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turnerloop: 36041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner c = c<<6 | *s++-0x80; n--; 37041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (!(c&(1U<<31))) { 38041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner *(unsigned *)st = 0; 39041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner *wc = c; 40041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner return N-n; 41041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner } 42041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (n) { 43041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner if (*s-0x80u >= 0x40) goto ilseq; 44041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner goto loop; 45041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner } 46041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner } 47041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner 48041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner *(unsigned *)st = c; 49041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner return -2; 50041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turnerilseq: 51041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner *(unsigned *)st = 0; 52041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner errno = EILSEQ; 53041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner return -1; 54041656818eb2625982d4b55d176468a4bd07fb32David 'Digit' Turner} 55