83 lines
1.9 KiB
Rust
83 lines
1.9 KiB
Rust
//! Terminal output. `print!`/`println!` format into a stack buffer and hand
|
|
//! it to SYS_PRINT in NUL-terminated chunks, so one call is one (or a few)
|
|
//! syscalls rather than libc write()'s one SYS_PUTCHAR per byte.
|
|
|
|
use core::fmt::{self, Write};
|
|
|
|
use crate::sys;
|
|
|
|
const CHUNK: usize = 256;
|
|
|
|
/// Buffered writer to the process's terminal (stdout).
|
|
pub struct Stdout {
|
|
buf: [u8; CHUNK],
|
|
len: usize,
|
|
}
|
|
|
|
impl Stdout {
|
|
pub const fn new() -> Self {
|
|
Stdout { buf: [0; CHUNK], len: 0 }
|
|
}
|
|
|
|
pub fn write_bytes(&mut self, bytes: &[u8]) {
|
|
for &b in bytes {
|
|
if b == 0 {
|
|
// SYS_PRINT stops at NUL; send it on its own.
|
|
self.flush();
|
|
unsafe { sys::syscall1(sys::SYS_PUTCHAR, 0) };
|
|
continue;
|
|
}
|
|
if self.len == CHUNK - 1 {
|
|
self.flush();
|
|
}
|
|
self.buf[self.len] = b;
|
|
self.len += 1;
|
|
}
|
|
}
|
|
|
|
pub fn flush(&mut self) {
|
|
if self.len == 0 {
|
|
return;
|
|
}
|
|
self.buf[self.len] = 0;
|
|
unsafe { sys::syscall1(sys::SYS_PRINT, self.buf.as_ptr() as u64) };
|
|
self.len = 0;
|
|
}
|
|
}
|
|
|
|
impl Default for Stdout {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl Write for Stdout {
|
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
self.write_bytes(s.as_bytes());
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Drop for Stdout {
|
|
fn drop(&mut self) {
|
|
self.flush();
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub fn _print(args: fmt::Arguments) {
|
|
let mut out = Stdout::new();
|
|
let _ = out.write_fmt(args);
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! print {
|
|
($($arg:tt)*) => { $crate::io::_print(format_args!($($arg)*)) };
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! println {
|
|
() => { $crate::print!("\n") };
|
|
($($arg:tt)*) => { $crate::io::_print(format_args!("{}\n", format_args!($($arg)*))) };
|
|
}
|