printf_wrap/
example.rs

1// Copyright (c) 2021-2022 The Pennsylvania State University and the project contributors.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! An example of how to use the types and traits of this crate to safely
5//! wrap functions with `printf(3)`-style format strings and varargs.
6
7use crate::{PrintfArgument, PrintfFmt};
8use libc::{c_char, c_int};
9
10macro_rules! tuple_impl {
11    ($num:tt, $p_name:ident, $snp_name:ident, ( $($t:ident),* ), ( $($var:ident),* )) => {
12        #[doc = concat!("A safe wrapper around [`printf`](libc::printf) for ", stringify!($num), " argument(s).")]
13        #[inline]
14        pub fn $p_name<$($t),*>(fmt: PrintfFmt<($($t,)*)>, $($var: $t),*) -> c_int
15            where $($t: PrintfArgument),* {
16
17            unsafe {
18                libc::printf(fmt.as_ptr() $(, $var.as_c_val())* )
19            }
20        }
21
22        #[doc = concat!("A safe wrapper around [`snprintf`](libc::snprintf) for ", stringify!($num), " argument(s).")]
23        #[inline]
24        pub fn $snp_name<$($t),*>(dst: &mut [u8], fmt: PrintfFmt<($($t,)*)>, $($var: $t),*) -> c_int
25            where $($t: PrintfArgument),* {
26
27            unsafe {
28                libc::snprintf(
29                    dst.as_mut_ptr() as *mut c_char,
30                    dst.len(),
31                    fmt.as_ptr()
32                    $(, $var.as_c_val())*
33                )
34            }
35        }
36    };
37}
38
39tuple_impl!(0, printf0, snprintf0, (), ());
40tuple_impl!(1, printf1, snprintf1, (A), (a));
41tuple_impl!(2, printf2, snprintf2, (A, B), (a, b));
42tuple_impl!(3, printf3, snprintf3, (A, B, C), (a, b, c));
43tuple_impl!(4, printf4, snprintf4, (A, B, C, D), (a, b, c, d));
44tuple_impl!(5, printf5, snprintf5, (A, B, C, D, E), (a, b, c, d, e));
45tuple_impl!(6, printf6, snprintf6, (A, B, C, D, E, F), (a, b, c, d, e, f));
46tuple_impl!(7, printf7, snprintf7, (A, B, C, D, E, F, G), (a, b, c, d, e, f, g));
47tuple_impl!(8, printf8, snprintf8, (A, B, C, D, E, F, G, H), (a, b, c, d, e, f, g, h));
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use crate::PrintfFmt;
53
54    #[test]
55    fn snprintf_test_invocation() {
56        let mut x: [u8; 12] = [5u8; 12];
57
58        assert_eq!(
59            snprintf2(&mut x[..], PrintfFmt::new("X %u Y %c\0").unwrap(), 15u32, b'Z'),
60            8,
61            "snprintf2 return value should be 8"
62        );
63        assert_eq!(&x, b"X 15 Y Z\0\x05\x05\x05", "contents of x");
64    }
65
66    #[test]
67    fn snprintf_no_buffer_overflow() {
68        let mut x: [u8; 8] = [5u8; 8];
69        assert_eq!(
70            snprintf1(&mut x[..4], PrintfFmt::new("a%d \0").unwrap(), -100),
71            6,
72            "snprintf1 return value should be 6"
73        );
74        assert_eq!(&x[4..], [5u8; 4], "only 4 bytes should have been written by snprintf1");
75    }
76}