Skip to content

Commit c2a7797

Browse files
author
shubh@DOE
committed
[libc] Support %lc in printf
Add %lc support to libc printf by utilizing wcrtomb internal function, also added relevant unit tests. Issue: #166598
1 parent f5742c4 commit c2a7797

File tree

4 files changed

+82
-5
lines changed

4 files changed

+82
-5
lines changed

libc/src/stdio/printf_core/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ add_header_library(
111111
.printf_config
112112
.writer
113113
libc.include.inttypes
114+
libc.hdr.types.wchar_t
114115
libc.src.__support.big_int
115116
libc.src.__support.common
116117
libc.src.__support.CPP.limits
@@ -123,6 +124,8 @@ add_header_library(
123124
libc.src.__support.integer_to_string
124125
libc.src.__support.libc_assert
125126
libc.src.__support.uint128
127+
libc.src.__support.wchar.mbstate
128+
libc.src.__support.wchar.wcrtomb
126129
libc.src.__support.StringUtil.error_to_string
127130
libc.src.string.memory_utils.inline_memcpy
128131
)

libc/src/stdio/printf_core/char_converter.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===-- String Converter for printf -----------------------------*- C++ -*-===//
1+
//===-- Character Converter for printf --------------------------*- C++ -*-===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -9,7 +9,10 @@
99
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
1010
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
1111

12+
#include "hdr/types/wchar_t.h"
1213
#include "src/__support/macros/config.h"
14+
#include "src/__support/wchar/mbstate.h"
15+
#include "src/__support/wchar/wcrtomb.h"
1316
#include "src/stdio/printf_core/converter_utils.h"
1417
#include "src/stdio/printf_core/core_structs.h"
1518
#include "src/stdio/printf_core/writer.h"
@@ -20,8 +23,11 @@ namespace printf_core {
2023
template <WriteMode write_mode>
2124
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
2225
const FormatSection &to_conv) {
23-
char c = static_cast<char>(to_conv.conv_val_raw);
24-
26+
char c;
27+
wchar_t wc;
28+
char mb_str[MB_LEN_MAX];
29+
internal::mbstate internal_mbstate = {0};
30+
int ret = 0;
2531
constexpr int STRING_LEN = 1;
2632

2733
size_t padding_spaces =
@@ -33,7 +39,21 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer,
3339
RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces));
3440
}
3541

36-
RET_IF_RESULT_NEGATIVE(writer->write(c));
42+
if (to_conv.length_modifier == LengthModifier::l) {
43+
wc = static_cast<wchar_t>(static_cast<unsigned int>(to_conv.conv_val_raw));
44+
ret = internal::wcrtomb(mb_str, wc, &internal_mbstate);
45+
if (ret <= 0) {
46+
return -1;
47+
}
48+
49+
for (int i = 0; i < ret; i++) {
50+
RET_IF_RESULT_NEGATIVE(writer->write(mb_str[i]));
51+
}
52+
53+
} else {
54+
c = static_cast<char>(to_conv.conv_val_raw);
55+
RET_IF_RESULT_NEGATIVE(writer->write(c));
56+
}
3757

3858
// If the padding is on the right side, write the spaces last.
3959
if (padding_spaces > 0 &&

libc/test/src/stdio/printf_core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ add_libc_unittest(
3535
libc.src.stdio.printf_core.converter
3636
libc.src.stdio.printf_core.writer
3737
libc.src.stdio.printf_core.core_structs
38+
libc.hdr.types.wchar_t
3839
)

libc/test/src/stdio/printf_core/converter_test.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "hdr/types/wchar_t.h"
910
#include "src/stdio/printf_core/converter.h"
1011
#include "src/stdio/printf_core/core_structs.h"
1112
#include "src/stdio/printf_core/writer.h"
12-
1313
#include "test/UnitTest/Test.h"
1414

1515
class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test {
@@ -255,3 +255,56 @@ TEST_F(LlvmLibcPrintfConverterTest, OctConversion) {
255255
ASSERT_STREQ(str, "1234");
256256
ASSERT_EQ(writer.get_chars_written(), size_t{4});
257257
}
258+
259+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversion) {
260+
261+
LIBC_NAMESPACE::printf_core::FormatSection section;
262+
section.has_conv = true;
263+
section.raw_string = "%c";
264+
section.conv_name = 'c';
265+
section.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
266+
section.conv_val_raw = static_cast<wchar_t>(L'S');
267+
268+
LIBC_NAMESPACE::printf_core::convert(&writer, section);
269+
270+
wb.buff[wb.buff_cur] = '\0';
271+
272+
ASSERT_STREQ(str, "S");
273+
ASSERT_EQ(writer.get_chars_written(), size_t{1});
274+
}
275+
276+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionLeftJustified) {
277+
LIBC_NAMESPACE::printf_core::FormatSection left_justified_conv;
278+
left_justified_conv.has_conv = true;
279+
left_justified_conv.raw_string = "%-4c";
280+
left_justified_conv.conv_name = 'c';
281+
left_justified_conv.length_modifier =
282+
LIBC_NAMESPACE::printf_core::LengthModifier::l;
283+
left_justified_conv.flags =
284+
LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
285+
left_justified_conv.min_width = 4;
286+
left_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
287+
288+
LIBC_NAMESPACE::printf_core::convert(&writer, left_justified_conv);
289+
wb.buff[wb.buff_cur] = '\0';
290+
291+
ASSERT_STREQ(str, "S ");
292+
ASSERT_EQ(writer.get_chars_written(), size_t{4});
293+
}
294+
295+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionRightJustified) {
296+
LIBC_NAMESPACE::printf_core::FormatSection right_justified_conv;
297+
right_justified_conv.has_conv = true;
298+
right_justified_conv.raw_string = "%4c";
299+
right_justified_conv.conv_name = 'c';
300+
right_justified_conv.length_modifier =
301+
LIBC_NAMESPACE::printf_core::LengthModifier::l;
302+
right_justified_conv.min_width = 4;
303+
right_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
304+
305+
LIBC_NAMESPACE::printf_core::convert(&writer, right_justified_conv);
306+
wb.buff[wb.buff_cur] = '\0';
307+
308+
ASSERT_STREQ(str, " S");
309+
ASSERT_EQ(writer.get_chars_written(), size_t{4});
310+
}

0 commit comments

Comments
 (0)