diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -62,6 +62,7 @@ char_converter.h int_converter.h hex_converter.h + ptr_converter.h DEPENDS .writer .core_structs diff --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp --- a/libc/src/stdio/printf_core/converter.cpp +++ b/libc/src/stdio/printf_core/converter.cpp @@ -61,7 +61,7 @@ case 'n': // return convert_write_int(writer, to_conv); case 'p': - // return convert_pointer(writer, to_conv); + return convert_pointer(writer, to_conv); default: return writer->write(to_conv.raw_string, to_conv.raw_len); } diff --git a/libc/src/stdio/printf_core/converter_atlas.h b/libc/src/stdio/printf_core/converter_atlas.h --- a/libc/src/stdio/printf_core/converter_atlas.h +++ b/libc/src/stdio/printf_core/converter_atlas.h @@ -36,5 +36,6 @@ // defines convert_write_int // defines convert_pointer +#include "src/stdio/printf_core/ptr_converter.h" #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CONVERTER_ATLAS_H diff --git a/libc/src/stdio/printf_core/ptr_converter.h b/libc/src/stdio/printf_core/ptr_converter.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_core/ptr_converter.h @@ -0,0 +1,39 @@ +//===-- Pointer 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. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PTR_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PTR_CONVERTER_H + +#include "src/stdio/printf_core/converter_utils.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/hex_converter.h" +#include "src/stdio/printf_core/writer.h" + +namespace __llvm_libc { +namespace printf_core { + +int inline convert_pointer(Writer *writer, const FormatSection &to_conv) { + if (to_conv.conv_val_ptr == (void *)(nullptr)) { + const char ZERO_STR[] = "(nullptr)"; + // subtract 1 from sizeof to remove the null byte at the end. + RET_IF_RESULT_NEGATIVE(writer->write(ZERO_STR, sizeof(ZERO_STR) - 1)); + } else { + FormatSection hex_conv; + hex_conv.has_conv = true; + hex_conv.conv_name = 'x'; + hex_conv.flags = FormatFlags::ALTERNATE_FORM; + hex_conv.conv_val_raw = reinterpret_cast(to_conv.conv_val_ptr); + return convert_hex(writer, hex_conv); + } + return 0; +} + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PTR_CONVERTER_H diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp b/libc/test/src/stdio/printf_core/converter_test.cpp --- a/libc/test/src/stdio/printf_core/converter_test.cpp +++ b/libc/test/src/stdio/printf_core/converter_test.cpp @@ -223,3 +223,23 @@ ASSERT_STREQ(str, "0x00000000123456ab"); ASSERT_EQ(writer.get_chars_written(), 18); } + +TEST(LlvmLibcPrintfConverterTest, PointerConversion) { + char str[20]; + __llvm_libc::printf_core::StringWriter str_writer(str); + __llvm_libc::printf_core::Writer writer( + reinterpret_cast(&str_writer), + __llvm_libc::printf_core::write_to_string); + + __llvm_libc::printf_core::FormatSection section; + section.has_conv = true; + section.raw_string = "%p"; + section.raw_len = 2; + section.conv_name = 'p'; + section.conv_val_ptr = (void *)(0x123456ab); + __llvm_libc::printf_core::convert(&writer, section); + + str_writer.terminate(); + ASSERT_STREQ(str, "0x123456ab"); + ASSERT_EQ(writer.get_chars_written(), 10); +} diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -346,6 +346,22 @@ ASSERT_STREQ(buff, "007F 0x1000000000 002 "); } +TEST(LlvmLibcSPrintfTest, PointerConv) { + char buff[64]; + int written; + + written = __llvm_libc::sprintf(buff, "%p", nullptr); + EXPECT_EQ(written, 9); + ASSERT_STREQ(buff, "(nullptr)"); + + written = __llvm_libc::sprintf(buff, "%p", 0x1a2b3c4d); + EXPECT_EQ(written, 10); + ASSERT_STREQ(buff, "0x1a2b3c4d"); + + written = __llvm_libc::sprintf(buff, "%p", buff); + EXPECT_GT(written, 0); +} + #ifndef LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE TEST(LlvmLibcSPrintfTest, IndexModeParsing) { char buff[64];