Large reorganization of headers (WIP)
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
sys_includes = ["sys/types.h", "stdint.h", "stddef.h"]
|
||||
include_guard = "_TIME_H"
|
||||
language = "C"
|
||||
|
||||
# WORKAROUND:
|
||||
# Tm is used by another header, and cbindgen doesn't prefix that with `struct` :|
|
||||
style = "Both"
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
|
||||
[defines]
|
||||
"target_os = linux" = "__linux__"
|
||||
"target_os = redox" = "__redox__"
|
||||
@@ -0,0 +1,52 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "linux.rs"]
|
||||
pub mod sys;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[path = "redox.rs"]
|
||||
pub mod sys;
|
||||
|
||||
use platform::types::*;
|
||||
pub use sys::*;
|
||||
|
||||
// Move epoch from 01.01.1970 to 01.03.0000 (yes, Year 0) - this is the first
|
||||
// day of a 400-year long "era", right after additional day of leap year.
|
||||
// This adjustment is required only for date calculation, so instead of
|
||||
// modifying time_t value (which would require 64-bit operations to work
|
||||
// correctly) it's enough to adjust the calculated number of days since epoch.
|
||||
pub(crate) const EPOCH_ADJUSTMENT_DAYS: c_long = 719468;
|
||||
// year to which the adjustment was made
|
||||
pub(crate) const ADJUSTED_EPOCH_YEAR: c_int = 0;
|
||||
// 1st March of year 0 is Wednesday
|
||||
pub(crate) const ADJUSTED_EPOCH_WDAY: c_long = 3;
|
||||
pub(crate) const DAYS_PER_ERA: c_long = (400 - 97) * 365 + 97 * 366;
|
||||
pub(crate) const DAYS_PER_CENTURY: c_ulong = (100 - 24) * 365 + 24 * 366;
|
||||
pub(crate) const DAYS_PER_4_YEARS: c_ulong = 3 * 365 + 366;
|
||||
pub(crate) const DAYS_PER_YEAR: c_int = 365;
|
||||
pub(crate) const DAYS_IN_JANUARY: c_int = 31;
|
||||
pub(crate) const DAYS_IN_FEBRUARY: c_int = 28;
|
||||
pub(crate) const YEARS_PER_ERA: c_int = 400;
|
||||
|
||||
pub(crate) const SECSPERMIN: c_long = 60;
|
||||
pub(crate) const MINSPERHOUR: c_long = 60;
|
||||
pub(crate) const HOURSPERDAY: c_long = 24;
|
||||
pub(crate) const SECSPERHOUR: c_long = SECSPERMIN * MINSPERHOUR;
|
||||
pub(crate) const SECSPERDAY: c_long = SECSPERHOUR * HOURSPERDAY;
|
||||
pub(crate) const DAYSPERWEEK: c_int = 7;
|
||||
|
||||
pub(crate) const YEAR_BASE: c_int = 1900;
|
||||
|
||||
pub(crate) const UTC: *const c_char = b"UTC\0" as *const u8 as *const c_char;
|
||||
|
||||
pub(crate) const DAY_NAMES: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
pub(crate) const MON_NAMES: [&str; 12] = [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
|
||||
pub(crate) const CLOCK_REALTIME: clockid_t = 0;
|
||||
pub const CLOCK_MONOTONIC: clockid_t = 1;
|
||||
pub(crate) const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
|
||||
pub(crate) const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
|
||||
|
||||
// Can't be time_t because cbindgen UGH
|
||||
pub(crate) const CLOCKS_PER_SEC: c_long = 1_000_000;
|
||||
@@ -0,0 +1,40 @@
|
||||
use constants::*;
|
||||
use platform::types::*;
|
||||
|
||||
// compute year, month, day & day of year
|
||||
// for description of this algorithm see
|
||||
// http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
||||
#[inline(always)]
|
||||
pub(crate) fn civil_from_days(days: c_long) -> (c_int, c_int, c_int, c_int) {
|
||||
let (era, year): (c_int, c_int);
|
||||
let (erayear, mut yearday, mut month, day): (c_int, c_int, c_int, c_int);
|
||||
let eraday: c_ulong;
|
||||
|
||||
era = (if days >= 0 {
|
||||
days
|
||||
} else {
|
||||
days - (DAYS_PER_ERA - 1)
|
||||
} / DAYS_PER_ERA) as c_int;
|
||||
eraday = (days - era as c_long * DAYS_PER_ERA) as c_ulong;
|
||||
let a = eraday / (DAYS_PER_4_YEARS - 1);
|
||||
let b = eraday / DAYS_PER_CENTURY;
|
||||
let c = eraday / (DAYS_PER_ERA as c_ulong - 1);
|
||||
erayear = ((eraday - a + b - c) / 365) as c_int;
|
||||
let d = DAYS_PER_YEAR * erayear + erayear / 4 - erayear / 100;
|
||||
yearday = (eraday - d as c_ulong) as c_int;
|
||||
month = (5 * yearday + 2) / 153;
|
||||
day = yearday - (153 * month + 2) / 5 + 1;
|
||||
month += if month < 10 { 2 } else { -10 };
|
||||
year = ADJUSTED_EPOCH_YEAR + erayear + era * YEARS_PER_ERA + (month <= 1) as c_int;
|
||||
yearday += if yearday >= DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY {
|
||||
-(DAYS_PER_YEAR - DAYS_IN_JANUARY - DAYS_IN_FEBRUARY)
|
||||
} else {
|
||||
DAYS_IN_JANUARY + DAYS_IN_FEBRUARY + is_leap(erayear)
|
||||
};
|
||||
return (year, month, day, yearday);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_leap(y: c_int) -> c_int {
|
||||
((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) as c_int
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use platform::types::*;
|
||||
|
||||
pub const CLOCK_REALTIME: c_int = 0;
|
||||
pub const CLOCK_MONOTONIC: c_int = 1;
|
||||
pub const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
|
||||
pub const CLOCK_THREAD_CPUTIME_ID: c_int = 3;
|
||||
pub const CLOCK_MONOTONIC_RAW: c_int = 4;
|
||||
pub const CLOCK_REALTIME_COARSE: c_int = 5;
|
||||
pub const CLOCK_MONOTONIC_COARSE: c_int = 6;
|
||||
pub const CLOCK_BOOTTIME: c_int = 7;
|
||||
pub const CLOCK_REALTIME_ALARM: c_int = 8;
|
||||
pub const CLOCK_BOOTTIME_ALARM: c_int = 9;
|
||||
pub const CLOCK_TAI: c_int = 11;
|
||||
@@ -0,0 +1,415 @@
|
||||
//! time implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
|
||||
|
||||
use core::mem::transmute;
|
||||
|
||||
use header::errno;
|
||||
use header::errno::EIO;
|
||||
use platform;
|
||||
use platform::{Pal, Sys};
|
||||
use platform::types::*;
|
||||
|
||||
use constants::*;
|
||||
use helpers::*;
|
||||
|
||||
pub mod constants;
|
||||
mod helpers;
|
||||
mod strftime;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct timespec {
|
||||
pub tv_sec: time_t,
|
||||
pub tv_nsec: c_long,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct tm {
|
||||
pub tm_sec: c_int,
|
||||
pub tm_min: c_int,
|
||||
pub tm_hour: c_int,
|
||||
pub tm_mday: c_int,
|
||||
pub tm_mon: c_int,
|
||||
pub tm_year: c_int,
|
||||
pub tm_wday: c_int,
|
||||
pub tm_yday: c_int,
|
||||
pub tm_isdst: c_int,
|
||||
pub tm_gmtoff: c_long,
|
||||
pub tm_zone: *const c_char,
|
||||
}
|
||||
|
||||
unsafe impl Sync for tm {}
|
||||
|
||||
// The C Standard says that localtime and gmtime return the same pointer.
|
||||
static mut TM: tm = tm {
|
||||
tm_sec: 0,
|
||||
tm_min: 0,
|
||||
tm_hour: 0,
|
||||
tm_mday: 0,
|
||||
tm_mon: 0,
|
||||
tm_year: 0,
|
||||
tm_wday: 0,
|
||||
tm_yday: 0,
|
||||
tm_isdst: 0,
|
||||
tm_gmtoff: 0,
|
||||
tm_zone: UTC,
|
||||
};
|
||||
|
||||
// The C Standard says that ctime and asctime return the same pointer.
|
||||
static mut ASCTIME: [c_char; 26] = [0; 26];
|
||||
|
||||
#[repr(C)]
|
||||
pub struct itimerspec {
|
||||
pub it_interval: timespec,
|
||||
pub it_value: timespec,
|
||||
}
|
||||
|
||||
pub struct sigevent;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn asctime(timeptr: *const tm) -> *mut c_char {
|
||||
unsafe { asctime_r(timeptr, transmute::<&mut _, *mut c_char>(&mut ASCTIME)) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char {
|
||||
let tm = unsafe { &*tm };
|
||||
let result = core::fmt::write(
|
||||
&mut platform::UnsafeStringWriter(buf as *mut u8),
|
||||
format_args!(
|
||||
"{:.3} {:.3}{:3} {:02}:{:02}:{:02} {}\n",
|
||||
DAY_NAMES[tm.tm_wday as usize],
|
||||
MON_NAMES[tm.tm_mon as usize],
|
||||
tm.tm_mday as usize,
|
||||
tm.tm_hour as usize,
|
||||
tm.tm_min as usize,
|
||||
tm.tm_sec as usize,
|
||||
(1900 + tm.tm_year)
|
||||
),
|
||||
);
|
||||
match result {
|
||||
Ok(_) => buf,
|
||||
Err(_) => {
|
||||
unsafe { platform::errno = EIO };
|
||||
core::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clock() -> clock_t {
|
||||
let mut ts: timespec = unsafe { core::mem::uninitialized() };
|
||||
|
||||
if clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mut ts) != 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ts.tv_sec > time_t::max_value() / CLOCKS_PER_SEC
|
||||
|| ts.tv_nsec / (1_000_000_000 / CLOCKS_PER_SEC)
|
||||
> time_t::max_value() - CLOCKS_PER_SEC * ts.tv_sec
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ts.tv_sec * CLOCKS_PER_SEC + ts.tv_nsec / (1_000_000_000 / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int {
|
||||
Sys::clock_gettime(clock_id, tp as *mut platform::types::timespec)
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn clock_settime(clock_id: clockid_t, tp: *const timespec) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ctime(clock: *const time_t) -> *mut c_char {
|
||||
asctime(localtime(clock))
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn ctime_r(clock: *const time_t, buf: *mut c_char) -> *mut c_char {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn difftime(time1: time_t, time0: time_t) -> c_double {
|
||||
(time1 - time0) as c_double
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn getdate(string: *const c_char) -> tm {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn gmtime(timer: *const time_t) -> *mut tm {
|
||||
unsafe { gmtime_r(timer, &mut TM) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn gmtime_r(clock: *const time_t, result: *mut tm) -> *mut tm {
|
||||
let (mut days, mut rem): (c_long, c_long);
|
||||
let mut weekday: c_int;
|
||||
let lcltime = unsafe { *clock };
|
||||
|
||||
days = lcltime / SECSPERDAY + EPOCH_ADJUSTMENT_DAYS;
|
||||
rem = lcltime % SECSPERDAY;
|
||||
if rem < 0 {
|
||||
rem += SECSPERDAY;
|
||||
days -= 1;
|
||||
}
|
||||
unsafe {
|
||||
(*result).tm_hour = (rem / SECSPERHOUR) as c_int;
|
||||
rem %= SECSPERHOUR;
|
||||
(*result).tm_min = (rem / SECSPERMIN) as c_int;
|
||||
(*result).tm_sec = (rem % SECSPERMIN) as c_int;
|
||||
}
|
||||
|
||||
weekday = ((ADJUSTED_EPOCH_WDAY + days) % DAYSPERWEEK as c_long) as c_int;
|
||||
if weekday < 0 {
|
||||
weekday += DAYSPERWEEK;
|
||||
}
|
||||
unsafe { (*result).tm_wday = weekday };
|
||||
|
||||
let (year, month, day, yearday) = civil_from_days(days);
|
||||
unsafe {
|
||||
(*result).tm_yday = yearday;
|
||||
(*result).tm_year = year - YEAR_BASE;
|
||||
(*result).tm_mon = month;
|
||||
(*result).tm_mday = day;
|
||||
|
||||
(*result).tm_isdst = 0;
|
||||
(*result).tm_gmtoff = 0;
|
||||
(*result).tm_zone = UTC;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm {
|
||||
localtime_r(clock, &mut TM)
|
||||
}
|
||||
|
||||
const MONTH_DAYS: [[c_int; 12]; 2] = [
|
||||
// Non-leap years:
|
||||
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||
// Leap years:
|
||||
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||
];
|
||||
|
||||
fn leap_year(year: c_int) -> bool {
|
||||
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn localtime_r(clock: *const time_t, t: *mut tm) -> *mut tm {
|
||||
let clock = *clock;
|
||||
|
||||
let mut day = (clock / (60 * 60 * 24)) as c_int;
|
||||
if clock < 0 && clock % (60 * 60 * 24) != 0 {
|
||||
// -1 because for negative values round upwards
|
||||
// -0.3 == 0, but we want -1
|
||||
day -= 1;
|
||||
}
|
||||
|
||||
(*t).tm_sec = (clock % 60) as c_int;
|
||||
(*t).tm_min = ((clock / 60) % 60) as c_int;
|
||||
(*t).tm_hour = ((clock / (60 * 60)) % 24) as c_int;
|
||||
|
||||
while (*t).tm_sec < 0 {
|
||||
(*t).tm_sec += 60;
|
||||
(*t).tm_min -= 1;
|
||||
}
|
||||
while (*t).tm_min < 0 {
|
||||
(*t).tm_min += 60;
|
||||
(*t).tm_hour -= 1;
|
||||
}
|
||||
while (*t).tm_hour < 0 {
|
||||
(*t).tm_hour += 24;
|
||||
}
|
||||
|
||||
// Jan 1th was a thursday, 4th of a zero-indexed week.
|
||||
(*t).tm_wday = (day + 4) % 7;
|
||||
if (*t).tm_wday < 0 {
|
||||
(*t).tm_wday += 7;
|
||||
}
|
||||
|
||||
let mut year = 1970;
|
||||
if day < 0 {
|
||||
while day < 0 {
|
||||
let days_in_year = if leap_year(year) { 366 } else { 365 };
|
||||
|
||||
day += days_in_year;
|
||||
year -= 1;
|
||||
}
|
||||
(*t).tm_year = year - 1900;
|
||||
(*t).tm_yday = day + 1;
|
||||
} else {
|
||||
loop {
|
||||
let days_in_year = if leap_year(year) { 366 } else { 365 };
|
||||
|
||||
if day < days_in_year {
|
||||
break;
|
||||
}
|
||||
|
||||
day -= days_in_year;
|
||||
year += 1;
|
||||
}
|
||||
(*t).tm_year = year - 1900;
|
||||
(*t).tm_yday = day;
|
||||
}
|
||||
|
||||
let leap = if leap_year(year) { 1 } else { 0 };
|
||||
(*t).tm_mon = 0;
|
||||
loop {
|
||||
let days_in_month = MONTH_DAYS[leap][(*t).tm_mon as usize];
|
||||
|
||||
if day < days_in_month {
|
||||
break;
|
||||
}
|
||||
|
||||
day -= days_in_month;
|
||||
(*t).tm_mon += 1;
|
||||
}
|
||||
(*t).tm_mday = 1 + day as c_int;
|
||||
(*t).tm_isdst = 0;
|
||||
|
||||
t
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t {
|
||||
let mut year = (*t).tm_year + 1900;
|
||||
let mut month = (*t).tm_mon;
|
||||
let mut day = (*t).tm_mday as i64 - 1;
|
||||
|
||||
let leap = if leap_year(year) { 1 } else { 0 };
|
||||
|
||||
if year < 1970 {
|
||||
day = MONTH_DAYS[if leap_year(year) { 1 } else { 0 }][(*t).tm_mon as usize] as i64 - day;
|
||||
|
||||
while year < 1969 {
|
||||
year += 1;
|
||||
day += if leap_year(year) { 366 } else { 365 };
|
||||
}
|
||||
|
||||
while month < 11 {
|
||||
month += 1;
|
||||
day += MONTH_DAYS[leap][month as usize] as i64;
|
||||
}
|
||||
|
||||
-(day * (60 * 60 * 24)
|
||||
- (((*t).tm_hour as i64) * (60 * 60) + ((*t).tm_min as i64) * 60 + (*t).tm_sec as i64))
|
||||
} else {
|
||||
while year > 1970 {
|
||||
year -= 1;
|
||||
day += if leap_year(year) { 366 } else { 365 };
|
||||
}
|
||||
|
||||
while month > 0 {
|
||||
month -= 1;
|
||||
day += MONTH_DAYS[leap][month as usize] as i64;
|
||||
}
|
||||
|
||||
(day * (60 * 60 * 24)
|
||||
+ ((*t).tm_hour as i64) * (60 * 60)
|
||||
+ ((*t).tm_min as i64) * 60
|
||||
+ (*t).tm_sec as i64)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int {
|
||||
Sys::nanosleep(
|
||||
rqtp as *const platform::types::timespec,
|
||||
rmtp as *mut platform::types::timespec,
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strftime(
|
||||
s: *mut c_char,
|
||||
maxsize: size_t,
|
||||
format: *const c_char,
|
||||
timeptr: *const tm,
|
||||
) -> size_t {
|
||||
let ret = strftime::strftime(
|
||||
&mut platform::StringWriter(s as *mut u8, maxsize),
|
||||
format,
|
||||
timeptr,
|
||||
);
|
||||
if ret < maxsize {
|
||||
return ret;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn strptime(buf: *const c_char, format: *const c_char, tm: *mut tm) -> *mut c_char {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn time(tloc: *mut time_t) -> time_t {
|
||||
let mut ts: platform::types::timespec = Default::default();
|
||||
Sys::clock_gettime(CLOCK_REALTIME, &mut ts);
|
||||
unsafe {
|
||||
if !tloc.is_null() {
|
||||
*tloc = ts.tv_sec
|
||||
};
|
||||
}
|
||||
ts.tv_sec
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn timer_create(
|
||||
clock_id: clockid_t,
|
||||
evp: *mut sigevent,
|
||||
timerid: *mut timer_t,
|
||||
) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn timer_delete(timerid: timer_t) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn tzset() {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn timer_settime(
|
||||
timerid: timer_t,
|
||||
flags: c_int,
|
||||
value: *const itimerspec,
|
||||
ovalue: *mut itimerspec,
|
||||
) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn timer_getoverrun(timerid: timer_t) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/*
|
||||
#[no_mangle]
|
||||
pub extern "C" fn func(args) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,4 @@
|
||||
use platform::types::*;
|
||||
|
||||
pub const CLOCK_REALTIME: c_int = 1;
|
||||
pub const CLOCK_MONOTONIC: c_int = 4;
|
||||
@@ -0,0 +1,144 @@
|
||||
use alloc::string::String;
|
||||
use platform::types::*;
|
||||
use platform::{self, Write};
|
||||
use tm;
|
||||
|
||||
pub unsafe fn strftime<W: Write>(
|
||||
w: &mut W,
|
||||
format: *const c_char,
|
||||
t: *const tm,
|
||||
) -> size_t {
|
||||
pub unsafe fn inner_strftime<W: Write>(
|
||||
mut w: &mut W,
|
||||
mut format: *const c_char,
|
||||
t: *const tm,
|
||||
) -> bool {
|
||||
macro_rules! w {
|
||||
(byte $b:expr) => {{
|
||||
if w.write_u8($b).is_err() {
|
||||
return false;
|
||||
}
|
||||
}};
|
||||
(char $chr:expr) => {{
|
||||
if w.write_char($chr).is_err() {
|
||||
return false;
|
||||
}
|
||||
}};
|
||||
(recurse $fmt:expr) => {{
|
||||
let mut fmt = String::with_capacity($fmt.len() + 1);
|
||||
fmt.push_str($fmt);
|
||||
fmt.push('\0');
|
||||
|
||||
if !inner_strftime(w, fmt.as_ptr() as *mut c_char, t) {
|
||||
return false;
|
||||
}
|
||||
}};
|
||||
($str:expr) => {{
|
||||
if w.write_str($str).is_err() {
|
||||
return false;
|
||||
}
|
||||
}};
|
||||
($fmt:expr, $($args:expr),+) => {{
|
||||
// Would use write!() if I could get the length written
|
||||
if write!(w, $fmt, $($args),+).is_err() {
|
||||
return false;
|
||||
}
|
||||
}};
|
||||
}
|
||||
const WDAYS: [&'static str; 7] = [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
];
|
||||
const MONTHS: [&'static str; 12] = [
|
||||
"January",
|
||||
"Febuary",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
while *format != 0 {
|
||||
if *format as u8 != b'%' {
|
||||
w!(byte *format as u8);
|
||||
format = format.offset(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
format = format.offset(1);
|
||||
|
||||
if *format as u8 == b'E' || *format as u8 == b'O' {
|
||||
// Ignore because these do nothing without locale
|
||||
format = format.offset(1);
|
||||
}
|
||||
|
||||
match *format as u8 {
|
||||
b'%' => w!(byte b'%'),
|
||||
b'n' => w!(byte b'\n'),
|
||||
b't' => w!(byte b'\t'),
|
||||
b'a' => w!(&WDAYS[(*t).tm_wday as usize][..3]),
|
||||
b'A' => w!(WDAYS[(*t).tm_wday as usize]),
|
||||
b'b' | b'h' => w!(&MONTHS[(*t).tm_mon as usize][..3]),
|
||||
b'B' => w!(MONTHS[(*t).tm_mon as usize]),
|
||||
b'C' => {
|
||||
let mut year = (*t).tm_year / 100;
|
||||
// Round up
|
||||
if (*t).tm_year % 100 != 0 {
|
||||
year += 1;
|
||||
}
|
||||
w!("{:02}", year + 19);
|
||||
}
|
||||
b'd' => w!("{:02}", (*t).tm_mday),
|
||||
b'D' => w!(recurse "%m/%d/%y"),
|
||||
b'e' => w!("{:2}", (*t).tm_mday),
|
||||
b'F' => w!(recurse "%Y-%m-%d"),
|
||||
b'H' => w!("{:02}", (*t).tm_hour),
|
||||
b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1),
|
||||
b'j' => w!("{:03}", (*t).tm_yday),
|
||||
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'p' => w!(if (*t).tm_hour < 12 { "AM" } else { "PM" }),
|
||||
b'P' => w!(if (*t).tm_hour < 12 { "am" } else { "pm" }),
|
||||
b'r' => w!(recurse "%I:%M:%S %p"),
|
||||
b'R' => w!(recurse "%H:%M"),
|
||||
// Nothing is modified in mktime, but the C standard of course requires a mutable pointer ._.
|
||||
b's' => w!("{}", ::mktime(t as *mut tm)),
|
||||
b'S' => w!("{:02}", (*t).tm_sec),
|
||||
b'T' => w!(recurse "%H:%M:%S"),
|
||||
b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1),
|
||||
b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7),
|
||||
b'w' => w!("{}", (*t).tm_wday),
|
||||
b'W' => w!("{}", ((*t).tm_yday + 7 - ((*t).tm_wday + 6) % 7) / 7),
|
||||
b'y' => w!("{:02}", (*t).tm_year % 100),
|
||||
b'Y' => w!("{}", (*t).tm_year + 1900),
|
||||
b'z' => w!("+0000"), // TODO
|
||||
b'Z' => w!("UTC"), // TODO
|
||||
b'+' => w!(recurse "%a %b %d %T %Z %Y"),
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
format = format.offset(1);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
let mut w = platform::CountingWriter::new(w);
|
||||
if !inner_strftime(&mut w, format, t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
w.written
|
||||
}
|
||||
Reference in New Issue
Block a user