[libc-commits] [libc] [libc] Add `vsscanf` function (PR #97529)
Izaak Schroeder via libc-commits
libc-commits at lists.llvm.org
Wed Jul 3 18:03:22 PDT 2024
https://github.com/izaakschroeder updated https://github.com/llvm/llvm-project/pull/97529
>From aa40c39c7ff0981b3aec58dd84601be441af70bf Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 23:55:25 -0700
Subject: [PATCH 1/2] [libc] Add `vsscanf` function
---
libc/spec/stdc.td | 7 +++++++
libc/src/stdio/CMakeLists.txt | 10 ++++++++++
libc/src/stdio/vsscanf.cpp | 36 +++++++++++++++++++++++++++++++++++
libc/src/stdio/vsscanf.h | 20 +++++++++++++++++++
4 files changed, 73 insertions(+)
create mode 100644 libc/src/stdio/vsscanf.cpp
create mode 100644 libc/src/stdio/vsscanf.h
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 9ff40bf76700c..0d35a1e3e6203 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -968,6 +968,13 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<IntType>,
[ArgSpec<IntType>, ArgSpec<FILEPtr>]
>,
+ FunctionSpec<
+ "vsscanf",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>,
+ ArgSpec<ConstCharPtr>,
+ ArgSpec<VaListType>]
+ >,
],
[
ObjectSpec<
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index a659d9e847a9e..3f1d97cad6afd 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -203,6 +203,16 @@ add_entrypoint_object(
libc.src.stdio.printf_core.vfprintf_internal
)
+add_entrypoint_object(
+ vsscanf
+ SRCS
+ vsscanf.cpp
+ HDRS
+ vsscanf.h
+ DEPENDS
+ libc.src.__support.arg_list
+)
+
add_stdio_entrypoint_object(
fileno
SRCS
diff --git a/libc/src/stdio/vsscanf.cpp b/libc/src/stdio/vsscanf.cpp
new file mode 100644
index 0000000000000..dee86793e821a
--- /dev/null
+++ b/libc/src/stdio/vsscanf.cpp
@@ -0,0 +1,36 @@
+//===-- Implementation of vsscanf -------------------------------*- 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/vsscanf.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/scanf_core/reader.h"
+#include "src/stdio/scanf_core/scanf_main.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, vsscanf,
+ (const char *buffer, const char *format, va_list vlist)) {
+ internal::ArgList args(vlist); // This holder class allows for easier copying
+ // and pointer semantics, as well as handling
+ // destruction automatically.
+
+ scanf_core::ReadBuffer rb{const_cast<char *>(buffer),
+ cpp::numeric_limits<size_t>::max()};
+ scanf_core::Reader reader(&rb);
+ int ret_val = scanf_core::scanf_main(&reader, 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
diff --git a/libc/src/stdio/vsscanf.h b/libc/src/stdio/vsscanf.h
new file mode 100644
index 0000000000000..992c44d3d95b9
--- /dev/null
+++ b/libc/src/stdio/vsscanf.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of vsscanf ------------------------*- 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_VSSCANF_H
+#define LLVM_LIBC_SRC_STDIO_VSSCANF_H
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE {
+
+int vsscanf(const char *s, const char *format, va_list vlist);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDIO_VSSCANF_H
>From 8d5254892cf4e7ac5f528d1e0324cc7cea7050bf Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Wed, 3 Jul 2024 18:02:57 -0700
Subject: [PATCH 2/2] [libc]: add `vsscanf` tests
---
libc/test/src/stdio/CMakeLists.txt | 12 ++++
libc/test/src/stdio/vsscanf_test.cpp | 83 ++++++++++++++++++++++++++++
2 files changed, 95 insertions(+)
create mode 100644 libc/test/src/stdio/vsscanf_test.cpp
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 5eb8c9577893b..b82e1ccf1a49e 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -273,6 +273,18 @@ add_libc_test(
LibcFPTestHelpers
)
+add_libc_test(
+ vsscanf_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ vsscanf_test.cpp
+ DEPENDS
+ libc.src.stdio.vsscanf
+ LINK_LIBRARIES
+ LibcFPTestHelpers
+)
+
add_libc_test(
puts_test
HERMETIC_TEST_ONLY # writes to libc's stdout
diff --git a/libc/test/src/stdio/vsscanf_test.cpp b/libc/test/src/stdio/vsscanf_test.cpp
new file mode 100644
index 0000000000000..faf951d0aee18
--- /dev/null
+++ b/libc/test/src/stdio/vsscanf_test.cpp
@@ -0,0 +1,83 @@
+//===-- Unittests for vsscanf ---------------------------------------------===//
+//
+// 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/limits.h"
+#include "src/__support/arg_list.h"
+
+#include "src/stdio/vsscanf.h"
+
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcVSScanfTest, IntConvSimple) {
+ int result = 0;
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("123", "%d", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, 123);
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("456", "%i", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, 456);
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("789", "%x", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, 0x789);
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("012", "%o", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, 012);
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("345", "%u", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, 345);
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("10000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000",
+ "%d", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 1);
+ EXPECT_EQ(result, int(LIBC_NAMESPACE::cpp::numeric_limits<intmax_t>::max()));
+
+ auto fn = [](int fmt, ...) {
+ va_list vlist;
+ va_start(vlist, fmt);
+ return LIBC_NAMESPACE::vsscanf("Not an integer", "%d", vlist);
+ };
+ EXPECT_EQ(fn(0, &result), 0);
+}
More information about the libc-commits
mailing list