diff --git a/package/c/hectic/cpp-test.c b/package/c/hectic/cpp-test.c index 5097091..200c52f 100755 --- a/package/c/hectic/cpp-test.c +++ b/package/c/hectic/cpp-test.c @@ -1,16 +1,7 @@ -// ------------ -// -- 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; +extern ColorMode debug_color_mode; const char* color_mode_to_string(ColorMode mode); @@ -30,7 +21,7 @@ void set_output_color_mode(ColorMode mode); * DEBUG_COLOR_MODE is the color mode for debug output after USE_COLOR() check. * used for debug colorized output */ -#define USE_COLOR_IN_DEBUG() (USE_COLOR() ? DEBUG_COLOR_MODE : COLOR_MODE_DISABLE) +#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" @@ -44,6 +35,5 @@ void set_output_color_mode(ColorMode mode); #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 21abb8d..f6f381b 100644 --- a/package/c/hectic/hectic.c +++ b/package/c/hectic/hectic.c @@ -288,7 +288,7 @@ void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, const void *ptr, const cha } 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); + return arena_strdup_fmt__(CTX(arena), "%senum%s %s = %s%s%s %zu ", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), 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) { @@ -321,6 +321,53 @@ char *char_to_debug_str__(CTX_DECLARATION, const char *name, char c) { return arena_strdup_fmt__(CTX(arena), "%s = %c", name, c); } +char *union_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *type, const char *name, const void *ptr, size_t active_variant, size_t count, ...) { + if (count % 2 == 0) { + raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "HECTICLIB ERROR: Union to debug str: count is even"); + assert(0); + } + + va_list args; + va_start(args, count); + + char *value = NULL; + bool variant_exists = false; + + // Find the matching value for the active variant + while (count--) { + size_t variant = va_arg(args, size_t); + if (variant == (size_t)-1) break; // End marker + + if (variant == active_variant) { + variant_exists = true; + value = va_arg(args, char*); + break; + } + // Skip the string value for non-matching variants + va_arg(args, char*); + } + + va_end(args); + + if (!variant_exists) { + return arena_strdup_fmt__(file, func, line, arena, + "%sunion%s %s %s = {invalid variant %d} %s%p%s", + DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), + type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); + } + + if (!value) { + return arena_strdup_fmt__(file, func, line, arena, + "%sunion%s %s %s = {unknown variant} %s%p%s", + DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), + type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); + } + + return arena_strdup_fmt__(file, func, line, arena, + "%sunion%s %s %s = %s %s%p%s", + DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), + type, name, value, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); +} /* Private function */ char *debug_join_debug_strings_v(CTX_DECLARATION, int count, va_list args) { @@ -363,7 +410,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} %s%p%s", type, name, joined, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); + return arena_strdup_fmt__(CTX(arena), "%sstruct%s %s %s = {%s} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), type, name, joined, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); } // ------------ @@ -2099,15 +2146,15 @@ char *template_text_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena return result; } -char *template_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateValue *self, PtrSet *visited) { +char *template_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateValue *self, TemplateNodeType type, PtrSet *visited) { char *result = arena_alloc(arena, MEM_KiB); - STRUCT_TO_DEBUG_STR(arena, result, TemplateValue, name, self, visited, 5, - template_section_value_to_debug_str__(POSITION_INFO, arena, "section", &self->section, visited), - template_interpolate_value_to_debug_str__(POSITION_INFO, arena, "interpolate", &self->interpolate, visited), - template_execute_value_to_debug_str__(POSITION_INFO, arena, "execute", &self->execute, visited), - template_include_value_to_debug_str__(POSITION_INFO, arena, "include", &self->include, visited), - template_text_value_to_debug_str__(POSITION_INFO, arena, "text", &self->text, visited) + UNION_TO_DEBUG_STR(arena, result, TemplateValue, name, self, visited, type, 5, + TEMPLATE_NODE_SECTION, template_section_value_to_debug_str__(POSITION_INFO, arena, "section", &self->section, visited), + TEMPLATE_NODE_INTERPOLATE, template_interpolate_value_to_debug_str__(POSITION_INFO, arena, "interpolate", &self->interpolate, visited), + TEMPLATE_NODE_EXECUTE, template_execute_value_to_debug_str__(POSITION_INFO, arena, "execute", &self->execute, visited), + TEMPLATE_NODE_INCLUDE, template_include_value_to_debug_str__(POSITION_INFO, arena, "include", &self->include, visited), + TEMPLATE_NODE_TEXT, template_text_value_to_debug_str__(POSITION_INFO, arena, "text", &self->text, visited) ); return result; } @@ -2116,7 +2163,7 @@ char *template_node_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, cons char *result = arena_alloc(arena, MEM_KiB); STRUCT_TO_DEBUG_STR(arena, result, TemplateNode, name, self, visited, 4, string_to_debug_str__(POSITION_INFO, arena, "type", template_node_type_to_string(self->type)), - template_value_to_debug_str__(POSITION_INFO, arena, "value", &self->value, visited), + template_value_to_debug_str__(POSITION_INFO, arena, "value", &self->value, self->type, visited), template_node_to_debug_str__(POSITION_INFO, arena, "children", self->children, visited), template_node_to_debug_str__(POSITION_INFO, arena, "next", self->next, visited) ); diff --git a/package/c/hectic/hectic.h b/package/c/hectic/hectic.h index 5f92f44..5cb4e8e 100644 --- a/package/c/hectic/hectic.h +++ b/package/c/hectic/hectic.h @@ -438,6 +438,8 @@ char *ptr_to_debug_str__(const char *file, const char *func, int line, Arena *ar char *char_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, char c); +char *union_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *type, const char *name, const void *ptr, size_t active_variant, size_t count, ...); + 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, ...); bool debug_ptrset_contains(PtrSet *set, void *ptr); @@ -457,6 +459,21 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr); #define CHAR_TO_DEBUG_STR(arena, name, c) \ char_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, c) +#define UNION_TO_DEBUG_STR(arena, buffer, type, name, ptr, visited, active_variant, count, ...) do { \ + if (!name) \ + name = "$1"; \ + \ + if (debug_ptrset_contains__(visited, ptr, #type, name)) \ + return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \ + \ + if (!ptr) \ + return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \ + \ + debug_ptrset_add__(__FILE__, __func__, __LINE__, arena, visited, ptr, #type, name); \ + \ + buffer = union_to_debug_str__(__FILE__, __func__, __LINE__, arena, #type, name, ptr, active_variant, count, ##__VA_ARGS__); \ +} while (0) + /* * STRUCT_TO_DEBUG_STR - Converts a structure into a debug string. * @@ -487,19 +504,16 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr); name = "$1"; \ \ if (debug_ptrset_contains__(visited, ptr, #type, name)) \ - return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = {cycle detected} %p", #type, name, ptr); \ + return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \ \ if (!ptr) \ - return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%s %s = NULL", #type, name); \ + return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \ \ debug_ptrset_add__(__FILE__, __func__, __LINE__, arena, visited, ptr, #type, name); \ \ buffer = struct_to_debug_str__(__FILE__, __func__, __LINE__, arena, #type, name, ptr, count, ##__VA_ARGS__); \ } while (0) -#define UNION_TO_DEBUG_STR(arena, buffer, type, name, ptr, visited, count, ...) \ - STRUCT_TO_DEBUG_STR(arena, buffer, type, name, ptr, visited, count, ##__VA_ARGS__) - // ------------------ // -- Logger Rules -- // ------------------ diff --git a/package/c/hectic/test/01-debug.c b/package/c/hectic/test/01-debug.c index a4be226..2109498 100755 --- a/package/c/hectic/test/01-debug.c +++ b/package/c/hectic/test/01-debug.c @@ -20,6 +20,18 @@ struct Struct2 { Struct *other; }; +typedef enum TestUnionVariant { + TEST_UNION_VARIANT_A, + TEST_UNION_VARIANT_B, + TEST_UNION_VARIANT_C +} TestUnionVariant; + +typedef union TestUnion { + int a; + char *b; + float c; +} TestUnion; + char *struct_to_debug_str(Arena *arena, char *name, Struct *self, PtrSet *visited) { raise_trace("struct_to_debug_str: name: %s, self: %p, visited: %p", name, self, visited); @@ -48,6 +60,18 @@ char *struct2_to_debug_str(Arena *arena, char *name, Struct2 *self, PtrSet *visi return result; } +char *test_union_to_debug_str(Arena *arena, char *name, TestUnion *self, PtrSet *visited, TestUnionVariant active_variant) { + raise_trace("test_union_to_debug_str: name: %s, self: %p, visited: %p, active_variant: %zu", name, self, visited, active_variant); + + char *result = arena_alloc(arena, MEM_KiB); + UNION_TO_DEBUG_STR(arena, result, TestUnion, name, self, visited, active_variant, 3, + TEST_UNION_VARIANT_A, INT_TO_DEBUG_STR(arena, "a", self->a), + TEST_UNION_VARIANT_B, STRING_TO_DEBUG_STR(arena, "b", self->b), + TEST_UNION_VARIANT_C, FLOAT_TO_DEBUG_STR(arena, "c", self->c) + ); + return result; +} + void test_struct_to_debug_str(Arena *arena) { // Mock a struct with a cycle Struct test_struct = {.a = 1, .b = 2, .next = NULL}; @@ -58,7 +82,7 @@ void test_struct_to_debug_str(Arena *arena) { raise_notice("result: %s", result); char *check = arena_alloc(arena, MEM_KiB); - sprintf(check, "Struct struct = {a = 1, b = 2, Struct next = {a = 1, b = 2, Struct next = {cycle detected} %p} %p} %p", (void*)&test_struct, (void*)&test_struct, (void*)&test_struct); + sprintf(check, "struct Struct struct = {a = 1, b = 2, struct Struct next = {a = 1, b = 2, struct Struct next = {cycle detected} %p} %p} %p", (void*)&test_struct, (void*)&test_struct, (void*)&test_struct); raise_notice("check: %s", check); assert(strcmp(result, check) == 0); } @@ -74,7 +98,18 @@ void test_struct2_to_debug_str(Arena *arena) { char *result = struct2_to_debug_str(arena, "struct2", &test_struct2, visited); raise_notice("result: %s", result); char *check = arena_alloc(arena, MEM_KiB); - sprintf(check, "Struct2 struct2 = {a = 1, f = 3.140000, c = %p \"hello\", Struct other = {a = 1, b = 2, Struct next = {a = 1, b = 2, Struct next = {cycle detected} %p} %p} %p, Struct2 left = NULL} %p", (void*)test_struct2.c,(void*)&test_struct, (void*)&test_struct, (void*)&test_struct, (void*)&test_struct2); + sprintf(check, "struct Struct2 struct2 = {a = 1, f = 3.140000, c = %p \"hello\", struct Struct other = {a = 1, b = 2, struct Struct next = {a = 1, b = 2, struct Struct next = {cycle detected} %p} %p} %p, struct Struct2 left = NULL} %p", (void*)test_struct2.c,(void*)&test_struct, (void*)&test_struct, (void*)&test_struct, (void*)&test_struct2); + raise_notice("check: %s", check); + assert(strcmp(result, check) == 0); +} + +void test_test_union_to_debug_str(Arena *arena) { + TestUnion test_union = {.a = 1}; + PtrSet *visited = ptrset_init(arena); + char *result = test_union_to_debug_str(arena, "test_union", &test_union, visited, TEST_UNION_VARIANT_A); + raise_notice("result: %s", result); + char *check = arena_alloc(arena, MEM_KiB); + sprintf(check, "union TestUnion test_union = {a = 1} %p", (void*)&test_union); raise_notice("check: %s", check); assert(strcmp(result, check) == 0); } @@ -92,6 +127,9 @@ int main(void) { printf("%sTesting struct_to_debug_str2%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET)); test_struct2_to_debug_str(&arena); + printf("%sTesting test_union_to_debug_str%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET)); + test_test_union_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));