#include "config.h" #include "logging.h" #include #include #include #include "alspan.h" #include "strutils.h" #include "vector.h" void al_print(LogLevel level, const char *fmt, ...) { /* Kind of ugly since string literals are const char arrays with a size * that includes the null terminator, which we want to exclude from the * span. */ auto prefix = al::as_span("[ALSOFT] (--) ").first<14>(); al::vector dynmsg; std::array stcmsg{}; char *str{stcmsg.data()}; auto prefend1 = std::copy_n(prefix.begin(), prefix.size(), stcmsg.begin()); al::span msg{prefend1, stcmsg.end()}; std::va_list args, args2; va_start(args, fmt); va_copy(args2, args); const int msglen{std::vsnprintf(msg.data(), msg.size(), fmt, args)}; if(msglen >= 0 && static_cast(msglen) >= msg.size()) UNLIKELY { dynmsg.resize(static_cast(msglen)+prefix.size() + 1u); str = dynmsg.data(); auto prefend2 = std::copy_n(prefix.begin(), prefix.size(), dynmsg.begin()); msg = {prefend2, dynmsg.end()}; std::vsnprintf(msg.data(), msg.size(), fmt, args2); } va_end(args2); va_end(args); if(gLogLevel >= level) { switch (level) { case LogLevel::Disable: case LogLevel::Error: AuLogError("{}", str); break; case LogLevel::Warning: AuLogWarn("{}", str); break; case LogLevel::Trace: AuLogVerbose("{}", str); break; default: AuLogGame("{}", str); } } }