16 #define WIN32_LEAN_AND_MEAN
18 #elif defined(__ANDROID__)
19 #include <android/log.h>
22 void al_print(LogLevel level
, FILE *logfile
, const char *fmt
, ...)
24 /* Kind of ugly since string literals are const char arrays with a size
25 * that includes the null terminator, which we want to exclude from the
28 auto prefix
= al::as_span("[ALSOFT] (--) ").first
<14>();
31 case LogLevel::Disable
: break;
32 case LogLevel::Error
: prefix
= al::as_span("[ALSOFT] (EE) ").first
<14>(); break;
33 case LogLevel::Warning
: prefix
= al::as_span("[ALSOFT] (WW) ").first
<14>(); break;
34 case LogLevel::Trace
: prefix
= al::as_span("[ALSOFT] (II) ").first
<14>(); break;
37 al::vector
<char> dynmsg
;
38 std::array
<char,256> stcmsg
{};
40 char *str
{stcmsg
.data()};
41 auto prefend1
= std::copy_n(prefix
.begin(), prefix
.size(), stcmsg
.begin());
42 al::span
<char> msg
{prefend1
, stcmsg
.end()};
44 std::va_list args
, args2
;
47 const int msglen
{std::vsnprintf(msg
.data(), msg
.size(), fmt
, args
)};
48 if(msglen
>= 0 && static_cast<size_t>(msglen
) >= msg
.size()) UNLIKELY
50 dynmsg
.resize(static_cast<size_t>(msglen
)+prefix
.size() + 1u);
53 auto prefend2
= std::copy_n(prefix
.begin(), prefix
.size(), dynmsg
.begin());
54 msg
= {prefend2
, dynmsg
.end()};
56 std::vsnprintf(msg
.data(), msg
.size(), fmt
, args2
);
61 if(gLogLevel
>= level
)
66 #if defined(_WIN32) && !defined(NDEBUG)
67 /* OutputDebugStringW has no 'level' property to distinguish between
68 * informational, warning, or error debug messages. So only print them for
71 std::wstring wstr
{utf8_to_wstr(str
)};
72 OutputDebugStringW(wstr
.c_str());
73 #elif defined(__ANDROID__)
74 auto android_severity
= [](LogLevel l
) noexcept
78 case LogLevel::Trace
: return ANDROID_LOG_DEBUG
;
79 case LogLevel::Warning
: return ANDROID_LOG_WARN
;
80 case LogLevel::Error
: return ANDROID_LOG_ERROR
;
81 /* Should not happen. */
82 case LogLevel::Disable
:
85 return ANDROID_LOG_ERROR
;
87 __android_log_print(android_severity(level
), "openal", "%s", str
);