--- /dev/null
+#ifndef _COMMONLIB_H_\r
+#define _COMMONLIB_H_\r
+#include <stdio.h>\r
+#include <stdbool.h>\r
+#include <stdarg.h>\r
+#include <stdint.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <assert.h>\r
+\r
+// Memory allocation\r
+#define C_MALLOC malloc\r
+#define C_FREE free\r
+#define C_REALLOC realloc\r
+#define C_MEMCPY memcpy\r
+\r
+// Remove Prefix\r
+#ifdef COMMONLIB_REMOVE_PREFIX\r
+#define ASSERT c_ASSERT\r
+#define ARRAY_LEN c_ARRAY_LEN\r
+\r
+#define da_append c_da_append\r
+#define DYNAMIC_ARRAY_INITIAL_CAPACITY c_DYNAMIC_ARRAY_INITIAL_CAPACITY\r
+// #define c_DYNAMIC_ARRAY_INITIAL_CAPACITY\r
+\r
+#define os_get_timedate c_os_get_timedate\r
+#define os_file_exists c_os_file_exists\r
+\r
+#define log_error c_log_error\r
+#define log_info c_log_info\r
+#define log_warning c_log_warning\r
+\r
+#define slurp_file c_slurp_file\r
+#define touch_file_if_doesnt_exist c_touch_file_if_doesnt_exist\r
+\r
+#define Arena c_Arena\r
+#define Arena_make c_Arena_make\r
+#define Arena_alloc c_Arena_alloc\r
+#define Arena_reset c_Arena_reset\r
+#define Arena_free c_Arena_free\r
+#define Arena_alloc_str c_Arena_alloc_str\r
+#define Arena_alloc_wstr c_Arena_alloc_wstr\r
+\r
+#define String_view c_String_view\r
+\r
+#define shift_args c_shift_args\r
+\r
+#endif // COMMONLIB_REMOVE_PREFIX\r
+\r
+// typedefs\r
+typedef unsigned int uint;\r
+typedef uint8_t uint8;\r
+typedef uint16_t uint16;\r
+typedef uint32_t uint32;\r
+typedef uint64_t uint64;\r
+\r
+typedef int8_t int8;\r
+typedef int16_t int16;\r
+typedef int32_t int32;\r
+typedef int64_t int64;\r
+\r
+typedef float float32;\r
+typedef double float64;\r
+\r
+typedef wchar_t wchar;\r
+\r
+typedef const char* cstr;\r
+typedef const wchar* wstr;\r
+\r
+\r
+// Macros\r
+#define c_ASSERT(condition, msg) do {\\r
+ if (!(condition)) {\\r
+ fprintf(stderr, "%s:%d:0 [ASSERTION FAILED] %s: %s", __FILE__, __LINE__, #condition, msg);\\r
+ exit(1);\\r
+ }\\r
+ } while (0)\r
+\r
+#define c_ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))\r
+\r
+#define c_pop_front(xs, xsz) (assert(xsz > 0 && "Array is empty"), xsz--, *xs++)\r
+#define c_shift_args c_pop_front\r
+\r
+//\r
+// Struct pre-decls\r
+//\r
+\r
+typedef struct c_Arena c_Arena;\r
+\r
+//\r
+// ## Data Structures\r
+//\r
+\r
+//\r
+// Dynamic-Array\r
+//\r
+\r
+// NOTE: To use c_da_append() the Dynamic-Array struct should be defined using\r
+// DEFINE_DYNAMIC_ARRAY or have the same members as below!\r
+// NOTE!!!: We actually don't want this since this makes the user want to \r
+// use this macro to define dynamic arrays. But the user might want extra fields\r
+// in the struct; So we recommend defining da structs manually like:\r
+// ```C\r
+// typedef struct {\r
+// <item-type> items;\r
+// size_t count;\r
+// size_t capacity;\r
+// [extra fields...];\r
+// }\r
+// ```\r
+// #define DEFINE_DYNAMIC_ARRAY(struct_name, elm_type) typedef struct {\r
+// elm_type *items;\r
+// size_t count;\r
+// size_t capacity;\r
+// }\r
+\r
+#define c_DYNAMIC_ARRAY_INITIAL_CAPACITY (sizeof(size_t))\r
+\r
+#define c_da_append(da, elm) do {\\r
+ if ((da).items == NULL) {\\r
+ (da).capacity = c_DYNAMIC_ARRAY_INITIAL_CAPACITY;\\r
+ (da).count = 0;\\r
+ (da).items = C_MALLOC(sizeof(elm) * (da).capacity);\\r
+ }\\r
+ if ((da).count >= (da).capacity) {\\r
+ (da).capacity *= 2;\\r
+ (da).items = C_REALLOC((da).items, (da).capacity * sizeof(elm));\\r
+ c_ASSERT((da).items != NULL, "TODO: Log error instead of asserting");\\r
+ }\\r
+ (da).items[(da).count++] = elm;\\r
+ } while (0)\r
+\r
+#define c_da_pop_front(da) (c_ASSERT(da.count > 0, "Array is empty"), da.count--, *da.items++)\r
+\r
+//\r
+// OS\r
+//\r
+\r
+#if defined(__linux__)\r
+#include <sys/stat.h>\r
+#endif\r
+\r
+void c_os_get_timedate(c_Arena* a);\r
+bool c_os_file_exists(cstr filename);\r
+\r
+//\r
+// Logging\r
+//\r
+\r
+#define c_log_error(fmt, ...) do {\\r
+ fprintf(stderr, "%s"fmt"\n", "[ERROR] ", ##__VA_ARGS__);\\r
+ } while (0)\r
+#define c_log_info(fmt, ...) do {\\r
+ fprintf(stdout, "%s"fmt"\n", "[INFO] ", ##__VA_ARGS__);\\r
+ } while (0)\r
+#define c_log_warning(fmt, ...) do {\\r
+ fprintf(stdout, "%s"fmt"\n", "[WARNING] ", ##__VA_ARGS__);\\r
+ } while (0)\r
+\r
+//\r
+// File\r
+//\r
+\r
+// reads entire file and gives back the string holding the contents. (caller must be responsible for freeing the string!)\r
+const char* c_slurp_file(const char* filename, bool* success);\r
+void c_touch_file_if_doesnt_exist(cstr file);\r
+\r
+//\r
+// ### Allocators ###\r
+//\r
+\r
+//\r
+// c_Arena\r
+//\r
+\r
+#define ARENA_BUFF_INITIAL_SIZE (1024*4)\r
+\r
+struct c_Arena {\r
+ void* buff;\r
+ uint64 buff_size;\r
+ void* ptr;\r
+};\r
+\r
+// pass size 0 to get ARENA_BUFF_INITIAL_SIZE\r
+c_Arena c_Arena_make(size_t size);\r
+void* c_Arena_alloc(c_Arena* a, size_t size);\r
+void c_Arena_reset(c_Arena* a);\r
+void c_Arena_free(c_Arena* a);\r
+\r
+#define c_Arena_alloc_str(a, fmt, ...) c_Arena_alloc(&(a), sizeof(char)*stbsp_snprintf((a).ptr, (int)((a).buff_size - ((uint8*)(a).ptr - (uint8*)(a).buff)), (fmt), __VA_ARGS__)+1)\r
+#define c_Arena_alloc_wstr(a, fmt, ...) c_Arena_alloc(&a, sizeof(char)*wprintf(a.ptr, a.buff_size - ((uint8*)a.ptr - (uint8*)a.buff), (fmt), __VA_ARGS__)+1)\r
+\r
+//\r
+// String Builder\r
+//\r
+\r
+typedef struct {\r
+ char* data;\r
+ size_t size;\r
+ size_t capacity;\r
+} c_String_builder;\r
+\r
+void c_sb_append(c_String_builder* sb, char* data);\r
+\r
+//\r
+// String view\r
+//\r
+\r
+typedef struct {\r
+ char *data;\r
+ size_t count;\r
+} c_String_view;\r
+\r
+#define c_SV_FMT "%.*s"\r
+#define c_SV_ARG(sv) (int)sv.count, sv.data\r
+\r
+#define c_SV(cstr) (c_String_view){.data = cstr, strlen(cstr)}\r
+\r
+void c_sv_print_dumb(c_String_view sv);\r
+c_String_view c_sv_from_cstr(const char* cstr); // Actually just use SV(cstr) macro...\r
+c_String_view c_sv_lpop(c_String_view* sv, uint32 n);\r
+c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int));\r
+c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int));\r
+c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch);\r
+c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch);\r
+void c_sv_lremove(c_String_view* sv, size_t n);\r
+void c_sv_rremove(c_String_view* sv, size_t n);\r
+void c_sv_lremove_until_char(c_String_view* sv, char ch);\r
+void c_sv_rremove_until_char(c_String_view* sv, char ch);\r
+void c_sv_lremove_until_char_after(c_String_view* sv, char ch);\r
+void c_sv_rremove_until_char_after(c_String_view* sv, char ch);\r
+void c_sv_ltrim(c_String_view* sv);\r
+void c_sv_rtrim(c_String_view* sv);\r
+void c_sv_trim(c_String_view* sv);\r
+char* c_sv_to_cstr(c_String_view sv);\r
+int32 c_sv_to_int(c_String_view sv);\r
+uint64 c_sv_to_uint64(c_String_view sv);\r
+uint8 c_sv_to_uint8_hex(c_String_view sv);\r
+void* c_sv_to_ptr(c_String_view sv);\r
+float32 c_sv_to_float(c_String_view sv);\r
+bool c_sv_contains_char(c_String_view sv, char ch);\r
+bool c_sv_is_hex_numbers(c_String_view sv);\r
+bool c_sv_equals(c_String_view sv1, c_String_view sv2);\r
+\r
+#endif /* _COMMONLIB_H_ */\r
+\r
+//////////////////////////////////////////////////\r
+#ifdef COMMONLIB_IMPLEMENTATION\r
+#include <string.h>\r
+#include <errno.h>\r
+#include <stdlib.h>\r
+\r
+// My things implementation:\r
+\r
+//\r
+// OS\r
+//\r
+\r
+#if defined(_WIN32) || defined(__CYGWIN__)\r
+void c_os_get_timedate(c_Arena* a) {\r
+ (void)a;\r
+ c_ASSERT(false, "Unimplemented!");\r
+}\r
+\r
+bool c_os_file_exists(cstr filename) {\r
+ (void) filename;\r
+ c_ASSERT(false, "Unimplemented!");\r
+ return false;\r
+}\r
+\r
+#elif defined(__linux__)\r
+void c_os_get_timedate(c_Arena* a) {\r
+ (void)a;\r
+ c_ASSERT(false, "Unimplemented!");\r
+}\r
+\r
+bool c_os_file_exists(cstr filename) {\r
+ struct stat buf;\r
+ return stat(filename, &buf) == 0;\r
+}\r
+#endif\r
+\r
+// simple and dirty way to have defering in C (not recommended to use!)\r
+#define defer(ret_val) \\r
+ result = ret_val;\\r
+ goto defer\r
+\r
+// TODO: Refactor error messages\r
+const char *c_slurp_file(const char* filename, bool* success) {\r
+ FILE* f = fopen(filename, "rb");\r
+ char* result = NULL;\r
+\r
+ if (f == NULL){\r
+ c_log_error("slurp_file::fopen(\"%s\", \"rb\") -> %s\n", filename, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ if (fseek(f, 0, SEEK_END) < 0) {\r
+ c_log_error("slurp_file::fseek(%s, 0, SEEK_END) -> %s\n", filename, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ size_t fsize = ftell(f);\r
+\r
+ if (fsize == (size_t)-1){\r
+ c_log_error("slurp_file::ftell(%s) -> %s\n", filename, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ result = C_MALLOC(sizeof(char)*(fsize+1));\r
+\r
+ if (result == NULL){\r
+ c_log_error("slurp_file::malloc(%zu) -> %s\n", sizeof(char)*fsize, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ if (fseek(f, 0, SEEK_SET) < 0) {\r
+ c_log_error("slurp_file::fseek(%s, 0, SEEK_SET) -> %s\n", filename, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ if (fread((char*)result, sizeof(char), fsize, f) != fsize){\r
+ c_log_error("slurp_file::fread(result, %zu, 1, f) -> %s\n", fsize, strerror(errno));\r
+ defer(NULL);\r
+ }\r
+\r
+ // set null-terminator\r
+ result[fsize] = '\0';\r
+\r
+ defer:\r
+ if (f) fclose(f);\r
+ *success = result != NULL;\r
+ return result;\r
+}\r
+\r
+void c_touch_file_if_doesnt_exist(cstr filename) {\r
+ if (c_os_file_exists(filename)) return;\r
+ FILE* file = fopen(filename, "w");\r
+ if (file) fclose(file);\r
+}\r
+\r
+//\r
+// ### Allocators ###\r
+//\r
+\r
+// c_Arena\r
+\r
+c_Arena c_Arena_make(size_t size) {\r
+ c_Arena res = {0};\r
+ res.buff_size = size == 0 ? ARENA_BUFF_INITIAL_SIZE : size;\r
+ res.buff = C_MALLOC(res.buff_size);\r
+ res.ptr = res.buff;\r
+\r
+ c_ASSERT(res.buff, "Malloc failed?");\r
+\r
+ return res;\r
+}\r
+\r
+void* c_Arena_alloc(c_Arena* a, size_t size) {\r
+ c_ASSERT(a->buff, "Bro pass an initialized arena!");\r
+\r
+ void* res = a->ptr;\r
+ a->ptr = (uint8*)a->ptr + size;\r
+\r
+ size_t diff = (size_t)((uint8*)a->ptr - (uint8*)a->buff);\r
+ if (diff > a->buff_size) {\r
+ c_log_info("c_Arena resized from %zu to %zu", a->buff_size, a->buff_size*2);\r
+ a->buff_size *= 2;\r
+ a->buff = C_REALLOC(a->buff, a->buff_size);\r
+ a->ptr = (uint8*)a->buff + diff;\r
+ res = a->ptr;\r
+ a->ptr = (uint8*)a->ptr + size;\r
+ }\r
+ /* c_ASSERT((size_t)((uint8*)a->ptr - (uint8*)a->buff) <= a->buff_size); */\r
+\r
+ return res;\r
+}\r
+\r
+void c_Arena_reset(c_Arena* a) {\r
+ a->ptr = a->buff;\r
+}\r
+\r
+void c_Arena_free(c_Arena* a) {\r
+ C_FREE(a->buff);\r
+}\r
+\r
+//\r
+// String Builder\r
+//\r
+\r
+void c_sb_append(c_String_builder* sb, char* data) {\r
+ size_t data_size = strlen(data);\r
+ if (sb->size + data_size > sb->capacity) {\r
+ sb->capacity *= 2;\r
+ sb->data = C_REALLOC(sb->data, sb->capacity);\r
+ }\r
+\r
+ // void *memcpy(void dest[restrict .n], const void src[restrict .n],\r
+ C_MEMCPY((void *)((uintptr_t)sb->data + (uintptr_t)sb->data), data, data_size);\r
+ sb->size += data_size;\r
+}\r
+\r
+//\r
+// String view\r
+//\r
+\r
+void c_sv_print_dumb(c_String_view sv){\r
+ for (size_t i = 0; i < (size_t)sv.count; ++i){\r
+ putc(*(sv.data+i), stdout);\r
+ }\r
+}\r
+\r
+c_String_view c_sv_from_cstr(const char* cstr){\r
+ return (c_String_view){\r
+ .data = (char *)cstr,\r
+ .count = strlen(cstr),\r
+ };\r
+}\r
+\r
+c_String_view c_sv_lpop(c_String_view* sv, uint32 n) {\r
+ c_String_view res = {0};\r
+ if (sv->count < n) return res;\r
+ res.data = sv->data;\r
+ res.count = n;\r
+\r
+ sv->data += n;\r
+ sv->count -= n;\r
+\r
+ return res;\r
+}\r
+\r
+c_String_view c_sv_lpop_until_predicate(c_String_view* sv, int(*predicate)(int)){\r
+ const char* old_sv_data = sv->data;\r
+ while (sv->count > 0 && !predicate(*sv->data)){\r
+ sv->data++;\r
+ sv->count--;\r
+ }\r
+\r
+ return (c_String_view){\r
+ .data = sv->data - (sv->data - old_sv_data),\r
+ .count = (sv->data - old_sv_data),\r
+ };\r
+}\r
+\r
+c_String_view c_sv_rpop_until_predicate(c_String_view* sv, int(*predicate)(int)){\r
+ size_t old_sv_count = sv->count;\r
+ while (sv->count > 0 && !predicate(*(sv->data+sv->count-1))){\r
+ sv->count--;\r
+ }\r
+\r
+ return (c_String_view){\r
+ .data = sv->data + sv->count,\r
+ .count = old_sv_count - sv->count,\r
+ };\r
+}\r
+\r
+c_String_view c_sv_lpop_until_char(c_String_view* sv, char ch){\r
+ const char* old_sv_data = sv->data;\r
+ while (sv->count > 0 && *sv->data != ch){\r
+ sv->data++;\r
+ sv->count--;\r
+ }\r
+\r
+ return (c_String_view){\r
+ .data = sv->data - (sv->data - old_sv_data),\r
+ .count = (sv->data - old_sv_data),\r
+ };\r
+}\r
+\r
+c_String_view c_sv_rpop_until_char(c_String_view* sv, char ch){\r
+ size_t old_sv_count = sv->count;\r
+ while (sv->count > 0 && *(sv->data+sv->count-1) != ch){\r
+ sv->count--;\r
+ }\r
+\r
+ return (c_String_view){\r
+ .data = sv->data + sv->count,\r
+ .count = old_sv_count - sv->count,\r
+ };\r
+}\r
+\r
+void c_sv_lremove(c_String_view* sv, size_t n){\r
+ if (n > sv->count) n = sv->count;\r
+\r
+ sv->data += n;\r
+ sv->count -= n;\r
+}\r
+\r
+void c_sv_rremove(c_String_view* sv, size_t n){\r
+ if (n > sv->count)\r
+ sv->count = 0;\r
+ else\r
+ sv->count -= n;\r
+}\r
+\r
+void c_sv_lremove_until_char(c_String_view* sv, char ch){\r
+ while (sv->count > 0 && *sv->data != ch){\r
+ sv->data++;\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_rremove_until_char(c_String_view* sv, char ch){\r
+ while (sv->count > 0 && *(sv->data+sv->count-1) != ch){\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_lremove_until_char_after(c_String_view* sv, char ch){\r
+ while (sv->count > 0 && *(sv->data-1) != ch){\r
+ sv->data++;\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_rremove_until_char_after(c_String_view* sv, char ch){\r
+ while (sv->count > 0 && *(sv->data+sv->count) != ch){\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_ltrim(c_String_view* sv){\r
+ while (sv->count > 0 && isspace(*sv->data)){\r
+ sv->data++;\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_rtrim(c_String_view* sv){\r
+ while (sv->count > 0 && isspace(*(sv->data+sv->count-1))){\r
+ sv->count--;\r
+ }\r
+}\r
+\r
+void c_sv_trim(c_String_view* sv){\r
+ c_sv_ltrim(sv);\r
+ c_sv_rtrim(sv);\r
+}\r
+\r
+char* c_sv_to_cstr(c_String_view sv){\r
+ char* res = (char*)calloc(1, sizeof(char)*sv.count);\r
+ C_MEMCPY(res, sv.data, sv.count);\r
+ return res;\r
+}\r
+\r
+// TODO: check for failure of conversion. returns 0/0.0 on failure, so just check if the str contains zero.\r
+int32 c_sv_to_int(c_String_view sv) {\r
+ char* str = c_sv_to_cstr(sv);\r
+ int32 res = atoi(str);\r
+ C_FREE(str);\r
+ return res;\r
+}\r
+\r
+uint64 c_sv_to_uint64(c_String_view sv) {\r
+ char* str = c_sv_to_cstr(sv);\r
+ uint64 res = (uint64)atoll(str);\r
+ C_FREE(str);\r
+ return res;\r
+}\r
+\r
+uint8 c_sv_to_uint8_hex(c_String_view sv) {\r
+ char* str = c_sv_to_cstr(sv);\r
+ char* end = str + sv.count;\r
+ uint8 res = (uint8)strtol(str, &end, 16);\r
+ C_FREE(str);\r
+ return res;\r
+}\r
+\r
+float32 c_sv_to_float(c_String_view sv) {\r
+ char* str = c_sv_to_cstr(sv);\r
+ float32 res = (float32)atof(str);\r
+ C_FREE(str);\r
+ return res;\r
+}\r
+\r
+void* c_sv_to_ptr(c_String_view sv) {\r
+ char* str = c_sv_to_cstr(sv);\r
+ char* end = NULL;\r
+ void* res = (void*)strtoull(str, &end, 16);\r
+ C_FREE(str);\r
+ return res;\r
+}\r
+\r
+bool c_sv_contains_char(c_String_view sv, char ch){\r
+ for (size_t i = 0; i < sv.count; ++i){\r
+ if (sv.data[i] == ch) return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool c_sv_is_hex_numbers(c_String_view sv) {\r
+ char hex[] = {\r
+ '0', '1', '2', '3', '4', '5', '6', '7',\r
+ '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f',\r
+ 'A', 'B', 'C', 'D', 'E', 'F'\r
+ };\r
+ bool found = false;\r
+ for (size_t i = 0; i < sv.count; ++i) {\r
+ char c = sv.data[i];\r
+ for (size_t j = 0; j < c_ARRAY_LEN(hex); ++j) {\r
+ if (hex[j] == c) {\r
+ found = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ return found;\r
+}\r
+\r
+bool c_sv_equals(c_String_view sv1, c_String_view sv2) {\r
+ if (sv1.count != sv2.count) return false;\r
+ for (size_t i = 0; i < sv1.count; ++i) {\r
+ if (sv1.data[i] != sv2.data[i]) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+#endif\r