From a9ea2ef64eb72c8af02bd55fd1a221b4bc0588b4 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 13 Jul 2018 09:13:46 +0200 Subject: [PATCH 1/3] Fixup time & support negative & mktime --- src/time/src/lib.rs | 188 +++++++++++++++++++++----------- tests/.gitignore | 2 + tests/Makefile | 2 + tests/expected/localtime.stderr | 0 tests/expected/localtime.stdout | 6 + tests/expected/mktime.stderr | 0 tests/expected/mktime.stdout | 6 + tests/localtime.c | 18 +++ tests/mktime.c | 22 ++++ 9 files changed, 183 insertions(+), 61 deletions(-) create mode 100644 tests/expected/localtime.stderr create mode 100644 tests/expected/localtime.stdout create mode 100644 tests/expected/mktime.stderr create mode 100644 tests/expected/mktime.stdout create mode 100644 tests/localtime.c create mode 100644 tests/mktime.c diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs index 43014c275e..878df02ce5 100644 --- a/src/time/src/lib.rs +++ b/src/time/src/lib.rs @@ -198,70 +198,136 @@ pub unsafe extern "C" fn localtime(clock: *const time_t) -> *mut tm { localtime_r(clock, &mut TM) } -#[no_mangle] -pub unsafe extern "C" fn localtime_r(clock: *const time_t, r: *mut tm) -> *mut tm { - fn leap_year(year: c_int) -> bool { - year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) - } - let mut clock = *clock; +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], +]; - if clock < 0 { - unimplemented!("localtime_r with a negative time is to be implemented"); - } - - let mut days = (clock / (60 * 60 * 24)) as c_int; - - // Epoch, Jan 1 1970, was on a thursday. - // Jan 5th was a monday. - (*r).tm_wday = (days + 4) % 7; - - (*r).tm_year = 1970; - - loop { - let days_in_year = if leap_year((*r).tm_year) { 366 } else { 365 }; - - if days < days_in_year { - break; - } - - days -= days_in_year; - (*r).tm_year += 1; - } - - (*r).tm_yday = days; - - (*r).tm_sec = (clock % 60) as c_int; - (*r).tm_min = ((clock % (60 * 60)) / 60) as c_int; - (*r).tm_hour = (clock / (60 * 60)) as c_int; - - 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], - ]; - - let leap = if leap_year((*r).tm_year) { 1 } else { 0 }; - - loop { - let days_in_month = MONTH_DAYS[leap][(*r).tm_mon as usize]; - - if days < (*r).tm_mon { - break; - } - - days -= days_in_month; - (*r).tm_mon += 1; - } - (*r).tm_mday = days as c_int; - (*r).tm_isdst = 0; - - r +fn leap_year(year: c_int) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) } -// #[no_mangle] -pub extern "C" fn mktime(timeptr: *mut tm) -> time_t { - unimplemented!(); +#[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; + + 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 }; + } + + let leap = if leap_year(year) { 1 } else { 0 }; + + 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 { + day += if leap_year(year) { 366 } else { 365 }; + year -= 1; + } + + let leap = if leap_year(year) { 1 } else { 0 }; + + while month > 0 { + day += MONTH_DAYS[leap][month as usize] as i64; + month -= 1; + } + + (day * (60 * 60 * 24) + + ((*t).tm_hour as i64) * (60 * 60) + + ((*t).tm_min as i64) * 60 + + (*t).tm_sec as i64) + } } #[no_mangle] diff --git a/tests/.gitignore b/tests/.gitignore index afb0d2f8cf..fb6577e978 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,8 +21,10 @@ /getid /link /locale +/localtime /math /mem +/mktime /pipe /printf /rmdir diff --git a/tests/Makefile b/tests/Makefile index 0957b27f2c..eec3cb7073 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -16,8 +16,10 @@ EXPECT_BINS=\ ftruncate \ getc_unget \ locale \ + localtime \ math \ mem \ + mktime \ pipe \ printf \ rename \ diff --git a/tests/expected/localtime.stderr b/tests/expected/localtime.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/localtime.stdout b/tests/expected/localtime.stdout new file mode 100644 index 0000000000..12a3072c69 --- /dev/null +++ b/tests/expected/localtime.stdout @@ -0,0 +1,6 @@ +Year 69, Day of year: 333, Month 10, Day of month: 29, Day of week: 6, 0:0:0 +Year 69, Day of year: 365, Month 11, Day of month: 31, Day of week: 3, 0:0:0 +Year 69, Day of year: 365, Month 11, Day of month: 31, Day of week: 3, 23:51:40 +Year 70, Day of year: 0, Month 0, Day of month: 1, Day of week: 4, 0:0:0 +Year 118, Day of year: 193, Month 6, Day of month: 13, Day of week: 5, 4:9:10 +Fri Jul 13 06:03:43 2018 diff --git a/tests/expected/mktime.stderr b/tests/expected/mktime.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/mktime.stdout b/tests/expected/mktime.stdout new file mode 100644 index 0000000000..c9b309e63c --- /dev/null +++ b/tests/expected/mktime.stdout @@ -0,0 +1,6 @@ +31536000 +-2851200 = -2851200 +-86400 = -86400 +-500 = -500 +0 = 0 +1531454950 = 1531454950 diff --git a/tests/localtime.c b/tests/localtime.c new file mode 100644 index 0000000000..edce6cf64e --- /dev/null +++ b/tests/localtime.c @@ -0,0 +1,18 @@ +#include +#include + +int main() { + int day = 60 * 60 * 24; + time_t inputs[] = { -(day * 33), -day, -500, 0, 1531454950 }; + for (int i = 0; i < 5; i += 1) { + struct tm* t = localtime(&inputs[i]); + + printf( + "Year %d, Day of year: %d, Month %d, Day of month: %d, Day of week: %d, %d:%d:%d\n", + t->tm_year, t->tm_yday, t->tm_mon, t->tm_mday, t->tm_wday, t->tm_hour, t->tm_min, t->tm_sec + ); + } + + time_t input = 1531461823; + fputs(ctime(&input), stdout); // Omit newline +} diff --git a/tests/mktime.c b/tests/mktime.c new file mode 100644 index 0000000000..17eb30b1ad --- /dev/null +++ b/tests/mktime.c @@ -0,0 +1,22 @@ +#include +#include + +int main() { + struct tm t = {}; + + t.tm_year = 71; + t.tm_mday = 1; + + printf("%ld\n", mktime(&t)); + + int day = 60 * 60 * 24; + time_t inputs[] = { -(day * 33), -day, -500, 0, 1531454950 }; + for (int i = 0; i < 5; i += 1) { + struct tm* t2 = localtime(&inputs[i]); + + printf("%ld = %ld\n", inputs[i], mktime(t2)); + if (inputs[i] != mktime(t2)) { + puts("Failed!"); + } + } +} From 5f098c89c378c221a9b16dbfe0549ab8b7650f27 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 13 Jul 2018 10:16:42 +0200 Subject: [PATCH 2/3] Add more tests for mktime and localtime --- src/time/src/lib.rs | 10 ++++------ tests/mktime.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs index 878df02ce5..a7a4118eb5 100644 --- a/src/time/src/lib.rs +++ b/src/time/src/lib.rs @@ -291,6 +291,8 @@ pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t { 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; @@ -299,8 +301,6 @@ pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t { day += if leap_year(year) { 366 } else { 365 }; } - let leap = if leap_year(year) { 1 } else { 0 }; - while month < 11 { month += 1; day += MONTH_DAYS[leap][month as usize] as i64; @@ -312,15 +312,13 @@ pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t { + (*t).tm_sec as i64)) } else { while year > 1970 { - day += if leap_year(year) { 366 } else { 365 }; year -= 1; + day += if leap_year(year) { 366 } else { 365 }; } - let leap = if leap_year(year) { 1 } else { 0 }; - while month > 0 { - day += MONTH_DAYS[leap][month as usize] as i64; month -= 1; + day += MONTH_DAYS[leap][month as usize] as i64; } (day * (60 * 60 * 24) diff --git a/tests/mktime.c b/tests/mktime.c index 17eb30b1ad..9b9d940693 100644 --- a/tests/mktime.c +++ b/tests/mktime.c @@ -1,6 +1,23 @@ +#include #include +#include #include +int check(time_t input) { + struct tm* t = localtime(&input); + + printf("%ld = %ld\n", input, mktime(t)); + + if (input != mktime(t)) { + printf( + "Year %d, Day of year: %d, Month %d, Day of month: %d, Day of week: %d, %d:%d:%d\n", + t->tm_year, t->tm_yday, t->tm_mon, t->tm_mday, t->tm_wday, t->tm_hour, t->tm_min, t->tm_sec + ); + puts("Failed!"); + return -1; + } + return 0; +} int main() { struct tm t = {}; @@ -12,11 +29,20 @@ int main() { int day = 60 * 60 * 24; time_t inputs[] = { -(day * 33), -day, -500, 0, 1531454950 }; for (int i = 0; i < 5; i += 1) { - struct tm* t2 = localtime(&inputs[i]); + if (check(inputs[i])) { + return -1; + } + } - printf("%ld = %ld\n", inputs[i], mktime(t2)); - if (inputs[i] != mktime(t2)) { - puts("Failed!"); + srand(time(NULL)); + + for (int i = 0; i < 10; i += 1) { + time_t input = (time_t) rand(); + struct tm* time = localtime(&input); + time_t output = mktime(time); + if (input != output) { + // asctime has newline + printf("Comparison %ld == %ld failed. Time: %s", input, output, asctime(time)); } } } From 9cb0881cc48a041149d8193c55046549242868d2 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 13 Jul 2018 15:01:13 +0200 Subject: [PATCH 3/3] Alias wbstowcs and wbtowc to their correct functions --- src/stdlib/src/lib.rs | 14 ++++++----- src/time/src/lib.rs | 4 +-- src/wchar/src/lib.rs | 57 +++++++++++++++++++++---------------------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index db92a87c04..4c09888261 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -352,14 +352,16 @@ pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int { result as i32 } -// #[no_mangle] -pub extern "C" fn mbstowcs(pwcs: *mut wchar_t, s: *const c_char, n: size_t) -> size_t { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn mbstowcs(pwcs: *mut wchar_t, mut s: *const c_char, n: size_t) -> size_t { + let mut state: mbstate_t = mbstate_t {}; + mbsrtowcs(pwcs, &mut s, n, &mut state) } -// #[no_mangle] -pub extern "C" fn mbtowc(pwc: *mut wchar_t, s: *const c_char, n: size_t) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn mbtowc(pwc: *mut wchar_t, s: *const c_char, n: size_t) -> c_int { + let mut state: mbstate_t = mbstate_t {}; + mbrtowc(pwc, s, n, &mut state) as c_int } #[no_mangle] diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs index a7a4118eb5..096bc599b5 100644 --- a/src/time/src/lib.rs +++ b/src/time/src/lib.rs @@ -307,9 +307,7 @@ pub unsafe extern "C" fn mktime(t: *mut tm) -> time_t { } -(day * (60 * 60 * 24) - - (((*t).tm_hour as i64) * (60 * 60) - + ((*t).tm_min as i64) * 60 - + (*t).tm_sec as i64)) + - (((*t).tm_hour as i64) * (60 * 60) + ((*t).tm_min as i64) * 60 + (*t).tm_sec as i64)) } else { while year > 1970 { year -= 1; diff --git a/src/wchar/src/lib.rs b/src/wchar/src/lib.rs index 91cae381c6..02c679cd27 100644 --- a/src/wchar/src/lib.rs +++ b/src/wchar/src/lib.rs @@ -10,7 +10,6 @@ extern crate time; extern crate va_list as vl; use core::ptr; -use core::usize; use platform::types::*; use stdio::*; use time::*; @@ -95,7 +94,7 @@ pub unsafe extern "C" fn mbsinit(ps: *const mbstate_t) -> c_int { } #[no_mangle] -pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut mbstate_t) -> usize { +pub unsafe extern "C" fn mbrlen(s: *const c_char, n: size_t, ps: *mut mbstate_t) -> size_t { static mut INTERNAL: mbstate_t = mbstate_t; mbrtowc(ptr::null_mut(), s, n, &mut INTERNAL) } @@ -105,9 +104,9 @@ pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut mbstate_t) pub unsafe extern "C" fn mbrtowc( pwc: *mut wchar_t, s: *const c_char, - n: usize, + n: size_t, ps: *mut mbstate_t, -) -> usize { +) -> size_t { static mut INTERNAL: mbstate_t = mbstate_t; if ps.is_null() { @@ -127,10 +126,10 @@ pub unsafe extern "C" fn mbrtowc( pub unsafe extern "C" fn mbsnrtowcs( dst_ptr: *mut wchar_t, src_ptr: *mut *const c_char, - src_len: usize, - dst_len: usize, + src_len: size_t, + dst_len: size_t, ps: *mut mbstate_t, -) -> usize { +) -> size_t { static mut INTERNAL: mbstate_t = mbstate_t; if ps.is_null() { @@ -191,10 +190,10 @@ pub unsafe extern "C" fn mbsnrtowcs( pub extern "C" fn mbsrtowcs( dst: *mut wchar_t, src: *mut *const c_char, - len: usize, + len: size_t, ps: *mut mbstate_t, -) -> usize { - unsafe { mbsnrtowcs(dst, src, usize::max_value(), len, ps) } +) -> size_t { + unsafe { mbsnrtowcs(dst, src, size_t::max_value(), len, ps) } } #[no_mangle] @@ -210,7 +209,7 @@ pub unsafe extern "C" fn putwchar(wc: wchar_t) -> wint_t { // #[no_mangle] pub extern "C" fn swprintf( s: *mut wchar_t, - n: usize, + n: size_t, format: *const wchar_t, mut ap: va_list, ) -> c_int { @@ -250,7 +249,7 @@ pub extern "C" fn vwprintf(format: *const wchar_t, arg: va_list) -> c_int { // #[no_mangle] pub extern "C" fn vswprintf( s: *mut wchar_t, - n: usize, + n: size_t, format: *const wchar_t, arg: va_list, ) -> c_int { @@ -259,7 +258,7 @@ pub extern "C" fn vswprintf( //widechar to multibyte #[no_mangle] -pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> usize { +pub extern "C" fn wcrtomb(s: *mut c_char, wc: wchar_t, ps: *mut mbstate_t) -> size_t { let mut buffer: [c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize]; let mut wc_cpy = wc; let mut s_cpy = s; @@ -298,17 +297,17 @@ pub extern "C" fn wcscpy(ws1: *mut wchar_t, ws2: *const wchar_t) -> *mut wchar_t } // #[no_mangle] -pub extern "C" fn wcscspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize { +pub extern "C" fn wcscspn(ws1: *const wchar_t, ws2: *const wchar_t) -> size_t { unimplemented!(); } // #[no_mangle] pub extern "C" fn wcsftime( wcs: *mut wchar_t, - maxsize: usize, + maxsize: size_t, format: *const wchar_t, timptr: *mut tm, -) -> usize { +) -> size_t { unimplemented!(); } @@ -318,17 +317,17 @@ pub extern "C" fn wcslen(ws: *const wchar_t) -> c_ulong { } // #[no_mangle] -pub extern "C" fn wcsncat(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> *mut wchar_t { +pub extern "C" fn wcsncat(ws1: *mut wchar_t, ws2: *const wchar_t, n: size_t) -> *mut wchar_t { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wcsncmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize) -> c_int { +pub extern "C" fn wcsncmp(ws1: *const wchar_t, ws2: *const wchar_t, n: size_t) -> c_int { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wcsncpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> *mut wchar_t { +pub extern "C" fn wcsncpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: size_t) -> *mut wchar_t { unimplemented!(); } @@ -346,14 +345,14 @@ pub extern "C" fn wcsrchr(ws1: *const wchar_t, ws2: wchar_t) -> *mut wchar_t { pub extern "C" fn wcsrtombs( dst: *mut c_char, src: *mut *const wchar_t, - len: usize, + len: size_t, ps: *mut mbstate_t, -) -> usize { +) -> size_t { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wcsspn(ws1: *const wchar_t, ws2: *const wchar_t) -> usize { +pub extern "C" fn wcsspn(ws1: *const wchar_t, ws2: *const wchar_t) -> size_t { unimplemented!(); } @@ -392,12 +391,12 @@ pub extern "C" fn wcswcs(ws1: *const wchar_t, ws2: *const wchar_t) -> *mut wchar } // #[no_mangle] -pub extern "C" fn wcswidth(pwcs: *const wchar_t, n: usize) -> c_int { +pub extern "C" fn wcswidth(pwcs: *const wchar_t, n: size_t) -> c_int { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wcsxfrm(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> usize { +pub extern "C" fn wcsxfrm(ws1: *mut wchar_t, ws2: *const wchar_t, n: size_t) -> size_t { unimplemented!(); } @@ -412,27 +411,27 @@ pub extern "C" fn wcwidth(wc: wchar_t) -> c_int { } // #[no_mangle] -pub extern "C" fn wmemchr(ws: *const wchar_t, wc: wchar_t, n: usize) -> *mut c_int { +pub extern "C" fn wmemchr(ws: *const wchar_t, wc: wchar_t, n: size_t) -> *mut c_int { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wmemcmp(ws1: *const wchar_t, ws2: *const wchar_t, n: usize) -> c_int { +pub extern "C" fn wmemcmp(ws1: *const wchar_t, ws2: *const wchar_t, n: size_t) -> c_int { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wmemcpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> *mut wchar_t { +pub extern "C" fn wmemcpy(ws1: *mut wchar_t, ws2: *const wchar_t, n: size_t) -> *mut wchar_t { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: usize) -> *mut wchar_t { +pub extern "C" fn wmemmove(ws1: *mut wchar_t, ws2: *const wchar_t, n: size_t) -> *mut wchar_t { unimplemented!(); } // #[no_mangle] -pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: usize) -> *mut wchar_t { +pub extern "C" fn wmemset(ws1: *mut wchar_t, ws2: wchar_t, n: size_t) -> *mut wchar_t { unimplemented!(); }