1. 4FIPS
  2. PHOTOS
  3. VIDEOS
  4. APPS
  5. CODE
  6. FORUMS
  7. ABOUT
/*
(c) 2004-14 Filip Stoklas, aka FipS, www.4FipS.com
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
*/

#include "fs_common.h"
#include "fs_common_os.h"

#include <stdarg.h> // va_list
#include <chrono>

// --- ASSERT ---

namespace fs { namespace assert {

namespace
{
    handler_type g_handler = default_handler;
}

bool dispatch(const char *cond, const char *func, const char *file, int line) FS_NOEXCEPT
{
    return handler()(cond, func, file, line);
}

handler_type set_handler(handler_type h) FS_NOEXCEPT
{
    handler_type orig = g_handler;
    g_handler = h;
    return orig;
}

handler_type handler() FS_NOEXCEPT
{
    return g_handler;
}

const char * strip_fname(const char *path) FS_NOEXCEPT
{
    const char *p1 = strrchr(path, '/');
    const char *p2 = strrchr(path, '\\');
    return p1 > p2 ? p1 + 1 : p2 > p1 ? p2 + 1 : path;
}

bool default_handler(const char *cond, const char *func, const char *file, int line) FS_NOEXCEPT
{
    char buf[1024];

    FS_TRACE(("[x] ASSERTION: '%s', '%s', %s(%d)", cond, func, strip_fname(file), line));

    str::snprintf_trunc(
     buf, FS_COUNT_OF(buf),
     "CONDITION:\n%s\n\n"
     "FILE:\n%s (line=%d)\n\n"
     "FUNCTION:\n%s\n\n"
     "Would you like to debug now?",
     cond, strip_fname(file), line, func
    );

    return os::show_yes_no_dialog("!!! FIPS ASSERTION !!!", buf, true);
}

}} // namespace fs::assert

// --- TRACE ---

namespace fs { namespace trace {

namespace
{
    handler_type g_handler = default_handler;
}

void dispatch(const char *fmt, ...) FS_NOEXCEPT
{
    char buf[1024];

    va_list args;
    va_start(args, fmt);
    str::vsnprintf_trunc(buf, FS_COUNT_OF(buf), fmt, args);
    va_end(args);

    handler()(buf);
}

handler_type set_handler(handler_type h) FS_NOEXCEPT
{
    handler_type orig = g_handler;
    g_handler = h;
    return orig;
}

handler_type handler() FS_NOEXCEPT
{
    return g_handler;
}

void default_handler(const char *text) FS_NOEXCEPT
{
    // we need this extra copy to be able to print text+'\n' atomically
    char buf[1024];
    str::snprintf_trunc(buf, FS_COUNT_OF(buf), "%s\n", text);
    os::debug_print(buf);
}

}} // namespace fs::trace

// --- PROBE ---

namespace fs { namespace probe {

namespace
{
    handler_type g_handler = { default_handler, nullptr };
}

void dispatch(const char *key, double val) FS_NOEXCEPT
{
    const auto h = handler();
    h.cb(h.ctx, key, val);
}

handler_type set_handler(handler_type h) FS_NOEXCEPT
{
    handler_type orig = g_handler;
    g_handler = h;
    return orig;
}

handler_type handler() FS_NOEXCEPT
{
    return g_handler;
}

void default_handler(void *ctx, const char *key, double val) FS_NOEXCEPT
{
    FS_TRACE(("[.] PROBE: %s %g", key, val));
}

}} // namespace fs::probe

// --- ERROR ---

namespace fs { namespace error {

namespace
{
    handler_type g_handler = default_handler;
    bool g_debug_break_enabled = false;
}

void dispatch(const error &err) FS_NOEXCEPT
{
    handler()(err);
}

handler_type set_handler(handler_type h) FS_NOEXCEPT
{
    handler_type orig = g_handler;
    g_handler = h;
    return orig;
}

handler_type handler() FS_NOEXCEPT
{
    return g_handler;
}

void default_handler(const error &err) FS_NOEXCEPT
{
    FS_TRACE(("[x] ERROR: '%s' !", err.what()));
    std::terminate();
}

bool enable_debug_break(bool on) FS_NOEXCEPT
{
    const bool orig = g_debug_break_enabled;
    g_debug_break_enabled = on;
    return orig;
}

bool debug_break_enabled() FS_NOEXCEPT
{
    return g_debug_break_enabled;
}

}} // namespace fs::error

// --- MISC ---

namespace fs {

double sys_time() FS_NOEXCEPT
{
    using namespace std::chrono;
    using res = nanoseconds;

    return
     duration_cast<res>(high_resolution_clock::now().time_since_epoch()).count() /
     static_cast<double>(duration_cast<res>(seconds(1)).count());
}

} // namespace fs