1 //===-- Internal implementation header of vfscanf ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_VFSCANF_INTERNAL_H
10 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_VFSCANF_INTERNAL_H
12 #include "src/__support/File/file.h"
13 #include "src/__support/arg_list.h"
14 #include "src/__support/macros/config.h"
15 #include "src/__support/macros/properties/architectures.h"
16 #include "src/stdio/scanf_core/reader.h"
17 #include "src/stdio/scanf_core/scanf_main.h"
19 #if defined(LIBC_TARGET_ARCH_IS_GPU)
20 #include "src/stdio/ferror.h"
21 #include "src/stdio/getc.h"
22 #include "src/stdio/ungetc.h"
25 #include "hdr/types/FILE.h"
28 namespace LIBC_NAMESPACE_DECL
{
32 #if defined(LIBC_TARGET_ARCH_IS_GPU)
33 // The GPU build provides FILE access through the host operating system's
34 // library. So here we simply use the public entrypoints like in the SYSTEM_FILE
35 // interface. Entrypoints should normally not call others, this is an exception.
36 // FIXME: We do not acquire any locks here, so this is not thread safe.
37 LIBC_INLINE
void flockfile(::FILE *) { return; }
39 LIBC_INLINE
void funlockfile(::FILE *) { return; }
41 LIBC_INLINE
int getc(void *f
) {
42 return LIBC_NAMESPACE::getc(reinterpret_cast<::FILE *>(f
));
45 LIBC_INLINE
void ungetc(int c
, void *f
) {
46 LIBC_NAMESPACE::ungetc(c
, reinterpret_cast<::FILE *>(f
));
49 LIBC_INLINE
int ferror_unlocked(::FILE *f
) { return LIBC_NAMESPACE::ferror(f
); }
51 #elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
53 LIBC_INLINE
void flockfile(FILE *f
) {
54 reinterpret_cast<LIBC_NAMESPACE::File
*>(f
)->lock();
57 LIBC_INLINE
void funlockfile(FILE *f
) {
58 reinterpret_cast<LIBC_NAMESPACE::File
*>(f
)->unlock();
61 LIBC_INLINE
int getc(void *f
) {
64 reinterpret_cast<LIBC_NAMESPACE::File
*>(f
)->read_unlocked(&c
, 1);
65 size_t r
= result
.value
;
66 if (result
.has_error() || r
!= 1)
72 LIBC_INLINE
void ungetc(int c
, void *f
) {
73 reinterpret_cast<LIBC_NAMESPACE::File
*>(f
)->ungetc_unlocked(c
);
76 LIBC_INLINE
int ferror_unlocked(FILE *f
) {
77 return reinterpret_cast<LIBC_NAMESPACE::File
*>(f
)->error_unlocked();
80 #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
82 // Since ungetc_unlocked isn't always available, we don't acquire the lock for
84 LIBC_INLINE
void flockfile(::FILE *) { return; }
86 LIBC_INLINE
void funlockfile(::FILE *) { return; }
88 LIBC_INLINE
int getc(void *f
) { return ::getc(reinterpret_cast<::FILE *>(f
)); }
90 LIBC_INLINE
void ungetc(int c
, void *f
) {
91 ::ungetc(c
, reinterpret_cast<::FILE *>(f
));
94 LIBC_INLINE
int ferror_unlocked(::FILE *f
) { return ::ferror(f
); }
96 #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
98 } // namespace internal
100 namespace scanf_core
{
102 LIBC_INLINE
int vfscanf_internal(::FILE *__restrict stream
,
103 const char *__restrict format
,
104 internal::ArgList
&args
) {
105 internal::flockfile(stream
);
106 scanf_core::Reader
reader(stream
, &internal::getc
, internal::ungetc
);
107 int retval
= scanf_core::scanf_main(&reader
, format
, args
);
108 if (retval
== 0 && internal::ferror_unlocked(stream
))
110 internal::funlockfile(stream
);
114 } // namespace scanf_core
115 } // namespace LIBC_NAMESPACE_DECL
117 #endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_VFSCANF_INTERNAL_H