Skip to content

Commit 7a33e23

Browse files
author
shubh@DOE
committed
init
1 parent f5742c4 commit 7a33e23

File tree

6 files changed

+142
-8
lines changed

6 files changed

+142
-8
lines changed

libc/src/stdio/printf_core/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ add_header_library(
6767
parser.h
6868
DEPENDS
6969
.core_structs
70+
libc.hdr.types.wint_t.h
7071
libc.src.__support.arg_list
7172
libc.src.__support.ctype_utils
7273
libc.src.__support.str_to_integer
@@ -111,6 +112,8 @@ add_header_library(
111112
.printf_config
112113
.writer
113114
libc.include.inttypes
115+
libc.hdr.types.wchar_t
116+
libc.hdr.types.wint_t
114117
libc.src.__support.big_int
115118
libc.src.__support.common
116119
libc.src.__support.CPP.limits
@@ -123,6 +126,8 @@ add_header_library(
123126
libc.src.__support.integer_to_string
124127
libc.src.__support.libc_assert
125128
libc.src.__support.uint128
129+
libc.src.__support.wchar.mbstate
130+
libc.src.__support.wchar.wcrtomb
126131
libc.src.__support.StringUtil.error_to_string
127132
libc.src.string.memory_utils.inline_memcpy
128133
)

libc/src/stdio/printf_core/char_converter.h

Lines changed: 26 additions & 3 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,11 @@
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"
13+
#include "hdr/types/wint_t.h"
1214
#include "src/__support/macros/config.h"
15+
#include "src/__support/wchar/mbstate.h"
16+
#include "src/__support/wchar/wcrtomb.h"
1317
#include "src/stdio/printf_core/converter_utils.h"
1418
#include "src/stdio/printf_core/core_structs.h"
1519
#include "src/stdio/printf_core/writer.h"
@@ -21,7 +25,6 @@ template <WriteMode write_mode>
2125
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
2226
const FormatSection &to_conv) {
2327
char c = static_cast<char>(to_conv.conv_val_raw);
24-
2528
constexpr int STRING_LEN = 1;
2629

2730
size_t padding_spaces =
@@ -33,7 +36,27 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer,
3336
RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces));
3437
}
3538

36-
RET_IF_RESULT_NEGATIVE(writer->write(c));
39+
if (to_conv.length_modifier == LengthModifier::l) {
40+
wint_t wi = static_cast<wint_t>(to_conv.conv_val_raw);
41+
42+
if (wi == WEOF) {
43+
return -1;
44+
}
45+
46+
char mb_str[MB_LEN_MAX];
47+
internal::mbstate mbstate;
48+
wchar_t wc = static_cast<wchar_t>(wi);
49+
50+
auto ret = internal::wcrtomb(mb_str, wc, &internal_mbstate);
51+
if (!ret.has_value()) {
52+
return -1;
53+
}
54+
55+
RET_IF_RESULT_NEGATIVE(writer->write({mb_str, ret.value()}));
56+
57+
} else {
58+
RET_IF_RESULT_NEGATIVE(writer->write(c));
59+
}
3760

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

libc/src/stdio/printf_core/parser.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H
1010
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H
1111

12+
#include "hdr/types/wint_t.h"
1213
#include "include/llvm-libc-macros/stdfix-macros.h"
1314
#include "src/__support/CPP/algorithm.h" // max
1415
#include "src/__support/CPP/limits.h"
@@ -73,9 +74,9 @@ template <typename ArgProvider> class Parser {
7374
ArgProvider args_cur;
7475

7576
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
76-
// args_start stores the start of the va_args, which is allows getting the
77-
// value of arguments that have already been passed. args_index is tracked so
78-
// that we know which argument args_cur is on.
77+
// args_start stores the start of the va_args, which helps in getting the
78+
// number of arguments that have already been passed. args_index is tracked
79+
// so that we know which argument args_cur is on.
7980
ArgProvider args_start;
8081
size_t args_index = 1;
8182

@@ -173,7 +174,11 @@ template <typename ArgProvider> class Parser {
173174
section.has_conv = true;
174175
break;
175176
case ('c'):
176-
WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);
177+
if (section.length_modifier == LengthModifier::l) {
178+
WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, wint_t, conv_index);
179+
} else {
180+
WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);
181+
}
177182
break;
178183
case ('d'):
179184
case ('i'):

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_libc_unittest(
77
LINK_LIBRARIES
88
LibcPrintfHelpers
99
DEPENDS
10+
libc.hdr.types.wchar_t
1011
libc.src.stdio.printf_core.parser
1112
libc.src.stdio.printf_core.core_structs
1213
libc.src.__support.CPP.string_view
@@ -32,6 +33,7 @@ add_libc_unittest(
3233
SRCS
3334
converter_test.cpp
3435
DEPENDS
36+
libc.hdr.types.wchar_t
3537
libc.src.stdio.printf_core.converter
3638
libc.src.stdio.printf_core.writer
3739
libc.src.stdio.printf_core.core_structs

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

Lines changed: 81 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,83 @@ 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+
LIBC_NAMESPACE::printf_core::FormatSection section;
261+
section.has_conv = true;
262+
section.raw_string = "%lc";
263+
section.conv_name = 'c';
264+
section.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
265+
section.conv_val_raw = static_cast<wchar_t>(L'');
266+
267+
LIBC_NAMESPACE::printf_core::convert(&writer, section);
268+
269+
wb.buff[wb.buff_cur] = '\0';
270+
271+
ASSERT_STREQ(str, "");
272+
ASSERT_EQ(writer.get_chars_written(), size_t{1});
273+
}
274+
275+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionLeftJustified) {
276+
LIBC_NAMESPACE::printf_core::FormatSection left_justified_conv;
277+
left_justified_conv.has_conv = true;
278+
left_justified_conv.raw_string = "%-4lc";
279+
left_justified_conv.conv_name = 'c';
280+
left_justified_conv.length_modifier =
281+
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'');
286+
287+
LIBC_NAMESPACE::printf_core::convert(&writer, left_justified_conv);
288+
wb.buff[wb.buff_cur] = '\0';
289+
290+
ASSERT_STREQ(str, "");
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 = "%4lc";
298+
right_justified_conv.conv_name = 'c';
299+
right_justified_conv.length_modifier =
300+
LIBC_NAMESPACE::printf_core::LengthModifier::l;
301+
right_justified_conv.min_width = 4;
302+
right_justified_conv.conv_val_raw = static_cast<wchar_t>(L'');
303+
304+
LIBC_NAMESPACE::printf_core::convert(&writer, right_justified_conv);
305+
wb.buff[wb.buff_cur] = '\0';
306+
307+
ASSERT_STREQ(str, "");
308+
ASSERT_EQ(writer.get_chars_written(), size_t{4});
309+
}
310+
311+
TEST_F(LlvmLibcPrintfConverterTest, WideCharConversionInvalid) {
312+
LIBC_NAMESPACE::printf_core::FormatSection section;
313+
section.has_conv = true;
314+
section.raw_string = "%lc";
315+
section.conv_name = 'c';
316+
section.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
317+
// An invalid wide character.
318+
section.conv_val_raw = static_cast<wchar_t>(0xFFFFFFFF);
319+
320+
int ret = LIBC_NAMESPACE::printf_core::convert(&writer, section);
321+
322+
ASSERT_EQ(ret, -1);
323+
}
324+
325+
TEST_F(LlvmLibcPrintfConverterTest, WideCharWEOFConversion) {
326+
LIBC_NAMESPACE::printf_core::FormatSection section;
327+
section.has_conv = true;
328+
section.raw_string = "%lc";
329+
section.conv_name = 'c';
330+
section.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
331+
// WEOF value.
332+
section.conv_val_raw = static_cast<wchar_t>(WEOF);
333+
334+
int ret = LIBC_NAMESPACE::printf_core::convert(&writer, section);
335+
336+
ASSERT_EQ(ret, -1);
337+
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "hdr/types/wchar_t.h"
910
#include "src/__support/CPP/bit.h"
1011
#include "src/__support/CPP/string_view.h"
1112
#include "src/__support/arg_list.h"
@@ -370,6 +371,24 @@ TEST(LlvmLibcPrintfParserTest,
370371
ASSERT_PFORMAT_EQ(expected, format_arr[0]);
371372
}
372373

374+
TEST(LlvmLibcPrintfParserTest, EvalOneArgWithWideCharacter) {
375+
LIBC_NAMESPACE::printf_core::FormatSection format_arr[2];
376+
const char *str = "%lc";
377+
wchar_t arg1 = L'';
378+
evaluate(format_arr, str, arg1);
379+
380+
LIBC_NAMESPACE::printf_core::FormatSection expected;
381+
expected.has_conv = true;
382+
383+
expected.raw_string = {str, 3};
384+
expected.length_modifier = LIBC_NAMESPACE::printf_core::LengthModifier::l;
385+
expected.conv_val_raw =
386+
static_cast<LIBC_NAMESPACE::fputil::FPBits<double>::StorageType>(arg1);
387+
expected.conv_name = 'c';
388+
389+
ASSERT_PFORMAT_EQ(expected, format_arr[0]);
390+
}
391+
373392
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
374393

375394
TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {

0 commit comments

Comments
 (0)