ohmu
·
2026-10-15
1#include <errno.h>
2
3#ifndef NDEBUG
4
5 #include "common/debug.h"
6 #include "common/thread.h"
7
8[[gnu::nonnull(1), gnu::pure, gnu::always_inline, nodiscard]]
9static inline const char* ffFindFileName(const char* file) {
10 const char* lastSlash = __builtin_strrchr(file, '/');
11 #ifdef _WIN32
12 if (lastSlash == nullptr) {
13 lastSlash = __builtin_strrchr(file, '\\');
14 }
15 #endif
16 if (lastSlash != nullptr) {
17 return lastSlash + 1;
18 }
19 return file;
20}
21
22#if __GNUC__ && !__clang__
23[[gnu::optimize("O2")]]
24#endif
25void ffDebugPrint(const char* file, int line, const char* format, ...) {
26 if (!instance.config.display.debugMode) {
27 return;
28 }
29
30 static FFThreadMutex debugMutex = FF_THREAD_MUTEX_INITIALIZER;
31 // Saved before the lock and restored after the unlock: FF_DEBUG() is called from error paths
32 // that go on to read `errno`, so nothing this function does -- neither the lock nor the
33 // formatting -- may be allowed to leave its own value behind.
34 int errno_ = errno;
35 ffThreadMutexLock(&debugMutex);
36 static char errmsg_[1024]; // Don't increase stack size
37 va_list args;
38 va_start(args, format);
39 vsnprintf(errmsg_, sizeof(errmsg_), format, args);
40 va_end(args);
41 fprintf(stderr, "[%s%4d, %s] %s\n", ffFindFileName(file), line, ffTimeToTimeStr(ffTimeGetNow()), errmsg_);
42 ffThreadMutexUnlock(&debugMutex);
43 errno = errno_;
44}
45
46 #if _WIN32
47 #include "common/windows/nt.h"
48
49 #include <windows.h>
50 #include <cfgmgr32.h>
51
52const char* ffDebugWin32Error(DWORD errorCode) {
53 static char buffer[512];
54
55 wchar_t bufferW[256];
56 ULONG len = FormatMessageW(
57 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
58 nullptr,
59 (DWORD) errorCode,
60 0,
61 bufferW,
62 ARRAY_SIZE(bufferW),
63 nullptr);
64
65 if (len == 0) {
66 snprintf(buffer, sizeof(buffer), "Unknown error code (%lu)", errorCode);
67 } else {
68 // Remove trailing newline
69 while (len > 0 && (bufferW[len - 1] == '\r' || bufferW[len - 1] == '\n')) {
70 --len;
71 }
72
73 if (NT_SUCCESS(RtlUnicodeToUTF8N(buffer, sizeof(buffer), &len, bufferW, len * sizeof(wchar_t)))) {
74 snprintf(buffer + len, sizeof(buffer) - len, " (%lu)", errorCode);
75 } else {
76 snprintf(buffer, sizeof(buffer), "Unknown error (%lu)", errorCode);
77 }
78 }
79
80 return buffer;
81}
82
83const char* ffDebugConfigRet(CONFIGRET ret) {
84 return ffDebugWin32Error(CM_MapCrToWin32Err(ret, ERROR_INTERNAL_ERROR));
85}
86
87const char* ffDebugNtStatus(NTSTATUS status) {
88 return ffDebugWin32Error(RtlNtStatusToDosError(status));
89}
90
91static inline DWORD HRESULTToWin32Error(HRESULT hr) {
92 if (SUCCEEDED(hr)) {
93 return ERROR_SUCCESS;
94 }
95
96 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) {
97 return HRESULT_CODE(hr);
98 }
99
100 return ERROR_INTERNAL_ERROR;
101}
102
103const char* ffDebugHResult(HRESULT hr) {
104 return ffDebugWin32Error(HRESULTToWin32Error(hr));
105}
106 #endif
107
108#endif