1 | //===-- Internal implementation header of vfprintf --------------*- 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_PRINTF_CORE_VFPRINTF_INTERNAL_H |
10 | #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H |
11 | |
12 | #include "src/__support/File/file.h" |
13 | #include "src/__support/arg_list.h" |
14 | #include "src/__support/macros/attributes.h" // For LIBC_INLINE |
15 | #include "src/stdio/printf_core/core_structs.h" |
16 | #include "src/stdio/printf_core/printf_main.h" |
17 | #include "src/stdio/printf_core/writer.h" |
18 | |
19 | #include <stdio.h> |
20 | |
21 | namespace LIBC_NAMESPACE { |
22 | |
23 | namespace internal { |
24 | #ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE |
25 | LIBC_INLINE int ferror_unlocked(FILE *f) { |
26 | return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked(); |
27 | } |
28 | |
29 | LIBC_INLINE void flockfile(FILE *f) { |
30 | reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock(); |
31 | } |
32 | |
33 | LIBC_INLINE void funlockfile(FILE *f) { |
34 | reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock(); |
35 | } |
36 | |
37 | LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, |
38 | FILE *f) { |
39 | return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked( |
40 | ptr, size * nmemb); |
41 | } |
42 | #else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) |
43 | LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror_unlocked(stream: f); } |
44 | |
45 | LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(stream: f); } |
46 | |
47 | LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(stream: f); } |
48 | |
49 | LIBC_INLINE size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, |
50 | ::FILE *f) { |
51 | return ::fwrite_unlocked(ptr: ptr, size: size, n: nmemb, stream: f); |
52 | } |
53 | #endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE |
54 | } // namespace internal |
55 | |
56 | namespace printf_core { |
57 | |
58 | LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { |
59 | ::FILE *target_file = reinterpret_cast<::FILE *>(fp); |
60 | // Write new_str to the target file. The logic preventing a zero-length write |
61 | // is in the writer, so we don't check here. |
62 | size_t written = internal::fwrite_unlocked(ptr: new_str.data(), size: sizeof(char), |
63 | nmemb: new_str.size(), f: target_file); |
64 | if (written != new_str.size() || internal::ferror_unlocked(f: target_file)) |
65 | return FILE_WRITE_ERROR; |
66 | return WRITE_OK; |
67 | } |
68 | |
69 | LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, |
70 | const char *__restrict format, |
71 | internal::ArgList &args) { |
72 | constexpr size_t BUFF_SIZE = 1024; |
73 | char buffer[BUFF_SIZE]; |
74 | printf_core::WriteBuffer wb(buffer, BUFF_SIZE, &file_write_hook, |
75 | reinterpret_cast<void *>(stream)); |
76 | Writer writer(&wb); |
77 | internal::flockfile(f: stream); |
78 | int retval = printf_main(writer: &writer, str: format, args); |
79 | int flushval = wb.overflow_write(new_str: "" ); |
80 | if (flushval != WRITE_OK) |
81 | retval = flushval; |
82 | internal::funlockfile(f: stream); |
83 | return retval; |
84 | } |
85 | |
86 | } // namespace printf_core |
87 | } // namespace LIBC_NAMESPACE |
88 | |
89 | #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_VFPRINTF_INTERNAL_H |
90 | |