Share almost all code between printf and wprintf.

4lDO2 1c5732ba 96917f51

Changed files
+61 -600
src
header
stdio
wchar
+7
src/c_str.rs
··· 35 35 fn c2r(c: Self::C) -> Self::Char; 36 36 37 37 fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]>; 38 + fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]>; 38 39 39 40 unsafe fn strlen(s: *const Self::C) -> usize; 40 41 unsafe fn strchr(s: *const Self::C, c: Self::C) -> *const Self::C; ··· 64 65 } 65 66 fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> { 66 67 Some(b) 68 + } 69 + fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]> { 70 + Some(c) 67 71 } 68 72 } 69 73 impl Kind for Wide { ··· 93 97 c as _ 94 98 } 95 99 fn chars_from_bytes(b: &[u8]) -> Option<&[Self::Char]> { 100 + None 101 + } 102 + fn chars_to_bytes(c: &[Self::Char]) -> Option<&[u8]> { 96 103 None 97 104 } 98 105 }
+48 -32
src/header/stdio/printf.rs
··· 322 322 } 323 323 } 324 324 325 - fn fmt_int<I>(fmt: u8, i: I) -> String 325 + fn fmt_int<I, T: c_str::Kind>(fmt: char, i: I) -> String 326 326 where 327 327 I: fmt::Display + fmt::Octal + fmt::LowerHex + fmt::UpperHex + fmt::Binary, 328 328 { 329 329 match fmt { 330 - b'o' => format!("{:o}", i), 331 - b'u' => i.to_string(), 332 - b'x' => format!("{:x}", i), 333 - b'X' => format!("{:X}", i), 334 - b'b' | b'B' => format!("{:b}", i), 330 + 'o' => format!("{:o}", i), 331 + 'u' => i.to_string(), 332 + 'x' => format!("{:x}", i), 333 + 'X' => format!("{:X}", i), 334 + 'b' | 'B' if T::IS_THIN_NOT_WIDE => format!("{:b}", i), 335 335 _ => panic!( 336 336 "fmt_int should never be called with the fmt {:?}", 337 337 fmt as char, ··· 384 384 385 385 fn fmt_float_exp<W: Write>( 386 386 w: &mut W, 387 - exp_fmt: u8, 387 + exp_fmt: char, 388 388 trim: bool, 389 389 precision: usize, 390 390 float: c_double, ··· 412 412 }; 413 413 pad(w, !left, b'0', len..pad_zero)?; 414 414 w.write_all(bytes)?; 415 - write!(w, "{}{:+03}", exp_fmt as char, exp)?; 415 + write!(w, "{}{:+03}", exp_fmt, exp)?; 416 416 pad(w, left, b' ', len..pad_space)?; 417 417 418 418 Ok(()) ··· 622 622 } 623 623 } 624 624 625 - unsafe fn inner_printf<W: Write>(w: W, format: CStr, mut ap: VaList) -> io::Result<c_int> { 625 + pub(crate) unsafe fn inner_printf<T: c_str::Kind>( 626 + w: impl Write, 627 + format: NulStr<T>, 628 + mut ap: VaList, 629 + ) -> io::Result<c_int> { 626 630 let w = &mut platform::CountingWriter::new(w); 627 631 628 632 let iterator = PrintfIter { format }; ··· 669 673 for section in iterator { 670 674 let arg = match section { 671 675 Ok(PrintfFmt::Plain(text)) => { 672 - w.write_all(text)?; 676 + if T::IS_THIN_NOT_WIDE { 677 + let bytes = T::chars_to_bytes(text).expect("is thin"); 678 + w.write_all(bytes)?; 679 + } else { 680 + // TODO: wcsrtombs wrapper 681 + for c in text.iter().filter_map(|u| char::from_u32((*u).into())) { 682 + write!(w, "{}", c); 683 + } 684 + } 673 685 continue; 674 686 } 675 687 Ok(PrintfFmt::Arg(arg)) => arg, ··· 694 706 signed_space as usize 695 707 }; 696 708 let intkind = arg.intkind; 697 - let fmt = arg.fmt as u8; 709 + let fmt = arg.fmt; 698 710 let fmtkind = arg.fmtkind; 699 711 let fmtcase = match fmt { 700 - b'x' | b'b' | b'f' | b'e' | b'g' => Some(FmtCase::Lower), 701 - b'X' | b'B' | b'F' | b'E' | b'G' => Some(FmtCase::Upper), 712 + 'b' if T::IS_THIN_NOT_WIDE => Some(FmtCase::Lower), 713 + 'B' if T::IS_THIN_NOT_WIDE => Some(FmtCase::Upper), 714 + 'x' | 'f' | 'e' | 'g' => Some(FmtCase::Lower), 715 + 'X' | 'F' | 'E' | 'G' => Some(FmtCase::Upper), 702 716 _ => None, 703 717 }; 704 718 ··· 764 778 } 765 779 FmtKind::Unsigned => { 766 780 let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 767 - VaArg::c_char(i) => fmt_int(fmt, i as c_uchar), 781 + VaArg::c_char(i) => fmt_int::<_, T>(fmt, i as c_uchar), 768 782 VaArg::c_double(i) => panic!("this should not be possible"), 769 - VaArg::c_int(i) => fmt_int(fmt, i as c_uint), 770 - VaArg::c_long(i) => fmt_int(fmt, i as c_ulong), 771 - VaArg::c_longlong(i) => fmt_int(fmt, i as c_ulonglong), 772 - VaArg::c_short(i) => fmt_int(fmt, i as c_ushort), 773 - VaArg::intmax_t(i) => fmt_int(fmt, i as uintmax_t), 774 - VaArg::pointer(i) => fmt_int(fmt, i as usize), 775 - VaArg::ptrdiff_t(i) => fmt_int(fmt, i as size_t), 776 - VaArg::ssize_t(i) => fmt_int(fmt, i as size_t), 783 + VaArg::c_int(i) => fmt_int::<_, T>(fmt, i as c_uint), 784 + VaArg::c_long(i) => fmt_int::<_, T>(fmt, i as c_ulong), 785 + VaArg::c_longlong(i) => fmt_int::<_, T>(fmt, i as c_ulonglong), 786 + VaArg::c_short(i) => fmt_int::<_, T>(fmt, i as c_ushort), 787 + VaArg::intmax_t(i) => fmt_int::<_, T>(fmt, i as uintmax_t), 788 + VaArg::pointer(i) => fmt_int::<_, T>(fmt, i as usize), 789 + VaArg::ptrdiff_t(i) => fmt_int::<_, T>(fmt, i as size_t), 790 + VaArg::ssize_t(i) => fmt_int::<_, T>(fmt, i as size_t), 777 791 VaArg::wint_t(_) => unreachable!("this should not be possible"), 778 792 }; 779 793 let zero = precision == Some(0) && string == "0"; ··· 791 805 len.max(precision.unwrap_or(0)) 792 806 + if alternate && string != "0" { 793 807 match fmt { 794 - b'o' if no_precision => 1, 795 - b'x' | b'X' | b'b' | b'B' => 2, 808 + 'o' if no_precision => 1, 809 + 'x' | 'X' => 2, 810 + 'b' | 'B' if T::IS_THIN_NOT_WIDE => 2, 796 811 _ => 0, 797 812 } 798 813 } else { ··· 804 819 805 820 if alternate && string != "0" { 806 821 match fmt { 807 - b'o' if no_precision => w.write_all(b"0")?, 808 - b'x' => w.write_all(b"0x")?, 809 - b'X' => w.write_all(b"0X")?, 810 - b'b' => w.write_all(b"0b")?, 811 - b'B' => w.write_all(b"0B")?, 822 + 'o' if no_precision => w.write_all(b"0")?, 823 + 'x' => w.write_all(b"0x")?, 824 + 'X' => w.write_all(b"0X")?, 825 + 'b' if T::IS_THIN_NOT_WIDE => w.write_all(b"0b")?, 826 + 'B' if T::IS_THIN_NOT_WIDE => w.write_all(b"0B")?, 812 827 _ => (), 813 828 } 814 829 } ··· 856 871 }; 857 872 if float.is_finite() { 858 873 let (log, exp) = float_exp(float); 859 - let exp_fmt = b'E' | (fmt & 32); 874 + // TODO: .is_uppercase()? 875 + let exp_fmt = if fmt as u32 & 32 == 32 { 'e' } else { 'E' }; 860 876 let precision = precision.unwrap_or(6); 861 877 let use_exp_format = exp < -4 || exp >= precision as isize; 862 878 ··· 1263 1279 /// # Safety 1264 1280 /// Behavior is undefined if any of the following conditions are violated: 1265 1281 /// - `ap` must follow the safety contract of variable arguments of C. 1266 - pub unsafe fn printf<W: Write>(w: W, format: CStr, ap: VaList) -> c_int { 1267 - inner_printf(w, format, ap).unwrap_or(-1) 1282 + pub unsafe fn printf(w: impl Write, format: CStr, ap: VaList) -> c_int { 1283 + inner_printf::<c_str::Thin>(w, format, ap).unwrap_or(-1) 1268 1284 }
+6 -568
src/header/wchar/wprintf.rs
··· 1 1 // TODO: reuse more code with the thin printf impl 2 2 use crate::{ 3 3 c_str::{self, WStr}, 4 - header::stdio::printf::{FmtKind, IntKind, Number, PrintfFmt, PrintfIter, VaArg, VaListCache}, 5 - io::{self, Write}, 6 - }; 7 - use alloc::{ 8 - collections::BTreeMap, 9 - string::{String, ToString}, 10 - vec::Vec, 11 - }; 12 - use core::{char, cmp, f64, ffi::VaList, fmt, num::FpCategory, ops::Range, slice}; 13 - 14 - use crate::{ 15 - header::errno::EILSEQ, 16 - platform::{self, types::*}, 4 + header::stdio::printf::inner_printf, 5 + io::Write, 17 6 }; 18 - 19 - // ___ _ _ _ _ 20 - // |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ 21 - // | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \(_) 22 - // | || | | | | | |_) | | __/ | | | | | __/ | | | || (_| | |_| | (_) | | | |_ 23 - // |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_(_) 24 - // |_| 25 - 26 - enum FmtCase { 27 - Lower, 28 - Upper, 29 - } 30 - 31 - // The spelled-out "infinity"/"INFINITY" is also permitted by the standard 32 - static INF_STR_LOWER: &str = "inf"; 33 - static INF_STR_UPPER: &str = "INF"; 34 - 35 - static NAN_STR_LOWER: &str = "nan"; 36 - static NAN_STR_UPPER: &str = "NAN"; 37 - 38 - fn fmt_int<I>(fmt: u32, i: I) -> String 39 - where 40 - I: fmt::Display + fmt::Octal + fmt::LowerHex + fmt::UpperHex, 41 - { 42 - match char::from_u32(fmt).unwrap_or('\0') { 43 - 'o' => format!("{:o}", i), 44 - 'u' => i.to_string(), 45 - 'x' => format!("{:x}", i), 46 - 'X' => format!("{:X}", i), 47 - _ => panic!( 48 - "fmt_int should never be called with the fmt {:?}", 49 - char::from_u32(fmt) 50 - ), 51 - } 52 - } 53 - 54 - fn pad<W: Write>( 55 - w: &mut W, 56 - current_side: bool, 57 - pad_char: u32, 58 - range: Range<usize>, 59 - ) -> io::Result<()> { 60 - if current_side { 61 - for _ in range { 62 - if let Some(c) = char::from_u32(pad_char) { 63 - write!(w, "{}", c)?; 64 - } 65 - } 66 - } 67 - Ok(()) 68 - } 69 - 70 - fn abs(float: c_double) -> c_double { 71 - // Don't ask me whe float.abs() seems absent... 72 - if float.is_sign_negative() { 73 - -float 74 - } else { 75 - float 76 - } 77 - } 78 - 79 - fn float_string(float: c_double, precision: usize, trim: bool) -> String { 80 - let mut string = format!("{:.p$}", float, p = precision); 81 - if trim && string.contains('.') { 82 - let truncate = { 83 - let slice = string.trim_end_matches('0'); 84 - let mut truncate = slice.len(); 85 - if slice.ends_with('.') { 86 - truncate -= 1; 87 - } 88 - truncate 89 - }; 90 - string.truncate(truncate); 91 - } 92 - string 93 - } 94 - 95 - fn float_exp(mut float: c_double) -> (c_double, isize) { 96 - let mut exp: isize = 0; 97 - while abs(float) >= 10.0 { 98 - float /= 10.0; 99 - exp += 1; 100 - } 101 - while f64::EPSILON < abs(float) && abs(float) < 1.0 { 102 - float *= 10.0; 103 - exp -= 1; 104 - } 105 - (float, exp) 106 - } 107 - 108 - fn fmt_float_exp<W: Write>( 109 - w: &mut W, 110 - exp_fmt: u32, 111 - trim: bool, 112 - precision: usize, 113 - float: c_double, 114 - exp: isize, 115 - left: bool, 116 - pad_space: usize, 117 - pad_zero: usize, 118 - ) -> io::Result<()> { 119 - let mut exp2 = exp; 120 - let mut exp_len = 1; 121 - while exp2 >= 10 { 122 - exp2 /= 10; 123 - exp_len += 1; 124 - } 125 - 126 - let string = float_string(float, precision, trim); 127 - let len = string.len() + 2 + 2.max(exp_len); 128 - 129 - pad(w, !left, ' ' as u32, len..pad_space)?; 130 - let bytes = if string.starts_with('-') { 131 - w.write_all(&[b'-'])?; 132 - &string.as_bytes()[1..] 133 - } else { 134 - string.as_bytes() 135 - }; 136 - pad(w, !left, '0' as u32, len..pad_zero)?; 137 - w.write_all(bytes)?; 138 - if let Some(c) = char::from_u32(exp_fmt) { 139 - write!(w, "{}{:+03}", c, exp)?; 140 - } 141 - pad(w, left, ' ' as u32, len..pad_space)?; 142 - 143 - Ok(()) 144 - } 145 - 146 - fn fmt_float_normal<W: Write>( 147 - w: &mut W, 148 - trim: bool, 149 - precision: usize, 150 - float: c_double, 151 - left: bool, 152 - pad_space: usize, 153 - pad_zero: usize, 154 - ) -> io::Result<usize> { 155 - let string = float_string(float, precision, trim); 156 - 157 - pad(w, !left, ' ' as u32, string.len()..pad_space)?; 158 - let bytes = if string.starts_with('-') { 159 - w.write_all(&[b'-'])?; 160 - &string.as_bytes()[1..] 161 - } else { 162 - string.as_bytes() 163 - }; 164 - pad(w, true, '0' as u32, string.len()..pad_zero)?; 165 - w.write_all(bytes)?; 166 - pad(w, left, ' ' as u32, string.len()..pad_space)?; 167 - 168 - Ok(string.len()) 169 - } 170 - 171 - /// Write ±infinity or ±NaN representation for any floating-point style 172 - fn fmt_float_nonfinite<W: Write>(w: &mut W, float: c_double, case: FmtCase) -> io::Result<()> { 173 - if float.is_sign_negative() { 174 - w.write_all(&[b'-'])?; 175 - } 176 - 177 - let nonfinite_str = match float.classify() { 178 - FpCategory::Infinite => match case { 179 - FmtCase::Lower => INF_STR_LOWER, 180 - FmtCase::Upper => INF_STR_UPPER, 181 - }, 182 - FpCategory::Nan => match case { 183 - FmtCase::Lower => NAN_STR_LOWER, 184 - FmtCase::Upper => NAN_STR_UPPER, 185 - }, 186 - _ => { 187 - // This function should only be called with infinite or NaN value. 188 - panic!("this should not be possible") 189 - } 190 - }; 191 - 192 - w.write_all(nonfinite_str.as_bytes())?; 193 - 194 - Ok(()) 195 - } 196 - 197 - unsafe fn inner_wprintf<W: Write>(w: W, format: WStr, mut ap: VaList) -> io::Result<c_int> { 198 - let w = &mut platform::CountingWriter::new(w); 199 - 200 - let iterator = PrintfIter::<c_str::Wide> { format }; 201 - 202 - // Pre-fetch vararg types 203 - let mut varargs = VaListCache::default(); 204 - let mut positional = BTreeMap::new(); 205 - // ^ NOTE: This depends on the sorted order, do not change to HashMap or whatever 206 - 207 - for section in iterator { 208 - let arg = match section { 209 - Ok(PrintfFmt::Plain(text)) => continue, 210 - Ok(PrintfFmt::Arg(arg)) => arg, 211 - Err(()) => return Ok(-1), 212 - }; 213 - if arg.fmtkind == FmtKind::Percent { 214 - continue; 215 - } 216 - for num in &[arg.min_width, arg.precision.unwrap_or(Number::Static(0))] { 217 - match num { 218 - Number::Next => varargs.args.push(VaArg::c_int(ap.arg::<c_int>())), 219 - Number::Index(i) => { 220 - positional.insert(i - 1, (FmtKind::Signed, IntKind::Int)); 221 - } 222 - Number::Static(_) => (), 223 - } 224 - } 225 - match arg.index { 226 - Some(i) => { 227 - positional.insert(i - 1, (arg.fmtkind, arg.intkind)); 228 - } 229 - None => varargs 230 - .args 231 - .push(VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap)), 232 - } 233 - } 234 - 235 - // Make sure, in order, the positional arguments exist with the specified type 236 - for (i, arg) in positional { 237 - varargs.get(i, &mut ap, Some(arg)); 238 - } 239 - 240 - // Main loop 241 - for section in iterator { 242 - let arg = match section { 243 - Ok(PrintfFmt::Plain(text)) => { 244 - for &wc in text.iter() { 245 - if let Some(c) = char::from_u32(wc) { 246 - write!(w, "{}", c)?; 247 - } 248 - } 249 - continue; 250 - } 251 - Ok(PrintfFmt::Arg(arg)) => arg, 252 - Err(()) => return Ok(-1), 253 - }; 254 - let alternate = arg.alternate; 255 - let zero = arg.zero; 256 - let mut left = arg.left; 257 - let sign_reserve = arg.sign_reserve; 258 - let sign_always = arg.sign_always; 259 - let min_width = arg.min_width.resolve(&mut varargs, &mut ap); 260 - let precision = arg.precision.map(|n| n.resolve(&mut varargs, &mut ap)); 261 - let pad_zero = if zero { min_width } else { 0 }; 262 - let signed_space = match pad_zero { 263 - 0 => min_width as isize, 264 - _ => 0, 265 - }; 266 - let pad_space = if signed_space < 0 { 267 - left = true; 268 - -signed_space as usize 269 - } else { 270 - signed_space as usize 271 - }; 272 - let intkind = arg.intkind; 273 - let fmt_char = arg.fmt; 274 - let fmt = fmt_char as u32; 275 - let fmtkind = arg.fmtkind; 276 - let fmtcase = match fmt_char { 277 - 'x' | 'f' | 'e' | 'g' => Some(FmtCase::Lower), 278 - 'X' | 'F' | 'E' | 'G' => Some(FmtCase::Upper), 279 - _ => None, 280 - }; 281 - 282 - let index = arg.index.map(|i| i - 1).unwrap_or_else(|| { 283 - if fmtkind == FmtKind::Percent { 284 - 0 285 - } else { 286 - let i = varargs.i; 287 - varargs.i += 1; 288 - i 289 - } 290 - }); 291 - 292 - match fmtkind { 293 - FmtKind::Percent => w.write_all(&[b'%'])?, 294 - FmtKind::Signed => { 295 - let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 296 - VaArg::c_char(i) => i.to_string(), 297 - VaArg::c_double(i) => panic!("this should not be possible"), 298 - VaArg::c_int(i) => i.to_string(), 299 - VaArg::c_long(i) => i.to_string(), 300 - VaArg::c_longlong(i) => i.to_string(), 301 - VaArg::c_short(i) => i.to_string(), 302 - VaArg::intmax_t(i) => i.to_string(), 303 - VaArg::pointer(i) => (i as usize).to_string(), 304 - VaArg::ptrdiff_t(i) => i.to_string(), 305 - VaArg::ssize_t(i) => i.to_string(), 306 - VaArg::wint_t(_) => unreachable!("this should not be possible"), 307 - }; 308 - let positive = !string.starts_with('-'); 309 - let zero = precision == Some(0) && string == "0"; 310 - 311 - let mut len = string.len(); 312 - let mut final_len = string.len().max(precision.unwrap_or(0)); 313 - if positive && (sign_reserve || sign_always) { 314 - final_len += 1; 315 - } 316 - if zero { 317 - len = 0; 318 - final_len = 0; 319 - } 320 - 321 - pad(w, !left, ' ' as u32, final_len..pad_space)?; 322 - 323 - let bytes = if positive { 324 - if sign_reserve { 325 - w.write_all(&[b' '])?; 326 - } else if sign_always { 327 - w.write_all(&[b'+'])?; 328 - } 329 - string.as_bytes() 330 - } else { 331 - w.write_all(&[b'-'])?; 332 - &string.as_bytes()[1..] 333 - }; 334 - pad(w, true, '0' as u32, len..precision.unwrap_or(pad_zero))?; 335 - 336 - if !zero { 337 - w.write_all(bytes)?; 338 - } 339 - 340 - pad(w, left, ' ' as u32, final_len..pad_space)?; 341 - } 342 - FmtKind::Unsigned => { 343 - let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 344 - VaArg::c_char(i) => fmt_int(fmt, i as c_uchar), 345 - VaArg::c_double(i) => panic!("this should not be possible"), 346 - VaArg::c_int(i) => fmt_int(fmt, i as c_uint), 347 - VaArg::c_long(i) => fmt_int(fmt, i as c_ulong), 348 - VaArg::c_longlong(i) => fmt_int(fmt, i as c_ulonglong), 349 - VaArg::c_short(i) => fmt_int(fmt, i as c_ushort), 350 - VaArg::intmax_t(i) => fmt_int(fmt, i as uintmax_t), 351 - VaArg::pointer(i) => fmt_int(fmt, i as usize), 352 - VaArg::ptrdiff_t(i) => fmt_int(fmt, i as size_t), 353 - VaArg::ssize_t(i) => fmt_int(fmt, i as size_t), 354 - VaArg::wint_t(_) => unreachable!("this should not be possible"), 355 - }; 356 - let zero = precision == Some(0) && string == "0"; 357 - 358 - // If this int is padded out to be larger than it is, don't 359 - // add an extra zero if octal. 360 - let no_precision = precision.map(|pad| pad < string.len()).unwrap_or(true); 361 - 362 - let len; 363 - let final_len = if zero { 364 - len = 0; 365 - 0 366 - } else { 367 - len = string.len(); 368 - len.max(precision.unwrap_or(0)) 369 - + if alternate && string != "0" { 370 - match char::from_u32(fmt).unwrap_or('\0') { 371 - 'o' if no_precision => 1, 372 - 'x' | 'X' => 2, 373 - _ => 0, 374 - } 375 - } else { 376 - 0 377 - } 378 - }; 379 - 380 - pad(w, !left, ' ' as u32, final_len..pad_space)?; 381 - 382 - if alternate && string != "0" { 383 - match char::from_u32(fmt).unwrap_or('\0') { 384 - 'o' if no_precision => w.write_all(&[b'0'])?, 385 - 'x' => w.write_all(&[b'0', b'x'])?, 386 - 'X' => w.write_all(&[b'0', b'X'])?, 387 - _ => (), 388 - } 389 - } 390 - pad(w, true, '0' as u32, len..precision.unwrap_or(pad_zero))?; 391 - 392 - if !zero { 393 - w.write_all(string.as_bytes())?; 394 - } 395 - 396 - pad(w, left, ' ' as u32, final_len..pad_space)?; 397 - } 398 - FmtKind::Scientific => { 399 - let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 400 - VaArg::c_double(i) => i, 401 - _ => panic!("this should not be possible"), 402 - }; 403 - if float.is_finite() { 404 - let (float, exp) = float_exp(float); 405 - let precision = precision.unwrap_or(6); 7 + use core::ffi::VaList; 406 8 407 - fmt_float_exp( 408 - w, fmt, false, precision, float, exp, left, pad_space, pad_zero, 409 - )?; 410 - } else { 411 - fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 412 - } 413 - } 414 - FmtKind::Decimal => { 415 - let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 416 - VaArg::c_double(i) => i, 417 - _ => panic!("this should not be possible"), 418 - }; 419 - if float.is_finite() { 420 - let precision = precision.unwrap_or(6); 9 + use crate::platform::{self, types::*}; 421 10 422 - fmt_float_normal(w, false, precision, float, left, pad_space, pad_zero)?; 423 - } else { 424 - fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 425 - } 426 - } 427 - FmtKind::AnyNotation => { 428 - let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 429 - VaArg::c_double(i) => i, 430 - _ => panic!("this should not be possible"), 431 - }; 432 - if float.is_finite() { 433 - let (log, exp) = float_exp(float); 434 - let exp_fmt = ('E' as u32) | (fmt & 32); 435 - let precision = precision.unwrap_or(6); 436 - let use_exp_format = exp < -4 || exp >= precision as isize; 437 - 438 - if use_exp_format { 439 - // Length of integral part will always be 1 here, 440 - // because that's how x/floor(log10(x)) works 441 - let precision = precision.saturating_sub(1); 442 - fmt_float_exp( 443 - w, exp_fmt, true, precision, log, exp, left, pad_space, pad_zero, 444 - )?; 445 - } else { 446 - // Length of integral part will be the exponent of 447 - // the unused logarithm, unless the exponent is 448 - // negative which in case the integral part must 449 - // of course be 0, 1 in length 450 - let len = 1 + cmp::max(0, exp) as usize; 451 - let precision = precision.saturating_sub(len); 452 - fmt_float_normal(w, true, precision, float, left, pad_space, pad_zero)?; 453 - } 454 - } else { 455 - fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 456 - } 457 - } 458 - FmtKind::String => { 459 - let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 460 - VaArg::pointer(p) => p, 461 - _ => panic!("this should not be possible"), 462 - } as *const c_char; 463 - 464 - if ptr.is_null() { 465 - w.write_all(b"(null)")?; 466 - } else { 467 - let max = precision.unwrap_or(::core::usize::MAX); 468 - 469 - if intkind == IntKind::Long || intkind == IntKind::LongLong { 470 - // Handle wchar_t 471 - let mut ptr = ptr as *const wchar_t; 472 - let mut string = String::new(); 473 - 474 - while *ptr != 0 { 475 - let c = match char::from_u32(*ptr as _) { 476 - Some(c) => c, 477 - None => { 478 - platform::ERRNO.set(EILSEQ); 479 - return Err(io::last_os_error()); 480 - } 481 - }; 482 - if string.len() + c.len_utf8() >= max { 483 - break; 484 - } 485 - string.push(c); 486 - ptr = ptr.add(1); 487 - } 488 - 489 - pad(w, !left, ' ' as u32, string.len()..pad_space)?; 490 - w.write_all(string.as_bytes())?; 491 - pad(w, left, ' ' as u32, string.len()..pad_space)?; 492 - } else { 493 - let mut len = 0; 494 - while *ptr.add(len) != 0 && len < max { 495 - len += 1; 496 - } 497 - 498 - pad(w, !left, ' ' as u32, len..pad_space)?; 499 - w.write_all(slice::from_raw_parts(ptr as *const u8, len))?; 500 - pad(w, left, ' ' as u32, len..pad_space)?; 501 - } 502 - } 503 - } 504 - FmtKind::Char => match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 505 - VaArg::c_char(c) => { 506 - pad(w, !left, ' ' as u32, 1..pad_space)?; 507 - w.write_all(&[c as u8])?; 508 - pad(w, left, ' ' as u32, 1..pad_space)?; 509 - } 510 - VaArg::wint_t(c) => { 511 - let c = match char::from_u32(c as _) { 512 - Some(c) => c, 513 - None => { 514 - platform::ERRNO.set(EILSEQ); 515 - return Err(io::last_os_error()); 516 - } 517 - }; 518 - let mut buf = [0; 4]; 519 - 520 - pad(w, !left, ' ' as u32, 1..pad_space)?; 521 - w.write_all(c.encode_utf8(&mut buf).as_bytes())?; 522 - pad(w, left, ' ' as u32, 1..pad_space)?; 523 - } 524 - _ => unreachable!("this should not be possible"), 525 - }, 526 - FmtKind::Pointer => { 527 - let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 528 - VaArg::pointer(p) => p, 529 - _ => panic!("this should not be possible"), 530 - }; 531 - 532 - let mut len = 1; 533 - if ptr.is_null() { 534 - len = "(nil)".len(); 535 - } else { 536 - let mut ptr = ptr as usize; 537 - while ptr >= 10 { 538 - ptr /= 10; 539 - len += 1; 540 - } 541 - } 542 - 543 - pad(w, !left, ' ' as u32, len..pad_space)?; 544 - if ptr.is_null() { 545 - write!(w, "(nil)")?; 546 - } else { 547 - write!(w, "0x{:x}", ptr as usize)?; 548 - } 549 - pad(w, left, ' ' as u32, len..pad_space)?; 550 - } 551 - FmtKind::GetWritten => { 552 - let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 553 - VaArg::pointer(p) => p, 554 - _ => panic!("this should not be possible"), 555 - }; 556 - 557 - match intkind { 558 - IntKind::Byte => *(ptr as *mut c_char) = w.written as c_char, 559 - IntKind::Short => *(ptr as *mut c_short) = w.written as c_short, 560 - IntKind::Int => *(ptr as *mut c_int) = w.written as c_int, 561 - IntKind::Long => *(ptr as *mut c_long) = w.written as c_long, 562 - IntKind::LongLong => *(ptr as *mut c_longlong) = w.written as c_longlong, 563 - IntKind::IntMax => *(ptr as *mut intmax_t) = w.written as intmax_t, 564 - IntKind::PtrDiff => *(ptr as *mut ptrdiff_t) = w.written as ptrdiff_t, 565 - IntKind::Size => *(ptr as *mut size_t) = w.written as size_t, 566 - } 567 - } 568 - } 569 - } 570 - Ok(w.written as c_int) 571 - } 572 - 573 - pub unsafe fn wprintf<W: Write>(w: W, format: WStr, ap: VaList) -> c_int { 574 - inner_wprintf(w, format, ap).unwrap_or(-1) 11 + pub unsafe fn wprintf(w: impl Write, format: WStr, ap: VaList) -> c_int { 12 + inner_printf::<c_str::Wide>(w, format, ap).unwrap_or(-1) 575 13 }