mlibc/options/ansi/generic/wchar-stubs.cpp
2019-05-08 07:01:52 +02:00

168 lines
4.4 KiB
C++

#include <errno.h>
#include <stdio.h>
#include <wchar.h>
#include <bits/ensure.h>
#include <mlibc/charcode.hpp>
#include <mlibc/debug.hpp>
namespace {
// All conversion functions mbrlen(), mbrtowc(), wcrtomb(),
// mbsrtowcs() and wcsrtombs() have an internal state.
__mlibc_mbstate mbrlen_state = __MLIBC_MBSTATE_INITIALIZER;
__mlibc_mbstate mbrtowc_state = __MLIBC_MBSTATE_INITIALIZER;
__mlibc_mbstate mbsrtowcs_state = __MLIBC_MBSTATE_INITIALIZER;
}
wint_t btowc(int c) {
if(c == EOF)
return WEOF;
char nc = c;
auto cc = mlibc::current_charcode();
wchar_t wc;
if(auto e = cc->promote_wtranscode(nc, wc); e != mlibc::charcode_error::null)
return WEOF;
return wc;
}
int wctob(wint_t wc) {
// TODO: Revisit this once we have character encoding functions.
return wc;
}
int mbsinit(const mbstate_t *stp) {
if(!stp)
return -1;
return !stp->__progress && !stp->__shift;
}
size_t mbrlen(const char *mbs, size_t mb_limit, mbstate_t *stp) {
auto cc = mlibc::current_charcode();
wchar_t wc;
if(!stp)
stp = &mbrlen_state;
if(!mbs) {
*stp = __MLIBC_MBSTATE_INITIALIZER;
return 0;
}
mlibc::code_seq<const char> nseq{mbs, mbs + mb_limit};
mlibc::code_seq<wchar_t> wseq{&wc, &wc + 1};
if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null)
__ensure(!"decode_wtranscode() errors are not handled");
return nseq.it - mbs;
}
size_t mbrtowc(wchar_t *wcp, const char *mbs, size_t mb_limit, mbstate_t *stp) {
auto cc = mlibc::current_charcode();
if(!stp)
stp = &mbrtowc_state;
if(!mbs) {
*stp = __MLIBC_MBSTATE_INITIALIZER;
return 0;
}
// TODO: Decode to a local wchar_t.
__ensure(wcp);
mlibc::code_seq<const char> nseq{mbs, mbs + mb_limit};
mlibc::code_seq<wchar_t> wseq{wcp, wcp + 1};
if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) {
if(e == mlibc::charcode_error::input_underflow)
return static_cast<size_t>(-2);
__ensure(e == mlibc::charcode_error::illegal_input);
errno = EILSEQ;
return static_cast<size_t>(-1);
}else{
size_t n = wseq.it - wcp;
if(!n) // Null-terminate resulting wide string.
*wcp = 0;
return n;
}
}
size_t wcrtomb(char *mbs, wchar_t wc, mbstate_t *stp) {
auto cc = mlibc::current_charcode();
// wcrtomb() always takes a mbstate_t.
__ensure(stp);
// TODO: Implement the following case:
__ensure(mbs);
mlibc::code_seq<const wchar_t> wseq{&wc, &wc + 1};
mlibc::code_seq<char> nseq{mbs, mbs + 4}; // TODO: Replace 4 by some named constant.
if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) {
__ensure(!"encode_wtranscode() errors are not handled");
__builtin_unreachable();
}else{
size_t n = nseq.it - mbs;
if(!n) // Null-terminate resulting wide string.
*mbs = 0;
return n;
}
}
size_t mbsrtowcs(wchar_t *wcs, const char **mbsp, size_t wc_limit, mbstate_t *stp) {
__ensure(mbsp);
auto cc = mlibc::current_charcode();
__mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER;
mlibc::code_seq<const char> nseq{*mbsp, nullptr};
mlibc::code_seq<wchar_t> wseq{wcs, wcs + wc_limit};
if(!stp)
stp = &mbsrtowcs_state;
if(!wcs) {
size_t size;
if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null)
__ensure(!"decode_wtranscode() errors are not handled");
return size;
}
if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) {
__ensure(!"decode_wtranscode() errors are not handled");
__builtin_unreachable();
}else{
size_t n = wseq.it - wcs;
if(n < wc_limit) // Null-terminate resulting wide string.
wcs[n] = 0;
*mbsp = nullptr;
return n;
}
}
size_t wcsrtombs(char *mbs, const wchar_t **wcsp, size_t mb_limit, mbstate_t *stp) {
__ensure(wcsp && "wcsrtombs() with null input");
auto cc = mlibc::current_charcode();
mlibc::code_seq<char> nseq{mbs, mbs + mb_limit};
mlibc::code_seq<const wchar_t> wseq{*wcsp, nullptr};
__ensure(mbs && "Handle !mbs case as in mbstowcs()");
if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) {
__ensure(!"encode_wtranscode() errors are not handled");
__builtin_unreachable();
}else{
*wcsp = wseq.it;
size_t n = nseq.it - mbs;
if(n < mb_limit) // Null-terminate resulting narrow string.
mbs[n] = 0;
return n;
}
}
int wcwidth(wchar_t) {
static bool warned = false;
if(!warned)
mlibc::infoLogger() << "\e[35mmlibc: wcwidth() always returns 1\e[39m" << frg::endlog;
warned = true;
return 1;
}