[libc-commits] [libc] [libc] Support %lc in printf (PR #169301)
Shubh Pachchigar via libc-commits
libc-commits at lists.llvm.org
Fri Nov 28 01:45:44 PST 2025
https://github.com/shubhe25p updated https://github.com/llvm/llvm-project/pull/169301
>From 5bed042ffb9439115c0a67756e2d6fefd727dbb0 Mon Sep 17 00:00:00 2001
From: "shubh at DOE" <shubhp at mbm3a24.local>
Date: Fri, 28 Nov 2025 01:44:44 -0800
Subject: [PATCH] [libc] Support %lc in printf
Add %lc support to libc printf by utilizing
wcrtomb internal function, also added relevant
unit tests.
---
libc/src/stdio/printf_core/CMakeLists.txt | 3 +
libc/src/stdio/printf_core/char_converter.h | 24 +++++++-
.../test/src/stdio/printf_core/CMakeLists.txt | 1 +
.../src/stdio/printf_core/converter_test.cpp | 55 ++++++++++++++++++-
4 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index 624129b2b36e7..f35a65de1f110 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -111,6 +111,7 @@ add_header_library(
.printf_config
.writer
libc.include.inttypes
+ libc.hdr.types.wchar_t
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.CPP.limits
@@ -123,6 +124,8 @@ add_header_library(
libc.src.__support.integer_to_string
libc.src.__support.libc_assert
libc.src.__support.uint128
+ libc.src.__support.wchar.mbstate
+ libc.src.__support.wchar.wcrtomb
libc.src.__support.StringUtil.error_to_string
libc.src.string.memory_utils.inline_memcpy
)
diff --git a/libc/src/stdio/printf_core/char_converter.h b/libc/src/stdio/printf_core/char_converter.h
index fd2eb2553887a..3c6dc854b9fda 100644
--- a/libc/src/stdio/printf_core/char_converter.h
+++ b/libc/src/stdio/printf_core/char_converter.h
@@ -9,7 +9,10 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
+#include "libc/hdr/types/wchar_t.h"
#include "src/__support/macros/config.h"
+#include "src/__support/wchar/mbstate.h"
+#include "src/__support/wchar/wcrtomb.h"
#include "src/stdio/printf_core/converter_utils.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/writer.h"
@@ -20,8 +23,12 @@ namespace printf_core {
template <WriteMode write_mode>
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
const FormatSection &to_conv) {
+ wchar_t wc;
+ char mb_str[MB_LEN_MAX];
+ static internal::mbstate internal_mbstate;
+ int ret = 0;
+
char c = static_cast<char>(to_conv.conv_val_raw);
-
constexpr int STRING_LEN = 1;
size_t padding_spaces =
@@ -33,7 +40,20 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer,
RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces));
}
- RET_IF_RESULT_NEGATIVE(writer->write(c));
+ if (to_conv.length_modifier == LengthModifier::l) {
+ wc = static_cast<wchar_t>(c);
+ ret = internal::wcrtomb(mb_str, wc, &internal_mbstate);
+ if (ret <= 0) {
+ return -1;
+ }
+
+ for (int i = 0; i < ret; i++) {
+ RET_IF_RESULT_NEGATIVE(writer->write(mb_str[i]));
+ }
+
+ } else {
+ RET_IF_RESULT_NEGATIVE(writer->write(c));
+ }
// If the padding is on the right side, write the spaces last.
if (padding_spaces > 0 &&
diff --git a/libc/test/src/stdio/printf_core/CMakeLists.txt b/libc/test/src/stdio/printf_core/CMakeLists.txt
index ff7ebbc4f5fd0..a4c919420777d 100644
--- a/libc/test/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/test/src/stdio/printf_core/CMakeLists.txt
@@ -35,4 +35,5 @@ add_libc_unittest(
libc.src.stdio.printf_core.converter
libc.src.stdio.printf_core.writer
libc.src.stdio.printf_core.core_structs
+ libc.hdr.types.wchar_t
)
diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp
index 2dae2a22c864c..c181175e6314f 100644
--- a/libc/test/src/stdio/printf_core/converter_test.cpp
+++ b/libc/test/src/stdio/printf_core/converter_test.cpp
@@ -9,7 +9,7 @@
#include "src/stdio/printf_core/converter.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/writer.h"
-
+#include "libc/hdr/types/wchar_t.h"
#include "test/UnitTest/Test.h"
class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test {
@@ -255,3 +255,56 @@ TEST_F(LlvmLibcPrintfConverterTest, OctConversion) {
ASSERT_STREQ(str, "1234");
ASSERT_EQ(writer.get_chars_written(), size_t{4});
}
+
+TEST_F(LlvmLibcPrintfConverterTest, WideCharConversion) {
+
+ LIBC_NAMESPACE::printf_core::FormatSection section;
+ section.has_conv = true;
+ section.raw_string = "%c";
+ section.conv_name = 'c';
+ section.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
+ section.conv_val_raw = static_cast<wchar_t>(L'S');
+
+ LIBC_NAMESPACE::printf_core::convert(&writer, section);
+
+ wb.buff[wb.buff_cur] = '\0';
+
+ ASSERT_STREQ(str, "S");
+ ASSERT_EQ(writer.get_chars_written(), size_t{1});
+}
+
+TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionLeftJustified) {
+ LIBC_NAMESPACE::printf_core::FormatSection left_justified_conv;
+ left_justified_conv.has_conv = true;
+ left_justified_conv.raw_string = "%-4c";
+ left_justified_conv.conv_name = 'c';
+ left_justified_conv.length_modifier =
+ LIBC_NAMESPACE::printf_core::LengthModifier::l;
+ left_justified_conv.flags =
+ LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
+ left_justified_conv.min_width = 4;
+ left_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
+
+ LIBC_NAMESPACE::printf_core::convert(&writer, left_justified_conv);
+ wb.buff[wb.buff_cur] = '\0';
+
+ ASSERT_STREQ(str, "S ");
+ ASSERT_EQ(writer.get_chars_written(), size_t{4});
+}
+
+TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionRightJustified) {
+ LIBC_NAMESPACE::printf_core::FormatSection right_justified_conv;
+ right_justified_conv.has_conv = true;
+ right_justified_conv.raw_string = "%4c";
+ right_justified_conv.conv_name = 'c';
+ right_justified_conv.length_modifier =
+ LIBC_NAMESPACE::printf_core::LengthModifier::l;
+ right_justified_conv.min_width = 4;
+ right_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
+
+ LIBC_NAMESPACE::printf_core::convert(&writer, right_justified_conv);
+ wb.buff[wb.buff_cur] = '\0';
+
+ ASSERT_STREQ(str, " S");
+ ASSERT_EQ(writer.get_chars_written(), size_t{4});
+}
More information about the libc-commits
mailing list