mirror of https://github.com/flysand7/ciabatta.git
uchar.h
This commit is contained in:
parent
337e6734a7
commit
673a363d4b
136
src/code/uchar.c
136
src/code/uchar.c
|
@ -9,6 +9,7 @@ size_t mbrtoc16(
|
||||||
mbstate_t *restrict ps
|
mbstate_t *restrict ps
|
||||||
) {
|
) {
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
|
*ps = (mbstate_t) {0};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
@ -49,8 +50,8 @@ size_t mbrtoc16(
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cp -= 0x10000;
|
cp -= 0x10000;
|
||||||
parsed_char = 0xd800 | (cp & 0x3ff);
|
parsed_char = 0xd800 | (cp >> 10);
|
||||||
next_char = 0xdc00 | (cp >> 10);
|
next_char = 0xdc00 | (cp & 0x3ff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -73,17 +74,142 @@ size_t c16rtomb(
|
||||||
char *restrict s,
|
char *restrict s,
|
||||||
char16_t c16,
|
char16_t c16,
|
||||||
mbstate_t *restrict ps
|
mbstate_t *restrict ps
|
||||||
);
|
) {
|
||||||
|
if(*s == NULL) {
|
||||||
|
*ps = (mbstate_t) {0};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
unsigned cp;
|
||||||
|
// High surrogate (save)
|
||||||
|
if(0xd800 <= c16 && c16 < 0xdc00) {
|
||||||
|
ps->leftover = c16;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Low surrogate (parse)
|
||||||
|
else if(0xdc00 <= c16 && c16 < 0xe000) {
|
||||||
|
if(ps->leftover == 0) goto encoding_error;
|
||||||
|
cp = ((ps->leftover & 0x3ff) << 10) | (c16 & 0x3ff);
|
||||||
|
}
|
||||||
|
// Other char
|
||||||
|
else {
|
||||||
|
cp = c16;
|
||||||
|
}
|
||||||
|
size_t nbytes = 4;
|
||||||
|
if(cp < 0x10000) nbytes = 3;
|
||||||
|
if(cp < 0x800) nbytes = 2;
|
||||||
|
if(cp < 0x80) nbytes = 1;
|
||||||
|
switch(nbytes) {
|
||||||
|
case 1: {
|
||||||
|
s[0] = cp;
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
s[0] = 0xc0 | (cp >> 6);
|
||||||
|
s[1] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
s[0] = 0xe0 | (cp >> 12);
|
||||||
|
s[1] = 0x80 | ((cp >> 6) & 0x3f);
|
||||||
|
s[2] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
case 4: {
|
||||||
|
s[0] = 0xf0 | (cp >> 18);
|
||||||
|
s[1] = 0x80 | ((cp >> 12) & 0x3f);
|
||||||
|
s[2] = 0x80 | ((cp >> 6) & 0x3f);
|
||||||
|
s[3] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return nbytes;
|
||||||
|
encoding_error:
|
||||||
|
errno = EILSEQ;
|
||||||
|
return (size_t)(-1);
|
||||||
|
}
|
||||||
|
|
||||||
size_t mbrtoc32(
|
size_t mbrtoc32(
|
||||||
char32_t *restrict pc32,
|
char32_t *restrict pc32,
|
||||||
char const *restrict s,
|
char const *restrict s,
|
||||||
size_t n,
|
size_t n,
|
||||||
mbstate_t *restrict ps
|
mbstate_t *restrict ps
|
||||||
);
|
) {
|
||||||
|
if(s == NULL) {
|
||||||
|
*ps = (mbstate_t) {0};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t nbytes;
|
||||||
|
|
||||||
|
// Decode the first byte of UTF-8 sequence
|
||||||
|
unsigned byte0 = *s;
|
||||||
|
if (0x00 <= byte0 && byte0 < 0x80) nbytes = 1;
|
||||||
|
else if(0xc0 <= byte0 && byte0 < 0xe0) nbytes = 2;
|
||||||
|
else if(0xe0 <= byte0 && byte0 < 0xf0) nbytes = 3;
|
||||||
|
else if(0xf0 <= byte0 && byte0 < 0xf8) nbytes = 4;
|
||||||
|
else goto encoding_error;
|
||||||
|
unsigned nbytesreq = nbytes;
|
||||||
|
if(n < nbytesreq) {
|
||||||
|
return (size_t)(-2);
|
||||||
|
}
|
||||||
|
char32_t cp = byte0;
|
||||||
|
switch(nbytesreq) {
|
||||||
|
case 2: cp &= 0x1f; break;
|
||||||
|
case 3: cp &= 0x0f; break;
|
||||||
|
case 4: cp &= 0x07; break;
|
||||||
|
}
|
||||||
|
while(--nbytesreq)
|
||||||
|
cp |= (cp << 6) | ((*++s) & 0x3f);
|
||||||
|
if(0xdc00 <= cp && cp <= 0xe000)
|
||||||
|
goto encoding_error;
|
||||||
|
// Overloing seqs
|
||||||
|
if(cp < 0x80 && nbytes > 1) goto encoding_error;
|
||||||
|
if(cp < 0x800 && nbytes > 2) goto encoding_error;
|
||||||
|
if(cp < 0x10000 && nbytes > 3) goto encoding_error;
|
||||||
|
if(cp > 0x10ffff) goto encoding_error;
|
||||||
|
|
||||||
|
if(pc32 != NULL) *pc32 = cp;
|
||||||
|
if(cp == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return nbytes;
|
||||||
|
encoding_error:
|
||||||
|
errno = EILSEQ;
|
||||||
|
return (size_t)(-1);
|
||||||
|
}
|
||||||
|
|
||||||
size_t c32rtomb(
|
size_t c32rtomb(
|
||||||
char *restrict s,
|
char *restrict s,
|
||||||
char32_t c32,
|
char32_t c32,
|
||||||
mbstate_t *restrict ps
|
mbstate_t *restrict ps
|
||||||
);
|
) {
|
||||||
|
if(*s == NULL) {
|
||||||
|
*ps = (mbstate_t) {0};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
unsigned cp = c32;
|
||||||
|
if(cp >= 0x10ffff) goto encoding_error;
|
||||||
|
size_t nbytes = 4;
|
||||||
|
if(cp < 0x10000) nbytes = 3;
|
||||||
|
if(cp < 0x800) nbytes = 2;
|
||||||
|
if(cp < 0x80) nbytes = 1;
|
||||||
|
switch(nbytes) {
|
||||||
|
case 1: {
|
||||||
|
s[0] = cp;
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
s[0] = 0xc0 | (cp >> 6);
|
||||||
|
s[1] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
s[0] = 0xe0 | (cp >> 12);
|
||||||
|
s[1] = 0x80 | ((cp >> 6) & 0x3f);
|
||||||
|
s[2] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
case 4: {
|
||||||
|
s[0] = 0xf0 | (cp >> 18);
|
||||||
|
s[1] = 0x80 | ((cp >> 12) & 0x3f);
|
||||||
|
s[2] = 0x80 | ((cp >> 6) & 0x3f);
|
||||||
|
s[3] = 0x80 | ((cp >> 0) & 0x3f);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return nbytes;
|
||||||
|
encoding_error:
|
||||||
|
errno = EILSEQ;
|
||||||
|
return (size_t)(-1);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue