35e834ee6af711da7d6ab077d0674966d690bba7
[oweals/musl.git] / src / multibyte / mbrtowc.c
1 /* 
2  * This code was written by Rich Felker in 2010; no copyright is claimed.
3  * This code is in the public domain. Attribution is appreciated but
4  * unnecessary.
5  */
6
7 #include <wchar.h>
8 #include <errno.h>
9 #include "internal.h"
10
11 size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
12 {
13         static unsigned internal_state;
14         unsigned c;
15         const unsigned char *s = (const void *)src;
16         const unsigned N = n;
17
18         if (!st) st = (void *)&internal_state;
19         c = *(unsigned *)st;
20         
21         if (!s) {
22                 if (c) goto ilseq;
23                 return 0;
24         } else if (!wc) wc = (void *)&wc;
25
26         if (!n) return -2;
27         if (!c) {
28                 if (*s < 0x80) return !!(*wc = *s);
29                 if (*s-SA > SB-SA) goto ilseq;
30                 c = bittab[*s++-SA]; n--;
31         }
32
33         if (n) {
34                 if (OOB(c,*s)) goto ilseq;
35 loop:
36                 c = c<<6 | *s++-0x80; n--;
37                 if (!(c&(1U<<31))) {
38                         *(unsigned *)st = 0;
39                         *wc = c;
40                         return N-n;
41                 }
42                 if (n) {
43                         if (*s-0x80u >= 0x40) goto ilseq;
44                         goto loop;
45                 }
46         }
47
48         *(unsigned *)st = c;
49         return -2;
50 ilseq:
51         *(unsigned *)st = 0;
52         errno = EILSEQ;
53         return -1;
54 }