Crates.io | printf-compat |
lib.rs | printf-compat |
version | 0.1.1 |
source | src |
created_at | 2020-11-26 15:21:31.844874 |
updated_at | 2020-11-26 16:13:40.888462 |
description | printf reimplemented in Rust |
homepage | |
repository | https://github.com/lights0123/printf-compat |
max_upload_size | |
id | 316761 |
size | 64,551 |
printf
reimplemented in Rust
This is a complete reimplementation of printf
in Rust, using the unstable
(i.e. requires a Nightly compiler) c_variadic
feature.
printf
, use this crate to easily add
your own output. core::fmt
too big? No problem! Write your own
formatting code, or use a minimal formatting library like ufmt
or
defmt
. Don't need every single option given by printf
format
strings? No problem! Just don't implement it.wasm32-unknown-unknown
instead of emscripten
(as wasm-bindgen is only compatible with the former), you have no libc. If
you want to interface with a C library, you'll have to do it all yourself.
With this crate, that turns into 5 lines instead of hundreds for printf
.printf-compat lets you pick how you want to output a message. Use
pre-written adapters for fmt::Write
(like a
String
) or io::Write
(like
io::stdout()
), or implement your own.
This crate is no_std
compatible (printf-compat = { version = "0.1", default-features = false }
in your Cargo.toml). The main machinery doesn't
require the use of core::fmt
, and it can't panic.
Of course, printf
is completely unsafe, as it requires the use of
va_list
. However, outside of that, all of the actual string parsing is
written in completely safe Rust. No buffer overflow attacks!
The n
format specifier, which writes to a user-provided pointer, is
considered a serious security vulnerability if a user-provided string is
ever passed to printf
. It is supported by this crate; however, it
doesn't do anything by default, and you'll have to explicitly do the writing
yourself.
A wide test suite is used to ensure that many different possibilities are
identical to glibc's printf
. Differences are
documented.
Start by adding the unstable feature:
#![feature(c_variadic)]
Now, add your function signature:
use cty::{c_char, c_int};
#[no_mangle]
unsafe extern "C" fn c_library_print(str: *const c_char, mut args: ...) -> c_int {
todo!()
}
If you have access to std
, i.e. not an embedded platform, you can use
std::os::raw
instead of cty
. Also, think about what you're doing:
printf
because you don't have one, you'll want to
call it printf
and add #[no_mangle]
.#[no_mangle]
and
rename the function to what it expects.#[no_mangle]
.Now, add your logic:
use printf_compat::{format, output};
let mut s = String::new();
let bytes_written = format(str, args.as_va_list(), output::fmt_write(&mut s));
println!("{}", s);
bytes_written
Of course, replace output::fmt_write
with whatever you like—some are
provided for you in output
. If you'd like to write your own, follow
their function signature: you need to provide a function to format()
that takes an Argument
and returns the number of bytes written (although
you don't need to if your C library doesn't use it) or -1 if there was an
error.
License: MIT OR Apache-2.0