25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

485 satır
16 KiB

  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #include <stdarg.h>
  4. #include <stdbool.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "platform.hpp"
  9. #include "hashmap.hpp"
  10. #include "hooks.hpp"
  11. FILE* ftb_stdout = stdout;
  12. #define str_eq(s1, s2) (strcmp(s1, s2) == 0)
  13. #define console_normal "\x1B[0m"
  14. #define console_red "\x1B[31m"
  15. #define console_green "\x1B[32m"
  16. #define console_cyan "\x1B[36m"
  17. typedef const char* static_string;
  18. typedef int (*printer_function_32b)(FILE*, u32);
  19. typedef int (*printer_function_64b)(FILE*, u64);
  20. typedef int (*printer_function_flt)(FILE*, double);
  21. typedef int (*printer_function_ptr)(FILE*, void*);
  22. typedef int (*printer_function_void)(FILE*);
  23. enum struct Printer_Function_Type {
  24. unknown,
  25. _32b,
  26. _64b,
  27. _flt,
  28. _ptr,
  29. _void
  30. };
  31. Array_List<char*> color_stack = {0};
  32. Hash_Map<char*, printer_function_ptr> printer_map = {0};
  33. Hash_Map<char*, int> type_map = {0};
  34. #define register_printer(spec, fun, type) \
  35. register_printer_ptr(spec, (printer_function_ptr)fun, type)
  36. void register_printer_ptr(const char* spec, printer_function_ptr fun, Printer_Function_Type type) {
  37. printer_map.set_object((char*)spec, fun);
  38. type_map.set_object((char*)spec, (int)type);
  39. }
  40. int maybe_special_print(FILE* file, static_string format, int* pos, va_list* arg_list) {
  41. if(format[*pos] != '{')
  42. return 0;
  43. int end_pos = (*pos)+1;
  44. while (format[end_pos] != '}' &&
  45. format[end_pos] != ',' &&
  46. format[end_pos] != '[' &&
  47. format[end_pos] != 0)
  48. ++end_pos;
  49. if (format[end_pos] == 0)
  50. return 0;
  51. char* spec = (char*)malloc(end_pos - (*pos));
  52. strncpy(spec, format+(*pos)+1, end_pos - (*pos));
  53. spec[end_pos - (*pos)-1] = '\0';
  54. u64 spec_hash = hm_hash(spec);
  55. Printer_Function_Type type = (Printer_Function_Type)type_map.get_object(spec, spec_hash);
  56. union {
  57. printer_function_32b printer_32b;
  58. printer_function_64b printer_64b;
  59. printer_function_ptr printer_ptr;
  60. printer_function_flt printer_flt;
  61. printer_function_void printer_void;
  62. } printer;
  63. // just grab it, it will have the correct type
  64. printer.printer_ptr = printer_map.get_object(spec, spec_hash);
  65. if (type == Printer_Function_Type::unknown) {
  66. printf("ERROR: %s printer not found\n", spec);
  67. free(spec);
  68. return 0;
  69. }
  70. free(spec);
  71. if (format[end_pos] == ',') {
  72. int element_count;
  73. ++end_pos;
  74. sscanf(format+end_pos, "%d", &element_count);
  75. while (format[end_pos] != '}' &&
  76. format[end_pos] != 0)
  77. ++end_pos;
  78. if (format[end_pos] == 0)
  79. return 0;
  80. // both brackets already included:
  81. int written_length = 2;
  82. fputs("[", file);
  83. for (int i = 0; i < element_count - 1; ++i) {
  84. if (type == Printer_Function_Type::_32b) written_length += printer.printer_32b(file, va_arg(*arg_list, u32));
  85. else if (type == Printer_Function_Type::_64b) written_length += printer.printer_64b(file, va_arg(*arg_list, u64));
  86. else if (type == Printer_Function_Type::_flt) written_length += printer.printer_flt(file, va_arg(*arg_list, double));
  87. else if (type == Printer_Function_Type::_ptr) written_length += printer.printer_ptr(file, va_arg(*arg_list, void*));
  88. else written_length += printer.printer_void(file);
  89. written_length += 2;
  90. fputs(", ", file);
  91. }
  92. if (element_count > 0) {
  93. if (type == Printer_Function_Type::_32b) written_length += printer.printer_32b(file, va_arg(*arg_list, u32));
  94. else if (type == Printer_Function_Type::_64b) written_length += printer.printer_64b(file, va_arg(*arg_list, u64));
  95. else if (type == Printer_Function_Type::_flt) written_length += printer.printer_flt(file, va_arg(*arg_list, double));
  96. else if (type == Printer_Function_Type::_ptr) written_length += printer.printer_ptr(file, va_arg(*arg_list, void*));
  97. else written_length += printer.printer_void(file);
  98. }
  99. fputs("]", file);
  100. *pos = end_pos;
  101. return written_length;
  102. } else if (format[end_pos] == '[') {
  103. end_pos++;
  104. u32 element_count;
  105. union {
  106. u32* arr_32b;
  107. u64* arr_64b;
  108. f32* arr_flt;
  109. void** arr_ptr;
  110. } arr;
  111. if (type == Printer_Function_Type::_32b) arr.arr_32b = va_arg(*arg_list, u32*);
  112. else if (type == Printer_Function_Type::_64b) arr.arr_64b = va_arg(*arg_list, u64*);
  113. else if (type == Printer_Function_Type::_flt) arr.arr_flt = va_arg(*arg_list, f32*);
  114. else arr.arr_ptr = va_arg(*arg_list, void**);
  115. if (format[end_pos] == '*') {
  116. element_count = va_arg(*arg_list, u32);
  117. } else {
  118. sscanf(format+end_pos, "%d", &element_count);
  119. }
  120. // skip to next ']'
  121. while (format[end_pos] != ']' &&
  122. format[end_pos] != 0)
  123. ++end_pos;
  124. if (format[end_pos] == 0)
  125. return 0;
  126. // skip to next '}'
  127. while (format[end_pos] != '}' &&
  128. format[end_pos] != 0)
  129. ++end_pos;
  130. if (format[end_pos] == 0)
  131. return 0;
  132. // both brackets already included:
  133. int written_length = 2;
  134. fputs("[", file);
  135. for (u32 i = 0; i < element_count - 1; ++i) {
  136. if (type == Printer_Function_Type::_32b) written_length += printer.printer_32b(file, arr.arr_32b[i]);
  137. else if (type == Printer_Function_Type::_64b) written_length += printer.printer_64b(file, arr.arr_64b[i]);
  138. else if (type == Printer_Function_Type::_flt) written_length += printer.printer_flt(file, arr.arr_flt[i]);
  139. else if (type == Printer_Function_Type::_ptr) written_length += printer.printer_ptr(file, arr.arr_ptr[i]);
  140. else written_length += printer.printer_void(file);
  141. written_length += 2;
  142. fputs(", ", file);
  143. }
  144. if (element_count > 0) {
  145. if (type == Printer_Function_Type::_32b) written_length += printer.printer_32b(file, arr.arr_32b[element_count - 1]);
  146. else if (type == Printer_Function_Type::_64b) written_length += printer.printer_64b(file, arr.arr_64b[element_count - 1]);
  147. else if (type == Printer_Function_Type::_flt) written_length += printer.printer_flt(file, arr.arr_flt[element_count - 1]);
  148. else if (type == Printer_Function_Type::_ptr) written_length += printer.printer_ptr(file, arr.arr_ptr[element_count - 1]);
  149. else written_length += printer.printer_void(file);
  150. }
  151. fputs("]", file);
  152. *pos = end_pos;
  153. return written_length;
  154. } else {
  155. *pos = end_pos;
  156. if (type == Printer_Function_Type::_32b) return printer.printer_32b(file, va_arg(*arg_list, u32));
  157. else if (type == Printer_Function_Type::_64b) return printer.printer_64b(file, va_arg(*arg_list, u64));
  158. else if (type == Printer_Function_Type::_flt) return printer.printer_flt(file, va_arg(*arg_list, double));
  159. else if (type == Printer_Function_Type::_ptr) return printer.printer_ptr(file, va_arg(*arg_list, void*));
  160. else return printer.printer_void(file);
  161. }
  162. return 0;
  163. }
  164. int maybe_fprintf(FILE* file, static_string format, int* pos, va_list* arg_list) {
  165. // %[flags][width][.precision][length]specifier
  166. // flags ::= [+- #0]
  167. // width ::= [<number>+ \*]
  168. // precision ::= \.[<number>+ \*]
  169. // length ::= [h l L]
  170. // specifier ::= [c d i e E f g G o s u x X p n %]
  171. int end_pos = *pos;
  172. int writen_len = 0;
  173. int used_arg_values = 1;
  174. // overstep flags:
  175. while(format[end_pos] == '+' ||
  176. format[end_pos] == '-' ||
  177. format[end_pos] == ' ' ||
  178. format[end_pos] == '#' ||
  179. format[end_pos] == '0')
  180. ++end_pos;
  181. // overstep width
  182. if (format[end_pos] == '*') {
  183. ++used_arg_values;
  184. ++end_pos;
  185. }
  186. else {
  187. while(format[end_pos] >= '0' && format[end_pos] <= '9')
  188. ++end_pos;
  189. }
  190. // overstep precision
  191. if (format[end_pos] == '.') {
  192. ++end_pos;
  193. if (format[end_pos] == '*') {
  194. ++used_arg_values;
  195. ++end_pos;
  196. }
  197. else {
  198. while(format[end_pos] >= '0' && format[end_pos] <= '9')
  199. ++end_pos;
  200. }
  201. }
  202. // overstep length:
  203. while(format[end_pos] == 'h' ||
  204. format[end_pos] == 'l' ||
  205. format[end_pos] == 'L')
  206. ++end_pos;
  207. // check for actual built_in specifier
  208. if(format[end_pos] == 'c' ||
  209. format[end_pos] == 'd' ||
  210. format[end_pos] == 'i' ||
  211. format[end_pos] == 'e' ||
  212. format[end_pos] == 'E' ||
  213. format[end_pos] == 'f' ||
  214. format[end_pos] == 'g' ||
  215. format[end_pos] == 'G' ||
  216. format[end_pos] == 'o' ||
  217. format[end_pos] == 's' ||
  218. format[end_pos] == 'u' ||
  219. format[end_pos] == 'x' ||
  220. format[end_pos] == 'X' ||
  221. format[end_pos] == 'p' ||
  222. format[end_pos] == 'n' ||
  223. format[end_pos] == '%')
  224. {
  225. writen_len = end_pos - *pos + 2;
  226. char* temp = (char*)malloc((writen_len+1)* sizeof(char));
  227. temp[0] = '%';
  228. temp[1] = 0;
  229. strncpy(temp+1, format+*pos, writen_len);
  230. temp[writen_len] = 0;
  231. // printf("\ntest:: len(%s) = %d\n", temp, writen_len+1);
  232. /// NOTE(Felix): Somehow we have to pass a copy of the list to vfprintf
  233. // because otherwise it destroys it on some platforms :(
  234. va_list arg_list_copy;
  235. va_copy(arg_list_copy, *arg_list);
  236. writen_len = vfprintf(file, temp, arg_list_copy);
  237. va_end(arg_list_copy);
  238. // NOTE(Felix): maually overstep the args that vfprintf will have used
  239. for (int i = 0; i < used_arg_values; ++i) {
  240. va_arg(*arg_list, void*);
  241. }
  242. free(temp);
  243. *pos = end_pos;
  244. }
  245. return writen_len;
  246. }
  247. int print_va_args_to_file(FILE* file, static_string format, va_list* arg_list) {
  248. int printed_chars = 0;
  249. char c;
  250. int pos = -1;
  251. while ((c = format[++pos])) {
  252. if (c != '%') {
  253. putc(c, file);
  254. ++printed_chars;
  255. } else {
  256. c = format[++pos];
  257. int move = maybe_special_print(file, format, &pos, arg_list);
  258. if (move == 0) {
  259. move = maybe_fprintf(file, format, &pos, arg_list);
  260. if (move == -1) {
  261. fputc('%', file);
  262. fputc(c, file);
  263. move = 1;
  264. }
  265. }
  266. printed_chars += move;
  267. }
  268. }
  269. return printed_chars;
  270. }
  271. int print_va_args_to_string(char** out, static_string format, va_list* arg_list) {
  272. FILE* t_file = tmpfile();
  273. if (!t_file) {
  274. return 0;
  275. }
  276. int num_printed_chars = print_va_args_to_file(t_file, format, arg_list);
  277. *out = (char*)malloc(sizeof(char) * (num_printed_chars+1));
  278. rewind(t_file);
  279. fread(*out, sizeof(char), num_printed_chars, t_file);
  280. (*out)[num_printed_chars] = '\0';
  281. fclose(t_file);
  282. return num_printed_chars;
  283. }
  284. int print_va_args(static_string format, va_list* arg_list) {
  285. return print_va_args_to_file(stdout, format, arg_list);
  286. }
  287. int print_to_string(char** out, static_string format, ...) {
  288. va_list arg_list;
  289. va_start(arg_list, format);
  290. FILE* t_file = tmpfile();
  291. if (!t_file) {
  292. return 0;
  293. }
  294. int num_printed_chars = print_va_args_to_file(t_file, format, &arg_list);
  295. va_end(arg_list);
  296. *out = (char*)malloc(sizeof(char) * (num_printed_chars+1));
  297. rewind(t_file);
  298. fread(*out, sizeof(char), num_printed_chars, t_file);
  299. (*out)[num_printed_chars] = '\0';
  300. fclose(t_file);
  301. return num_printed_chars;
  302. }
  303. int print_to_file(FILE* file, static_string format, ...) {
  304. va_list arg_list;
  305. va_start(arg_list, format);
  306. int num_printed_chars = print_va_args_to_file(file, format, &arg_list);
  307. va_end(arg_list);
  308. return num_printed_chars;
  309. }
  310. int print(static_string format, ...) {
  311. va_list arg_list;
  312. va_start(arg_list, format);
  313. int num_printed_chars = print_va_args_to_file(ftb_stdout, format, &arg_list);
  314. va_end(arg_list);
  315. return num_printed_chars;
  316. }
  317. int print_bool(FILE* f, u32 val) {
  318. return print_to_file(f, val ? "true" : "false");
  319. }
  320. int print_u32(FILE* f, u32 num) {
  321. return print_to_file(f, "%u", num);
  322. }
  323. int print_u64(FILE* f, u64 num) {
  324. return print_to_file(f, "%llu", num);
  325. }
  326. int print_s32(FILE* f, s32 num) {
  327. return print_to_file(f, "%d", num);
  328. }
  329. int print_s64(FILE* f, s64 num) {
  330. return print_to_file(f, "%lld", num);
  331. }
  332. int print_flt(FILE* f, double arg) {
  333. return print_to_file(f, "%f", arg);
  334. }
  335. int print_str(FILE* f, char* str) {
  336. return print_to_file(f, "%s", str);
  337. }
  338. int print_color_start(FILE* f, char* str) {
  339. color_stack.append(str);
  340. return print_to_file(f, "%s", str);
  341. }
  342. int print_color_end(FILE* f) {
  343. --color_stack.count;
  344. if (color_stack.count == 0) {
  345. return print_to_file(f, "%s", console_normal);
  346. } else {
  347. return print_to_file(f, "%s", color_stack[color_stack.count-1]);
  348. }
  349. }
  350. int print_ptr(FILE* f, void* ptr) {
  351. if (ptr)
  352. return print_to_file(f, "%#0*X", sizeof(void*)*2+2, ptr);
  353. return print_to_file(f, "nullptr");
  354. }
  355. auto print_Str(FILE* f, String* str) -> s32 {
  356. return print_to_file(f, "%.*s", str->length, str->data);
  357. }
  358. auto print_str_line(FILE* f, char* str) -> s32 {
  359. u32 length = 0;
  360. char* str_cpy = str;
  361. while (str[length] != '\0') {
  362. if (str[length] == '\n')
  363. break;
  364. length++;
  365. }
  366. return print_to_file(f, "%.*s", length, str);
  367. }
  368. void init_printer() {
  369. #ifdef FTB_WINDOWS
  370. // enable colored terminal output for windows
  371. HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  372. DWORD dwMode = 0;
  373. GetConsoleMode(hOut, &dwMode);
  374. dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
  375. SetConsoleMode(hOut, dwMode);
  376. #endif
  377. color_stack.alloc();
  378. printer_map.alloc();
  379. type_map.alloc();
  380. system_shutdown_hook << [](){
  381. color_stack.dealloc();
  382. printer_map.dealloc();
  383. type_map.dealloc();
  384. };
  385. register_printer("u32", print_u32, Printer_Function_Type::_32b);
  386. register_printer("u64", print_u64, Printer_Function_Type::_64b);
  387. register_printer("bool", print_bool, Printer_Function_Type::_32b);
  388. register_printer("s64", print_s64, Printer_Function_Type::_64b);
  389. register_printer("s32", print_s32, Printer_Function_Type::_32b);
  390. register_printer("f32", print_flt, Printer_Function_Type::_flt);
  391. register_printer("f64", print_flt, Printer_Function_Type::_flt);
  392. register_printer("->char", print_str, Printer_Function_Type::_ptr);
  393. register_printer("->", print_ptr, Printer_Function_Type::_ptr);
  394. register_printer("color<", print_color_start, Printer_Function_Type::_ptr);
  395. register_printer(">color", print_color_end, Printer_Function_Type::_void);
  396. register_printer("->Str", print_Str, Printer_Function_Type::_ptr);
  397. register_printer("->char_line", print_str_line, Printer_Function_Type::_ptr);
  398. }