c_main/
lib.rs

1//! C main entry point with nice wrapper for arguments.
2//!
3//!```rust
4//!#![no_main]
5//!
6//!#[no_mangle]
7//!pub fn rust_main(args: c_main::Args) -> isize {
8//!    for arg in args.into_iter().skip(1) {
9//!        println!("arg={:?}", arg);
10//!    }
11//!    0
12//!}
13//!```
14
15#![no_std]
16#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
17#![cfg_attr(rustfmt, rustfmt_skip)]
18
19mod args;
20pub use args::Args;
21
22#[allow(unused)]
23#[cold]
24#[inline(never)]
25unsafe fn invalid_cli_args_error() -> libc::c_int {
26    libc::printf("Unable to parse C argv as utf-8 string\n\0".as_ptr() as _);
27    255
28}
29
30///Converts C string to Rust's, verifying it is UTF-8
31///
32///It is UB to pass non-C string as it requires \0
33pub unsafe fn c_str_to_rust(ptr: *const u8) -> Result<&'static str, core::str::Utf8Error> {
34    let len = libc::strlen(ptr as *const i8);
35    let parts = core::slice::from_raw_parts(ptr, len);
36    core::str::from_utf8(parts)
37}
38
39///Converts C string to Rust's one assuming it is UTF-8
40///
41///It is UB to pass non-C string as it requires \0
42pub unsafe fn c_str_to_rust_unchecked(ptr: *const u8) -> &'static str {
43    let len = libc::strlen(ptr as *const i8);
44    let parts = core::slice::from_raw_parts(ptr, len);
45    core::str::from_utf8_unchecked(parts)
46}
47
48extern "Rust" {
49    fn rust_main(args: args::Args) -> isize;
50}
51
52#[doc(hidden)]
53#[cfg(not(test))]
54#[no_mangle]
55pub unsafe extern fn main(argc: libc::c_int, argv: *const *const u8) -> libc::c_int {
56    match args::Args::new(argc as isize, argv) {
57        Ok(args) => rust_main(args) as _,
58        Err(_) => invalid_cli_args_error(),
59    }
60}