• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <inttypes.h>
9 #include <wchar.h>
10 #include <errno.h>
11 
12 #include "internal.h"
13 
mbsrtowcs(wchar_t * restrict ws,const char ** restrict src,size_t wn,mbstate_t * restrict st)14 size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
15 {
16 	const unsigned char *s = (const void *)*src;
17 	size_t wn0 = wn;
18 	unsigned c = 0;
19 
20 	if (st && (c = *(unsigned *)st)) {
21 		if (ws) {
22 			*(unsigned *)st = 0;
23 			goto resume;
24 		} else {
25 			goto resume0;
26 		}
27 	}
28 
29 	if (!ws) for (;;) {
30 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
31 			while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
32 				s += 4;
33 				wn -= 4;
34 			}
35 		}
36 		if (*s-1u < 0x7f) {
37 			s++;
38 			wn--;
39 			continue;
40 		}
41 		if (*s-SA > SB-SA) break;
42 		c = bittab[*s++-SA];
43 resume0:
44 		if (OOB(c,*s)) { s--; break; }
45 		s++;
46 		if (c&(1U<<25)) {
47 			if (*s-0x80u >= 0x40) { s-=2; break; }
48 			s++;
49 			if (c&(1U<<19)) {
50 				if (*s-0x80u >= 0x40) { s-=3; break; }
51 				s++;
52 			}
53 		}
54 		wn--;
55 		c = 0;
56 	} else for (;;) {
57 		if (!wn) return wn0;
58 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
59 			while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
60 				*ws++ = *s++;
61 				*ws++ = *s++;
62 				*ws++ = *s++;
63 				*ws++ = *s++;
64 				wn -= 4;
65 			}
66 		}
67 		if (*s-1u < 0x7f) {
68 			*ws++ = *s++;
69 			wn--;
70 			continue;
71 		}
72 		if (*s-SA > SB-SA) break;
73 		c = bittab[*s++-SA];
74 resume:
75 		if (OOB(c,*s)) { s--; break; }
76 		c = (c<<6) | *s++-0x80;
77 		if (c&(1U<<31)) {
78 			if (*s-0x80u >= 0x40) { s-=2; break; }
79 			c = (c<<6) | *s++-0x80;
80 			if (c&(1U<<31)) {
81 				if (*s-0x80u >= 0x40) { s-=3; break; }
82 				c = (c<<6) | *s++-0x80;
83 			}
84 		}
85 		*ws++ = c;
86 		wn--;
87 		c = 0;
88 	}
89 
90 	if (!c && !*s) {
91 		if (ws) {
92 			*ws = 0;
93 			*src = 0;
94 		}
95 		return wn0-wn;
96 	}
97 	errno = EILSEQ;
98 	if (ws) *src = (const void *)s;
99 	return -1;
100 }
101