#ifndef EPRINTF_HECTIC #define EPRINTF_HECTIC // NOTE(yukkop): definitions and features from the POSIX.1-2008 standard #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include // ------------- // -- Helpers -- // ------------- // Helper macros for argument counting // NOTE(yukkop): this ugly macroses for avoid all posible warnings #define PP_CAT(a, b) a##b // ------------ // -- Colors -- // ------------ // Color mode enumeration typedef enum { COLOR_MODE_AUTO, COLOR_MODE_FORCE, COLOR_MODE_DISABLE } ColorMode; // Static color mode variable static ColorMode color_mode __attribute__((unused)) = COLOR_MODE_AUTO; // Function to set color mode void set_output_color_mode(ColorMode mode); // Macros for detecting terminal and color usage #define IS_TERMINAL() (isatty(fileno(stderr))) #define USE_COLOR() ((color_mode == COLOR_MODE_FORCE) || (color_mode == COLOR_MODE_AUTO && IS_TERMINAL())) #define COLOR_RED (USE_COLOR() ? "\033[1;31m" : "") #define COLOR_RESET (USE_COLOR() ? "\033[0m" : "") // ------------ // -- Errors -- // ------------ // Define color macros based on output type //#define ERROR_PREFIX PP_CAT(COLOR_RED, "Error: ") //#define ERROR_SUFFIX PP_CAT(COLOR_RESET, "\n") #define ERROR_PREFIX (USE_COLOR() ? "\033[1;31mError: " : "Error: ") #define ERROR_SUFFIX (USE_COLOR() ? "\033[0m\n" : "\n") // eprintf handling 1 or more arguments #define eprintf(fmt, ...) "%s" fmt "%s", ERROR_PREFIX, ##__VA_ARGS__, ERROR_SUFFIX #define todo fprintf(stderr, "%sNot implimented yet%s", COLOR_RED, COLOR_RESET);exit(1) // ------------ // -- Logger -- // ------------ typedef enum { LOG_LEVEL_TRACE, LOG_LEVEL_DEBUG, LOG_LEVEL_LOG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_WARN, LOG_LEVEL_EXCEPTION } LogLevel; void logger_level_reset(); void init_logger(void); void logger_level(LogLevel level); LogLevel log_level_from_string(const char *level_str); char* raise_message(LogLevel level, const char *file, const char *func, int line, const char *format, ...); #ifndef PRECOMPILED_LOG_LEVEL #define PRECOMPILED_LOG_LEVEL LOG_LEVEL_TRACE // default level #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_TRACE #define raise_trace(...) ((void)0) // log removed at compile time #else #define raise_trace(...) raise_message(LOG_LEVEL_TRACE, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_DEBUG #define raise_debug(...) ((void)0) #else #define raise_debug(...) raise_message(LOG_LEVEL_DEBUG, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_LOG #define raise_log(...) ((void)0) #else #define raise_log(...) raise_message(LOG_LEVEL_LOG, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_INFO #define raise_info(...) ((void)0) #else #define raise_info(...) raise_message(LOG_LEVEL_INFO, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_NOTICE #define raise_notice(...) ((void)0) #else #define raise_notice(...) raise_message(LOG_LEVEL_NOTICE, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_WARN #define raise_warn(...) ((void)0) #else #define raise_warn(...) raise_message(LOG_LEVEL_WARN, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif #if PRECOMPILED_LOG_LEVEL > LOG_LEVEL_EXCEPTION #define raise_exception(...) ((void)0) #else #define raise_exception(...) raise_message(LOG_LEVEL_EXCEPTION, __FILE__, __func__, __LINE__, ##__VA_ARGS__) #endif // ----------- // -- arena -- // ----------- #define ARENA_DEFAULT_SIZE MEM_MiB typedef struct { void *begin; void *current; size_t capacity; } Arena; Arena arena_init__(const char *file, const char *func, int line, size_t size); void* arena_alloc_or_null__(const char *file, const char *func, int line, Arena *arena, size_t size); void* arena_alloc__(const char *file, const char *func, int line, Arena *arena, size_t size); void arena_reset__(const char *file, const char *func, int line, Arena *arena); void arena_free__(const char *file, const char *func, int line, Arena *arena); char* arena_strdup__(const char *file, const char *func, int line, Arena *arena, const char *s); char* arena_repstr__(const char *file, const char *func, int line, Arena *arena, const char *src, size_t start, size_t len, const char *rep); void* arena_realloc_copy__(const char *file, const char *func, int line, Arena *arena, void *old_ptr, size_t old_size, size_t new_size); // NOTE(yukkop): This macro is used to define procedures so that `__LINE__` and `__FILE__` // in `raise_debug` reflect the location where the macro is called, not where it's defined. #define arena_alloc_or_null(arena, size) \ arena_alloc_or_null__(__FILE__, __func__, __LINE__, arena, size) #define arena_init(size) \ arena_init__(__FILE__, __func__, __LINE__, size) #define arena_reset(arena) \ arena_reset__(__FILE__, __func__, __LINE__, arena) #define arena_free(arena) \ arena_free__(__FILE__, __func__, __LINE__, arena) #define arena_alloc(arena, size) \ arena_alloc__(__FILE__, __func__, __LINE__, arena, size) #define arena_strdup(arena, s) \ arena_strdup__(__FILE__, __func__, __LINE__, arena, s) #define arena_repstr(arena, src, start, len, rep) \ arena_repstr__(__FILE__, __func__, __LINE__, arena, src, start, len, rep) #define arena_realloc_copy(arena, old_ptr, old_size, new_size) \ arena_realloc_copy__(__FILE__, __func__, __LINE__, arena, old_ptr, old_size, new_size) // ---------- // -- misc -- // ---------- #define MEM_b 1 #define MEM_KiB 1024 #define MEM_MiB (MEM_KiB * 1024) #define MEM_GiB (MEM_MiB * 1024) #define MEM_TiB (MEM_TiB * 1024) #define MEM_PiB (MEM_TiB * 1024) #define MEM_EiB (MEM_PiB * 1024) #define MEM_ZiB (MEM_EiB * 1024) #define MEM_YiB (MEM_ZiB * 1024) #define MEM_RiB (MEM_YiB * 1024) #define MEM_QiB (MEM_RiB * 1024) void substr_clone__(const char *file, const char *func, int line, const char * const src, char *dest, size_t from, size_t len); #define substr_clone(src, dest, from, len) substr_clone__(__FILE__, __LINE__, src, dest, from, len) // ---------- // -- Json -- // ---------- typedef enum { JSON_NORAW = 0, JSON_RAW = 1, } JsonRawOpt; typedef enum { JSON_NULL, JSON_BOOL, JSON_NUMBER, JSON_STRING, JSON_ARRAY, JSON_OBJECT, } JsonType; /* Full JSON structure */ typedef struct Json { struct Json *next; /* Next sibling */ struct Json *child; /* Child element (for arrays/objects) */ JsonType type; char *key; /* Key if item is in an object */ union { double number; char *string; int boolean; } JsonValue; } Json; Json *json_parse(Arena *arena, const char **s); char *json_to_string(Arena *arena, const Json * const item); char *json_to_string_with_opts(Arena *arena, const Json * const item, JsonRawOpt raw); /* Retrieve an object item by key (case-sensitive) */ Json *json_get_object_item(const Json * const object, const char * const key); // ----------- // -- Slice -- // ----------- typedef struct { void *data; size_t len; size_t isize; } Slice; // Usage: // printf("Content: %.*s\n", SLICE_ARGS(slice, char)); // printf("Content: %d\n", SLICE_ARGS(slice, int)); #define SLICE_ARGS(slice, type) ((int)((slice).len / sizeof(type))), ((type*)((slice).data)) Slice slice_create__(const char *file, const char *func, int line, size_t isize, void *array, size_t array_len, size_t start, size_t len); Slice slice_subslice__(const char *file, const char *func, int line, Slice s, size_t start, size_t len); int* arena_slice_copy__(const char *file, const char *func, int line, Arena *arena, Slice s); #define slice_create(type, array, array_len, start, len) \ slice_create__(__FILE__, __func__, __LINE__, sizeof(type), array, array_len, start, len) #define slice_subslice(s, start, len) \ slice_subslice__(__FILE__, __func__, __LINE__, s, start, len) #define arena_slice_copy(arena, s) \ arena_slice_copy__(__FILE__, __func__, __LINE__, arena, s) #define SLICE_TO_STRING(type, slice, fmt) __extension__ ({ \ size_t count = (slice).len / (slice).isize; \ size_t bufsize = count * 32 + 1; \ char *buf = malloc(bufsize); \ if (buf) { \ buf[0] = '\0'; \ for (size_t i = 0; i < count; i++) { \ char temp[32]; \ snprintf(temp, sizeof(temp), fmt " ", \ ((type *)((slice).data))[i]); \ strncat(buf, temp, bufsize - strlen(buf) - 1); \ } \ } \ buf; \ }) #endif // EPRINTF_H