fix undefined left-shift of negative values in utf-8 state table
[musl] / 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 <stdlib.h>
8 #include <wchar.h>
9 #include <errno.h>
10 #include "internal.h"
11
12 size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
13 {
14         static unsigned internal_state;
15         unsigned c;
16         const unsigned char *s = (const void *)src;
17         const unsigned N = n;
18         wchar_t dummy;
19
20         if (!st) st = (void *)&internal_state;
21         c = *(unsigned *)st;
22         
23         if (!s) {
24                 if (c) goto ilseq;
25                 return 0;
26         } else if (!wc) wc = &dummy;
27
28         if (!n) return -2;
29         if (!c) {
30                 if (*s < 0x80) return !!(*wc = *s);
31                 if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1;
32                 if (*s-SA > SB-SA) goto ilseq;
33                 c = bittab[*s++-SA]; n--;
34         }
35
36         if (n) {
37                 if (OOB(c,*s)) goto ilseq;
38 loop:
39                 c = c<<6 | *s++-0x80; n--;
40                 if (!(c&(1U<<31))) {
41                         *(unsigned *)st = 0;
42                         *wc = c;
43                         return N-n;
44                 }
45                 if (n) {
46                         if (*s-0x80u >= 0x40) goto ilseq;
47                         goto loop;
48                 }
49         }
50
51         *(unsigned *)st = c;
52         return -2;
53 ilseq:
54         *(unsigned *)st = 0;
55         errno = EILSEQ;
56         return -1;
57 }