\r
OBJ = stub.o heap.o stdlib.o env.o stdio.o string.o rand.o\r
OBJ += scanf.o signals.o strtoi.o strtof.o\r
-OBJ += printf.o time.o errno.o\r
+OBJ += printf.o time.o timeconv.o errno.o ctype.o\r
OBJ += arch/$(ARCHDIR).ao\r
# signals.o\r
DEPFILES := $(OBJ:%.o=%.d)\r
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * ctype.c
+ * - Character Types
+ */
+#include <ctype.h>
+
+int isalpha(int ch)
+{
+ if('A'<=ch&&ch<='Z') return 1;
+ if('a'<=ch&&ch<='z') return 1;
+ return 0;
+}
+int isdigit(int ch) {
+ if('0'<=ch&&ch<='9') return 1;
+ return 0;
+}
+
+int isalnum(int ch) {
+ return isalpha(ch) || isdigit(ch);
+}
+
+int toupper(int ch) {
+ if('a'<=ch && ch <='z')
+ return ch - 'a' + 'A';
+ return ch;
+}
+int tolower(int ch) {
+ if('A'<=ch && ch <='Z')
+ return ch - 'A' + 'a';
+ return ch;
+}
+
+int isprint(int ch ) {
+ if( ch < ' ' ) return 0;
+ if( ch > 'z' ) return 0;
+ return 1;
+}
+
+int isspace(int ch) {
+ if(ch == ' ') return 1;
+ if(ch == '\t') return 1;
+ if(ch == '\r') return 1;
+ if(ch == '\n') return 1;
+ return 0;
+}
+
+int isxdigit(int ch) {
+ if('0'<=ch&&ch<='9') return 1;
+ if('a'<=ch&&ch<='f') return 1;
+ if('F'<=ch&&ch<='F') return 1;
+ return 0;
+}
+
+// C99
+int isblank(int ch) {
+ if(ch == ' ') return 1;
+ if(ch == '\t') return 1;
+ return 0;
+}
+
case EPERM: return "Operation not permitted";
case ENOTTY: return "Not a TTY";
case EAGAIN: return "Try again";
+ case EFBIG: return "File too big";
case EALREADY: return "Operation was no-op";
case EAFNOSUPPORT: return "Address family not supported";
case EINTERNAL: return "Internal error";
#ifndef _LIBC__ASSERT_H_
#define _LIBC__ASSERT_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdlib.h>
//#include <stdio.h>
#include <acess/sys.h>
# define assert(expr) do{if(!(expr)) { _SysDebug("%s:%i: Assertion '%s' failed", __FILE__, __LINE__, #expr); exit(-1);}}while(0)
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif
#ifndef _CTYPE_H_
#define _CTYPE_H_
-static inline int isalpha(int ch) {
- if('A'<=ch&&ch<='Z') return 1;
- if('a'<=ch&&ch<='z') return 1;
- return 0;
-}
-static inline int isdigit(int ch) {
- if('0'<=ch&&ch<='9') return 1;
- return 0;
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
-static inline int isalnum(int ch) {
- return isalpha(ch) || isdigit(ch);
-}
+extern int isalpha(int ch);
+extern int isdigit(int ch);
-static inline int toupper(int ch) {
- if('a'<=ch && ch <='z')
- return ch - 'a' + 'A';
- return ch;
-}
-static inline int tolower(int ch) {
- if('A'<=ch && ch <='Z')
- return ch - 'A' + 'a';
- return ch;
-}
+extern int isalnum(int ch);
-static inline int isspace(int ch) {
- if(ch == ' ') return 1;
- if(ch == '\t') return 1;
- if(ch == '\r') return 1;
- if(ch == '\n') return 1;
- return 0;
-}
+extern int toupper(int ch);
+extern int tolower(int ch);
-static inline int isxdigit(int ch) {
- if('0'<=ch&&ch<='9') return 1;
- if('a'<=ch&&ch<='f') return 1;
- if('F'<=ch&&ch<='F') return 1;
- return 0;
-}
+extern int isprint(int ch);
+
+extern int isspace(int ch);
+
+extern int isxdigit(int ch);
// C99
-static inline int isblank(int ch) {
- if(ch == ' ') return 1;
- if(ch == '\t') return 1;
- return 0;
+extern int isblank(int ch);
+
+#ifdef __cplusplus
}
+#endif
#endif
EAGAIN, // Try again
EALREADY, // Operation was a NOP
+
+ EFBIG, // File too large
// psockets
EAFNOSUPPORT,
#ifndef _LIBC_SETJMP_H_
#define _LIBC_SETJMP_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined(__i386__)
typedef void *jmp_buf[8];
#elif defined(__amd64__)
extern int setjmp(jmp_buf buf);
extern void longjmp(jmp_buf buf, int val);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#ifndef _SIGNAL_H_
#define _SIGNAL_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "signal_list.h"
typedef void (*sighandler_t)(int);
//! Atomic integer type
typedef volatile int sig_atomic_t;
-#define SIG_IGN ((void*)1)
-#define SIG_DFL ((void*)0)
-#define SIG_ERR ((void*)-1)
+#define SIG_IGN ((sighandler_t)1)
+#define SIG_DFL ((sighandler_t)0)
+#define SIG_ERR ((sighandler_t)-1)
extern sighandler_t signal(int signum, sighandler_t handler);
extern int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
+#if __cplusplus
+}
+#endif
+
#endif
#include <stdarg.h>
#include <stddef.h> // size_t
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* === Types === */
typedef struct sFILE FILE;
#define getchar acess_getchar
#define putchar acess_putchar
+#define rename acess_rename
+
#define fprintf acess_fprintf
#define vfprintf acess_vfprintf
extern FILE *fmemopen(void *buffer, size_t length, const char *mode);
extern FILE *open_memstream(char **bufferptr, size_t *lengthptr);
extern FILE *fdopen(int fd, const char *modes);
+extern FILE *tmpfile(void);
extern int fclose(FILE *fp);
extern void fflush(FILE *fp);
extern off_t ftell(FILE *fp);
+extern off_t ftello(FILE *fp);
extern int fseek(FILE *fp, long int amt, int whence);
+extern int fseeko(FILE *fp, off_t amt, int whence);
extern void clearerr(FILE *stream);
extern int feof(FILE *stream);
extern int ferror(FILE *stream);
extern int fprintf(FILE *fp, const char *format, ...);
extern int vfprintf(FILE *fp, const char *format, va_list args);
+extern int rename(const char *oldpath, const char *newpath);
+
// scanf
extern int scanf(const char *format, ...);
extern int fscanf(FILE *stream, const char *format, ...);
extern FILE *stdout;
extern FILE *stderr;
+#if __cplusplus
+}
+#endif
+
#endif
#include <stdarg.h>\r
#include <sys/types.h>\r
\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
#define EXIT_FAILURE 1\r
#define EXIT_SUCCESS 0\r
\r
# define labs acess_labs\r
# define llabs acess_llabs\r
\r
+# define mktemp acess_mktemp\r
+\r
# define getenv acess_getenv\r
# define putenv acess_putenv\r
\r
extern unsigned long long strtoull(const char *ptr, char **end, int base);\r
extern unsigned long strtoul(const char *ptr, char **end, int base);\r
extern int atoi(const char *ptr);\r
+extern long atol(const char *ptr);\r
+extern long long atoll(const char *ptr);\r
\r
extern double strtod(const char *ptr, char **end);\r
extern float strtof(const char *ptr, char **end);\r
extern long int labs(long int j);\r
extern long long int llabs(long long int j);\r
\r
+extern char *mktemp(char *__template);\r
+\r
/* --- Environment --- */\r
extern char *getenv(const char *name);\r
extern int putenv(char *string);\r
# define SEEK_END (-1)\r
#endif\r
\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#include <libposix_stdlib.h>\r
+\r
#endif\r
#include <stddef.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Strings */
extern size_t strlen(const char *string);
extern size_t strnlen(const char *string, size_t maxlen);
extern size_t strcspn(const char *haystack, const char *reject);
extern size_t strspn(const char *haystack, const char *accept);
+extern char *strtok(char *str, const char *delim);
+extern char *strtok_r(char *str, const char *delim, char **saveptr);
+
/* Memory */
extern void *memset(void *dest, int val, size_t count);
extern void *memcpy(void *dest, const void *src, size_t count);
extern int memcmp(const void *mem1, const void *mem2, size_t count);
extern void *memchr(const void *ptr, int value, size_t num);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#include <sys/types.h> // time_t
#include <stddef.h> // size_t
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct tm
{
int tm_sec; // 0-60
//
//! Convert the time structure into a string of form 'Sun Sep 16 01:03:52 1973\n\0'
extern char *asctime(const struct tm *timeptr);
+extern char *asctime_r(const struct tm *timeptr, char *buf);
//! asctime(localtime(timer))
extern char *ctime(const time_t *timer);
+extern char *ctime_r(const time_t *timer, struct tm *result);
//! Convert \a timter into UTC
extern struct tm *gmtime(const time_t *timer);
+extern struct tm *gmtime_r(const time_t *timer, struct tm *result);
extern struct tm *localtime(const time_t *timer);
+extern struct tm *localtime_r(const time_t *timep, struct tm *result);
+
+extern size_t strftime(char*s, size_t maxsize, const char*format, const struct tm*timeptr);
-extern size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, const struct tm*restrict timeptr);
+#ifdef __cplusplus
+};
+#endif
#include <libposix_time.h>
return ret;\r
}\r
\r
+EXPORT FILE *fdopen(int fd, const char *mode)\r
+{\r
+ FILE *ret;\r
+ \r
+ if( fd < 0 || !mode ) return NULL;\r
+ \r
+ ret = get_file_struct();\r
+ \r
+ ret->FD = fd;\r
+ ret->Flags = _fopen_modetoflags(mode);\r
+ if(ret->Flags == -1) {\r
+ ret->Flags = 0;\r
+ return NULL;\r
+ }\r
+ \r
+ ret->Buffer = NULL;\r
+ ret->BufferPos = 0;\r
+ ret->BufferSpace = 0;\r
+ \r
+ return ret;\r
+}\r
+\r
+EXPORT FILE *tmpfile(void)\r
+{\r
+ return NULL;\r
+}\r
+\r
EXPORT int fclose(FILE *fp)\r
{\r
if( !(fp->Flags & FILE_FLAG_ALLOC) )\r
return 0;\r
}\r
\r
-EXPORT int fseek(FILE *fp, long int amt, int whence)\r
+EXPORT int fseeko(FILE *fp, off_t amt, int whence)\r
{\r
if(!fp || fp->FD == FD_NOTOPEN) {\r
errno = EBADF;\r
}\r
}\r
\r
+EXPORT int fseek(FILE *fp, long int amt, int whence)\r
+{\r
+ return fseeko(fp, amt, whence);\r
+}\r
+\r
size_t _fwrite_unbuffered(FILE *fp, size_t size, size_t num, const void *data)\r
{\r
size_t ret = 0, bytes;\r
#include <stdio.h>
#include <ctype.h>
#include "lib.h"
+#include <string.h>
/**
* \fn EXPORT int strcmp(const char *s1, const char *s2)
}
return ret;
}
+
+char *strtok(char *str, const char *delim)
+{
+ static char *__saveptr;
+ return strtok_r(str, delim, &__saveptr);
+}
+char *strtok_r(char *str, const char *delim, char **saveptr)
+{
+ char *pos = (str ? str : *saveptr);
+
+ while( strchr(delim, *pos) )
+ pos ++;
+
+ if( *pos == '\0' )
+ return NULL;
+
+ char *ret = pos;
+ while( !strchr(delim, *pos) )
+ pos ++;
+
+ // Cap the returned string
+ // - If we're at the end of the original string, don't shift pos
+ if( *pos != '\0' ) {
+ *pos = '\0';
+ pos ++;
+ }
+
+ *saveptr = pos;
+
+ return ret;
+}
+
#include <time.h>
#include <acess/sys.h>
#include <string.h>
+#include "timeconv.h"
+#include <errno.h>
+
+#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;
struct tm *localtime(const time_t *timer)
{
- struct tm *ret = &static_tm;
+ return localtime_r(timer, &static_tm);
- // TODO: This breaks on negative timestamps
-
- 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_isdst = 0; // Fuck DST
+
return ret;
}
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * timeconv.c
+ * - Shared User/Kernel time conversion code
+ */
+#include "timeconv.h"
+#include <errno.h>
+
+#define ENABLE_LEAP_SECONDS 1
+
+static const short DAYS_IN[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+#define DEC31 365
+#define JUN30 181
+
+#if ENABLE_LEAP_SECONDS
+// Leap seconds after 2000 (stored as day numbers of application)
+// - Leap seconds apply after the last second of said day (23:59:60)
+// TODO: Need to encode possible double leap seconds, and negative leap seconds
+static int64_t leap_seconds_after[] = {
+ // ls + (year + leap + day + thisleap)
+ (5*365+2+DEC31+0), // Dec 31 2005
+ (8*365+2+DEC31+1), // Dec 31 2008
+ (12*365+3+JUN30+1) // Jun 30 2012
+};
+static int n_leap_seconds_after = sizeof(leap_seconds_after)/sizeof(leap_seconds_after[0]);
+#endif
+
+static int YearIsLeap(int year) {
+ return (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
+}
+static int DaysUntilYear(int year) {
+ return year*365 + (year/400) - (year/100) + (year/4);
+}
+
+int64_t seconds_since_y2k(int years_since, int mon, int day, int h, int m, int s)
+{
+ errno = EINVAL;
+ if( !(1 <= mon && mon <= 12) ) return 0;
+ if( !(1 <= day && day <= DAYS_IN[mon-1]) ) return 0;
+ if( !(0 <= h && h <= 23) ) return 0;
+ if( !(0 <= m && m <= 59) ) return 0;
+ if( !(0 <= s && s <= 60) ) return 0;
+
+ // Special case check for leap days
+ if( mon == 2 && day == 29 )
+ {
+ if( !YearIsLeap(years_since) )
+ return 0;
+ }
+
+ // Day
+ int64_t days = DaysUntilYear(years_since);
+ days += DAYS_BEFORE[mon-1];
+ if(mon > 2 && YearIsLeap(years_since))
+ days ++;
+ days += day;
+
+ // Seconds
+ int64_t seconds = h * 60*60 + m * 60;
+ seconds += s;
+ bool today_has_ls = false;
+ #if ENABLE_LEAP_SECONDS
+ if( days > 0 )
+ {
+ for( int i = 0; i < n_leap_seconds_after; i ++ )
+ {
+ if( days < leap_seconds_after[i] )
+ break ;
+ if(days > leap_seconds_after[i])
+ seconds ++;
+ else
+ today_has_ls = true;
+ // A leap second on this day is handled with s=60
+ }
+ }
+
+ // Now that we know if this day has a leap second, sanity check leap seconds
+ if( s == 60 )
+ {
+ if( !today_has_ls || !(h == 23 && m == 59) )
+ return 0;
+ }
+ #else
+ if( s == 60 ) return 0;
+ #endif
+
+ errno = 0;
+
+ return days * 24*60*60 + seconds;
+}
+
+// returns number of days
+int64_t get_days_since_y2k(int64_t ts, int *h, int *m, int *s)
+{
+ #if ENABLE_LEAP_SECONDS
+ // Calculate leap second count
+ int n_leap = 0;
+ bool is_ls = false;
+ if( ts > 0 )
+ {
+ for( int i = 0; i < n_leap_seconds_after; i ++ )
+ {
+ // lts = Timestamp of the leap second
+ int64_t lts = leap_seconds_after[i] * 24*60*60 + 23*60*60 + 59*60 + 60 + i;
+ if( lts > ts ) break;
+ if( lts == ts )
+ is_ls = true;
+ n_leap ++;
+ }
+ }
+ ts -= n_leap;
+ #endif
+
+ int64_t days = ts / 24*60*60;
+ int64_t seconds = ts % (24*60*60);
+ *s = (is_ls ? 60 : seconds % 60);
+ *m = (seconds/60 % 24);
+ *h = seconds / (60*60);
+
+ return days;
+}
+
+/**
+ * \param days Days since 1 Jan 2000
+ */
+int64_t get_years_since_y2k(int64_t days, bool *is_leap, int *doy)
+{
+ // Calculate Year
+ bool is_ly = false;
+ // Year (400 yr blocks) - (400/4-3) leap years
+ const int days_per_400_yrs = 365*400 + (400/4-3);
+ int year = 400 * days / days_per_400_yrs;
+ days = days % days_per_400_yrs;
+ if( days < 366 ) // First year in 400 is a leap
+ is_ly = true;
+ else
+ {
+ // 100 yr blocks - 100/4-1 leap years
+ const int days_per_100_yrs = 365*100 + (100/4-1);
+ year += 100 * days / days_per_100_yrs;
+ days = days % days_per_100_yrs;
+ if( days < 366 ) // First year in 100 isn't a leap
+ is_ly = false;
+ else
+ {
+ const int days_per_4_yrs = 365*4 + 1;
+ year += 4 * days / days_per_4_yrs;
+ days = days % days_per_4_yrs;
+ if( days < 366 ) // First year in 4 is a leap
+ is_ly = true;
+ else {
+ year += days / 365;
+ days = days % 365;
+ }
+ }
+ }
+ *doy = days;
+ *is_leap = is_ly;
+
+ return year;
+}
+
+void get_month_day(int doy, bool is_ly, int *mon, int *day)
+{
+ if( doy > 365+(is_ly?1:0) ) {
+ *mon = 0;
+ *day = 0;
+ }
+
+ bool mon_day_set = false;
+ if( doy >= DAYS_BEFORE[2] && is_ly )
+ {
+ if( doy == DAYS_BEFORE[2] ) {
+ *mon = 2;
+ *day = 29;
+ mon_day_set = true;
+ }
+ doy --;
+ }
+ for( int i = 1; i < 12+1 && !mon_day_set; i ++ )
+ {
+ if( doy < DAYS_BEFORE[i] )
+ {
+ *mon = i;
+ *day = doy - DAYS_BEFORE[i];
+ mon_day_set = true;
+ }
+ }
+}
+
+int expand_from_secs_since_y2k(int64_t ts, int *years_since, int *mon, int *day, int *h, int *m, int *s)
+{
+ int64_t days = get_days_since_y2k(ts, h, m, s);
+
+ bool is_ly;
+ int doy;
+ *years_since = get_years_since_y2k(days, &is_ly, &doy);
+
+ // Calculate month/day of month
+ get_month_day(doy, is_ly, mon, day);
+ return 0;
+}
+
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * timeconv.h
+ * - Shared User/Kernel time conversion code
+ */
+#ifndef _LIBC_TIMECONV_H_
+#define _LIBC_TIMECONV_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+extern int64_t seconds_since_y2k(int years_since, int mon, int day, int h, int m, int s);
+
+/**
+ * \return Number of days since Y2K
+ *
+ * Extracts the time of day from the timestamp, (possibly taking into account leap seconds)
+ */
+extern int64_t get_days_since_y2k(int64_t ts, int *h, int *m, int *s);
+
+/**
+ * \param days Number of days since Y2K
+ * \return Number of years since Y2K
+ *
+ * Converts a count of days since Y2K, and returns the number of years. Extracting the day of
+ * year, and if that year is a leap year.
+ */
+extern int64_t get_years_since_y2k(int64_t days, bool *is_leap, int *doy);
+
+
+/**
+ * Gets the month and day of month from a day of year and leap year status
+ */
+extern void get_month_day(int doy, bool is_ly, int *mon, int *day);
+
+#endif
+