Usermode/libc - Add support for %H and %M in strftime
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / time.c
index 412475b..611ae9b 100644 (file)
@@ -8,12 +8,35 @@
 #include <time.h>
 #include <acess/sys.h>
 #include <string.h>
+#include "timeconv.h"
+#include <errno.h>
+#include <stdio.h>     // sprintf
+
+#define UNIX_TO_2K     ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
 
 clock_t clock(void)
 {
        return _SysTimestamp();
 }
 
+time_t mktime(struct tm *timeptr)
+{
+       time_t ret = seconds_since_y2k(
+               timeptr->tm_year - 2000,
+               timeptr->tm_mon,
+               timeptr->tm_mday,
+               timeptr->tm_hour,
+               timeptr->tm_min,
+               timeptr->tm_sec
+               );
+       if( ret == 0 && errno ) {
+               // Bad date
+       }
+       ret += UNIX_TO_2K;
+       
+       return ret;
+}
+
 time_t time(time_t *t)
 {
        time_t ret = _SysTimestamp() / 1000;
@@ -22,26 +45,79 @@ time_t time(time_t *t)
        return ret;
 }
 
+//! Convert the time structure into a string of form 'Sun Sep 16 01:03:52 1973\n\0'
+char *asctime(const struct tm *timeptr)
+{
+       static char staticbuf[sizeof("Sun Sep 16 01:03:52 1973\n")];
+       return asctime_r(timeptr, staticbuf);
+}
+char *asctime_r(const struct tm *timeptr, char *buf)
+{
+       const char *WDAYS[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
+       const char *MONS[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
+       sprintf(buf,
+               "%s %s %i %02i:%02i:%02i %4i\n",
+               WDAYS[timeptr->tm_wday],
+               MONS[timeptr->tm_mon],
+               timeptr->tm_mday,
+               timeptr->tm_hour,
+               timeptr->tm_min,
+               timeptr->tm_sec,
+               timeptr->tm_year
+               );
+       return buf;
+}
+
+//! asctime(localtime(timer))
+char *ctime(const time_t *timer)
+{
+       struct tm       time_buf;
+       localtime_r(timer, &time_buf);
+       return asctime(&time_buf);
+}
+extern char *ctime_r(const time_t *timer, char *buf)
+{
+       struct tm       time_buf;
+       localtime_r(timer, &time_buf);
+       return asctime_r(&time_buf, buf);
+}
+
+//! Convert \a timter into UTC
+struct tm *gmtime(const time_t *timer)
+{
+       // Ignore UTC
+       return localtime(timer);
+}
+struct tm *gmtime_r(const time_t *timer, struct tm *result)
+{
+       return localtime_r(timer, result);
+}
+
 static struct tm       static_tm;
 
 struct tm *localtime(const time_t *timer)
 {
-       struct tm *ret = &static_tm;
-
-       // TODO: This breaks on negative timestamps
+       return localtime_r(timer, &static_tm);
 
-       int64_t day = *timer / (1000*60*60*24);
-       int64_t iday = *timer % (1000*60*60*24);        
+}
+struct tm *localtime_r(const time_t *timer, struct tm *ret)
+{
+       // Hours, Mins, Seconds
+       int64_t days = get_days_since_y2k(*timer, &ret->tm_hour, &ret->tm_min, &ret->tm_sec);
+       
+       // Week day
+       ret->tm_wday = (days + 6) % 7;  // Sun = 0, 1 Jan 2000 was Sat (6)
+       
+       // Year and Day of Year
+       bool    is_ly;
+       ret->tm_year = 2000 + get_years_since_y2k(days, &is_ly, &ret->tm_yday);
 
-       ret->tm_sec = (iday / 1000) % 60;;
-       ret->tm_min = (iday / (1000*60)) % 60;
-       ret->tm_hour = (iday / (1000*60*60));
-       ret->tm_year = 0;
-       ret->tm_mon = 0;
-       ret->tm_mday = 0;
-       ret->tm_wday = (day + 6) % 7;   // 1 Jan 2000 was a saturday
-       ret->tm_yday = 0;
+       // Month and Day of Month
+       get_month_day(ret->tm_yday, is_ly, &ret->tm_mon, &ret->tm_mday);
+       ret->tm_mon --;
+       
        ret->tm_isdst = 0;      // Fuck DST
+       
        return ret;
 }
 
@@ -69,11 +145,18 @@ size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, con
                if( *format == 0 )
                        break;
                format ++;
+               
+               // If EOS is hit on a '%', break early
+               if( *format == 0 )
+                       break;
                switch(*format++)
                {
-               case 0: format--;       break;
-               case '%':       ofs += _puts(s, maxsize, ofs, format-1, 1);     break;
-               case 'd':       // The day of the month as a decimal number (range 01 to 31).
+               // Literal '%', 
+               case '%':
+                       ofs += _puts(s, maxsize, ofs, format-1, 1);
+                       break;
+               // The day of the month as a decimal number (range 01 to 31).
+               case 'd':
                        {
                        char tmp[2] = {'0','0'};
                        tmp[0] += (timeptr->tm_mday / 10) % 10;
@@ -81,6 +164,24 @@ size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, con
                        ofs += _puts(s, maxsize, ofs, tmp, 2);
                        }
                        break;
+               // Two-digit 24 hour
+               case 'H':
+                       {
+                       char tmp[2] = {'0','0'};
+                       tmp[0] += (timeptr->tm_hour / 10) % 10;
+                       tmp[1] +=  timeptr->tm_hour % 10;
+                       ofs += _puts(s, maxsize, ofs, tmp, 2);
+                       }
+                       break;
+               // Two-digit minutes
+               case 'M':
+                       {
+                       char tmp[2] = {'0','0'};
+                       tmp[0] += (timeptr->tm_min / 10) % 10;
+                       tmp[1] +=  timeptr->tm_min % 10;
+                       ofs += _puts(s, maxsize, ofs, tmp, 2);
+                       }
+                       break;
                default:
                        _SysDebug("TODO: strftime('...%%%c...')", format[-1]);
                        break;

UCC git Repository :: git.ucc.asn.au