Skip to main content

libc/
stdio.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use core::ffi::{VaList, c_char, c_int, c_void};
8use core::fmt;
9use core::mem::{align_of, size_of};
10
11mod string_file;
12
13pub use string_file::{ScopedFile, StringFile};
14
15/// The C++ `FILE::Callback` signature: `int(void* ptr, const char* str, size_t len)`.
16pub type FileCallback = unsafe extern "C" fn(*mut c_void, *const c_char, usize) -> c_int;
17
18/// This represents the kernel `<stdio.h>` `FILE` type.
19#[repr(C)]
20pub struct FILE {
21    write: Option<FileCallback>,
22    ptr: *mut c_void,
23}
24
25const _: () = {
26    assert!(size_of::<FILE>() == 16);
27    assert!(align_of::<FILE>() == 8);
28};
29
30impl FILE {
31    /// Creates a `FILE` that sends everything written to it to `write`, passing `ptr` as the
32    /// callback's first argument, like the C++ `FILE(Callback* write, void* ptr)` constructor.
33    ///
34    /// # Safety
35    ///
36    /// For the lifetime of the returned `FILE`, `write` (if present) must be sound to call with
37    /// `ptr` and any `(data, len)` where `data` points to `len` readable bytes when `len > 0` (and
38    /// may be null when `len == 0`).
39    pub const unsafe fn new(write: Option<FileCallback>, ptr: *mut c_void) -> Self {
40        Self { write, ptr }
41    }
42
43    /// Writes `bytes` via the callback, like the C++ `FILE::Write`. This is what `fprintf` calls
44    /// to do output.
45    ///
46    /// Returns the callback's result, or -1 if this `FILE` has no callback.
47    pub fn write(&self, bytes: &[u8]) -> c_int {
48        let Some(write) = self.write else {
49            return -1;
50        };
51        // SAFETY:
52        // - `self.ptr` is the context uniquely paired with `write` by the C API.
53        // - `bytes` points to a valid sequence of `bytes.len()` bytes that remains valid and
54        //   immutable for the duration of the FFI call.
55        unsafe { write(self.ptr, bytes.as_ptr().cast::<c_char>(), bytes.len()) }
56    }
57}
58
59impl fmt::Write for FILE {
60    fn write_str(&mut self, s: &str) -> fmt::Result {
61        let Some(write) = self.write else {
62            return Err(fmt::Error);
63        };
64        if s.is_empty() {
65            return Ok(());
66        }
67        let c_chars = s.as_ptr().cast::<c_char>();
68        // SAFETY:
69        // - `self.ptr` is the context uniquely paired with `write` by the C API.
70        // - `s` is not empty, so `c_chars` points to a valid sequence of `s.len()` bytes.
71        // - The `s` memory region remains valid and immutable for the duration of the FFI call.
72        let ret = unsafe { write(self.ptr, c_chars, s.len()) };
73        if ret < 0 { Err(fmt::Error) } else { Ok(()) }
74    }
75}
76
77unsafe extern "C" {
78    /// Writes formatted output to `f`, matching `<stdio.h>` `fprintf`.
79    ///
80    /// # Safety
81    ///
82    /// `f` must point to a valid `FILE`. `fmt` must be non-null and point to a valid
83    /// NUL-terminated C format string whose format specifiers match the variadic arguments.
84    pub fn fprintf(f: *mut FILE, fmt: *const c_char, ...) -> c_int;
85
86    /// Writes `VaList` formatted output to `f`, matching `<stdio.h>` `vfprintf`.
87    ///
88    /// # Safety
89    ///
90    /// `f` must point to a valid `FILE`. `fmt` must be non-null and point to a valid
91    /// NUL-terminated C format string whose format specifiers match the arguments in `ap`.
92    pub fn vfprintf(f: *mut FILE, fmt: *const c_char, ap: VaList<'_>) -> c_int;
93}