| @@ -1,7 +1,7 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net> | |||
| // Copyright © 2010–2024 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| @@ -13,11 +13,13 @@ | |||
| #pragma once | |||
| #if !_DEBUG | |||
| #include "../base/env.h" // sys::getenv | |||
| #include "../base/env.h" // lol::sys::getenv | |||
| #endif | |||
| #include <cstdarg> // va_start | |||
| #include <cstdio> // std::vfprintf | |||
| #include <cstdio> // std::vfprintf | |||
| #include <functional> // std::function | |||
| #include <string> // std::string | |||
| namespace lol | |||
| { | |||
| @@ -48,6 +50,12 @@ struct msg | |||
| helper(message_type::error, fmt, args...); | |||
| } | |||
| // Allow the user to provide their own logging function | |||
| static void set_output(std::function<bool(std::string const&)> fn) | |||
| { | |||
| get_output() = fn; | |||
| } | |||
| private: | |||
| msg() = delete; | |||
| @@ -59,6 +67,12 @@ private: | |||
| error, | |||
| }; | |||
| static std::function<bool(std::string const&)>& get_output() | |||
| { | |||
| static std::function<bool(std::string const&)> output; | |||
| return output; | |||
| }; | |||
| static void helper(message_type type, char const *fmt, ...) | |||
| { | |||
| // Unless this is a debug build, ignore debug messages unless | |||
| @@ -72,7 +86,7 @@ private: | |||
| } | |||
| #endif | |||
| static char const * const prefix[] = | |||
| static std::string prefix[] | |||
| { | |||
| "DEBUG", | |||
| "INFO", | |||
| @@ -80,14 +94,25 @@ private: | |||
| "ERROR", | |||
| }; | |||
| fprintf(stdout, "%s: ", prefix[int(type)]); | |||
| std::string str = prefix[int(type)] + ": "; | |||
| size_t pos = str.size(); | |||
| va_list ap; | |||
| va_start(ap, fmt); | |||
| vfprintf(stdout, fmt, ap); | |||
| size_t count = std::vsnprintf(nullptr, 0, fmt, ap); | |||
| str.resize(pos + count); | |||
| // This is OK because C++ strings are indeed null-terminated | |||
| std::vsnprintf(str.data() + pos, count + 1, fmt, ap); | |||
| va_end(ap); | |||
| fflush(stdout); | |||
| // If a user function was provided, use it, and if it returns true, stop | |||
| // processing the message immediately. | |||
| if (auto &fn = get_output(); fn && fn(str)) | |||
| return; | |||
| fprintf(stderr, "%s", str.c_str()); | |||
| fflush(stderr); | |||
| } | |||
| }; | |||
| } // namespace lol | |||