1 //===-- Internal 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_SCANF_CORE_VFSCANF_INTERNAL_H 10 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_VFSCANF_INTERNAL_H 11 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" 18 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" 23 #endif 24 25 #include "hdr/types/FILE.h" 26 #include <stddef.h> 27 28 namespace LIBC_NAMESPACE_DECL { 29 30 namespace internal { 31 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; } 38 39 LIBC_INLINE void funlockfile(::FILE *) { return; } 40 41 LIBC_INLINE int getc(void *f) { 42 return LIBC_NAMESPACE::getc(reinterpret_cast<::FILE *>(f)); 43 } 44 45 LIBC_INLINE void ungetc(int c, void *f) { 46 LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f)); 47 } 48 49 LIBC_INLINE int ferror_unlocked(::FILE *f) { return LIBC_NAMESPACE::ferror(f); } 50 51 #elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) 52 53 LIBC_INLINE void flockfile(FILE *f) { 54 reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock(); 55 } 56 57 LIBC_INLINE void funlockfile(FILE *f) { 58 reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock(); 59 } 60 61 LIBC_INLINE int getc(void *f) { 62 unsigned char c; 63 auto result = 64 reinterpret_cast<LIBC_NAMESPACE::File *>(f)->read_unlocked(&c, 1); 65 size_t r = result.value; 66 if (result.has_error() || r != 1) 67 return '\0'; 68 69 return c; 70 } 71 72 LIBC_INLINE void ungetc(int c, void *f) { 73 reinterpret_cast<LIBC_NAMESPACE::File *>(f)->ungetc_unlocked(c); 74 } 75 76 LIBC_INLINE int ferror_unlocked(FILE *f) { 77 return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked(); 78 } 79 80 #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) 81 82 // Since ungetc_unlocked isn't always available, we don't acquire the lock for 83 // system files. 84 LIBC_INLINE void flockfile(::FILE *) { return; } 85 86 LIBC_INLINE void funlockfile(::FILE *) { return; } 87 88 LIBC_INLINE int getc(void *f) { return ::getc(reinterpret_cast<::FILE *>(f)); } 89 90 LIBC_INLINE void ungetc(int c, void *f) { 91 ::ungetc(c, reinterpret_cast<::FILE *>(f)); 92 } 93 94 LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror(f); } 95 96 #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE 97 98 } // namespace internal 99 100 namespace scanf_core { 101 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)) 109 retval = EOF; 110 internal::funlockfile(stream); 111 112 return retval; 113 } 114 } // namespace scanf_core 115 } // namespace LIBC_NAMESPACE_DECL 116 117 #endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_VFSCANF_INTERNAL_H 118