aboutsummaryrefslogtreecommitdiff
path: root/libc/src/stdio
diff options
context:
space:
mode:
Diffstat (limited to 'libc/src/stdio')
-rw-r--r--libc/src/stdio/printf_core/CMakeLists.txt19
-rw-r--r--libc/src/stdio/printf_core/char_converter.h50
-rw-r--r--libc/src/stdio/printf_core/core_structs.h2
-rw-r--r--libc/src/stdio/printf_core/linux/error_mapper.h3
-rw-r--r--libc/src/stdio/printf_core/parser.h32
5 files changed, 95 insertions, 11 deletions
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index 624129b..ae93cc75 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -43,6 +43,22 @@ if(NOT TARGET ${target_error_mapper})
set(target_error_mapper libc.src.stdio.printf_core.generic.error_mapper)
endif()
+if(LIBC_CONF_PRINTF_DISABLE_WIDE)
+ set(wchar_deps "")
+ set(parser_wchar_deps "")
+else()
+ set(wchar_deps
+ libc.hdr.types.wchar_t
+ libc.hdr.types.wint_t
+ libc.hdr.wchar_macros
+ libc.src.__support.wchar.wcrtomb
+ libc.src.__support.wchar.mbstate
+ )
+ set(parser_wchar_deps
+ libc.hdr.types.wint_t
+ )
+endif()
+
add_header_library(
printf_config
HDRS
@@ -76,6 +92,7 @@ add_header_library(
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
libc.src.__support.common
+ ${parser_wchar_deps}
)
add_header_library(
@@ -111,6 +128,7 @@ add_header_library(
.printf_config
.writer
libc.include.inttypes
+ libc.hdr.limits_macros
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.CPP.limits
@@ -125,6 +143,7 @@ add_header_library(
libc.src.__support.uint128
libc.src.__support.StringUtil.error_to_string
libc.src.string.memory_utils.inline_memcpy
+ ${wchar_deps}
)
add_header_library(
diff --git a/libc/src/stdio/printf_core/char_converter.h b/libc/src/stdio/printf_core/char_converter.h
index fd2eb25..e4792c3 100644
--- a/libc/src/stdio/printf_core/char_converter.h
+++ b/libc/src/stdio/printf_core/char_converter.h
@@ -1,4 +1,4 @@
-//===-- String Converter for printf -----------------------------*- C++ -*-===//
+//===-- Character Converter for printf --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -9,6 +9,15 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H
+#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE
+#include "hdr/types/wchar_t.h"
+#include "hdr/types/wint_t.h"
+#include "hdr/wchar_macros.h"
+#include "src/__support/wchar/mbstate.h"
+#include "src/__support/wchar/wcrtomb.h"
+#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
+
+#include "hdr/limits_macros.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/converter_utils.h"
#include "src/stdio/printf_core/core_structs.h"
@@ -20,12 +29,41 @@ namespace printf_core {
template <WriteMode write_mode>
LIBC_INLINE int convert_char(Writer<write_mode> *writer,
const FormatSection &to_conv) {
- char c = static_cast<char>(to_conv.conv_val_raw);
- constexpr int STRING_LEN = 1;
+ char buffer[MB_LEN_MAX];
+ size_t write_size = 0;
+
+ if (to_conv.length_modifier == LengthModifier::l) {
+#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE
+ wint_t wi = static_cast<wint_t>(to_conv.conv_val_raw);
+
+ if (wi == WEOF) {
+ return ILLEGAL_WIDE_CHAR;
+ }
+
+ internal::mbstate mbstate;
+ wchar_t wc = static_cast<wchar_t>(wi);
+ auto ret = internal::wcrtomb(buffer, wc, &mbstate);
+
+ if (!ret.has_value()) {
+ return MB_CONVERSION_ERROR;
+ }
+
+ write_size = ret.value();
+#else
+ // If wide characters are disabled, treat the 'l' modifier as a no-op.
+ buffer[0] = static_cast<char>(to_conv.conv_val_raw);
+ write_size = 1;
+
+#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
+ } else {
+ buffer[0] = static_cast<char>(to_conv.conv_val_raw);
+ write_size = 1;
+ }
- size_t padding_spaces =
- to_conv.min_width > STRING_LEN ? to_conv.min_width - STRING_LEN : 0;
+ size_t padding_spaces = to_conv.min_width > static_cast<int>(write_size)
+ ? to_conv.min_width - static_cast<int>(write_size)
+ : 0;
// If the padding is on the left side, write the spaces first.
if (padding_spaces > 0 &&
@@ -33,7 +71,7 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer,
RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces));
}
- RET_IF_RESULT_NEGATIVE(writer->write(c));
+ RET_IF_RESULT_NEGATIVE(writer->write({buffer, write_size}));
// If the padding is on the right side, write the spaces last.
if (padding_spaces > 0 &&
diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h
index 0d41f22..d93fa96 100644
--- a/libc/src/stdio/printf_core/core_structs.h
+++ b/libc/src/stdio/printf_core/core_structs.h
@@ -142,6 +142,8 @@ constexpr int INT_CONVERSION_ERROR = -1004;
constexpr int FIXED_POINT_CONVERSION_ERROR = -1005;
constexpr int ALLOCATION_ERROR = -1006;
constexpr int OVERFLOW_ERROR = -1007;
+constexpr int ILLEGAL_WIDE_CHAR = -1008;
+constexpr int MB_CONVERSION_ERROR = -1009;
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/linux/error_mapper.h b/libc/src/stdio/printf_core/linux/error_mapper.h
index 3c2fe66..3449f12 100644
--- a/libc/src/stdio/printf_core/linux/error_mapper.h
+++ b/libc/src/stdio/printf_core/linux/error_mapper.h
@@ -40,6 +40,9 @@ LIBC_INLINE static int internal_error_to_errno(int internal_error) {
return ENOMEM;
case OVERFLOW_ERROR:
return EOVERFLOW;
+ case ILLEGAL_WIDE_CHAR:
+ case MB_CONVERSION_ERROR:
+ return EILSEQ;
default:
LIBC_ASSERT(
false &&
diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h
index cef9b1a..a3b6299 100644
--- a/libc/src/stdio/printf_core/parser.h
+++ b/libc/src/stdio/printf_core/parser.h
@@ -27,6 +27,9 @@
#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
#include "src/__support/libc_errno.h"
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
+#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE
+#include "hdr/types/wint_t.h"
+#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
@@ -73,9 +76,9 @@ template <typename ArgProvider> class Parser {
ArgProvider args_cur;
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
- // args_start stores the start of the va_args, which is allows getting the
- // value of arguments that have already been passed. args_index is tracked so
- // that we know which argument args_cur is on.
+ // args_start stores the start of the va_args, which helps in getting the
+ // number of arguments that have already been passed. args_index is tracked
+ // so that we know which argument args_cur is on.
ArgProvider args_start;
size_t args_index = 1;
@@ -173,7 +176,17 @@ public:
section.has_conv = true;
break;
case ('c'):
- WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);
+ if (section.length_modifier == LengthModifier::l) {
+#ifdef LIBC_COPT_PRINTF_DISABLE_WIDE
+ using WideCharArgType = int;
+#else
+ using WideCharArgType = wint_t;
+#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
+ WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, WideCharArgType,
+ conv_index);
+ } else {
+ WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index);
+ }
break;
case ('d'):
case ('i'):
@@ -574,7 +587,16 @@ private:
conv_size = type_desc_from_type<void>();
break;
case ('c'):
- conv_size = type_desc_from_type<int>();
+ if (lm == LengthModifier::l) {
+#ifdef LIBC_COPT_PRINTF_DISABLE_WIDE
+ using WideCharArgType = int;
+#else
+ using WideCharArgType = wint_t;
+#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
+ conv_size = type_desc_from_type<WideCharArgType>();
+ } else {
+ conv_size = type_desc_from_type<int>();
+ }
break;
case ('d'):
case ('i'):