452 lines
7.9 KiB
HolyC
452 lines
7.9 KiB
HolyC
#define PUSH_SYSV_REGS \
|
|
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
|
|
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
|
|
#define POP_SYSV_REGS \
|
|
p0 = p0; \
|
|
p1 = p1; \
|
|
p2 = p2; \
|
|
p3 = p3; \
|
|
p4 = p4; \
|
|
p5 = p5; \
|
|
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
|
|
RSI POP RBP POP RBX POP RDX POP RCX}
|
|
#define GET_SYSV_ARGS \
|
|
asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \
|
|
I64 reg RDI p0; \
|
|
I64 reg RSI p1; \
|
|
I64 reg RDX p2; \
|
|
I64 reg RCX p3; \
|
|
I64 reg R8 p4; \
|
|
I64 reg R9 p5; \
|
|
asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9}
|
|
|
|
asm {
|
|
_SETJMP::
|
|
MOV [RDI], RBX // Store caller saved registers
|
|
MOV [RDI+8], RBP // ^
|
|
MOV [RDI+16], R12 // ^
|
|
MOV [RDI+24], R13 // ^
|
|
MOV [RDI+32], R14 // ^
|
|
MOV [RDI+40], R15 // ^
|
|
LEA RDX, [RSP+8] // go one value up (as if setjmp wasn't called)
|
|
MOV [RDI+48], RDX // Store the new rsp pointer in env[7]
|
|
MOV RDX, [RSP] // go one value up (as if setjmp wasn't called)
|
|
MOV [RDI+56], RDX // Store the address we will resume at in env[8]
|
|
XOR EAX, EAX // Always return 0
|
|
RET
|
|
_LONGJMP::
|
|
XOR EAX, EAX
|
|
CMP ESI, 1
|
|
ADC EAX, ESI
|
|
MOV RBX, [RDI]
|
|
MOV RBP, [RDI + 8]
|
|
MOV R12, [RDI + 16]
|
|
MOV R13, [RDI + 24]
|
|
MOV R14, [RDI + 32]
|
|
MOV R15, [RDI + 40]
|
|
MOV RSP, [RDI + 48]
|
|
JMP U64 [RDI + 56]
|
|
}
|
|
|
|
_extern _SETJMP U64 _setjmp(U64 jmp_buf);
|
|
_extern _LONGJMP U64 longjmp(U64 jmp_buf, U64 ret);
|
|
|
|
class libc_tm {
|
|
I32 tm_sec; /* seconds, range 0 to 59 */
|
|
I32 tm_min; /* minutes, range 0 to 59 */
|
|
I32 tm_hour; /* hours, range 0 to 23 */
|
|
I32 tm_mday; /* day of the month, range 1 to 31 */
|
|
I32 tm_mon; /* month, range 0 to 11 */
|
|
I32 tm_year; /* The number of years since 1900 */
|
|
I32 tm_wday; /* day of the week, range 0 to 6 */
|
|
I32 tm_yday; /* day in the year, range 0 to 365 */
|
|
I32 tm_isdst; /* daylight saving time */
|
|
};
|
|
|
|
#define NIST_TIME_OFFSET -9488
|
|
|
|
I64 CDate2Unix(CDate dt)
|
|
{ // TempleOS datetime to Unix timestamp.
|
|
return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ + NIST_TIME_OFFSET);
|
|
}
|
|
|
|
public CDate Unix2CDate(I64 timestamp)
|
|
{//Unix timestamp to TempleOS datetime.
|
|
return (timestamp-NIST_TIME_OFFSET)*CDATE_FREQ+Str2Date("1/1/1970");
|
|
}
|
|
|
|
U0 free()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
Free(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 putchar()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
PutChars(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @localtime(U64 p0)
|
|
{
|
|
// FIXME: implement this?
|
|
no_warn p0;
|
|
return 0;
|
|
}
|
|
|
|
U0 localtime()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@localtime(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @gmtime(U64* timep)
|
|
{
|
|
CDateStruct ds;
|
|
Date2Struct(&ds, Unix2CDate(*timep));
|
|
libc_tm* tm = CAlloc(sizeof(libc_tm));
|
|
|
|
tm->tm_sec = ds.sec;
|
|
tm->tm_min = ds.min;
|
|
tm->tm_hour = ds.hour;
|
|
tm->tm_mday = ds.day_of_mon;
|
|
tm->tm_mon = ds.mon;
|
|
tm->tm_year = ds.year;
|
|
tm->tm_wday = ds.day_of_week;
|
|
return tm;
|
|
}
|
|
|
|
U0 gmtime()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@gmtime(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @mktime(libc_tm* tm)
|
|
{
|
|
CDateStruct ds;
|
|
MemSet(&ds, 0, sizeof(CDateStruct));
|
|
if (tm) {
|
|
ds.sec = tm->tm_sec;
|
|
ds.min = tm->tm_min;
|
|
ds.hour = tm->tm_hour;
|
|
ds.day_of_mon = tm->tm_mday;
|
|
ds.mon = tm->tm_mon;
|
|
ds.year = tm->tm_year;
|
|
ds.day_of_week = tm->tm_wday;
|
|
} else {
|
|
Date2Struct(&ds, Now);
|
|
}
|
|
return CDate2Unix(Struct2Date(&ds));
|
|
}
|
|
|
|
U0 mktime()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@mktime(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
I64 @strncmp(U8* s1, U8* s2, I32 n)
|
|
{
|
|
U64 u1, u2;
|
|
|
|
while (n-- > 0) {
|
|
u1 = *s1++;
|
|
u2 = *s2++;
|
|
u1 = u1 & 0xff;
|
|
u2 = u2 & 0xff;
|
|
if (u1 != u2)
|
|
return u1 - u2;
|
|
if (u1 == '\0')
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
U0 strncmp()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@strncmp(p0, p1, p2);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 strcpy()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
StrCpy(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 fprintf()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
Print(p1, p2, p3, p4, p5);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
|
|
U0 printf()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
Print(p0, p1, p2, p3, p4, p5);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 puts()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
PutS(p0);
|
|
"\n";
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 fputs()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
PutS(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 fputc()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
PutChars(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @fwrite(U8* buffer, I64 size, I64 count, U64 stream)
|
|
{
|
|
if (!buffer || !size || !count || !stream)
|
|
return NULL;
|
|
I64 bytes = size * count;
|
|
switch (stream) {
|
|
case 1...2:
|
|
U8* s = CAlloc(bytes + 1);
|
|
MemCpy(s, buffer, bytes);
|
|
"%s", s;
|
|
Free(s);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
U0 fwrite()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@fwrite(p0, p1, p2, p3);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 strerror()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
"strerror: %d\n", p0;
|
|
PressAKey;
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 strlen()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
StrLen(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U8 *@strchr(U8 *str, I64 chr) {
|
|
while (*str) {
|
|
if (*str == chr) {
|
|
return str;
|
|
}
|
|
str++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
U0 strchr()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@strchr(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U8* @strrchr(U8 *str, I64 chr) {
|
|
U8* str2 = str + (StrLen(str) - 1);
|
|
while (str2 > str - 1) {
|
|
if (*str2 == chr) {
|
|
return str2;
|
|
}
|
|
str2--;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
U0 strrchr()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@strrchr(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 strcmp()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
StrCmp(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 memcpy()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
MemCpy(p0, p1, p2);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 memset()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
MemSet(p0, p1, p2);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 malloc()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
MAlloc(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U8* @realloc(U8* ptr, I64 size)
|
|
{
|
|
U8* new;
|
|
if (!ptr) {
|
|
new = MAlloc(size);
|
|
} else {
|
|
new = MAlloc(size);
|
|
MemCpy(new, ptr, size);
|
|
Free(ptr);
|
|
}
|
|
return new;
|
|
}
|
|
|
|
U0 realloc()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@realloc(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
I64 @time(I64* ptr)
|
|
{
|
|
no_warn ptr;
|
|
return CDate2Unix(Now);
|
|
}
|
|
|
|
U0 time()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@time(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @gettimeofday(U64* tv)
|
|
{
|
|
if (!tv)
|
|
return 0;
|
|
U64 seconds = CDate2Unix(Now);
|
|
tv[0] = seconds;
|
|
tv[1] = NULL;
|
|
return 0;
|
|
}
|
|
|
|
U0 gettimeofday()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@gettimeofday(p0);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 @fgets(U8* p0, I64 p1)
|
|
{
|
|
GetS(p0, p1);
|
|
while (*p0) {
|
|
if (*p0 == 0x1f)
|
|
*p0 = 0x20;
|
|
++p0;
|
|
}
|
|
Print("");
|
|
}
|
|
|
|
U0 fgets()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@fgets(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @ferror()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
U0 ferror()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@ferror;
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U64 @strcat(U8* dst, U8* src)
|
|
{
|
|
StrCpy(dst + StrLen(dst), src);
|
|
return 0;
|
|
}
|
|
|
|
U0 strcat()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
@strcat(p0, p1);
|
|
POP_SYSV_REGS
|
|
}
|
|
|
|
U0 strstr()
|
|
{
|
|
PUSH_SYSV_REGS
|
|
GET_SYSV_ARGS
|
|
StrFind(p1, p0);
|
|
POP_SYSV_REGS
|
|
|
|
}
|