diff --git a/src/c_str.rs b/src/c_str.rs index a41f2506ef..758fd4ae7f 100644 --- a/src/c_str.rs +++ b/src/c_str.rs @@ -21,17 +21,21 @@ pub enum Wide {} impl private::Sealed for Thin {} impl private::Sealed for Wide {} -pub trait Kind: private::Sealed + Copy { +pub trait Kind: private::Sealed + Copy + 'static { /// c_char or wchar_t - type C: Copy; + type C: Copy + 'static; // u8 or u32 - type Char: Copy + Into + PartialEq; + type Char: Copy + From + Into + PartialEq + 'static; const NUL: Self::Char; + const IS_THIN_NOT_WIDE: bool; + fn r2c(c: Self::Char) -> Self::C; fn c2r(c: Self::C) -> Self::Char; + fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]>; + unsafe fn strlen(s: *const Self::C) -> usize; unsafe fn strchr(s: *const Self::C, c: Self::C) -> *const Self::C; unsafe fn strchrnul(s: *const Self::C, c: Self::C) -> *const Self::C; @@ -41,6 +45,7 @@ impl Kind for Thin { type Char = u8; const NUL: Self::Char = 0; + const IS_THIN_NOT_WIDE: bool = true; unsafe fn strlen(s: *const c_char) -> usize { crate::header::string::strlen(s) @@ -57,12 +62,16 @@ impl Kind for Thin { fn c2r(c: c_char) -> u8 { c as _ } + fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> { + Some(b) + } } impl Kind for Wide { type C = wchar_t; type Char = u32; const NUL: Self::Char = 0; + const IS_THIN_NOT_WIDE: bool = false; unsafe fn strlen(s: *const Self::C) -> usize { crate::header::wchar::wcslen(s) @@ -83,6 +92,9 @@ impl Kind for Wide { fn c2r(c: Self::C) -> Self::Char { c as _ } + fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> { + None + } } /// Safe wrapper for immutable borrowed C strings, guaranteed to be the same layout as `*const u8`. @@ -118,8 +130,10 @@ impl<'a, T: Kind> NulStr<'a, T> { #[doc(alias = "strchrnul")] pub fn find_get_subslice_or_all( self, - c: T::Char, + c: impl Into, ) -> Result<(&'a [T::Char], Self), (&'a [T::Char], Self)> { + let c = c.into(); + // SAFETY: strchrnul expects self.as_ptr() to be valid up to and including its last NUL // byte let found = unsafe { T::strchrnul(self.as_ptr(), T::r2c(c)) }; diff --git a/src/header/stdio/printf.rs b/src/header/stdio/printf.rs index 367ab25c0f..b1ab4841e0 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -1,6 +1,6 @@ -// TODO: generalize with wprintf impl +// TODO: reuse more code with the wide printf impl use crate::{ - c_str::CStr, + c_str::{self, CStr, NulStr}, io::{self, Write}, }; use alloc::{ @@ -23,7 +23,7 @@ use crate::{ // |_| #[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum IntKind { +pub(crate) enum IntKind { Byte, Short, Int, @@ -34,7 +34,7 @@ enum IntKind { Size, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum FmtKind { +pub(crate) enum FmtKind { Percent, Signed, @@ -50,13 +50,13 @@ enum FmtKind { GetWritten, } #[derive(Clone, Copy, Debug)] -enum Number { +pub(crate) enum Number { Static(usize), Index(usize), Next, } impl Number { - unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { + pub(crate) unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { let arg = match self { Number::Static(num) => return num, Number::Index(i) => varargs.get(i - 1, ap, None), @@ -82,7 +82,7 @@ impl Number { } } #[derive(Clone, Copy, Debug)] -enum VaArg { +pub(crate) enum VaArg { c_char(c_char), c_double(c_double), c_int(c_int), @@ -96,7 +96,7 @@ enum VaArg { wint_t(wint_t), } impl VaArg { - unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg { + pub(crate) unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg { // Per the C standard using va_arg with a type with a size // less than that of an int for integers and double for floats // is invalid. As a result any arguments smaller than an int or @@ -227,12 +227,12 @@ impl VaArg { } } #[derive(Default)] -struct VaListCache { - args: Vec, - i: usize, +pub(crate) struct VaListCache { + pub(crate) args: Vec, + pub(crate) i: usize, } impl VaListCache { - unsafe fn get( + pub(crate) unsafe fn get( &mut self, i: usize, ap: &mut VaList, @@ -287,11 +287,11 @@ static INF_STR_UPPER: &str = "INF"; static NAN_STR_LOWER: &str = "nan"; static NAN_STR_UPPER: &str = "NAN"; -fn pop_int_raw(format: &mut CStr) -> Option { +fn pop_int_raw(format: &mut NulStr) -> Option { let mut int = None; while let Some((digit, rest)) = format - .split_first() - .and_then(|(d, r)| Some(((d as char).to_digit(10)?, r))) + .split_first_char() + .and_then(|(d, r)| Some((d.to_digit(10)?, r))) { *format = rest; if int.is_none() { @@ -302,19 +302,19 @@ fn pop_int_raw(format: &mut CStr) -> Option { } int } -fn pop_index(format: &mut CStr) -> Option { +fn pop_index(format: &mut NulStr) -> Option { // Peek ahead for a positional argument: let mut format2 = *format; if let Some(i) = pop_int_raw(&mut format2) { - if let Some((b'$', format2)) = format2.split_first() { + if let Some(('$', format2)) = format2.split_first_char() { *format = format2; return Some(i); } } None } -fn pop_int(format: &mut CStr) -> Option { - if let Some((b'*', rest)) = format.split_first() { +fn pop_int(format: &mut NulStr) -> Option { + if let Some(('*', rest)) = format.split_first_char() { *format = rest; Some(pop_index(format).map(Number::Index).unwrap_or(Number::Next)) } else { @@ -470,30 +470,31 @@ fn fmt_float_nonfinite(w: &mut W, float: c_double, case: FmtCase) -> i } #[derive(Clone, Copy)] -struct PrintfIter<'a> { - format: CStr<'a>, +pub(crate) struct PrintfIter<'a, T: c_str::Kind> { + pub(crate) format: NulStr<'a, T>, } #[derive(Clone, Copy, Debug)] -struct PrintfArg { - index: Option, - alternate: bool, - zero: bool, - left: bool, - sign_reserve: bool, - sign_always: bool, - min_width: Number, - precision: Option, - intkind: IntKind, - fmt: u8, - fmtkind: FmtKind, +pub(crate) struct PrintfArg { + pub(crate) index: Option, + pub(crate) alternate: bool, + pub(crate) zero: bool, + pub(crate) left: bool, + pub(crate) sign_reserve: bool, + pub(crate) sign_always: bool, + pub(crate) min_width: Number, + pub(crate) precision: Option, + pub(crate) intkind: IntKind, + pub(crate) fmt: char, + pub(crate) fmtkind: FmtKind, } #[derive(Debug)] -enum PrintfFmt<'a> { - Plain(&'a [u8]), +pub(crate) enum PrintfFmt<'a, U> { + Plain(&'a [U]), Arg(PrintfArg), } -impl<'a> Iterator for PrintfIter<'a> { - type Item = Result, ()>; +impl<'a, T: c_str::Kind> Iterator for PrintfIter<'a, T> { + type Item = Result, ()>; + fn next(&mut self) -> Option { // Send PrintfFmt::Plain until the next % let first_percent = match self.format.find_get_subslice_or_all(b'%') { @@ -521,13 +522,13 @@ impl<'a> Iterator for PrintfIter<'a> { let mut sign_reserve = false; let mut sign_always = false; - while let Some((c, rest)) = self.format.split_first() { + while let Some((c, rest)) = self.format.split_first_char() { match c { - b'#' => alternate = true, - b'0' => zero = true, - b'-' => left = true, - b' ' => sign_reserve = true, - b'+' => sign_always = true, + '#' => alternate = true, + '0' => zero = true, + '-' => left = true, + ' ' => sign_reserve = true, + '+' => sign_always = true, _ => break, } self.format = rest; @@ -535,7 +536,7 @@ impl<'a> Iterator for PrintfIter<'a> { // Width and precision: let min_width = pop_int(&mut self.format).unwrap_or(Number::Static(0)); - let precision = if let Some((b'.', rest)) = self.format.split_first() { + let precision = if let Some(('.', rest)) = self.format.split_first_char() { self.format = rest; match pop_int(&mut self.format) { int @ Some(_) => int, @@ -547,55 +548,59 @@ impl<'a> Iterator for PrintfIter<'a> { // Integer size: let mut intkind = IntKind::Int; - while let Some((byte, rest)) = self.format.split_first() { + while let Some((byte, rest)) = self.format.split_first_char() { intkind = match byte { - b'h' => { + 'h' => { if intkind == IntKind::Short || intkind == IntKind::Byte { IntKind::Byte } else { IntKind::Short } } - b'j' => IntKind::IntMax, - b'l' => { + 'j' => IntKind::IntMax, + 'l' => { if intkind == IntKind::Long || intkind == IntKind::LongLong { IntKind::LongLong } else { IntKind::Long } } - b'q' | b'L' => IntKind::LongLong, - b't' => IntKind::PtrDiff, - b'z' => IntKind::Size, + 'q' | 'L' => IntKind::LongLong, + 't' => IntKind::PtrDiff, + 'z' => IntKind::Size, _ => break, }; self.format = rest; } - let Some((fmt, rest)) = self.format.split_first() else { + let Some((fmt, rest)) = self.format.split_first_char() else { return Some(Err(())); }; self.format = rest; let fmtkind = match fmt { - b'%' => FmtKind::Percent, - b'd' | b'i' => FmtKind::Signed, - b'o' | b'u' | b'x' | b'X' | b'b' | b'B' => FmtKind::Unsigned, - b'e' | b'E' => FmtKind::Scientific, - b'f' | b'F' => FmtKind::Decimal, - b'g' | b'G' => FmtKind::AnyNotation, - b's' => FmtKind::String, - b'c' => FmtKind::Char, - b'p' => FmtKind::Pointer, - b'n' => FmtKind::GetWritten, - b'm' => { + '%' => FmtKind::Percent, + 'd' | 'i' => FmtKind::Signed, + 'o' | 'u' | 'x' | 'X' => FmtKind::Unsigned, + 'b' | 'B' if T::IS_THIN_NOT_WIDE => FmtKind::Unsigned, + 'e' | 'E' => FmtKind::Scientific, + 'f' | 'F' => FmtKind::Decimal, + 'g' | 'G' => FmtKind::AnyNotation, + 's' => FmtKind::String, + 'c' => FmtKind::Char, + 'p' => FmtKind::Pointer, + 'n' => FmtKind::GetWritten, + 'm' if T::IS_THIN_NOT_WIDE => { // %m is technically for syslog only, but musl and glibc implement it for // printf because it is difficult and error prone to implement a format // specifier for just *one* function. return Some(Ok(PrintfFmt::Plain( - errno::STR_ERROR - .get(platform::ERRNO.get() as usize) - .map(|e| e.as_bytes()) - .unwrap_or(b"unknown error"), + T::chars_from_bytes( + errno::STR_ERROR + .get(platform::ERRNO.get() as usize) + .map(|e| e.as_bytes()) + .unwrap_or(b"unknown error"), + ) + .expect("string must be thin"), ))); } _ => return Some(Err(())), @@ -689,7 +694,7 @@ unsafe fn inner_printf(w: W, format: CStr, mut ap: VaList) -> io::Resu signed_space as usize }; let intkind = arg.intkind; - let fmt = arg.fmt; + let fmt = arg.fmt as u8; let fmtkind = arg.fmtkind; let fmtcase = match fmt { b'x' | b'b' | b'f' | b'e' | b'g' => Some(FmtCase::Lower), diff --git a/src/header/wchar/wprintf.rs b/src/header/wchar/wprintf.rs index c89b7397e0..67f6d0b516 100644 --- a/src/header/wchar/wprintf.rs +++ b/src/header/wchar/wprintf.rs @@ -1,6 +1,7 @@ -// TODO: generalize with printf impl +// TODO: reuse more code with the thin printf impl use crate::{ - c_str::WStr, + c_str::{self, WStr}, + header::stdio::printf::{FmtKind, IntKind, Number, PrintfFmt, PrintfIter, VaArg, VaListCache}, io::{self, Write}, }; use alloc::{ @@ -15,259 +16,6 @@ use crate::{ platform::{self, types::*}, }; -// ____ _ _ _ _ -// | __ ) ___ (_) | ___ _ __ _ __ | | __ _| |_ ___ _ -// | _ \ / _ \| | |/ _ \ '__| '_ \| |/ _` | __/ _ (_) -// | |_) | (_) | | | __/ | | |_) | | (_| | || __/_ -// |____/ \___/|_|_|\___|_| | .__/|_|\__,_|\__\___(_) -// |_| - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum IntKind { - Byte, - Short, - Int, - Long, - LongLong, - IntMax, - PtrDiff, - Size, -} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum FmtKind { - Percent, - - Signed, - Unsigned, - - Scientific, - Decimal, - AnyNotation, - - String, - Char, - Pointer, - GetWritten, -} -#[derive(Clone, Copy, Debug)] -enum Number { - Static(usize), - Index(usize), - Next, -} -impl Number { - unsafe fn resolve(self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { - let arg = match self { - Number::Static(num) => return num, - Number::Index(i) => varargs.get(i - 1, ap, None), - Number::Next => { - let i = varargs.i; - varargs.i += 1; - varargs.get(i, ap, None) - } - }; - match arg { - VaArg::c_char(i) => i as usize, - VaArg::c_double(i) => i as usize, - VaArg::c_int(i) => i as usize, - VaArg::c_long(i) => i as usize, - VaArg::c_longlong(i) => i as usize, - VaArg::c_short(i) => i as usize, - VaArg::intmax_t(i) => i as usize, - VaArg::pointer(i) => i as usize, - VaArg::ptrdiff_t(i) => i as usize, - VaArg::ssize_t(i) => i as usize, - VaArg::wint_t(i) => i as usize, - } - } -} -#[derive(Clone, Copy, Debug)] -enum VaArg { - c_char(c_char), - c_double(c_double), - c_int(c_int), - c_long(c_long), - c_longlong(c_longlong), - c_short(c_short), - intmax_t(intmax_t), - pointer(*const c_void), - ptrdiff_t(ptrdiff_t), - ssize_t(ssize_t), - wint_t(wint_t), -} -impl VaArg { - unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg { - // Per the C standard using va_arg with a type with a size - // less than that of an int for integers and double for floats - // is invalid. As a result any arguments smaller than an int or - // double passed to a function will be promoted to the smallest - // possible size. The VaList::arg function will handle this - // automagically. - - match (fmtkind, intkind) { - (FmtKind::Percent, _) => panic!("Can't call arg_from on %"), - - (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => { - VaArg::wint_t(ap.arg::()) - } - - (FmtKind::Char, _) - | (FmtKind::Unsigned, IntKind::Byte) - | (FmtKind::Signed, IntKind::Byte) => { - // c_int is passed but truncated to c_char - VaArg::c_char(ap.arg::() as c_char) - } - (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => { - // c_int is passed but truncated to c_short - VaArg::c_short(ap.arg::() as c_short) - } - (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => { - VaArg::c_int(ap.arg::()) - } - (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => { - VaArg::c_long(ap.arg::()) - } - (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => { - VaArg::c_longlong(ap.arg::()) - } - (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => { - VaArg::intmax_t(ap.arg::()) - } - (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => { - VaArg::ptrdiff_t(ap.arg::()) - } - (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => { - VaArg::ssize_t(ap.arg::()) - } - - (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => { - VaArg::c_double(ap.arg::()) - } - - (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => { - VaArg::pointer(ap.arg::<*const c_void>()) - } - } - } - unsafe fn transmute(&self, fmtkind: FmtKind, intkind: IntKind) -> VaArg { - // At this point, there are conflicting wprintf arguments. An - // example of this is: - // ```c - // wprintf(L"%1$d %1$lf\n", 5, 0.1); - // ``` - // We handle it just like glibc: We read it from the VaList - // using the *last* argument type, but we transmute it when we - // try to access the other ones. - union Untyped { - c_char: c_char, - c_double: c_double, - c_int: c_int, - c_long: c_long, - c_longlong: c_longlong, - c_short: c_short, - intmax_t: intmax_t, - pointer: *const c_void, - ptrdiff_t: ptrdiff_t, - ssize_t: ssize_t, - wint_t: wint_t, - } - let untyped = match *self { - VaArg::c_char(i) => Untyped { c_char: i }, - VaArg::c_double(i) => Untyped { c_double: i }, - VaArg::c_int(i) => Untyped { c_int: i }, - VaArg::c_long(i) => Untyped { c_long: i }, - VaArg::c_longlong(i) => Untyped { c_longlong: i }, - VaArg::c_short(i) => Untyped { c_short: i }, - VaArg::intmax_t(i) => Untyped { intmax_t: i }, - VaArg::pointer(i) => Untyped { pointer: i }, - VaArg::ptrdiff_t(i) => Untyped { ptrdiff_t: i }, - VaArg::ssize_t(i) => Untyped { ssize_t: i }, - VaArg::wint_t(i) => Untyped { wint_t: i }, - }; - match (fmtkind, intkind) { - (FmtKind::Percent, _) => panic!("Can't call transmute on %"), - - (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => { - VaArg::wint_t(untyped.wint_t) - } - - (FmtKind::Char, _) - | (FmtKind::Unsigned, IntKind::Byte) - | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char), - (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => { - VaArg::c_short(untyped.c_short) - } - (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => { - VaArg::c_int(untyped.c_int) - } - (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => { - VaArg::c_long(untyped.c_long) - } - (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => { - VaArg::c_longlong(untyped.c_longlong) - } - (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => { - VaArg::intmax_t(untyped.intmax_t) - } - (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => { - VaArg::ptrdiff_t(untyped.ptrdiff_t) - } - (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => { - VaArg::ssize_t(untyped.ssize_t) - } - - (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => { - VaArg::c_double(untyped.c_double) - } - - (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => { - VaArg::pointer(untyped.pointer) - } - } - } -} -#[derive(Default)] -struct VaListCache { - args: Vec, - i: usize, -} -impl VaListCache { - unsafe fn get( - &mut self, - i: usize, - ap: &mut VaList, - default: Option<(FmtKind, IntKind)>, - ) -> VaArg { - if let Some(&arg) = self.args.get(i) { - // This value is already cached - let mut arg = arg; - if let Some((fmtkind, intkind)) = default { - // ...but as a different type - arg = arg.transmute(fmtkind, intkind); - } - return arg; - } - - // Get all values before this value - while self.args.len() < i { - // We can't POSSIBLY know the type if we reach this - // point. Reaching here means there are unused gaps in the - // arguments. Ultimately we'll have to settle down with - // defaulting to c_int. - self.args.push(VaArg::c_int(ap.arg::())) - } - - // Add the value to the cache - self.args.push(match default { - Some((fmtkind, intkind)) => VaArg::arg_from(fmtkind, intkind, ap), - None => VaArg::c_int(ap.arg::()), - }); - - // Return the value - self.args[i] - } -} - // ___ _ _ _ _ // |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ // | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \(_) @@ -287,41 +35,6 @@ static INF_STR_UPPER: &str = "INF"; static NAN_STR_LOWER: &str = "nan"; static NAN_STR_UPPER: &str = "NAN"; -fn pop_int_raw(format: &mut WStr) -> Option { - let mut int = None; - while let Some((digit, rest)) = format - .split_first_char() - .and_then(|(c, r)| Some((c.to_digit(10)?, r))) - { - *format = rest; - if int.is_none() { - int = Some(0); - } - *int.as_mut().unwrap() *= 10; - *int.as_mut().unwrap() += digit as usize; - } - int -} -fn pop_index(format: &mut WStr) -> Option { - // Peek ahead for a positional argument: - let mut format2 = *format; - if let Some(i) = pop_int_raw(&mut format2) { - if let Some(('$', rest)) = format2.split_first_char() { - *format = rest; - return Some(i); - } - } - None -} -fn pop_int(format: &mut WStr) -> Option { - if let Some(('*', rest)) = format.split_first_char() { - *format = rest; - Some(pop_index(format).map(Number::Index).unwrap_or(Number::Next)) - } else { - pop_int_raw(format).map(Number::Static) - } -} - fn fmt_int(fmt: u32, i: I) -> String where I: fmt::Display + fmt::Octal + fmt::LowerHex + fmt::UpperHex, @@ -481,146 +194,10 @@ fn fmt_float_nonfinite(w: &mut W, float: c_double, case: FmtCase) -> i Ok(()) } -#[derive(Clone, Copy)] -struct WPrintfIter<'a> { - format: WStr<'a>, -} -#[derive(Clone, Copy, Debug)] -struct WPrintfArg { - index: Option, - alternate: bool, - zero: bool, - left: bool, - sign_reserve: bool, - sign_always: bool, - min_width: Number, - precision: Option, - intkind: IntKind, - fmt: u32, - fmtkind: FmtKind, -} -#[derive(Debug)] -enum WPrintfFmt<'a> { - Plain(&'a [u32]), - Arg(WPrintfArg), -} -impl<'a> Iterator for WPrintfIter<'a> { - type Item = Result, ()>; - fn next(&mut self) -> Option { - unsafe { - // Send WPrintfFmt::Plain until the next % - let first_percent = match self.format.find_get_subslice_or_all(u32::from(b'%')) { - Err(([], _)) => return None, - Ok((chunk @ [_, ..], rest)) | Err((chunk @ [_, ..], rest)) => { - self.format = rest; - return Some(Ok(WPrintfFmt::Plain(chunk))); - } - Ok(([], rest)) => rest, - }; - - let mut peekahead = self.format; - let index = pop_index(&mut peekahead).map(|i| { - self.format = peekahead; - i - }); - - // Flags: - let mut alternate = false; - let mut zero = false; - let mut left = false; - let mut sign_reserve = false; - let mut sign_always = false; - - while let Some((c, rest)) = self.format.split_first_char() { - match c { - '#' => alternate = true, - '0' => zero = true, - '-' => left = true, - ' ' => sign_reserve = true, - '+' => sign_always = true, - _ => break, - } - self.format = rest; - } - - // Width and precision: - let min_width = pop_int(&mut self.format).unwrap_or(Number::Static(0)); - let precision = if let Some(('.', rest)) = self.format.split_first_char() { - self.format = rest; - match pop_int(&mut self.format) { - int @ Some(_) => int, - None => return Some(Err(())), - } - } else { - None - }; - - // Integer size: - let mut intkind = IntKind::Int; - while let Some((char, rest)) = self.format.split_first_char() { - intkind = match char { - 'h' => { - if intkind == IntKind::Short || intkind == IntKind::Byte { - IntKind::Byte - } else { - IntKind::Short - } - } - 'j' => IntKind::IntMax, - 'l' => { - if intkind == IntKind::Long || intkind == IntKind::LongLong { - IntKind::LongLong - } else { - IntKind::Long - } - } - 'q' | 'L' => IntKind::LongLong, - 't' => IntKind::PtrDiff, - 'z' => IntKind::Size, - _ => break, - }; - - self.format = rest; - } - let Some((fmt, rest)) = self.format.split_first_char() else { - return Some(Err(())); - }; - let fmtkind = match fmt { - '%' => FmtKind::Percent, - 'd' | 'i' => FmtKind::Signed, - 'o' | 'u' | 'x' | 'X' => FmtKind::Unsigned, - 'e' | 'E' => FmtKind::Scientific, - 'f' | 'F' => FmtKind::Decimal, - 'g' | 'G' => FmtKind::AnyNotation, - 's' => FmtKind::String, - 'c' => FmtKind::Char, - 'p' => FmtKind::Pointer, - 'n' => FmtKind::GetWritten, - _ => return Some(Err(())), - }; - self.format = rest; - - Some(Ok(WPrintfFmt::Arg(WPrintfArg { - index, - alternate, - zero, - left, - sign_reserve, - sign_always, - min_width, - precision, - intkind, - fmt: fmt as u32, - fmtkind, - }))) - } - } -} - unsafe fn inner_wprintf(w: W, format: WStr, mut ap: VaList) -> io::Result { let w = &mut platform::CountingWriter::new(w); - let iterator = WPrintfIter { format }; + let iterator = PrintfIter:: { format }; // Pre-fetch vararg types let mut varargs = VaListCache::default(); @@ -629,8 +206,8 @@ unsafe fn inner_wprintf(w: W, format: WStr, mut ap: VaList) -> io::Res for section in iterator { let arg = match section { - Ok(WPrintfFmt::Plain(text)) => continue, - Ok(WPrintfFmt::Arg(arg)) => arg, + Ok(PrintfFmt::Plain(text)) => continue, + Ok(PrintfFmt::Arg(arg)) => arg, Err(()) => return Ok(-1), }; if arg.fmtkind == FmtKind::Percent { @@ -663,7 +240,7 @@ unsafe fn inner_wprintf(w: W, format: WStr, mut ap: VaList) -> io::Res // Main loop for section in iterator { let arg = match section { - Ok(WPrintfFmt::Plain(text)) => { + Ok(PrintfFmt::Plain(text)) => { for &wc in text.iter() { if let Some(c) = char::from_u32(wc) { write!(w, "{}", c)?; @@ -671,7 +248,7 @@ unsafe fn inner_wprintf(w: W, format: WStr, mut ap: VaList) -> io::Res } continue; } - Ok(WPrintfFmt::Arg(arg)) => arg, + Ok(PrintfFmt::Arg(arg)) => arg, Err(()) => return Ok(-1), }; let alternate = arg.alternate; @@ -693,9 +270,10 @@ unsafe fn inner_wprintf(w: W, format: WStr, mut ap: VaList) -> io::Res signed_space as usize }; let intkind = arg.intkind; - let fmt = arg.fmt; + let fmt_char = arg.fmt; + let fmt = fmt_char as u32; let fmtkind = arg.fmtkind; - let fmtcase = match char::from_u32(fmt).unwrap_or('\0') { + let fmtcase = match fmt_char { 'x' | 'f' | 'e' | 'g' => Some(FmtCase::Lower), 'X' | 'F' | 'E' | 'G' => Some(FmtCase::Upper), _ => None,