1570af302Sopenharmony_ci#include <stdint.h> 2570af302Sopenharmony_ci#include <wchar.h> 3570af302Sopenharmony_ci#include <errno.h> 4570af302Sopenharmony_ci#include <string.h> 5570af302Sopenharmony_ci#include <stdlib.h> 6570af302Sopenharmony_ci#include "internal.h" 7570af302Sopenharmony_ci 8570af302Sopenharmony_cisize_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st) 9570af302Sopenharmony_ci{ 10570af302Sopenharmony_ci const unsigned char *s = (const void *)*src; 11570af302Sopenharmony_ci size_t wn0 = wn; 12570af302Sopenharmony_ci unsigned c = 0; 13570af302Sopenharmony_ci 14570af302Sopenharmony_ci if (st && (c = *(unsigned *)st)) { 15570af302Sopenharmony_ci if (ws) { 16570af302Sopenharmony_ci *(unsigned *)st = 0; 17570af302Sopenharmony_ci goto resume; 18570af302Sopenharmony_ci } else { 19570af302Sopenharmony_ci goto resume0; 20570af302Sopenharmony_ci } 21570af302Sopenharmony_ci } 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci if (MB_CUR_MAX==1) { 24570af302Sopenharmony_ci if (!ws) return strlen((const char *)s); 25570af302Sopenharmony_ci for (;;) { 26570af302Sopenharmony_ci if (!wn) { 27570af302Sopenharmony_ci *src = (const void *)s; 28570af302Sopenharmony_ci return wn0; 29570af302Sopenharmony_ci } 30570af302Sopenharmony_ci if (!*s) break; 31570af302Sopenharmony_ci c = *s++; 32570af302Sopenharmony_ci *ws++ = CODEUNIT(c); 33570af302Sopenharmony_ci wn--; 34570af302Sopenharmony_ci } 35570af302Sopenharmony_ci *ws = 0; 36570af302Sopenharmony_ci *src = 0; 37570af302Sopenharmony_ci return wn0-wn; 38570af302Sopenharmony_ci } 39570af302Sopenharmony_ci 40570af302Sopenharmony_ci if (!ws) for (;;) { 41570af302Sopenharmony_ci#ifdef __GNUC__ 42570af302Sopenharmony_ci typedef uint32_t __attribute__((__may_alias__)) w32; 43570af302Sopenharmony_ci if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { 44570af302Sopenharmony_ci while (!(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) { 45570af302Sopenharmony_ci s += 4; 46570af302Sopenharmony_ci wn -= 4; 47570af302Sopenharmony_ci } 48570af302Sopenharmony_ci } 49570af302Sopenharmony_ci#endif 50570af302Sopenharmony_ci if (*s-1u < 0x7f) { 51570af302Sopenharmony_ci s++; 52570af302Sopenharmony_ci wn--; 53570af302Sopenharmony_ci continue; 54570af302Sopenharmony_ci } 55570af302Sopenharmony_ci if (*s-SA > SB-SA) break; 56570af302Sopenharmony_ci c = bittab[*s++-SA]; 57570af302Sopenharmony_ciresume0: 58570af302Sopenharmony_ci if (OOB(c,*s)) { s--; break; } 59570af302Sopenharmony_ci s++; 60570af302Sopenharmony_ci if (c&(1U<<25)) { 61570af302Sopenharmony_ci if (*s-0x80u >= 0x40) { s-=2; break; } 62570af302Sopenharmony_ci s++; 63570af302Sopenharmony_ci if (c&(1U<<19)) { 64570af302Sopenharmony_ci if (*s-0x80u >= 0x40) { s-=3; break; } 65570af302Sopenharmony_ci s++; 66570af302Sopenharmony_ci } 67570af302Sopenharmony_ci } 68570af302Sopenharmony_ci wn--; 69570af302Sopenharmony_ci c = 0; 70570af302Sopenharmony_ci } else for (;;) { 71570af302Sopenharmony_ci if (!wn) { 72570af302Sopenharmony_ci *src = (const void *)s; 73570af302Sopenharmony_ci return wn0; 74570af302Sopenharmony_ci } 75570af302Sopenharmony_ci#ifdef __GNUC__ 76570af302Sopenharmony_ci typedef uint32_t __attribute__((__may_alias__)) w32; 77570af302Sopenharmony_ci if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { 78570af302Sopenharmony_ci while (wn>=5 && !(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) { 79570af302Sopenharmony_ci *ws++ = *s++; 80570af302Sopenharmony_ci *ws++ = *s++; 81570af302Sopenharmony_ci *ws++ = *s++; 82570af302Sopenharmony_ci *ws++ = *s++; 83570af302Sopenharmony_ci wn -= 4; 84570af302Sopenharmony_ci } 85570af302Sopenharmony_ci } 86570af302Sopenharmony_ci#endif 87570af302Sopenharmony_ci if (*s-1u < 0x7f) { 88570af302Sopenharmony_ci *ws++ = *s++; 89570af302Sopenharmony_ci wn--; 90570af302Sopenharmony_ci continue; 91570af302Sopenharmony_ci } 92570af302Sopenharmony_ci if (*s-SA > SB-SA) break; 93570af302Sopenharmony_ci c = bittab[*s++-SA]; 94570af302Sopenharmony_ciresume: 95570af302Sopenharmony_ci if (OOB(c,*s)) { s--; break; } 96570af302Sopenharmony_ci c = (c<<6) | *s++-0x80; 97570af302Sopenharmony_ci if (c&(1U<<31)) { 98570af302Sopenharmony_ci if (*s-0x80u >= 0x40) { s-=2; break; } 99570af302Sopenharmony_ci c = (c<<6) | *s++-0x80; 100570af302Sopenharmony_ci if (c&(1U<<31)) { 101570af302Sopenharmony_ci if (*s-0x80u >= 0x40) { s-=3; break; } 102570af302Sopenharmony_ci c = (c<<6) | *s++-0x80; 103570af302Sopenharmony_ci } 104570af302Sopenharmony_ci } 105570af302Sopenharmony_ci *ws++ = c; 106570af302Sopenharmony_ci wn--; 107570af302Sopenharmony_ci c = 0; 108570af302Sopenharmony_ci } 109570af302Sopenharmony_ci 110570af302Sopenharmony_ci if (!c && !*s) { 111570af302Sopenharmony_ci if (ws) { 112570af302Sopenharmony_ci *ws = 0; 113570af302Sopenharmony_ci *src = 0; 114570af302Sopenharmony_ci } 115570af302Sopenharmony_ci return wn0-wn; 116570af302Sopenharmony_ci } 117570af302Sopenharmony_ci errno = EILSEQ; 118570af302Sopenharmony_ci if (ws) *src = (const void *)s; 119570af302Sopenharmony_ci return -1; 120570af302Sopenharmony_ci} 121