wstdio.cpp 7.5 KB

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