[libc-commits] [libc] b8f134f - [libc] Implement 'vfscanf' and 'vscanf' (#105293)
via libc-commits
libc-commits at lists.llvm.org
Mon Aug 26 07:00:14 PDT 2024
Author: Joseph Huber
Date: 2024-08-26T09:00:10-05:00
New Revision: b8f134faba3a41f47d2d05125118ea1acf512cb3
URL: https://github.com/llvm/llvm-project/commit/b8f134faba3a41f47d2d05125118ea1acf512cb3
DIFF: https://github.com/llvm/llvm-project/commit/b8f134faba3a41f47d2d05125118ea1acf512cb3.diff
LOG: [libc] Implement 'vfscanf' and 'vscanf' (#105293)
Summary:
These are simply forwarding the vlist to the existing helper.
Added:
libc/src/stdio/vfscanf.cpp
libc/src/stdio/vfscanf.h
libc/src/stdio/vscanf.cpp
libc/src/stdio/vscanf.h
libc/test/src/stdio/vfscanf_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/newhdrgen/yaml/stdio.yaml
libc/spec/stdc.td
libc/src/stdio/CMakeLists.txt
libc/test/src/stdio/CMakeLists.txt
Removed:
################################################################################
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 bac1e3cfa85da7..141dc70463d64a 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/newhdrgen/yaml/stdio.yaml b/libc/newhdrgen/yaml/stdio.yaml
index 43438699b58409..fd116bbc00895d 100644
--- a/libc/newhdrgen/yaml/stdio.yaml
+++ b/libc/newhdrgen/yaml/stdio.yaml
@@ -178,6 +178,14 @@ functions:
- type: FILE *__restrict
- type: const char *__restrict
- type: '...'
+ - name: vfscanf
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: FILE *__restrict
+ - type: const char *__restrict
+ - type: va_list
- name: fseek
standards:
- stdc
@@ -284,6 +292,13 @@ functions:
arguments:
- type: const char *__restrict
- type: '...'
+ - name: vscanf
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: const char *__restrict
+ - type: va_list
- name: setbuf
standards:
- stdc
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 6d8be9f8e4016d..026cc72b458a77 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1042,6 +1042,12 @@ def StdC : StandardSpec<"stdc"> {
[ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
+ FunctionSpec<
+ "vscanf",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
FunctionSpec<
"fscanf",
RetValSpec<IntType>,
@@ -1049,6 +1055,13 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<ConstCharRestrictedPtr>,
ArgSpec<VarArgType>]
>,
+ FunctionSpec<
+ "vfscanf",
+ RetValSpec<IntType>,
+ [ArgSpec<FILERestrictedPtr>,
+ ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<VaListType>]
+ >,
FunctionSpec<
"sprintf",
RetValSpec<IntType>,
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 372b8fc8192455..b9bc904471df9a 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