SystemFunctions.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. #define RETURN_INT(value) \
  10. *r = INT_VALUE(value); \
  11. return false
  12. static u32 seed = 0;
  13. static bool rawMode = false;
  14. static struct termios originalTerminal;
  15. static bool sfPrint(Code* c, Value* r, Value* vs, i32 n) {
  16. for(i32 i = 0; i < n; i++) {
  17. Value* v = vs + i;
  18. switch(v->type) {
  19. case VT_INT32: printf("%d", v->data); break;
  20. case VT_ARRAY: printf("array"); break;
  21. case VT_CONSTANT_STRING:
  22. printf("%s", c->code.data + v->data);
  23. break;
  24. }
  25. }
  26. RETURN_INT(0);
  27. }
  28. static bool sfPrintLine(Code* c, Value* r, Value* vs, i32 n) {
  29. bool b = sfPrint(c, r, vs, n);
  30. putchar('\n');
  31. return b;
  32. }
  33. #define ESC "\33["
  34. #define esc(s) fputs(ESC s, stdout)
  35. static bool sfClear(Code*, Value* r, Value*, i32) {
  36. esc("2J");
  37. RETURN_INT(0);
  38. }
  39. static bool sfGetWidth(Code*, Value* r, Value*, i32) {
  40. struct winsize w;
  41. if(ioctl(0, TIOCGWINSZ, &w)) {
  42. RETURN_INT(0);
  43. }
  44. RETURN_INT(w.ws_col);
  45. }
  46. static bool sfGetHeight(Code*, Value* r, Value*, i32) {
  47. struct winsize w;
  48. if(ioctl(0, TIOCGWINSZ, &w)) {
  49. RETURN_INT(0);
  50. }
  51. RETURN_INT(w.ws_row);
  52. }
  53. static bool sfClearLine(Code*, Value* r, Value*, i32) {
  54. esc("2K\r");
  55. RETURN_INT(0);
  56. }
  57. static bool sfHideCursor(Code*, Value* r, Value*, i32) {
  58. esc("?25l");
  59. RETURN_INT(0);
  60. }
  61. static bool sfShowCursor(Code*, Value* r, Value*, i32) {
  62. esc("?25h");
  63. RETURN_INT(0);
  64. }
  65. static bool sfResetCursor(Code*, Value* r, Value*, i32) {
  66. esc("H");
  67. RETURN_INT(0);
  68. }
  69. static bool sfMoveCursorLeft(Code*, Value* r, Value* vs, i32) {
  70. if(vs[0].data > 0) {
  71. printf(ESC "%dD", vs[0].data);
  72. }
  73. RETURN_INT(0);
  74. }
  75. static bool sfMoveCursorRight(Code*, Value* r, Value* vs, i32) {
  76. if(vs[0].data > 0) {
  77. printf(ESC "%dC", vs[0].data);
  78. }
  79. RETURN_INT(0);
  80. }
  81. static bool sfMoveCursorUp(Code*, Value* r, Value* vs, i32) {
  82. if(vs[0].data > 0) {
  83. printf(ESC "%dA", vs[0].data);
  84. }
  85. RETURN_INT(0);
  86. }
  87. static bool sfMoveCursorDown(Code*, Value* r, Value* vs, i32) {
  88. if(vs[0].data > 0) {
  89. printf(ESC "%dB", vs[0].data);
  90. }
  91. RETURN_INT(0);
  92. }
  93. static bool sfSleep(Code*, Value* r, Value* vs, i32) {
  94. struct timespec t = {.tv_sec = vs[0].data, .tv_nsec = vs[1].data};
  95. thrd_sleep(&t, nullptr);
  96. RETURN_INT(0);
  97. }
  98. static bool sfRandom(Code*, Value* r, Value* vs, i32) {
  99. seed = seed * 1664525u + 1013904223u;
  100. u32 s = seed % (u32)(vs[1].data + 1 - vs[0].data);
  101. RETURN_INT(vs[0].data + (i32)s);
  102. }
  103. static bool codeAllocate(Code* c, Value* v, i32 n) {
  104. v->type = VT_ARRAY;
  105. v->data = -1;
  106. if(n <= 0) {
  107. return false;
  108. }
  109. codeRunCollector(c);
  110. size_t s = sizeof(Allocation) + ((size_t)n + 1) * sizeof(Value);
  111. Allocation* a = memoryAllocate(s);
  112. if(a == nullptr) {
  113. SET_ERROR("Out of memory");
  114. return true;
  115. }
  116. memset(a, 0, s);
  117. a->next = c->allocations;
  118. c->allocations = a;
  119. a->values[0].type = VT_INT32;
  120. a->values[0].data = n;
  121. v->data = memoryConvertToIndex(a);
  122. return false;
  123. }
  124. static bool sfArray(Code* c, Value* r, Value* vs, i32) {
  125. return codeAllocate(c, r, vs[0].data);
  126. }
  127. static bool sfGetAllocations(Code* c, Value* r, Value*, i32) {
  128. codeRunCollector(c);
  129. i32 counter = 0;
  130. for(Allocation* a = c->allocations; a != nullptr; a = a->next) {
  131. counter++;
  132. }
  133. RETURN_INT(counter);
  134. }
  135. static bool sfEnterRawTerminal(Code* c, Value* r, Value*, i32) {
  136. if(rawMode) {
  137. RETURN_INT(0);
  138. }
  139. if(tcgetattr(STDIN_FILENO, &originalTerminal)) {
  140. SET_ERROR("Cannot safe current terminal mode");
  141. return true;
  142. }
  143. struct termios raw = originalTerminal;
  144. raw.c_iflag &= ~(tcflag_t)(ICRNL | IXON);
  145. raw.c_lflag &= ~(tcflag_t)(ECHO | ICANON | IEXTEN | ISIG);
  146. raw.c_cc[VMIN] = 0;
  147. raw.c_cc[VTIME] = 0;
  148. if(tcsetattr(STDIN_FILENO, TCSANOW, &raw)) {
  149. SET_ERROR("Cannot enter raw terminal mode");
  150. return true;
  151. }
  152. RETURN_INT(0);
  153. }
  154. static bool sfLeaveRawTerminal(Code* c, Value* r, Value*, i32) {
  155. if(!rawMode) {
  156. RETURN_INT(0);
  157. }
  158. if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &originalTerminal)) {
  159. SET_ERROR("Cannot leave raw terminal mode");
  160. return true;
  161. }
  162. RETURN_INT(0);
  163. }
  164. static bool sfReadChar(Code*, Value* r, Value*, i32) {
  165. u8 ch = 0;
  166. ssize_t bytes = read(STDIN_FILENO, &ch, 1);
  167. RETURN_INT(bytes <= 0 ? '\0' : ch);
  168. }
  169. static bool sfFlush(Code*, Value* r, Value*, i32) {
  170. fflush(stdout);
  171. RETURN_INT(0);
  172. }
  173. typedef struct {
  174. SystemFunction function;
  175. i32 arguments;
  176. const char* name;
  177. } FunctionEntry;
  178. static FunctionEntry systemFunctions[] = {
  179. {sfPrint, -1, "print"},
  180. {sfPrintLine, -1, "printLine"},
  181. {sfClear, 0, "clear"},
  182. {sfSleep, 2, "sleep"},
  183. {sfGetWidth, 0, "getWidth"},
  184. {sfGetHeight, 0, "getHeight"},
  185. {sfClearLine, 0, "clearLine"},
  186. {sfHideCursor, 0, "hideCursor"},
  187. {sfShowCursor, 0, "showCursor"},
  188. {sfResetCursor, 0, "resetCursor"},
  189. {sfMoveCursorLeft, 1, "moveCursorLeft"},
  190. {sfMoveCursorRight, 1, "moveCursorRight"},
  191. {sfMoveCursorUp, 1, "moveCursorUp"},
  192. {sfMoveCursorDown, 1, "moveCursorDown"},
  193. {sfRandom, 2, "random"},
  194. {sfArray, 1, "array"},
  195. {sfGetAllocations, 0, "getAllocations"},
  196. {sfEnterRawTerminal, 0, "enterRawTerminal"},
  197. {sfLeaveRawTerminal, 0, "leaveRawTerminal"},
  198. {sfReadChar, 0, "readChar"},
  199. {sfFlush, 0, "flush"},
  200. };
  201. static constexpr i32 amount = sizeof(systemFunctions) / sizeof(FunctionEntry);
  202. i32 getSystemFunctionIndex(const char* s) {
  203. for(i32 i = 0; i < amount; i++) {
  204. if(strcmp(systemFunctions[i].name, s) == 0) {
  205. return i;
  206. }
  207. }
  208. return -1;
  209. }
  210. i32 getSystemFunctionArguments(i32 index) {
  211. if(index >= 0 && index < amount) {
  212. return systemFunctions[index].arguments;
  213. }
  214. return -1;
  215. }
  216. SystemFunction getSystemFunction(i32 index) {
  217. if(index >= 0 && index < amount) {
  218. return systemFunctions[index].function;
  219. }
  220. return nullptr;
  221. }
  222. void initSystemFunctions() {
  223. struct timespec t = {};
  224. timespec_get(&t, TIME_UTC);
  225. seed = (u32)t.tv_nsec;
  226. }