Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

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