#include "dg.h" #include "mem.h" #include #include #include static void diag_addv(tobi_diag_list *dl, tobi_diag_level level, size_t off, const char *source, size_t input_index, int has_source, const char *fmt, va_list ap) { if (dl->len == dl->cap) { dl->cap = tobi_xgrow_cap(dl->cap, dl->len + 1u, 8u); dl->items = tobi_xrealloc(dl->items, tobi_xmul_size(dl->cap, sizeof(dl->items[0]))); } va_list cp; va_copy(cp, ap); int n = vsnprintf(NULL, 0, fmt, cp); va_end(cp); if (n < 0) { n = 0; } char *msg = tobi_xmalloc((size_t)n + 1); (void)vsnprintf(msg, (size_t)n + 1, fmt, ap); dl->items[dl->len].level = level; dl->items[dl->len].off = off; dl->items[dl->len].source = has_source && source ? tobi_xstrdup(source) : NULL; dl->items[dl->len].input_index = input_index; dl->items[dl->len].has_source = has_source && source != NULL; dl->items[dl->len].msg = msg; dl->len++; } void tobi_diag_init(tobi_diag_list *dl) { dl->items = NULL; dl->len = 0; dl->cap = 0; } void tobi_diag_free(tobi_diag_list *dl) { for (size_t i = 0; i < dl->len; i++) { free(dl->items[i].source); free(dl->items[i].msg); } free(dl->items); dl->items = NULL; dl->len = 0; dl->cap = 0; } void tobi_diag_add(tobi_diag_list *dl, tobi_diag_level level, size_t off, const char *fmt, ...) { va_list ap; va_start(ap, fmt); diag_addv(dl, level, off, NULL, 0, 0, fmt, ap); va_end(ap); } void tobi_diag_add_source(tobi_diag_list *dl, tobi_diag_level level, size_t off, const char *source, size_t input_index, int has_source, const char *fmt, ...) { va_list ap; va_start(ap, fmt); diag_addv(dl, level, off, source, input_index, has_source, fmt, ap); va_end(ap); } void tobi_diag_set_source(tobi_diag_list *dl, const char *source, size_t input_index) { if (!dl || !source) { return; } for (size_t i = 0; i < dl->len; i++) { free(dl->items[i].source); dl->items[i].source = tobi_xstrdup(source); dl->items[i].input_index = input_index; dl->items[i].has_source = 1; } } int tobi_diag_has_error(const tobi_diag_list *dl) { for (size_t i = 0; i < dl->len; i++) { if (dl->items[i].level == TOBI_DIAG_ERROR) { return 1; } } return 0; } const char *tobi_diag_level_name(tobi_diag_level level) { return level == TOBI_DIAG_ERROR ? "error" : "warning"; }