2024-03-25 05:11:57 +00:00
|
|
|
/*
|
2024-01-31 12:49:23 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// $$$$$$$\
|
|
|
|
// $$ __$$\
|
|
|
|
// $$ | $$ | $$$$$$\ $$$$$$$\ $$$$$$\
|
|
|
|
// $$$$$$$\ | \____$$\ $$ _____|$$ __$$\
|
|
|
|
// $$ __$$\ $$$$$$$ |\$$$$$$\ $$$$$$$$ |
|
|
|
|
// $$ | $$ |$$ __$$ | \____$$\ $$ ____|
|
|
|
|
// $$$$$$$ |\$$$$$$$ |$$$$$$$ |\$$$$$$$\
|
|
|
|
// \_______/ \_______|\_______/ \_______|
|
|
|
|
//
|
|
|
|
// dqn_base.cpp
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
2024-03-25 05:11:57 +00:00
|
|
|
*/
|
2024-01-31 12:49:23 +00:00
|
|
|
|
|
|
|
// NOTE: [$INTR] Intrinsics ////////////////////////////////////////////////////////////////////////
|
2023-10-24 13:11:48 +00:00
|
|
|
#if !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
|
2023-07-04 14:04:53 +00:00
|
|
|
#if defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
|
|
|
|
#include <cpuid.h>
|
|
|
|
#endif
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_API Dqn_CPUIDRegisters Dqn_CPUID(int function_id)
|
2023-07-04 14:04:53 +00:00
|
|
|
{
|
|
|
|
Dqn_CPUIDRegisters result = {};
|
2023-08-26 07:27:37 +00:00
|
|
|
#if defined(DQN_COMPILER_MSVC)
|
2023-07-04 14:04:53 +00:00
|
|
|
__cpuid(DQN_CAST(int *)result.array, function_id);
|
2023-08-16 11:59:38 +00:00
|
|
|
#elif defined(DQN_COMPILER_GCC) || defined(DQN_COMPILER_CLANG)
|
2023-07-04 14:04:53 +00:00
|
|
|
__get_cpuid(function_id, &result.array[0] /*eax*/, &result.array[1] /*ebx*/, &result.array[2] /*ecx*/ , &result.array[3] /*edx*/);
|
2023-08-16 11:59:38 +00:00
|
|
|
#else
|
2023-07-04 14:04:53 +00:00
|
|
|
#error "Compiler not supported"
|
2023-08-16 11:59:38 +00:00
|
|
|
#endif
|
2023-07-04 14:04:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
2023-10-24 13:11:48 +00:00
|
|
|
#endif // !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
|
2023-07-04 14:04:53 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$TMUT] Dqn_TicketMutex ///////////////////////////////////////////////////////////////////
|
2023-07-04 14:04:53 +00:00
|
|
|
DQN_API void Dqn_TicketMutex_Begin(Dqn_TicketMutex *mutex)
|
|
|
|
{
|
|
|
|
unsigned int ticket = Dqn_Atomic_AddU32(&mutex->ticket, 1);
|
|
|
|
Dqn_TicketMutex_BeginTicket(mutex, ticket);
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_TicketMutex_End(Dqn_TicketMutex *mutex)
|
|
|
|
{
|
|
|
|
Dqn_Atomic_AddU32(&mutex->serving, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_uint Dqn_TicketMutex_MakeTicket(Dqn_TicketMutex *mutex)
|
|
|
|
{
|
|
|
|
Dqn_uint result = Dqn_Atomic_AddU32(&mutex->ticket, 1);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_TicketMutex_BeginTicket(Dqn_TicketMutex const *mutex, Dqn_uint ticket)
|
|
|
|
{
|
|
|
|
DQN_ASSERTF(mutex->serving <= ticket,
|
|
|
|
"Mutex skipped ticket? Was ticket generated by the correct mutex via MakeTicket? ticket = %u, "
|
|
|
|
"mutex->serving = %u",
|
|
|
|
ticket,
|
|
|
|
mutex->serving);
|
|
|
|
while (ticket != mutex->serving) {
|
|
|
|
// NOTE: Use spinlock intrinsic
|
|
|
|
_mm_pause();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API bool Dqn_TicketMutex_CanLock(Dqn_TicketMutex const *mutex, Dqn_uint ticket)
|
|
|
|
{
|
|
|
|
bool result = (ticket == mutex->serving);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-08-26 07:27:37 +00:00
|
|
|
#if defined(DQN_COMPILER_MSVC) || defined(DQN_COMPILER_CLANG_CL)
|
2023-07-04 14:04:53 +00:00
|
|
|
#if !defined(DQN_CRT_SECURE_NO_WARNINGS_PREVIOUSLY_DEFINED)
|
|
|
|
#undef _CRT_SECURE_NO_WARNINGS
|
|
|
|
#endif
|
|
|
|
#endif
|
2023-08-29 12:35:25 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$PRIN] Dqn_Print /////////////////////////////////////////////////////////////////////////
|
2023-08-29 12:35:25 +00:00
|
|
|
DQN_API Dqn_PrintStyle Dqn_Print_StyleColour(uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold)
|
|
|
|
{
|
|
|
|
Dqn_PrintStyle result = {};
|
|
|
|
result.bold = bold;
|
|
|
|
result.colour = true;
|
|
|
|
result.r = r;
|
|
|
|
result.g = g;
|
|
|
|
result.b = b;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32(uint32_t rgb, Dqn_PrintBold bold)
|
|
|
|
{
|
|
|
|
uint8_t r = (rgb >> 24) & 0xFF;
|
|
|
|
uint8_t g = (rgb >> 16) & 0xFF;
|
|
|
|
uint8_t b = (rgb >> 8) & 0xFF;
|
|
|
|
Dqn_PrintStyle result = Dqn_Print_StyleColour(r, g, b, bold);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API Dqn_PrintStyle Dqn_Print_StyleBold()
|
|
|
|
{
|
|
|
|
Dqn_PrintStyle result = {};
|
|
|
|
result.bold = Dqn_PrintBold_Yes;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_Str8 string)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err);
|
|
|
|
|
|
|
|
#if defined(DQN_OS_WIN32)
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Get the output handles from kernel ////////////////////////////////////////////////////
|
2023-08-29 12:35:25 +00:00
|
|
|
DQN_THREAD_LOCAL void *std_out_print_handle = nullptr;
|
|
|
|
DQN_THREAD_LOCAL void *std_err_print_handle = nullptr;
|
|
|
|
DQN_THREAD_LOCAL bool std_out_print_to_console = false;
|
|
|
|
DQN_THREAD_LOCAL bool std_err_print_to_console = false;
|
|
|
|
|
|
|
|
if (!std_out_print_handle) {
|
|
|
|
unsigned long mode = 0; (void)mode;
|
|
|
|
std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0;
|
|
|
|
|
|
|
|
std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE);
|
|
|
|
std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Select the output handle //////////////////////////////////////////////////////////////
|
2023-08-29 12:35:25 +00:00
|
|
|
void *print_handle = std_out_print_handle;
|
|
|
|
bool print_to_console = std_out_print_to_console;
|
|
|
|
if (std_handle == Dqn_PrintStd_Err) {
|
|
|
|
print_handle = std_err_print_handle;
|
|
|
|
print_to_console = std_err_print_to_console;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Write the string //////////////////////////////////////////////////////////////////////
|
2023-08-29 12:35:25 +00:00
|
|
|
DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1);
|
|
|
|
unsigned long bytes_written = 0; (void)bytes_written;
|
|
|
|
if (print_to_console) {
|
|
|
|
WriteConsoleA(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
|
|
|
|
} else {
|
|
|
|
WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr);
|
|
|
|
}
|
|
|
|
#else
|
2023-10-24 13:11:48 +00:00
|
|
|
fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STR_FMT(string));
|
2023-08-29 12:35:25 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
if (string.data && string.size) {
|
|
|
|
if (style.colour)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgStr8(style.r, style.g, style.b));
|
2023-08-29 12:35:25 +00:00
|
|
|
if (style.bold == Dqn_PrintBold_Yes)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldStr8);
|
2023-08-29 12:35:25 +00:00
|
|
|
Dqn_Print_Std(std_handle, string);
|
|
|
|
if (style.colour || style.bold == Dqn_PrintBold_Yes)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetStr8);
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Print_StdFV(std_handle, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
#if !defined(DQN_USE_STD_PRINTF)
|
|
|
|
DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len)
|
|
|
|
{
|
|
|
|
Dqn_Str8 string = {};
|
|
|
|
string.data = DQN_CAST(char *)buf;
|
|
|
|
string.size = len;
|
|
|
|
|
|
|
|
Dqn_PrintStd std_handle = DQN_CAST(Dqn_PrintStd)DQN_CAST(uintptr_t)user;
|
|
|
|
Dqn_Print_Std(std_handle, string);
|
|
|
|
return (char *)buf;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
#if defined(DQN_USE_STD_PRINTF)
|
|
|
|
vfprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, fmt, args);
|
|
|
|
#else
|
2023-08-29 12:35:25 +00:00
|
|
|
char buffer[STB_SPRINTF_MIN];
|
|
|
|
STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args);
|
2024-01-31 12:49:23 +00:00
|
|
|
#endif
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
if (fmt) {
|
|
|
|
if (style.colour)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgStr8(style.r, style.g, style.b));
|
2023-08-29 12:35:25 +00:00
|
|
|
if (style.bold == Dqn_PrintBold_Yes)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldStr8);
|
2023-08-29 12:35:25 +00:00
|
|
|
Dqn_Print_StdFV(std_handle, fmt, args);
|
|
|
|
if (style.colour || style.bold == Dqn_PrintBold_Yes)
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, Dqn_Print_ESCResetStr8);
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_Str8 string)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
Dqn_Print_Std(std_handle, string);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Print_StdLnFV(std_handle, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
Dqn_Print_StdFV(std_handle, fmt, args);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_Str8 string)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
Dqn_Print_StdStyle(std_handle, style, string);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Print_StdLnFVStyle(std_handle, style, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Print_Std(std_handle, DQN_STR8("\n"));
|
2023-08-29 12:35:25 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API Dqn_Str8 Dqn_Print_ESCColourStr8(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
|
|
|
DQN_THREAD_LOCAL char buffer[32];
|
2023-10-24 13:11:48 +00:00
|
|
|
buffer[0] = 0;
|
|
|
|
Dqn_Str8 result = {};
|
2024-01-31 12:49:23 +00:00
|
|
|
result.size = DQN_SNPRINTF(buffer,
|
|
|
|
DQN_ARRAY_UCOUNT(buffer),
|
|
|
|
"\x1b[%d;2;%u;%u;%um",
|
|
|
|
colour == Dqn_PrintESCColour_Fg ? 38 : 48,
|
|
|
|
r, g, b);
|
2023-10-24 13:11:48 +00:00
|
|
|
result.data = buffer;
|
2023-08-29 12:35:25 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API Dqn_Str8 Dqn_Print_ESCColourU32Str8(Dqn_PrintESCColour colour, uint32_t value)
|
2023-08-29 12:35:25 +00:00
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
uint8_t r = DQN_CAST(uint8_t)(value >> 24);
|
|
|
|
uint8_t g = DQN_CAST(uint8_t)(value >> 16);
|
|
|
|
uint8_t b = DQN_CAST(uint8_t)(value >> 8);
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 result = Dqn_Print_ESCColourStr8(colour, r, g, b);
|
2023-08-29 12:35:25 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: [$LLOG] Dqn_Log ///////////////////////////////////////////////////////////////////////////
|
|
|
|
DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Arena *arena,
|
2023-10-24 13:11:48 +00:00
|
|
|
bool colour,
|
|
|
|
Dqn_Str8 type,
|
|
|
|
int log_type,
|
|
|
|
Dqn_CallSite call_site,
|
|
|
|
DQN_FMT_ATTRIB char const *fmt,
|
|
|
|
va_list args)
|
|
|
|
{
|
2024-01-31 12:49:23 +00:00
|
|
|
DQN_LOCAL_PERSIST Dqn_usize max_type_length = 0;
|
|
|
|
max_type_length = DQN_MAX(max_type_length, type.size);
|
|
|
|
int type_padding = DQN_CAST(int)(max_type_length - type.size);
|
|
|
|
|
|
|
|
Dqn_Str8 colour_esc = {};
|
|
|
|
Dqn_Str8 bold_esc = {};
|
|
|
|
Dqn_Str8 reset_esc = {};
|
|
|
|
if (colour) {
|
|
|
|
bold_esc = Dqn_Print_ESCBoldStr8;
|
|
|
|
reset_esc = Dqn_Print_ESCResetStr8;
|
|
|
|
switch (log_type) {
|
|
|
|
case Dqn_LogType_Debug: break;
|
|
|
|
case Dqn_LogType_Info: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Info); break;
|
|
|
|
case Dqn_LogType_Warning: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Warning); break;
|
|
|
|
case Dqn_LogType_Error: colour_esc = Dqn_Print_ESCColourFgU32Str8(Dqn_LogTypeColourU32_Error); break;
|
2023-08-31 12:10:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(call_site.file);
|
|
|
|
Dqn_OSDateTimeStr8 const time = Dqn_OS_DateLocalTimeStr8Now();
|
|
|
|
Dqn_Str8 header = Dqn_Str8_InitF(arena,
|
2024-03-25 05:11:57 +00:00
|
|
|
"%.*s " // date
|
|
|
|
"%.*s " // hms
|
|
|
|
"%.*s" // colour
|
|
|
|
"%.*s" // bold
|
|
|
|
"%.*s" // type
|
|
|
|
"%*s" // type padding
|
|
|
|
"%.*s" // reset
|
|
|
|
" %.*s" // file name
|
|
|
|
":%05I32u " // line number
|
|
|
|
,
|
|
|
|
DQN_CAST(int)time.date_size - 2, time.date + 2, // date
|
|
|
|
DQN_CAST(int)time.hms_size, time.hms, // hms
|
|
|
|
DQN_STR_FMT(colour_esc), // colour
|
|
|
|
DQN_STR_FMT(bold_esc), // bold
|
|
|
|
DQN_STR_FMT(type), // type
|
|
|
|
DQN_CAST(int)type_padding, "", // type padding
|
|
|
|
DQN_STR_FMT(reset_esc), // reset
|
|
|
|
DQN_STR_FMT(file_name), // file name
|
|
|
|
call_site.line); // line number
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_usize header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size;
|
|
|
|
|
|
|
|
// NOTE: Header padding ////////////////////////////////////////////////////////////////////////
|
|
|
|
DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0;
|
|
|
|
max_header_length = DQN_MAX(max_header_length, header_size_no_ansi_codes);
|
|
|
|
Dqn_usize header_padding = max_header_length - header_size_no_ansi_codes;
|
|
|
|
|
|
|
|
// NOTE: Construct final log ///////////////////////////////////////////////////////////////////
|
|
|
|
Dqn_Str8 user_msg = Dqn_Str8_InitFV(arena, fmt, args);
|
|
|
|
Dqn_Str8 result = Dqn_Str8_Alloc(arena, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
|
2024-03-25 05:11:57 +00:00
|
|
|
if (Dqn_Str8_HasData(result)) {
|
|
|
|
DQN_MEMCPY(result.data, header.data, header.size);
|
|
|
|
DQN_MEMSET(result.data + header.size, ' ', header_padding);
|
|
|
|
if (Dqn_Str8_HasData(user_msg))
|
|
|
|
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
|
|
|
|
}
|
2023-08-31 12:10:47 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_Str8 type, int log_type, void *user_data, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-31 12:10:47 +00:00
|
|
|
{
|
|
|
|
Dqn_Library *lib = g_dqn_library;
|
|
|
|
(void)log_type;
|
|
|
|
(void)user_data;
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Open log file for appending if requested //////////////////////////
|
2023-08-31 12:10:47 +00:00
|
|
|
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
2024-02-11 05:14:00 +00:00
|
|
|
if (lib->log_to_file && !lib->log_file.handle && !lib->log_file.error) {
|
2024-01-31 12:49:23 +00:00
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Str8 log_path = Dqn_OS_PathConvertF(scratch.arena, "%.*s/dqn.log", DQN_STR_FMT(lib->exe_dir));
|
2024-02-11 07:23:13 +00:00
|
|
|
lib->log_file = Dqn_OS_FileOpen(log_path, Dqn_OSFileOpen_CreateAlways, Dqn_OSFileAccess_AppendOnly, nullptr);
|
2023-08-31 12:10:47 +00:00
|
|
|
}
|
|
|
|
Dqn_TicketMutex_End(&lib->log_file_mutex);
|
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Generate the log header ///////////////////////////////////////////
|
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Str8 log_line = Dqn_Log_MakeStr8(scratch.arena, !lib->log_no_colour, type, log_type, call_site, fmt, args);
|
2023-08-31 12:10:47 +00:00
|
|
|
|
2024-01-31 12:49:23 +00:00
|
|
|
// NOTE: Print log /////////////////////////////////////////////////////////
|
2023-08-31 12:10:47 +00:00
|
|
|
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
|
|
|
|
|
|
|
|
Dqn_TicketMutex_Begin(&lib->log_file_mutex);
|
2024-02-11 07:23:13 +00:00
|
|
|
Dqn_OS_FileWrite(&lib->log_file, log_line, nullptr);
|
|
|
|
Dqn_OS_FileWrite(&lib->log_file, DQN_STR8("\n"), nullptr);
|
2023-08-31 12:10:47 +00:00
|
|
|
Dqn_TicketMutex_End(&lib->log_file_mutex);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Log_FVCallSite(Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-31 12:10:47 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
if (g_dqn_library) {
|
|
|
|
Dqn_LogProc *logging_function = g_dqn_library->log_callback ? g_dqn_library->log_callback : Dqn_Log_FVDefault_;
|
|
|
|
logging_function(type, -1 /*log_type*/, g_dqn_library->log_user_data, call_site, fmt, args);
|
|
|
|
} else {
|
|
|
|
// NOTE: Rarely taken branch, only when trying to use this library without initialising it
|
|
|
|
Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args);
|
|
|
|
}
|
2023-08-31 12:10:47 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Log_FCallSite(Dqn_Str8 type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-31 12:10:47 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Log_FVCallSite(type, call_site, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Log_TypeFVCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
2023-08-31 12:10:47 +00:00
|
|
|
{
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Str8 type_string = DQN_STR8("DQN-BAD-LOG-TYPE");
|
2023-08-31 12:10:47 +00:00
|
|
|
switch (type) {
|
2023-10-24 13:11:48 +00:00
|
|
|
case Dqn_LogType_Error: type_string = DQN_STR8("ERROR"); break;
|
|
|
|
case Dqn_LogType_Info: type_string = DQN_STR8("INFO"); break;
|
|
|
|
case Dqn_LogType_Warning: type_string = DQN_STR8("WARN"); break;
|
|
|
|
case Dqn_LogType_Debug: type_string = DQN_STR8("DEBUG"); break;
|
|
|
|
case Dqn_LogType_Count: type_string = DQN_STR8("BADXX"); break;
|
2023-08-31 12:10:47 +00:00
|
|
|
}
|
2023-10-24 13:11:48 +00:00
|
|
|
Dqn_Log_FVCallSite(type_string, call_site, fmt, args);
|
2023-08-31 12:10:47 +00:00
|
|
|
}
|
|
|
|
|
2023-10-24 13:11:48 +00:00
|
|
|
DQN_API void Dqn_Log_TypeFCallSite(Dqn_LogType type, Dqn_CallSite call_site, DQN_FMT_ATTRIB char const *fmt, ...)
|
2023-08-31 12:10:47 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_Log_TypeFVCallSite(type, call_site, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
2024-02-11 05:14:00 +00:00
|
|
|
|
|
|
|
// NOTE: [$ERRS] Dqn_ErrorSink /////////////////////////////////////////////////////////////////////
|
2024-02-29 10:30:06 +00:00
|
|
|
DQN_API Dqn_ErrorSink *Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode mode)
|
2024-02-11 05:14:00 +00:00
|
|
|
{
|
|
|
|
Dqn_ThreadContext *thread_context = Dqn_ThreadContext_Get();
|
|
|
|
Dqn_ErrorSink *result = &thread_context->error_sink;
|
|
|
|
Dqn_ErrorSinkNode *node = Dqn_Arena_New(result->arena, Dqn_ErrorSinkNode, Dqn_ZeroMem_Yes);
|
|
|
|
node->next = result->stack;
|
|
|
|
node->arena_pos = Dqn_Arena_Pos(result->arena);
|
2024-02-29 10:30:06 +00:00
|
|
|
node->mode = mode;
|
2024-02-11 05:14:00 +00:00
|
|
|
result->stack = node;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-19 12:11:00 +00:00
|
|
|
DQN_API bool Dqn_ErrorSink_HasError(Dqn_ErrorSink *error)
|
|
|
|
{
|
|
|
|
bool result = error && error->stack->error;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-11 05:14:00 +00:00
|
|
|
DQN_API Dqn_ErrorSinkNode Dqn_ErrorSink_End(Dqn_Arena *arena, Dqn_ErrorSink *error)
|
|
|
|
{
|
|
|
|
Dqn_ErrorSinkNode result = {};
|
|
|
|
if (!error)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
Dqn_ErrorSinkNode *node = error->stack;
|
|
|
|
if (!node)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
DQN_ASSERTF(arena != error->arena,
|
|
|
|
"You are not allowed to reuse the arena for ending the error sink because the memory would get popped and lost");
|
|
|
|
result = *error->stack;
|
|
|
|
result.next = nullptr;
|
|
|
|
result.msg = Dqn_Str8_Copy(arena, result.msg);
|
|
|
|
error->stack = error->stack->next;
|
|
|
|
Dqn_Arena_PopTo(error->arena, result.arena_pos);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-03-25 02:13:43 +00:00
|
|
|
DQN_API void Dqn_ErrorSink_EndAndIgnore(Dqn_ErrorSink *error)
|
|
|
|
{
|
|
|
|
Dqn_ErrorSink_End(nullptr, error);
|
|
|
|
}
|
|
|
|
|
2024-02-29 10:30:06 +00:00
|
|
|
DQN_API bool Dqn_ErrorSink_EndAndLogError(Dqn_ErrorSink *error, Dqn_Str8 error_msg)
|
2024-02-11 05:14:00 +00:00
|
|
|
{
|
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_ErrorSinkNode node = Dqn_ErrorSink_End(scratch.arena, error);
|
|
|
|
if (node.error) {
|
2024-02-29 10:30:06 +00:00
|
|
|
if (Dqn_Str8_HasData(error_msg)) {
|
2024-03-19 12:11:00 +00:00
|
|
|
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s: %.*s", DQN_STR_FMT(error_msg), DQN_STR_FMT(node.msg));
|
2024-02-11 05:14:00 +00:00
|
|
|
} else {
|
|
|
|
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, node.call_site, "%.*s", DQN_STR_FMT(node.msg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool result = node.error;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-29 10:30:06 +00:00
|
|
|
DQN_API bool Dqn_ErrorSink_EndAndLogErrorFV(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
|
|
|
{
|
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
|
|
|
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-11 05:14:00 +00:00
|
|
|
DQN_API bool Dqn_ErrorSink_EndAndLogErrorF(Dqn_ErrorSink *error, DQN_FMT_ATTRIB char const *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2024-02-29 10:30:06 +00:00
|
|
|
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
|
|
|
Dqn_Str8 log = Dqn_Str8_InitFV(scratch.arena, fmt, args);
|
|
|
|
bool result = Dqn_ErrorSink_EndAndLogError(error, log);
|
2024-02-11 05:14:00 +00:00
|
|
|
va_end(args);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_ErrorSink_EndAndExitIfErrorFV(Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
|
|
|
{
|
2024-03-19 12:11:00 +00:00
|
|
|
if (Dqn_ErrorSink_EndAndLogErrorFV(error, fmt, args)) {
|
|
|
|
DQN_DEBUG_BREAK;
|
2024-02-11 05:14:00 +00:00
|
|
|
Dqn_OS_Exit(exit_code);
|
2024-03-19 12:11:00 +00:00
|
|
|
}
|
2024-02-11 05:14:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_ErrorSink_EndAndExitIfErrorF(Dqn_ErrorSink *error, uint32_t exit_code, DQN_FMT_ATTRIB char const *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_ErrorSink_EndAndExitIfErrorFV(error, exit_code, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_ErrorSink_MakeFV_(Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, va_list args)
|
|
|
|
{
|
2024-02-29 10:30:06 +00:00
|
|
|
if (!error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Dqn_ErrorSinkNode *node = error->stack;
|
|
|
|
DQN_ASSERTF(node, "Error sink must be begun by calling 'Begin' before using this function.");
|
|
|
|
if (!node->error) { // NOTE: Only preserve the first error
|
|
|
|
node->msg = Dqn_Str8_InitFV(error->arena, fmt, args);
|
|
|
|
node->error_code = error_code;
|
|
|
|
node->error = true;
|
|
|
|
node->call_site = Dqn_ThreadContext_Get()->call_site;
|
|
|
|
if (node->mode == Dqn_ErrorSinkMode_ExitOnError)
|
2024-03-19 12:11:00 +00:00
|
|
|
Dqn_ErrorSink_EndAndExitIfErrorF(error, error_code, "Fatal error %u", error_code);
|
2024-02-11 05:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DQN_API void Dqn_ErrorSink_MakeF_(Dqn_ErrorSink *error, uint32_t error_code, DQN_FMT_ATTRIB char const *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
Dqn_ErrorSink_MakeFV_(error, error_code, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|