]> git.tdb.fi Git - ext/openal.git/blob - core/logging.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / logging.cpp
1
2 #include "config.h"
3
4 #include "logging.h"
5
6 #include <cstdarg>
7 #include <cstdio>
8 #include <string>
9
10 #include "alspan.h"
11 #include "strutils.h"
12 #include "vector.h"
13
14
15 #if defined(_WIN32)
16 #define WIN32_LEAN_AND_MEAN
17 #include <windows.h>
18 #elif defined(__ANDROID__)
19 #include <android/log.h>
20 #endif
21
22 void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
23 {
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
26      * span.
27      */
28     auto prefix = al::as_span("[ALSOFT] (--) ").first<14>();
29     switch(level)
30     {
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;
35     }
36
37     al::vector<char> dynmsg;
38     std::array<char,256> stcmsg{};
39
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()};
43
44     std::va_list args, args2;
45     va_start(args, fmt);
46     va_copy(args2, args);
47     const int msglen{std::vsnprintf(msg.data(), msg.size(), fmt, args)};
48     if(msglen >= 0 && static_cast<size_t>(msglen) >= msg.size()) UNLIKELY
49     {
50         dynmsg.resize(static_cast<size_t>(msglen)+prefix.size() + 1u);
51
52         str = dynmsg.data();
53         auto prefend2 = std::copy_n(prefix.begin(), prefix.size(), dynmsg.begin());
54         msg = {prefend2, dynmsg.end()};
55
56         std::vsnprintf(msg.data(), msg.size(), fmt, args2);
57     }
58     va_end(args2);
59     va_end(args);
60
61     if(gLogLevel >= level)
62     {
63         fputs(str, logfile);
64         fflush(logfile);
65     }
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
69      * non-Release builds.
70      */
71     std::wstring wstr{utf8_to_wstr(str)};
72     OutputDebugStringW(wstr.c_str());
73 #elif defined(__ANDROID__)
74     auto android_severity = [](LogLevel l) noexcept
75     {
76         switch(l)
77         {
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:
83             break;
84         }
85         return ANDROID_LOG_ERROR;
86     };
87     __android_log_print(android_severity(level), "openal", "%s", str);
88 #endif
89 }