mbrtowc.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
mbrtowc.c (1519B)
---
1 #include <errno.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <wchar.h>
5
6 #include "../libc.h"
7
8 #undef mbrtowc
9
10 size_t
11 mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n,
12 mbstate_t *restrict ps)
13 {
14 static mbstate_t state;
15 const unsigned char *t = (const unsigned char *) s;
16 wchar_t dummy;
17 unsigned long wc;
18 unsigned c, oc;
19 int sh, max;
20
21 if (!ps)
22 ps = &state;
23
24 if (t == NULL) {
25 if (ps->sh != 0)
26 goto return_error;
27 pwc = &dummy;
28 goto return_code_set;
29 }
30 if (n == 0)
31 return -2;
32
33 oc = ps->oc;
34 wc = ps->wc;
35 sh = ps->sh;
36
37 /* initial state? */
38 if (sh == 0) {
39 /* NUL character? */
40 if ((c = wc = *t) == 0)
41 goto return_code;
42 t++;
43 n--;
44
45 /* fast track for ascii? */
46 if (c < 0x80)
47 goto return_code;
48
49 /* out of sequence multibyte? */
50 if ((c & 0xc0) != 0xc0)
51 goto return_error;
52
53 /* in sequence multibyte! */
54 oc = c << 1;
55 wc = 0;
56 sh = 1;
57 }
58
59 for ( ; n > 0; --n) {
60 if (sh > MB_CUR_MAX)
61 goto return_error;
62
63 c = *t++;
64 if ((c & 0xc0) != 0x80)
65 goto return_error;
66
67 wc <<= 6;
68 wc |= c & 0x3f;
69 oc <<= 1;
70 sh++;
71
72 if ((oc & 0x80) == 0) {
73 oc = (oc & 0xff) >> sh;
74 wc |= oc << (sh-1) * 6;
75
76 if (!_validutf8(wc, &max) || sh != max)
77 goto return_error;
78 goto return_code_set;
79 }
80 }
81
82 ps->sh = sh;
83 ps->oc = oc;
84 ps->wc = wc;
85 return -2;
86
87 return_code_set:
88 memset(ps, 0, sizeof(*ps));
89 return_code:
90 if (pwc)
91 *pwc = wc;
92 return t - (unsigned char *) s;
93
94 return_error:
95 memset(ps, 0, sizeof(*ps));
96 errno = EILSEQ;
97 return -1;
98 }