Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libc/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
)
Expand Down
24 changes: 22 additions & 2 deletions libc/src/stdio/printf_core/char_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 =
Expand All @@ -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 &&
Expand Down
1 change: 1 addition & 0 deletions libc/test/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
55 changes: 54 additions & 1 deletion libc/test/src/stdio/printf_core/converter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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});
}
Loading