2024-04-18 22:59:11 +10:00
|
|
|
#pragma once
|
|
|
|
#include "dqn.h"
|
|
|
|
|
2024-03-25 16:11:57 +11:00
|
|
|
/*
|
2024-01-31 23:49:23 +11:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// $$$$$$\ $$$$$$\
|
|
|
|
// $$ __$$\ $$ __$$\
|
|
|
|
// $$ / $$ |$$ / \__|
|
|
|
|
// $$ | $$ |\$$$$$$\
|
|
|
|
// $$ | $$ | \____$$\
|
|
|
|
// $$ | $$ |$$\ $$ |
|
|
|
|
// $$$$$$ |\$$$$$$ |
|
|
|
|
// \______/ \______/
|
|
|
|
//
|
|
|
|
// dqn_os.cpp
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
2024-03-25 16:11:57 +11:00
|
|
|
*/
|
2024-01-31 23:49:23 +11:00
|
|
|
|
|
|
|
// NOTE: [$DATE] Date //////////////////////////////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8(DN_OSDateTime time, char date_separator, char hms_separator)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSDateTimeStr8 result = {};
|
|
|
|
result.hms_size = DN_CAST(uint8_t) DN_SNPRINTF(result.hms,
|
|
|
|
DN_ARRAY_ICOUNT(result.hms),
|
2024-01-31 23:49:23 +11:00
|
|
|
"%02hhu%c%02hhu%c%02hhu",
|
|
|
|
time.hour,
|
|
|
|
hms_separator,
|
|
|
|
time.minutes,
|
|
|
|
hms_separator,
|
|
|
|
time.seconds);
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
result.date_size = DN_CAST(uint8_t) DN_SNPRINTF(result.date,
|
|
|
|
DN_ARRAY_ICOUNT(result.date),
|
2024-01-31 23:49:23 +11:00
|
|
|
"%hu%c%02hhu%c%02hhu",
|
|
|
|
time.year,
|
|
|
|
date_separator,
|
|
|
|
time.month,
|
|
|
|
date_separator,
|
|
|
|
time.day);
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ASSERT(result.hms_size < DN_ARRAY_UCOUNT(result.hms));
|
|
|
|
DN_ASSERT(result.date_size < DN_ARRAY_UCOUNT(result.date));
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_OSDateTimeStr8 DN_OS_DateLocalTimeStr8Now(char date_separator, char hms_separator)
|
2023-10-25 00:11:48 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSDateTime time = DN_OS_DateLocalTimeNow();
|
|
|
|
DN_OSDateTimeStr8 result = DN_OS_DateLocalTimeStr8(time, date_separator, hms_separator);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API uint64_t DN_OS_DateUnixTimeS()
|
|
|
|
{
|
|
|
|
uint64_t result = DN_OS_DateUnixTimeNs() / (1'000 /*us*/ * 1'000 /*ms*/ * 1'000 /*s*/);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
DN_API bool DN_OS_DateIsValid(DN_OSDateTime date)
|
2024-02-25 22:37:14 +11:00
|
|
|
{
|
|
|
|
if (date.year < 1970)
|
|
|
|
return false;
|
|
|
|
if (date.month <= 0 || date.month >= 13)
|
|
|
|
return false;
|
|
|
|
if (date.day <= 0 || date.day >= 32)
|
|
|
|
return false;
|
|
|
|
if (date.hour >= 24)
|
|
|
|
return false;
|
|
|
|
if (date.minutes >= 60)
|
|
|
|
return false;
|
|
|
|
if (date.seconds >= 60)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Other /////////////////////////////////////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_EXEDir(DN_Arena *arena)
|
2023-10-25 00:11:48 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = {};
|
2024-01-31 23:49:23 +11:00
|
|
|
if (!arena)
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(arena);
|
|
|
|
DN_Str8 exe_path = DN_OS_EXEPath(tmem.arena);
|
|
|
|
DN_Str8 separators[] = {DN_STR8("/"), DN_STR8("\\")};
|
|
|
|
DN_Str8BinarySplitResult split = DN_Str8_BinarySplitLastArray(exe_path, separators, DN_ARRAY_UCOUNT(separators));
|
|
|
|
result = DN_Str8_Copy(arena, split.lhs);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-02-25 22:37:14 +11:00
|
|
|
// NOTE: Counters //////////////////////////////////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_PerfCounterS(uint64_t begin, uint64_t end)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t frequency = DN_OS_PerfCounterFrequency();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t ticks = end - begin;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = ticks / DN_CAST(DN_F64)frequency;
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_PerfCounterMs(uint64_t begin, uint64_t end)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t frequency = DN_OS_PerfCounterFrequency();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t ticks = end - begin;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = (ticks * 1'000) / DN_CAST(DN_F64)frequency;
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_PerfCounterUs(uint64_t begin, uint64_t end)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t frequency = DN_OS_PerfCounterFrequency();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t ticks = end - begin;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = (ticks * 1'000'000) / DN_CAST(DN_F64)frequency;
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_PerfCounterNs(uint64_t begin, uint64_t end)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t frequency = DN_OS_PerfCounterFrequency();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t ticks = end - begin;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = (ticks * 1'000'000'000) / DN_CAST(DN_F64)frequency;
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_OSTimer DN_OS_TimerBegin()
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSTimer result = {};
|
|
|
|
result.start = DN_OS_PerfCounterNow();
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API void DN_OS_TimerEnd(DN_OSTimer *timer)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
timer->end = DN_OS_PerfCounterNow();
|
2024-01-31 23:49:23 +11:00
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_TimerS(DN_OSTimer timer)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = DN_OS_PerfCounterS(timer.start, timer.end);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_TimerMs(DN_OSTimer timer)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = DN_OS_PerfCounterMs(timer.start, timer.end);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_TimerUs(DN_OSTimer timer)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = DN_OS_PerfCounterUs(timer.start, timer.end);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_F64 DN_OS_TimerNs(DN_OSTimer timer)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_F64 result = DN_OS_PerfCounterNs(timer.start, timer.end);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API uint64_t DN_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_tsc_frequency)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t os_frequency = DN_OS_PerfCounterFrequency();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t os_target_elapsed = duration_ms_to_gauge_tsc_frequency * os_frequency / 1000ULL;
|
2025-02-14 00:27:42 +11:00
|
|
|
uint64_t tsc_begin = DN_CPU_TSC();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t result = 0;
|
|
|
|
if (tsc_begin) {
|
|
|
|
uint64_t os_elapsed = 0;
|
2025-02-14 00:27:42 +11:00
|
|
|
for (uint64_t os_begin = DN_OS_PerfCounterNow(); os_elapsed < os_target_elapsed; )
|
|
|
|
os_elapsed = DN_OS_PerfCounterNow() - os_begin;
|
|
|
|
uint64_t tsc_end = DN_CPU_TSC();
|
2024-01-31 23:49:23 +11:00
|
|
|
uint64_t tsc_elapsed = tsc_end - tsc_begin;
|
|
|
|
result = tsc_elapsed / os_elapsed * os_frequency;
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
2023-10-25 00:11:48 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
#if !defined(DN_NO_OS_FILE_API)
|
|
|
|
// NOTE: [$FILE] DN_OSPathInfo/File ///////////////////////////////////////////////////////////////
|
|
|
|
DN_API bool DN_OS_FileIsOlderThan(DN_Str8 file, DN_Str8 check_against)
|
2024-08-01 13:34:36 +10:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSPathInfo file_info = DN_OS_PathInfo(file);
|
|
|
|
DN_OSPathInfo check_against_info = DN_OS_PathInfo(check_against);
|
2024-08-01 13:34:36 +10:00
|
|
|
bool result = !file_info.exists || file_info.last_write_time_in_s < check_against_info.last_write_time_in_s;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_FileWrite(DN_OSFile *file, DN_Str8 buffer, DN_ErrSink *error)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
bool result = DN_OS_FileWritePtr(file, buffer.data, buffer.size, error);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_FileWriteFV(DN_OSFile *file, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
if (!file || !fmt)
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(nullptr);
|
|
|
|
DN_Str8 buffer = DN_Str8_InitFV(tmem.arena, fmt, args);
|
|
|
|
result = DN_OS_FileWritePtr(file, buffer.data, buffer.size, error);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_FileWriteF(DN_OSFile *file, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, ...)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
bool result = DN_OS_FileWriteFV(file, error, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_end(args);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: R/W Entire File ///////////////////////////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_ReadAll(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error)
|
2024-02-11 18:23:13 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = {};
|
2024-02-11 18:23:13 +11:00
|
|
|
if (!arena)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// NOTE: Query file size + allocate buffer /////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSPathInfo path_info = DN_OS_PathInfo(path);
|
2024-02-11 18:23:13 +11:00
|
|
|
if (!path_info.exists) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ErrSink_AppendF(error, 1, "File does not exist/could not be queried for reading '%.*s'", DN_STR_FMT(path));
|
2024-02-11 18:23:13 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ArenaTempMem temp_mem = DN_Arena_TempMemBegin(arena);
|
|
|
|
result = DN_Str8_Alloc(arena, path_info.size, DN_ZeroMem_No);
|
|
|
|
if (!DN_Str8_HasData(result)) {
|
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(nullptr);
|
|
|
|
DN_Str8 buffer_size_str8 = DN_U64ToByteSizeStr8(tmem.arena, path_info.size, DN_U64ByteSizeType_Auto);
|
|
|
|
DN_ErrSink_AppendF(error, 1 /*error_code*/, "Failed to allocate %.*s for reading file '%.*s'", DN_STR_FMT(buffer_size_str8), DN_STR_FMT(path));
|
|
|
|
DN_Arena_TempMemEnd(temp_mem);
|
2024-02-11 18:23:13 +11:00
|
|
|
result = {};
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Read the file from disk ///////////////////////////////////////////////////////////////
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_OpenIfExist, DN_OSFileAccess_Read, error);
|
|
|
|
bool read_failed = !DN_OS_FileRead(&file, result.data, result.size, error);
|
2024-02-25 22:37:14 +11:00
|
|
|
if (file.error || read_failed) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Arena_TempMemEnd(temp_mem);
|
2024-02-11 18:23:13 +11:00
|
|
|
result = {};
|
|
|
|
}
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OS_FileClose(&file);
|
2024-02-11 18:23:13 +11:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAll(DN_Str8 path, DN_Str8 buffer, DN_ErrSink *error)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSFile file = DN_OS_FileOpen(path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_Write, error);
|
|
|
|
bool result = DN_OS_FileWrite(&file, buffer, error);
|
|
|
|
DN_OS_FileClose(&file);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAllFV(DN_Str8 file_path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(nullptr);
|
|
|
|
DN_Str8 buffer = DN_Str8_InitFV(tmem.arena, fmt, args);
|
|
|
|
bool result = DN_OS_WriteAll(file_path, buffer, error);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAllF(DN_Str8 file_path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, ...)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
bool result = DN_OS_WriteAllFV(file_path, error, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_end(args);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAllSafe(DN_Str8 path, DN_Str8 buffer, DN_ErrSink *error)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(nullptr);
|
|
|
|
DN_Str8 tmp_path = DN_Str8_InitF(tmem.arena, "%.*s.tmp", DN_STR_FMT(path));
|
|
|
|
if (!DN_OS_WriteAll(tmp_path, buffer, error))
|
2024-01-31 23:49:23 +11:00
|
|
|
return false;
|
2025-02-14 00:27:42 +11:00
|
|
|
if (!DN_OS_CopyFile(tmp_path, path, true /*overwrite*/, error))
|
2024-01-31 23:49:23 +11:00
|
|
|
return false;
|
2025-02-14 00:27:42 +11:00
|
|
|
if (!DN_OS_PathDelete(tmp_path))
|
2024-01-31 23:49:23 +11:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAllSafeFV(DN_Str8 path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, va_list args)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(nullptr);
|
|
|
|
DN_Str8 buffer = DN_Str8_InitFV(tmem.arena, fmt, args);
|
|
|
|
bool result = DN_OS_WriteAllSafe(path, buffer, error);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_WriteAllSafeF(DN_Str8 path, DN_ErrSink *error, DN_FMT_ATTRIB char const *fmt, ...)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
bool result = DN_OS_WriteAllSafeFV(path, error, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
2025-02-14 00:27:42 +11:00
|
|
|
#endif // !defined(DN_NO_OS_FILE_API)
|
2024-01-31 23:49:23 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
// NOTE: [$PATH] DN_OSPath ////////////////////////////////////////////////////////////////////////
|
|
|
|
DN_API bool DN_OS_PathAddRef(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
if (!arena || !fs_path || !DN_Str8_HasData(path))
|
2024-01-31 23:49:23 +11:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (path.size <= 0)
|
|
|
|
return true;
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 const delimiter_array[] = {
|
|
|
|
DN_STR8("\\"),
|
|
|
|
DN_STR8("/")
|
2024-01-31 23:49:23 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
if (fs_path->links_size == 0) {
|
|
|
|
fs_path->has_prefix_path_separator = (path.data[0] == '/');
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8BinarySplitResult delimiter = DN_Str8_BinarySplitArray(path, delimiter_array, DN_ARRAY_UCOUNT(delimiter_array));
|
|
|
|
for (; delimiter.lhs.data; delimiter = DN_Str8_BinarySplitArray(delimiter.rhs, delimiter_array, DN_ARRAY_UCOUNT(delimiter_array))) {
|
2024-01-31 23:49:23 +11:00
|
|
|
if (delimiter.lhs.size <= 0)
|
|
|
|
continue;
|
2023-10-25 00:11:48 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSPathLink *link = DN_Arena_New(arena, DN_OSPathLink, DN_ZeroMem_Yes);
|
2024-01-31 23:49:23 +11:00
|
|
|
if (!link)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
link->string = delimiter.lhs;
|
|
|
|
link->prev = fs_path->tail;
|
|
|
|
if (fs_path->tail) {
|
|
|
|
fs_path->tail->next = link;
|
|
|
|
} else {
|
|
|
|
fs_path->head = link;
|
|
|
|
}
|
|
|
|
fs_path->tail = link;
|
|
|
|
fs_path->links_size += 1;
|
|
|
|
fs_path->string_size += delimiter.lhs.size;
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
|
2024-01-31 23:49:23 +11:00
|
|
|
if (!delimiter.lhs.data)
|
2023-10-25 00:11:48 +11:00
|
|
|
break;
|
|
|
|
}
|
2024-01-31 23:49:23 +11:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_PathAdd(DN_Arena *arena, DN_OSPath *fs_path, DN_Str8 path)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 copy = DN_Str8_Copy(arena, path);
|
|
|
|
bool result = DN_Str8_HasData(copy) ? true : DN_OS_PathAddRef(arena, fs_path, copy);
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_PathAddF(DN_Arena *arena, DN_OSPath *fs_path, DN_FMT_ATTRIB char const *fmt, ...)
|
2023-10-25 00:11:48 +11:00
|
|
|
{
|
2024-01-31 23:49:23 +11:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 path = DN_Str8_InitFV(arena, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_end(args);
|
2025-02-14 00:27:42 +11:00
|
|
|
bool result = DN_OS_PathAddRef(arena, fs_path, path);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
2023-10-25 00:11:48 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API bool DN_OS_PathPop(DN_OSPath *fs_path)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
if (!fs_path)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (fs_path->tail) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ASSERT(fs_path->head);
|
2024-01-31 23:49:23 +11:00
|
|
|
fs_path->links_size -= 1;
|
|
|
|
fs_path->string_size -= fs_path->tail->string.size;
|
|
|
|
fs_path->tail = fs_path->tail->prev;
|
|
|
|
if (fs_path->tail) {
|
|
|
|
fs_path->tail->next = nullptr;
|
|
|
|
} else {
|
|
|
|
fs_path->head = nullptr;
|
|
|
|
}
|
|
|
|
} else {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ASSERT(!fs_path->head);
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
|
2024-01-31 23:49:23 +11:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_PathTo(DN_Arena *arena, DN_Str8 path, DN_Str8 path_separator)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSPath fs_path = {};
|
|
|
|
DN_OS_PathAddRef(arena, &fs_path, path);
|
|
|
|
DN_Str8 result = DN_OS_PathBuildWithSeparator(arena, &fs_path, path_separator);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_PathToF(DN_Arena *arena, DN_Str8 path_separator, DN_FMT_ATTRIB char const *fmt, ...)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(arena);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 path = DN_Str8_InitFV(tmem.arena, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_end(args);
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = DN_OS_PathTo(arena, path, path_separator);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_Path(DN_Arena *arena, DN_Str8 path)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = DN_OS_PathTo(arena, path, DN_OSPathSeperatorString);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_PathF(DN_Arena *arena, DN_FMT_ATTRIB char const *fmt, ...)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(arena);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 path = DN_Str8_InitFV(tmem.arena, fmt, args);
|
2024-01-31 23:49:23 +11:00
|
|
|
va_end(args);
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = DN_OS_Path(arena, path);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_Str8 DN_OS_PathBuildWithSeparator(DN_Arena *arena, DN_OSPath const *fs_path, DN_Str8 path_separator)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_Str8 result = {};
|
2024-01-31 23:49:23 +11:00
|
|
|
if (!fs_path || fs_path->links_size <= 0)
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
|
|
|
|
2024-01-31 23:49:23 +11:00
|
|
|
// NOTE: Each link except the last one needs the path separator appended to it, '/' or '\\'
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_USize string_size = (fs_path->has_prefix_path_separator ? path_separator.size : 0) + fs_path->string_size + ((fs_path->links_size - 1) * path_separator.size);
|
|
|
|
result = DN_Str8_Alloc(arena, string_size, DN_ZeroMem_No);
|
2024-01-31 23:49:23 +11:00
|
|
|
if (result.data) {
|
|
|
|
char *dest = result.data;
|
|
|
|
if (fs_path->has_prefix_path_separator) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_MEMCPY(dest, path_separator.data, path_separator.size);
|
2024-01-31 23:49:23 +11:00
|
|
|
dest += path_separator.size;
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
for (DN_OSPathLink *link = fs_path->head; link; link = link->next) {
|
|
|
|
DN_Str8 string = link->string;
|
|
|
|
DN_MEMCPY(dest, string.data, string.size);
|
2024-01-31 23:49:23 +11:00
|
|
|
dest += string.size;
|
|
|
|
|
|
|
|
if (link != fs_path->tail) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_MEMCPY(dest, path_separator.data, path_separator.size);
|
2024-01-31 23:49:23 +11:00
|
|
|
dest += path_separator.size;
|
|
|
|
}
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-31 23:49:23 +11:00
|
|
|
result.data[string_size] = 0;
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-31 23:49:23 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
// NOTE: [$EXEC] DN_OSExec ////////////////////////////////////////////////////////////////////////
|
|
|
|
DN_API DN_OSExecResult DN_OS_Exec(DN_Slice<DN_Str8> cmd_line,
|
|
|
|
DN_OSExecArgs *args,
|
|
|
|
DN_Arena *arena,
|
|
|
|
DN_ErrSink *error)
|
2024-03-25 13:14:05 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSExecAsyncHandle async_handle = DN_OS_ExecAsync(cmd_line, args, error);
|
|
|
|
DN_OSExecResult result = DN_OS_ExecWait(async_handle, arena, error);
|
2023-10-25 00:11:48 +11:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_OSExecResult DN_OS_ExecOrAbort(DN_Slice<DN_Str8> cmd_line, DN_OSExecArgs *args, DN_Arena *arena)
|
2023-10-25 00:11:48 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ErrSink *error = DN_ErrSink_Begin(DN_ErrSinkMode_Nil);
|
|
|
|
DN_OSExecResult result = DN_OS_Exec(cmd_line, args, arena, error);
|
2024-03-25 13:14:05 +11:00
|
|
|
if (result.os_error_code) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ErrSink_EndAndExitIfErrorF(
|
2024-03-25 13:14:05 +11:00
|
|
|
error,
|
|
|
|
result.os_error_code,
|
|
|
|
"OS failed to execute the requested command returning the error code %u",
|
|
|
|
result.os_error_code);
|
|
|
|
}
|
2023-10-25 00:11:48 +11:00
|
|
|
|
2024-03-25 13:14:05 +11:00
|
|
|
if (result.exit_code) {
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ErrSink_EndAndExitIfErrorF(
|
2024-03-25 13:14:05 +11:00
|
|
|
error,
|
|
|
|
result.exit_code,
|
|
|
|
"OS executed command and returned non-zero exit code %u",
|
|
|
|
result.exit_code);
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
2024-03-25 13:14:05 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_ErrSink_EndAndIgnore(error);
|
2024-03-25 13:14:05 +11:00
|
|
|
return result;
|
2023-10-25 00:11:48 +11:00
|
|
|
}
|
2024-01-31 23:49:23 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
// NOTE: [$THRD] DN_OSThread //////////////////////////////////////////////////////////////////////
|
|
|
|
DN_THREAD_LOCAL DN_TLS *g_dn_os_thread_tls;
|
2024-08-01 13:34:36 +10:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
static void DN_OS_ThreadExecute_(void *user_context)
|
2024-08-01 13:34:36 +10:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSThread *thread = DN_CAST(DN_OSThread *)user_context;
|
|
|
|
DN_TLS_Init(&thread->tls);
|
|
|
|
DN_OS_ThreadSetTLS(&thread->tls);
|
|
|
|
DN_OS_SemaphoreWait(&thread->init_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
2024-08-01 13:34:36 +10:00
|
|
|
thread->func(thread);
|
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API void DN_OS_ThreadSetTLS(DN_TLS *tls)
|
2024-08-01 13:34:36 +10:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
g_dn_os_thread_tls = tls;
|
|
|
|
}
|
|
|
|
|
|
|
|
DN_API void DN_OS_ThreadSetName(DN_Str8 name)
|
|
|
|
{
|
|
|
|
DN_TLS *tls = DN_TLS_Get();
|
|
|
|
tls->name_size = DN_CAST(uint8_t)DN_MIN(name.size, sizeof(tls->name) - 1);
|
|
|
|
DN_MEMCPY(tls->name, name.data, tls->name_size);
|
|
|
|
tls->name[tls->name_size] = 0;
|
|
|
|
|
|
|
|
#if defined(DN_OS_WIN32)
|
|
|
|
DN_Win_ThreadSetName(name);
|
|
|
|
#else
|
|
|
|
DN_Posix_ThreadSetName(name);
|
|
|
|
#endif
|
2024-08-01 13:34:36 +10:00
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
// NOTE: [$HTTP] DN_OSHttp ////////////////////////////////////////////////////////////////////////
|
|
|
|
DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
2025-02-14 00:27:42 +11:00
|
|
|
if (response && DN_OS_SemaphoreIsValid(&response->on_complete_semaphore))
|
|
|
|
DN_OS_SemaphoreWait(&response->on_complete_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
2024-01-31 23:49:23 +11:00
|
|
|
}
|
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_API DN_OSHttpResponse DN_OS_HttpRequest(DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers)
|
2024-01-31 23:49:23 +11:00
|
|
|
{
|
|
|
|
// TODO(doyle): Revise the memory allocation and its lifetime
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OSHttpResponse result = {};
|
|
|
|
DN_TLSTMem tmem = DN_TLS_TMem(arena);
|
2024-08-01 13:34:36 +10:00
|
|
|
result.tmem_arena = tmem.arena;
|
2024-01-31 23:49:23 +11:00
|
|
|
|
2025-02-14 00:27:42 +11:00
|
|
|
DN_OS_HttpRequestAsync(&result, arena, host, path, secure, method, body, headers);
|
|
|
|
DN_OS_HttpRequestWait(&result);
|
2024-01-31 23:49:23 +11:00
|
|
|
return result;
|
|
|
|
}
|