[libc-commits] [libc] [libc][WIP] add iprintf (PR #115194)
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Nov 7 13:00:50 PST 2024
https://github.com/michaelrj-google updated https://github.com/llvm/llvm-project/pull/115194
>From 07cf7cb666203d5687cf10e47539a774907ef23e Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Wed, 6 Nov 2024 10:54:44 -0800
Subject: [PATCH 1/2] [libc][WIP] add iprintf
iprintf is printf without floats, clang supports this here: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp#L3392
---
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/src/stdio/CMakeLists.txt | 1 +
libc/src/stdio/generic/CMakeLists.txt | 17 +++++-
libc/src/stdio/generic/iprintf.cpp | 39 ++++++++++++
libc/src/stdio/iprintf.h | 21 +++++++
libc/src/stdio/printf_core/CMakeLists.txt | 74 +++++++++++++++++++++++
libc/test/src/stdio/CMakeLists.txt | 11 ++++
libc/test/src/stdio/iprintf_test.cpp | 33 ++++++++++
8 files changed, 196 insertions(+), 1 deletion(-)
create mode 100644 libc/src/stdio/generic/iprintf.cpp
create mode 100644 libc/src/stdio/iprintf.h
create mode 100644 libc/test/src/stdio/iprintf_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9a4a0ff9e75a40..e5d90dfa2010fa 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -212,6 +212,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fscanf
libc.src.stdio.vfscanf
libc.src.stdio.printf
+ libc.src.stdio.iprintf
libc.src.stdio.remove
libc.src.stdio.rename
libc.src.stdio.scanf
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index b9bc904471df9a..4456e9cb3ad16b 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -286,6 +286,7 @@ add_stdio_entrypoint_object(fputc)
add_stdio_entrypoint_object(putc)
add_stdio_entrypoint_object(putchar)
add_stdio_entrypoint_object(printf)
+add_stdio_entrypoint_object(iprintf)
add_stdio_entrypoint_object(fprintf)
add_stdio_entrypoint_object(fgetc)
add_stdio_entrypoint_object(fgetc_unlocked)
diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt
index bf301a6b0cb3c6..250d0ec58a12fc 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -366,7 +366,6 @@ add_entrypoint_object(
list(APPEND fprintf_deps
libc.hdr.types.FILE
libc.src.__support.arg_list
- libc.src.stdio.printf_core.vfprintf_internal
)
if(LLVM_LIBC_FULL_BUILD)
@@ -393,6 +392,19 @@ add_entrypoint_object(
../printf.h
DEPENDS
${printf_deps}
+ libc.src.stdio.printf_core.vfprintf_internal
+)
+
+# the printf variant with no floats is called iprintf for some reason
+add_entrypoint_object(
+ iprintf
+ SRCS
+ iprintf.cpp
+ HDRS
+ ../iprintf.h
+ DEPENDS
+ ${printf_deps}
+ libc.src.stdio.printf_core.vfprintf_internal_nofloat
)
add_entrypoint_object(
@@ -403,6 +415,7 @@ add_entrypoint_object(
../vprintf.h
DEPENDS
${printf_deps}
+ libc.src.stdio.printf_core.vfprintf_internal
)
add_entrypoint_object(
@@ -413,6 +426,7 @@ add_entrypoint_object(
../fprintf.h
DEPENDS
${fprintf_deps}
+ libc.src.stdio.printf_core.vfprintf_internal
)
add_entrypoint_object(
@@ -423,6 +437,7 @@ add_entrypoint_object(
../vfprintf.h
DEPENDS
${fprintf_deps}
+ libc.src.stdio.printf_core.vfprintf_internal
)
add_entrypoint_object(
diff --git a/libc/src/stdio/generic/iprintf.cpp b/libc/src/stdio/generic/iprintf.cpp
new file mode 100644
index 00000000000000..5b124d74311144
--- /dev/null
+++ b/libc/src/stdio/generic/iprintf.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of iprintf -------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/iprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include "hdr/types/FILE.h"
+#include <stdarg.h>
+
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+#define PRINTF_STDOUT LIBC_NAMESPACE::stdout
+#else // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+#define PRINTF_STDOUT ::stdout
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, iprintf, (const char *__restrict format, ...)) {
+ va_list vlist;
+ va_start(vlist, format);
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ va_end(vlist);
+ int ret_val = printf_core::vfprintf_internal(
+ reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
+ return ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/iprintf.h b/libc/src/stdio/iprintf.h
new file mode 100644
index 00000000000000..8844c03618da8a
--- /dev/null
+++ b/libc/src/stdio/iprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of iprintf ------------------------*- 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_IPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_IPRINTF_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int iprintf(const char *__restrict format, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_IPRINTF_H
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index 9eaffe2f7ed621..d8489e8dcf1cf7 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -22,6 +22,11 @@ endif()
if(LIBC_CONF_PRINTF_DISABLE_STRERROR)
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_DISABLE_STRERROR")
endif()
+
+set(printf_config_copts_nofloat ${printf_config_copts})
+list(APPEND printf_config_copts_nofloat "-DLIBC_COPT_PRINTF_DISABLE_FLOAT")
+list(PREPEND printf_config_copts_nofloat "COMPILE_OPTIONS")
+
if(printf_config_copts)
list(PREPEND printf_config_copts "COMPILE_OPTIONS")
endif()
@@ -33,6 +38,14 @@ add_header_library(
${printf_config_copts}
)
+
+add_header_library(
+ printf_config_nofloat
+ HDRS
+ printf_config.h
+ ${printf_config_copts_nofloat}
+)
+
add_header_library(
core_structs
HDRS
@@ -110,6 +123,41 @@ add_object_library(
libc.src.__support.StringUtil.error_to_string
)
+
+add_object_library(
+ converter_nofloat
+ SRCS
+ converter.cpp
+ HDRS
+ converter.h
+ converter_atlas.h
+ converter_utils.h
+ string_converter.h
+ char_converter.h
+ int_converter.h
+ ptr_converter.h
+ write_int_converter.h
+ fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
+ strerror_converter.h
+ DEPENDS
+ .core_structs
+ .printf_config_nofloat
+ .writer
+ libc.src.__support.big_int
+ libc.src.__support.common
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.span
+ libc.src.__support.CPP.string_view
+ libc.src.__support.float_to_string
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.integer_to_string
+ libc.src.__support.libc_assert
+ libc.src.__support.uint128
+ libc.src.__support.StringUtil.error_to_string
+)
+
add_object_library(
printf_main
SRCS
@@ -124,6 +172,20 @@ add_object_library(
libc.src.__support.arg_list
)
+add_object_library(
+ printf_main_nofloat
+ SRCS
+ printf_main.cpp
+ HDRS
+ printf_main.h
+ DEPENDS
+ .parser
+ .converter_nofloat
+ .writer
+ .core_structs
+ libc.src.__support.arg_list
+)
+
add_header_library(
vasprintf_internal
HDRS
@@ -154,3 +216,15 @@ add_header_library(
libc.src.stdio.printf_core.writer
${use_system_file}
)
+
+add_header_library(
+ vfprintf_internal_nofloat
+ HDRS
+ vfprintf_internal.h
+ DEPENDS
+ libc.src.__support.File.file
+ libc.src.__support.arg_list
+ libc.src.stdio.printf_core.printf_main_nofloat
+ libc.src.stdio.printf_core.writer
+ ${use_system_file}
+)
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index e17f8d8c101a96..a4e166fd7beec9 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -197,6 +197,17 @@ add_libc_test(
libc.src.stdio.printf
)
+add_libc_test(
+ iprintf_test
+ ${hermetic_test_only}
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ iprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.iprintf
+)
+
add_libc_test(
asprintf_test
SUITE
diff --git a/libc/test/src/stdio/iprintf_test.cpp b/libc/test/src/stdio/iprintf_test.cpp
new file mode 100644
index 00000000000000..3be6b9c9edf86e
--- /dev/null
+++ b/libc/test/src/stdio/iprintf_test.cpp
@@ -0,0 +1,33 @@
+//===-- Unittests for iprintf ---------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/iprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcIprintfTest, PrintOut) {
+ int written;
+
+ constexpr char simple[] = "A simple string with no conversions.\n";
+ written = LIBC_NAMESPACE::iprintf(simple);
+ EXPECT_EQ(written, static_cast<int>(sizeof(simple) - 1));
+
+ constexpr char numbers[] = "1234567890\n";
+ written = LIBC_NAMESPACE::iprintf("%s", numbers);
+ EXPECT_EQ(written, static_cast<int>(sizeof(numbers) - 1));
+
+ constexpr char format_more[] = "%s and more\n";
+ constexpr char short_numbers[] = "1234";
+ written = LIBC_NAMESPACE::iprintf(format_more, short_numbers);
+ EXPECT_EQ(written,
+ static_cast<int>(sizeof(format_more) + sizeof(short_numbers) - 4));
+
+ constexpr char format_float[] = "%f doesn't work\n";
+ written = LIBC_NAMESPACE::iprintf(format_float, 1.0);
+ EXPECT_EQ(written, static_cast<int>(sizeof(format_float) - 1));
+}
>From 7b048e6913512e586d56166175c0a77bdabbcbd9 Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Thu, 7 Nov 2024 12:58:33 -0800
Subject: [PATCH 2/2] ROTFO: Cleanup cmake, add printf variants
ROTFO stands for Rest of the Formatting Options, of course.
---
libc/config/linux/x86_64/entrypoints.txt | 7 +-
libc/src/stdio/CMakeLists.txt | 25 ++++++
libc/src/stdio/fiprintf.h | 21 +++++
libc/src/stdio/generic/CMakeLists.txt | 55 +++++++++----
libc/src/stdio/generic/fiprintf.cpp | 34 ++++++++
libc/src/stdio/printf_core/CMakeLists.txt | 98 +++++++++++------------
libc/src/stdio/siprintf.cpp | 39 +++++++++
libc/src/stdio/siprintf.h | 20 +++++
libc/src/stdio/sniprintf.cpp | 39 +++++++++
libc/src/stdio/sniprintf.h | 22 +++++
libc/test/src/stdio/CMakeLists.txt | 33 ++++++++
libc/test/src/stdio/fiprintf_test.cpp | 92 +++++++++++++++++++++
libc/test/src/stdio/siprintf_test.cpp | 38 +++++++++
libc/test/src/stdio/sniprintf_test.cpp | 66 +++++++++++++++
14 files changed, 520 insertions(+), 69 deletions(-)
create mode 100644 libc/src/stdio/fiprintf.h
create mode 100644 libc/src/stdio/generic/fiprintf.cpp
create mode 100644 libc/src/stdio/siprintf.cpp
create mode 100644 libc/src/stdio/siprintf.h
create mode 100644 libc/src/stdio/sniprintf.cpp
create mode 100644 libc/src/stdio/sniprintf.h
create mode 100644 libc/test/src/stdio/fiprintf_test.cpp
create mode 100644 libc/test/src/stdio/siprintf_test.cpp
create mode 100644 libc/test/src/stdio/sniprintf_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e5d90dfa2010fa..42b7cc59139239 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -212,7 +212,6 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fscanf
libc.src.stdio.vfscanf
libc.src.stdio.printf
- libc.src.stdio.iprintf
libc.src.stdio.remove
libc.src.stdio.rename
libc.src.stdio.scanf
@@ -228,6 +227,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.vsprintf
libc.src.stdio.vasprintf
+ # stdio.h hidden entrypoints
+ libc.src.stdio.iprintf
+ libc.src.stdio.fiprintf
+ libc.src.stdio.siprintf
+ libc.src.stdio.sniprintf
+
# sys/epoll.h entrypoints
libc.src.sys.epoll.epoll_create
libc.src.sys.epoll.epoll_create1
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 4456e9cb3ad16b..42b1bded7dd9b0 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -195,6 +195,30 @@ add_entrypoint_object(
libc.src.stdio.printf_core.writer
)
+add_entrypoint_object(
+ siprintf
+ SRCS
+ siprintf.cpp
+ HDRS
+ siprintf.h
+ DEPENDS
+ libc.src.stdio.printf_core.printf_main_nofloat
+ libc.src.stdio.printf_core.writer
+)
+
+# technically clang doesn't yet support sniprintf, so I could rename it to the
+# objectively cooler (and more accurate) sinprintf. Alas I chose not to.
+add_entrypoint_object(
+ sniprintf
+ SRCS
+ sniprintf.cpp
+ HDRS
+ sniprintf.h
+ DEPENDS
+ libc.src.stdio.printf_core.printf_main_nofloat
+ libc.src.stdio.printf_core.writer
+)
+
add_entrypoint_object(
asprintf
SRCS
@@ -288,6 +312,7 @@ add_stdio_entrypoint_object(putchar)
add_stdio_entrypoint_object(printf)
add_stdio_entrypoint_object(iprintf)
add_stdio_entrypoint_object(fprintf)
+add_stdio_entrypoint_object(fiprintf)
add_stdio_entrypoint_object(fgetc)
add_stdio_entrypoint_object(fgetc_unlocked)
add_stdio_entrypoint_object(getc)
diff --git a/libc/src/stdio/fiprintf.h b/libc/src/stdio/fiprintf.h
new file mode 100644
index 00000000000000..4e210f7cf8908d
--- /dev/null
+++ b/libc/src/stdio/fiprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of fiprintf -----------------------*- 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_FIPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_FIPRINTF_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int fiprintf(::FILE *__restrict stream, const char *__restrict format, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_FIPRINTF_H
diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt
index 250d0ec58a12fc..f32cc22a72a0f8 100644
--- a/libc/src/stdio/generic/CMakeLists.txt
+++ b/libc/src/stdio/generic/CMakeLists.txt
@@ -375,13 +375,28 @@ if(LLVM_LIBC_FULL_BUILD)
)
endif()
+# Copy the deps for fiprintf_deps
+set(fiprintf_deps ${fprintf_deps})
+
+list(APPEND fprintf_deps
+ libc.src.stdio.printf_core.vfprintf_internal
+)
+
+list(APPEND fiprintf_deps
+ libc.src.stdio.printf_core.vfprintf_internal_nofloat
+)
+
# Copy the deps for printf_deps
set(printf_deps ${fprintf_deps})
+set(iprintf_deps ${fiprintf_deps})
if(LLVM_LIBC_FULL_BUILD)
list(APPEND printf_deps
libc.src.__support.File.platform_stdout
)
+ list(APPEND iprintf_deps
+ libc.src.__support.File.platform_stdout
+ )
endif()
add_entrypoint_object(
@@ -392,19 +407,6 @@ add_entrypoint_object(
../printf.h
DEPENDS
${printf_deps}
- libc.src.stdio.printf_core.vfprintf_internal
-)
-
-# the printf variant with no floats is called iprintf for some reason
-add_entrypoint_object(
- iprintf
- SRCS
- iprintf.cpp
- HDRS
- ../iprintf.h
- DEPENDS
- ${printf_deps}
- libc.src.stdio.printf_core.vfprintf_internal_nofloat
)
add_entrypoint_object(
@@ -415,7 +417,6 @@ add_entrypoint_object(
../vprintf.h
DEPENDS
${printf_deps}
- libc.src.stdio.printf_core.vfprintf_internal
)
add_entrypoint_object(
@@ -426,7 +427,6 @@ add_entrypoint_object(
../fprintf.h
DEPENDS
${fprintf_deps}
- libc.src.stdio.printf_core.vfprintf_internal
)
add_entrypoint_object(
@@ -437,7 +437,30 @@ add_entrypoint_object(
../vfprintf.h
DEPENDS
${fprintf_deps}
- libc.src.stdio.printf_core.vfprintf_internal
+)
+
+# the printf variant with no floats is called iprintf for some reason. Idk ask XMOS
+add_entrypoint_object(
+ iprintf
+ SRCS
+ iprintf.cpp
+ HDRS
+ ../iprintf.h
+ DEPENDS
+ ${iprintf_deps}
+)
+
+# Similarly I'm unclear why the "i" modifier goes after the target modifier but w/e.
+# Oldest commit I could find mentioning it dates from 2011:
+# https://github.com/llvm/llvm-project/commit/2dfb888392d4d82f467dfc8c9c4d2192cd71afb6
+add_entrypoint_object(
+ fiprintf
+ SRCS
+ fiprintf.cpp
+ HDRS
+ ../fiprintf.h
+ DEPENDS
+ ${fiprintf_deps}
)
add_entrypoint_object(
diff --git a/libc/src/stdio/generic/fiprintf.cpp b/libc/src/stdio/generic/fiprintf.cpp
new file mode 100644
index 00000000000000..6f1223f33977da
--- /dev/null
+++ b/libc/src/stdio/generic/fiprintf.cpp
@@ -0,0 +1,34 @@
+//===-- Implementation of fiprintf ------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fiprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include "hdr/types/FILE.h"
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fiprintf,
+ (::FILE *__restrict stream, const char *__restrict format,
+ ...)) {
+ va_list vlist;
+ va_start(vlist, format);
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ va_end(vlist);
+ int ret_val = printf_core::vfprintf_internal(stream, format, args);
+ return ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index d8489e8dcf1cf7..c62c45fe90af14 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -86,76 +86,70 @@ add_object_library(
libc.src.string.memory_utils.inline_memset
)
+list(APPEND printf_converter_deps_nofloat
+ .core_structs
+ .writer
+ libc.src.__support.big_int
+ libc.src.__support.common
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.span
+ libc.src.__support.CPP.string_view
+ libc.src.__support.integer_to_string
+ libc.src.__support.libc_assert
+ libc.src.__support.uint128
+ libc.src.__support.StringUtil.error_to_string
+)
+
+list(APPEND printf_converter_hdrs_nofloat
+ converter_atlas.h
+ converter_utils.h
+ string_converter.h
+ char_converter.h
+ int_converter.h
+ ptr_converter.h
+ write_int_converter.h
+ fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
+ strerror_converter.h
+)
+
+set(printf_converter_deps ${printf_converter_deps_nofloat})
+set(printf_converter_hdrs ${printf_converter_hdrs_nofloat})
+
+list(APPEND printf_converter_deps
+ libc.src.__support.float_to_string
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.rounding_mode
+)
+
+list(APPEND printf_converter_hdrs
+ float_inf_nan_converter.h
+ float_hex_converter.h
+ float_dec_converter.h
+)
+
add_object_library(
converter
SRCS
converter.cpp
HDRS
converter.h
- converter_atlas.h
- converter_utils.h
- string_converter.h
- char_converter.h
- int_converter.h
- ptr_converter.h
- write_int_converter.h
- float_inf_nan_converter.h
- float_hex_converter.h
- float_dec_converter.h
- fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
- strerror_converter.h
+ ${printf_converter_hdrs}
DEPENDS
- .core_structs
.printf_config
- .writer
- libc.src.__support.big_int
- libc.src.__support.common
- libc.src.__support.CPP.limits
- libc.src.__support.CPP.span
- libc.src.__support.CPP.string_view
- libc.src.__support.float_to_string
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.rounding_mode
- libc.src.__support.integer_to_string
- libc.src.__support.libc_assert
- libc.src.__support.uint128
- libc.src.__support.StringUtil.error_to_string
+ ${printf_converter_deps}
)
-
add_object_library(
converter_nofloat
SRCS
converter.cpp
HDRS
converter.h
- converter_atlas.h
- converter_utils.h
- string_converter.h
- char_converter.h
- int_converter.h
- ptr_converter.h
- write_int_converter.h
- fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
- strerror_converter.h
+ ${printf_converter_hdrs_nofloat}
DEPENDS
- .core_structs
.printf_config_nofloat
- .writer
- libc.src.__support.big_int
- libc.src.__support.common
- libc.src.__support.CPP.limits
- libc.src.__support.CPP.span
- libc.src.__support.CPP.string_view
- libc.src.__support.float_to_string
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.rounding_mode
- libc.src.__support.integer_to_string
- libc.src.__support.libc_assert
- libc.src.__support.uint128
- libc.src.__support.StringUtil.error_to_string
+ ${printf_converter_deps_nofloat}
)
add_object_library(
diff --git a/libc/src/stdio/siprintf.cpp b/libc/src/stdio/siprintf.cpp
new file mode 100644
index 00000000000000..9f78581ec9451f
--- /dev/null
+++ b/libc/src/stdio/siprintf.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of siprintf ------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/siprintf.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, siprintf,
+ (char *__restrict buffer, const char *__restrict format,
+ ...)) {
+ va_list vlist;
+ va_start(vlist, format);
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ va_end(vlist);
+
+ printf_core::WriteBuffer wb(buffer, cpp::numeric_limits<size_t>::max());
+ printf_core::Writer writer(&wb);
+
+ int ret_val = printf_core::printf_main(&writer, format, args);
+ wb.buff[wb.buff_cur] = '\0';
+ return ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/siprintf.h b/libc/src/stdio/siprintf.h
new file mode 100644
index 00000000000000..9d7b389c7fd9a8
--- /dev/null
+++ b/libc/src/stdio/siprintf.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of siprintf -----------------------*- 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_SIPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_SIPRINTF_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int siprintf(char *__restrict buffer, const char *__restrict format, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_SIPRINTF_H
diff --git a/libc/src/stdio/sniprintf.cpp b/libc/src/stdio/sniprintf.cpp
new file mode 100644
index 00000000000000..45c7e9f50bb983
--- /dev/null
+++ b/libc/src/stdio/sniprintf.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of sniprintf -----------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/sniprintf.h"
+
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sniprintf,
+ (char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, ...)) {
+ va_list vlist;
+ va_start(vlist, format);
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ va_end(vlist);
+ printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::Writer writer(&wb);
+
+ int ret_val = printf_core::printf_main(&writer, format, args);
+ if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
+ wb.buff[wb.buff_cur] = '\0';
+ return ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/sniprintf.h b/libc/src/stdio/sniprintf.h
new file mode 100644
index 00000000000000..589b0a6b0ae116
--- /dev/null
+++ b/libc/src/stdio/sniprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of sniprintf ----------------------*- 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_SNIPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_SNIPRINTF_H
+
+#include "src/__support/macros/config.h"
+#include <stddef.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sniprintf(char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_SNIPRINTF_H
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index a4e166fd7beec9..cf4c1c319ebd6f 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -147,6 +147,16 @@ add_fp_unittest(
${sprintf_test_copts}
)
+add_libc_test(
+ siprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ siprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.siprintf
+)
+
add_libc_test(
snprintf_test
SUITE
@@ -157,6 +167,16 @@ add_libc_test(
libc.src.stdio.snprintf
)
+add_libc_test(
+ sniprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ sniprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.sniprintf
+)
+
if(LLVM_LIBC_FULL_BUILD)
# In fullbuild mode, fprintf's tests use the internal FILE for other functions.
list(APPEND fprintf_test_deps
@@ -208,6 +228,19 @@ add_libc_test(
libc.src.stdio.iprintf
)
+add_libc_test(
+ fiprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ fiprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.fiprintf
+ ${fprintf_test_deps}
+ COMPILE_OPTIONS
+ ${use_system_file}
+)
+
add_libc_test(
asprintf_test
SUITE
diff --git a/libc/test/src/stdio/fiprintf_test.cpp b/libc/test/src/stdio/fiprintf_test.cpp
new file mode 100644
index 00000000000000..ea6046f1ea51bd
--- /dev/null
+++ b/libc/test/src/stdio/fiprintf_test.cpp
@@ -0,0 +1,92 @@
+//===-- Unittests for fiprintf --------------------------------------------===//
+//
+// 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 LIBC_COPT_STDIO_USE_SYSTEM_FILE
+#include "src/stdio/fclose.h"
+#include "src/stdio/ferror.h"
+#include "src/stdio/fopen.h"
+#include "src/stdio/fread.h"
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+
+#include "src/stdio/fiprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+namespace printf_test {
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+using LIBC_NAMESPACE::fclose;
+using LIBC_NAMESPACE::ferror;
+using LIBC_NAMESPACE::fopen;
+using LIBC_NAMESPACE::fread;
+#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
+using ::fclose;
+using ::ferror;
+using ::fopen;
+using ::fread;
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+} // namespace printf_test
+
+TEST(LlvmLibcFIPrintfTest, WriteToFile) {
+ const char *FILENAME = "fiprintf_output.test";
+ auto FILE_PATH = libc_make_test_file_path(FILENAME);
+
+ ::FILE *file = printf_test::fopen(FILE_PATH, "w");
+ ASSERT_FALSE(file == nullptr);
+
+ int written;
+
+ constexpr char simple[] = "A simple string with no conversions.\n";
+ written = LIBC_NAMESPACE::fiprintf(file, simple);
+ EXPECT_EQ(written, 37);
+
+ constexpr char numbers[] = "1234567890\n";
+ written = LIBC_NAMESPACE::fiprintf(file, "%s", numbers);
+ EXPECT_EQ(written, 11);
+
+ constexpr char format_more[] = "%s and more\n";
+ constexpr char short_numbers[] = "1234";
+ written = LIBC_NAMESPACE::fiprintf(file, format_more, short_numbers);
+ EXPECT_EQ(written, 14);
+
+ constexpr char format_float[] = "%f doesn't work\n";
+ written = LIBC_NAMESPACE::fiprintf(file, format_float, 1.0);
+ EXPECT_EQ(written, static_cast<int>(sizeof(format_float) - 1));
+
+ ASSERT_EQ(0, printf_test::fclose(file));
+
+ file = printf_test::fopen(FILE_PATH, "r");
+ ASSERT_FALSE(file == nullptr);
+
+ char data[50];
+ ASSERT_EQ(printf_test::fread(data, 1, sizeof(simple) - 1, file),
+ sizeof(simple) - 1);
+ data[sizeof(simple) - 1] = '\0';
+ ASSERT_STREQ(data, simple);
+ ASSERT_EQ(printf_test::fread(data, 1, sizeof(numbers) - 1, file),
+ sizeof(numbers) - 1);
+ data[sizeof(numbers) - 1] = '\0';
+ ASSERT_STREQ(data, numbers);
+ ASSERT_EQ(printf_test::fread(
+ data, 1, sizeof(format_more) + sizeof(short_numbers) - 4, file),
+ sizeof(format_more) + sizeof(short_numbers) - 4);
+ data[sizeof(format_more) + sizeof(short_numbers) - 4] = '\0';
+ ASSERT_STREQ(data, "1234 and more\n");
+
+ ASSERT_EQ(printf_test::fread(data, 1, sizeof(format_float) - 1, file),
+ sizeof(format_float) - 1);
+ data[sizeof(format_float) - 1] = '\0';
+ ASSERT_STREQ(data, "%f doesn't work\n");
+
+ ASSERT_EQ(printf_test::ferror(file), 0);
+
+ written = LIBC_NAMESPACE::fiprintf(
+ file, "Writing to a read only file should fail.");
+ EXPECT_LT(written, 0);
+
+ ASSERT_EQ(printf_test::fclose(file), 0);
+}
diff --git a/libc/test/src/stdio/siprintf_test.cpp b/libc/test/src/stdio/siprintf_test.cpp
new file mode 100644
index 00000000000000..1bfed210dc3856
--- /dev/null
+++ b/libc/test/src/stdio/siprintf_test.cpp
@@ -0,0 +1,38 @@
+//===-- Unittests for siprintf --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/siprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcSIPrintfTest, SimpleParsing) {
+ char buff[100];
+ int written;
+
+ constexpr char simple[] = "A simple string with no conversions.";
+ written = LIBC_NAMESPACE::siprintf(buff, simple);
+ EXPECT_EQ(written, static_cast<int>(sizeof(simple) - 1));
+ ASSERT_STREQ(buff, simple);
+
+ constexpr char numbers[] = "1234567890";
+ written = LIBC_NAMESPACE::siprintf(buff, "%s", numbers);
+ EXPECT_EQ(written, static_cast<int>(sizeof(numbers) - 1));
+ ASSERT_STREQ(buff, numbers);
+
+ constexpr char format_more[] = "%s and more";
+ constexpr char short_numbers[] = "1234";
+ written = LIBC_NAMESPACE::siprintf(buff, format_more, short_numbers);
+ EXPECT_EQ(written,
+ static_cast<int>(sizeof(format_more) + sizeof(short_numbers) - 4));
+ ASSERT_STREQ(buff, "1234 and more");
+
+ constexpr char format_float[] = "%f doesn't work\n";
+ written = LIBC_NAMESPACE::siprintf(buff, format_float, 1.0);
+ EXPECT_EQ(written, static_cast<int>(sizeof(format_float) - 1));
+ ASSERT_STREQ(buff, format_float);
+}
diff --git a/libc/test/src/stdio/sniprintf_test.cpp b/libc/test/src/stdio/sniprintf_test.cpp
new file mode 100644
index 00000000000000..7ec7aee57653b5
--- /dev/null
+++ b/libc/test/src/stdio/sniprintf_test.cpp
@@ -0,0 +1,66 @@
+//===-- Unittests for sniprintf -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/sniprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+// The sprintf test cases cover testing the shared printf functionality, so
+// these tests will focus on sniprintf exclusive features.
+
+TEST(LlvmLibcSNIPrintfTest, CutOff) {
+ char buff[100];
+ int written;
+
+ written = LIBC_NAMESPACE::sniprintf(buff, 16,
+ "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string");
+
+ written = LIBC_NAMESPACE::sniprintf(buff, 5, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234");
+
+ written = LIBC_NAMESPACE::sniprintf(buff, 67, "%-101c", 'a');
+ EXPECT_EQ(written, 101);
+ ASSERT_STREQ(buff, "a "
+ " " // Each of these is 8 spaces, and there are 8.
+ " " // In total there are 65 spaces
+ " " // 'a' + 65 spaces + '\0' = 67
+ " "
+ " "
+ " "
+ " "
+ " ");
+
+ written =
+ LIBC_NAMESPACE::sniprintf(buff, 10, "%f before and %f after", 1.0, 2.0);
+ EXPECT_EQ(written, 22);
+ ASSERT_STREQ(buff, "%f before");
+
+ // passing null as the output pointer is allowed as long as buffsz is 0.
+ written = LIBC_NAMESPACE::sniprintf(nullptr, 0, "%s and more", "1234567890");
+ EXPECT_EQ(written, 19);
+
+ written = LIBC_NAMESPACE::sniprintf(nullptr, 0, "%*s", INT_MIN, "nothing");
+ EXPECT_EQ(written, INT_MAX);
+}
+
+TEST(LlvmLibcSNIPrintfTest, NoCutOff) {
+ char buff[64];
+ int written;
+
+ written = LIBC_NAMESPACE::sniprintf(buff, 37,
+ "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string with no conversions.");
+
+ written = LIBC_NAMESPACE::sniprintf(buff, 20, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234567890");
+}
More information about the libc-commits
mailing list