diff --git a/libc-dep/Cargo.toml b/libc-dep/Cargo.toml index fefb8b74..06d6bd3f 100644 --- a/libc-dep/Cargo.toml +++ b/libc-dep/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] libc = "0.2" nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] } +jiff = "0.2" diff --git a/libcc2rs/Cargo.toml b/libcc2rs/Cargo.toml index 5e10915b..6370ac02 100644 --- a/libcc2rs/Cargo.toml +++ b/libcc2rs/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" libcc2rs-macros = { path = "../libcc2rs-macros", version = "0.1.0" } libc = "0.2" nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] } +jiff = "0.2" diff --git a/libcc2rs/src/libc_shims/time.rs b/libcc2rs/src/libc_shims/time.rs index 10fa6cfd..e958b3c4 100644 --- a/libcc2rs/src/libc_shims/time.rs +++ b/libcc2rs/src/libc_shims/time.rs @@ -20,6 +20,40 @@ pub struct Tm { pub tm_zone: Value>, } +impl Tm { + pub fn from_zoned(dt: &jiff::Zoned) -> Self { + let tm = Tm::default(); + *tm.tm_sec.borrow_mut() = dt.second() as i32; + *tm.tm_min.borrow_mut() = dt.minute() as i32; + *tm.tm_hour.borrow_mut() = dt.hour() as i32; + *tm.tm_mday.borrow_mut() = dt.day() as i32; + *tm.tm_mon.borrow_mut() = dt.month() as i32 - 1; + *tm.tm_year.borrow_mut() = dt.year() as i32 - 1900; + *tm.tm_wday.borrow_mut() = dt.weekday().to_sunday_zero_offset() as i32; + *tm.tm_yday.borrow_mut() = dt.day_of_year() as i32 - 1; + *tm.tm_isdst.borrow_mut() = 0; + *tm.tm_gmtoff.borrow_mut() = dt.offset().seconds() as i64; + #[cfg(target_os = "linux")] + let zone: &'static [u8] = b"GMT"; + #[cfg(target_os = "macos")] + let zone: &'static [u8] = b"UTC"; + *tm.tm_zone.borrow_mut() = Ptr::from_string_literal(zone); + tm + } + + pub fn to_civil(&self) -> Result { + jiff::civil::DateTime::new( + (*self.tm_year.borrow() + 1900) as i16, + (*self.tm_mon.borrow() + 1) as i8, + *self.tm_mday.borrow() as i8, + *self.tm_hour.borrow() as i8, + *self.tm_min.borrow() as i8, + *self.tm_sec.borrow() as i8, + 0, + ) + } +} + impl Clone for Tm { fn clone(&self) -> Self { Self { diff --git a/rule-preprocessor/src/semantic.rs b/rule-preprocessor/src/semantic.rs index f9030457..2f475a95 100644 --- a/rule-preprocessor/src/semantic.rs +++ b/rule-preprocessor/src/semantic.rs @@ -46,7 +46,14 @@ fn build_rustc_args(crate_root: &Path) -> Vec { args.push("-L".to_string()); args.push(format!("dependency={}", deps.display())); - for dep in &["libcc2rs", "libc", "brotli_sys", "rustls_ffi", "nix"] { + for dep in &[ + "libcc2rs", + "libc", + "brotli_sys", + "rustls_ffi", + "nix", + "jiff", + ] { if let Some(rlib) = find_rlib(deps.as_path(), dep) { args.push("--extern".to_string()); args.push(format!("{}={}", dep, rlib.display())); diff --git a/rules/Cargo.toml b/rules/Cargo.toml index d9a5e1be..0c8d3841 100644 --- a/rules/Cargo.toml +++ b/rules/Cargo.toml @@ -14,3 +14,4 @@ libcc2rs = { version = "0.1.0", path = "../libcc2rs" } brotli-sys = "0.3" rustls-ffi = { version = "0.15.3", default-features = false } nix = { version = "0.30", features = ["socket", "net", "fs", "poll", "time", "user", "dir", "term", "event", "hostname"] } +jiff = "0.2" diff --git a/rules/time/src.c b/rules/time/src.c index 270bf646..7d4f8d2c 100644 --- a/rules/time/src.c +++ b/rules/time/src.c @@ -41,3 +41,7 @@ int f8(struct timeval *tv, void *tz) { #else #error "Unsupported platform for gettimeofday" #endif + +clockid_t f9() { + return CLOCK_REALTIME; +} diff --git a/rules/time/tgt_refcount.rs b/rules/time/tgt_refcount.rs index d5bd7893..808c5e56 100644 --- a/rules/time/tgt_refcount.rs +++ b/rules/time/tgt_refcount.rs @@ -14,3 +14,139 @@ fn t2() -> libcc2rs::Timeval { fn t3() -> libcc2rs::Timespec { Default::default() } + +fn f1(a0: Ptr<::libc::time_t>) -> ::libc::time_t { + let __out = a0; + match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) { + Ok(__ts) => { + let __s = __ts.tv_sec(); + if !__out.is_null() { + __out.write(__s); + } + __s + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } +} + +fn f2(a0: nix::time::ClockId, a1: Ptr) -> i32 { + match nix::time::clock_gettime(a0) { + Ok(__ts) => { + a1.with_mut(|__t| { + *__t.tv_sec.borrow_mut() = __ts.tv_sec() as i64; + *__t.tv_nsec.borrow_mut() = __ts.tv_nsec() as i64; + }); + 0 + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } +} + +fn f4(a0: Ptr<::libc::time_t>, a1: Ptr) -> Ptr { + let __res = a1.clone(); + match jiff::Timestamp::from_second(a0.read()) { + Ok(__ts) => { + let __dt = __ts.to_zoned(jiff::tz::TimeZone::UTC); + __res.with_mut(|__tm| *__tm = Tm::from_zoned(&__dt)); + __res + } + Err(_) => { + libcc2rs::cpp2rust_errno().write(::libc::EOVERFLOW); + Ptr::null() + } + } +} + +fn f6(a0: Ptr, a1: usize, a2: Ptr, a3: Ptr) -> usize { + let __dt = a3.with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => { + jiff::fmt::strtime::format(a2.to_rust_string().as_str(), __d).unwrap_or_default() + } + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > a1 { + 0 + } else { + let mut __dst = a0.clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } +} + +fn f7(a0: Ptr, a1: Ptr) -> i32 { + let __times = a1; + let __at = __times.with(|__tv| { + nix::sys::time::TimeVal::new( + *__tv.tv_sec.borrow() as ::libc::time_t, + *__tv.tv_usec.borrow() as ::libc::suseconds_t, + ) + }); + let __mt = __times.offset(1).with(|__tv| { + nix::sys::time::TimeVal::new( + *__tv.tv_sec.borrow() as ::libc::time_t, + *__tv.tv_usec.borrow() as ::libc::suseconds_t, + ) + }); + match nix::sys::stat::utimes(a0.to_rust_string().as_str(), &__at, &__mt) { + Ok(()) => 0, + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } +} + +// a1 is ignored intentionally, see: https://man7.org/linux/man-pages/man2/gettimeofday.2.html +// +// "The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL." +#[cfg(target_os = "linux")] +fn f8(a0: Ptr, a1: Ptr<::libc::timezone>) -> i32 { + match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) { + Ok(__ts) => { + a0.with_mut(|__tv| { + *__tv.tv_sec.borrow_mut() = __ts.tv_sec() as i64; + *__tv.tv_usec.borrow_mut() = (__ts.tv_nsec() / 1000) as i64; + }); + 0 + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } +} + +// a1 is ignored intentionally, see: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/gettimeofday.2.html +// +// "Note: timezone is no longer used; this information is kept outside the kernel." +#[cfg(target_os = "macos")] +fn f8(a0: Ptr, a1: AnyPtr) -> i32 { + match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) { + Ok(__ts) => { + a0.with_mut(|__tv| { + *__tv.tv_sec.borrow_mut() = __ts.tv_sec() as i64; + *__tv.tv_usec.borrow_mut() = (__ts.tv_nsec() / 1000) as i64; + }); + 0 + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } +} + +unsafe fn f9() -> nix::time::ClockId { + nix::time::ClockId::CLOCK_REALTIME +} diff --git a/rules/time/tgt_unsafe.rs b/rules/time/tgt_unsafe.rs index 0f8c1cd5..58bd70de 100644 --- a/rules/time/tgt_unsafe.rs +++ b/rules/time/tgt_unsafe.rs @@ -51,3 +51,7 @@ unsafe fn f8(a0: *mut libc::timeval, a1: *mut libc::timezone) -> i32 { unsafe fn f8(a0: *mut libc::timeval, a1: *mut libc::c_void) -> i32 { libc::gettimeofday(a0, a1) } + +unsafe fn f9() -> libc::clockid_t { + libc::CLOCK_REALTIME +} diff --git a/tests/lit/lit/formats/Cpp2RustTest.py b/tests/lit/lit/formats/Cpp2RustTest.py index 89465616..006bc2a1 100644 --- a/tests/lit/lit/formats/Cpp2RustTest.py +++ b/tests/lit/lit/formats/Cpp2RustTest.py @@ -212,6 +212,10 @@ def build_rust(self): libc_dep_deps.glob("libnix-*.rlib"), key=lambda p: p.stat().st_mtime, ) + jiff_rlib = max( + libc_dep_deps.glob("libjiff-*.rlib"), + key=lambda p: p.stat().st_mtime, + ) cmd = [ "rustc", "+" + read_rust_version(), @@ -240,6 +244,8 @@ def build_rust(self): f"libc={libc_rlib}", "--extern", f"nix={nix_rlib}", + "--extern", + f"jiff={jiff_rlib}", ] _, err, returncode = lit.util.executeCommand(cmd, str(self.tmp_dir)) if exp.should_not_compile: diff --git a/tests/unit/out/refcount/sys_time.rs b/tests/unit/out/refcount/sys_time.rs new file mode 100644 index 00000000..dd18d962 --- /dev/null +++ b/tests/unit/out/refcount/sys_time.rs @@ -0,0 +1,268 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn test_time_0() { + let t1: Value = Rc::new(RefCell::new({ + let __out = Ptr::::null(); + match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) { + Ok(__ts) => { + let __s = __ts.tv_sec(); + if !__out.is_null() { + __out.write(__s); + } + __s + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } + })); + let t2: Value = Rc::new(RefCell::new(0_i64)); + let t3: Value = Rc::new(RefCell::new({ + let __out = (t2.as_pointer()); + match nix::time::clock_gettime(nix::time::ClockId::CLOCK_REALTIME) { + Ok(__ts) => { + let __s = __ts.tv_sec(); + if !__out.is_null() { + __out.write(__s); + } + __s + } + Err(__e) => { + libcc2rs::cpp2rust_errno().write(__e as i32); + -1 + } + } + })); + assert!(((((*t1.borrow()) > 1500000000_i64) as i32) != 0)); + assert!(((((*t2.borrow()) == (*t3.borrow())) as i32) != 0)); + assert!(((((*t3.borrow()) >= (*t1.borrow())) as i32) != 0)); +} +pub fn print_tm_1(t: i64) { + let t: Value = Rc::new(RefCell::new(t)); + let tm: Value = Rc::new(RefCell::new(Default::default())); + assert!( + (((!(({ + let __res = (tm.as_pointer()).clone(); + match jiff::Timestamp::from_second((t.as_pointer()).read()) { + Ok(__ts) => { + let __dt = __ts.to_zoned(jiff::tz::TimeZone::UTC); + __res.with_mut(|__tm| *__tm = Tm::from_zoned(&__dt)); + __res + } + Err(_) => { + libcc2rs::cpp2rust_errno().write(::libc::EOVERFLOW); + Ptr::null() + } + } + }) + .is_null())) as i32) + != 0) + ); + println!( + "{}-{}-{} {}:{}:{} wday={} yday={} {} gmtoff={} isdst={}", + (*(*tm.borrow()).tm_year.borrow()), + (*(*tm.borrow()).tm_mon.borrow()), + (*(*tm.borrow()).tm_mday.borrow()), + (*(*tm.borrow()).tm_hour.borrow()), + (*(*tm.borrow()).tm_min.borrow()), + (*(*tm.borrow()).tm_sec.borrow()), + (*(*tm.borrow()).tm_wday.borrow()), + (*(*tm.borrow()).tm_yday.borrow()), + (*(*tm.borrow()).tm_zone.borrow()), + (*(*tm.borrow()).tm_gmtoff.borrow()), + (*(*tm.borrow()).tm_isdst.borrow()) + ); +} +pub fn test_gmtime_r_2() { + ({ print_tm_1(0_i64) }); + ({ print_tm_1(1_i64) }); + ({ print_tm_1(86399_i64) }); + ({ print_tm_1(86400_i64) }); + ({ print_tm_1(951782400_i64) }); + ({ print_tm_1(951868799_i64) }); + ({ print_tm_1(1704067199_i64) }); + ({ print_tm_1(1704067200_i64) }); + ({ print_tm_1(1721126096_i64) }); + ({ print_tm_1(4102444800_i64) }); +} +pub fn test_strftime_3() { + let t: Value = Rc::new(RefCell::new(1721126096_i64)); + let tm: Value = Rc::new(RefCell::new(Default::default())); + assert!( + (((!(({ + let __res = (tm.as_pointer()).clone(); + match jiff::Timestamp::from_second((t.as_pointer()).read()) { + Ok(__ts) => { + let __dt = __ts.to_zoned(jiff::tz::TimeZone::UTC); + __res.with_mut(|__tm| *__tm = Tm::from_zoned(&__dt)); + __res + } + Err(_) => { + libcc2rs::cpp2rust_errno().write(::libc::EOVERFLOW); + Ptr::null() + } + } + }) + .is_null())) as i32) + != 0) + ); + let buf: Value> = Rc::new(RefCell::new( + (0..64).map(|_| ::default()).collect::>(), + )); + assert!( + ((({ + let __dt = (tm.as_pointer()).with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => jiff::fmt::strtime::format( + Ptr::from_string_literal(b"%Y-%m-%d %H:%M:%S") + .to_rust_string() + .as_str(), + __d, + ) + .unwrap_or_default(), + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > ::std::mem::size_of::<[u8; 64]>() { + 0 + } else { + let mut __dst = (buf.as_pointer() as Ptr).clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } + } > 0_usize) as i32) + != 0) + ); + println!("{}", (buf.as_pointer() as Ptr::)); + assert!( + ((({ + let __dt = (tm.as_pointer()).with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => jiff::fmt::strtime::format( + Ptr::from_string_literal(b"%a, %d %b %Y %T") + .to_rust_string() + .as_str(), + __d, + ) + .unwrap_or_default(), + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > ::std::mem::size_of::<[u8; 64]>() { + 0 + } else { + let mut __dst = (buf.as_pointer() as Ptr).clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } + } > 0_usize) as i32) + != 0) + ); + println!("{}", (buf.as_pointer() as Ptr::)); + assert!( + ((({ + let __dt = (tm.as_pointer()).with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => jiff::fmt::strtime::format( + Ptr::from_string_literal(b"day %j 100%%") + .to_rust_string() + .as_str(), + __d, + ) + .unwrap_or_default(), + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > ::std::mem::size_of::<[u8; 64]>() { + 0 + } else { + let mut __dst = (buf.as_pointer() as Ptr).clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } + } > 0_usize) as i32) + != 0) + ); + println!("{}", (buf.as_pointer() as Ptr::)); + assert!( + ((({ + let __dt = (tm.as_pointer()).with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => jiff::fmt::strtime::format( + Ptr::from_string_literal(b"%e").to_rust_string().as_str(), + __d, + ) + .unwrap_or_default(), + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > ::std::mem::size_of::<[u8; 64]>() { + 0 + } else { + let mut __dst = (buf.as_pointer() as Ptr).clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } + } > 0_usize) as i32) + != 0) + ); + println!("{}", (buf.as_pointer() as Ptr::)); + let small: Value> = Rc::new(RefCell::new( + (0..4).map(|_| ::default()).collect::>(), + )); + assert!( + ((({ + let __dt = (tm.as_pointer()).with(|__tm| __tm.to_civil()); + let __text = match __dt { + Ok(__d) => jiff::fmt::strtime::format( + Ptr::from_string_literal(b"%Y-%m-%d") + .to_rust_string() + .as_str(), + __d, + ) + .unwrap_or_default(), + Err(_) => String::new(), + }; + if __text.is_empty() || __text.len() + 1 > ::std::mem::size_of::<[u8; 4]>() { + 0 + } else { + let mut __dst = (small.as_pointer() as Ptr).clone(); + for __b in __text.as_bytes() { + __dst.write(*__b); + __dst += 1; + } + __dst.write(0); + __text.len() + } + } == 0_usize) as i32) + != 0) + ); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + ({ test_time_0() }); + ({ test_gmtime_r_2() }); + ({ test_strftime_3() }); + return 0; +} diff --git a/tests/unit/out/unsafe/sys_time.rs b/tests/unit/out/unsafe/sys_time.rs new file mode 100644 index 00000000..bd511f1d --- /dev/null +++ b/tests/unit/out/unsafe/sys_time.rs @@ -0,0 +1,142 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn test_time_0() { + let mut t1: i64 = libc::time(std::ptr::null_mut()); + let mut t2: i64 = 0_i64; + let mut t3: i64 = libc::time((&mut t2 as *mut i64)); + assert!(((((t1) > (1500000000_i64)) as i32) != 0)); + assert!(((((t2) == (t3)) as i32) != 0)); + assert!(((((t3) >= (t1)) as i32) != 0)); +} +pub unsafe fn print_tm_1(mut t: i64) { + let mut tm: ::libc::tm = unsafe { std::mem::zeroed() }; + assert!( + (((!((libc::gmtime_r( + (&mut t as *mut i64).cast_const(), + (&mut tm as *mut ::libc::tm) + )) + .is_null())) as i32) + != 0) + ); + printf( + (c"%d-%d-%d %d:%d:%d wday=%d yday=%d %s gmtoff=%ld isdst=%d\n" + .as_ptr() + .cast_mut()) + .cast_const() as *const i8, + tm.tm_year, + tm.tm_mon, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec, + tm.tm_wday, + tm.tm_yday, + tm.tm_zone, + tm.tm_gmtoff, + tm.tm_isdst, + ); +} +pub unsafe fn test_gmtime_r_2() { + (unsafe { print_tm_1(0_i64) }); + (unsafe { print_tm_1(1_i64) }); + (unsafe { print_tm_1(86399_i64) }); + (unsafe { print_tm_1(86400_i64) }); + (unsafe { print_tm_1(951782400_i64) }); + (unsafe { print_tm_1(951868799_i64) }); + (unsafe { print_tm_1(1704067199_i64) }); + (unsafe { print_tm_1(1704067200_i64) }); + (unsafe { print_tm_1(1721126096_i64) }); + (unsafe { print_tm_1(4102444800_i64) }); +} +pub unsafe fn test_strftime_3() { + let mut t: i64 = 1721126096_i64; + let mut tm: ::libc::tm = unsafe { std::mem::zeroed() }; + assert!( + (((!((libc::gmtime_r( + (&mut t as *mut i64).cast_const(), + (&mut tm as *mut ::libc::tm) + )) + .is_null())) as i32) + != 0) + ); + let mut buf: [libc::c_char; 64] = [(0 as libc::c_char); 64]; + assert!( + ((((libc::strftime( + buf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>(), + (c"%Y-%m-%d %H:%M:%S".as_ptr().cast_mut()).cast_const(), + (&mut tm as *mut ::libc::tm).cast_const() + )) > (0_usize)) as i32) + != 0) + ); + printf( + (c"%s\n".as_ptr().cast_mut()).cast_const() as *const i8, + buf.as_mut_ptr(), + ); + assert!( + ((((libc::strftime( + buf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>(), + (c"%a, %d %b %Y %T".as_ptr().cast_mut()).cast_const(), + (&mut tm as *mut ::libc::tm).cast_const() + )) > (0_usize)) as i32) + != 0) + ); + printf( + (c"%s\n".as_ptr().cast_mut()).cast_const() as *const i8, + buf.as_mut_ptr(), + ); + assert!( + ((((libc::strftime( + buf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>(), + (c"day %j 100%%".as_ptr().cast_mut()).cast_const(), + (&mut tm as *mut ::libc::tm).cast_const() + )) > (0_usize)) as i32) + != 0) + ); + printf( + (c"%s\n".as_ptr().cast_mut()).cast_const() as *const i8, + buf.as_mut_ptr(), + ); + assert!( + ((((libc::strftime( + buf.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>(), + (c"%e".as_ptr().cast_mut()).cast_const(), + (&mut tm as *mut ::libc::tm).cast_const() + )) > (0_usize)) as i32) + != 0) + ); + printf( + (c"%s\n".as_ptr().cast_mut()).cast_const() as *const i8, + buf.as_mut_ptr(), + ); + let mut small: [libc::c_char; 4] = [(0 as libc::c_char); 4]; + assert!( + ((((libc::strftime( + small.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 4]>(), + (c"%Y-%m-%d".as_ptr().cast_mut()).cast_const(), + (&mut tm as *mut ::libc::tm).cast_const() + )) == (0_usize)) as i32) + != 0) + ); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { test_time_0() }); + (unsafe { test_gmtime_r_2() }); + (unsafe { test_strftime_3() }); + return 0; +} diff --git a/tests/unit/sys_time.c b/tests/unit/sys_time.c new file mode 100644 index 00000000..daa3e01e --- /dev/null +++ b/tests/unit/sys_time.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +static void test_time(void) { + time_t t1 = time(NULL); + time_t t2 = 0; + time_t t3 = time(&t2); + assert(t1 > 1500000000); + assert(t2 == t3); + assert(t3 >= t1); +} + +static void print_tm(time_t t) { + struct tm tm; + assert(gmtime_r(&t, &tm) != NULL); + printf("%d-%d-%d %d:%d:%d wday=%d yday=%d %s gmtoff=%ld isdst=%d\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_wday, tm.tm_yday, tm.tm_zone, tm.tm_gmtoff, tm.tm_isdst); +} + +static void test_gmtime_r(void) { + print_tm(0); + print_tm(1); + print_tm(86399); + print_tm(86400); + print_tm(951782400); /* leap day */ + print_tm(951868799); + print_tm(1704067199); /* year boundary */ + print_tm(1704067200); + print_tm(1721126096); + print_tm(4102444800); +} + +static void test_strftime(void) { + time_t t = 1721126096; + struct tm tm; + assert(gmtime_r(&t, &tm) != NULL); + char buf[64]; + assert(strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm) > 0); + printf("%s\n", buf); + assert(strftime(buf, sizeof(buf), "%a, %d %b %Y %T", &tm) > 0); + printf("%s\n", buf); + assert(strftime(buf, sizeof(buf), "day %j 100%%", &tm) > 0); + printf("%s\n", buf); + assert(strftime(buf, sizeof(buf), "%e", &tm) > 0); + printf("%s\n", buf); + char small[4]; + assert(strftime(small, sizeof(small), "%Y-%m-%d", &tm) == 0); +} + +int main(void) { + test_time(); + test_gmtime_r(); + test_strftime(); + return 0; +}