[libc-commits] [libc] 9f1d905 - [libc] add snprintf
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Tue May 17 13:33:03 PDT 2022
Author: Michael Jones
Date: 2022-05-17T13:32:59-07:00
New Revision: 9f1d905f39ac7f32b1965b8062c0803955ccbd0f
URL: https://github.com/llvm/llvm-project/commit/9f1d905f39ac7f32b1965b8062c0803955ccbd0f
DIFF: https://github.com/llvm/llvm-project/commit/9f1d905f39ac7f32b1965b8062c0803955ccbd0f.diff
LOG: [libc] add snprintf
After adding sprintf, snprintf is simple. The functions are very
similar. The tests only cover the behavior of the max length since the
sprintf tests should cover the other behavior.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D125826
Added:
libc/src/stdio/snprintf.cpp
libc/src/stdio/snprintf.h
libc/test/src/stdio/snprintf_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/stdc.td
libc/src/stdio/CMakeLists.txt
libc/src/stdio/sprintf.cpp
libc/test/src/stdio/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d1edcd16c8356..da2e77e6516d2 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -269,6 +269,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdio.fwrite
libc.src.stdio.fwrite_unlocked
libc.src.stdio.sprintf
+ libc.src.stdio.snprintf
# signal.h entrypoints
# TODO: Enable signal.h entrypoints after fixing signal.h
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 3becf12dfc863..aa09bc36a25da 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -539,6 +539,27 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
+ FunctionSpec<
+ "snprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<CharRestrictedPtr>,
+ ArgSpec<SizeTType>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VarArgType>]
+ >,
+ FunctionSpec<
+ "printf",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VarArgType>]
+ >,
+ FunctionSpec<
+ "fprintf",
+ RetValSpec<IntType>,
+ [ArgSpec<FILERestrictedPtr>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VarArgType>]
+ >,
]
>;
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 9f64d18d4d1d9..2abb5091b1cb1 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -211,7 +211,18 @@ add_entrypoint_object(
HDRS
sprintf.h
DEPENDS
- libc.include.stdio
+ libc.src.stdio.printf_core.printf_main
+ libc.src.stdio.printf_core.string_writer
+ libc.src.stdio.printf_core.writer
+)
+
+add_entrypoint_object(
+ snprintf
+ SRCS
+ snprintf.cpp
+ HDRS
+ snprintf.h
+ DEPENDS
libc.src.stdio.printf_core.printf_main
libc.src.stdio.printf_core.string_writer
libc.src.stdio.printf_core.writer
diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp
new file mode 100644
index 0000000000000..ecc5fc94e6e8c
--- /dev/null
+++ b/libc/src/stdio/snprintf.cpp
@@ -0,0 +1,40 @@
+//===-- Implementation of snprintf ------------------------------*- 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/snprintf.h"
+
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/string_writer.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, snprintf,
+ (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::StringWriter str_writer(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::Writer writer(reinterpret_cast<void *>(&str_writer),
+ printf_core::write_to_string);
+
+ 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.
+ str_writer.terminate();
+ return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/snprintf.h b/libc/src/stdio/snprintf.h
new file mode 100644
index 0000000000000..ec223be0e7baa
--- /dev/null
+++ b/libc/src/stdio/snprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of snprintf -----------------------*- 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_SNPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_SNPRINTF_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+int snprintf(char *__restrict buffer, size_t buffsz,
+ const char *__restrict format, ...);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_SNPRINTF_H
diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp
index a05c431451a57..442dbdfb14d11 100644
--- a/libc/src/stdio/sprintf.cpp
+++ b/libc/src/stdio/sprintf.cpp
@@ -23,7 +23,7 @@ LLVM_LIBC_FUNCTION(int, sprintf,
va_list vlist;
va_start(vlist, format);
internal::ArgList args(vlist); // This holder class allows for easier copying
- // and pointer semantics, as well as handing
+ // and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
printf_core::StringWriter str_writer(buffer);
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index e9f458539d1f0..331b90f32162b 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -73,6 +73,16 @@ add_libc_unittest(
libc.src.stdio.sprintf
)
+add_libc_unittest(
+ snprintf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ snprintf_test.cpp
+ DEPENDS
+ libc.src.stdio.snprintf
+)
+
add_subdirectory(printf_core)
add_subdirectory(testdata)
diff --git a/libc/test/src/stdio/snprintf_test.cpp b/libc/test/src/stdio/snprintf_test.cpp
new file mode 100644
index 0000000000000..4930f37c4084c
--- /dev/null
+++ b/libc/test/src/stdio/snprintf_test.cpp
@@ -0,0 +1,46 @@
+//===-- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/snprintf.h"
+
+#include "utils/UnitTest/Test.h"
+
+// The sprintf test cases cover testing the shared printf functionality, so
+// these tests will focus on snprintf exclusive features.
+
+TEST(LlvmLibcSNPrintfTest, CutOff) {
+ char buff[64];
+ int written;
+
+ written =
+ __llvm_libc::snprintf(buff, 16, "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string");
+
+ written = __llvm_libc::snprintf(buff, 5, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234");
+
+ // passing null as the output pointer is allowed as long as buffsz is 0.
+ written = __llvm_libc::snprintf(nullptr, 0, "%s and more", "1234567890");
+ EXPECT_EQ(written, 19);
+}
+
+TEST(LlvmLibcSNPrintfTest, NoCutOff) {
+ char buff[64];
+ int written;
+
+ written =
+ __llvm_libc::snprintf(buff, 37, "A simple string with no conversions.");
+ EXPECT_EQ(written, 36);
+ ASSERT_STREQ(buff, "A simple string with no conversions.");
+
+ written = __llvm_libc::snprintf(buff, 20, "%s", "1234567890");
+ EXPECT_EQ(written, 10);
+ ASSERT_STREQ(buff, "1234567890");
+}
More information about the libc-commits
mailing list