#include "cdio/compat/logging.h" #include #include // Avoid unnecessary repeated calls; don't seem to mess anything up, but may as // well keep clean. bool replaced_cdio_logger = false; cdio_log_level_t get_cdio_log_level() { return cdio_loglevel_default; } void set_cdio_log_level(cdio_log_level_t l) { // The `_default` refers to the default handler, but it has explicitly been // opened up to alternate implementations as well. cdio_loglevel_default = l; } void haskell_log_handler(cdio_log_level_t lvl, const char* msg) { if (lvl >= cdio_loglevel_default) { cdio_log_entry_t* entry = (cdio_log_entry_t*) malloc(sizeof(cdio_log_entry_t)); if (!entry) return; // The Haskell garbage collector could easily clean anything logged // from the bindings before it's read. char* message = malloc(strlen(msg) + 1); if (!message) { free(entry); return; } else strcpy(message, msg); entry->level = lvl; entry->prev = haskell_log; entry->message = message; haskell_log = entry; } } void setup_cdio_logger() { if (!replaced_cdio_logger) { cdio_log_set_handler(*haskell_log_handler); haskell_log = NULL; replaced_cdio_logger = true; } } cdio_log_entry_t** read_cdio_log() { if (!haskell_log) return NULL; // We need the total number of entries for determining allocation size. int count = 0; cdio_log_entry_t* entry = haskell_log; while (entry) { ++count; entry = entry->prev; } cdio_log_entry_t** out = (cdio_log_entry_t**) calloc(count + 1, sizeof(cdio_log_entry_t*)); if (!out) return NULL; // ...and since we have the total anyway, may as well reverse the FILO into // chronological order now. entry = haskell_log; for (int i = count - 1; i >= 0; --i) { out[i] = entry; entry = entry->prev; } return out; } void free_cdio_log() { while (haskell_log) { cdio_log_entry_t* entry = haskell_log; haskell_log = entry->prev; if (entry->message) free((void *)entry->message); free(entry); } }