blob: 74bf5f23be4e57f3da6d4d762080fbe988c1aa43 [file] [log] [blame]
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "internal.h"
size_t mbsrtowcs(wchar_t* restrict ws, const char** restrict src, size_t wn,
mbstate_t* restrict st) {
const unsigned char* s = (const void*)*src;
size_t wn0 = wn;
unsigned c = 0;
if (st && (c = *(unsigned*)st)) {
if (ws) {
*(unsigned*)st = 0;
goto resume;
} else {
goto resume0;
}
}
if (MB_CUR_MAX == 1) {
if (!ws)
return strlen((const char*)s);
for (;;) {
if (!wn) {
*src = (const void*)s;
return wn0;
}
if (!*s)
break;
c = *s++;
*ws++ = CODEUNIT(c);
wn--;
}
*ws = 0;
*src = 0;
return wn0 - wn;
}
if (!ws)
for (;;) {
if (*s - 1u < 0x7f && (uintptr_t)s % 4 == 0) {
while (!((*(uint32_t*)s | (*(uint32_t*)s - 0x01010101)) & 0x80808080)) {
s += 4;
wn -= 4;
}
}
if (*s - 1u < 0x7f) {
s++;
wn--;
continue;
}
if (*s - SA > SB - SA)
break;
c = bittab[*s++ - SA];
resume0:
if (OOB(c, *s)) {
s--;
break;
}
s++;
if (c & (1U << 25)) {
if (*s - 0x80u >= 0x40) {
s -= 2;
break;
}
s++;
if (c & (1U << 19)) {
if (*s - 0x80u >= 0x40) {
s -= 3;
break;
}
s++;
}
}
wn--;
c = 0;
}
else
for (;;) {
if (!wn) {
*src = (const void*)s;
return wn0;
}
if (*s - 1u < 0x7f && (uintptr_t)s % 4 == 0) {
while (wn >= 5 && !((*(uint32_t*)s | (*(uint32_t*)s - 0x01010101)) & 0x80808080)) {
*ws++ = *s++;
*ws++ = *s++;
*ws++ = *s++;
*ws++ = *s++;
wn -= 4;
}
}
if (*s - 1u < 0x7f) {
*ws++ = *s++;
wn--;
continue;
}
if (*s - SA > SB - SA)
break;
c = bittab[*s++ - SA];
resume:
if (OOB(c, *s)) {
s--;
break;
}
c = (c << 6) | (*s++ - 0x80);
if (c & (1U << 31)) {
if (*s - 0x80u >= 0x40) {
s -= 2;
break;
}
c = (c << 6) | (*s++ - 0x80);
if (c & (1U << 31)) {
if (*s - 0x80u >= 0x40) {
s -= 3;
break;
}
c = (c << 6) | (*s++ - 0x80);
}
}
*ws++ = c;
wn--;
c = 0;
}
if (!c && !*s) {
if (ws) {
*ws = 0;
*src = 0;
}
return wn0 - wn;
}
errno = EILSEQ;
if (ws)
*src = (const void*)s;
return -1;
}