[libc-commits] [libc] 16d5c24 - [libc] Add v variants of printf functions
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Fri Aug 4 14:50:29 PDT 2023
Author: Michael Jones
Date: 2023-08-04T14:50:24-07:00
New Revision: 16d5c242261832a4bff3de482bd16bd03389fb6d
URL: https://github.com/llvm/llvm-project/commit/16d5c242261832a4bff3de482bd16bd03389fb6d
DIFF: https://github.com/llvm/llvm-project/commit/16d5c242261832a4bff3de482bd16bd03389fb6d.diff
LOG: [libc] Add v variants of printf functions
The v variants of the printf functions take their variadic arguments as
a va_list instead of as individual arguments. They are otherwise
identical to the corresponding printf variants. This patch adds them
(vprintf, vfprintf, vsprintf, and vsnprintf) as well as tests.
Reviewed By: phosek
Differential Revision: https://reviews.llvm.org/D157138
Added:
libc/src/stdio/vfprintf.cpp
libc/src/stdio/vfprintf.h
libc/src/stdio/vprintf.cpp
libc/src/stdio/vprintf.h
libc/src/stdio/vsnprintf.cpp
libc/src/stdio/vsnprintf.h
libc/src/stdio/vsprintf.cpp
libc/src/stdio/vsprintf.h
libc/test/src/stdio/vfprintf_test.cpp
libc/test/src/stdio/vprintf_test.cpp
libc/test/src/stdio/vsnprintf_test.cpp
libc/test/src/stdio/vsprintf_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv64/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/stdio.h.def
libc/spec/spec.td
libc/spec/stdc.td
libc/src/stdio/CMakeLists.txt
libc/test/src/stdio/CMakeLists.txt
utils/bazel/llvm-project-overlay/libc/BUILD.bazel
utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index f807d0745bfc1d..46676df5c2d292 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.remove
libc.src.stdio.sprintf
libc.src.stdio.snprintf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vsnprintf
# sys/mman.h entrypoints
libc.src.sys.mman.madvise
@@ -405,10 +407,13 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdio.funlockfile
libc.src.stdio.fwrite
libc.src.stdio.fwrite_unlocked
- libc.src.stdio.fprintf
libc.src.stdio.getchar
libc.src.stdio.getchar_unlocked
+ #TODO: Look into if fprintf can be enabled for overlay on aarch64
+ libc.src.stdio.fprintf
libc.src.stdio.printf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vprintf
libc.src.stdio.putc
libc.src.stdio.putchar
libc.src.stdio.puts
diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt
index 7884993d2c8972..d6933c909a66a8 100644
--- a/libc/config/linux/riscv64/entrypoints.txt
+++ b/libc/config/linux/riscv64/entrypoints.txt
@@ -128,6 +128,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.snprintf
libc.src.stdio.fprintf
libc.src.stdio.printf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vsnprintf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vprintf
# sys/mman.h entrypoints
libc.src.sys.mman.madvise
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index fbef1cfda65670..28cdd8a44f1179 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -128,6 +128,10 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.snprintf
libc.src.stdio.fprintf
libc.src.stdio.printf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vsnprintf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vprintf
# sys/mman.h entrypoints
libc.src.sys.mman.madvise
diff --git a/libc/include/stdio.h.def b/libc/include/stdio.h.def
index 5eb0e98809603d..a28d009288d5a6 100644
--- a/libc/include/stdio.h.def
+++ b/libc/include/stdio.h.def
@@ -13,6 +13,8 @@
#include <llvm-libc-macros/file-seek-macros.h>
#include <llvm-libc-macros/stdio-macros.h>
+#include <stdarg.h>
+
%%public_api()
#endif // LLVM_LIBC_STDIO_H
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index 2336754c5d030a..ac0fba3bd0af78 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -37,6 +37,7 @@ class RestrictedPtrType<Type type> : Type {
// Builtin types.
def VarArgType : NamedType<"...">;
+def VaListType : NamedType<"va_list">;
def VoidType : NamedType<"void">;
def IntType : NamedType<"int">;
def UnsignedIntType : NamedType<"unsigned int">;
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index cbb3015d0f0c4c..96668ccb5558b5 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -698,6 +698,34 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
+ FunctionSpec<
+ "vsprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<CharRestrictedPtr>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
+ FunctionSpec<
+ "vsnprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<CharRestrictedPtr>,
+ ArgSpec<SizeTType>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
+ FunctionSpec<
+ "vprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
+ FunctionSpec<
+ "vfprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<FILERestrictedPtr>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
FunctionSpec<
"ungetc",
RetValSpec<IntType>,
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index df0933fcce510b..6cd4f2c1c5f5f9 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -542,6 +542,53 @@ add_entrypoint_object(
${printf_copts}
)
+add_entrypoint_object(
+ vsprintf
+ SRCS
+ vsprintf.cpp
+ HDRS
+ vsprintf.h
+ DEPENDS
+ libc.src.stdio.printf_core.printf_main
+ libc.src.stdio.printf_core.writer
+)
+
+add_entrypoint_object(
+ vsnprintf
+ SRCS
+ vsnprintf.cpp
+ HDRS
+ vsnprintf.h
+ DEPENDS
+ libc.src.stdio.printf_core.printf_main
+ libc.src.stdio.printf_core.writer
+)
+
+add_entrypoint_object(
+ vprintf
+ SRCS
+ vprintf.cpp
+ HDRS
+ vprintf.h
+ DEPENDS
+ ${printf_deps}
+ COMPILE_OPTIONS
+ ${printf_copts}
+)
+
+add_entrypoint_object(
+ vfprintf
+ SRCS
+ vfprintf.cpp
+ HDRS
+ vfprintf.h
+ DEPENDS
+ libc.src.__support.arg_list
+ libc.src.stdio.printf_core.vfprintf_internal
+ COMPILE_OPTIONS
+ ${printf_copts}
+)
+
add_entrypoint_object(
ftell
SRCS
diff --git a/libc/src/stdio/vfprintf.cpp b/libc/src/stdio/vfprintf.cpp
new file mode 100644
index 00000000000000..aa56c26b46d6a2
--- /dev/null
+++ b/libc/src/stdio/vfprintf.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of vfprintf ------------------------------*- 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/vfprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vfprintf,
+ (::FILE *__restrict stream, const char *__restrict format,
+ va_list vlist)) {
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ int ret_val = printf_core::vfprintf_internal(stream, format, args);
+ return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vfprintf.h b/libc/src/stdio/vfprintf.h
new file mode 100644
index 00000000000000..b4a2d5e24042c6
--- /dev/null
+++ b/libc/src/stdio/vfprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of vfprintf -----------------------*- 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_VFPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VFPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int vfprintf(::FILE *__restrict stream, const char *__restrict format,
+ va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VFPRINTF_H
diff --git a/libc/src/stdio/vprintf.cpp b/libc/src/stdio/vprintf.cpp
new file mode 100644
index 00000000000000..d38bf4fecfc07d
--- /dev/null
+++ b/libc/src/stdio/vprintf.cpp
@@ -0,0 +1,36 @@
+//===-- Implementation of vprintf -------------------------------*- 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/vprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifndef LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+#define PRINTF_STDOUT __llvm_libc::stdout
+#else // LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+#define PRINTF_STDOUT ::stdout
+#endif // LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vprintf,
+ (const char *__restrict format, va_list vlist)) {
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ int ret_val = printf_core::vfprintf_internal(
+ reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
+ return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vprintf.h b/libc/src/stdio/vprintf.h
new file mode 100644
index 00000000000000..ffc5d39eaede89
--- /dev/null
+++ b/libc/src/stdio/vprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of vprintf ------------------------*- 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_VPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int vprintf(const char *__restrict format, va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VPRINTF_H
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
new file mode 100644
index 00000000000000..0dc34a83fd441d
--- /dev/null
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -0,0 +1,35 @@
+//===-- Implementation of vsnprintf -----------------------------*- 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/vsnprintf.h"
+
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vsnprintf,
+ (char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, va_list vlist)) {
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+ 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 __llvm_libc
diff --git a/libc/src/stdio/vsnprintf.h b/libc/src/stdio/vsnprintf.h
new file mode 100644
index 00000000000000..caa381e8383ad1
--- /dev/null
+++ b/libc/src/stdio/vsnprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of vsnprintf ----------------------*- 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_VSNPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VSNPRINTF_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+int vsnprintf(char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VSNPRINTF_H
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
new file mode 100644
index 00000000000000..cf86f92ced4c31
--- /dev/null
+++ b/libc/src/stdio/vsprintf.cpp
@@ -0,0 +1,35 @@
+//===-- Implementation of vsprintf ------------------------------*- 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/vsprintf.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vsprintf,
+ (char *__restrict buffer, const char *__restrict format,
+ va_list vlist)) {
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+
+ 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 __llvm_libc
diff --git a/libc/src/stdio/vsprintf.h b/libc/src/stdio/vsprintf.h
new file mode 100644
index 00000000000000..a129a2a420c2b8
--- /dev/null
+++ b/libc/src/stdio/vsprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of vsprintf -----------------------*- 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_VSPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VSPRINTF_H
+
+#include <stdarg.h>
+
+namespace __llvm_libc {
+
+int vsprintf(char *__restrict buffer, const char *__restrict format,
+ va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VSPRINTF_H
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 6e9267e7190cf9..af87aa96059bca 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -135,9 +135,6 @@ add_libc_unittest(
libc.src.stdio.snprintf
)
-list(APPEND fprintf_test_deps
- libc.src.stdio.fprintf
-)
if(LLVM_LIBC_FULL_BUILD)
# In fullbuild mode, fprintf's tests use the internal FILE for other functions.
list(APPEND fprintf_test_deps
@@ -158,6 +155,7 @@ add_libc_unittest(
SRCS
fprintf_test.cpp
DEPENDS
+ libc.src.stdio.fprintf
${fprintf_test_deps}
COMPILE_OPTIONS
${fprintf_test_copts}
@@ -173,6 +171,50 @@ add_libc_unittest(
libc.src.stdio.printf
)
+add_fp_unittest(
+ vsprintf_test
+ UNIT_TEST_ONLY
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vsprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.vsprintf
+)
+
+add_libc_unittest(
+ vsnprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vsnprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.vsnprintf
+)
+
+add_libc_unittest(
+ vfprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vfprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.vfprintf
+ ${fprintf_test_deps}
+ COMPILE_OPTIONS
+ ${fprintf_test_copts}
+)
+
+add_libc_unittest(
+ vprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.vprintf
+)
+
add_libc_unittest(
fscanf_test
SUITE
diff --git a/libc/test/src/stdio/vfprintf_test.cpp b/libc/test/src/stdio/vfprintf_test.cpp
new file mode 100644
index 00000000000000..d7c5eb8292e5b5
--- /dev/null
+++ b/libc/test/src/stdio/vfprintf_test.cpp
@@ -0,0 +1,97 @@
+//===-- Unittests for vfprintf --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// These tests are copies of the non-v variants of the printf functions. This is
+// because these functions are identical in every way except for how the varargs
+// are passed.
+
+#ifndef LIBC_COPT_PRINTF_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_PRINTF_USE_SYSTEM_FILE
+
+#include "src/stdio/vfprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+#include <stdio.h>
+
+namespace printf_test {
+#ifndef LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+using __llvm_libc::fclose;
+using __llvm_libc::ferror;
+using __llvm_libc::fopen;
+using __llvm_libc::fread;
+#else // defined(LIBC_COPT_PRINTF_USE_SYSTEM_FILE)
+using ::fclose;
+using ::ferror;
+using ::fopen;
+using ::fread;
+#endif // LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+} // namespace printf_test
+
+int call_vfprintf(::FILE *__restrict stream, const char *__restrict format,
+ ...) {
+ va_list vlist;
+ va_start(vlist, format);
+ int ret = __llvm_libc::vfprintf(stream, format, vlist);
+ va_end(vlist);
+ return ret;
+}
+
+TEST(LlvmLibcVFPrintfTest, WriteToFile) {
+ const char *FILENAME = "fprintf_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 = call_vfprintf(file, simple);
+ EXPECT_EQ(written, 37);
+
+ constexpr char numbers[] = "1234567890\n";
+ written = call_vfprintf(file, "%s", numbers);
+ EXPECT_EQ(written, 11);
+
+ constexpr char format_more[] = "%s and more\n";
+ constexpr char short_numbers[] = "1234";
+ written = call_vfprintf(file, format_more, short_numbers);
+ EXPECT_EQ(written, 14);
+
+ 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::ferror(file), 0);
+
+ written = call_vfprintf(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/vprintf_test.cpp b/libc/test/src/stdio/vprintf_test.cpp
new file mode 100644
index 00000000000000..0710bbffe5b137
--- /dev/null
+++ b/libc/test/src/stdio/vprintf_test.cpp
@@ -0,0 +1,41 @@
+//===-- Unittests for vprintf --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// These tests are copies of the non-v variants of the printf functions. This is
+// because these functions are identical in every way except for how the varargs
+// are passed.
+
+#include "src/stdio/vprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+int call_vprintf(const char *__restrict format, ...) {
+ va_list vlist;
+ va_start(vlist, format);
+ int ret = __llvm_libc::vprintf(format, vlist);
+ va_end(vlist);
+ return ret;
+}
+
+TEST(LlvmLibcVPrintfTest, PrintOut) {
+ int written;
+
+ constexpr char simple[] = "A simple string with no conversions.\n";
+ written = call_vprintf(simple);
+ EXPECT_EQ(written, static_cast<int>(sizeof(simple) - 1));
+
+ constexpr char numbers[] = "1234567890\n";
+ written = call_vprintf("%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 = call_vprintf(format_more, short_numbers);
+ EXPECT_EQ(written,
+ static_cast<int>(sizeof(format_more) + sizeof(short_numbers) - 4));
+}
diff --git a/libc/test/src/stdio/vsnprintf_test.cpp b/libc/test/src/stdio/vsnprintf_test.cpp
new file mode 100644
index 00000000000000..08f10708b8dca3
--- /dev/null
+++ b/libc/test/src/stdio/vsnprintf_test.cpp
@@ -0,0 +1,69 @@
+//===-- Unittests for snprintf --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// These tests are copies of the non-v variants of the printf functions. This is
+// because these functions are identical in every way except for how the varargs
+// are passed.
+
+#include "src/stdio/vsnprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+int call_vsnprintf(char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, ...) {
+ va_list vlist;
+ va_start(vlist, format);
+ int ret = __llvm_libc::vsnprintf(buffer, buffsz, format, vlist);
+ va_end(vlist);
+ return ret;
+}
+
+// The sprintf test cases cover testing the shared printf functionality, so
+// these tests will focus on snprintf exclusive features.
+
+TEST(LlvmLibcVSNPrintfTest, CutOff) {
+ char buff[100];
+ int written;
+
+ written = call_vsnprintf(buff, 16, "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string");
+
+ written = call_vsnprintf(buff, 5, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234");
+
+ written = call_vsnprintf(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
+ " "
+ " "
+ " "
+ " "
+ " ");
+
+ // passing null as the output pointer is allowed as long as buffsz is 0.
+ written = call_vsnprintf(nullptr, 0, "%s and more", "1234567890");
+ EXPECT_EQ(written, 19);
+}
+
+TEST(LlvmLibcVSNPrintfTest, NoCutOff) {
+ char buff[64];
+ int written;
+
+ written = call_vsnprintf(buff, 37, "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string with no conversions.");
+
+ written = call_vsnprintf(buff, 20, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234567890");
+}
diff --git a/libc/test/src/stdio/vsprintf_test.cpp b/libc/test/src/stdio/vsprintf_test.cpp
new file mode 100644
index 00000000000000..3f0551a877f60c
--- /dev/null
+++ b/libc/test/src/stdio/vsprintf_test.cpp
@@ -0,0 +1,66 @@
+//===-- Unittests for vsprintf --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// These tests are shortened copies of the non-v variants of the printf
+// functions. This is because these functions are identical in every way except
+// for how the varargs are passed.
+
+#include "src/stdio/vsprintf.h"
+
+#include "test/UnitTest/Test.h"
+
+int call_vsprintf(char *__restrict buffer, const char *__restrict format, ...) {
+ va_list vlist;
+ va_start(vlist, format);
+ int ret = __llvm_libc::vsprintf(buffer, format, vlist);
+ va_end(vlist);
+ return ret;
+}
+
+TEST(LlvmLibcVSPrintfTest, SimpleNoConv) {
+ char buff[64];
+ int written;
+
+ written = call_vsprintf(buff, "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string with no conversions.");
+}
+
+TEST(LlvmLibcVSPrintfTest, PercentConv) {
+ char buff[64];
+ int written;
+
+ written = call_vsprintf(buff, "%%");
+ EXPECT_EQ(written, 1);
+ ASSERT_STREQ(buff, "%");
+
+ written = call_vsprintf(buff, "abc %% def");
+ EXPECT_EQ(written, 9);
+ ASSERT_STREQ(buff, "abc % def");
+
+ written = call_vsprintf(buff, "%%%%%%");
+ EXPECT_EQ(written, 3);
+ ASSERT_STREQ(buff, "%%%");
+}
+
+TEST(LlvmLibcVSPrintfTest, CharConv) {
+ char buff[64];
+ int written;
+
+ written = call_vsprintf(buff, "%c", 'a');
+ EXPECT_EQ(written, 1);
+ ASSERT_STREQ(buff, "a");
+
+ written = call_vsprintf(buff, "%3c %-3c", '1', '2');
+ EXPECT_EQ(written, 7);
+ ASSERT_STREQ(buff, " 1 2 ");
+
+ written = call_vsprintf(buff, "%*c", 2, '3');
+ EXPECT_EQ(written, 2);
+ ASSERT_STREQ(buff, " 3");
+}
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 0ee3395260b5b6..2fbab7ae00a41b 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -2642,6 +2642,19 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "vfprintf_internal",
+ hdrs = ["src/stdio/printf_core/vfprintf_internal.h"],
+ defines = PRINTF_COPTS,
+ deps = [
+ ":__support_arg_list",
+ ":__support_file_file",
+ ":__support_macros_attributes",
+ ":printf_main",
+ ":printf_writer",
+ ],
+)
+
libc_function(
name = "sprintf",
srcs = ["src/stdio/sprintf.cpp"],
@@ -2669,23 +2682,63 @@ libc_function(
],
)
-libc_support_library(
- name = "vfprintf_internal",
- hdrs = ["src/stdio/printf_core/vfprintf_internal.h"],
+libc_function(
+ name = "printf",
+ srcs = ["src/stdio/printf.cpp"],
+ hdrs = ["src/stdio/printf.h"],
defines = PRINTF_COPTS,
deps = [
":__support_arg_list",
":__support_file_file",
- ":__support_macros_attributes",
+ ":errno",
+ ":vfprintf_internal",
+ ],
+)
+
+libc_function(
+ name = "fprintf",
+ srcs = ["src/stdio/fprintf.cpp"],
+ hdrs = ["src/stdio/fprintf.h"],
+ defines = PRINTF_COPTS,
+ deps = [
+ ":__support_arg_list",
+ ":__support_file_file",
+ ":errno",
+ ":vfprintf_internal",
+ ],
+)
+
+libc_function(
+ name = "vsprintf",
+ srcs = ["src/stdio/vsprintf.cpp"],
+ hdrs = ["src/stdio/vsprintf.h"],
+ defines = PRINTF_COPTS,
+ deps = [
+ ":__support_arg_list",
+ ":__support_cpp_limits",
+ ":errno",
":printf_main",
":printf_writer",
],
)
libc_function(
- name = "printf",
- srcs = ["src/stdio/printf.cpp"],
- hdrs = ["src/stdio/printf.h"],
+ name = "vsnprintf",
+ srcs = ["src/stdio/vsnprintf.cpp"],
+ hdrs = ["src/stdio/vsnprintf.h"],
+ defines = PRINTF_COPTS,
+ deps = [
+ ":__support_arg_list",
+ ":errno",
+ ":printf_main",
+ ":printf_writer",
+ ],
+)
+
+libc_function(
+ name = "vprintf",
+ srcs = ["src/stdio/vprintf.cpp"],
+ hdrs = ["src/stdio/vprintf.h"],
defines = PRINTF_COPTS,
deps = [
":__support_arg_list",
@@ -2696,9 +2749,9 @@ libc_function(
)
libc_function(
- name = "fprintf",
- srcs = ["src/stdio/fprintf.cpp"],
- hdrs = ["src/stdio/fprintf.h"],
+ name = "vfprintf",
+ srcs = ["src/stdio/vfprintf.cpp"],
+ hdrs = ["src/stdio/vfprintf.h"],
defines = PRINTF_COPTS,
deps = [
":__support_arg_list",
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel
index 46bef299013a2b..e25ed33b908f8d 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel
@@ -89,3 +89,35 @@ libc_test(
"//libc:fprintf",
],
)
+
+libc_test(
+ name = "vsprintf_test",
+ srcs = ["vsprintf_test.cpp"],
+ libc_function_deps = [
+ "//libc:vsprintf",
+ ],
+)
+
+libc_test(
+ name = "vsnprintf_test",
+ srcs = ["vsnprintf_test.cpp"],
+ libc_function_deps = [
+ "//libc:vsnprintf",
+ ],
+)
+
+libc_test(
+ name = "vprintf_test",
+ srcs = ["vprintf_test.cpp"],
+ libc_function_deps = [
+ "//libc:vprintf",
+ ],
+)
+
+libc_test(
+ name = "vfprintf_test",
+ srcs = ["vfprintf_test.cpp"],
+ libc_function_deps = [
+ "//libc:vfprintf",
+ ],
+)
More information about the libc-commits
mailing list