#include "SystemFunctions.h" #include #include #include #include #include #include #include "Memory.h" #define RETURN_INT(value) \ *r = INT_VALUE(value); \ return false static u32 seed = 0; static bool rawMode = false; static struct termios originalTerminal; static bool sfPrint(Code* c, Value* r, Value* vs, i32 n) { for(i32 i = 0; i < n; i++) { Value* v = vs + i; switch(v->type) { case VT_INT32: printf("%d", v->data); break; case VT_ARRAY: printf("array"); break; case VT_CONSTANT_STRING: printf("%s", c->code.data + v->data); break; } } RETURN_INT(0); } static bool sfPrintLine(Code* c, Value* r, Value* vs, i32 n) { bool b = sfPrint(c, r, vs, n); putchar('\n'); return b; } #define ESC "\33[" #define esc(s) fputs(ESC s, stdout) static bool sfClear(Code*, Value* r, Value*, i32) { esc("2J"); RETURN_INT(0); } static bool sfGetWidth(Code*, Value* r, Value*, i32) { struct winsize w; if(ioctl(0, TIOCGWINSZ, &w)) { RETURN_INT(0); } RETURN_INT(w.ws_col); } static bool sfGetHeight(Code*, Value* r, Value*, i32) { struct winsize w; if(ioctl(0, TIOCGWINSZ, &w)) { RETURN_INT(0); } RETURN_INT(w.ws_row); } static bool sfClearLine(Code*, Value* r, Value*, i32) { esc("2K\r"); RETURN_INT(0); } static bool sfHideCursor(Code*, Value* r, Value*, i32) { esc("?25l"); RETURN_INT(0); } static bool sfShowCursor(Code*, Value* r, Value*, i32) { esc("?25h"); RETURN_INT(0); } static bool sfResetCursor(Code*, Value* r, Value*, i32) { esc("H"); RETURN_INT(0); } static bool sfMoveCursorLeft(Code*, Value* r, Value* vs, i32) { if(vs[0].data > 0) { printf(ESC "%dD", vs[0].data); } RETURN_INT(0); } static bool sfMoveCursorRight(Code*, Value* r, Value* vs, i32) { if(vs[0].data > 0) { printf(ESC "%dC", vs[0].data); } RETURN_INT(0); } static bool sfMoveCursorUp(Code*, Value* r, Value* vs, i32) { if(vs[0].data > 0) { printf(ESC "%dA", vs[0].data); } RETURN_INT(0); } static bool sfMoveCursorDown(Code*, Value* r, Value* vs, i32) { if(vs[0].data > 0) { printf(ESC "%dB", vs[0].data); } RETURN_INT(0); } static bool sfSleep(Code*, Value* r, Value* vs, i32) { struct timespec t = {.tv_sec = vs[0].data, .tv_nsec = vs[1].data}; thrd_sleep(&t, nullptr); RETURN_INT(0); } static bool sfRandom(Code*, Value* r, Value* vs, i32) { seed = seed * 1664525u + 1013904223u; u32 s = seed % (u32)(vs[1].data + 1 - vs[0].data); RETURN_INT(vs[0].data + (i32)s); } static bool codeAllocate(Code* c, Value* v, i32 n) { v->type = VT_ARRAY; v->data = -1; if(n <= 0) { return false; } codeRunCollector(c); size_t s = sizeof(Allocation) + ((size_t)n + 1) * sizeof(Value); Allocation* a = memoryAllocate(s); if(a == nullptr) { SET_ERROR("Out of memory"); return true; } memset(a, 0, s); a->next = c->allocations; c->allocations = a; a->values[0].type = VT_INT32; a->values[0].data = n; v->data = memoryConvertToIndex(a); return false; } static bool sfArray(Code* c, Value* r, Value* vs, i32) { return codeAllocate(c, r, vs[0].data); } static bool sfGetAllocations(Code* c, Value* r, Value*, i32) { codeRunCollector(c); i32 counter = 0; for(Allocation* a = c->allocations; a != nullptr; a = a->next) { counter++; } RETURN_INT(counter); } static bool sfEnterRawTerminal(Code* c, Value* r, Value*, i32) { if(rawMode) { RETURN_INT(0); } if(tcgetattr(STDIN_FILENO, &originalTerminal)) { SET_ERROR("Cannot safe current terminal mode"); return true; } struct termios raw = originalTerminal; raw.c_iflag &= ~(tcflag_t)(ICRNL | IXON); raw.c_lflag &= ~(tcflag_t)(ECHO | ICANON | IEXTEN | ISIG); raw.c_cc[VMIN] = 0; raw.c_cc[VTIME] = 0; if(tcsetattr(STDIN_FILENO, TCSANOW, &raw)) { SET_ERROR("Cannot enter raw terminal mode"); return true; } RETURN_INT(0); } static bool sfLeaveRawTerminal(Code* c, Value* r, Value*, i32) { if(!rawMode) { RETURN_INT(0); } if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &originalTerminal)) { SET_ERROR("Cannot leave raw terminal mode"); return true; } RETURN_INT(0); } static bool sfReadChar(Code*, Value* r, Value*, i32) { u8 ch = 0; ssize_t bytes = read(STDIN_FILENO, &ch, 1); RETURN_INT(bytes <= 0 ? '\0' : ch); } static bool sfFlush(Code*, Value* r, Value*, i32) { fflush(stdout); RETURN_INT(0); } typedef struct { SystemFunction function; i32 arguments; const char* name; } FunctionEntry; static FunctionEntry systemFunctions[] = { {sfPrint, -1, "print"}, {sfPrintLine, -1, "printLine"}, {sfClear, 0, "clear"}, {sfSleep, 2, "sleep"}, {sfGetWidth, 0, "getWidth"}, {sfGetHeight, 0, "getHeight"}, {sfClearLine, 0, "clearLine"}, {sfHideCursor, 0, "hideCursor"}, {sfShowCursor, 0, "showCursor"}, {sfResetCursor, 0, "resetCursor"}, {sfMoveCursorLeft, 1, "moveCursorLeft"}, {sfMoveCursorRight, 1, "moveCursorRight"}, {sfMoveCursorUp, 1, "moveCursorUp"}, {sfMoveCursorDown, 1, "moveCursorDown"}, {sfRandom, 2, "random"}, {sfArray, 1, "array"}, {sfGetAllocations, 0, "getAllocations"}, {sfEnterRawTerminal, 0, "enterRawTerminal"}, {sfLeaveRawTerminal, 0, "leaveRawTerminal"}, {sfReadChar, 0, "readChar"}, {sfFlush, 0, "flush"}, }; static constexpr i32 amount = sizeof(systemFunctions) / sizeof(FunctionEntry); i32 getSystemFunctionIndex(const char* s) { for(i32 i = 0; i < amount; i++) { if(strcmp(systemFunctions[i].name, s) == 0) { return i; } } return -1; } i32 getSystemFunctionArguments(i32 index) { if(index >= 0 && index < amount) { return systemFunctions[index].arguments; } return -1; } SystemFunction getSystemFunction(i32 index) { if(index >= 0 && index < amount) { return systemFunctions[index].function; } return nullptr; } void initSystemFunctions() { struct timespec t = {}; timespec_get(&t, TIME_UTC); seed = (u32)t.tv_nsec; }