[libc-commits] [libc] [libc] implement fwide (PR #196157)

Michael Jones via libc-commits libc-commits at lists.llvm.org
Thu May 7 10:54:20 PDT 2026


https://github.com/michaelrj-google updated https://github.com/llvm/llvm-project/pull/196157

>From 0af6f39e1069674be47231fc12da2c8087bd8ad3 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 6 May 2026 18:26:55 +0000
Subject: [PATCH 1/3] [libc] implement fwide

Add fwide function and tests. Part 1/11. All build file changes are in
part 11.

Assisted by Gemini
---
 libc/src/wchar/fwide.cpp           | 38 +++++++++++++++++++++
 libc/src/wchar/fwide.h             | 21 ++++++++++++
 libc/test/src/wchar/fwide_test.cpp | 54 ++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)
 create mode 100644 libc/src/wchar/fwide.cpp
 create mode 100644 libc/src/wchar/fwide.h
 create mode 100644 libc/test/src/wchar/fwide_test.cpp

diff --git a/libc/src/wchar/fwide.cpp b/libc/src/wchar/fwide.cpp
new file mode 100644
index 0000000000000..6965b4ea1ef82
--- /dev/null
+++ b/libc/src/wchar/fwide.cpp
@@ -0,0 +1,38 @@
+//===-- Implementation of fwide -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/wchar/fwide.h"
+#include "hdr/types/FILE.h"
+#include "src/__support/File/file.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fwide, (::FILE *stream, int mode)) {
+  LIBC_CRASH_ON_NULLPTR(stream);
+  auto *f = reinterpret_cast<File *>(stream);
+
+  File::Orientation orient;
+  if (mode > 0) {
+    orient = f->try_set_orientation(File::Orientation::WIDE);
+  } else if (mode < 0) {
+    orient = f->try_set_orientation(File::Orientation::BYTE);
+  } else {
+    orient = f->get_orientation();
+  }
+
+  if (orient == File::Orientation::WIDE)
+    return 1;
+  if (orient == File::Orientation::BYTE)
+    return -1;
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/fwide.h b/libc/src/wchar/fwide.h
new file mode 100644
index 0000000000000..bdb5a0534ca77
--- /dev/null
+++ b/libc/src/wchar/fwide.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for fwide -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_WCHAR_FWIDE_H
+#define LLVM_LIBC_SRC_WCHAR_FWIDE_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int fwide(::FILE *stream, int mode);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_WCHAR_FWIDE_H
diff --git a/libc/test/src/wchar/fwide_test.cpp b/libc/test/src/wchar/fwide_test.cpp
new file mode 100644
index 0000000000000..6131310a13018
--- /dev/null
+++ b/libc/test/src/wchar/fwide_test.cpp
@@ -0,0 +1,54 @@
+//===-- Unittests for fwide -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fclose.h"
+#include "src/stdio/fopen.h"
+#include "src/wchar/fwide.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcFwideTest, QueryInitial) {
+  auto FILENAME =
+      libc_make_test_file_path(APPEND_LIBC_TEST("fwide_query.test"));
+  ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
+  ASSERT_FALSE(file == nullptr);
+
+  // Initial orientation should be unoriented (0)
+  EXPECT_EQ(LIBC_NAMESPACE::fwide(file, 0), 0);
+
+  ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
+}
+
+TEST(LlvmLibcFwideTest, OrientWide) {
+  auto FILENAME = libc_make_test_file_path(APPEND_LIBC_TEST("fwide_wide.test"));
+  ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
+  ASSERT_FALSE(file == nullptr);
+
+  // Setting mode > 0 should return > 0 (wide oriented)
+  EXPECT_GT(LIBC_NAMESPACE::fwide(file, 1), 0);
+
+  // Subsequent orientation queries/attempts should still return > 0
+  EXPECT_GT(LIBC_NAMESPACE::fwide(file, 0), 0);
+  EXPECT_GT(LIBC_NAMESPACE::fwide(file, -1), 0);
+
+  ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
+}
+
+TEST(LlvmLibcFwideTest, OrientByte) {
+  auto FILENAME = libc_make_test_file_path(APPEND_LIBC_TEST("fwide_byte.test"));
+  ::FILE *file = LIBC_NAMESPACE::fopen(FILENAME, "w");
+  ASSERT_FALSE(file == nullptr);
+
+  // Setting mode < 0 should return < 0 (byte oriented)
+  EXPECT_LT(LIBC_NAMESPACE::fwide(file, -1), 0);
+
+  // Subsequent orientation queries/attempts should still return < 0
+  EXPECT_LT(LIBC_NAMESPACE::fwide(file, 0), 0);
+  EXPECT_LT(LIBC_NAMESPACE::fwide(file, 1), 0);
+
+  ASSERT_EQ(LIBC_NAMESPACE::fclose(file), 0);
+}

>From 8a9f5a568e6129128b5172e4af334402ed08ee0a Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 6 May 2026 20:04:51 +0000
Subject: [PATCH 2/3] format

---
 libc/src/wchar/fwide.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/wchar/fwide.cpp b/libc/src/wchar/fwide.cpp
index 6965b4ea1ef82..19af86e79de79 100644
--- a/libc/src/wchar/fwide.cpp
+++ b/libc/src/wchar/fwide.cpp
@@ -15,7 +15,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(int, fwide, (::FILE *stream, int mode)) {
+LLVM_LIBC_FUNCTION(int, fwide, (::FILE * stream, int mode)) {
   LIBC_CRASH_ON_NULLPTR(stream);
   auto *f = reinterpret_cast<File *>(stream);
 

>From ab5e539a24b6033c68c2e8afe98c6ecf5afe164c Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Thu, 7 May 2026 17:53:24 +0000
Subject: [PATCH 3/3] fix header formatting, add build setup.

---
 libc/config/linux/aarch64/entrypoints.txt |  12 ++
 libc/config/linux/riscv/entrypoints.txt   |  12 ++
 libc/config/linux/x86_64/entrypoints.txt  |  12 +-
 libc/include/wchar.yaml                   |  67 +++++++++++
 libc/src/wchar/CMakeLists.txt             | 139 +++++++++++++++++++++-
 libc/src/wchar/fwide.cpp                  |   8 +-
 libc/src/wchar/fwide.h                    |   8 +-
 7 files changed, 254 insertions(+), 4 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ea3f4cd8f51a0..a0fb4663c1e54 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1242,6 +1242,18 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # sys/select.h entrypoints
     libc.src.sys.select.select
+
+    # wchar.h entrypoints
+    # libc.src.wchar.fgetwc
+    # libc.src.wchar.fgetws
+    # libc.src.wchar.fputwc
+    # libc.src.wchar.fputws
+    libc.src.wchar.fwide
+    # libc.src.wchar.getwc
+    # libc.src.wchar.getwchar
+    # libc.src.wchar.putwc
+    # libc.src.wchar.putwchar
+    # libc.src.wchar.ungetwc
   )
 endif()
 
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index d8d520c6d4236..f67984d4f6484 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1376,6 +1376,18 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # sys/select.h entrypoints
     libc.src.sys.select.select
+
+    # wchar.h entrypoints
+    # libc.src.wchar.fgetwc
+    # libc.src.wchar.fgetws
+    # libc.src.wchar.fputwc
+    # libc.src.wchar.fputws
+    libc.src.wchar.fwide
+    # libc.src.wchar.getwc
+    # libc.src.wchar.getwchar
+    # libc.src.wchar.putwc
+    # libc.src.wchar.putwchar
+    # libc.src.wchar.ungetwc
   )
 endif()
 
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index dfd6064951d52..b6247c1172150 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1463,9 +1463,19 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.wchar.wcrtomb
     libc.src.wchar.wcsrtombs
     libc.src.wchar.wcsnrtombs
+    # libc.src.wchar.fgetwc
+    # libc.src.wchar.fgetws
+    # libc.src.wchar.fputwc
+    # libc.src.wchar.fputws
+    libc.src.wchar.fwide
+    # libc.src.wchar.getwc
+    # libc.src.wchar.getwchar
+    # libc.src.wchar.putwc
+    # libc.src.wchar.putwchar
+    # libc.src.wchar.ungetwc
 
     # nl_types.h entrypoints
-    libc.src.nl_types.catopen 
+    libc.src.nl_types.catopen
     libc.src.nl_types.catclose
     libc.src.nl_types.catgets
   )
diff --git a/libc/include/wchar.yaml b/libc/include/wchar.yaml
index 6575f2504c900..c7a956d542ff6 100644
--- a/libc/include/wchar.yaml
+++ b/libc/include/wchar.yaml
@@ -369,3 +369,70 @@ functions:
       - type: wchar_t *__restrict
       - type: const wchar_t *__restrict
       - type: size_t
+  - name: fgetwc
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: FILE *
+  - name: fgetws
+    standards:
+      - stdc
+    return_type: wchar_t *
+    arguments:
+      - type: wchar_t *__restrict
+      - type: int
+      - type: FILE *__restrict
+  - name: fputwc
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: wchar_t
+      - type: FILE *
+  - name: fputws
+    standards:
+      - stdc
+    return_type: int
+    arguments:
+      - type: const wchar_t *__restrict
+      - type: FILE *__restrict
+  - name: fwide
+    standards:
+      - stdc
+    return_type: int
+    arguments:
+      - type: FILE *
+      - type: int
+  - name: getwc
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: FILE *
+  - name: getwchar
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: void
+  - name: putwc
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: wchar_t
+      - type: FILE *
+  - name: putwchar
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: wchar_t
+  - name: ungetwc
+    standards:
+      - stdc
+    return_type: wint_t
+    arguments:
+      - type: wint_t
+      - type: FILE *
diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt
index 89383c33c6a4e..6b075da6d430c 100644
--- a/libc/src/wchar/CMakeLists.txt
+++ b/libc/src/wchar/CMakeLists.txt
@@ -310,7 +310,7 @@ add_entrypoint_object(
     libc.hdr.types.size_t
     libc.hdr.wchar_macros
     libc.src.__support.macros.null_check
-)   
+)
 
 add_entrypoint_object(
   wcschr
@@ -566,3 +566,140 @@ add_entrypoint_object(
     libc.src.__support.macros.config
     libc.src.__support.common
 )
+
+add_entrypoint_object(
+  fwide
+  SRCS
+    fwide.cpp
+  HDRS
+    fwide.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.src.__support.File.file
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  fputwc
+  SRCS
+    fputwc.cpp
+  HDRS
+    fputwc.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wint_t
+    libc.hdr.types.wchar_t
+    libc.hdr.wchar_macros
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  fgetwc
+  SRCS
+    fgetwc.cpp
+  HDRS
+    fgetwc.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wint_t
+    libc.hdr.types.wchar_t
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  fputws
+  SRCS
+    fputws.cpp
+  HDRS
+    fputws.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wchar_t
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.string.string_utils
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  fgetws
+  SRCS
+    fgetws.cpp
+  HDRS
+    fgetws.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wchar_t
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  ungetwc
+  SRCS
+    ungetwc.cpp
+  HDRS
+    ungetwc.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wint_t
+    libc.src.__support.File.file
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  getwc
+  SRCS
+    getwc.cpp
+  HDRS
+    getwc.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wint_t
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  getwchar
+  SRCS
+    getwchar.cpp
+  HDRS
+    getwchar.h
+  DEPENDS
+    libc.src.stdio.stdin
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+)
+
+add_entrypoint_object(
+  putwc
+  SRCS
+    putwc.cpp
+  HDRS
+    putwc.h
+  DEPENDS
+    libc.hdr.types.FILE
+    libc.hdr.types.wint_t
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  putwchar
+  SRCS
+    putwchar.cpp
+  HDRS
+    putwchar.h
+  DEPENDS
+    libc.src.stdio.stdout
+    libc.src.__support.File.file
+    libc.src.__support.libc_errno
+)
diff --git a/libc/src/wchar/fwide.cpp b/libc/src/wchar/fwide.cpp
index 19af86e79de79..ada4c30ba9c59 100644
--- a/libc/src/wchar/fwide.cpp
+++ b/libc/src/wchar/fwide.cpp
@@ -1,10 +1,16 @@
-//===-- Implementation of fwide -------------------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of the fwide function, which sets and
+/// gets the orientation of a stream.
+///
+//===----------------------------------------------------------------------===//
 
 #include "src/wchar/fwide.h"
 #include "hdr/types/FILE.h"
diff --git a/libc/src/wchar/fwide.h b/libc/src/wchar/fwide.h
index bdb5a0534ca77..1463af6db9604 100644
--- a/libc/src/wchar/fwide.h
+++ b/libc/src/wchar/fwide.h
@@ -1,10 +1,16 @@
-//===-- Implementation header for fwide -----------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the prototype of the fwide function, which sets and
+/// gets the orientation of a stream.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC_WCHAR_FWIDE_H
 #define LLVM_LIBC_SRC_WCHAR_FWIDE_H



More information about the libc-commits mailing list