From 267d0ec464350f05678492df09850c802399160a Mon Sep 17 00:00:00 2001 From: yukkop Date: Sun, 13 Apr 2025 19:38:11 +0000 Subject: [PATCH] refactor: `hectic` C: logger rules and results --- package/c/hectic/cpp-test.c | 50 ++++ package/c/hectic/hectic.c | 379 ++++++++++-------------- package/c/hectic/hectic.h | 210 ++++++++----- package/c/hectic/make.sh | 11 +- package/c/hectic/test/01-debug.c | 4 +- package/c/hectic/test/02-logger-rules | 16 - package/c/hectic/test/02-logger-rules.c | 29 ++ package/c/hectic/test/03-arena.c | 3 +- package/c/hectic/test/04-json.c | 3 +- package/c/hectic/test/05-slice.c | 5 +- package/c/hectic/test/06-templater.c | 3 +- 11 files changed, 393 insertions(+), 320 deletions(-) create mode 100755 package/c/hectic/cpp-test.c delete mode 100755 package/c/hectic/test/02-logger-rules create mode 100755 package/c/hectic/test/02-logger-rules.c diff --git a/package/c/hectic/cpp-test.c b/package/c/hectic/cpp-test.c new file mode 100755 index 0000000..09f4423 --- /dev/null +++ b/package/c/hectic/cpp-test.c @@ -0,0 +1,50 @@ +// ------------ +// -- Colors -- +// ------------ + +// Color mode enumeration +typedef enum { + COLOR_MODE_AUTO, + COLOR_MODE_FORCE, + COLOR_MODE_DISABLE +} ColorMode; + +// External color mode variable declaration +extern ColorMode color_mode; + +const char* color_mode_to_string(ColorMode mode); + +// 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))) + +/* + * USE_COLOR() is true if color is forced or if color is auto and the output is a terminal. + * used for all colorized output + */ +#define USE_COLOR() ((color_mode == COLOR_MODE_FORCE) || (color_mode == COLOR_MODE_AUTO && IS_TERMINAL())) + +/* + * DEBUG_COLOR_MODE is the color mode for debug output after USE_COLOR() check. + * used for debug colorized output + */ +#define DEBUG_COLOR_MODE COLOR_MODE_FORCE +#define USE_COLOR_IN_DEBUG() (USE_COLOR() ? DEBUG_COLOR_MODE : COLOR_MODE_DISABLE) + +#define COLOR_RED "\033[1;31m" +#define COLOR_GREEN "\033[1;32m" +#define COLOR_YELLOW "\033[1;33m" +#define COLOR_BLUE "\033[1;34m" +#define COLOR_MAGENTA "\033[1;35m" +#define COLOR_CYAN "\033[1;36m" +#define COLOR_WHITE "\033[1;37m" +#define COLOR_RESET "\033[0m" + +#define OPTIONAL_COLOR(color) (USE_COLOR() ? color : "") +#define DEBUG_COLOR(color) (USE_COLOR_IN_DEBUG() ? color : "") + +OPTIONAL_COLOR(COLOR_RED) "Hello" OPTIONAL_COLOR(COLOR_RESET) + +DEBUG_COLOR(COLOR_RED) "Hello" DEBUG_COLOR(COLOR_RESET) diff --git a/package/c/hectic/hectic.c b/package/c/hectic/hectic.c index c932f46..cba3631 100644 --- a/package/c/hectic/hectic.c +++ b/package/c/hectic/hectic.c @@ -32,15 +32,16 @@ char *strsep(char **stringp, const char *delim) { #endif // Forward declarations -void free_log_rules(); const char* json_type_to_string(JsonType type); // Global color mode variable definition ColorMode color_mode = COLOR_MODE_AUTO; +ColorMode debug_color_mode = COLOR_MODE_AUTO; // Global logging variables LogLevel current_log_level = LOG_LEVEL_INFO; LogRule *log_rules = NULL; +Arena *log_rules_arena = NULL; const char* color_mode_to_string(ColorMode mode) { switch (mode) { @@ -67,6 +68,40 @@ void set_output_color_mode(ColorMode mode) { #define CTX_DECLARATION POSITION_INFO_DECLARATION, Arena *arena #define CTX(lifetimed_arena) POSITION_INFO, arena = (lifetimed_arena) +// ----------- +// -- Error -- +// ----------- + +const char* error_code_to_string(HecticErrorCode code) { + switch (code) { + case HECTIC_ERROR_NONE: return "NONE"; + case TEMPLATE_ERROR_NONE: return "NONE"; + case TEMPLATE_ERROR_UNKNOWN_TAG: return "UNKNOWN_TAG"; + case TEMPLATE_ERROR_NESTED_INTERPOLATION: return "NESTED_INTERPOLATION"; + case TEMPLATE_ERROR_NESTED_SECTION_ITERATOR: return "NESTED_SECTION_ITERATOR"; + case TEMPLATE_ERROR_UNEXPECTED_SECTION_END: return "UNEXPECTED_SECTION_END"; + case TEMPLATE_ERROR_NESTED_INCLUDE: return "NESTED_INCLUDE"; + case TEMPLATE_ERROR_NESTED_EXECUTE: return "NESTED_EXECUTE"; + case TEMPLATE_ERROR_INVALID_CONFIG: return "INVALID_CONFIG"; + case TEMPLATE_ERROR_OUT_OF_MEMORY: return "OUT_OF_MEMORY"; + case LOGGER_ERROR_INVALID_RULES_STRING: return "INVALID_RULES_STRING"; + case LOGGER_ERROR_OUT_OF_MEMORY: return "OUT_OF_MEMORY"; + default: return "UNKNOWN"; + } +} + +// ------------ +// -- Result -- +// ------------ + +char *result_type_to_string(ResultType type) { + switch (type) { + case RESULT_ERROR: return "ERROR"; + case RESULT_SOME: return "SOME"; + default: return "UNKNOWN"; + } +} + // ------------ // -- Logger -- // ------------ @@ -120,28 +155,41 @@ LogLevel log_level_from_string(const char *level_str) { void logger_level_reset() { current_log_level = LOG_LEVEL_INFO; - free_log_rules(); + logger_free(); } void logger_level(LogLevel level) { current_log_level = level; - free_log_rules(); // Clear any complex rules + logger_free(); } -void init_logger(void) { +// NOTE(yukkop): This function not uses POSITION_INFO because it's not have a user error. All possible errors are realization errors. +void logger_init(void) { + log_rules_arena = malloc(sizeof(Arena)); + if (!log_rules_arena) { + fprintf(stderr, "INIT: Failed to allocate memory for logger arena\n"); + exit(1); + } + + *log_rules_arena = arena_init__(__FILE__, __func__, __LINE__, 1024); const char* env_level = getenv("LOG_LEVEL"); + printf("INIT: env_level: %s\n", env_level); if (env_level) { // Check if it's a complex rule format (contains '=' or ',') if (strchr(env_level, '=') || strchr(env_level, ',')) { - if (logger_parse_rules(env_level)) { - fprintf(stderr, "INIT: Logger initialized with complex rules from environment\n"); - } else { + printf("INIT: env_level is complex\n"); + LogRuleResult parse_result = logger_parse_rules__(__FILE__, __func__, __LINE__, log_rules_arena, env_level); + if (IS_RESULT_ERROR(parse_result)) { fprintf(stderr, "INIT: Failed to parse complex log rules, using default level INFO\n"); current_log_level = LOG_LEVEL_INFO; + log_rules = arena_alloc__(__FILE__, __func__, __LINE__, log_rules_arena, sizeof(LogRule)); + *log_rules = RESULT_SOME_VALUE(parse_result); + } else { + fprintf(stderr, "INIT: Logger initialized with complex rules from environment\n"); } } else { - // Simple log level + printf("INIT: env_level is simple\n"); current_log_level = log_level_from_string(env_level); fprintf(stderr, "INIT: Logger initialized with level %s from environment\n", log_level_to_string(current_log_level)); @@ -152,6 +200,15 @@ void init_logger(void) { } } +void logger_free(void) { + log_rules = NULL; + if (log_rules_arena) { + arena_free__(__FILE__, __func__, __LINE__, log_rules_arena); + free(log_rules_arena); + log_rules_arena = NULL; + } +} + char* raise_message( LogLevel level, const char *file, @@ -207,6 +264,7 @@ PtrSet *ptrset_init__(POSITION_INFO_DECLARATION, Arena *arena) { } bool debug_ptrset_contains__(PtrSet *set, const void *ptr) { + if (!set) return false; for (size_t i = 0; i < set->size; i++) { if (set->data[i] == ptr) return true; @@ -215,6 +273,7 @@ bool debug_ptrset_contains__(PtrSet *set, const void *ptr) { } void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, const void *ptr) { + if (!set) return; if (set->size == set->capacity) { set->capacity = set->capacity ? set->capacity * 2 : 4; set->data = arena_realloc__(CTX(arena), set->data, set->capacity, set->capacity * sizeof(void*)); @@ -222,8 +281,15 @@ void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, const void *ptr) { set->data[set->size++] = ptr; } +char *enum_to_debug_str__(CTX_DECLARATION, const char *name, size_t enum_value, const char *enum_str) { + return arena_strdup_fmt__(CTX(arena), "%s = %s%s%s %zu ", name, DEBUG_COLOR(COLOR_CYAN), enum_str, DEBUG_COLOR(COLOR_RESET), enum_value); +} + char *string_to_debug_str__(CTX_DECLARATION, const char *name, const char *string) { - return arena_strdup_fmt__(CTX(arena), "%s = %p \"%s\"", name, string, string); + if (!string) { + return arena_strdup_fmt__(CTX(arena), "%s = NULL", name); + } + return arena_strdup_fmt__(CTX(arena), "%s = %s%p%s \"%s\"", name, DEBUG_COLOR(COLOR_CYAN), string, DEBUG_COLOR(COLOR_RESET), string); } char *int_to_debug_str__(CTX_DECLARATION, const char *name, int number) { @@ -239,6 +305,9 @@ char *size_t_to_debug_str__(CTX_DECLARATION, const char *name, size_t number) { } char *ptr_to_debug_str__(CTX_DECLARATION, const char *name, void *ptr) { + if (!ptr) { + return arena_strdup_fmt__(CTX(arena), "%s = NULL", name); + } return arena_strdup_fmt__(CTX(arena), "%s = %p", name, ptr); } @@ -256,12 +325,10 @@ char *debug_join_debug_strings_v(CTX_DECLARATION, int count, va_list args) { va_copy(args_copy, args); raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: Starting first pass"); for (int i = 0; i < count; i++) { - raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter1"); char *s = va_arg(args_copy, char*); int len = strlen(s); raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: String %d: [%s] %p len: %d", i, s, s, len); total_len += len; - raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter2"); } va_end(args_copy); @@ -290,7 +357,7 @@ char *struct_to_debug_str__(CTX_DECLARATION, const char *type, const char *name, char *joined = debug_join_debug_strings_v(CTX(arena), count, args); va_end(args); - return arena_strdup_fmt__(CTX(arena), "%s %s = {%s} %p", type, name, joined, ptr); + return arena_strdup_fmt__(CTX(arena), "%s %s = {%s} %s%p%s", type, name, joined, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); } // ------------ @@ -1447,49 +1514,21 @@ char* slice_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Slice slice) return buffer; } - -// ------------------ -// -- logger rules -- -// ------------------ - -// Clean up existing log rules -void free_log_rules() { - LogRule *rule = log_rules; - while (rule) { - LogRule *next = rule->next; - if (rule->file_pattern) free(rule->file_pattern); - if (rule->function_pattern) free(rule->function_pattern); - free(rule); - rule = next; - } - log_rules = NULL; -} - -// Add a new log rule to the rule chain -LogRule* add_log_rule(LogLevel level, const char *file_pattern, const char *function_pattern, - int line_start, int line_end) { - LogRule *rule = (LogRule*)malloc(sizeof(LogRule)); - if (!rule) return NULL; +/* + * Construct a new log rule + */ +LogRuleResult log_rule_init(Arena *arena, LogLevel level, const char *file_pattern, const char *function_pattern, int line_start, int line_end) { + LogRule *rule = arena_alloc__(__FILE__, __func__, __LINE__, arena, sizeof(LogRule)); + if (!rule) return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_OUT_OF_MEMORY, "Out of memory"); rule->level = level; - rule->file_pattern = file_pattern ? strdup(file_pattern) : NULL; - rule->function_pattern = function_pattern ? strdup(function_pattern) : NULL; + rule->file_pattern = file_pattern ? arena_strdup__(__FILE__, __func__, __LINE__, arena, file_pattern) : NULL; + rule->function_pattern = function_pattern ? arena_strdup__(__FILE__, __func__, __LINE__, arena, function_pattern) : NULL; rule->line_start = line_start; rule->line_end = line_end; rule->next = NULL; - // Add to the end of the list - if (!log_rules) { - log_rules = rule; - } else { - LogRule *last = log_rules; - while (last->next) { - last = last->next; - } - last->next = rule; - } - - return rule; + return RESULT_SOME(LogRuleResult, *rule); } // Parse a line range specification (start:end) @@ -1514,15 +1553,16 @@ void parse_line_range(const char *range_str, int *start, int *end) { } // Parse a complex rule string and set up log rules -int logger_parse_rules(const char *rules_str) { - if (!rules_str || !*rules_str) return 0; - - // Clean up existing rules - free_log_rules(); +LogRuleResult logger_parse_rules__(CTX_DECLARATION, const char *rules_str) { + if (!rules_str || !*rules_str) return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_INVALID_RULES_STRING, "Invalid rules string"); // Make a copy of the rules string since we'll be modifying it - char *rules_copy = strdup(rules_str); - if (!rules_copy) return 0; + char *rules_copy = arena_strdup__(CTX(arena), rules_str); + if (!rules_copy) return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_OUT_OF_MEMORY, "Out of memory"); + + // Initialize the rules list + LogRule *rules = NULL; + LogRule **current = &rules; // First rule sets the default level char *next_rule = rules_copy; @@ -1586,11 +1626,25 @@ int logger_parse_rules(const char *rules_str) { // Create a new rule LogLevel level = log_level_from_string(level_str); - add_log_rule(level, file_pattern, function_pattern, line_start, line_end); + LogRuleResult rule_result = log_rule_init(arena, level, file_pattern, function_pattern, line_start, line_end); + + if (IS_RESULT_ERROR(rule_result)) { + free(rules_copy); + return rule_result; + } + + // Add the rule to the list + *current = arena_alloc__(CTX(arena), sizeof(LogRule)); + if (!*current) { + free(rules_copy); + return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_OUT_OF_MEMORY, "Out of memory"); + } + + **current = RESULT_SOME_VALUE(rule_result); + current = &(*current)->next; } - free(rules_copy); - return 1; + return RESULT_SOME(LogRuleResult, *rules); } // Check if a file matches a pattern @@ -1637,9 +1691,21 @@ LogLevel logger_get_effective_level(const char *file, const char *func, int line } // Add a new log rule programmatically -int logger_add_rule(LogLevel level, const char *file_pattern, const char *function_pattern, - int line_start, int line_end) { - return add_log_rule(level, file_pattern, function_pattern, line_start, line_end) != NULL; +HecticError logger_add_rule(Arena *arena, LogRule *rules, LogLevel level, const char *file_pattern, const char *function_pattern, int line_start, int line_end) { + LogRuleResult init_result = log_rule_init(arena, level, file_pattern, function_pattern, line_start, line_end); + if (IS_RESULT_ERROR(init_result)) { + return RESULT_ERROR_VALUE(init_result); + } + if (!rules) { + *rules = RESULT_SOME_VALUE(init_result); + } else { + LogRule *last = rules; + while (last->next) { + last = last->next; + } + *last->next = RESULT_SOME_VALUE(init_result); + } + return (HecticError){ .code = HECTIC_ERROR_NONE, .message = NULL }; } // Print all current logging rules to stderr @@ -1662,83 +1728,10 @@ void logger_print_rules() { } } -// Helper to format a rule as a string -static void format_rule_to_buffer(char *buffer, size_t size, LogRule *rule) { - char line_range[32] = ""; - - // Format line range if specified - if (rule->line_start > 0) { - if (rule->line_end > 0 && rule->line_end != rule->line_start) { - snprintf(line_range, sizeof(line_range), "%d:%d", rule->line_start, rule->line_end); - } else { - snprintf(line_range, sizeof(line_range), "%d", rule->line_start); - } - } - - // Format the complete rule - if (rule->file_pattern && rule->function_pattern && line_range[0]) { - // File + function + line range - snprintf(buffer, size, "%s@%s@%s=%s", - rule->file_pattern, rule->function_pattern, line_range, - log_level_to_string(rule->level)); - } else if (rule->file_pattern && rule->function_pattern) { - // File + function - snprintf(buffer, size, "%s@%s=%s", - rule->file_pattern, rule->function_pattern, - log_level_to_string(rule->level)); - } else if (rule->file_pattern && line_range[0]) { - // File + line range - snprintf(buffer, size, "%s@%s=%s", - rule->file_pattern, line_range, - log_level_to_string(rule->level)); - } else if (rule->file_pattern) { - // Just file - snprintf(buffer, size, "%s=%s", - rule->file_pattern, - log_level_to_string(rule->level)); - } else { - // Empty rule (shouldn't happen) - snprintf(buffer, size, "EMPTY=%s", log_level_to_string(rule->level)); - } -} - -// Format all rules into a string -char* logger_rules_to_string(Arena *arena) { - if (!arena) return NULL; - - // Allocate a buffer in the arena (estimate size needed) - size_t estimated_size = 1024; // Start with 1KB - char *buffer = arena_alloc(arena, estimated_size); - if (!buffer) return NULL; - - // Initialize with default level - int pos = snprintf(buffer, estimated_size, "%s", log_level_to_string(current_log_level)); - - // Add each rule - for (LogRule *rule = log_rules; rule; rule = rule->next) { - // Format the rule - char rule_str[256]; - format_rule_to_buffer(rule_str, sizeof(rule_str), rule); - - // Check buffer space and add to result - if (pos + strlen(rule_str) + 2 < estimated_size) { - buffer[pos++] = ','; - strcpy(buffer + pos, rule_str); - pos += strlen(rule_str); - } else { - // Buffer too small, just stop - strcat(buffer, ",..."); - break; - } - } - - return buffer; -} - char *log_rules_to_debug_str__(CTX_DECLARATION, char *name, LogRule *self, PtrSet *visited) { char *result = arena_alloc(arena, MEM_KiB); STRUCT_TO_DEBUG_STR(arena, result, LogRule, name, self, visited, 6, - string_to_debug_str__(POSITION_INFO, arena, "level", log_level_to_string(self->level)), + enum_to_debug_str__(POSITION_INFO, arena, "level", self->level, log_level_to_string(self->level)), string_to_debug_str__(POSITION_INFO, arena, "file_pattern", self->file_pattern), string_to_debug_str__(POSITION_INFO, arena, "function_pattern", self->function_pattern), int_to_debug_str__(POSITION_INFO, arena, "line_start", self->line_start), @@ -1808,18 +1801,15 @@ bool template_validate_config__(POSITION_INFO_DECLARATION, const TemplateConfig #define TEMPLATE_ASSERT_SYNTAX(pattern, message_arg, code_arg) \ if (strncmp(*s, pattern, strlen(pattern))) { \ raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \ - result->type = RESULT_ERROR; \ - result->Result.Error.code = code_arg; \ - result->Result.Error.message = message_arg; \ - return result; \ + return RESULT_ERROR(TemplateResult, code_arg, message_arg); \ } -TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config); +TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config); -TemplateResult *template_parse_interpolation__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { +TemplateResult template_parse_interpolation__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Interpolation"); - TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); + TemplateResult result; const char **s = s_ptr; @@ -1839,22 +1829,22 @@ TemplateResult *template_parse_interpolation__(POSITION_INFO_DECLARATION, Arena } size_t key_len = *s - key_start; - result->Result.some.value.interpolate.key = arena_strncpy__(POSITION_INFO, arena, key_start, key_len); + result.type = RESULT_SOME; - result->type = RESULT_SOME; - result->Result.some.type = TEMPLATE_NODE_INTERPOLATE; + result.Result.some.value.interpolate.key = arena_strncpy__(POSITION_INFO, arena, key_start, key_len); + result.Result.some.type = TEMPLATE_NODE_INTERPOLATE; *s_ptr = *s + strlen(config->Syntax.Braces.close); return result; } -TemplateResult *template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { +TemplateResult template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Section"); - TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); - result->type = RESULT_SOME; - result->Result.some.type = TEMPLATE_NODE_SECTION; + TemplateResult result; + result.type = RESULT_SOME; + result.Result.some.type = TEMPLATE_NODE_SECTION; const char **s = s_ptr; @@ -1876,7 +1866,7 @@ TemplateResult *template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena } size_t iterator_len = *s - iterator_start; - result->Result.some.value.section.iterator = arena_strncpy__(POSITION_INFO, arena, iterator_start, iterator_len); + result.Result.some.value.section.iterator = arena_strncpy__(POSITION_INFO, arena, iterator_start, iterator_len); // Find the collection name *s = skip_whitespace(*s); @@ -1891,26 +1881,26 @@ TemplateResult *template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena } size_t collection_len = *s - collection_start; - result->Result.some.value.section.collection = arena_strncpy__(POSITION_INFO, arena, collection_start, collection_len); + result.Result.some.value.section.collection = arena_strncpy__(POSITION_INFO, arena, collection_start, collection_len); // Parse the body - TemplateResult *body_result = template_parse__(POSITION_INFO, arena, s, config); - if (body_result->type == RESULT_ERROR) { + TemplateResult body_result = template_parse__(POSITION_INFO, arena, s, config); + if (body_result.type == RESULT_ERROR) { return body_result; } - result->Result.some.value.section.body = &body_result->Result.some; + result.Result.some.value.section.body = &body_result.Result.some; *s_ptr = *s + strlen(config->Syntax.Braces.close); return result; } -TemplateResult *template_parse_include__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { +TemplateResult template_parse_include__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Include"); - TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); - result->type = RESULT_SOME; - result->Result.some.type = TEMPLATE_NODE_INCLUDE; + TemplateResult result; + result.type = RESULT_SOME; + result.Result.some.type = TEMPLATE_NODE_INCLUDE; const char **s = s_ptr; @@ -1930,19 +1920,19 @@ TemplateResult *template_parse_include__(POSITION_INFO_DECLARATION, Arena *arena } size_t include_len = *s - include_start; - result->Result.some.value.include.key = arena_strncpy__(POSITION_INFO, arena, include_start, include_len); + result.Result.some.value.include.key = arena_strncpy__(POSITION_INFO, arena, include_start, include_len); *s_ptr = *s + strlen(config->Syntax.Braces.close); return result; } -TemplateResult *template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { +TemplateResult template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Execute"); - TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); - result->type = RESULT_SOME; - result->Result.some.type = TEMPLATE_NODE_EXECUTE; + TemplateResult result; + result.type = RESULT_SOME; + result.Result.some.type = TEMPLATE_NODE_EXECUTE; const char **s = s_ptr; @@ -1959,24 +1949,24 @@ TemplateResult *template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena } size_t code_len = *s - code_start; - result->Result.some.value.execute.code = arena_strncpy__(POSITION_INFO, arena, code_start, code_len); + result.Result.some.value.execute.code = arena_strncpy__(POSITION_INFO, arena, code_start, code_len); *s_ptr = *s + strlen(config->Syntax.Braces.close); return result; } -TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config) { +TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Iteration start"); if (!template_validate_config__(POSITION_INFO, config)) { raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Invalid config"); - return NULL; + return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_INVALID_CONFIG, "Invalid config"); } if (!arena) { raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Arena is NULL"); - return NULL; + return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_OUT_OF_MEMORY, "Out of memory"); } const char *start = *s; @@ -1997,7 +1987,7 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const } // Deside tag type by prefix - TemplateResult *current_result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); + TemplateResult current_result; { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Found tag"); @@ -2019,22 +2009,14 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const current_result = template_parse_execute__(POSITION_INFO, arena, s, config); } else { raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Unknown tag prefix: %s", slice_create__(POSITION_INFO, 1, (char *)tag_prefix, strlen(tag_prefix), 0, TEMPLATE_MAX_PREFIX_LEN)); - - TemplateResult *error_result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); - error_result->type = RESULT_ERROR; - error_result->Result.Error.code = TEMPLATE_ERROR_UNKNOWN_TAG; - error_result->Result.Error.message = "Unknown tag prefix"; - - return error_result; + return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_UNKNOWN_TAG, "Unknown tag prefix"); } + + TRY(current_result); } - if (current_result->type == RESULT_ERROR) { - return current_result; - } - - *current = current_result->Result.some; + *current = current_result.Result.some; current->next = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateNode)); current = current->next; } @@ -2048,33 +2030,13 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const current->value.text.content = arena_strncpy__(POSITION_INFO, arena, start, *s - start); } - TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); - result->type = RESULT_SOME; - result->Result.some = *root; - - return result; + return RESULT_SOME(TemplateResult, *root); } #undef TEMPLATE_ASSERT_SYNTAX #define TEMPLATE_NODE_MAX_DEBUG_DEPTH 20 -const char *template_error_code_to_string(TemplateErrorCode code) { - switch (code) { - case TEMPLATE_ERROR_NONE: return "NONE"; - case TEMPLATE_ERROR_UNKNOWN_TAG: return "UNKNOWN_TAG"; - case TEMPLATE_ERROR_NESTED_INTERPOLATION: return "NESTED_INTERPOLATION"; - case TEMPLATE_ERROR_UNEXPECTED_SECTION_END: return "UNEXPECTED_SECTION_END"; - case TEMPLATE_ERROR_NESTED_SECTION_ITERATOR: return "NESTED_SECTION_ITERATOR"; - case TEMPLATE_ERROR_NESTED_INCLUDE: return "NESTED_INCLUDE"; - case TEMPLATE_ERROR_NESTED_EXECUTE: return "NESTED_EXECUTE"; - default: { - raise_exception("HECTICLIB ERROR: Unknown template error code: %d", code); - return "UNKNOWN"; - }; - } -} - char *template_node_type_to_string(TemplateNodeType type) { switch (type) { case TEMPLATE_NODE_SECTION: return "SECTION"; @@ -2089,19 +2051,6 @@ char *template_node_type_to_string(TemplateNodeType type) { } } -//char *log_rules_to_debug_str__(CTX_DECLARATION, char *name, LogRule *self, PtrSet *visited) { -// char *result = arena_alloc(arena, MEM_KiB); -// STRUCT_TO_DEBUG_STR(arena, result, LogRule, name, self, visited, 6, -// string_to_debug_str__(POSITION_INFO, arena, "level", log_level_to_string(self->level)), -// string_to_debug_str__(POSITION_INFO, arena, "file_pattern", self->file_pattern), -// string_to_debug_str__(POSITION_INFO, arena, "function_pattern", self->function_pattern), -// int_to_debug_str__(POSITION_INFO, arena, "line_start", self->line_start), -// int_to_debug_str__(POSITION_INFO, arena, "line_end", self->line_end), -// log_rules_to_debug_str__(POSITION_INFO, arena, "next", self->next, visited) -// ); -// return result; -//} - char *template_section_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateSectionValue *self, PtrSet *visited) { char *result = arena_alloc(arena, MEM_KiB); STRUCT_TO_DEBUG_STR(arena, result, TemplateSectionValue, name, self, visited, 3, diff --git a/package/c/hectic/hectic.h b/package/c/hectic/hectic.h index 7f9afd3..a56d640 100644 --- a/package/c/hectic/hectic.h +++ b/package/c/hectic/hectic.h @@ -34,6 +34,7 @@ typedef enum { // External color mode variable declaration extern ColorMode color_mode; +extern ColorMode debug_color_mode; const char* color_mode_to_string(ColorMode mode); @@ -42,8 +43,19 @@ void set_output_color_mode(ColorMode mode); // Macros for detecting terminal and color usage #define IS_TERMINAL() (isatty(fileno(stderr))) + +/* + * USE_COLOR() is true if color is forced or if color is auto and the output is a terminal. + * used for all colorized output + */ #define USE_COLOR() ((color_mode == COLOR_MODE_FORCE) || (color_mode == COLOR_MODE_AUTO && IS_TERMINAL())) +/* + * DEBUG_COLOR_MODE is the color mode for debug output after USE_COLOR() check. + * used for debug colorized output + */ +#define USE_COLOR_IN_DEBUG() (color_mode == COLOR_MODE_AUTO ? ((debug_color_mode == COLOR_MODE_FORCE) || (debug_color_mode == COLOR_MODE_AUTO && IS_TERMINAL())) : USE_COLOR()) + #define COLOR_RED "\033[1;31m" #define COLOR_GREEN "\033[1;32m" #define COLOR_YELLOW "\033[1;33m" @@ -54,37 +66,26 @@ void set_output_color_mode(ColorMode mode); #define COLOR_RESET "\033[0m" #define OPTIONAL_COLOR(color) (USE_COLOR() ? color : "") +#define DEBUG_COLOR(color) (USE_COLOR_IN_DEBUG() ? color : "") + +// ------------ +// -- Errors -- +// ------------ typedef enum { - RESULT_ERROR, - RESULT_SOME, -} ResultType; - -#define RESULT(name, result_type, error_type) \ - typedef struct { \ - ResultType type; \ - union { \ - struct { \ - error_type code; \ - char *message; \ - } Error; \ - result_type some; \ - } Result; \ - } name##Result - -#define IS_RESULT_ERROR(result) (result->type == RESULT_ERROR) -#define IS_RESULT_SOME(result) (result->type == RESULT_SOME) - -#define TRY(result) if (IS_RESULT_ERROR(result)) { return result; } - -#define RESULT_ERROR_CODE(result) (result->Result.error.code) -#define RESULT_ERROR_MESSAGE(result) (result->Result.error.message) - -#define RESULT_SOME_VALUE(result) (result->Result.some) - -// ------------ -// -- Errors -- -// ------------ + HECTIC_ERROR_NONE = 0, + TEMPLATE_ERROR_NONE = 985567, + TEMPLATE_ERROR_UNKNOWN_TAG = 985568, + TEMPLATE_ERROR_NESTED_INTERPOLATION = 985569, + TEMPLATE_ERROR_NESTED_SECTION_ITERATOR = 985570, + TEMPLATE_ERROR_UNEXPECTED_SECTION_END = 985571, + TEMPLATE_ERROR_NESTED_INCLUDE = 985572, + TEMPLATE_ERROR_NESTED_EXECUTE = 985573, + TEMPLATE_ERROR_INVALID_CONFIG = 985574, + TEMPLATE_ERROR_OUT_OF_MEMORY = 985575, + LOGGER_ERROR_INVALID_RULES_STRING = 985576, + LOGGER_ERROR_OUT_OF_MEMORY = 985577, +} HecticErrorCode; // Define color macros based on output type //#define ERROR_PREFIX PP_CAT(COLOR_RED, "Error: ") @@ -97,6 +98,55 @@ typedef enum { #define todo fprintf(stderr, "%sNot implimented yet%s", COLOR_RED, COLOR_RESET);exit(1) +// ------------ +// -- Result -- +// ------------ + +typedef enum { + RESULT_ERROR, + RESULT_SOME, +} ResultType; + +char *result_type_to_string(ResultType type); + +typedef struct { + HecticErrorCode code; + char *message; +} HecticError; + +#define RESULT(name, some_type) \ + typedef struct { \ + ResultType type; \ + union { \ + HecticError error; \ + some_type some; \ + } Result; \ + } name##Result + +typedef struct { + ResultType type; + union { + HecticError error; + } Result; +} EmptyResult; + +#define IS_RESULT_ERROR(result) (result.type == RESULT_ERROR) +#define IS_RESULT_SOME(result) (result.type == RESULT_SOME) + +#define TRY(result) if (IS_RESULT_ERROR(result)) { return result; } + +#define RESULT_ERROR_CODE(result) (result.Result.error.code) +#define RESULT_ERROR_MESSAGE(result) (result.Result.error.message) + +#define RESULT_SOME_VALUE(result) (result.Result.some) +#define RESULT_ERROR_VALUE(result) (result.Result.error) + +#define RESULT_SOME(result_type, value) \ + (result_type) { .type = RESULT_SOME, .Result.some = value } + +#define RESULT_ERROR(result_type, error_code, error_message) \ + (result_type) { .type = RESULT_ERROR, .Result.error = { .code = error_code, .message = error_message } } + // ------------ // -- Logger -- // ------------ @@ -171,51 +221,14 @@ typedef struct LogRule { void logger_level_reset(); -void init_logger(void); +void logger_init(void); + +void logger_free(void); void logger_level(LogLevel level); LogLevel log_level_from_string(const char *level_str); -typedef enum { - PLACEHOLDER_ERROR, -} LogRuleParseError; - -RESULT(LogParse, LogRule, LogRuleParseError); - -/* - * Set complex logging rules from a string - * Format: DEFAULT_LEVEL,@=LEVEL,@:=LEVEL,... - * Example: "INFO,main.c@main=DEBUG,helper.c@10:50=TRACE" - * - * @param rules_str The rule string to parse - * @return 1 on success, 0 on failure - */ -int logger_parse_rules(const char *rules_str); - -/* - * Set complex logging rule programmatically - * - * @param level Log level for this rule - * @param file_pattern File pattern to match (NULL for any file) - * @param function_pattern Function pattern to match (NULL for any function) - * @param line_start Start line number (-1 for any) - * @param line_end End line number (-1 for any) - * @return 1 on success, 0 on failure - */ -int logger_add_rule(LogLevel level, const char *file_pattern, const char *function_pattern, - int line_start, int line_end); - -/* - * Get the effective log level for a message based on complex rules - * - * @param file Source file where log was generated - * @param func Function where log was generated - * @param line Line number where log was generated - * @return The effective log level for this context - */ -LogLevel logger_get_effective_level(const char *file, const char *func, int line); - /** * Core logging function that formats and outputs log messages. * @@ -423,6 +436,8 @@ char *char_to_debug_str__(const char *file, const char *func, int line, Arena *a char *struct_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *type, const char *name, const void *ptr, int count, ...); +#define ENUM_TO_DEBUG_STR(arena, name, enum_value, enum_str) \ + enum_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, enum_value, enum_str) #define STRING_TO_DEBUG_STR(arena, name, string) \ string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string) #define INT_TO_DEBUG_STR(arena, name, number) \ @@ -453,6 +468,49 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr); buffer = struct_to_debug_str__(__FILE__, __func__, __LINE__, arena, #type, name, ptr, count, ##__VA_ARGS__); \ } while (0) +// ------------------ +// -- Logger Rules -- +// ------------------ + +RESULT(LogRule, LogRule); + +/* + * Set complex logging rules from a string + * Format: DEFAULT_LEVEL,@=LEVEL,@:=LEVEL,... + * Example: "INFO,main.c@main=DEBUG,helper.c@10:50=TRACE" + * + * @param rules_str The rule string to parse + * @return a LogRuleResult containing the LogRule* or an Error + */ +LogRuleResult logger_parse_rules__(const char *file, const char *func, int line, Arena *arena, const char *rules_str); + +/* + * Set complex logging rule programmatically + * + * @param level Log level for this rule + * @param file_pattern File pattern to match (NULL for any file) + * @param function_pattern Function pattern to match (NULL for any function) + * @param line_start Start line number (-1 for any) + * @param line_end End line number (-1 for any) + * @return 1 on success, 0 on failure + */ +HecticError logger_add_rule(Arena *arena, LogRule *rules, LogLevel level, const char *file_pattern, const char *function_pattern, int line_start, int line_end); + +/* + * Get the effective log level for a message based on complex rules + * + * @param file Source file where log was generated + * @param func Function where log was generated + * @param line Line number where log was generated + * @return The effective log level for this context + */ +LogLevel logger_get_effective_level(const char *file, const char *func, int line); + +char *log_rules_to_debug_str__(const char *file, const char *func, int line, Arena *arena, char *name, LogRule *self, PtrSet *visited); + +#define LOG_RULES_TO_DEBUG_STR(arena, name, self) \ + log_rules_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, self, ptrset_init(arena)) + // ---------- // -- Json -- // ---------- @@ -626,16 +684,6 @@ typedef union { TemplateTextValue text; } TemplateValue; -typedef enum { - TEMPLATE_ERROR_NONE, - TEMPLATE_ERROR_UNKNOWN_TAG, - TEMPLATE_ERROR_NESTED_INTERPOLATION, - TEMPLATE_ERROR_NESTED_SECTION_ITERATOR, - TEMPLATE_ERROR_UNEXPECTED_SECTION_END, - TEMPLATE_ERROR_NESTED_INCLUDE, - TEMPLATE_ERROR_NESTED_EXECUTE, -} TemplateErrorCode; - struct TemplateNode { TemplateNodeType type; TemplateValue value; @@ -643,9 +691,9 @@ struct TemplateNode { TemplateNode *next; // sibling nodes }; -RESULT(Template, TemplateNode, TemplateErrorCode); +RESULT(Template, TemplateNode); -TemplateResult *template_parse__(const char *file, const char *func, int line, Arena *arena, const char **s, const TemplateConfig *config); +TemplateResult template_parse__(const char *file, const char *func, int line, Arena *arena, const char **s, const TemplateConfig *config); TemplateConfig template_default_config__(const char *file, const char *func, int line); diff --git a/package/c/hectic/make.sh b/package/c/hectic/make.sh index b0e0f57..afff883 100644 --- a/package/c/hectic/make.sh +++ b/package/c/hectic/make.sh @@ -84,7 +84,7 @@ while [ $# -gt 0 ]; do done MODE="${1:-build}" -shift > /dev/null +shift 2> /dev/null if [ -n "$COLOR_FLAG" ]; then CFLAGS="$CFLAGS $COLOR_FLAG" @@ -118,12 +118,19 @@ case "$MODE" in esac done + # Check if any requested test doesn't exist + for test in "${TESTS_TO_RUN[@]}"; do + if [ ! -f "test/${test}.c" ]; then + echo "Error: Test '${test}' not found in test directory" + exit 1 + fi + done + echo "TESTS_TO_RUN: ${TESTS_TO_RUN[@]}" for test_file in test/*.c; do test_name=$(basename "${test_file%.c}") # Skip if specific tests are requested and this isn't one of them - # TODO: error on unknown test file if [ ${#TESTS_TO_RUN[@]} -ne 0 ] && ! [[ " ${TESTS_TO_RUN[*]} " =~ " ${test_name} " ]]; then continue fi diff --git a/package/c/hectic/test/01-debug.c b/package/c/hectic/test/01-debug.c index 0cae17e..5ceb1c3 100755 --- a/package/c/hectic/test/01-debug.c +++ b/package/c/hectic/test/01-debug.c @@ -81,7 +81,8 @@ void test_struct2_to_debug_str(Arena *arena) { int main(void) { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); + debug_color_mode = COLOR_MODE_DISABLE; + logger_init(); Arena arena = arena_init(MEM_MiB); @@ -92,6 +93,7 @@ int main(void) { test_struct2_to_debug_str(&arena); arena_free(&arena); + logger_free(); printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); return 0; } \ No newline at end of file diff --git a/package/c/hectic/test/02-logger-rules b/package/c/hectic/test/02-logger-rules deleted file mode 100755 index 8b23aca..0000000 --- a/package/c/hectic/test/02-logger-rules +++ /dev/null @@ -1,16 +0,0 @@ -#include "hectic.h" -#include - -int main(void) { - printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); - - Arena arena = arena_init(MEM_MiB); - - char *rules = arena_alloc(&arena, MEM_KiB); - strcpy(rules, "trace:file:test.c:100-150"); - - arena_free(&arena); - printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - return 0; -} \ No newline at end of file diff --git a/package/c/hectic/test/02-logger-rules.c b/package/c/hectic/test/02-logger-rules.c new file mode 100755 index 0000000..fa56754 --- /dev/null +++ b/package/c/hectic/test/02-logger-rules.c @@ -0,0 +1,29 @@ +#include "hectic.h" +#include + +void test_parse_rules(Arena *arena) { + char *rules = arena_alloc(arena, MEM_KiB); + strcpy(rules, "ERROR,02-logger-rules.c@5:13=INFO,hectic.c@arena_alloc__=NOTICE"); + + LogRuleResult result = logger_parse_rules__(__FILE__, __func__, __LINE__, arena, rules); + + raise_notice("result.type: %s", result_type_to_string(result.type)); + assert(result.type != RESULT_ERROR); + + raise_notice("result.some: %s", LOG_RULES_TO_DEBUG_STR(arena, "result.some", &RESULT_SOME_VALUE(result))); +} + +int main(void) { + printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); + debug_color_mode = COLOR_MODE_DISABLE; + logger_init(); + + Arena arena = arena_init(MEM_MiB); + + test_parse_rules(&arena); + + arena_free(&arena); + logger_free(); + printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); + return 0; +} \ No newline at end of file diff --git a/package/c/hectic/test/03-arena.c b/package/c/hectic/test/03-arena.c index a7cb118..0dce57b 100644 --- a/package/c/hectic/test/03-arena.c +++ b/package/c/hectic/test/03-arena.c @@ -92,7 +92,7 @@ void test_arena_overwrite_detection() { int main() { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); + logger_init(); test_arena_init(); test_arena_alloc(); @@ -103,6 +103,7 @@ int main() { test_arena_repstr(); test_arena_overwrite_detection(); + logger_free(); printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); return 0; } diff --git a/package/c/hectic/test/04-json.c b/package/c/hectic/test/04-json.c index 693ec8a..a502f2c 100644 --- a/package/c/hectic/test/04-json.c +++ b/package/c/hectic/test/04-json.c @@ -125,7 +125,7 @@ static void test_arena_reset_reuse(void) { int main(void) { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); + logger_init(); test_parse_json_object(); test_parse_json_number(); @@ -137,6 +137,7 @@ int main(void) { test_nested_json_object(); test_arena_reset_reuse(); + logger_free(); printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); return 0; } diff --git a/package/c/hectic/test/05-slice.c b/package/c/hectic/test/05-slice.c index ba34a59..9388276 100644 --- a/package/c/hectic/test/05-slice.c +++ b/package/c/hectic/test/05-slice.c @@ -84,14 +84,15 @@ void test_slice_string() { int main() { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); + logger_init(); test_slice_create(); test_slice_subslice(); test_slice_copy(); test_slice_edge_cases(); test_slice_string(); - + + logger_free(); printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); return 0; } \ No newline at end of file diff --git a/package/c/hectic/test/06-templater.c b/package/c/hectic/test/06-templater.c index 2984584..63c5326 100755 --- a/package/c/hectic/test/06-templater.c +++ b/package/c/hectic/test/06-templater.c @@ -71,7 +71,7 @@ static void test_template_node_to_debug_str(Arena *arena) { int main(void) { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); - init_logger(); + logger_init(); Arena arena = arena_init(ARENA_SIZE); @@ -87,6 +87,7 @@ int main(void) { //printf("%sTest 1: template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET)); //arena_reset(&arena); + logger_free(); arena_free(&arena); printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); return 0;