[libc-commits] [libc] [libc] Implement 'vfscanf' and 'vscanf' (PR #105293)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Tue Aug 20 13:01:21 PDT 2024
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/105293
>From 795d5e3920638370a8c6e6b41b3021c6e599955a Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Tue, 20 Aug 2024 14:06:09 -0500
Subject: [PATCH] [libc] Implement 'vfscanf' and 'vscanf'
Summary:
These are simply forwarding the vlist to the existing helper.
---
libc/config/linux/aarch64/entrypoints.txt | 2 +
libc/config/linux/riscv/entrypoints.txt | 2 +
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/src/stdio/CMakeLists.txt | 20 +++++
libc/src/stdio/vfscanf.cpp | 34 ++++++++
libc/src/stdio/vfscanf.h | 24 ++++++
libc/src/stdio/vscanf.cpp | 40 +++++++++
libc/src/stdio/vscanf.h | 23 ++++++
libc/test/src/stdio/CMakeLists.txt | 14 ++++
libc/test/src/stdio/vfscanf_test.cpp | 98 +++++++++++++++++++++++
10 files changed, 259 insertions(+)
create mode 100644 libc/src/stdio/vfscanf.cpp
create mode 100644 libc/src/stdio/vfscanf.h
create mode 100644 libc/src/stdio/vscanf.cpp
create mode 100644 libc/src/stdio/vscanf.h
create mode 100644 libc/test/src/stdio/vfscanf_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index d22bd1153598eb..60aa7f5ccb319a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -211,10 +211,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fileno
libc.src.stdio.fprintf
libc.src.stdio.fscanf
+ libc.src.stdio.vfscanf
libc.src.stdio.printf
libc.src.stdio.remove
libc.src.stdio.rename
libc.src.stdio.scanf
+ libc.src.stdio.vscanf
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 1a647737ec455a..9a2746dcb86f87 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -210,10 +210,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fileno
libc.src.stdio.fprintf
libc.src.stdio.fscanf
+ libc.src.stdio.vfscanf
libc.src.stdio.printf
libc.src.stdio.remove
libc.src.stdio.rename
libc.src.stdio.scanf
+ libc.src.stdio.vscanf
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 65c5757efe6274..71590ece1d3f9f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -210,10 +210,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fileno
libc.src.stdio.fprintf
libc.src.stdio.fscanf
+ libc.src.stdio.vfscanf
libc.src.stdio.printf
libc.src.stdio.remove
libc.src.stdio.rename
libc.src.stdio.scanf
+ libc.src.stdio.vscanf
libc.src.stdio.snprintf
libc.src.stdio.sprintf
libc.src.stdio.asprintf
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index bc5ef5fe0e9b48..79069f1e74f05e 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -143,6 +143,16 @@ add_entrypoint_object(
${scanf_deps}
)
+add_entrypoint_object(
+ vfscanf
+ SRCS
+ vfscanf.cpp
+ HDRS
+ vfscanf.h
+ DEPENDS
+ ${scanf_deps}
+)
+
add_entrypoint_object(
scanf
SRCS
@@ -153,6 +163,16 @@ add_entrypoint_object(
${scanf_deps}
)
+add_entrypoint_object(
+ vscanf
+ SRCS
+ vscanf.cpp
+ HDRS
+ vscanf.h
+ DEPENDS
+ ${scanf_deps}
+)
+
add_entrypoint_object(
sprintf
SRCS
diff --git a/libc/src/stdio/vfscanf.cpp b/libc/src/stdio/vfscanf.cpp
new file mode 100644
index 00000000000000..220576522d0fdb
--- /dev/null
+++ b/libc/src/stdio/vfscanf.cpp
@@ -0,0 +1,34 @@
+//===-- Implementation of vfscanf -------------------------------*- 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/vfscanf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/scanf_core/vfscanf_internal.h"
+
+#include "hdr/types/FILE.h"
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, vfscanf,
+ (::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.
+ va_end(vlist);
+ int ret_val = scanf_core::vfscanf_internal(stream, format, args);
+ // This is done to avoid including stdio.h in the internals. On most systems
+ // EOF is -1, so this will be transformed into just "return ret_val".
+ return (ret_val == -1) ? EOF : ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/vfscanf.h b/libc/src/stdio/vfscanf.h
new file mode 100644
index 00000000000000..1a0a12d9eb4cd3
--- /dev/null
+++ b/libc/src/stdio/vfscanf.h
@@ -0,0 +1,24 @@
+//===-- Implementation header of vfscanf ------------------------*- 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_VFSCANF_H
+#define LLVM_LIBC_SRC_STDIO_VFSCANF_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/macros/config.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int vfscanf(::FILE *__restrict stream, const char *__restrict format,
+ va_list vlist);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_VFSCANF_H
diff --git a/libc/src/stdio/vscanf.cpp b/libc/src/stdio/vscanf.cpp
new file mode 100644
index 00000000000000..64f5cc1d6962a1
--- /dev/null
+++ b/libc/src/stdio/vscanf.cpp
@@ -0,0 +1,40 @@
+//===-- Implementation of vscanf --------------------------------*- 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/vscanf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/__support/macros/config.h"
+#include "src/stdio/scanf_core/vfscanf_internal.h"
+
+#include "hdr/types/FILE.h"
+#include <stdarg.h>
+
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+#define SCANF_STDIN LIBC_NAMESPACE::stdin
+#else // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+#define SCANF_STDIN ::stdin
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, vscanf,
+ (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.
+ va_end(vlist);
+ int ret_val = scanf_core::vfscanf_internal(
+ reinterpret_cast<::FILE *>(SCANF_STDIN), format, args);
+ // This is done to avoid including stdio.h in the internals. On most systems
+ // EOF is -1, so this will be transformed into just "return ret_val".
+ return (ret_val == -1) ? EOF : ret_val;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdio/vscanf.h b/libc/src/stdio/vscanf.h
new file mode 100644
index 00000000000000..5c59b91128ea32
--- /dev/null
+++ b/libc/src/stdio/vscanf.h
@@ -0,0 +1,23 @@
+//===-- Implementation header of vscanf -------------------------*- 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_VSCANF_H
+#define LLVM_LIBC_SRC_STDIO_VSCANF_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/macros/config.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int vscanf(const char *__restrict format, va_list vlist);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDIO_VSCANF_H
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 8b05b928a02695..d7b88186b5704a 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -286,6 +286,20 @@ add_libc_test(
${use_system_file}
)
+add_libc_test(
+ vfscanf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vfscanf_test.cpp
+ DEPENDS
+ libc.src.stdio.vfscanf
+ ${fscanf_test_deps}
+ libc.src.__support.CPP.string_view
+ COMPILE_OPTIONS
+ ${use_system_file}
+)
+
if(LIBC_CONF_SCANF_DISABLE_FLOAT)
list(APPEND sscanf_test_copts "-DLIBC_COPT_SCANF_DISABLE_FLOAT")
endif()
diff --git a/libc/test/src/stdio/vfscanf_test.cpp b/libc/test/src/stdio/vfscanf_test.cpp
new file mode 100644
index 00000000000000..7a9cbf7f123880
--- /dev/null
+++ b/libc/test/src/stdio/vfscanf_test.cpp
@@ -0,0 +1,98 @@
+//===-- Unittests for vfscanf ---------------------------------------------===//
+//
+// 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/__support/CPP/string_view.h"
+
+#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/fwrite.h"
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+
+#include "src/stdio/vfscanf.h"
+
+#include "test/UnitTest/Test.h"
+
+#include <stdio.h>
+
+namespace scanf_test {
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+using LIBC_NAMESPACE::fclose;
+using LIBC_NAMESPACE::ferror;
+using LIBC_NAMESPACE::fopen;
+using LIBC_NAMESPACE::fwrite;
+#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
+using ::fclose;
+using ::ferror;
+using ::fopen;
+using ::fwrite;
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+} // namespace scanf_test
+
+static int call_vfscanf(::FILE *stream, const char *__restrict format, ...) {
+ va_list vlist;
+ va_start(vlist, format);
+ int ret = LIBC_NAMESPACE::vfscanf(stream, format, vlist);
+ va_end(vlist);
+ return ret;
+}
+
+TEST(LlvmLibcFScanfTest, WriteToFile) {
+ const char *FILENAME = "fscanf_output.test";
+ auto FILE_PATH = libc_make_test_file_path(FILENAME);
+ ::FILE *file = scanf_test::fopen(FILE_PATH, "w");
+ ASSERT_FALSE(file == nullptr);
+
+ int read;
+
+ constexpr char simple[] = "A simple string with no conversions.\n";
+
+ ASSERT_EQ(sizeof(simple) - 1,
+ scanf_test::fwrite(simple, 1, sizeof(simple) - 1, file));
+
+ constexpr char numbers[] = "1234567890\n";
+
+ ASSERT_EQ(sizeof(numbers) - 1,
+ scanf_test::fwrite(numbers, 1, sizeof(numbers) - 1, file));
+
+ constexpr char numbers_and_more[] = "1234 and more\n";
+
+ ASSERT_EQ(sizeof(numbers_and_more) - 1,
+ scanf_test::fwrite(numbers_and_more, 1,
+ sizeof(numbers_and_more) - 1, file));
+
+ read = call_vfscanf(file, "Reading from a write-only file should fail.");
+ EXPECT_LT(read, 0);
+
+ ASSERT_EQ(0, scanf_test::fclose(file));
+
+ file = scanf_test::fopen(FILE_PATH, "r");
+ ASSERT_FALSE(file == nullptr);
+
+ char data[50];
+ read = call_vfscanf(file, "%[A-Za-z .\n]", data);
+ ASSERT_EQ(read, 1);
+ ASSERT_STREQ(simple, data);
+
+ read = call_vfscanf(file, "%s", data);
+ ASSERT_EQ(read, 1);
+ ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(numbers, 10),
+ LIBC_NAMESPACE::cpp::string_view(data));
+
+ // The format string starts with a space to handle the fact that the %s leaves
+ // a trailing \n and %c doesn't strip leading whitespace.
+ read = call_vfscanf(file, " %50c", data);
+ ASSERT_EQ(read, 1);
+ ASSERT_EQ(
+ LIBC_NAMESPACE::cpp::string_view(numbers_and_more),
+ LIBC_NAMESPACE::cpp::string_view(data, sizeof(numbers_and_more) - 1));
+
+ ASSERT_EQ(scanf_test::ferror(file), 0);
+ ASSERT_EQ(scanf_test::fclose(file), 0);
+}
More information about the libc-commits
mailing list