refactor: hectic C: logger rules and results
This commit is contained in:
50
package/c/hectic/cpp-test.c
Executable file
50
package/c/hectic/cpp-test.c
Executable file
@@ -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)
|
||||||
@@ -32,15 +32,16 @@ char *strsep(char **stringp, const char *delim) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
void free_log_rules();
|
|
||||||
const char* json_type_to_string(JsonType type);
|
const char* json_type_to_string(JsonType type);
|
||||||
|
|
||||||
// Global color mode variable definition
|
// Global color mode variable definition
|
||||||
ColorMode color_mode = COLOR_MODE_AUTO;
|
ColorMode color_mode = COLOR_MODE_AUTO;
|
||||||
|
ColorMode debug_color_mode = COLOR_MODE_AUTO;
|
||||||
|
|
||||||
// Global logging variables
|
// Global logging variables
|
||||||
LogLevel current_log_level = LOG_LEVEL_INFO;
|
LogLevel current_log_level = LOG_LEVEL_INFO;
|
||||||
LogRule *log_rules = NULL;
|
LogRule *log_rules = NULL;
|
||||||
|
Arena *log_rules_arena = NULL;
|
||||||
|
|
||||||
const char* color_mode_to_string(ColorMode mode) {
|
const char* color_mode_to_string(ColorMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -67,6 +68,40 @@ void set_output_color_mode(ColorMode mode) {
|
|||||||
#define CTX_DECLARATION POSITION_INFO_DECLARATION, Arena *arena
|
#define CTX_DECLARATION POSITION_INFO_DECLARATION, Arena *arena
|
||||||
#define CTX(lifetimed_arena) POSITION_INFO, arena = (lifetimed_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 --
|
// -- Logger --
|
||||||
// ------------
|
// ------------
|
||||||
@@ -120,28 +155,41 @@ LogLevel log_level_from_string(const char *level_str) {
|
|||||||
|
|
||||||
void logger_level_reset() {
|
void logger_level_reset() {
|
||||||
current_log_level = LOG_LEVEL_INFO;
|
current_log_level = LOG_LEVEL_INFO;
|
||||||
free_log_rules();
|
logger_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void logger_level(LogLevel level) {
|
void logger_level(LogLevel level) {
|
||||||
current_log_level = 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");
|
const char* env_level = getenv("LOG_LEVEL");
|
||||||
|
printf("INIT: env_level: %s\n", env_level);
|
||||||
|
|
||||||
if (env_level) {
|
if (env_level) {
|
||||||
// Check if it's a complex rule format (contains '=' or ',')
|
// Check if it's a complex rule format (contains '=' or ',')
|
||||||
if (strchr(env_level, '=') || strchr(env_level, ',')) {
|
if (strchr(env_level, '=') || strchr(env_level, ',')) {
|
||||||
if (logger_parse_rules(env_level)) {
|
printf("INIT: env_level is complex\n");
|
||||||
fprintf(stderr, "INIT: Logger initialized with complex rules from environment\n");
|
LogRuleResult parse_result = logger_parse_rules__(__FILE__, __func__, __LINE__, log_rules_arena, env_level);
|
||||||
} else {
|
if (IS_RESULT_ERROR(parse_result)) {
|
||||||
fprintf(stderr, "INIT: Failed to parse complex log rules, using default level INFO\n");
|
fprintf(stderr, "INIT: Failed to parse complex log rules, using default level INFO\n");
|
||||||
current_log_level = LOG_LEVEL_INFO;
|
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 {
|
} else {
|
||||||
// Simple log level
|
printf("INIT: env_level is simple\n");
|
||||||
current_log_level = log_level_from_string(env_level);
|
current_log_level = log_level_from_string(env_level);
|
||||||
fprintf(stderr, "INIT: Logger initialized with level %s from environment\n",
|
fprintf(stderr, "INIT: Logger initialized with level %s from environment\n",
|
||||||
log_level_to_string(current_log_level));
|
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(
|
char* raise_message(
|
||||||
LogLevel level,
|
LogLevel level,
|
||||||
const char *file,
|
const char *file,
|
||||||
@@ -207,6 +264,7 @@ PtrSet *ptrset_init__(POSITION_INFO_DECLARATION, Arena *arena) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool debug_ptrset_contains__(PtrSet *set, const void *ptr) {
|
bool debug_ptrset_contains__(PtrSet *set, const void *ptr) {
|
||||||
|
if (!set) return false;
|
||||||
for (size_t i = 0; i < set->size; i++) {
|
for (size_t i = 0; i < set->size; i++) {
|
||||||
if (set->data[i] == ptr)
|
if (set->data[i] == ptr)
|
||||||
return true;
|
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) {
|
void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, const void *ptr) {
|
||||||
|
if (!set) return;
|
||||||
if (set->size == set->capacity) {
|
if (set->size == set->capacity) {
|
||||||
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
||||||
set->data = arena_realloc__(CTX(arena), set->data, set->capacity, set->capacity * sizeof(void*));
|
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;
|
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) {
|
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) {
|
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) {
|
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);
|
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);
|
va_copy(args_copy, args);
|
||||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: Starting first pass");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: Starting first pass");
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter1");
|
|
||||||
char *s = va_arg(args_copy, char*);
|
char *s = va_arg(args_copy, char*);
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: String %d: [%s] %p len: %d", i, s, s, len);
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG JOIN: String %d: [%s] %p len: %d", i, s, s, len);
|
||||||
total_len += len;
|
total_len += len;
|
||||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "iter2");
|
|
||||||
}
|
}
|
||||||
va_end(args_copy);
|
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);
|
char *joined = debug_join_debug_strings_v(CTX(arena), count, args);
|
||||||
va_end(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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// ------------------
|
* Construct a new log rule
|
||||||
// -- logger rules --
|
*/
|
||||||
// ------------------
|
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));
|
||||||
// Clean up existing log rules
|
if (!rule) return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_OUT_OF_MEMORY, "Out of memory");
|
||||||
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;
|
|
||||||
|
|
||||||
rule->level = level;
|
rule->level = level;
|
||||||
rule->file_pattern = file_pattern ? strdup(file_pattern) : NULL;
|
rule->file_pattern = file_pattern ? arena_strdup__(__FILE__, __func__, __LINE__, arena, file_pattern) : NULL;
|
||||||
rule->function_pattern = function_pattern ? strdup(function_pattern) : NULL;
|
rule->function_pattern = function_pattern ? arena_strdup__(__FILE__, __func__, __LINE__, arena, function_pattern) : NULL;
|
||||||
rule->line_start = line_start;
|
rule->line_start = line_start;
|
||||||
rule->line_end = line_end;
|
rule->line_end = line_end;
|
||||||
rule->next = NULL;
|
rule->next = NULL;
|
||||||
|
|
||||||
// Add to the end of the list
|
return RESULT_SOME(LogRuleResult, *rule);
|
||||||
if (!log_rules) {
|
|
||||||
log_rules = rule;
|
|
||||||
} else {
|
|
||||||
LogRule *last = log_rules;
|
|
||||||
while (last->next) {
|
|
||||||
last = last->next;
|
|
||||||
}
|
|
||||||
last->next = rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a line range specification (start:end)
|
// 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
|
// Parse a complex rule string and set up log rules
|
||||||
int logger_parse_rules(const char *rules_str) {
|
LogRuleResult logger_parse_rules__(CTX_DECLARATION, const char *rules_str) {
|
||||||
if (!rules_str || !*rules_str) return 0;
|
if (!rules_str || !*rules_str) return RESULT_ERROR(LogRuleResult, LOGGER_ERROR_INVALID_RULES_STRING, "Invalid rules string");
|
||||||
|
|
||||||
// Clean up existing rules
|
|
||||||
free_log_rules();
|
|
||||||
|
|
||||||
// Make a copy of the rules string since we'll be modifying it
|
// Make a copy of the rules string since we'll be modifying it
|
||||||
char *rules_copy = strdup(rules_str);
|
char *rules_copy = arena_strdup__(CTX(arena), rules_str);
|
||||||
if (!rules_copy) return 0;
|
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
|
// First rule sets the default level
|
||||||
char *next_rule = rules_copy;
|
char *next_rule = rules_copy;
|
||||||
@@ -1586,11 +1626,25 @@ int logger_parse_rules(const char *rules_str) {
|
|||||||
|
|
||||||
// Create a new rule
|
// Create a new rule
|
||||||
LogLevel level = log_level_from_string(level_str);
|
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 RESULT_SOME(LogRuleResult, *rules);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a file matches a pattern
|
// 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
|
// Add a new log rule programmatically
|
||||||
int logger_add_rule(LogLevel level, const char *file_pattern, const char *function_pattern,
|
HecticError logger_add_rule(Arena *arena, LogRule *rules, LogLevel level, const char *file_pattern, const char *function_pattern, int line_start, int line_end) {
|
||||||
int line_start, int line_end) {
|
LogRuleResult init_result = log_rule_init(arena, level, file_pattern, function_pattern, line_start, line_end);
|
||||||
return add_log_rule(level, file_pattern, function_pattern, line_start, line_end) != NULL;
|
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
|
// 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 *log_rules_to_debug_str__(CTX_DECLARATION, char *name, LogRule *self, PtrSet *visited) {
|
||||||
char *result = arena_alloc(arena, MEM_KiB);
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
STRUCT_TO_DEBUG_STR(arena, result, LogRule, name, self, visited, 6,
|
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, "file_pattern", self->file_pattern),
|
||||||
string_to_debug_str__(POSITION_INFO, arena, "function_pattern", self->function_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_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) \
|
#define TEMPLATE_ASSERT_SYNTAX(pattern, message_arg, code_arg) \
|
||||||
if (strncmp(*s, pattern, strlen(pattern))) { \
|
if (strncmp(*s, pattern, strlen(pattern))) { \
|
||||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \
|
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \
|
||||||
result->type = RESULT_ERROR; \
|
return RESULT_ERROR(TemplateResult, code_arg, message_arg); \
|
||||||
result->Result.Error.code = code_arg; \
|
|
||||||
result->Result.Error.message = message_arg; \
|
|
||||||
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);
|
||||||
|
|
||||||
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");
|
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;
|
const char **s = s_ptr;
|
||||||
|
|
||||||
@@ -1839,22 +1829,22 @@ TemplateResult *template_parse_interpolation__(POSITION_INFO_DECLARATION, Arena
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t key_len = *s - key_start;
|
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.value.interpolate.key = arena_strncpy__(POSITION_INFO, arena, key_start, key_len);
|
||||||
result->Result.some.type = TEMPLATE_NODE_INTERPOLATE;
|
result.Result.some.type = TEMPLATE_NODE_INTERPOLATE;
|
||||||
|
|
||||||
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||||
|
|
||||||
return result;
|
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");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Section");
|
||||||
|
|
||||||
TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult));
|
TemplateResult result;
|
||||||
result->type = RESULT_SOME;
|
result.type = RESULT_SOME;
|
||||||
result->Result.some.type = TEMPLATE_NODE_SECTION;
|
result.Result.some.type = TEMPLATE_NODE_SECTION;
|
||||||
|
|
||||||
const char **s = s_ptr;
|
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;
|
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
|
// Find the collection name
|
||||||
*s = skip_whitespace(*s);
|
*s = skip_whitespace(*s);
|
||||||
@@ -1891,26 +1881,26 @@ TemplateResult *template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t collection_len = *s - collection_start;
|
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
|
// Parse the body
|
||||||
TemplateResult *body_result = template_parse__(POSITION_INFO, arena, s, config);
|
TemplateResult body_result = template_parse__(POSITION_INFO, arena, s, config);
|
||||||
if (body_result->type == RESULT_ERROR) {
|
if (body_result.type == RESULT_ERROR) {
|
||||||
return body_result;
|
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);
|
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||||
|
|
||||||
return result;
|
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");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Include");
|
||||||
TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult));
|
TemplateResult result;
|
||||||
result->type = RESULT_SOME;
|
result.type = RESULT_SOME;
|
||||||
result->Result.some.type = TEMPLATE_NODE_INCLUDE;
|
result.Result.some.type = TEMPLATE_NODE_INCLUDE;
|
||||||
|
|
||||||
const char **s = s_ptr;
|
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;
|
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);
|
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||||
|
|
||||||
return result;
|
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");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Execute");
|
||||||
|
|
||||||
TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult));
|
TemplateResult result;
|
||||||
result->type = RESULT_SOME;
|
result.type = RESULT_SOME;
|
||||||
result->Result.some.type = TEMPLATE_NODE_EXECUTE;
|
result.Result.some.type = TEMPLATE_NODE_EXECUTE;
|
||||||
|
|
||||||
const char **s = s_ptr;
|
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;
|
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);
|
*s_ptr = *s + strlen(config->Syntax.Braces.close);
|
||||||
|
|
||||||
return result;
|
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");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Iteration start");
|
||||||
|
|
||||||
if (!template_validate_config__(POSITION_INFO, config)) {
|
if (!template_validate_config__(POSITION_INFO, config)) {
|
||||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Invalid 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) {
|
if (!arena) {
|
||||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Arena is NULL");
|
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;
|
const char *start = *s;
|
||||||
@@ -1997,7 +1987,7 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Deside tag type by prefix
|
// 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");
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Found tag");
|
||||||
|
|
||||||
@@ -2020,21 +2010,13 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const
|
|||||||
} else {
|
} 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));
|
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));
|
return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_UNKNOWN_TAG, "Unknown tag prefix");
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRY(current_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_result->type == RESULT_ERROR) {
|
*current = current_result.Result.some;
|
||||||
return current_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
*current = current_result->Result.some;
|
|
||||||
current->next = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateNode));
|
current->next = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateNode));
|
||||||
current = current->next;
|
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);
|
current->value.text.content = arena_strncpy__(POSITION_INFO, arena, start, *s - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateResult *result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult));
|
return RESULT_SOME(TemplateResult, *root);
|
||||||
result->type = RESULT_SOME;
|
|
||||||
result->Result.some = *root;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef TEMPLATE_ASSERT_SYNTAX
|
#undef TEMPLATE_ASSERT_SYNTAX
|
||||||
|
|
||||||
#define TEMPLATE_NODE_MAX_DEBUG_DEPTH 20
|
#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) {
|
char *template_node_type_to_string(TemplateNodeType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TEMPLATE_NODE_SECTION: return "SECTION";
|
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 *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);
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
STRUCT_TO_DEBUG_STR(arena, result, TemplateSectionValue, name, self, visited, 3,
|
STRUCT_TO_DEBUG_STR(arena, result, TemplateSectionValue, name, self, visited, 3,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ typedef enum {
|
|||||||
|
|
||||||
// External color mode variable declaration
|
// External color mode variable declaration
|
||||||
extern ColorMode color_mode;
|
extern ColorMode color_mode;
|
||||||
|
extern ColorMode debug_color_mode;
|
||||||
|
|
||||||
const char* color_mode_to_string(ColorMode 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
|
// Macros for detecting terminal and color usage
|
||||||
#define IS_TERMINAL() (isatty(fileno(stderr)))
|
#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()))
|
#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_RED "\033[1;31m"
|
||||||
#define COLOR_GREEN "\033[1;32m"
|
#define COLOR_GREEN "\033[1;32m"
|
||||||
#define COLOR_YELLOW "\033[1;33m"
|
#define COLOR_YELLOW "\033[1;33m"
|
||||||
@@ -54,38 +66,27 @@ void set_output_color_mode(ColorMode mode);
|
|||||||
#define COLOR_RESET "\033[0m"
|
#define COLOR_RESET "\033[0m"
|
||||||
|
|
||||||
#define OPTIONAL_COLOR(color) (USE_COLOR() ? color : "")
|
#define OPTIONAL_COLOR(color) (USE_COLOR() ? color : "")
|
||||||
|
#define DEBUG_COLOR(color) (USE_COLOR_IN_DEBUG() ? color : "")
|
||||||
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 --
|
// -- Errors --
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
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 color macros based on output type
|
||||||
//#define ERROR_PREFIX PP_CAT(COLOR_RED, "Error: ")
|
//#define ERROR_PREFIX PP_CAT(COLOR_RED, "Error: ")
|
||||||
//#define ERROR_SUFFIX PP_CAT(COLOR_RESET, "\n")
|
//#define ERROR_SUFFIX PP_CAT(COLOR_RESET, "\n")
|
||||||
@@ -97,6 +98,55 @@ typedef enum {
|
|||||||
|
|
||||||
#define todo fprintf(stderr, "%sNot implimented yet%s", COLOR_RED, COLOR_RESET);exit(1)
|
#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 --
|
// -- Logger --
|
||||||
// ------------
|
// ------------
|
||||||
@@ -171,51 +221,14 @@ typedef struct LogRule {
|
|||||||
|
|
||||||
void logger_level_reset();
|
void logger_level_reset();
|
||||||
|
|
||||||
void init_logger(void);
|
void logger_init(void);
|
||||||
|
|
||||||
|
void logger_free(void);
|
||||||
|
|
||||||
void logger_level(LogLevel level);
|
void logger_level(LogLevel level);
|
||||||
|
|
||||||
LogLevel log_level_from_string(const char *level_str);
|
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,<file>@<function>=LEVEL,<file>@<line_start>:<line_end>=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.
|
* 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, ...);
|
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) \
|
#define STRING_TO_DEBUG_STR(arena, name, string) \
|
||||||
string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string)
|
string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string)
|
||||||
#define INT_TO_DEBUG_STR(arena, name, number) \
|
#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__); \
|
buffer = struct_to_debug_str__(__FILE__, __func__, __LINE__, arena, #type, name, ptr, count, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
// ------------------
|
||||||
|
// -- Logger Rules --
|
||||||
|
// ------------------
|
||||||
|
|
||||||
|
RESULT(LogRule, LogRule);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set complex logging rules from a string
|
||||||
|
* Format: DEFAULT_LEVEL,<file>@<function>=LEVEL,<file>@<line_start>:<line_end>=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 --
|
// -- Json --
|
||||||
// ----------
|
// ----------
|
||||||
@@ -626,16 +684,6 @@ typedef union {
|
|||||||
TemplateTextValue text;
|
TemplateTextValue text;
|
||||||
} TemplateValue;
|
} 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 {
|
struct TemplateNode {
|
||||||
TemplateNodeType type;
|
TemplateNodeType type;
|
||||||
TemplateValue value;
|
TemplateValue value;
|
||||||
@@ -643,9 +691,9 @@ struct TemplateNode {
|
|||||||
TemplateNode *next; // sibling nodes
|
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);
|
TemplateConfig template_default_config__(const char *file, const char *func, int line);
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ while [ $# -gt 0 ]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
MODE="${1:-build}"
|
MODE="${1:-build}"
|
||||||
shift > /dev/null
|
shift 2> /dev/null
|
||||||
|
|
||||||
if [ -n "$COLOR_FLAG" ]; then
|
if [ -n "$COLOR_FLAG" ]; then
|
||||||
CFLAGS="$CFLAGS $COLOR_FLAG"
|
CFLAGS="$CFLAGS $COLOR_FLAG"
|
||||||
@@ -118,12 +118,19 @@ case "$MODE" in
|
|||||||
esac
|
esac
|
||||||
done
|
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[@]}"
|
echo "TESTS_TO_RUN: ${TESTS_TO_RUN[@]}"
|
||||||
for test_file in test/*.c; do
|
for test_file in test/*.c; do
|
||||||
test_name=$(basename "${test_file%.c}")
|
test_name=$(basename "${test_file%.c}")
|
||||||
|
|
||||||
# Skip if specific tests are requested and this isn't one of them
|
# 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
|
if [ ${#TESTS_TO_RUN[@]} -ne 0 ] && ! [[ " ${TESTS_TO_RUN[*]} " =~ " ${test_name} " ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ void test_struct2_to_debug_str(Arena *arena) {
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
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);
|
Arena arena = arena_init(MEM_MiB);
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ int main(void) {
|
|||||||
test_struct2_to_debug_str(&arena);
|
test_struct2_to_debug_str(&arena);
|
||||||
|
|
||||||
arena_free(&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));
|
printf("%sAll tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#include "hectic.h"
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
29
package/c/hectic/test/02-logger-rules.c
Executable file
29
package/c/hectic/test/02-logger-rules.c
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "hectic.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -92,7 +92,7 @@ void test_arena_overwrite_detection() {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
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_init();
|
||||||
test_arena_alloc();
|
test_arena_alloc();
|
||||||
@@ -103,6 +103,7 @@ int main() {
|
|||||||
test_arena_repstr();
|
test_arena_repstr();
|
||||||
test_arena_overwrite_detection();
|
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));
|
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ static void test_arena_reset_reuse(void) {
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
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_object();
|
||||||
test_parse_json_number();
|
test_parse_json_number();
|
||||||
@@ -137,6 +137,7 @@ int main(void) {
|
|||||||
test_nested_json_object();
|
test_nested_json_object();
|
||||||
test_arena_reset_reuse();
|
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));
|
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ void test_slice_string() {
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
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_create();
|
||||||
test_slice_subslice();
|
test_slice_subslice();
|
||||||
@@ -92,6 +92,7 @@ int main() {
|
|||||||
test_slice_edge_cases();
|
test_slice_edge_cases();
|
||||||
test_slice_string();
|
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));
|
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ static void test_template_node_to_debug_str(Arena *arena) {
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
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);
|
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));
|
//printf("%sTest 1: template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
|
||||||
//arena_reset(&arena);
|
//arena_reset(&arena);
|
||||||
|
|
||||||
|
logger_free();
|
||||||
arena_free(&arena);
|
arena_free(&arena);
|
||||||
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user