You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

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