mirror of
https://git.planet-casio.com/Vhex-Kernel-Core/fxlibc.git
synced 2024-12-28 04:23:38 +01:00
time: add support for C99 <time.h> (DONE)
This commit is contained in:
parent
e71f9867e2
commit
92ccd8b1db
13 changed files with 365 additions and 25 deletions
|
@ -192,7 +192,15 @@ set(SOURCES
|
|||
src/libc/string/strstr.c
|
||||
src/libc/string/strstr_base.c
|
||||
src/libc/string/strtok.c
|
||||
src/libc/string/strxfrm.c)
|
||||
src/libc/string/strxfrm.c
|
||||
# time
|
||||
src/libc/time/asctime.c
|
||||
src/libc/time/ctime.c
|
||||
src/libc/time/difftime.c
|
||||
src/libc/time/gmtime.c
|
||||
src/libc/time/localtime.c
|
||||
src/libc/time/mktime.c
|
||||
src/libc/time/strftime.c)
|
||||
|
||||
# Silence extended warnings on Grisu2b code
|
||||
set_source_files_properties(3rdparty/grisu2b_59_56/grisu2b_59_56.c PROPERTIES
|
||||
|
@ -239,9 +247,13 @@ endif()
|
|||
|
||||
if(gint IN_LIST TARGET_FOLDERS)
|
||||
list(APPEND SOURCES
|
||||
# stdlib
|
||||
src/libc/stdlib/target/gint/free.c
|
||||
src/libc/stdlib/target/gint/malloc.c
|
||||
src/libc/stdlib/target/gint/realloc.c)
|
||||
src/libc/stdlib/target/gint/realloc.c
|
||||
# time
|
||||
src/libc/time/target/gint/clock.c
|
||||
src/libc/time/target/gint/time.c)
|
||||
endif()
|
||||
|
||||
if(casiowin-fx IN_LIST TARGET_FOLDERS)
|
||||
|
|
26
STATUS
26
STATUS
|
@ -157,16 +157,16 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
|
|||
7.22 <tgmath.h> => GCC
|
||||
|
||||
7.23 <time.h>
|
||||
! 7.23.1 Components of time: TODO
|
||||
! 7.23.2.1 clock: TODO
|
||||
! 7.23.2.2 difftime: TODO
|
||||
! 7.23.2.3 mktime: TODO
|
||||
! 7.23.2.4 time: TODO
|
||||
! 7.23.3.1 asctime: TODO
|
||||
! 7.23.3.2 ctime: TODO
|
||||
! 7.23.3.3 gmtime: TODO
|
||||
! 7.23.3.4 localtime: TODO
|
||||
! 7.23.3.5 strftime: TODO
|
||||
7.23.1 Components of time: DONE
|
||||
7.23.2.1 clock: DONE
|
||||
7.23.2.2 difftime: DONE
|
||||
7.23.2.3 mktime: DONE (DST flag ignored)
|
||||
7.23.2.4 time: DONE
|
||||
7.23.3.1 asctime: DONE
|
||||
7.23.3.2 ctime: DONE
|
||||
7.23.3.3 gmtime: DONE
|
||||
7.23.3.4 localtime: DONE (No timezones; same as gmtime)
|
||||
7.23.3.5 strftime: DONE (No %g/%G/%U/%V/%W; timezones %z/%Z empty)
|
||||
|
||||
7.24 <wchar.h>
|
||||
TODO (not a priority)
|
||||
|
@ -184,6 +184,7 @@ What if we wanted to support more locales?
|
|||
-> Fix the "TODO: locale: ..." messages wherever assumptions on the locale are
|
||||
made in the code
|
||||
-> Properly implement strcoll() and strxfrm()
|
||||
-> Add support in strftime()
|
||||
|
||||
# Supporting text and binary files (newline translation)
|
||||
|
||||
|
@ -195,3 +196,8 @@ This requires all the wide-char functions but also updating fpos_t to be a
|
|||
structure with at least some mbstate_t member (7.19.2§6).
|
||||
|
||||
I really don't want to do that. Use multi-byte functions with UTF-8.
|
||||
|
||||
# Supporting timezones
|
||||
|
||||
-> Update localtime()
|
||||
-> Add some timezone API
|
||||
|
|
|
@ -5,28 +5,65 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Number of ticks per second in a clock_t value. */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Number of ticks per second in a clock_t value. This is not necessarily the
|
||||
full precision (eg. the RTC has only 128 units per second). */
|
||||
#define CLOCKS_PER_SEC 1000000
|
||||
|
||||
/* Type used to represent process CPU time; unit is CLOCKS_PER_SEC. */
|
||||
/* Represent process CPU time; unit is CLOCKS_PER_SEC. */
|
||||
typedef uint64_t clock_t;
|
||||
|
||||
/* Type used to represent a number of seconds since Epoch. */
|
||||
typedef uint64_t time_t;
|
||||
/* Represent a number of seconds since 1970-01-01 00:00:00 +0000 (UTC). */
|
||||
typedef int64_t time_t;
|
||||
|
||||
/* Broken-down time. */
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
int tm_sec; /* Seconds (0..60) */
|
||||
int tm_min; /* Minutes (0..59) */
|
||||
int tm_hour; /* Hours (0..23) */
|
||||
int tm_mday; /* Day of month (1..31) */
|
||||
int tm_mon; /* Month (0..11) */
|
||||
int tm_year; /* Years since 1900 */
|
||||
int tm_wday; /* Day of week, starting Sunday (0..6) */
|
||||
int tm_yday; /* Day of year (0..365) */
|
||||
int tm_isdst; /* Daylight Saving Time flag */
|
||||
};
|
||||
|
||||
/* Returns CPU time used by the program (in number of CLOCKS_PER_SEC). */
|
||||
extern clock_t clock(void);
|
||||
|
||||
/* Time elapsed between __start and __end, in seconds. */
|
||||
double difftime(time_t __end, time_t __start);
|
||||
|
||||
/* Normalizes __time and returns associated timestamp.
|
||||
TODO: Currently ignores the [tm_isdst] field. */
|
||||
extern time_t mktime(struct tm *__time);
|
||||
|
||||
/* Determine current timestamp; also set it in __timeptr if non-NULL. */
|
||||
extern time_t time(time_t *__timeptr);
|
||||
|
||||
/* Text representation, like "Sun Sep 16 01:03:52 1973\n". The returned string
|
||||
is statically allocated and is overwritten by every call. */
|
||||
extern char *asctime(const struct tm *__time);
|
||||
|
||||
/* Convert calendar time to asctime()'s text representation. */
|
||||
extern char *ctime(const time_t *__time);
|
||||
|
||||
/* Convert calendar time to broken-down time as UTC. */
|
||||
extern struct tm *gmtime(const time_t *__time);
|
||||
|
||||
/* Convert calendar time to broken-down local time.
|
||||
TODO: We don't have timezones so this always returns UTC. */
|
||||
extern struct tm *localtime(const time_t *time);
|
||||
|
||||
/* Formats __time according to the specified format; similar to snprintf().
|
||||
TODO: %g, %G, %V (week-based year), and %U, %W (week number) are not
|
||||
supported and substituted by "??". %z and %Z output nothing. */
|
||||
size_t strftime(char * restrict __s, size_t __maxsize,
|
||||
const char * restrict __format, const struct tm * restrict __time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
21
src/libc/time/asctime.c
Normal file
21
src/libc/time/asctime.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const char wday_name[8][3] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???"
|
||||
};
|
||||
static const char mon_name[13][3] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???"
|
||||
};
|
||||
|
||||
char *asctime(const struct tm *time)
|
||||
{
|
||||
int wday = ((unsigned int)time->tm_wday < 7) ? time->tm_wday : 7;
|
||||
int mon = ((unsigned int)time->tm_mon < 12) ? time->tm_mon : 12;
|
||||
static char str[26];
|
||||
sprintf(str, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
||||
wday_name[wday], mon_name[mon], time->tm_mday, time->tm_hour,
|
||||
time->tm_min, time->tm_sec, time->tm_year + 1900);
|
||||
return str;
|
||||
}
|
6
src/libc/time/ctime.c
Normal file
6
src/libc/time/ctime.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <time.h>
|
||||
|
||||
char *ctime(const time_t *time)
|
||||
{
|
||||
return asctime(localtime(time));
|
||||
}
|
6
src/libc/time/difftime.c
Normal file
6
src/libc/time/difftime.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <time.h>
|
||||
|
||||
double difftime(time_t t1, time_t t0)
|
||||
{
|
||||
return (double)(t1 - t0);
|
||||
}
|
20
src/libc/time/gmtime.c
Normal file
20
src/libc/time/gmtime.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <time.h>
|
||||
#include "timeutil.h"
|
||||
|
||||
struct tm *gmtime(const time_t *timeptr)
|
||||
{
|
||||
static struct tm t;
|
||||
|
||||
/* Specify Epoch + *timeptr seconds */
|
||||
t.tm_year = 1970 - 1900;
|
||||
t.tm_mon = 0;
|
||||
t.tm_mday = 1;
|
||||
t.tm_hour = 0;
|
||||
t.tm_min = 0;
|
||||
t.tm_sec = *timeptr;
|
||||
t.tm_isdst = 0;
|
||||
|
||||
/* Then let mktime() do all the hard work */
|
||||
mktime(&t);
|
||||
return &t;
|
||||
}
|
7
src/libc/time/localtime.c
Normal file
7
src/libc/time/localtime.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <time.h>
|
||||
|
||||
/* TODO: localtime: No timezone specification is supported */
|
||||
struct tm *localtime(const time_t *time)
|
||||
{
|
||||
return gmtime(time);
|
||||
}
|
58
src/libc/time/mktime.c
Normal file
58
src/libc/time/mktime.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <time.h>
|
||||
#include "timeutil.h"
|
||||
|
||||
/* TODO: mktime: DST not supported */
|
||||
time_t mktime(struct tm *time)
|
||||
{
|
||||
/* Normalize time */
|
||||
time->tm_min += (time->tm_sec / 60);
|
||||
time->tm_hour += (time->tm_min / 60);
|
||||
time->tm_mday += (time->tm_hour / 24);
|
||||
time->tm_sec %= 60;
|
||||
time->tm_min %= 60;
|
||||
time->tm_hour %= 24;
|
||||
|
||||
/* Normalize date */
|
||||
int days = daysin(time->tm_mon, time->tm_year + 1900);
|
||||
while(time->tm_mday > days) {
|
||||
time->tm_mday -= days;
|
||||
if(++time->tm_mon == 12) {
|
||||
time->tm_mon = 0;
|
||||
time->tm_year++;
|
||||
}
|
||||
days = daysin(time->tm_mon, time->tm_year + 1900);
|
||||
}
|
||||
|
||||
/* Determine day in year */
|
||||
time->tm_yday = time->tm_mday - 1;
|
||||
for(int i = 0; i < time->tm_mon; i++)
|
||||
time->tm_yday += daysin(i, time->tm_year + 1900);
|
||||
|
||||
/* Determine day in week. The calendar has a period of 400 years and
|
||||
1601-01-01 was a Monday. */
|
||||
|
||||
/* Years elapsed since last 400n+1 year (1601-2001-etc). */
|
||||
int yr = (time->tm_year + 1900 - 1) % 400;
|
||||
/* Leap years during this period */
|
||||
int leaps = (yr / 4) - (yr >= 100) - (yr >= 200) - (yr >= 300);
|
||||
/* Days elapsed since 01-01 on the last 400n+1 year */
|
||||
days = 365 * yr + leaps + time->tm_yday;
|
||||
/* Current day of week (1 is Monday on 01-01 of last 400n+1 year) */
|
||||
time->tm_wday = (1 + days) % 7;
|
||||
|
||||
/* We don't determine DST at the targeted time */
|
||||
time->tm_isdst = 0;
|
||||
|
||||
/* Number of periods elapsed since 1601-01-01 (may be negative) */
|
||||
int periods = (time->tm_year + 1900 - 1601) / 400;
|
||||
periods -= (time->tm_year + 1900 < 1601);
|
||||
/* Days elapsed since 1970-01-01; the calendar period is 146097 days
|
||||
and there are 134774 days between 1601-01-01 and 1970-01-01 */
|
||||
days += 146097 * periods - 134774;
|
||||
|
||||
time_t t = days;
|
||||
t = 24 * t + time->tm_hour;
|
||||
t = 60 * t + time->tm_min;
|
||||
t = 60 * t + time->tm_sec;
|
||||
return t;
|
||||
}
|
94
src/libc/time/strftime.c
Normal file
94
src/libc/time/strftime.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *day_names[7] = {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
|
||||
"Saturday",
|
||||
};
|
||||
static const char *month_names[12] = {
|
||||
"January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December",
|
||||
};
|
||||
|
||||
/* Perform a call to snprintf() to print a value */
|
||||
#define do_snprintf(...) { \
|
||||
size_t _written = snprintf(s+len, n-len, __VA_ARGS__); \
|
||||
len += _written; \
|
||||
if(len >= n) goto full; \
|
||||
}; break
|
||||
/* Perform a sub-call to strftime to expand a complex format */
|
||||
#define do_strftime(fmt) { \
|
||||
size_t _written = strftime2(s+len, n-len, fmt, time); \
|
||||
if(_written == 0) goto full; \
|
||||
len += _written; \
|
||||
}; break
|
||||
|
||||
size_t strftime2(char * restrict s, size_t n, const char * restrict format,
|
||||
const struct tm * restrict time)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
while(*format) {
|
||||
if(*format != '%') {
|
||||
s[len++] = *format++;
|
||||
if(len >= n) goto full;
|
||||
continue;
|
||||
}
|
||||
format++;
|
||||
int c = *format++;
|
||||
|
||||
/* In the "C" locale, ignore modifiers E and O */
|
||||
if(c == 'E') c = *format++;
|
||||
else if(c == 'O') c = *format++;
|
||||
|
||||
switch(c) {
|
||||
case 'a': do_snprintf("%.3s", day_names[time->tm_wday]);
|
||||
case 'A': do_snprintf("%s", day_names[time->tm_wday]);
|
||||
case 'b': do_snprintf("%.3s", month_names[time->tm_mon]);
|
||||
case 'B': do_snprintf("%s", month_names[time->tm_mon]);
|
||||
case 'c': do_strftime("%a %b %e %T %Y");
|
||||
case 'C': do_snprintf("%02d", (time->tm_year + 1900) / 100);
|
||||
case 'd': do_snprintf("%02d", time->tm_mday);
|
||||
case 'D': do_strftime("%m/%d/%y");
|
||||
case 'e': do_snprintf("%2d", time->tm_mday);
|
||||
case 'F': do_strftime("%Y-%m-%d");
|
||||
/* TODO: strftime: Support week-based year */
|
||||
case 'g': do_snprintf("??");
|
||||
case 'G': do_snprintf("????");
|
||||
case 'h': do_strftime("%b");
|
||||
case 'H': do_snprintf("%02d", time->tm_hour);
|
||||
case 'I': do_snprintf("%02d", (time->tm_hour+11)%12 + 1);
|
||||
case 'j': do_snprintf("%03d", time->tm_yday + 1);
|
||||
case 'm': do_snprintf("%02d", time->tm_mon + 1);
|
||||
case 'M': do_snprintf("%02d", time->tm_min);
|
||||
case 'n': do_snprintf("\n");
|
||||
case 'p': do_snprintf(time->tm_hour < 12 ? "AM" : "PM");
|
||||
case 'r': do_strftime("%I:%M:%S %p");
|
||||
case 'R': do_strftime("%H:%M");
|
||||
case 'S': do_snprintf("%02d", time->tm_sec);
|
||||
case 't': do_snprintf("\t");
|
||||
case 'T': do_strftime("%H:%M:%S");
|
||||
case 'u': do_snprintf("%d", (time->tm_wday+6) % 7 + 1);
|
||||
/* TODO: strftime: Support week number */
|
||||
case 'U': do_snprintf("??");
|
||||
case 'V': do_snprintf("??");
|
||||
case 'w': do_snprintf("%d", time->tm_wday);
|
||||
case 'W': do_snprintf("??");
|
||||
case 'x': do_strftime("%m/%d/%y");
|
||||
case 'X': do_strftime("%T");
|
||||
case 'y': do_snprintf("%02d", time->tm_year % 100);
|
||||
case 'Y': do_snprintf("%d", time->tm_year + 1900);
|
||||
/* TODO: strftime: Support timezones */
|
||||
case 'z': break;
|
||||
case 'Z': break;
|
||||
case '%': do_snprintf("%%");
|
||||
}
|
||||
}
|
||||
|
||||
s[len] = 0;
|
||||
return len;
|
||||
|
||||
full:
|
||||
s[n-1] = 0;
|
||||
return 0;
|
||||
}
|
20
src/libc/time/target/gint/clock.c
Normal file
20
src/libc/time/target/gint/clock.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <time.h>
|
||||
#include <gint/rtc.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
|
||||
static clock_t clock_init;
|
||||
|
||||
static clock_t clock_abs(void)
|
||||
{
|
||||
return (CLOCKS_PER_SEC * (uint64_t)rtc_ticks()) / 128;
|
||||
}
|
||||
|
||||
GCONSTRUCTOR static void clock_initialize(void)
|
||||
{
|
||||
clock_init = clock_abs();
|
||||
}
|
||||
|
||||
clock_t clock(void)
|
||||
{
|
||||
return clock_abs() - clock_init;
|
||||
}
|
23
src/libc/time/target/gint/time.c
Normal file
23
src/libc/time/target/gint/time.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <time.h>
|
||||
#include <gint/rtc.h>
|
||||
|
||||
time_t time(time_t *timeptr)
|
||||
{
|
||||
rtc_time_t rtc;
|
||||
struct tm tm;
|
||||
time_t calendar;
|
||||
|
||||
rtc_get_time(&rtc);
|
||||
tm.tm_sec = rtc.seconds;
|
||||
tm.tm_min = rtc.minutes;
|
||||
tm.tm_hour = rtc.hours;
|
||||
tm.tm_mday = rtc.month_day;
|
||||
tm.tm_mon = rtc.month;
|
||||
tm.tm_year = rtc.year - 1900;
|
||||
tm.tm_isdst = 0;
|
||||
|
||||
calendar = mktime(&tm);
|
||||
if(timeptr != NULL)
|
||||
*timeptr = calendar;
|
||||
return calendar;
|
||||
}
|
30
src/libc/time/timeutil.h
Normal file
30
src/libc/time/timeutil.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef __TIMEUTIL_H__
|
||||
# define __TIMEUTIL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Check whether a given year is a leap year. */
|
||||
static inline bool isleap(int yr)
|
||||
{
|
||||
if(!(yr % 400)) return true;
|
||||
if(!(yr % 100)) return false;
|
||||
return !(yr & 3);
|
||||
}
|
||||
|
||||
/* Number of days for the given month (0..11) and year. */
|
||||
static inline int daysin(int month, int yr)
|
||||
{
|
||||
static char count[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
return count[month] + (month == 1 && isleap(yr));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__TIMEUTIL_H__*/
|
Loading…
Reference in a new issue