[libc-commits] [libc] [libc] Add wchar support to File (PR #189504)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Fri May 1 09:37:19 PDT 2026


================
@@ -509,4 +550,132 @@ File::ModeFlags File::mode_flags(const char *mode) {
   return flags;
 }
 
+FileIOResult File::write_unlocked(const wchar_t *ws, size_t len) {
+  switch (orientation) {
+  case Orientation::BYTE:
+    err = true;
+    return {0, EINVAL};
+  case Orientation::UNORIENTED:
+    orientation = Orientation::WIDE;
+    break;
+  case Orientation::WIDE:
+    break;
+  }
+
+  size_t written = 0;
+  for (size_t i = 0; i < len; ++i) {
+    internal::CharacterConverter cr(&mbstate);
+    int push_err = cr.push(static_cast<char32_t>(ws[i]));
+    if (push_err != 0) {
+      err = true;
+      return {written, push_err};
+    }
+    // buffer the whole wchar to save on calls to write.
+    char buffer[4];
+    size_t char_size = 0;
+    while (!cr.isEmpty()) {
+      auto pop_res = cr.pop<char8_t>();
+      if (!pop_res.has_value()) {
+        err = true;
+        return {written, pop_res.error()};
+      }
+      char8_t byte = pop_res.value();
+      buffer[char_size] = byte;
+      ++char_size;
+    }
+    auto write_res = write_unlocked_impl(buffer, char_size);
+    if (write_res.has_error())
+      return {written, write_res.error};
+    if (write_res.value < 1)
+      return {written, 0};
+    ++written;
+  }
+  return {written, 0};
+}
+
+FileIOResult File::read_unlocked(wchar_t *ws, size_t len) {
+  switch (orientation) {
+  case Orientation::BYTE:
+    err = true;
+    return {0, EINVAL};
+  case Orientation::UNORIENTED:
+    orientation = Orientation::WIDE;
+    break;
+  case Orientation::WIDE:
+    break;
+  }
+
+  size_t read_count = 0;
+  for (size_t i = 0; i < len; ++i) {
+    internal::CharacterConverter cr(&mbstate);
+    while (!cr.isFull()) {
+      uint8_t byte;
+      auto read_res = read_unlocked_impl(&byte, 1);
+      if (read_res.has_error())
+        return {read_count, read_res.error};
+      if (read_res.value == 0) { // EOF
+        if (cr.isEmpty())
+          return {read_count, 0};
+        err = true;
+        return {read_count, EILSEQ}; // Incomplete character at EOF
+      }
+      int push_err = cr.push(static_cast<char8_t>(byte));
+      if (push_err != 0) {
+        err = true;
+        return {read_count, push_err};
+      }
+    }
+    auto pop_res = cr.pop<char32_t>();
+    if (!pop_res.has_value()) {
+      err = true;
+      return {read_count, pop_res.error()};
+    }
+    ws[i] = static_cast<wchar_t>(pop_res.value());
+    ++read_count;
+  }
+  return {read_count, 0};
+}
+
+wint_t File::ungetwc_unlocked(wint_t wc) {
+  if (wc == WEOF)
----------------
kaladron wrote:

ungetc_unlocked has a guard:

```
  if (c == EOF || !read_allowed() || (prev_op == FileOp::WRITE))
    return EOF;
```

Does read_allowed need to be checked here too?

https://github.com/llvm/llvm-project/pull/189504


More information about the libc-commits mailing list