From ff37adeeba9c8630a3936188a2372d11f7da546e Mon Sep 17 00:00:00 2001
From: Marat Safin <jeizsm@gmail.com>
Date: Thu, 19 Apr 2018 07:54:42 +0300
Subject: [PATCH] add asctime

Signed-off-by: Marat Safin <jeizsm@gmail.com>
---
 Cargo.lock                |  1 +
 src/time/Cargo.toml       |  1 +
 src/time/src/constants.rs |  5 +++++
 src/time/src/lib.rs       | 31 +++++++++++++++++++++++++++++--
 tests/.gitignore          |  1 +
 tests/Makefile            |  3 ++-
 tests/asctime.c           | 16 ++++++++++++++++
 7 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100644 tests/asctime.c

diff --git a/Cargo.lock b/Cargo.lock
index bb3c3a928..f7cb6db3f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -514,6 +514,7 @@ name = "time"
 version = "0.1.0"
 dependencies = [
  "cbindgen 0.5.2",
+ "errno 0.1.0",
  "platform 0.1.0",
 ]
 
diff --git a/src/time/Cargo.toml b/src/time/Cargo.toml
index fe104d90b..152135455 100644
--- a/src/time/Cargo.toml
+++ b/src/time/Cargo.toml
@@ -9,3 +9,4 @@ cbindgen = { path = "../../cbindgen" }
 
 [dependencies]
 platform = { path = "../platform" }
+errno = { path = "../errno" }
diff --git a/src/time/src/constants.rs b/src/time/src/constants.rs
index 609dc6eb2..a7c1aa0d3 100644
--- a/src/time/src/constants.rs
+++ b/src/time/src/constants.rs
@@ -37,3 +37,8 @@ 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"
+];
diff --git a/src/time/src/lib.rs b/src/time/src/lib.rs
index 10538eba2..cd338df10 100644
--- a/src/time/src/lib.rs
+++ b/src/time/src/lib.rs
@@ -3,6 +3,7 @@
 #![no_std]
 #![feature(const_fn)]
 
+extern crate errno;
 extern crate platform;
 
 pub mod constants;
@@ -11,6 +12,9 @@ mod helpers;
 use platform::types::*;
 use constants::*;
 use helpers::*;
+use core::fmt::write;
+use core::mem::transmute;
+use errno::EIO;
 
 /*
  *#[repr(C)]
@@ -52,6 +56,9 @@ static mut TM: tm = tm {
     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,
@@ -62,12 +69,32 @@ pub struct sigevent;
 
 #[no_mangle]
 pub extern "C" fn asctime(timeptr: *const tm) -> *mut c_char {
-    unimplemented!();
+    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 {
-    unimplemented!();
+    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]
diff --git a/tests/.gitignore b/tests/.gitignore
index 44269d3e9..2b0c542fe 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -50,3 +50,4 @@
 /write
 /time
 /gmtime
+/asctime
diff --git a/tests/Makefile b/tests/Makefile
index 63f40dff9..1f83dd139 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -44,7 +44,8 @@ EXPECT_BINS=\
 	waitpid \
 	write \
 	time \
-	gmtime
+	gmtime \
+	asctime
 
 # Binaries that may generate varied output
 BINS=\
diff --git a/tests/asctime.c b/tests/asctime.c
new file mode 100644
index 000000000..6462d44cc
--- /dev/null
+++ b/tests/asctime.c
@@ -0,0 +1,16 @@
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char** argv) {
+    time_t a = 0;
+    tm *time_info = gmtime(&a);
+
+    char *time_string = asctime(time_info);
+
+    if (time_string == NULL || strcmp(time_string, "Thu Jan  1 00:00:00 1970\n") != 0) {
+        exit(1);
+    }
+    return 0;
+}
-- 
GitLab