SystemFunctions.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #include "SystemFunctions.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/ioctl.h>
  5. #include <termios.h>
  6. #include <threads.h>
  7. #include <unistd.h>
  8. #include "Memory.h"
  9. #include "Utils.h"
  10. #include "Window.h"
  11. #define RETURN_INT(value) \
  12. *r = INT_VALUE(value); \
  13. return false
  14. static u32 seed = 0;
  15. static bool rawMode = false;
  16. static struct termios originalTerminal;
  17. static void append(char** buffer, size_t* n, int change) {
  18. if(change > 0) {
  19. *buffer += change;
  20. *n -= (size_t)change;
  21. }
  22. }
  23. static void printUnicode(const Value* v, char** buffer, size_t* n) {
  24. UTF8 u = convertUnicodeToUTF8(v->data);
  25. for(u32 l = 0; l < u.length && *n > 1; l++) {
  26. **buffer = u.data[l];
  27. append(buffer, n, 1);
  28. }
  29. if(*n > 0) {
  30. **buffer = '\0';
  31. }
  32. }
  33. #define APPEND(b, n, format, ...) \
  34. append(b, n, snprintf(*b, *n, format __VA_OPT__(, ) __VA_ARGS__));
  35. static void printArray(
  36. const Code* c, const Value* v, char** buffer, size_t* n) {
  37. if(v->data == -1) {
  38. APPEND(buffer, n, "null array");
  39. return;
  40. }
  41. Allocation* a = memoryConvertToPointer(v->data);
  42. Value* end = a->values + a->values[0].data + 1;
  43. for(Value* i = a->values + 1; i != end; i++) {
  44. switch(i->type) {
  45. case VT_INT32: printUnicode(i, buffer, n); break;
  46. case VT_ARRAY: APPEND(buffer, n, "array"); break;
  47. case VT_CONSTANT_STRING:
  48. APPEND(buffer, n, "%s", c->code.data + i->data);
  49. break;
  50. }
  51. }
  52. }
  53. static void print(const Code* c, Value* vs, i32 n, char* buffer, size_t bn) {
  54. for(i32 i = 0; i < n; i++) {
  55. Value* v = vs + i;
  56. switch(v->type) {
  57. case VT_INT32: APPEND(&buffer, &bn, "%d", v->data); break;
  58. case VT_ARRAY: printArray(c, v, &buffer, &bn); break;
  59. case VT_CONSTANT_STRING:
  60. APPEND(&buffer, &bn, "%s", c->code.data + v->data);
  61. break;
  62. }
  63. }
  64. }
  65. static bool sfPrint(Code* c, Value* r, Value* vs, i32 n) {
  66. char buffer[1024];
  67. print(c, vs, n, buffer, sizeof(buffer));
  68. fputs(buffer, stdout);
  69. RETURN_INT(0);
  70. }
  71. static bool sfRender(Code* c, Value* r, Value* vs, i32 n) {
  72. i32 x = vs[0].data;
  73. i32 y = vs[1].data;
  74. Color color = (Color)vs[2].data;
  75. char buffer[1024];
  76. print(c, vs + 3, n - 3, buffer, sizeof(buffer));
  77. char* s = buffer;
  78. while(*s != 0) {
  79. UTF8 u = {.data = {*(s++)}, .length = 1};
  80. for(int k = 0; k < 3 && isUTF8Remainder(*s); k++) {
  81. u.data[u.length] = *s;
  82. u.length++;
  83. s++;
  84. }
  85. i32 i = convertUTF8toUnicode(u);
  86. windowSetCharacter(x, y, i, color);
  87. x += 8;
  88. }
  89. RETURN_INT(0);
  90. }
  91. static bool sfPrintLine(Code* c, Value* r, Value* vs, i32 n) {
  92. bool b = sfPrint(c, r, vs, n);
  93. putchar('\n');
  94. return b;
  95. }
  96. #define ESC "\33["
  97. #define esc(s) fputs(ESC s, stdout)
  98. static bool sfClear(Code*, Value* r, Value*, i32) {
  99. esc("2J");
  100. RETURN_INT(0);
  101. }
  102. static bool sfGetWidth(Code*, Value* r, Value*, i32) {
  103. struct winsize w;
  104. if(ioctl(0, TIOCGWINSZ, &w)) {
  105. RETURN_INT(0);
  106. }
  107. RETURN_INT(w.ws_col);
  108. }
  109. static bool sfGetHeight(Code*, Value* r, Value*, i32) {
  110. struct winsize w;
  111. if(ioctl(0, TIOCGWINSZ, &w)) {
  112. RETURN_INT(0);
  113. }
  114. RETURN_INT(w.ws_row);
  115. }
  116. static bool sfClearLine(Code*, Value* r, Value*, i32) {
  117. esc("2K\r");
  118. RETURN_INT(0);
  119. }
  120. static bool sfHideCursor(Code*, Value* r, Value*, i32) {
  121. esc("?25l");
  122. RETURN_INT(0);
  123. }
  124. static bool sfShowCursor(Code*, Value* r, Value*, i32) {
  125. esc("?25h");
  126. RETURN_INT(0);
  127. }
  128. static bool sfResetCursor(Code*, Value* r, Value*, i32) {
  129. esc("H");
  130. RETURN_INT(0);
  131. }
  132. static bool sfMoveCursorLeft(Code*, Value* r, Value* vs, i32) {
  133. if(vs[0].data > 0) {
  134. printf(ESC "%dD", vs[0].data);
  135. }
  136. RETURN_INT(0);
  137. }
  138. static bool sfMoveCursorRight(Code*, Value* r, Value* vs, i32) {
  139. if(vs[0].data > 0) {
  140. printf(ESC "%dC", vs[0].data);
  141. }
  142. RETURN_INT(0);
  143. }
  144. static bool sfMoveCursorUp(Code*, Value* r, Value* vs, i32) {
  145. if(vs[0].data > 0) {
  146. printf(ESC "%dA", vs[0].data);
  147. }
  148. RETURN_INT(0);
  149. }
  150. static bool sfMoveCursorDown(Code*, Value* r, Value* vs, i32) {
  151. if(vs[0].data > 0) {
  152. printf(ESC "%dB", vs[0].data);
  153. }
  154. RETURN_INT(0);
  155. }
  156. static bool sfSleep(Code*, Value* r, Value* vs, i32) {
  157. struct timespec t = {.tv_sec = vs[0].data, .tv_nsec = vs[1].data};
  158. thrd_sleep(&t, nullptr);
  159. RETURN_INT(0);
  160. }
  161. static bool sfRandom(Code*, Value* r, Value* vs, i32) {
  162. seed = seed * 1664525u + 1013904223u;
  163. u32 s = seed % (u32)(vs[1].data + 1 - vs[0].data);
  164. RETURN_INT(vs[0].data + (i32)s);
  165. }
  166. static bool codeAllocate(Code* c, Value* v, i32 n) {
  167. v->type = VT_ARRAY;
  168. v->data = -1;
  169. if(n <= 0) {
  170. return false;
  171. }
  172. codeRunCollector(c);
  173. size_t s = sizeof(Allocation) + ((size_t)n + 1) * sizeof(Value);
  174. Allocation* a = memoryAllocate(s);
  175. if(a == nullptr) {
  176. SET_ERROR("Out of memory");
  177. return true;
  178. }
  179. memset(a, 0, s);
  180. a->next = c->allocations;
  181. c->allocations = a;
  182. a->values[0].type = VT_INT32;
  183. a->values[0].data = n;
  184. v->data = memoryConvertToIndex(a);
  185. return false;
  186. }
  187. static bool sfArray(Code* c, Value* r, Value* vs, i32) {
  188. return codeAllocate(c, r, vs[0].data);
  189. }
  190. static bool sfGetAllocations(Code* c, Value* r, Value*, i32) {
  191. codeRunCollector(c);
  192. i32 counter = 0;
  193. for(Allocation* a = c->allocations; a != nullptr; a = a->next) {
  194. counter++;
  195. }
  196. RETURN_INT(counter);
  197. }
  198. static bool sfEnterRawTerminal(Code* c, Value* r, Value*, i32) {
  199. if(rawMode) {
  200. RETURN_INT(0);
  201. }
  202. if(tcgetattr(STDIN_FILENO, &originalTerminal)) {
  203. SET_ERROR("Cannot safe current terminal mode");
  204. return true;
  205. }
  206. struct termios raw = originalTerminal;
  207. raw.c_iflag &= ~(tcflag_t)(ICRNL | IXON);
  208. raw.c_lflag &= ~(tcflag_t)(ECHO | ICANON | IEXTEN | ISIG);
  209. raw.c_cc[VMIN] = 0;
  210. raw.c_cc[VTIME] = 0;
  211. if(tcsetattr(STDIN_FILENO, TCSANOW, &raw)) {
  212. SET_ERROR("Cannot enter raw terminal mode");
  213. return true;
  214. }
  215. RETURN_INT(0);
  216. }
  217. static bool sfLeaveRawTerminal(Code* c, Value* r, Value*, i32) {
  218. if(!rawMode) {
  219. RETURN_INT(0);
  220. }
  221. if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &originalTerminal)) {
  222. SET_ERROR("Cannot leave raw terminal mode");
  223. return true;
  224. }
  225. RETURN_INT(0);
  226. }
  227. static bool sfReadChar(Code*, Value* r, Value*, i32) {
  228. u8 ch = 0;
  229. ssize_t bytes = read(STDIN_FILENO, &ch, 1);
  230. RETURN_INT(bytes <= 0 ? '\0' : ch);
  231. }
  232. static bool sfFlush(Code*, Value* r, Value*, i32) {
  233. fflush(stdout);
  234. RETURN_INT(0);
  235. }
  236. static bool sfWindowInit(Code* c, Value* r, Value* vs, i32) {
  237. WindowSettings ws = {
  238. .width = vs[0].data, .height = vs[1].data, .title = "Dummy"};
  239. c->error = windowInit(&ws);
  240. *r = INT_VALUE(0);
  241. return hasError(&c->error);
  242. }
  243. #define WINDOW_CHECK() \
  244. do { \
  245. if(!windowExists()) { \
  246. SET_ERROR("No window exists"); \
  247. return true; \
  248. } \
  249. } while(false)
  250. static bool sfWindowShouldClose(Code* c, Value* r, Value*, i32) {
  251. WINDOW_CHECK();
  252. RETURN_INT(windowShouldClose());
  253. }
  254. static bool sfWindowNextFrame(Code* c, Value* r, Value*, i32) {
  255. WINDOW_CHECK();
  256. windowNextFrame();
  257. RETURN_INT(0);
  258. }
  259. static bool sfWindowClear(Code* c, Value* r, Value* vs, i32) {
  260. WINDOW_CHECK();
  261. windowClear((Color)vs[0].data);
  262. RETURN_INT(0);
  263. }
  264. static bool sfWindowSetPixel(Code* c, Value* r, Value* vs, i32) {
  265. WINDOW_CHECK();
  266. windowSetPixel(vs[0].data, vs[1].data, (Color)vs[2].data);
  267. RETURN_INT(0);
  268. }
  269. static bool sfColor(Code*, Value* r, Value* vs, i32) {
  270. RETURN_INT(COLOR(vs[0].data, vs[1].data, vs[2].data));
  271. }
  272. static bool sfGetRed(Code*, Value* r, Value* vs, i32) {
  273. RETURN_INT((vs[0].data & 0b1111100000000000) >> 11);
  274. }
  275. static bool sfGetGreen(Code*, Value* r, Value* vs, i32) {
  276. RETURN_INT((vs[0].data & 0b11111000000) >> 6);
  277. }
  278. static bool sfGetBlue(Code*, Value* r, Value* vs, i32) {
  279. RETURN_INT((vs[0].data & 0b111110) >> 1);
  280. }
  281. static bool sfIsButtonDown(Code*, Value* r, Value* vs, i32) {
  282. RETURN_INT(isButtonDown((Button)vs[0].data));
  283. }
  284. static bool sfGetButtonDownTime(Code*, Value* r, Value* vs, i32) {
  285. RETURN_INT(getButtonDownTime((Button)vs[0].data));
  286. }
  287. typedef struct {
  288. SystemFunction function;
  289. i32 arguments;
  290. const char* name;
  291. } FunctionEntry;
  292. static FunctionEntry systemFunctions[] = {
  293. {sfPrint, -1, "print"},
  294. {sfPrintLine, -1, "printLine"},
  295. {sfClear, 0, "clear"},
  296. {sfSleep, 2, "sleep"},
  297. {sfGetWidth, 0, "getWidth"},
  298. {sfGetHeight, 0, "getHeight"},
  299. {sfClearLine, 0, "clearLine"},
  300. {sfHideCursor, 0, "hideCursor"},
  301. {sfShowCursor, 0, "showCursor"},
  302. {sfResetCursor, 0, "resetCursor"},
  303. {sfMoveCursorLeft, 1, "moveCursorLeft"},
  304. {sfMoveCursorRight, 1, "moveCursorRight"},
  305. {sfMoveCursorUp, 1, "moveCursorUp"},
  306. {sfMoveCursorDown, 1, "moveCursorDown"},
  307. {sfRandom, 2, "random"},
  308. {sfArray, 1, "array"},
  309. {sfGetAllocations, 0, "getAllocations"},
  310. {sfEnterRawTerminal, 0, "enterRawTerminal"},
  311. {sfLeaveRawTerminal, 0, "leaveRawTerminal"},
  312. {sfReadChar, 0, "readChar"},
  313. {sfFlush, 0, "flush"},
  314. {sfWindowInit, 2, "initWindow"},
  315. {sfWindowShouldClose, 0, "shouldClose"},
  316. {sfWindowNextFrame, 0, "nextFrame"},
  317. {sfWindowClear, 1, "clearWindow"},
  318. {sfWindowSetPixel, 3, "setPixel"},
  319. {sfColor, 3, "color"},
  320. {sfGetRed, 1, "getRed"},
  321. {sfGetGreen, 1, "getGreen"},
  322. {sfGetBlue, 1, "getBlue"},
  323. {sfIsButtonDown, 1, "isButtonDown"},
  324. {sfGetButtonDownTime, 1, "getButtonDownTime"},
  325. {sfRender, -4, "render"},
  326. };
  327. static constexpr i32 amount = sizeof(systemFunctions) / sizeof(FunctionEntry);
  328. i32 getSystemFunctionIndex(const char* s) {
  329. for(i32 i = 0; i < amount; i++) {
  330. if(strcmp(systemFunctions[i].name, s) == 0) {
  331. return i;
  332. }
  333. }
  334. return -1;
  335. }
  336. i32 getSystemFunctionArguments(i32 index) {
  337. if(index >= 0 && index < amount) {
  338. return systemFunctions[index].arguments;
  339. }
  340. return -1;
  341. }
  342. SystemFunction getSystemFunction(i32 index) {
  343. if(index >= 0 && index < amount) {
  344. return systemFunctions[index].function;
  345. }
  346. return nullptr;
  347. }
  348. void initSystemFunctions() {
  349. struct timespec t = {};
  350. timespec_get(&t, TIME_UTC);
  351. seed = (u32)t.tv_nsec;
  352. }