(format: &PyStrRef, checked_tm: CheckedTm, vm: &VirtualMachine)
| 638 | |
| 639 | #[cfg(any(unix, windows))] |
| 640 | fn strftime_crt(format: &PyStrRef, checked_tm: CheckedTm, vm: &VirtualMachine) -> PyResult { |
| 641 | #[cfg(unix)] |
| 642 | let _keep_zone_alive = &checked_tm.zone; |
| 643 | let mut tm = checked_tm.tm; |
| 644 | tm.tm_isdst = tm.tm_isdst.clamp(-1, 1); |
| 645 | |
| 646 | // MSVC strftime requires year in [1; 9999] |
| 647 | #[cfg(windows)] |
| 648 | { |
| 649 | let year = tm.tm_year + 1900; |
| 650 | if !(1..=9999).contains(&year) { |
| 651 | return Err(vm.new_value_error("strftime() requires year in [1; 9999]")); |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | #[cfg(unix)] |
| 656 | fn strftime_ascii(fmt: &str, tm: &libc::tm, vm: &VirtualMachine) -> PyResult<String> { |
| 657 | let fmt_c = |
| 658 | CString::new(fmt).map_err(|_| vm.new_value_error("embedded null character"))?; |
| 659 | let mut size = 1024usize; |
| 660 | let max_scale = 256usize.saturating_mul(fmt.len().max(1)); |
| 661 | loop { |
| 662 | let mut out = vec![0u8; size]; |
| 663 | let written = unsafe { |
| 664 | libc::strftime( |
| 665 | out.as_mut_ptr().cast(), |
| 666 | out.len(), |
| 667 | fmt_c.as_ptr(), |
| 668 | tm as *const libc::tm, |
| 669 | ) |
| 670 | }; |
| 671 | if written > 0 || size >= max_scale { |
| 672 | return Ok(String::from_utf8_lossy(&out[..written]).into_owned()); |
| 673 | } |
| 674 | size = size.saturating_mul(2); |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | #[cfg(windows)] |
| 679 | fn strftime_ascii(fmt: &str, tm: &libc::tm, vm: &VirtualMachine) -> PyResult<String> { |
| 680 | if fmt.contains('\0') { |
| 681 | return Err(vm.new_value_error("embedded null character")); |
| 682 | } |
| 683 | // Use wcsftime for proper Unicode output (e.g. %Z timezone names) |
| 684 | let fmt_wide: Vec<u16> = fmt.encode_utf16().chain(core::iter::once(0)).collect(); |
| 685 | let mut size = 1024usize; |
| 686 | let max_scale = 256usize.saturating_mul(fmt.len().max(1)); |
| 687 | loop { |
| 688 | let mut out = vec![0u16; size]; |
| 689 | let written = unsafe { |
| 690 | rustpython_common::suppress_iph!(wcsftime( |
| 691 | out.as_mut_ptr(), |
| 692 | out.len(), |
| 693 | fmt_wide.as_ptr(), |
| 694 | tm as *const libc::tm, |
| 695 | )) |
| 696 | }; |
| 697 | if written > 0 || size >= max_scale { |
no test coverage detected