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 }