/* * Copyright (c) 2021, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include static_assert(AssertSize()); extern "C" { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwide.html int fwide(FILE*, int mode) { // Nope Nope Nope. return mode; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fgetwc.html wint_t fgetwc(FILE* stream) { VERIFY(stream); Array underlying; auto underlying_bytes = underlying.span(); size_t encoded_length = 0; size_t bytes_read = 0; do { size_t nread = fread(underlying_bytes.offset_pointer(bytes_read), 1, 1, stream); if (nread != 1) { errno = EILSEQ; return WEOF; } ++bytes_read; if (bytes_read == 1) { if (underlying[0] >> 7 == 0) { encoded_length = 1; } else if (underlying[0] >> 5 == 6) { encoded_length = 2; } else if (underlying[0] >> 4 == 0xe) { encoded_length = 3; } else if (underlying[0] >> 3 == 0x1e) { encoded_length = 4; } else { errno = EILSEQ; return WEOF; } } } while (bytes_read < encoded_length); wchar_t code_point; auto read_bytes = mbrtowc(&code_point, bit_cast(underlying.data()), encoded_length, nullptr); VERIFY(read_bytes == encoded_length); return code_point; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/getwc.html wint_t getwc(FILE* stream) { return fgetwc(stream); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/getwchar.html wint_t getwchar() { return getwc(stdin); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fputwc.html wint_t fputwc(wchar_t wc, FILE* stream) { VERIFY(stream); // Negative wide chars are weird if constexpr (IsSigned) { if (wc < 0) { errno = EILSEQ; return WEOF; } } StringBuilder sb; sb.append_code_point(static_cast(wc)); auto bytes = sb.string_view().bytes(); ScopedFileLock lock(stream); size_t nwritten = stream->write(bytes.data(), bytes.size()); if (nwritten < bytes.size()) return WEOF; return wc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/putwc.html wint_t putwc(wchar_t wc, FILE* stream) { return fputwc(wc, stream); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/putwchar.html wint_t putwchar(wchar_t wc) { return fputwc(wc, stdout); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fgetws.html wchar_t* fgetws(wchar_t* __restrict buffer, int size, FILE* __restrict stream) { VERIFY(stream); ScopedFileLock lock(stream); bool ok = stream->gets(bit_cast(buffer), size); return ok ? buffer : nullptr; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fputws.html int fputws(wchar_t const* __restrict ws, FILE* __restrict stream) { VERIFY(stream); ScopedFileLock lock(stream); int size = 0; for (auto const* p = ws; *p != 0; ++p, ++size) { if (putwc(*p, stream) == WEOF) return WEOF; } return size; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ungetwc.html wint_t ungetwc(wint_t wc, FILE* stream) { VERIFY(stream); ScopedFileLock lock(stream); StringBuilder sb; sb.append_code_point(static_cast(wc)); auto bytes = sb.string_view().bytes(); size_t ok_bytes = 0; for (auto byte : bytes) { if (!stream->ungetc(byte)) { // Discard the half-ungotten bytes. stream->read(const_cast(bytes.data()), ok_bytes); return WEOF; } ++ok_bytes; } return wc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wprintf.html int wprintf(wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vfwprintf(stdout, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwprintf.html int fwprintf(FILE* __restrict stream, wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vfwprintf(stream, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/swprintf.html int swprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vswprintf(wcs, max_length, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vwprintf.html int vwprintf(wchar_t const* __restrict format, va_list args) { return vfwprintf(stdout, format, args); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vfwprintf.html int vfwprintf(FILE* __restrict stream, wchar_t const* __restrict format, va_list args) { auto const* fmt = bit_cast(format); return printf_internal([stream](wchar_t*&, wchar_t wc) { putwc(wc, stream); }, nullptr, fmt, args); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vswprintf.html int vswprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, va_list args) { auto const* fmt = bit_cast(format); size_t length_so_far = 0; printf_internal([max_length, &length_so_far](wchar_t*& buffer, wchar_t wc) { if (length_so_far > max_length) return; *buffer++ = wc; ++length_so_far; }, wcs, fmt, args); return static_cast(length_so_far); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwscanf.html int fwscanf(FILE* __restrict stream, wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vfwscanf(stream, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/swscanf.html int swscanf(wchar_t const* __restrict ws, wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vswscanf(ws, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wscanf.html int wscanf(wchar_t const* __restrict format, ...) { va_list ap; va_start(ap, format); auto rc = vfwscanf(stdout, format, ap); va_end(ap); return rc; } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vfwscanf.html int vfwscanf(FILE* __restrict stream, wchar_t const* __restrict format, va_list arg) { (void)stream; (void)format; (void)arg; dbgln("FIXME: Implement vfwscanf()"); TODO(); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vswscanf.html int vswscanf(wchar_t const* __restrict ws, wchar_t const* __restrict format, va_list arg) { (void)ws; (void)format; (void)arg; dbgln("FIXME: Implement vswscanf()"); TODO(); } // https://pubs.opengroup.org/onlinepubs/9699919799/functions/vwscanf.html int vwscanf(wchar_t const* __restrict format, va_list arg) { (void)format; (void)arg; dbgln("FIXME: Implement vwscanf()"); TODO(); } }