Skip to content

Commit 03948a1

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.
1 parent bd0769e commit 03948a1

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

libc/src/stdio/printf_core/char_converter.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@
1313
#include "src/stdio/printf_core/converter_utils.h"
1414
#include "src/stdio/printf_core/core_structs.h"
1515
#include "src/stdio/printf_core/writer.h"
16+
#include "src/__support/wchar/mbstate.h"
17+
#include "src/__support/wchar/wcrtomb.h"
1618

1719
namespace LIBC_NAMESPACE_DECL {
1820
namespace printf_core {
1921

2022
template <WriteMode write_mode>
2123
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
2224
const FormatSection &to_conv) {
23-
char c = static_cast<char>(to_conv.conv_val_raw);
24-
25+
char c;
26+
wchar_t wc;
27+
char mb_str[MB_LEN_MAX];
28+
static internal::mbstate internal_mbstate;
29+
int ret = 0;
2530
constexpr int STRING_LEN = 1;
2631

2732
size_t padding_spaces =
@@ -33,7 +38,21 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer,
3338
RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces));
3439
}
3540

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

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

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ 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.src.wchar.wcrtomb
39+
libc.hdr.types.wchar_t
3840
)

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,54 @@ 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 = LIBC_NAMESPACE::printf_core::LengthModifier::l;
282+
left_justified_conv.flags =
283+
LIBC_NAMESPACE::printf_core::FormatFlags::LEFT_JUSTIFIED;
284+
left_justified_conv.min_width = 4;
285+
left_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
286+
287+
LIBC_NAMESPACE::printf_core::convert(&writer, left_justified_conv);
288+
wb.buff[wb.buff_cur] = '\0';
289+
290+
ASSERT_STREQ(str, "S ");
291+
ASSERT_EQ(writer.get_chars_written(), size_t{4});
292+
}
293+
294+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionRightJustified) {
295+
LIBC_NAMESPACE::printf_core::FormatSection right_justified_conv;
296+
right_justified_conv.has_conv = true;
297+
right_justified_conv.raw_string = "%4c";
298+
right_justified_conv.conv_name = 'c';
299+
right_justified_conv.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
300+
right_justified_conv.min_width = 4;
301+
right_justified_conv.conv_val_raw = static_cast<wchar_t>(L'S');
302+
303+
LIBC_NAMESPACE::printf_core::convert(&writer, right_justified_conv);
304+
wb.buff[wb.buff_cur] = '\0';
305+
306+
ASSERT_STREQ(str, " S");
307+
ASSERT_EQ(writer.get_chars_written(), size_t{4});
308+
}

0 commit comments

Comments
 (0)