|
| 1 | +// Copyright (c) 2022-present INESC-ID. |
| 2 | +// Distributed under the MIT license that can be found in the LICENSE file. |
| 3 | + |
| 4 | +use sprintf::parser::{ConversionType, FormatElement, parse_format_string}; |
| 5 | +use sprintf::{Printf, vsprintfp}; |
| 6 | + |
| 7 | +use crate::va_args::{VaArg, VaArgGet}; |
| 8 | + |
| 9 | +pub fn format_c(fmt: &str, va: &[VaArg]) -> String { |
| 10 | + let elements = match parse_format_string(fmt) { |
| 11 | + Ok(elements) => elements, |
| 12 | + Err(e) => panic!("format_c: cannot parse {fmt:?}: {e:?}"), |
| 13 | + }; |
| 14 | + let mut args: Vec<Box<dyn Printf>> = Vec::new(); |
| 15 | + let mut pos = 0; |
| 16 | + for element in &elements { |
| 17 | + if let FormatElement::Format(spec) = element { |
| 18 | + if spec.conversion_type == ConversionType::PercentSign { |
| 19 | + continue; |
| 20 | + } |
| 21 | + let arg = &va[pos]; |
| 22 | + args.push(match spec.conversion_type { |
| 23 | + ConversionType::DecInt => match arg { |
| 24 | + VaArg::Int(v) => Box::new(*v), |
| 25 | + VaArg::UInt(v) => Box::new(*v), |
| 26 | + VaArg::Long(v) => Box::new(*v), |
| 27 | + VaArg::ULong(v) => Box::new(*v), |
| 28 | + _ => panic!("format_c: integer conversion expects an integer argument"), |
| 29 | + }, |
| 30 | + ConversionType::OctInt |
| 31 | + | ConversionType::HexIntLower |
| 32 | + | ConversionType::HexIntUpper => match arg { |
| 33 | + VaArg::Int(v) => Box::new(*v as u32), |
| 34 | + VaArg::UInt(v) => Box::new(*v), |
| 35 | + VaArg::Long(v) => Box::new(*v as u64), |
| 36 | + VaArg::ULong(v) => Box::new(*v), |
| 37 | + VaArg::Ptr(p) => Box::new(p.to_int()), |
| 38 | + VaArg::RawPtr(v) => Box::new(*v as usize), |
| 39 | + VaArg::Double(_) => { |
| 40 | + panic!("format_c: integer conversion expects an integer argument") |
| 41 | + } |
| 42 | + }, |
| 43 | + ConversionType::Char => Box::new(i32::get(arg) as u8 as char), |
| 44 | + ConversionType::String => match arg { |
| 45 | + VaArg::Ptr(v) => Box::new(v.reinterpret_cast::<u8>().to_rust_string()), |
| 46 | + _ => panic!("format_c: %s expects a string argument"), |
| 47 | + }, |
| 48 | + ConversionType::DecFloatLower |
| 49 | + | ConversionType::DecFloatUpper |
| 50 | + | ConversionType::SciFloatLower |
| 51 | + | ConversionType::SciFloatUpper |
| 52 | + | ConversionType::CompactFloatLower |
| 53 | + | ConversionType::CompactFloatUpper => Box::new(f64::get(arg)), |
| 54 | + ConversionType::PercentSign => panic!("format_c: %% consumes no argument"), |
| 55 | + }); |
| 56 | + pos += 1; |
| 57 | + } |
| 58 | + } |
| 59 | + let refs: Vec<&dyn Printf> = args.iter().map(|arg| arg.as_ref()).collect(); |
| 60 | + match vsprintfp(&elements, &refs) { |
| 61 | + Ok(s) => s, |
| 62 | + Err(e) => panic!("format_c: cannot format {fmt:?}: {e:?}"), |
| 63 | + } |
| 64 | +} |
0 commit comments