1 use crate::io::{self, Write}; 2 use alloc::{ 3 collections::BTreeMap, 4 string::{String, ToString}, 5 vec::Vec, 6 }; 7 use core::{char, cmp, f64, ffi::VaList, fmt, num::FpCategory, ops::Range, slice}; 8 9 use crate::{ 10 header::errno::EILSEQ, 11 platform::{self, types::*}, 12 }; 13 14 // ____ _ _ _ _ 15 // | __ ) ___ (_) | ___ _ __ _ __ | | __ _| |_ ___ _ 16 // | _ \ / _ \| | |/ _ \ '__| '_ \| |/ _` | __/ _ (_) 17 // | |_) | (_) | | | __/ | | |_) | | (_| | || __/_ 18 // |____/ \___/|_|_|\___|_| | .__/|_|\__,_|\__\___(_) 19 // |_| 20 21 #[derive(Clone, Copy, PartialEq, Eq)] 22 enum IntKind { 23 Byte, 24 Short, 25 Int, 26 Long, 27 LongLong, 28 IntMax, 29 PtrDiff, 30 Size, 31 } 32 #[derive(Clone, Copy, PartialEq, Eq)] 33 enum FmtKind { 34 Percent, 35 36 Signed, 37 Unsigned, 38 39 Scientific, 40 Decimal, 41 AnyNotation, 42 43 String, 44 Char, 45 Pointer, 46 GetWritten, 47 } 48 #[derive(Clone, Copy, Debug)] 49 enum Number { 50 Static(usize), 51 Index(usize), 52 Next, 53 } 54 impl Number { 55 unsafe fn resolve(&self, varargs: &mut VaListCache, ap: &mut VaList) -> usize { 56 let arg = match *self { 57 Number::Static(num) => return num, 58 Number::Index(i) => varargs.get(i - 1, ap, None), 59 Number::Next => { 60 let i = varargs.i; 61 varargs.i += 1; 62 varargs.get(i, ap, None) 63 } 64 }; 65 match arg { 66 VaArg::c_char(i) => i as usize, 67 VaArg::c_double(i) => i as usize, 68 VaArg::c_int(i) => i as usize, 69 VaArg::c_long(i) => i as usize, 70 VaArg::c_longlong(i) => i as usize, 71 VaArg::c_short(i) => i as usize, 72 VaArg::intmax_t(i) => i as usize, 73 VaArg::pointer(i) => i as usize, 74 VaArg::ptrdiff_t(i) => i as usize, 75 VaArg::ssize_t(i) => i as usize, 76 VaArg::wint_t(i) => i as usize, 77 } 78 } 79 } 80 #[derive(Clone, Copy, Debug)] 81 enum VaArg { 82 c_char(c_char), 83 c_double(c_double), 84 c_int(c_int), 85 c_long(c_long), 86 c_longlong(c_longlong), 87 c_short(c_short), 88 intmax_t(intmax_t), 89 pointer(*const c_void), 90 ptrdiff_t(ptrdiff_t), 91 ssize_t(ssize_t), 92 wint_t(wint_t), 93 } 94 impl VaArg { 95 unsafe fn arg_from(fmtkind: FmtKind, intkind: IntKind, ap: &mut VaList) -> VaArg { 96 // Per the C standard using va_arg with a type with a size 97 // less than that of an int for integers and double for floats 98 // is invalid. As a result any arguments smaller than an int or 99 // double passed to a function will be promoted to the smallest 100 // possible size. The VaList::arg function will handle this 101 // automagically. 102 103 match (fmtkind, intkind) { 104 (FmtKind::Percent, _) => panic!("Can't call arg_from on %"), 105 106 (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => { 107 VaArg::wint_t(ap.arg::<wint_t>()) 108 } 109 110 (FmtKind::Char, _) 111 | (FmtKind::Unsigned, IntKind::Byte) 112 | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(ap.arg::<c_char>()), 113 (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => { 114 VaArg::c_short(ap.arg::<c_short>()) 115 } 116 (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => { 117 VaArg::c_int(ap.arg::<c_int>()) 118 } 119 (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => { 120 VaArg::c_long(ap.arg::<c_long>()) 121 } 122 (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => { 123 VaArg::c_longlong(ap.arg::<c_longlong>()) 124 } 125 (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => { 126 VaArg::intmax_t(ap.arg::<intmax_t>()) 127 } 128 (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => { 129 VaArg::ptrdiff_t(ap.arg::<ptrdiff_t>()) 130 } 131 (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => { 132 VaArg::ssize_t(ap.arg::<ssize_t>()) 133 } 134 135 (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => { 136 VaArg::c_double(ap.arg::<c_double>()) 137 } 138 139 (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => { 140 VaArg::pointer(ap.arg::<*const c_void>()) 141 } 142 } 143 } 144 unsafe fn transmute(&self, fmtkind: FmtKind, intkind: IntKind) -> VaArg { 145 // At this point, there are conflicting printf arguments. An 146 // example of this is: 147 // ```c 148 // printf("%1$d %1$lf\n", 5, 0.1); 149 // ``` 150 // We handle it just like glibc: We read it from the VaList 151 // using the *last* argument type, but we transmute it when we 152 // try to access the other ones. 153 union Untyped { 154 c_char: c_char, 155 c_double: c_double, 156 c_int: c_int, 157 c_long: c_long, 158 c_longlong: c_longlong, 159 c_short: c_short, 160 intmax_t: intmax_t, 161 pointer: *const c_void, 162 ptrdiff_t: ptrdiff_t, 163 ssize_t: ssize_t, 164 wint_t: wint_t, 165 } 166 let untyped = match *self { 167 VaArg::c_char(i) => Untyped { c_char: i }, 168 VaArg::c_double(i) => Untyped { c_double: i }, 169 VaArg::c_int(i) => Untyped { c_int: i }, 170 VaArg::c_long(i) => Untyped { c_long: i }, 171 VaArg::c_longlong(i) => Untyped { c_longlong: i }, 172 VaArg::c_short(i) => Untyped { c_short: i }, 173 VaArg::intmax_t(i) => Untyped { intmax_t: i }, 174 VaArg::pointer(i) => Untyped { pointer: i }, 175 VaArg::ptrdiff_t(i) => Untyped { ptrdiff_t: i }, 176 VaArg::ssize_t(i) => Untyped { ssize_t: i }, 177 VaArg::wint_t(i) => Untyped { wint_t: i }, 178 }; 179 match (fmtkind, intkind) { 180 (FmtKind::Percent, _) => panic!("Can't call transmute on %"), 181 182 (FmtKind::Char, IntKind::Long) | (FmtKind::Char, IntKind::LongLong) => { 183 VaArg::wint_t(untyped.wint_t) 184 } 185 186 (FmtKind::Char, _) 187 | (FmtKind::Unsigned, IntKind::Byte) 188 | (FmtKind::Signed, IntKind::Byte) => VaArg::c_char(untyped.c_char), 189 (FmtKind::Unsigned, IntKind::Short) | (FmtKind::Signed, IntKind::Short) => { 190 VaArg::c_short(untyped.c_short) 191 } 192 (FmtKind::Unsigned, IntKind::Int) | (FmtKind::Signed, IntKind::Int) => { 193 VaArg::c_int(untyped.c_int) 194 } 195 (FmtKind::Unsigned, IntKind::Long) | (FmtKind::Signed, IntKind::Long) => { 196 VaArg::c_long(untyped.c_long) 197 } 198 (FmtKind::Unsigned, IntKind::LongLong) | (FmtKind::Signed, IntKind::LongLong) => { 199 VaArg::c_longlong(untyped.c_longlong) 200 } 201 (FmtKind::Unsigned, IntKind::IntMax) | (FmtKind::Signed, IntKind::IntMax) => { 202 VaArg::intmax_t(untyped.intmax_t) 203 } 204 (FmtKind::Unsigned, IntKind::PtrDiff) | (FmtKind::Signed, IntKind::PtrDiff) => { 205 VaArg::ptrdiff_t(untyped.ptrdiff_t) 206 } 207 (FmtKind::Unsigned, IntKind::Size) | (FmtKind::Signed, IntKind::Size) => { 208 VaArg::ssize_t(untyped.ssize_t) 209 } 210 211 (FmtKind::AnyNotation, _) | (FmtKind::Decimal, _) | (FmtKind::Scientific, _) => { 212 VaArg::c_double(untyped.c_double) 213 } 214 215 (FmtKind::GetWritten, _) | (FmtKind::Pointer, _) | (FmtKind::String, _) => { 216 VaArg::pointer(untyped.pointer) 217 } 218 } 219 } 220 } 221 #[derive(Default)] 222 struct VaListCache { 223 args: Vec<VaArg>, 224 i: usize, 225 } 226 impl VaListCache { 227 unsafe fn get( 228 &mut self, 229 i: usize, 230 ap: &mut VaList, 231 default: Option<(FmtKind, IntKind)>, 232 ) -> VaArg { 233 if let Some(&arg) = self.args.get(i) { 234 let mut arg = arg; 235 if let Some((fmtkind, intkind)) = default { 236 arg = arg.transmute(fmtkind, intkind); 237 } 238 return arg; 239 } 240 while self.args.len() < i { 241 // We can't POSSIBLY know the type if we reach this 242 // point. Reaching here means there are unused gaps in the 243 // arguments. Ultimately we'll have to settle down with 244 // defaulting to c_int. 245 self.args.push(VaArg::c_int(ap.arg::<c_int>())) 246 } 247 self.args.push(match default { 248 Some((fmtkind, intkind)) => VaArg::arg_from(fmtkind, intkind, ap), 249 None => VaArg::c_int(ap.arg::<c_int>()), 250 }); 251 self.args[i] 252 } 253 } 254 255 // ___ _ _ _ _ 256 // |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ 257 // | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \(_) 258 // | || | | | | | |_) | | __/ | | | | | __/ | | | || (_| | |_| | (_) | | | |_ 259 // |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_(_) 260 // |_| 261 262 enum FmtCase { 263 Lower, 264 Upper, 265 } 266 267 // The spelled-out "infinity"/"INFINITY" is also permitted by the standard 268 static INF_STR_LOWER: &str = "inf"; 269 static INF_STR_UPPER: &str = "INF"; 270 271 static NAN_STR_LOWER: &str = "nan"; 272 static NAN_STR_UPPER: &str = "NAN"; 273 274 unsafe fn pop_int_raw(format: &mut *const u8) -> Option<usize> { 275 let mut int = None; 276 while let Some(digit) = (**format as char).to_digit(10) { 277 *format = format.add(1); 278 if int.is_none() { 279 int = Some(0); 280 } 281 *int.as_mut().unwrap() *= 10; 282 *int.as_mut().unwrap() += digit as usize; 283 } 284 int 285 } 286 unsafe fn pop_index(format: &mut *const u8) -> Option<usize> { 287 // Peek ahead for a positional argument: 288 let mut format2 = *format; 289 if let Some(i) = pop_int_raw(&mut format2) { 290 if *format2 == b'$' { 291 *format = format2.add(1); 292 return Some(i); 293 } 294 } 295 None 296 } 297 unsafe fn pop_int(format: &mut *const u8) -> Option<Number> { 298 if **format == b'*' { 299 *format = format.add(1); 300 Some(pop_index(format).map(Number::Index).unwrap_or(Number::Next)) 301 } else { 302 pop_int_raw(format).map(Number::Static) 303 } 304 } 305 306 unsafe fn fmt_int<I>(fmt: u8, i: I) -> String 307 where 308 I: fmt::Display + fmt::Octal + fmt::LowerHex + fmt::UpperHex, 309 { 310 match fmt { 311 b'o' => format!("{:o}", i), 312 b'u' => i.to_string(), 313 b'x' => format!("{:x}", i), 314 b'X' => format!("{:X}", i), 315 _ => panic!( 316 "fmt_int should never be called with the fmt {:?}", 317 fmt as char 318 ), 319 } 320 } 321 322 fn pad<W: Write>( 323 w: &mut W, 324 current_side: bool, 325 pad_char: u8, 326 range: Range<usize>, 327 ) -> io::Result<()> { 328 if current_side { 329 for _ in range { 330 w.write_all(&[pad_char])?; 331 } 332 } 333 Ok(()) 334 } 335 336 fn abs(float: c_double) -> c_double { 337 // Don't ask me whe float.abs() seems absent... 338 if float.is_sign_negative() { 339 -float 340 } else { 341 float 342 } 343 } 344 345 fn float_string(float: c_double, precision: usize, trim: bool) -> String { 346 let mut string = format!("{:.p$}", float, p = precision); 347 if trim && string.contains('.') { 348 let truncate = { 349 let slice = string.trim_end_matches('0'); 350 let mut truncate = slice.len(); 351 if slice.ends_with('.') { 352 truncate -= 1; 353 } 354 truncate 355 }; 356 string.truncate(truncate); 357 } 358 string 359 } 360 361 fn float_exp(mut float: c_double) -> (c_double, isize) { 362 let mut exp: isize = 0; 363 while abs(float) >= 10.0 { 364 float /= 10.0; 365 exp += 1; 366 } 367 while f64::EPSILON < abs(float) && abs(float) < 1.0 { 368 float *= 10.0; 369 exp -= 1; 370 } 371 (float, exp) 372 } 373 374 fn fmt_float_exp<W: Write>( 375 w: &mut W, 376 exp_fmt: u8, 377 trim: bool, 378 precision: usize, 379 float: c_double, 380 exp: isize, 381 left: bool, 382 pad_space: usize, 383 pad_zero: usize, 384 ) -> io::Result<()> { 385 let mut exp2 = exp; 386 let mut exp_len = 1; 387 while exp2 >= 10 { 388 exp2 /= 10; 389 exp_len += 1; 390 } 391 392 let string = float_string(float, precision, trim); 393 let len = string.len() + 2 + 2.max(exp_len); 394 395 pad(w, !left, b' ', len..pad_space)?; 396 let bytes = if string.starts_with('-') { 397 w.write_all(&[b'-'])?; 398 &string.as_bytes()[1..] 399 } else { 400 string.as_bytes() 401 }; 402 pad(w, !left, b'0', len..pad_zero)?; 403 w.write_all(bytes)?; 404 write!(w, "{}{:+03}", exp_fmt as char, exp)?; 405 pad(w, left, b' ', len..pad_space)?; 406 407 Ok(()) 408 } 409 410 fn fmt_float_normal<W: Write>( 411 w: &mut W, 412 trim: bool, 413 precision: usize, 414 float: c_double, 415 left: bool, 416 pad_space: usize, 417 pad_zero: usize, 418 ) -> io::Result<usize> { 419 let string = float_string(float, precision, trim); 420 421 pad(w, !left, b' ', string.len()..pad_space)?; 422 let bytes = if string.starts_with('-') { 423 w.write_all(&[b'-'])?; 424 &string.as_bytes()[1..] 425 } else { 426 string.as_bytes() 427 }; 428 pad(w, true, b'0', string.len()..pad_zero)?; 429 w.write_all(bytes)?; 430 pad(w, left, b' ', string.len()..pad_space)?; 431 432 Ok(string.len()) 433 } 434 435 /// Write ±infinity or ±NaN representation for any floating-point style 436 fn fmt_float_nonfinite<W: Write>(w: &mut W, float: c_double, case: FmtCase) -> io::Result<()> { 437 if float.is_sign_negative() { 438 w.write_all(&[b'-'])?; 439 } 440 441 let nonfinite_str = match float.classify() { 442 FpCategory::Infinite => match case { 443 FmtCase::Lower => INF_STR_LOWER, 444 FmtCase::Upper => INF_STR_UPPER, 445 }, 446 FpCategory::Nan => match case { 447 FmtCase::Lower => NAN_STR_LOWER, 448 FmtCase::Upper => NAN_STR_UPPER, 449 }, 450 _ => { 451 // This function should only be called with infinite or NaN value. 452 panic!("this should not be possible") 453 } 454 }; 455 456 w.write_all(nonfinite_str.as_bytes())?; 457 458 Ok(()) 459 } 460 461 #[derive(Clone, Copy)] 462 struct PrintfIter { 463 format: *const u8, 464 } 465 #[derive(Clone, Copy)] 466 struct PrintfArg { 467 index: Option<usize>, 468 alternate: bool, 469 zero: bool, 470 left: bool, 471 sign_reserve: bool, 472 sign_always: bool, 473 min_width: Number, 474 precision: Option<Number>, 475 pad_space: Number, 476 pad_zero: Number, 477 intkind: IntKind, 478 fmt: u8, 479 fmtkind: FmtKind, 480 } 481 enum PrintfFmt { 482 Plain(&'static [u8]), 483 Arg(PrintfArg), 484 } 485 impl Iterator for PrintfIter { 486 type Item = Result<PrintfFmt, ()>; 487 fn next(&mut self) -> Option<Self::Item> { 488 unsafe { 489 // Send PrintfFmt::Plain until the next % 490 let mut len = 0; 491 while *self.format.add(len) != 0 && *self.format.add(len) != b'%' { 492 len += 1; 493 } 494 if len > 0 { 495 let slice = slice::from_raw_parts(self.format as *const u8, len); 496 self.format = self.format.add(len); 497 return Some(Ok(PrintfFmt::Plain(slice))); 498 } 499 self.format = self.format.add(len); 500 if *self.format == 0 { 501 return None; 502 } 503 504 // *self.format is guaranteed to be '%' at this point 505 self.format = self.format.add(1); 506 507 let mut peekahead = self.format; 508 let index = pop_index(&mut peekahead).map(|i| { 509 self.format = peekahead; 510 i 511 }); 512 513 // Flags: 514 let mut alternate = false; 515 let mut zero = false; 516 let mut left = false; 517 let mut sign_reserve = false; 518 let mut sign_always = false; 519 520 loop { 521 match *self.format { 522 b'#' => alternate = true, 523 b'0' => zero = true, 524 b'-' => left = true, 525 b' ' => sign_reserve = true, 526 b'+' => sign_always = true, 527 _ => break, 528 } 529 self.format = self.format.add(1); 530 } 531 532 // Width and precision: 533 let min_width = pop_int(&mut self.format).unwrap_or(Number::Static(0)); 534 let precision = if *self.format == b'.' { 535 self.format = self.format.add(1); 536 match pop_int(&mut self.format) { 537 int @ Some(_) => int, 538 None => return Some(Err(())), 539 } 540 } else { 541 None 542 }; 543 544 let pad_space = if zero { Number::Static(0) } else { min_width }; 545 let pad_zero = if zero { min_width } else { Number::Static(0) }; 546 547 // Integer size: 548 let mut intkind = IntKind::Int; 549 loop { 550 intkind = match *self.format { 551 b'h' => { 552 if intkind == IntKind::Short || intkind == IntKind::Byte { 553 IntKind::Byte 554 } else { 555 IntKind::Short 556 } 557 } 558 b'j' => IntKind::IntMax, 559 b'l' => { 560 if intkind == IntKind::Long || intkind == IntKind::LongLong { 561 IntKind::LongLong 562 } else { 563 IntKind::Long 564 } 565 } 566 b'q' | b'L' => IntKind::LongLong, 567 b't' => IntKind::PtrDiff, 568 b'z' => IntKind::Size, 569 _ => break, 570 }; 571 572 self.format = self.format.add(1); 573 } 574 let fmt = *self.format; 575 let fmtkind = match fmt { 576 b'%' => FmtKind::Percent, 577 b'd' | b'i' => FmtKind::Signed, 578 b'o' | b'u' | b'x' | b'X' => FmtKind::Unsigned, 579 b'e' | b'E' => FmtKind::Scientific, 580 b'f' | b'F' => FmtKind::Decimal, 581 b'g' | b'G' => FmtKind::AnyNotation, 582 b's' => FmtKind::String, 583 b'c' => FmtKind::Char, 584 b'p' => FmtKind::Pointer, 585 b'n' => FmtKind::GetWritten, 586 _ => return Some(Err(())), 587 }; 588 self.format = self.format.add(1); 589 590 Some(Ok(PrintfFmt::Arg(PrintfArg { 591 index, 592 alternate, 593 zero, 594 left, 595 sign_reserve, 596 sign_always, 597 min_width, 598 precision, 599 pad_space, 600 pad_zero, 601 intkind, 602 fmt, 603 fmtkind, 604 }))) 605 } 606 } 607 } 608 609 unsafe fn inner_printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> io::Result<c_int> { 610 let w = &mut platform::CountingWriter::new(w); 611 612 let iterator = PrintfIter { 613 format: format as *const u8, 614 }; 615 616 // Pre-fetch vararg types 617 let mut varargs = VaListCache::default(); 618 let mut positional = BTreeMap::new(); 619 // ^ NOTE: This depends on the sorted order, do not change to HashMap or whatever 620 621 for section in iterator { 622 let arg = match section { 623 Ok(PrintfFmt::Plain(text)) => continue, 624 Ok(PrintfFmt::Arg(arg)) => arg, 625 Err(()) => return Ok(-1), 626 }; 627 if arg.fmtkind == FmtKind::Percent { 628 continue; 629 } 630 for num in &[arg.min_width, arg.precision.unwrap_or(Number::Static(0))] { 631 match num { 632 Number::Next => varargs.args.push(VaArg::c_int(ap.arg::<c_int>())), 633 Number::Index(i) => { 634 positional.insert(i - 1, (FmtKind::Signed, IntKind::Int)); 635 } 636 Number::Static(_) => (), 637 } 638 } 639 match arg.index { 640 Some(i) => { 641 positional.insert(i - 1, (arg.fmtkind, arg.intkind)); 642 } 643 None => varargs 644 .args 645 .push(VaArg::arg_from(arg.fmtkind, arg.intkind, &mut ap)), 646 } 647 } 648 // Make sure, in order, the positional arguments exist with the specified type 649 for (i, arg) in positional { 650 varargs.get(i, &mut ap, Some(arg)); 651 } 652 653 // Main loop 654 for section in iterator { 655 let arg = match section { 656 Ok(PrintfFmt::Plain(text)) => { 657 w.write_all(text)?; 658 continue; 659 } 660 Ok(PrintfFmt::Arg(arg)) => arg, 661 Err(()) => return Ok(-1), 662 }; 663 let alternate = arg.alternate; 664 let zero = arg.zero; 665 let left = arg.left; 666 let sign_reserve = arg.sign_reserve; 667 let sign_always = arg.sign_always; 668 let min_width = arg.min_width.resolve(&mut varargs, &mut ap); 669 let precision = arg.precision.map(|n| n.resolve(&mut varargs, &mut ap)); 670 let pad_space = arg.pad_space.resolve(&mut varargs, &mut ap); 671 let pad_zero = arg.pad_zero.resolve(&mut varargs, &mut ap); 672 let intkind = arg.intkind; 673 let fmt = arg.fmt; 674 let fmtkind = arg.fmtkind; 675 let fmtcase = match fmt { 676 b'x' | b'f' | b'e' | b'g' => Some(FmtCase::Lower), 677 b'X' | b'F' | b'E' | b'G' => Some(FmtCase::Upper), 678 _ => None, 679 }; 680 681 let index = arg.index.map(|i| i - 1).unwrap_or_else(|| { 682 if fmtkind == FmtKind::Percent { 683 0 684 } else { 685 let i = varargs.i; 686 varargs.i += 1; 687 i 688 } 689 }); 690 691 match fmtkind { 692 FmtKind::Percent => w.write_all(&[b'%'])?, 693 FmtKind::Signed => { 694 let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 695 VaArg::c_char(i) => i.to_string(), 696 VaArg::c_double(i) => panic!("this should not be possible"), 697 VaArg::c_int(i) => i.to_string(), 698 VaArg::c_long(i) => i.to_string(), 699 VaArg::c_longlong(i) => i.to_string(), 700 VaArg::c_short(i) => i.to_string(), 701 VaArg::intmax_t(i) => i.to_string(), 702 VaArg::pointer(i) => (i as usize).to_string(), 703 VaArg::ptrdiff_t(i) => i.to_string(), 704 VaArg::ssize_t(i) => i.to_string(), 705 VaArg::wint_t(_) => unreachable!("this should not be possible"), 706 }; 707 let positive = !string.starts_with('-'); 708 let zero = precision == Some(0) && string == "0"; 709 710 let mut len = string.len(); 711 let mut final_len = string.len().max(precision.unwrap_or(0)); 712 if positive && (sign_reserve || sign_always) { 713 final_len += 1; 714 } 715 if zero { 716 len = 0; 717 final_len = 0; 718 } 719 720 pad(w, !left, b' ', final_len..pad_space)?; 721 722 let bytes = if positive { 723 if sign_reserve { 724 w.write_all(&[b' '])?; 725 } else if sign_always { 726 w.write_all(&[b'+'])?; 727 } 728 string.as_bytes() 729 } else { 730 w.write_all(&[b'-'])?; 731 &string.as_bytes()[1..] 732 }; 733 pad(w, true, b'0', len..precision.unwrap_or(pad_zero))?; 734 735 if !zero { 736 w.write_all(bytes)?; 737 } 738 739 pad(w, left, b' ', final_len..pad_space)?; 740 } 741 FmtKind::Unsigned => { 742 let string = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 743 VaArg::c_char(i) => fmt_int(fmt, i as c_uchar), 744 VaArg::c_double(i) => panic!("this should not be possible"), 745 VaArg::c_int(i) => fmt_int(fmt, i as c_uint), 746 VaArg::c_long(i) => fmt_int(fmt, i as c_ulong), 747 VaArg::c_longlong(i) => fmt_int(fmt, i as c_ulonglong), 748 VaArg::c_short(i) => fmt_int(fmt, i as c_ushort), 749 VaArg::intmax_t(i) => fmt_int(fmt, i as uintmax_t), 750 VaArg::pointer(i) => fmt_int(fmt, i as usize), 751 VaArg::ptrdiff_t(i) => fmt_int(fmt, i as size_t), 752 VaArg::ssize_t(i) => fmt_int(fmt, i as size_t), 753 VaArg::wint_t(_) => unreachable!("this should not be possible"), 754 }; 755 let zero = precision == Some(0) && string == "0"; 756 757 // If this int is padded out to be larger than it is, don't 758 // add an extra zero if octal. 759 let no_precision = precision.map(|pad| pad < string.len()).unwrap_or(true); 760 761 let len; 762 let final_len = if zero { 763 len = 0; 764 0 765 } else { 766 len = string.len(); 767 len.max(precision.unwrap_or(0)) 768 + if alternate && string != "0" { 769 match fmt { 770 b'o' if no_precision => 1, 771 b'x' | b'X' => 2, 772 _ => 0, 773 } 774 } else { 775 0 776 } 777 }; 778 779 pad(w, !left, b' ', final_len..pad_space)?; 780 781 if alternate && string != "0" { 782 match fmt { 783 b'o' if no_precision => w.write_all(&[b'0'])?, 784 b'x' => w.write_all(&[b'0', b'x'])?, 785 b'X' => w.write_all(&[b'0', b'X'])?, 786 _ => (), 787 } 788 } 789 pad(w, true, b'0', len..precision.unwrap_or(pad_zero))?; 790 791 if !zero { 792 w.write_all(string.as_bytes())?; 793 } 794 795 pad(w, left, b' ', final_len..pad_space)?; 796 } 797 FmtKind::Scientific => { 798 let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 799 VaArg::c_double(i) => i, 800 _ => panic!("this should not be possible"), 801 }; 802 if float.is_finite() { 803 let (float, exp) = float_exp(float); 804 let precision = precision.unwrap_or(6); 805 806 fmt_float_exp( 807 w, fmt, false, precision, float, exp, left, pad_space, pad_zero, 808 )?; 809 } else { 810 fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 811 } 812 } 813 FmtKind::Decimal => { 814 let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 815 VaArg::c_double(i) => i, 816 _ => panic!("this should not be possible"), 817 }; 818 if float.is_finite() { 819 let precision = precision.unwrap_or(6); 820 821 fmt_float_normal(w, false, precision, float, left, pad_space, pad_zero)?; 822 } else { 823 fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 824 } 825 } 826 FmtKind::AnyNotation => { 827 let float = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 828 VaArg::c_double(i) => i, 829 _ => panic!("this should not be possible"), 830 }; 831 if float.is_finite() { 832 let (log, exp) = float_exp(float); 833 let exp_fmt = b'E' | (fmt & 32); 834 let precision = precision.unwrap_or(6); 835 let use_exp_format = exp < -4 || exp >= precision as isize; 836 837 if use_exp_format { 838 // Length of integral part will always be 1 here, 839 // because that's how x/floor(log10(x)) works 840 let precision = precision.saturating_sub(1); 841 fmt_float_exp( 842 w, exp_fmt, true, precision, log, exp, left, pad_space, pad_zero, 843 )?; 844 } else { 845 // Length of integral part will be the exponent of 846 // the unused logarithm, unless the exponent is 847 // negative which in case the integral part must 848 // of course be 0, 1 in length 849 let len = 1 + cmp::max(0, exp) as usize; 850 let precision = precision.saturating_sub(len); 851 fmt_float_normal(w, true, precision, float, left, pad_space, pad_zero)?; 852 } 853 } else { 854 fmt_float_nonfinite(w, float, fmtcase.unwrap())?; 855 } 856 } 857 FmtKind::String => { 858 let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 859 VaArg::pointer(p) => p, 860 _ => panic!("this should not be possible"), 861 } as *const c_char; 862 863 if ptr.is_null() { 864 w.write_all(b"(null)")?; 865 } else { 866 let max = precision.unwrap_or(::core::usize::MAX); 867 868 if intkind == IntKind::Long || intkind == IntKind::LongLong { 869 // Handle wchar_t 870 let mut ptr = ptr as *const wchar_t; 871 let mut string = String::new(); 872 873 while *ptr != 0 { 874 let c = match char::from_u32(*ptr as _) { 875 Some(c) => c, 876 None => { 877 platform::errno = EILSEQ; 878 return Err(io::last_os_error()); 879 } 880 }; 881 if string.len() + c.len_utf8() >= max { 882 break; 883 } 884 string.push(c); 885 ptr = ptr.add(1); 886 } 887 888 pad(w, !left, b' ', string.len()..pad_space)?; 889 w.write_all(string.as_bytes())?; 890 pad(w, left, b' ', string.len()..pad_space)?; 891 } else { 892 let mut len = 0; 893 while *ptr.add(len) != 0 && len < max { 894 len += 1; 895 } 896 897 pad(w, !left, b' ', len..pad_space)?; 898 w.write_all(slice::from_raw_parts(ptr as *const u8, len))?; 899 pad(w, left, b' ', len..pad_space)?; 900 } 901 } 902 } 903 FmtKind::Char => match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 904 VaArg::c_char(c) => { 905 pad(w, !left, b' ', 1..pad_space)?; 906 w.write_all(&[c as u8])?; 907 pad(w, left, b' ', 1..pad_space)?; 908 } 909 VaArg::wint_t(c) => { 910 let c = match char::from_u32(c as _) { 911 Some(c) => c, 912 None => { 913 platform::errno = EILSEQ; 914 return Err(io::last_os_error()); 915 } 916 }; 917 let mut buf = [0; 4]; 918 919 pad(w, !left, b' ', 1..pad_space)?; 920 w.write_all(c.encode_utf8(&mut buf).as_bytes())?; 921 pad(w, left, b' ', 1..pad_space)?; 922 } 923 _ => unreachable!("this should not be possible"), 924 }, 925 FmtKind::Pointer => { 926 let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 927 VaArg::pointer(p) => p, 928 _ => panic!("this should not be possible"), 929 }; 930 931 let mut len = 1; 932 if ptr.is_null() { 933 len = "(nil)".len(); 934 } else { 935 let mut ptr = ptr as usize; 936 while ptr >= 10 { 937 ptr /= 10; 938 len += 1; 939 } 940 } 941 942 pad(w, !left, b' ', len..pad_space)?; 943 if ptr.is_null() { 944 write!(w, "(nil)")?; 945 } else { 946 write!(w, "0x{:x}", ptr as usize)?; 947 } 948 pad(w, left, b' ', len..pad_space)?; 949 } 950 FmtKind::GetWritten => { 951 let ptr = match varargs.get(index, &mut ap, Some((arg.fmtkind, arg.intkind))) { 952 VaArg::pointer(p) => p, 953 _ => panic!("this should not be possible"), 954 }; 955 956 match intkind { 957 IntKind::Byte => *(ptr as *mut c_char) = w.written as c_char, 958 IntKind::Short => *(ptr as *mut c_short) = w.written as c_short, 959 IntKind::Int => *(ptr as *mut c_int) = w.written as c_int, 960 IntKind::Long => *(ptr as *mut c_long) = w.written as c_long, 961 IntKind::LongLong => *(ptr as *mut c_longlong) = w.written as c_longlong, 962 IntKind::IntMax => *(ptr as *mut intmax_t) = w.written as intmax_t, 963 IntKind::PtrDiff => *(ptr as *mut ptrdiff_t) = w.written as ptrdiff_t, 964 IntKind::Size => *(ptr as *mut size_t) = w.written as size_t, 965 } 966 } 967 } 968 } 969 Ok(w.written as c_int) 970 } 971 972 pub unsafe fn printf<W: Write>(w: W, format: *const c_char, ap: VaList) -> c_int { 973 inner_printf(w, format, ap).unwrap_or(-1) 974 } 975