103 lines
1.6 KiB
C++
103 lines
1.6 KiB
C++
#include <BAN/UTF8.h>
|
|
|
|
#include <errno.h>
|
|
#include <wchar.h>
|
|
|
|
struct FILEScopeLock
|
|
{
|
|
FILEScopeLock(FILE* stream)
|
|
: m_stream(stream)
|
|
{
|
|
flockfile(m_stream);
|
|
}
|
|
~FILEScopeLock()
|
|
{
|
|
funlockfile(m_stream);
|
|
}
|
|
FILE* m_stream;
|
|
};
|
|
|
|
wint_t getwc(FILE* stream)
|
|
{
|
|
return fgetwc(stream);
|
|
}
|
|
|
|
wint_t fgetwc(FILE* stream)
|
|
{
|
|
FILEScopeLock _(stream);
|
|
|
|
char buffer[4];
|
|
|
|
buffer[0] = getc_unlocked(stream);
|
|
if (buffer[0] == EOF)
|
|
return WEOF;
|
|
|
|
const auto length = BAN::UTF8::byte_length(buffer[0]);
|
|
if (length == BAN::UTF8::invalid)
|
|
{
|
|
errno = EILSEQ;
|
|
return WEOF;
|
|
}
|
|
|
|
for (uint32_t i = 1; i < length; i++)
|
|
if ((buffer[i] = getc_unlocked(stream)) == EOF)
|
|
return WEOF;
|
|
|
|
const auto ret = BAN::UTF8::to_codepoint(buffer);
|
|
if (ret == BAN::UTF8::invalid)
|
|
{
|
|
errno = EILSEQ;
|
|
return WEOF;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
wint_t putwc(wchar_t wc, FILE* stream)
|
|
{
|
|
return fputwc(wc, stream);
|
|
}
|
|
|
|
wint_t fputwc(wchar_t wc, FILE* stream)
|
|
{
|
|
char buffer[4];
|
|
if (!BAN::UTF8::from_codepoints(&wc, 1, buffer))
|
|
{
|
|
errno = EILSEQ;
|
|
return WEOF;
|
|
}
|
|
|
|
FILEScopeLock _(stream);
|
|
|
|
const auto bytes = BAN::UTF8::byte_length(buffer[0]);
|
|
for (uint32_t i = 0; i < bytes; i++)
|
|
if (putc_unlocked(buffer[i], stream) == EOF)
|
|
return WEOF;
|
|
|
|
return wc;
|
|
}
|
|
|
|
wint_t ungetwc(wint_t wc, FILE* stream)
|
|
{
|
|
char buffer[4];
|
|
if (!BAN::UTF8::from_codepoints(&wc, 1, buffer))
|
|
{
|
|
errno = EILSEQ;
|
|
return WEOF;
|
|
}
|
|
|
|
FILEScopeLock _(stream);
|
|
|
|
const auto bytes = BAN::UTF8::byte_length(buffer[0]);
|
|
for (uint32_t i = 0; i < bytes; i++)
|
|
{
|
|
if (ungetc(buffer[i], stream) != EOF)
|
|
continue;
|
|
for (uint32_t j = 0; j < i; j++)
|
|
fgetc(stream);
|
|
return WEOF;
|
|
}
|
|
|
|
return wc;
|
|
}
|