Use unsafe blocks in time.h implementation

This commit is contained in:
sourceturner
2026-01-18 21:22:57 +01:00
parent 3873cf9a28
commit 2cf1a2d16a
2 changed files with 121 additions and 98 deletions
+65 -54
View File
@@ -2,6 +2,9 @@
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use crate::{
c_str::{CStr, CString},
error::{Errno, ResultExt},
@@ -210,7 +213,7 @@ pub struct itimerspec {
#[deprecated]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn asctime(timeptr: *const tm) -> *mut c_char {
asctime_r(timeptr, &raw mut ASCTIME as *mut _)
unsafe { asctime_r(timeptr, &raw mut ASCTIME as *mut _) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html>.
@@ -221,13 +224,13 @@ pub unsafe extern "C" fn asctime(timeptr: *const tm) -> *mut c_char {
#[deprecated]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char {
let tm_sec = (*tm).tm_sec;
let tm_min = (*tm).tm_min;
let tm_hour = (*tm).tm_hour;
let tm_mday = (*tm).tm_mday;
let tm_mon = (*tm).tm_mon;
let tm_year = (*tm).tm_year;
let tm_wday = (*tm).tm_wday;
let tm_sec = unsafe { (*tm).tm_sec };
let tm_min = unsafe { (*tm).tm_min };
let tm_hour = unsafe { (*tm).tm_hour };
let tm_mday = unsafe { (*tm).tm_mday };
let tm_mon = unsafe { (*tm).tm_mon };
let tm_year = unsafe { (*tm).tm_year };
let tm_wday = unsafe { (*tm).tm_wday };
/* Panic when we run into undefined behavior.
*
@@ -323,7 +326,7 @@ pub extern "C" fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int {
Sys::clock_getres(clock_id, Out::nullable(res))
Sys::clock_getres(clock_id, unsafe { Out::nullable(res) })
.map(|()| 0)
.or_minus_one_errno()
}
@@ -331,7 +334,7 @@ pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int {
Sys::clock_gettime(clock_id, Out::nonnull(tp))
Sys::clock_gettime(clock_id, unsafe { Out::nonnull(tp) })
.map(|()| 0)
.or_minus_one_errno()
}
@@ -350,7 +353,7 @@ pub extern "C" fn clock_nanosleep(
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn clock_settime(clock_id: clockid_t, tp: *const timespec) -> c_int {
Sys::clock_settime(clock_id, tp)
unsafe { Sys::clock_settime(clock_id, tp) }
.map(|()| 0)
.or_minus_one_errno()
}
@@ -363,7 +366,7 @@ pub unsafe extern "C" fn clock_settime(clock_id: clockid_t, tp: *const timespec)
#[deprecated]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ctime(clock: *const time_t) -> *mut c_char {
asctime(localtime(clock))
unsafe { asctime(localtime(clock)) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html>.
@@ -376,8 +379,8 @@ pub unsafe extern "C" fn ctime(clock: *const time_t) -> *mut c_char {
pub unsafe extern "C" fn ctime_r(clock: *const time_t, buf: *mut c_char) -> *mut c_char {
// Using MaybeUninit<tm> seems to cause a panic during the build process
let mut tm1 = blank_tm();
localtime_r(clock, &mut tm1);
asctime_r(&tm1, buf)
unsafe { localtime_r(clock, &mut tm1) };
unsafe { asctime_r(&tm1, buf) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/difftime.html>.
@@ -395,20 +398,20 @@ pub unsafe extern "C" fn getdate(string: *const c_char) -> *const tm {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gmtime.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gmtime(timer: *const time_t) -> *mut tm {
gmtime_r(timer, &raw mut TM)
unsafe { gmtime_r(timer, &raw mut TM) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gmtime.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn gmtime_r(clock: *const time_t, result: *mut tm) -> *mut tm {
let _ = get_localtime(*clock, result);
let _ = get_localtime(unsafe { *clock }, result);
result
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/localtime.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm {
localtime_r(clock, &raw mut TM)
unsafe { localtime_r(clock, &raw mut TM) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/localtime.html>.
@@ -416,8 +419,8 @@ pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm {
pub unsafe extern "C" fn localtime_r(clock: *const time_t, t: *mut tm) -> *mut tm {
let mut lock = TIMEZONE_LOCK.lock();
clear_timezone(&mut lock);
if let (Some(std_time), dst_time) = get_localtime(*clock, t) {
set_timezone(&mut lock, &std_time, dst_time);
if let (Some(std_time), dst_time) = get_localtime(unsafe { *clock }, t) {
unsafe { set_timezone(&mut lock, &std_time, dst_time) };
}
t
}
@@ -428,12 +431,12 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
let mut lock = TIMEZONE_LOCK.lock();
clear_timezone(&mut lock);
let year = (*timeptr).tm_year + 1900;
let month = ((*timeptr).tm_mon + 1) as _;
let day = (*timeptr).tm_mday as _;
let hour = (*timeptr).tm_hour as _;
let minute = (*timeptr).tm_min as _;
let second = (*timeptr).tm_sec as _;
let year = unsafe { (*timeptr).tm_year } + 1900;
let month = (unsafe { (*timeptr).tm_mon } + 1) as _;
let day = unsafe { (*timeptr).tm_mday } as _;
let hour = unsafe { (*timeptr).tm_hour } as _;
let minute = unsafe { (*timeptr).tm_min } as _;
let second = unsafe { (*timeptr).tm_sec } as _;
let naive_local = match NaiveDate::from_ymd_opt(year, month, day)
.and_then(|date| date.and_hms_opt(hour, minute, second))
@@ -445,7 +448,7 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
}
};
let offset = get_offset((*timeptr).tm_gmtoff).unwrap();
let offset = get_offset(unsafe { (*timeptr).tm_gmtoff }).unwrap();
let tz = time_zone();
// Create DateTime<FixedOffset>
let datetime = match offset.from_local_datetime(&naive_local) {
@@ -460,7 +463,7 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
let tz_datetime = datetime.with_timezone(&tz);
let timestamp = tz_datetime.timestamp();
ptr::write(timeptr, datetime_to_tm(&tz_datetime));
unsafe { ptr::write(timeptr, datetime_to_tm(&tz_datetime)) };
// Convert UTC time to local time
if let (std_time, dst_time) = match tz.timestamp_opt(timestamp, 0) {
@@ -469,7 +472,7 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
MappedLocalTime::Ambiguous(t1, t2) => (t2, Some(t1)),
MappedLocalTime::None => return timestamp,
} {
set_timezone(&mut lock, &std_time, dst_time);
unsafe { set_timezone(&mut lock, &std_time, dst_time) };
}
timestamp
@@ -478,7 +481,9 @@ pub unsafe extern "C" fn mktime(timeptr: *mut tm) -> time_t {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/nanosleep.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
Sys::nanosleep(rqtp, rmtp).map(|()| 0).or_minus_one_errno()
unsafe { Sys::nanosleep(rqtp, rmtp) }
.map(|()| 0)
.or_minus_one_errno()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html>.
@@ -489,11 +494,13 @@ pub unsafe extern "C" fn strftime(
format: *const c_char,
timeptr: *const tm,
) -> size_t {
let ret = strftime::strftime(
&mut platform::StringWriter(s as *mut u8, maxsize),
format,
timeptr,
);
let ret = unsafe {
strftime::strftime(
&mut platform::StringWriter(s as *mut u8, maxsize),
format,
timeptr,
)
};
if ret < maxsize { ret } else { 0 }
}
@@ -510,7 +517,7 @@ pub unsafe extern "C" fn time(tloc: *mut time_t) -> time_t {
let mut ts = timespec::default();
Sys::clock_gettime(CLOCK_REALTIME, Out::from_mut(&mut ts));
if !tloc.is_null() {
*tloc = ts.tv_sec
unsafe { *tloc = ts.tv_sec }
};
ts.tv_sec
}
@@ -518,17 +525,19 @@ pub unsafe extern "C" fn time(tloc: *mut time_t) -> time_t {
/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/timegm.3.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn timegm(tm: *mut tm) -> time_t {
let tm_val = &mut *tm;
let tm_val = unsafe { &mut *tm };
let dt = match convert_tm_generic(&Utc, tm_val) {
Some(dt) => dt,
None => return -1,
};
(*tm).tm_wday = dt.weekday().num_days_from_sunday() as _;
(*tm).tm_yday = dt.ordinal0() as _; // day of year starting at 0
(*tm).tm_isdst = 0; // UTC does not use DST
(*tm).tm_gmtoff = 0; // UTC offset is zero
(*tm).tm_zone = UTC_STR.as_ptr() as *const c_char;
unsafe {
(*tm).tm_wday = dt.weekday().num_days_from_sunday() as _;
(*tm).tm_yday = dt.ordinal0() as _; // day of year starting at 0
(*tm).tm_isdst = 0; // UTC does not use DST
(*tm).tm_gmtoff = 0; // UTC offset is zero
(*tm).tm_zone = UTC_STR.as_ptr() as *const c_char;
}
dt.timestamp()
}
@@ -537,7 +546,7 @@ pub unsafe extern "C" fn timegm(tm: *mut tm) -> time_t {
#[deprecated]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn timelocal(tm: *mut tm) -> time_t {
let tm_val = &mut *tm;
let tm_val = unsafe { &mut *tm };
let tz = time_zone();
let dt = match convert_tm_generic(&tz, tm_val) {
Some(dt) => dt,
@@ -545,11 +554,13 @@ pub unsafe extern "C" fn timelocal(tm: *mut tm) -> time_t {
};
let tz_name = CString::new(tz.name()).unwrap();
(*tm).tm_wday = dt.weekday().num_days_from_sunday() as _;
(*tm).tm_yday = dt.ordinal0() as _; // day of year starting at 0
(*tm).tm_isdst = dt.offset().dst_offset().num_hours() as _;
(*tm).tm_gmtoff = dt.offset().fix().local_minus_utc() as _;
(*tm).tm_zone = tz_name.into_raw().cast();
unsafe {
(*tm).tm_wday = dt.weekday().num_days_from_sunday() as _;
(*tm).tm_yday = dt.ordinal0() as _; // day of year starting at 0
(*tm).tm_isdst = dt.offset().dst_offset().num_hours() as _;
(*tm).tm_gmtoff = dt.offset().fix().local_minus_utc() as _;
(*tm).tm_zone = tz_name.into_raw().cast();
}
dt.timestamp()
}
@@ -653,7 +664,7 @@ pub unsafe extern "C" fn tzset() {
MappedLocalTime::None => return,
};
set_timezone(&mut lock, &std_time, dst_time)
unsafe { set_timezone(&mut lock, &std_time, dst_time) }
}
fn convert_tm_generic<Tz: TimeZone>(tz: &Tz, tm_val: &tm) -> Option<DateTime<Tz>> {
@@ -805,23 +816,23 @@ unsafe fn set_timezone(
let ut_offset = std.offset();
guard.0 = Some(CString::new(ut_offset.abbreviation().expect("Wrong timezone")).unwrap());
tzname.0[0] = guard.0.as_ref().unwrap().as_ptr().cast_mut();
(unsafe { tzname.0 })[0] = guard.0.as_ref().unwrap().as_ptr().cast_mut();
match dst {
Some(dst) => {
guard.1 =
Some(CString::new(dst.offset().abbreviation().expect("Wrong timezone")).unwrap());
tzname.0[1] = guard.1.as_ref().unwrap().as_ptr().cast_mut();
daylight = 1;
(unsafe { tzname.0 })[1] = guard.1.as_ref().unwrap().as_ptr().cast_mut();
unsafe { daylight = 1 };
}
None => {
guard.1 = None;
tzname.0[1] = guard.0.as_ref().unwrap().as_ptr().cast_mut();
daylight = 0;
(unsafe { tzname.0 })[1] = guard.0.as_ref().unwrap().as_ptr().cast_mut();
unsafe { daylight = 0 };
}
}
timezone = -c_long::from(ut_offset.fix().local_minus_utc());
unsafe { timezone = -c_long::from(ut_offset.fix().local_minus_utc()) };
}
#[inline(always)]
+56 -44
View File
@@ -2,6 +2,9 @@
//
// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html>.
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use alloc::string::String;
use super::{get_offset, tm};
@@ -31,11 +34,11 @@ use crate::header::langinfo::{
unsafe fn langinfo_to_str(item: nl_item) -> &'static str {
use core::ffi::CStr;
let ptr = nl_langinfo(item);
let ptr = unsafe { nl_langinfo(item) };
if ptr.is_null() {
return "";
}
match CStr::from_ptr(ptr).to_str() {
match unsafe { CStr::from_ptr(ptr) }.to_str() {
Ok(s) => s,
Err(_) => "",
}
@@ -71,7 +74,7 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
tmp.push_str($fmt);
tmp.push('\0');
if !inner_strftime(w, tmp.as_ptr() as *mut c_char, t) {
if unsafe { !inner_strftime(w, tmp.as_ptr() as *mut c_char, t) } {
return false;
}
}};
@@ -88,24 +91,24 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
}};
}
while *format != 0 {
while unsafe { *format } != 0 {
// If the character isn't '%', just copy it out.
if *format as u8 != b'%' {
w!(byte * format as u8);
format = format.offset(1);
if unsafe { *format } as u8 != b'%' {
w!(byte unsafe { *format } as u8);
format = unsafe { format.offset(1) };
continue;
}
// Skip '%'
format = format.offset(1);
format = unsafe { format.offset(1) };
// POSIX says '%E' and '%O' can modify numeric formats for locales,
// but we ignore them in this minimal "C" locale approach.
if *format as u8 == b'E' || *format as u8 == b'O' {
format = format.offset(1);
if unsafe { *format } as u8 == b'E' || unsafe { *format } as u8 == b'O' {
format = unsafe { format.offset(1) };
}
match *format as u8 {
match unsafe { *format } as u8 {
// Literal '%'
b'%' => w!(byte b'%'),
@@ -116,83 +119,83 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
// Abbreviated weekday name: %a
b'a' => {
// `ABDAY_1 + tm_wday` is the correct langinfo ID for abbreviated weekdays
let s = langinfo_to_str(ABDAY_1 + (*t).tm_wday as i32);
let s = unsafe { langinfo_to_str(ABDAY_1 + (*t).tm_wday as i32) };
w!(s);
}
// Full weekday name: %A
b'A' => {
// `DAY_1 + tm_wday` is the correct langinfo ID for full weekdays
let s = langinfo_to_str(DAY_1 + (*t).tm_wday as i32);
let s = unsafe { langinfo_to_str(DAY_1 + (*t).tm_wday as i32) };
w!(s);
}
// Abbreviated month name: %b or %h
b'b' | b'h' => {
let s = langinfo_to_str(ABMON_1 + (*t).tm_mon as i32);
let s = unsafe { langinfo_to_str(ABMON_1 + (*t).tm_mon as i32) };
w!(s);
}
// Full month name: %B
b'B' => {
let s = langinfo_to_str(MON_1 + (*t).tm_mon as i32);
let s = unsafe { langinfo_to_str(MON_1 + (*t).tm_mon as i32) };
w!(s);
}
// Century: %C
b'C' => {
let mut year = (*t).tm_year / 100;
if (*t).tm_year % 100 != 0 {
let mut year = unsafe { (*t).tm_year } / 100;
if unsafe { (*t).tm_year } % 100 != 0 {
year += 1;
}
w!("{:02}", year + 19);
}
// Day of month: %d
b'd' => w!("{:02}", (*t).tm_mday),
b'd' => w!("{:02}", unsafe { (*t).tm_mday }),
// %D => same as %m/%d/%y
b'D' => w!(recurse "%m/%d/%y"),
// Day of month, space-padded: %e
b'e' => w!("{:2}", (*t).tm_mday),
b'e' => w!("{:2}", unsafe { (*t).tm_mday }),
// ISO 8601 date: %F => %Y-%m-%d
b'F' => w!(recurse "%Y-%m-%d"),
// Hour (00-23): %H
b'H' => w!("{:02}", (*t).tm_hour),
b'H' => w!("{:02}", unsafe { (*t).tm_hour }),
// Hour (01-12): %I
b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1),
b'I' => w!("{:02}", (unsafe { (*t).tm_hour } + 12 - 1) % 12 + 1),
// Day of year: %j
b'j' => w!("{:03}", (*t).tm_yday + 1),
b'j' => w!("{:03}", unsafe { (*t).tm_yday } + 1),
// etc.
b'k' => w!("{:2}", (*t).tm_hour),
b'l' => w!("{:2}", ((*t).tm_hour + 12 - 1) % 12 + 1),
b'm' => w!("{:02}", (*t).tm_mon + 1),
b'M' => w!("{:02}", (*t).tm_min),
b'k' => w!("{:2}", unsafe { (*t).tm_hour }),
b'l' => w!("{:2}", (unsafe { (*t).tm_hour } + 12 - 1) % 12 + 1),
b'm' => w!("{:02}", unsafe { (*t).tm_mon } + 1),
b'M' => w!("{:02}", unsafe { (*t).tm_min }),
// AM/PM (uppercase): %p
b'p' => {
// Get "AM" / "PM" from langinfo
if (*t).tm_hour < 12 {
w!(langinfo_to_str(AM_STR));
if unsafe { (*t).tm_hour } < 12 {
w!(unsafe { langinfo_to_str(AM_STR) });
} else {
w!(langinfo_to_str(PM_STR));
w!(unsafe { langinfo_to_str(PM_STR) });
}
}
// am/pm (lowercase): %P
b'P' => {
// Convert the AM_STR / PM_STR to lowercase
if (*t).tm_hour < 12 {
let am = langinfo_to_str(AM_STR).to_ascii_lowercase();
if unsafe { (*t).tm_hour } < 12 {
let am = unsafe { langinfo_to_str(AM_STR) }.to_ascii_lowercase();
w!(&am);
} else {
let pm = langinfo_to_str(PM_STR).to_ascii_lowercase();
let pm = unsafe { langinfo_to_str(PM_STR) }.to_ascii_lowercase();
w!(&pm);
}
}
@@ -204,38 +207,44 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
b'R' => w!(recurse "%H:%M"),
// Seconds since the Epoch: %s => calls mktime() to convert tm to time_t
b's' => w!("{}", super::mktime(t as *mut tm)),
b's' => w!("{}", unsafe { super::mktime(t as *mut tm) }),
// Seconds (00-60): %S (unchanged)
b'S' => w!("{:02}", (*t).tm_sec),
b'S' => w!("{:02}", unsafe { (*t).tm_sec }),
// 24-hour clock with seconds: %T => %H:%M:%S
b'T' => w!(recurse "%H:%M:%S"),
// Weekday (1-7, Monday=1): %u
b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1),
b'u' => w!("{}", (unsafe { (*t).tm_wday } + 7 - 1) % 7 + 1),
// Sunday-based week of year: %U
b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7),
b'U' => w!(
"{}",
(unsafe { (*t).tm_yday } + 7 - unsafe { (*t).tm_wday }) / 7
),
// ISO-8601 week of year
b'V' => w!("{}", week_of_year(unsafe { &*t })),
// Weekday (0-6, Sunday=0): %w
b'w' => w!("{}", (*t).tm_wday),
b'w' => w!("{}", unsafe { (*t).tm_wday }),
// Monday-based week of year: %W
b'W' => w!("{}", ((*t).tm_yday + 7 - ((*t).tm_wday + 6) % 7) / 7),
b'W' => w!(
"{}",
(unsafe { (*t).tm_yday } + 7 - (unsafe { (*t).tm_wday } + 6) % 7) / 7
),
// Last two digits of year: %y
b'y' => w!("{:02}", (*t).tm_year % 100),
b'y' => w!("{:02}", unsafe { (*t).tm_year } % 100),
// Full year: %Y
b'Y' => w!("{}", (*t).tm_year + 1900),
b'Y' => w!("{}", unsafe { (*t).tm_year } + 1900),
// Timezone offset: %z
b'z' => {
let offset = (*t).tm_gmtoff;
let offset = unsafe { (*t).tm_gmtoff };
let (sign, offset) = if offset < 0 {
('-', -offset)
} else {
@@ -248,7 +257,10 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
}
// Timezone name: %Z
b'Z' => w!("{}", CStr::from_ptr((*t).tm_zone).to_str().unwrap()),
b'Z' => w!(
"{}",
unsafe { CStr::from_ptr((*t).tm_zone) }.to_str().unwrap()
),
// Date+time+TZ: %+
b'+' => w!(recurse "%a %b %d %T %Z %Y"),
@@ -258,14 +270,14 @@ pub unsafe fn strftime<W: WriteByte>(w: &mut W, format: *const c_char, t: *const
}
// Move past the format specifier
format = format.offset(1);
format = unsafe { format.offset(1) };
}
true
}
// Wrap the writer in a CountingWriter to return how many bytes were written.
let mut cw = platform::CountingWriter::new(w);
if !inner_strftime(&mut cw, format, t) {
if unsafe { !inner_strftime(&mut cw, format, t) } {
return 0;
}
cw.written