Skip to content

Commit b8f134f

Browse files
authored
[libc] Implement 'vfscanf' and 'vscanf' (#105293)
Summary: These are simply forwarding the vlist to the existing helper.
1 parent 1c48c9c commit b8f134f

File tree

12 files changed

+287
-0
lines changed

12 files changed

+287
-0
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,12 @@ set(TARGET_LIBC_ENTRYPOINTS
211211
libc.src.stdio.fileno
212212
libc.src.stdio.fprintf
213213
libc.src.stdio.fscanf
214+
libc.src.stdio.vfscanf
214215
libc.src.stdio.printf
215216
libc.src.stdio.remove
216217
libc.src.stdio.rename
217218
libc.src.stdio.scanf
219+
libc.src.stdio.vscanf
218220
libc.src.stdio.snprintf
219221
libc.src.stdio.sprintf
220222
libc.src.stdio.asprintf

libc/config/linux/riscv/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,12 @@ set(TARGET_LIBC_ENTRYPOINTS
210210
libc.src.stdio.fileno
211211
libc.src.stdio.fprintf
212212
libc.src.stdio.fscanf
213+
libc.src.stdio.vfscanf
213214
libc.src.stdio.printf
214215
libc.src.stdio.remove
215216
libc.src.stdio.rename
216217
libc.src.stdio.scanf
218+
libc.src.stdio.vscanf
217219
libc.src.stdio.snprintf
218220
libc.src.stdio.sprintf
219221
libc.src.stdio.asprintf

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,12 @@ set(TARGET_LIBC_ENTRYPOINTS
210210
libc.src.stdio.fileno
211211
libc.src.stdio.fprintf
212212
libc.src.stdio.fscanf
213+
libc.src.stdio.vfscanf
213214
libc.src.stdio.printf
214215
libc.src.stdio.remove
215216
libc.src.stdio.rename
216217
libc.src.stdio.scanf
218+
libc.src.stdio.vscanf
217219
libc.src.stdio.snprintf
218220
libc.src.stdio.sprintf
219221
libc.src.stdio.asprintf

libc/newhdrgen/yaml/stdio.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ functions:
178178
- type: FILE *__restrict
179179
- type: const char *__restrict
180180
- type: '...'
181+
- name: vfscanf
182+
standards:
183+
- stdc
184+
return_type: int
185+
arguments:
186+
- type: FILE *__restrict
187+
- type: const char *__restrict
188+
- type: va_list
181189
- name: fseek
182190
standards:
183191
- stdc
@@ -284,6 +292,13 @@ functions:
284292
arguments:
285293
- type: const char *__restrict
286294
- type: '...'
295+
- name: vscanf
296+
standards:
297+
- stdc
298+
return_type: int
299+
arguments:
300+
- type: const char *__restrict
301+
- type: va_list
287302
- name: setbuf
288303
standards:
289304
- stdc

libc/spec/stdc.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,13 +1042,26 @@ def StdC : StandardSpec<"stdc"> {
10421042
[ArgSpec<ConstCharRestrictedPtr>,
10431043
ArgSpec<VarArgType>]
10441044
>,
1045+
FunctionSpec<
1046+
"vscanf",
1047+
RetValSpec<IntType>,
1048+
[ArgSpec<ConstCharRestrictedPtr>,
1049+
ArgSpec<VaListType>]
1050+
>,
10451051
FunctionSpec<
10461052
"fscanf",
10471053
RetValSpec<IntType>,
10481054
[ArgSpec<FILERestrictedPtr>,
10491055
ArgSpec<ConstCharRestrictedPtr>,
10501056
ArgSpec<VarArgType>]
10511057
>,
1058+
FunctionSpec<
1059+
"vfscanf",
1060+
RetValSpec<IntType>,
1061+
[ArgSpec<FILERestrictedPtr>,
1062+
ArgSpec<ConstCharRestrictedPtr>,
1063+
ArgSpec<VaListType>]
1064+
>,
10521065
FunctionSpec<
10531066
"sprintf",
10541067
RetValSpec<IntType>,

libc/src/stdio/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,16 @@ add_entrypoint_object(
143143
${scanf_deps}
144144
)
145145

146+
add_entrypoint_object(
147+
vfscanf
148+
SRCS
149+
vfscanf.cpp
150+
HDRS
151+
vfscanf.h
152+
DEPENDS
153+
${scanf_deps}
154+
)
155+
146156
add_entrypoint_object(
147157
scanf
148158
SRCS
@@ -153,6 +163,16 @@ add_entrypoint_object(
153163
${scanf_deps}
154164
)
155165

166+
add_entrypoint_object(
167+
vscanf
168+
SRCS
169+
vscanf.cpp
170+
HDRS
171+
vscanf.h
172+
DEPENDS
173+
${scanf_deps}
174+
)
175+
156176
add_entrypoint_object(
157177
sprintf
158178
SRCS

libc/src/stdio/vfscanf.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- Implementation of vfscanf -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/stdio/vfscanf.h"
10+
11+
#include "src/__support/File/file.h"
12+
#include "src/__support/arg_list.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/stdio/scanf_core/vfscanf_internal.h"
15+
16+
#include "hdr/types/FILE.h"
17+
#include <stdarg.h>
18+
19+
namespace LIBC_NAMESPACE_DECL {
20+
21+
LLVM_LIBC_FUNCTION(int, vfscanf,
22+
(::FILE *__restrict stream, const char *__restrict format,
23+
va_list vlist)) {
24+
internal::ArgList args(vlist); // This holder class allows for easier copying
25+
// and pointer semantics, as well as handling
26+
// destruction automatically.
27+
va_end(vlist);
28+
int ret_val = scanf_core::vfscanf_internal(stream, format, args);
29+
// This is done to avoid including stdio.h in the internals. On most systems
30+
// EOF is -1, so this will be transformed into just "return ret_val".
31+
return (ret_val == -1) ? EOF : ret_val;
32+
}
33+
34+
} // namespace LIBC_NAMESPACE_DECL

libc/src/stdio/vfscanf.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- Implementation header of vfscanf ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_STDIO_VFSCANF_H
10+
#define LLVM_LIBC_SRC_STDIO_VFSCANF_H
11+
12+
#include "hdr/types/FILE.h"
13+
#include "src/__support/macros/config.h"
14+
15+
#include <stdarg.h>
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
19+
int vfscanf(::FILE *__restrict stream, const char *__restrict format,
20+
va_list vlist);
21+
22+
} // namespace LIBC_NAMESPACE_DECL
23+
24+
#endif // LLVM_LIBC_SRC_STDIO_VFSCANF_H

libc/src/stdio/vscanf.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===-- Implementation of vscanf --------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/stdio/vscanf.h"
10+
11+
#include "src/__support/File/file.h"
12+
#include "src/__support/arg_list.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/stdio/scanf_core/vfscanf_internal.h"
15+
16+
#include "hdr/types/FILE.h"
17+
#include <stdarg.h>
18+
19+
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
20+
#define SCANF_STDIN LIBC_NAMESPACE::stdin
21+
#else // LIBC_COPT_STDIO_USE_SYSTEM_FILE
22+
#define SCANF_STDIN ::stdin
23+
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
24+
25+
namespace LIBC_NAMESPACE_DECL {
26+
27+
LLVM_LIBC_FUNCTION(int, vscanf,
28+
(const char *__restrict format, va_list vlist)) {
29+
internal::ArgList args(vlist); // This holder class allows for easier copying
30+
// and pointer semantics, as well as handling
31+
// destruction automatically.
32+
va_end(vlist);
33+
int ret_val = scanf_core::vfscanf_internal(
34+
reinterpret_cast<::FILE *>(SCANF_STDIN), format, args);
35+
// This is done to avoid including stdio.h in the internals. On most systems
36+
// EOF is -1, so this will be transformed into just "return ret_val".
37+
return (ret_val == -1) ? EOF : ret_val;
38+
}
39+
40+
} // namespace LIBC_NAMESPACE_DECL

libc/src/stdio/vscanf.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation header of vscanf -------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_STDIO_VSCANF_H
10+
#define LLVM_LIBC_SRC_STDIO_VSCANF_H
11+
12+
#include "hdr/types/FILE.h"
13+
#include "src/__support/macros/config.h"
14+
15+
#include <stdarg.h>
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
19+
int vscanf(const char *__restrict format, va_list vlist);
20+
21+
} // namespace LIBC_NAMESPACE_DECL
22+
23+
#endif // LLVM_LIBC_SRC_STDIO_VSCANF_H

libc/test/src/stdio/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,20 @@ add_libc_test(
286286
${use_system_file}
287287
)
288288

289+
add_libc_test(
290+
vfscanf_test
291+
SUITE
292+
libc_stdio_unittests
293+
SRCS
294+
vfscanf_test.cpp
295+
DEPENDS
296+
libc.src.stdio.vfscanf
297+
${fscanf_test_deps}
298+
libc.src.__support.CPP.string_view
299+
COMPILE_OPTIONS
300+
${use_system_file}
301+
)
302+
289303
if(LIBC_CONF_SCANF_DISABLE_FLOAT)
290304
list(APPEND sscanf_test_copts "-DLIBC_COPT_SCANF_DISABLE_FLOAT")
291305
endif()

libc/test/src/stdio/vfscanf_test.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===-- Unittests for vfscanf ---------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/CPP/string_view.h"
10+
11+
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
12+
#include "src/stdio/fclose.h"
13+
#include "src/stdio/ferror.h"
14+
#include "src/stdio/fopen.h"
15+
#include "src/stdio/fwrite.h"
16+
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
17+
18+
#include "src/stdio/vfscanf.h"
19+
20+
#include "test/UnitTest/Test.h"
21+
22+
#include <stdio.h>
23+
24+
namespace scanf_test {
25+
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
26+
using LIBC_NAMESPACE::fclose;
27+
using LIBC_NAMESPACE::ferror;
28+
using LIBC_NAMESPACE::fopen;
29+
using LIBC_NAMESPACE::fwrite;
30+
#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
31+
using ::fclose;
32+
using ::ferror;
33+
using ::fopen;
34+
using ::fwrite;
35+
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
36+
} // namespace scanf_test
37+
38+
static int call_vfscanf(::FILE *stream, const char *__restrict format, ...) {
39+
va_list vlist;
40+
va_start(vlist, format);
41+
int ret = LIBC_NAMESPACE::vfscanf(stream, format, vlist);
42+
va_end(vlist);
43+
return ret;
44+
}
45+
46+
TEST(LlvmLibcFScanfTest, WriteToFile) {
47+
const char *FILENAME = "fscanf_output.test";
48+
auto FILE_PATH = libc_make_test_file_path(FILENAME);
49+
::FILE *file = scanf_test::fopen(FILE_PATH, "w");
50+
ASSERT_FALSE(file == nullptr);
51+
52+
int read;
53+
54+
constexpr char simple[] = "A simple string with no conversions.\n";
55+
56+
ASSERT_EQ(sizeof(simple) - 1,
57+
scanf_test::fwrite(simple, 1, sizeof(simple) - 1, file));
58+
59+
constexpr char numbers[] = "1234567890\n";
60+
61+
ASSERT_EQ(sizeof(numbers) - 1,
62+
scanf_test::fwrite(numbers, 1, sizeof(numbers) - 1, file));
63+
64+
constexpr char numbers_and_more[] = "1234 and more\n";
65+
66+
ASSERT_EQ(sizeof(numbers_and_more) - 1,
67+
scanf_test::fwrite(numbers_and_more, 1,
68+
sizeof(numbers_and_more) - 1, file));
69+
70+
read = call_vfscanf(file, "Reading from a write-only file should fail.");
71+
EXPECT_LT(read, 0);
72+
73+
ASSERT_EQ(0, scanf_test::fclose(file));
74+
75+
file = scanf_test::fopen(FILE_PATH, "r");
76+
ASSERT_FALSE(file == nullptr);
77+
78+
char data[50];
79+
read = call_vfscanf(file, "%[A-Za-z .\n]", data);
80+
ASSERT_EQ(read, 1);
81+
ASSERT_STREQ(simple, data);
82+
83+
read = call_vfscanf(file, "%s", data);
84+
ASSERT_EQ(read, 1);
85+
ASSERT_EQ(LIBC_NAMESPACE::cpp::string_view(numbers, 10),
86+
LIBC_NAMESPACE::cpp::string_view(data));
87+
88+
// The format string starts with a space to handle the fact that the %s leaves
89+
// a trailing \n and %c doesn't strip leading whitespace.
90+
read = call_vfscanf(file, " %50c", data);
91+
ASSERT_EQ(read, 1);
92+
ASSERT_EQ(
93+
LIBC_NAMESPACE::cpp::string_view(numbers_and_more),
94+
LIBC_NAMESPACE::cpp::string_view(data, sizeof(numbers_and_more) - 1));
95+
96+
ASSERT_EQ(scanf_test::ferror(file), 0);
97+
ASSERT_EQ(scanf_test::fclose(file), 0);
98+
}

0 commit comments

Comments
 (0)