Serenity Operating System
at master 275 lines 7.7 kB view raw
1/* 2 * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Assertions.h> 8#include <AK/BitCast.h> 9#include <AK/PrintfImplementation.h> 10#include <AK/StringBuilder.h> 11#include <AK/Types.h> 12#include <bits/stdio_file_implementation.h> 13#include <errno.h> 14#include <stdio.h> 15#include <wchar.h> 16 17static_assert(AssertSize<wchar_t, sizeof(u32)>()); 18 19extern "C" { 20 21// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwide.html 22int fwide(FILE*, int mode) 23{ 24 // Nope Nope Nope. 25 return mode; 26} 27 28// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fgetwc.html 29wint_t fgetwc(FILE* stream) 30{ 31 VERIFY(stream); 32 Array<u8, 4> underlying; 33 auto underlying_bytes = underlying.span(); 34 size_t encoded_length = 0; 35 size_t bytes_read = 0; 36 do { 37 size_t nread = fread(underlying_bytes.offset_pointer(bytes_read), 1, 1, stream); 38 if (nread != 1) { 39 errno = EILSEQ; 40 return WEOF; 41 } 42 ++bytes_read; 43 if (bytes_read == 1) { 44 if (underlying[0] >> 7 == 0) { 45 encoded_length = 1; 46 } else if (underlying[0] >> 5 == 6) { 47 encoded_length = 2; 48 } else if (underlying[0] >> 4 == 0xe) { 49 encoded_length = 3; 50 } else if (underlying[0] >> 3 == 0x1e) { 51 encoded_length = 4; 52 } else { 53 errno = EILSEQ; 54 return WEOF; 55 } 56 } 57 } while (bytes_read < encoded_length); 58 59 wchar_t code_point; 60 auto read_bytes = mbrtowc(&code_point, bit_cast<char const*>(underlying.data()), encoded_length, nullptr); 61 VERIFY(read_bytes == encoded_length); 62 return code_point; 63} 64 65// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getwc.html 66wint_t getwc(FILE* stream) 67{ 68 return fgetwc(stream); 69} 70 71// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getwchar.html 72wint_t getwchar() 73{ 74 return getwc(stdin); 75} 76 77// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fputwc.html 78wint_t fputwc(wchar_t wc, FILE* stream) 79{ 80 VERIFY(stream); 81 // Negative wide chars are weird 82 if constexpr (IsSigned<wchar_t>) { 83 if (wc < 0) { 84 errno = EILSEQ; 85 return WEOF; 86 } 87 } 88 StringBuilder sb; 89 sb.append_code_point(static_cast<u32>(wc)); 90 auto bytes = sb.string_view().bytes(); 91 ScopedFileLock lock(stream); 92 size_t nwritten = stream->write(bytes.data(), bytes.size()); 93 if (nwritten < bytes.size()) 94 return WEOF; 95 return wc; 96} 97 98// https://pubs.opengroup.org/onlinepubs/9699919799/functions/putwc.html 99wint_t putwc(wchar_t wc, FILE* stream) 100{ 101 return fputwc(wc, stream); 102} 103 104// https://pubs.opengroup.org/onlinepubs/9699919799/functions/putwchar.html 105wint_t putwchar(wchar_t wc) 106{ 107 return fputwc(wc, stdout); 108} 109 110// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fgetws.html 111wchar_t* fgetws(wchar_t* __restrict buffer, int size, FILE* __restrict stream) 112{ 113 VERIFY(stream); 114 ScopedFileLock lock(stream); 115 bool ok = stream->gets(bit_cast<u32*>(buffer), size); 116 return ok ? buffer : nullptr; 117} 118 119// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fputws.html 120int fputws(wchar_t const* __restrict ws, FILE* __restrict stream) 121{ 122 VERIFY(stream); 123 ScopedFileLock lock(stream); 124 int size = 0; 125 for (auto const* p = ws; *p != 0; ++p, ++size) { 126 if (putwc(*p, stream) == WEOF) 127 return WEOF; 128 } 129 return size; 130} 131 132// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ungetwc.html 133wint_t ungetwc(wint_t wc, FILE* stream) 134{ 135 VERIFY(stream); 136 ScopedFileLock lock(stream); 137 StringBuilder sb; 138 sb.append_code_point(static_cast<u32>(wc)); 139 auto bytes = sb.string_view().bytes(); 140 size_t ok_bytes = 0; 141 for (auto byte : bytes) { 142 if (!stream->ungetc(byte)) { 143 // Discard the half-ungotten bytes. 144 stream->read(const_cast<u8*>(bytes.data()), ok_bytes); 145 return WEOF; 146 } 147 ++ok_bytes; 148 } 149 return wc; 150} 151 152// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wprintf.html 153int wprintf(wchar_t const* __restrict format, ...) 154{ 155 va_list ap; 156 va_start(ap, format); 157 auto rc = vfwprintf(stdout, format, ap); 158 va_end(ap); 159 return rc; 160} 161 162// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwprintf.html 163int fwprintf(FILE* __restrict stream, wchar_t const* __restrict format, ...) 164{ 165 va_list ap; 166 va_start(ap, format); 167 auto rc = vfwprintf(stream, format, ap); 168 va_end(ap); 169 return rc; 170} 171 172// https://pubs.opengroup.org/onlinepubs/9699919799/functions/swprintf.html 173int swprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, ...) 174{ 175 va_list ap; 176 va_start(ap, format); 177 auto rc = vswprintf(wcs, max_length, format, ap); 178 va_end(ap); 179 return rc; 180} 181 182// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vwprintf.html 183int vwprintf(wchar_t const* __restrict format, va_list args) 184{ 185 return vfwprintf(stdout, format, args); 186} 187 188// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vfwprintf.html 189int vfwprintf(FILE* __restrict stream, wchar_t const* __restrict format, va_list args) 190{ 191 auto const* fmt = bit_cast<wchar_t const*>(format); 192 return printf_internal([stream](wchar_t*&, wchar_t wc) { 193 putwc(wc, stream); 194 }, 195 nullptr, fmt, args); 196} 197 198// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vswprintf.html 199int vswprintf(wchar_t* __restrict wcs, size_t max_length, wchar_t const* __restrict format, va_list args) 200{ 201 auto const* fmt = bit_cast<wchar_t const*>(format); 202 size_t length_so_far = 0; 203 printf_internal([max_length, &length_so_far](wchar_t*& buffer, wchar_t wc) { 204 if (length_so_far > max_length) 205 return; 206 *buffer++ = wc; 207 ++length_so_far; 208 }, 209 wcs, fmt, args); 210 if (length_so_far < max_length) 211 wcs[length_so_far] = L'\0'; 212 else 213 wcs[max_length - 1] = L'\0'; 214 return static_cast<int>(length_so_far); 215} 216 217// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fwscanf.html 218int fwscanf(FILE* __restrict stream, wchar_t const* __restrict format, ...) 219{ 220 va_list ap; 221 va_start(ap, format); 222 auto rc = vfwscanf(stream, format, ap); 223 va_end(ap); 224 return rc; 225} 226 227// https://pubs.opengroup.org/onlinepubs/9699919799/functions/swscanf.html 228int swscanf(wchar_t const* __restrict ws, wchar_t const* __restrict format, ...) 229{ 230 va_list ap; 231 va_start(ap, format); 232 auto rc = vswscanf(ws, format, ap); 233 va_end(ap); 234 return rc; 235} 236 237// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wscanf.html 238int wscanf(wchar_t const* __restrict format, ...) 239{ 240 va_list ap; 241 va_start(ap, format); 242 auto rc = vfwscanf(stdout, format, ap); 243 va_end(ap); 244 return rc; 245} 246 247// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vfwscanf.html 248int vfwscanf(FILE* __restrict stream, wchar_t const* __restrict format, va_list arg) 249{ 250 (void)stream; 251 (void)format; 252 (void)arg; 253 dbgln("FIXME: Implement vfwscanf()"); 254 TODO(); 255} 256 257// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vswscanf.html 258int vswscanf(wchar_t const* __restrict ws, wchar_t const* __restrict format, va_list arg) 259{ 260 (void)ws; 261 (void)format; 262 (void)arg; 263 dbgln("FIXME: Implement vswscanf()"); 264 TODO(); 265} 266 267// https://pubs.opengroup.org/onlinepubs/9699919799/functions/vwscanf.html 268int vwscanf(wchar_t const* __restrict format, va_list arg) 269{ 270 (void)format; 271 (void)arg; 272 dbgln("FIXME: Implement vwscanf()"); 273 TODO(); 274} 275}