diff options
Diffstat (limited to 'libc/src/stdio')
| -rw-r--r-- | libc/src/stdio/printf_core/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | libc/src/stdio/printf_core/char_converter.h | 50 | ||||
| -rw-r--r-- | libc/src/stdio/printf_core/core_structs.h | 2 | ||||
| -rw-r--r-- | libc/src/stdio/printf_core/linux/error_mapper.h | 3 | ||||
| -rw-r--r-- | libc/src/stdio/printf_core/parser.h | 32 |
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'): |
