[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