packages feed

hscdio-0.1.0.0: src/c/cdio/compat/logging.c

#include "cdio/compat/logging.h"

#include <stdlib.h>
#include <string.h>


// 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);
    }
}