dqn: Add MSVC SAL annotations
This commit is contained in:
parent
8f129e7893
commit
2868993ebc
@ -746,6 +746,18 @@ Dqn_UTest TestIntrinsics()
|
||||
// atomics/intrinsics are implemented using macros we ensure the macro was
|
||||
// written properly with these tests.
|
||||
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
|
||||
// NOTE: MSVC SAL complains that we are using Interlocked functionality on
|
||||
// variables it has detected as *not* being shared across threads. This is
|
||||
// fine, we're just running some basic tests, so permit it.
|
||||
//
|
||||
// Warning 28112 is a knock-on effect of this that it doesn't like us
|
||||
// reading the value of the variable that has been used in an Interlocked
|
||||
// function locally.
|
||||
DQN_MSVC_WARNING_DISABLE(28113) // Accessing a local variable val via an Interlocked function.
|
||||
DQN_MSVC_WARNING_DISABLE(28112) // A variable (val) which is accessed via an Interlocked function must always be accessed via an Interlocked function. See line 759.
|
||||
|
||||
DQN_UTEST_GROUP(test, "Dqn_Atomic") {
|
||||
DQN_UTEST_TEST("Dqn_Atomic_AddU32") {
|
||||
uint32_t val = 0;
|
||||
@ -775,7 +787,7 @@ Dqn_UTest TestIntrinsics()
|
||||
long a = 0;
|
||||
long b = 111;
|
||||
Dqn_Atomic_SetValue32(&a, b);
|
||||
DQN_UTEST_ASSERTF(&test, a == b, "a: %lu, b: %lu", a, b);
|
||||
DQN_UTEST_ASSERTF(&test, a == b, "a: %ld, b: %ld", a, b);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("Dqn_Atomic_SetValue64") {
|
||||
@ -797,6 +809,7 @@ Dqn_UTest TestIntrinsics()
|
||||
Dqn_CompilerWriteBarrierAndCPUWriteFence;
|
||||
Dqn_UTest_End(&test);
|
||||
}
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
||||
return test;
|
||||
}
|
||||
@ -1067,7 +1080,7 @@ Dqn_UTest TestOS()
|
||||
|
||||
DQN_UTEST_TEST("Query executable directory") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 result = Dqn_OS_EXEDir(scratch.allocator);
|
||||
Dqn_String8 result = Dqn_OS_EXEDir(scratch.arena);
|
||||
DQN_UTEST_ASSERT(&test, Dqn_String8_IsValid(result));
|
||||
DQN_UTEST_ASSERTF(&test, Dqn_Fs_DirExists(result), "result(%zu): %.*s", result.size, DQN_STRING_FMT(result));
|
||||
}
|
||||
@ -1233,7 +1246,7 @@ Dqn_UTest TestString8()
|
||||
DQN_UTEST_GROUP(test, "Dqn_String8") {
|
||||
DQN_UTEST_TEST("Initialise with string literal w/ macro") {
|
||||
Dqn_String8 string = DQN_STRING8("AB");
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64d", string.size);
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64u", string.size);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[0] == 'A', "string[0]: %c", string.data[0]);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[1] == 'B', "string[1]: %c", string.data[1]);
|
||||
}
|
||||
@ -1241,17 +1254,17 @@ Dqn_UTest TestString8()
|
||||
DQN_UTEST_TEST("Initialise with format string") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 string = Dqn_String8_InitF(scratch.allocator, "%s", "AB");
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64d", string.size);
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64u", string.size);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[0] == 'A', "string[0]: %c", string.data[0]);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[1] == 'B', "string[1]: %c", string.data[1]);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[2] == 0, "string[2]: %c", string.data[2]);
|
||||
DQN_UTEST_ASSERTF(&test, string.data[2] == 0, "string[2]: %c", string.data[2]);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("Copy string") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 string = DQN_STRING8("AB");
|
||||
Dqn_String8 copy = Dqn_String8_Copy(scratch.allocator, string);
|
||||
DQN_UTEST_ASSERTF(&test, copy.size == 2, "size: %I64d", copy.size);
|
||||
DQN_UTEST_ASSERTF(&test, copy.size == 2, "size: %I64u", copy.size);
|
||||
DQN_UTEST_ASSERTF(&test, copy.data[0] == 'A', "copy[0]: %c", copy.data[0]);
|
||||
DQN_UTEST_ASSERTF(&test, copy.data[1] == 'B', "copy[1]: %c", copy.data[1]);
|
||||
DQN_UTEST_ASSERTF(&test, copy.data[2] == 0, "copy[2]: %c", copy.data[2]);
|
||||
@ -1265,7 +1278,7 @@ Dqn_UTest TestString8()
|
||||
DQN_UTEST_TEST("Allocate string from arena") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 string = Dqn_String8_Allocate(scratch.allocator, 2, Dqn_ZeroMem_No);
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64d", string.size);
|
||||
DQN_UTEST_ASSERTF(&test, string.size == 2, "size: %I64u", string.size);
|
||||
}
|
||||
|
||||
// NOTE: Dqn_CString8_Trim[Prefix/Suffix]
|
||||
@ -1652,15 +1665,12 @@ Dqn_UTest TestVArray()
|
||||
// from the memory block (and hence the array) contiguously
|
||||
// when the size of the object is not aligned with the required
|
||||
// alignment of the object.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4324) // warning C4324: 'TestVArray::UnalignedObject': structure was padded due to alignment specifier
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(4324) // warning C4324: 'TestVArray::UnalignedObject': structure was padded due to alignment specifier
|
||||
struct alignas(8) UnalignedObject {
|
||||
char data[511];
|
||||
};
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_VArray<UnalignedObject> array = Dqn_VArray_InitByteSize<UnalignedObject>(scratch.arena, DQN_KILOBYTES(64));
|
||||
@ -1699,35 +1709,35 @@ Dqn_UTest TestWin()
|
||||
Dqn_UTest test = {};
|
||||
DQN_UTEST_GROUP(test, "Dqn_Win") {
|
||||
DQN_UTEST_TEST("String8 to String16 size required") {
|
||||
int result = Dqn_Win_String8ToCString16(DQN_STRING8("a"), nullptr, 0);
|
||||
int result = Dqn_Win_String8ToString16Buffer(DQN_STRING8("a"), nullptr, 0);
|
||||
DQN_UTEST_ASSERTF(&test, result == 1, "Size returned: %d. This size should not include the null-terminator", result);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String16 to String8 size required") {
|
||||
int result = Dqn_Win_String16ToCString8(DQN_STRING16(L"a"), nullptr, 0);
|
||||
int result = Dqn_Win_String16ToString8Buffer(DQN_STRING16(L"a"), nullptr, 0);
|
||||
DQN_UTEST_ASSERTF(&test, result == 1, "Size returned: %d. This size should not include the null-terminator", result);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String8 to String16 size required") {
|
||||
int result = Dqn_Win_String8ToCString16(DQN_STRING8("String"), nullptr, 0);
|
||||
int result = Dqn_Win_String8ToString16Buffer(DQN_STRING8("String"), nullptr, 0);
|
||||
DQN_UTEST_ASSERTF(&test, result == 6, "Size returned: %d. This size should not include the null-terminator", result);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String16 to String8 size required") {
|
||||
int result = Dqn_Win_String16ToCString8(DQN_STRING16(L"String"), nullptr, 0);
|
||||
int result = Dqn_Win_String16ToString8Buffer(DQN_STRING16(L"String"), nullptr, 0);
|
||||
DQN_UTEST_ASSERTF(&test, result == 6, "Size returned: %d. This size should not include the null-terminator", result);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String8 to String16") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 const INPUT = DQN_STRING8("String");
|
||||
int size_required = Dqn_Win_String8ToCString16(INPUT, nullptr, 0);
|
||||
int size_required = Dqn_Win_String8ToString16Buffer(INPUT, nullptr, 0);
|
||||
wchar_t *string = Dqn_Arena_NewArray(scratch.arena, wchar_t, size_required + 1, Dqn_ZeroMem_No);
|
||||
|
||||
// Fill the string with error sentinels, which ensures the string is zero terminated
|
||||
DQN_MEMSET(string, 'Z', size_required + 1);
|
||||
|
||||
int size_returned = Dqn_Win_String8ToCString16(INPUT, string, size_required + 1);
|
||||
int size_returned = Dqn_Win_String8ToString16Buffer(INPUT, string, size_required + 1);
|
||||
wchar_t const EXPECTED[] = {L'S', L't', L'r', L'i', L'n', L'g', 0};
|
||||
|
||||
DQN_UTEST_ASSERTF(&test, size_required == size_returned, "string_size: %d, result: %d", size_required, size_returned);
|
||||
@ -1738,19 +1748,45 @@ Dqn_UTest TestWin()
|
||||
DQN_UTEST_TEST("String16 to String8: No null-terminate") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 INPUT = DQN_STRING16(L"String");
|
||||
int size_required = Dqn_Win_String16ToCString8(INPUT, nullptr, 0);
|
||||
int size_required = Dqn_Win_String16ToString8Buffer(INPUT, nullptr, 0);
|
||||
char *string = Dqn_Arena_NewArray(scratch.arena, char, size_required + 1, Dqn_ZeroMem_No);
|
||||
|
||||
// Fill the string with error sentinels, which ensures the string is zero terminated
|
||||
DQN_MEMSET(string, 'Z', size_required + 1);
|
||||
|
||||
int size_returned = Dqn_Win_String16ToCString8(INPUT, string, size_required + 1);
|
||||
int size_returned = Dqn_Win_String16ToString8Buffer(INPUT, string, size_required + 1);
|
||||
char const EXPECTED[] = {'S', 't', 'r', 'i', 'n', 'g', 0};
|
||||
|
||||
DQN_UTEST_ASSERTF(&test, size_required == size_returned, "string_size: %d, result: %d", size_required, size_returned);
|
||||
DQN_UTEST_ASSERTF(&test, size_returned == DQN_ARRAY_UCOUNT(EXPECTED) - 1, "string_size: %d, expected: %zu", size_returned, DQN_ARRAY_UCOUNT(EXPECTED) - 1);
|
||||
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(EXPECTED, string, sizeof(EXPECTED)) == 0);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String8 to String16 arena") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 const INPUT = DQN_STRING8("String");
|
||||
Dqn_String16 string16 = Dqn_Win_String8ToString16(scratch.arena, INPUT);
|
||||
|
||||
int size_returned = Dqn_Win_String8ToString16Buffer(INPUT, nullptr, 0);
|
||||
wchar_t const EXPECTED[] = {L'S', L't', L'r', L'i', L'n', L'g', 0};
|
||||
|
||||
DQN_UTEST_ASSERTF(&test, string16.size == size_returned, "string_size: %d, result: %d", DQN_CAST(int)string16.size, size_returned);
|
||||
DQN_UTEST_ASSERTF(&test, string16.size == DQN_ARRAY_UCOUNT(EXPECTED) - 1, "string_size: %d, expected: %zu", DQN_CAST(int)string16.size, DQN_ARRAY_UCOUNT(EXPECTED) - 1);
|
||||
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(EXPECTED, string16.data, sizeof(EXPECTED)) == 0);
|
||||
}
|
||||
|
||||
DQN_UTEST_TEST("String16 to String8: No null-terminate arena") {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 INPUT = DQN_STRING16(L"String");
|
||||
Dqn_String8 string8 = Dqn_Win_String16ToString8(scratch.arena, INPUT);
|
||||
|
||||
int size_returned = Dqn_Win_String16ToString8Buffer(INPUT, nullptr, 0);
|
||||
char const EXPECTED[] = {'S', 't', 'r', 'i', 'n', 'g', 0};
|
||||
|
||||
DQN_UTEST_ASSERTF(&test, string8.size == size_returned, "string_size: %d, result: %d", DQN_CAST(int)string8.size, size_returned);
|
||||
DQN_UTEST_ASSERTF(&test, string8.size == DQN_ARRAY_UCOUNT(EXPECTED) - 1, "string_size: %d, expected: %zu", DQN_CAST(int)string8.size, DQN_ARRAY_UCOUNT(EXPECTED) - 1);
|
||||
DQN_UTEST_ASSERT(&test, DQN_MEMCMP(EXPECTED, string8.data, sizeof(EXPECTED)) == 0);
|
||||
}
|
||||
}
|
||||
return test;
|
||||
}
|
||||
|
15
build.bat
15
build.bat
@ -5,8 +5,7 @@ set code_dir=%~dp0
|
||||
if not exist Build mkdir Build
|
||||
pushd Build
|
||||
|
||||
REM Flags
|
||||
REM ------------------------------------------------------------------------
|
||||
REM Flags ==================================================================
|
||||
REM MT Static CRT
|
||||
REM EHa- Disable exception handling
|
||||
REM GR- Disable C RTTI
|
||||
@ -15,24 +14,22 @@ pushd Build
|
||||
REM Z7 Combine multi-debug files to one debug file
|
||||
REM wd4201 Nonstandard extension used: nameless struct/union
|
||||
REM Tp Treat header file as CPP source file
|
||||
set compile_flags=-MT -EHa -GR- -Od -Oi -Z7 -wd4201 -D DQN_TEST_WITH_MAIN -nologo
|
||||
set compile_flags=-MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -WX -D DQN_TEST_WITH_MAIN -nologo -analyze
|
||||
set linker_flags=-link -nologo
|
||||
set msvc_flags=-fsanitize=address
|
||||
set clang_flags=-fsanitize=address,undefined
|
||||
|
||||
REM Compiler: MSVC cl
|
||||
REM ------------------------------------------------------------------------
|
||||
REM Compiler: MSVC cl ======================================================
|
||||
where /q cl || (
|
||||
echo [ERROR] cl is not found, please put MSVC's cl on the path
|
||||
exit /b 1
|
||||
)
|
||||
cl %compile_flags% %msvc_flags% %code_dir%\Misc\dqn_unit_tests.cpp -I %code_dir% /Fe:dqn_unit_tests_msvc %link_flags%
|
||||
cl %compile_flags% %msvc_flags% %code_dir%\Misc\dqn_unit_tests.cpp -I %code_dir% /Fe:dqn_unit_tests_msvc %link_flags% || exit /b 1
|
||||
|
||||
REM Compiler: clang-cl
|
||||
REM ------------------------------------------------------------------------
|
||||
REM Compiler: clang-cl =====================================================
|
||||
where /q clang-cl || (
|
||||
echo [WARN] Optional clang compile via clang-cl if it's in the path, please put clang-cl on the path for this feature
|
||||
exit /b 1
|
||||
exit /b 0
|
||||
)
|
||||
clang-cl -D DQN_TEST_WITH_MAIN %code_dir%\Misc\dqn_unit_tests.cpp -I %code_dir% /Fe:dqn_unit_tests_clang -link
|
||||
popd
|
||||
|
12
dqn_base.h
12
dqn_base.h
@ -48,6 +48,18 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#define DQN_FMT_STRING_ANNOTATE _Printf_format_string_
|
||||
#define DQN_MSVC_WARNING_PUSH __pragma(warning(push))
|
||||
#define DQN_MSVC_WARNING_DISABLE(...) __pragma(warning(disable: ##__VA_ARGS__))
|
||||
#define DQN_MSVC_WARNING_POP __pragma(warning(pop))
|
||||
#else
|
||||
#define DQN_FMT_STRING_ANNOTATE
|
||||
#define DQN_MSVC_WARNING_PUSH
|
||||
#define DQN_MSVC_WARNING_DISABLE(...)
|
||||
#define DQN_MSVC_WARNING_POP
|
||||
#endif
|
||||
|
||||
// NOTE: [$MACR] Macros ============================================================================
|
||||
#define DQN_FOR_UINDEX(index, size) for (Dqn_usize index = 0; index < size; index++)
|
||||
#define DQN_FOR_IINDEX(index, size) for (Dqn_isize index = 0; index < size; index++)
|
||||
|
@ -376,12 +376,12 @@ template <typename T> struct Dqn_List
|
||||
};
|
||||
|
||||
// NOTE: API =======================================================================================
|
||||
DQN_API template <typename T> Dqn_List<T> Dqn_List_InitWithArena(Dqn_Arena *arena, Dqn_usize chunk_size = 128);
|
||||
DQN_API template <typename T> T * Dqn_List_At (Dqn_List<T> *list, Dqn_usize index, Dqn_ListChunk<T> *at_chunk);
|
||||
DQN_API template <typename T> bool Dqn_List_Iterate (Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index);
|
||||
template <typename T> Dqn_List<T> Dqn_List_Init (Dqn_Arena *arena, Dqn_usize chunk_size);
|
||||
template <typename T> T * Dqn_List_At (Dqn_List<T> *list, Dqn_usize index, Dqn_ListChunk<T> *at_chunk);
|
||||
template <typename T> bool Dqn_List_Iterate(Dqn_List<T> *list, Dqn_ListIterator<T> *it, Dqn_usize start_index);
|
||||
|
||||
DQN_API template <typename T> T * Dqn_List_Make (Dqn_List<T> *list, Dqn_usize count);
|
||||
DQN_API template <typename T> T * Dqn_List_Add (Dqn_List<T> *list, Dqn_usize count);
|
||||
template <typename T> T * Dqn_List_Make (Dqn_List<T> *list, Dqn_usize count);
|
||||
template <typename T> T * Dqn_List_Add (Dqn_List<T> *list, T const &value);
|
||||
#endif // !defined(DQN_NO_LIST)
|
||||
|
||||
#if !defined(DQN_NO_VARRAY)
|
||||
|
@ -208,15 +208,15 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator,
|
||||
"%.*s" // reset
|
||||
" %.*s" // file name
|
||||
":%05u ", // line number
|
||||
time.date_size - 2, time.date + 2,
|
||||
time.hms_size, time.hms,
|
||||
colour_esc.size, colour_esc.data,
|
||||
bold_esc.size, bold_esc.data,
|
||||
type.size, type.data,
|
||||
type_padding, "",
|
||||
reset_esc.size, reset_esc.data,
|
||||
file_name.size, file_name.data,
|
||||
call_site.line);
|
||||
DQN_CAST(uint32_t)time.date_size - 2, time.date + 2, // date
|
||||
DQN_CAST(uint32_t)time.hms_size, time.hms, // hms
|
||||
DQN_CAST(uint32_t)colour_esc.size, colour_esc.data, // colour
|
||||
DQN_CAST(uint32_t)bold_esc.size, bold_esc.data, // bold
|
||||
DQN_CAST(uint32_t)type.size, type.data, // type
|
||||
DQN_CAST(uint32_t)type_padding, "", // type padding
|
||||
DQN_CAST(uint32_t)reset_esc.size, reset_esc.data, // reset
|
||||
DQN_CAST(uint32_t)file_name.size, file_name.data, // file name
|
||||
call_site.line); // line number
|
||||
header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size;
|
||||
}
|
||||
|
||||
@ -244,13 +244,12 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use
|
||||
(void)log_type;
|
||||
(void)user_data;
|
||||
|
||||
// NOTE: Open log file for appending if requested
|
||||
// =========================================================================
|
||||
// NOTE: Open log file for appending if requested ==========================
|
||||
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex);
|
||||
if (g_dqn_library->log_to_file && !g_dqn_library->log_file) {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
|
||||
Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.allocator);
|
||||
Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.arena);
|
||||
#else
|
||||
Dqn_String8 exe_dir = DQN_STRING8(".");
|
||||
#endif
|
||||
@ -259,8 +258,7 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use
|
||||
}
|
||||
Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex);
|
||||
|
||||
// NOTE: Generate the log header
|
||||
// =========================================================================
|
||||
// NOTE: Generate the log header ===========================================
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator,
|
||||
!g_dqn_library->log_no_colour,
|
||||
@ -270,12 +268,11 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use
|
||||
fmt,
|
||||
args);
|
||||
|
||||
// NOTE: Print log
|
||||
// =========================================================================
|
||||
// NOTE: Print log =========================================================
|
||||
Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line);
|
||||
|
||||
Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex);
|
||||
if (g_dqn_library->log_to_file) {
|
||||
if (g_dqn_library->log_to_file && g_dqn_library->log_file) {
|
||||
fprintf(DQN_CAST(FILE *)g_dqn_library->log_file, "%.*s\n", DQN_STRING_FMT(log_line));
|
||||
}
|
||||
Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex);
|
||||
|
@ -1,6 +1,11 @@
|
||||
// NOTE: [$BSTK] b_stacktrace ======================================================================
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(6308) // b_stacktrace.h|147 'realloc' might return null pointer: assigning null pointer to 'b->buf', which is passed as an argument to 'realloc', will cause the original memory block to be leaked.
|
||||
DQN_MSVC_WARNING_DISABLE(6011) // b_stacktrace.h|244 Dereferencing NULL pointer 'cur'. : Lines: 183, 184, 185, 186, 187, 188, 189, 191, 196, 198, 208, 209, 210, 211, 212, 213, 214, 229, 230, 231, 237, 244
|
||||
DQN_MSVC_WARNING_DISABLE(6387) // b_stacktrace.h|284 'symbol' could be '0'.: Lines: 256, 257, 258, 259, 260, 261, 262, 264, 265, 266, 267, 268, 270, 276, 281, 282, 284
|
||||
#define B_STACKTRACE_IMPL
|
||||
#include "b_stacktrace.h"
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
||||
// NOTE: [$STBS] stb_sprintf =======================================================================
|
||||
#if !defined(DQN_STB_SPRINTF_HEADER_ONLY)
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <Windows.h>
|
||||
#include <shellscalingapi.h>
|
||||
#endif
|
||||
|
||||
#define B_STACKTRACE_API static
|
||||
#include "b_stacktrace.h"
|
||||
|
||||
@ -17,13 +18,14 @@
|
||||
#include <bcrypt.h> // Dqn_OS_SecureRNGBytes -> BCryptOpenAlgorithmProvider ... etc
|
||||
#include <shellapi.h> // Dqn_Win_MakeProcessDPIAware -> SetProcessDpiAwareProc
|
||||
#if !defined(DQN_NO_WINNET)
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(6553) // wininet.h|940 warning| The annotation for function 'InternetConnectA' on _Param_(8) does not apply to a value type.
|
||||
#include <wininet.h> // Dqn_Win_Net -> InternetConnect ... etc
|
||||
DQN_MSVC_WARNING_POP
|
||||
#endif // DQN_NO_WINNET
|
||||
#elif !defined(_INC_WINDOWS)
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
#endif
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
#define MAX_PATH 260
|
||||
|
||||
// NOTE: Wait/Synchronization
|
||||
@ -358,9 +360,7 @@
|
||||
/*HINSTANCE*/ void * __stdcall ShellExecuteA (void *hwnd, char const *lpOperation, char const *lpFile, char const *lpParameters, char const *lpDirectory, int nShowCmd);
|
||||
/*BOOL*/ int __stdcall ShowWindow (void *hWnd, int nCmdShow);
|
||||
}
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
DQN_MSVC_WARNING_POP
|
||||
#endif // !defined(_INC_WINDOWS)
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
#include <errno.h> // errno
|
||||
|
@ -761,10 +761,9 @@ DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator)
|
||||
// dividing by 10, so we write it in, then reverse it out after all is
|
||||
// done.
|
||||
Dqn_U64String temp = {};
|
||||
for (size_t digit_count = 0; val > 0; digit_count++) {
|
||||
if (separator && (digit_count != 0) && (digit_count % 3 == 0)) {
|
||||
for (Dqn_usize digit_count = 0; val > 0; digit_count++) {
|
||||
if (separator && (digit_count != 0) && (digit_count % 3 == 0))
|
||||
temp.data[temp.size++] = separator;
|
||||
}
|
||||
|
||||
auto digit = DQN_CAST(char)(val % 10);
|
||||
temp.data[temp.size++] = '0' + digit;
|
||||
@ -772,10 +771,14 @@ DQN_API Dqn_U64String Dqn_U64ToString(uint64_t val, char separator)
|
||||
}
|
||||
|
||||
// NOTE: Reverse the string
|
||||
for (size_t temp_index = temp.size - 1; temp_index < temp.size; temp_index--) {
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(6293) // Ill-defined for-loop
|
||||
DQN_MSVC_WARNING_DISABLE(6385) // Reading invalid data from 'temp.data' NOTE(doyle): Unsigned overflow is valid for loop termination
|
||||
for (Dqn_usize temp_index = temp.size - 1; temp_index < temp.size; temp_index--) {
|
||||
char ch = temp.data[temp_index];
|
||||
result.data[result.size++] = ch;
|
||||
}
|
||||
DQN_MSVC_WARNING_POP
|
||||
}
|
||||
|
||||
return result;
|
||||
|
20
dqn_math.h
20
dqn_math.h
@ -1,7 +1,5 @@
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
#endif
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
|
||||
#if !defined(DQN_NO_V2)
|
||||
// NOTE: [$VEC2] Vector2 ===========================================================================
|
||||
@ -159,11 +157,6 @@ DQN_API Dqn_V3 Dqn_V3_Normalise(Dqn_V3 a);
|
||||
|
||||
#if !defined(DQN_NO_V4)
|
||||
// NOTE: [$VEC4] Vector4 ===========================================================================
|
||||
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // warning C4201: nonstandard extension used: nameless struct/union
|
||||
#endif
|
||||
union Dqn_V4
|
||||
{
|
||||
struct { Dqn_f32 x, y, z, w; };
|
||||
@ -194,10 +187,6 @@ Dqn_V4 &operator*=(Dqn_V4 &lhs, Dqn_f32 rhs);
|
||||
Dqn_V4 &operator*=(Dqn_V4 &lhs, int32_t rhs);
|
||||
Dqn_V4 &operator-=(Dqn_V4 &lhs, Dqn_V4 rhs);
|
||||
Dqn_V4 &operator+=(Dqn_V4 &lhs, Dqn_V4 rhs);
|
||||
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#endif // !defined(DQN_NO_V4)
|
||||
|
||||
#if !defined(DQN_NO_M4)
|
||||
@ -308,7 +297,4 @@ DQN_API Dqn_Rect Dqn_RectCut_Cut(Dqn_RectCut rect_cut, Dqn_V2 size, Dqn_RectCutC
|
||||
// NOTE: [$MATH] Other =============================================================================
|
||||
DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b);
|
||||
DQN_API Dqn_f32 Dqn_Lerp_F32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b);
|
||||
|
||||
#if defined(DQN_COMPILER_W32_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
@ -102,7 +102,14 @@ DQN_API bool Dqn_VMem_Commit(void *ptr, Dqn_usize size, uint32_t page_flags)
|
||||
DQN_API void Dqn_VMem_Decommit(void *ptr, Dqn_usize size)
|
||||
{
|
||||
#if defined(DQN_OS_WIN32)
|
||||
|
||||
// NOTE: This is a decommit call, which is explicitly saying to free the
|
||||
// pages but not the VADs, you would use VMem_Release to release everything.
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(6250) // Calling 'VirtualFree' without the MEM_RELEASE flag might free memory but not address descriptors (VADs). This causes address space leaks.
|
||||
VirtualFree(ptr, size, MEM_DECOMMIT);
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
mprotect(ptr, size, PROT_NONE);
|
||||
madvise(ptr, size, MADV_FREE);
|
||||
@ -144,8 +151,9 @@ DQN_API int Dqn_VMem_Protect(void *ptr, Dqn_usize size, uint32_t page_flags)
|
||||
#if defined(DQN_NO_WIN)
|
||||
DQN_ASSERTF(result, "VirtualProtect failed");
|
||||
#else
|
||||
Dqn_WinErrorMsg error = Dqn_Win_LastError();
|
||||
DQN_ASSERTF(result, "VirtualProtect failed (%d): %.*s", error.code, error.size, error.data);
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
DQN_ASSERTF(result, "VirtualProtect failed (%d): %.*s", error.code, DQN_STRING_FMT(error.msg));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
@ -312,6 +320,7 @@ DQN_API void *Dqn_Arena_Alloc(Dqn_Arena *arena, Dqn_usize size, uint8_t align, D
|
||||
if (!arena->curr) {
|
||||
if (!Dqn_Arena_Grow(arena, size, size /*commit*/, 0 /*flags*/))
|
||||
return result;
|
||||
DQN_ASSERT(arena->curr);
|
||||
}
|
||||
|
||||
result = Dqn_MemBlock_Alloc(arena->curr, size, align, zero_mem);
|
||||
@ -401,7 +410,7 @@ DQN_API void Dqn_Arena_EndTempMemory(Dqn_ArenaTempMemory temp_memory, bool cance
|
||||
arena->tail->next = nullptr;
|
||||
|
||||
// NOTE: Reset the usage of all the blocks between the tail and current block's
|
||||
for (Dqn_MemBlock *block = arena->tail; block != arena->curr; block = block->prev)
|
||||
for (Dqn_MemBlock *block = arena->tail; block && (block != arena->curr); block = block->prev)
|
||||
block->used = 0;
|
||||
}
|
||||
|
||||
|
559
dqn_platform.cpp
559
dqn_platform.cpp
@ -94,7 +94,7 @@ DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int
|
||||
return (char *)buf;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, char const *fmt, ...)
|
||||
DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -102,7 +102,7 @@ DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, char const *fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, ...)
|
||||
DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -110,13 +110,13 @@ DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, char const *fmt, va_list args)
|
||||
DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
char buffer[STB_SPRINTF_MIN];
|
||||
STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, va_list args)
|
||||
DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
if (fmt) {
|
||||
if (style.colour)
|
||||
@ -135,7 +135,7 @@ DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string)
|
||||
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, char const *fmt, ...)
|
||||
DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -143,7 +143,7 @@ DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, char const *fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, char const *fmt, va_list args)
|
||||
DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_Print_StdFV(std_handle, fmt, args);
|
||||
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
|
||||
@ -155,7 +155,7 @@ DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style,
|
||||
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, ...)
|
||||
DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -163,7 +163,7 @@ DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, va_list args)
|
||||
DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_Print_StdFVStyle(std_handle, style, fmt, args);
|
||||
Dqn_Print_Std(std_handle, DQN_STRING8("\n"));
|
||||
@ -203,7 +203,7 @@ DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint
|
||||
#if !defined(DQN_NO_FS)
|
||||
// NOTE: [$FSYS] Dqn_Fs ============================================================================
|
||||
#if defined(DQN_OS_WIN32)
|
||||
DQN_API uint64_t Dqn__WinFileTimeToSeconds(FILETIME const *time)
|
||||
DQN_API uint64_t Dqn_Win__FileTimeToSeconds(FILETIME const *time)
|
||||
{
|
||||
ULARGE_INTEGER time_large_int = {};
|
||||
time_large_int.u.LowPart = time->dwLowDateTime;
|
||||
@ -216,12 +216,15 @@ DQN_API uint64_t Dqn__WinFileTimeToSeconds(FILETIME const *time)
|
||||
DQN_API bool Dqn_Fs_Exists(Dqn_String8 path)
|
||||
{
|
||||
bool result = false;
|
||||
if (!Dqn_String8_IsValid(path))
|
||||
return result;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
wchar_t path16[DQN_OS_WIN32_MAX_PATH];
|
||||
int path16_size = Dqn_Win_String8ToCString16(path, path16, DQN_ARRAY_ICOUNT(path16));
|
||||
if (path16_size) {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
if (path16.size) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
if (GetFileAttributesExW(path16, GetFileExInfoStandard, &attrib_data)) {
|
||||
if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) {
|
||||
result = (attrib_data.dwFileAttributes != INVALID_FILE_ATTRIBUTES) &&
|
||||
!(attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
@ -240,12 +243,15 @@ DQN_API bool Dqn_Fs_Exists(Dqn_String8 path)
|
||||
DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path)
|
||||
{
|
||||
bool result = false;
|
||||
if (!Dqn_String8_IsValid(path))
|
||||
return result;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
wchar_t path16[DQN_OS_WIN32_MAX_PATH];
|
||||
int path16_size = Dqn_Win_String8ToCString16(path, path16, DQN_ARRAY_ICOUNT(path16));
|
||||
if (path16_size) {
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
if (path16.size) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
if (GetFileAttributesExW(path16, GetFileExInfoStandard, &attrib_data)) {
|
||||
if (GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data)) {
|
||||
result = (attrib_data.dwFileAttributes != INVALID_FILE_ATTRIBUTES) &&
|
||||
(attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
@ -264,17 +270,21 @@ DQN_API bool Dqn_Fs_DirExists(Dqn_String8 path)
|
||||
DQN_API Dqn_FsInfo Dqn_Fs_GetInfo(Dqn_String8 path)
|
||||
{
|
||||
Dqn_FsInfo result = {};
|
||||
if (!Dqn_String8_IsValid(path))
|
||||
return result;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
wchar_t path16[DQN_OS_WIN32_MAX_PATH];
|
||||
Dqn_Win_String8ToCString16(path, path16, DQN_ARRAY_ICOUNT(path16));
|
||||
if (!GetFileAttributesExW(path16, GetFileExInfoStandard, &attrib_data))
|
||||
if (!GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data))
|
||||
return result;
|
||||
|
||||
result.exists = true;
|
||||
result.create_time_in_s = Dqn__WinFileTimeToSeconds(&attrib_data.ftCreationTime);
|
||||
result.last_access_time_in_s = Dqn__WinFileTimeToSeconds(&attrib_data.ftLastAccessTime);
|
||||
result.last_write_time_in_s = Dqn__WinFileTimeToSeconds(&attrib_data.ftLastWriteTime);
|
||||
result.create_time_in_s = Dqn_Win__FileTimeToSeconds(&attrib_data.ftCreationTime);
|
||||
result.last_access_time_in_s = Dqn_Win__FileTimeToSeconds(&attrib_data.ftLastAccessTime);
|
||||
result.last_write_time_in_s = Dqn_Win__FileTimeToSeconds(&attrib_data.ftLastWriteTime);
|
||||
|
||||
LARGE_INTEGER large_int = {};
|
||||
large_int.u.HighPart = DQN_CAST(int32_t)attrib_data.nFileSizeHigh;
|
||||
@ -314,18 +324,18 @@ DQN_API bool Dqn_Fs_Copy(Dqn_String8 src, Dqn_String8 dest, bool overwrite)
|
||||
bool result = false;
|
||||
#if defined(DQN_OS_WIN32)
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 src16 = Dqn_Win_String8ToString16Allocator(src, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 dest16 = Dqn_Win_String8ToString16Allocator(dest, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 src16 = Dqn_Win_String8ToString16(scratch.arena, src);
|
||||
Dqn_String16 dest16 = Dqn_Win_String8ToString16(scratch.arena, dest);
|
||||
|
||||
int fail_if_exists = overwrite == false;
|
||||
result = CopyFileW(src16.data, dest16.data, fail_if_exists) != 0;
|
||||
|
||||
if (!result) {
|
||||
Dqn_WinErrorMsg error = Dqn_Win_LastError();
|
||||
Dqn_Log_ErrorF("Copy file failed [src=\"%.*s\", dest=\"%.*s\", reason=\"%.*s\"]",
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to copy the file\n\nSource: %.*s\nDestination: %.*s\n\nWindows reported: %.*s",
|
||||
DQN_STRING_FMT(src),
|
||||
DQN_STRING_FMT(dest),
|
||||
DQN_STRING_FMT(error));
|
||||
DQN_STRING_FMT(error.msg));
|
||||
}
|
||||
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
@ -355,11 +365,9 @@ DQN_API bool Dqn_Fs_MakeDir(Dqn_String8 path)
|
||||
{
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
bool result = true;
|
||||
Dqn_usize path_indexes_size = 0;
|
||||
uint16_t path_indexes[64] = {};
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16Allocator(path, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
|
||||
// NOTE: Go back from the end of the string to all the directories in the
|
||||
// string, and try to create them. Since Win32 API cannot create
|
||||
@ -373,56 +381,58 @@ DQN_API bool Dqn_Fs_MakeDir(Dqn_String8 path)
|
||||
// If we find a file at some point in the path we fail out because the
|
||||
// series of directories can not be made if a file exists with the same
|
||||
// name.
|
||||
for (Dqn_usize index = path16.size - 1; index < path16.size; index--) {
|
||||
for (Dqn_usize index = 0; index < path16.size; index++) {
|
||||
bool first_char = index == (path16.size - 1);
|
||||
wchar_t ch = path16.data[index];
|
||||
if (ch == '/' || ch == '\\' || first_char) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
wchar_t temp = path16.data[index];
|
||||
if (!first_char)
|
||||
path16.data[index] = 0; // Temporarily null terminate it
|
||||
|
||||
if (!first_char) path16.data[index] = 0; // Temporarily null terminate it
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrib_data = {};
|
||||
bool successful = GetFileAttributesExW(path16.data, GetFileExInfoStandard, &attrib_data); // Check
|
||||
if (!first_char) path16.data[index] = temp; // Undo null termination
|
||||
|
||||
if (successful) {
|
||||
if (attrib_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// NOTE: We found a directory, we can stop here and start
|
||||
// building up all the directories that didn't exist up to
|
||||
// this point.
|
||||
break;
|
||||
// NOTE: The directory exists, continue iterating the path
|
||||
} else {
|
||||
// NOTE: There's something that exists in at this path, but
|
||||
// it's not a directory. This request to make a directory is
|
||||
// invalid.
|
||||
// NOTE: There's some kind of file that exists at the path
|
||||
// but it's not a directory. This request to make a
|
||||
// directory is invalid.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// NOTE: There's nothing that exists at this path, we can create
|
||||
// a directory here
|
||||
path_indexes[path_indexes_size++] = DQN_CAST(uint16_t)index;
|
||||
result |= (CreateDirectoryW(path16.data, nullptr) == 0);
|
||||
}
|
||||
|
||||
if (!first_char)
|
||||
path16.data[index] = temp; // Undo null termination
|
||||
}
|
||||
}
|
||||
|
||||
for (Dqn_usize index = path_indexes_size - 1; result && index < path_indexes_size; index--) {
|
||||
uint16_t path_index = path_indexes[index];
|
||||
wchar_t temp = path16.data[path_index];
|
||||
|
||||
if (index != 0) path16.data[path_index] = 0;
|
||||
result |= (CreateDirectoryW(path16.data, nullptr) == 0);
|
||||
if (index != 0) path16.data[path_index] = temp;
|
||||
}
|
||||
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
|
||||
// TODO(doyle): Implement this without using the path indexes, it's not
|
||||
// necessary. See Windows implementation.
|
||||
Dqn_usize path_indexes_size = 0;
|
||||
uint16_t path_indexes[64] = {};
|
||||
|
||||
Dqn_String8 copy = Dqn_String8_Copy(scratch.arena, path);
|
||||
for (Dqn_usize index = copy.size - 1; index < copy.size; index--) {
|
||||
bool first_char = index == (copy.size - 1);
|
||||
char ch = copy.data[index];
|
||||
if (ch == '/' || first_char) {
|
||||
char temp = copy.data[index];
|
||||
if (!first_char) copy.data[index] = 0; // Temporarily null terminate it
|
||||
|
||||
if (!first_char)
|
||||
copy.data[index] = 0; // Temporarily null terminate it
|
||||
|
||||
bool is_file = Dqn_Fs_Exists(copy);
|
||||
if (!first_char) copy.data[index] = temp; // Undo null termination
|
||||
|
||||
if (!first_char)
|
||||
copy.data[index] = temp; // Undo null termination
|
||||
|
||||
if (is_file) {
|
||||
// NOTE: There's something that exists in at this path, but
|
||||
@ -466,8 +476,8 @@ DQN_API bool Dqn_Fs_Move(Dqn_String8 src, Dqn_String8 dest, bool overwrite)
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 src16 = Dqn_Win_String8ToString16Allocator(src, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 dest16 = Dqn_Win_String8ToString16Allocator(dest, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 src16 = Dqn_Win_String8ToString16(scratch.arena, src);
|
||||
Dqn_String16 dest16 = Dqn_Win_String8ToString16(scratch.arena, dest);
|
||||
|
||||
unsigned long flags = MOVEFILE_COPY_ALLOWED;
|
||||
if (overwrite) {
|
||||
@ -476,10 +486,12 @@ DQN_API bool Dqn_Fs_Move(Dqn_String8 src, Dqn_String8 dest, bool overwrite)
|
||||
|
||||
result = MoveFileExW(src16.data, dest16.data, flags) != 0;
|
||||
if (!result) {
|
||||
Dqn_Log_ErrorF("Failed to move file [from=%.*s, to=%.*s, reason=%.*s]",
|
||||
Dqn_ThreadScratch inner_scratch = Dqn_Thread_GetScratch(scratch.arena);
|
||||
Dqn_WinError error = Dqn_Win_LastError(inner_scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to move the file\n\nSource: %.*s\nDestination: %.*s\n\nWindows reported: %.*s",
|
||||
DQN_STRING_FMT(src),
|
||||
DQN_STRING_FMT(dest),
|
||||
DQN_STRING_FMT(Dqn_Win_LastError()));
|
||||
DQN_STRING_FMT(error.msg));
|
||||
}
|
||||
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
@ -504,13 +516,16 @@ DQN_API bool Dqn_Fs_Move(Dqn_String8 src, Dqn_String8 dest, bool overwrite)
|
||||
DQN_API bool Dqn_Fs_Delete(Dqn_String8 path)
|
||||
{
|
||||
bool result = false;
|
||||
if (!Dqn_String8_IsValid(path))
|
||||
return result;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
wchar_t path16[DQN_OS_WIN32_MAX_PATH];
|
||||
int path16_size = Dqn_Win_String8ToCString16(path, path16, DQN_ARRAY_ICOUNT(path16));
|
||||
if (path16_size) {
|
||||
result = DeleteFileW(path16);
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
if (path16.size) {
|
||||
result = DeleteFileW(path16.data);
|
||||
if (!result)
|
||||
result = RemoveDirectoryW(path16);
|
||||
result = RemoveDirectoryW(path16.data);
|
||||
}
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
result = remove(path.data) == 0;
|
||||
@ -534,15 +549,12 @@ DQN_API char *Dqn_Fs_ReadCString8(char const *path, Dqn_usize path_size, Dqn_usi
|
||||
(void)file_size;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
// NOTE: Convert to UTF16
|
||||
// -------------------------------------------------------------------------
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
|
||||
Dqn_String8 path8 = Dqn_String8_Init(path, path_size);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16Allocator(path8, scratch.allocator);
|
||||
Dqn_WinErrorMsg error_msg = {};
|
||||
// NOTE: Convert to UTF16 ==================================================
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
|
||||
Dqn_String8 path8 = Dqn_String8_Init(path, path_size);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path8);
|
||||
|
||||
// NOTE: Get the file handle
|
||||
// -------------------------------------------------------------------------
|
||||
// NOTE: Get the file handle ===============================================
|
||||
void *file_handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data,
|
||||
/*DWORD dwDesiredAccess*/ GENERIC_READ,
|
||||
/*DWORD dwShareMode*/ 0,
|
||||
@ -551,8 +563,8 @@ DQN_API char *Dqn_Fs_ReadCString8(char const *path, Dqn_usize path_size, Dqn_usi
|
||||
/*DWORD dwFlagsAndAttributes*/ FILE_ATTRIBUTE_READONLY,
|
||||
/*HANDLE hTemplateFile*/ nullptr);
|
||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||
Dqn_Win_LastErrorToBuffer(&error_msg);
|
||||
Dqn_Log_ErrorF("Failed to open file for reading [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error_msg));
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to open file for reading [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error.msg));
|
||||
return nullptr;
|
||||
}
|
||||
DQN_DEFER { CloseHandle(file_handle); };
|
||||
@ -561,8 +573,8 @@ DQN_API char *Dqn_Fs_ReadCString8(char const *path, Dqn_usize path_size, Dqn_usi
|
||||
// -------------------------------------------------------------------------
|
||||
LARGE_INTEGER win_file_size;
|
||||
if (!GetFileSizeEx(file_handle, &win_file_size)) {
|
||||
Dqn_Win_LastErrorToBuffer(&error_msg);
|
||||
Dqn_Log_ErrorF("Failed to query file size [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error_msg));
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to query file size [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error.msg));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -587,19 +599,19 @@ DQN_API char *Dqn_Fs_ReadCString8(char const *path, Dqn_usize path_size, Dqn_usi
|
||||
|
||||
if (read_result == 0) {
|
||||
Dqn_Allocator_Dealloc(allocator, result, bytes_desired);
|
||||
Dqn_Win_LastErrorToBuffer(&error_msg);
|
||||
Dqn_Log_ErrorF("'ReadFile' failed to load file to memory [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error_msg));
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("'ReadFile' failed to load file to memory [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error.msg));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (bytes_read != bytes_desired) {
|
||||
Dqn_Win_LastErrorToBuffer(&error_msg);
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Allocator_Dealloc(allocator, result, bytes_desired);
|
||||
Dqn_Log_ErrorF("'ReadFile' failed to read all bytes into file [file=%.*s, bytes_desired=%u, bytes_read=%u, reason=%.*s]",
|
||||
DQN_STRING_FMT(path8),
|
||||
bytes_desired,
|
||||
bytes_read,
|
||||
DQN_STRING_FMT(error_msg));
|
||||
DQN_STRING_FMT(error.msg));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -666,7 +678,7 @@ DQN_API bool Dqn_Fs_WriteCString8(char const *path, Dqn_usize path_size, char co
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 path8 = Dqn_String8_Init(path, path_size);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16Allocator(path8, scratch.allocator);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path8);
|
||||
|
||||
void *file_handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data,
|
||||
/*DWORD dwDesiredAccess*/ GENERIC_WRITE,
|
||||
@ -677,7 +689,8 @@ DQN_API bool Dqn_Fs_WriteCString8(char const *path, Dqn_usize path_size, char co
|
||||
/*HANDLE hTemplateFile*/ nullptr);
|
||||
|
||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||
Dqn_Log_ErrorF("Failed to open file for writing [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(Dqn_Win_LastError()));
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to open file for writing [file=%.*s, reason=%.*s]", DQN_STRING_FMT(path8), DQN_STRING_FMT(error.msg));
|
||||
return result;
|
||||
}
|
||||
DQN_DEFER { CloseHandle(file_handle); };
|
||||
@ -748,7 +761,7 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u
|
||||
}
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16Allocator(path, scratch.allocator);
|
||||
Dqn_String16 path16 = Dqn_Win_String8ToString16(scratch.arena, path);
|
||||
void *handle = CreateFileW(/*LPCWSTR lpFileName*/ path16.data,
|
||||
/*DWORD dwDesiredAccess*/ access_mode,
|
||||
/*DWORD dwShareMode*/ 0,
|
||||
@ -758,12 +771,12 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u
|
||||
/*HANDLE hTemplateFile*/ nullptr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
Dqn_WinErrorMsg msg = Dqn_Win_LastError();
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
result.error_size =
|
||||
DQN_CAST(uint16_t) Dqn_SNPrintFDotTruncate(result.error,
|
||||
DQN_ARRAY_UCOUNT(result.error),
|
||||
"Open file failed: %.*s for \"%.*s\"",
|
||||
DQN_STRING_FMT(msg),
|
||||
DQN_STRING_FMT(error.msg),
|
||||
DQN_STRING_FMT(path));
|
||||
return result;
|
||||
}
|
||||
@ -842,12 +855,13 @@ DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize si
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
Dqn_WinErrorMsg msg = Dqn_Win_LastError();
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
file->error_size =
|
||||
DQN_CAST(uint16_t) Dqn_SNPrintFDotTruncate(file->error,
|
||||
DQN_ARRAY_UCOUNT(file->error),
|
||||
"Write file failed: %.*s for %.*s",
|
||||
DQN_STRING_FMT(msg));
|
||||
DQN_STRING_FMT(error.msg));
|
||||
}
|
||||
#else
|
||||
result = fwrite(buffer, DQN_CAST(Dqn_usize)size, 1 /*count*/, file->handle) == 1 /*count*/;
|
||||
@ -917,7 +931,7 @@ DQN_API bool Dqn_FsPath_Add(Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_String8 p
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_FsPath_AddF(Dqn_Arena *arena, Dqn_FsPath *fs_path, char const *fmt, ...)
|
||||
DQN_API bool Dqn_FsPath_AddF(Dqn_Arena *arena, Dqn_FsPath *fs_path, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -957,7 +971,7 @@ DQN_API Dqn_String8 Dqn_FsPath_Convert(Dqn_Arena *arena, Dqn_String8 path)
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_FsPath_ConvertF(Dqn_Arena *arena, char const *fmt, ...)
|
||||
DQN_API Dqn_String8 Dqn_FsPath_ConvertF(Dqn_Arena *arena, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
|
||||
va_list args;
|
||||
@ -1095,41 +1109,45 @@ DQN_API uint64_t Dqn_Date_EpochTime()
|
||||
#if defined(DQN_OS_WIN32)
|
||||
#if !defined(DQN_NO_WIN)
|
||||
// NOTE: [$WIND] Dqn_Win ===========================================================================
|
||||
DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg)
|
||||
DQN_API Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena)
|
||||
{
|
||||
msg->code = GetLastError();
|
||||
msg->data[0] = 0;
|
||||
Dqn_WinError result = {};
|
||||
result.code = GetLastError();
|
||||
if (arena) {
|
||||
unsigned long flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
void *module_to_get_errors_from = nullptr;
|
||||
|
||||
unsigned long flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
void *module_to_get_errors_from = nullptr;
|
||||
if (result.code >= 12000 && result.code <= 12175) { // WinINET Errors
|
||||
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
module_to_get_errors_from = GetModuleHandleA("wininet.dll");
|
||||
}
|
||||
|
||||
if (msg->code >= 12000 && msg->code <= 12175) { // WinINET Errors
|
||||
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
module_to_get_errors_from = GetModuleHandleA("wininet.dll");
|
||||
int32_t size = FormatMessageA(flags,
|
||||
module_to_get_errors_from, // LPCVOID lpSource,
|
||||
result.code, // unsigned long dwMessageId,
|
||||
0, // unsigned long dwLanguageId,
|
||||
nullptr, // LPSTR lpBuffer,
|
||||
0, // unsigned long nSize,
|
||||
nullptr); // va_list * Arguments
|
||||
|
||||
if (size) {
|
||||
Dqn_String8 buffer = Dqn_String8_Allocate(Dqn_Arena_Allocator(arena), size, Dqn_ZeroMem_No);
|
||||
int32_t buffer_size = DQN_CAST(int32_t)buffer.size;
|
||||
int32_t new_size = FormatMessageA(flags,
|
||||
module_to_get_errors_from, // LPCVOID lpSource,
|
||||
result.code, // unsigned long dwMessageId,
|
||||
0, // unsigned long dwLanguageId,
|
||||
buffer.data, // LPSTR lpBuffer,
|
||||
buffer_size, // unsigned long nSize,
|
||||
nullptr); // va_list * Arguments
|
||||
if (DQN_CHECK(new_size == size)) {
|
||||
result.msg = buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg->size = FormatMessageA(flags,
|
||||
module_to_get_errors_from, // LPCVOID lpSource,
|
||||
msg->code, // unsigned long dwMessageId,
|
||||
0, // unsigned long dwLanguageId,
|
||||
msg->data, // LPSTR lpBuffer,
|
||||
DQN_ARRAY_ICOUNT(msg->data), // unsigned long nSize,
|
||||
nullptr); // va_list * Arguments
|
||||
|
||||
if (msg->size >= 2 &&
|
||||
(msg->data[msg->size - 2] == '\r' && msg->data[msg->size - 1] == '\n')) {
|
||||
msg->size -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
DQN_API Dqn_WinErrorMsg Dqn_Win_LastError()
|
||||
{
|
||||
Dqn_WinErrorMsg result = {};
|
||||
Dqn_Win_LastErrorToBuffer(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DQN_API void Dqn_Win_MakeProcessDPIAware()
|
||||
{
|
||||
typedef bool SetProcessDpiAwareProc(void);
|
||||
@ -1141,6 +1159,9 @@ DQN_API void Dqn_Win_MakeProcessDPIAware()
|
||||
// GetProcAddress on the DPI function. If it's not there, we're on an old
|
||||
// version of windows, so we can call an older version of the API.
|
||||
void *lib_handle = LoadLibraryA("user32.dll");
|
||||
if (!lib_handle)
|
||||
return;
|
||||
|
||||
if (auto *set_process_dpi_awareness_context = DQN_CAST(SetProcessDpiAwarenessContextProc *)GetProcAddress(DQN_CAST(HMODULE)lib_handle, "SetProcessDpiAwarenessContext")) {
|
||||
set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
} else if (auto *set_process_dpi_awareness = DQN_CAST(SetProcessDpiAwarenessProc *)GetProcAddress(DQN_CAST(HMODULE)lib_handle, "SetProcessDpiAwareness")) {
|
||||
@ -1150,145 +1171,130 @@ DQN_API void Dqn_Win_MakeProcessDPIAware()
|
||||
}
|
||||
}
|
||||
|
||||
DQN_API void Dqn_Win_DumpLastError_(Dqn_CallSite call_site, char const *fmt, ...)
|
||||
{
|
||||
// TODO(dqn): Hmmm .. should this be a separate log or part of the above
|
||||
// macro. If so we need to make the logging macros more flexible.
|
||||
Dqn_WinErrorMsg msg = Dqn_Win_LastError();
|
||||
if (fmt) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Dqn_Log_TypeFVCallSite(Dqn_LogType_Error, call_site, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (msg.size)
|
||||
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, call_site, "Last Windows error [msg=%.*s]", DQN_STRING_FMT(msg));
|
||||
else
|
||||
Dqn_Log_TypeFCallSite(Dqn_LogType_Error, call_site, "Failed to dump last error, no error message found [format_message_error=%d, msg_error=%d]", GetLastError(), msg.code);
|
||||
}
|
||||
|
||||
// NOTE: Windows UTF8 to String16
|
||||
// -----------------------------------------------------------------------------
|
||||
DQN_API int Dqn_Win_CString8ToCString16(const char *src, int src_size, wchar_t *dest, int dest_size)
|
||||
{
|
||||
int result = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src, src_size, dest, dest_size);
|
||||
if (result && dest && dest_size > 0)
|
||||
dest[DQN_MIN(result, dest_size - 1)] = 0; // Null-terminate the buffer
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API int Dqn_Win_String8ToCString16(Dqn_String8 src, wchar_t *dest, int dest_size)
|
||||
{
|
||||
int result = 0;
|
||||
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
|
||||
if (src_size)
|
||||
result = Dqn_Win_CString8ToCString16(src.data, src_size, dest, dest_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String16 Dqn_Win_String8ToString16Allocator(Dqn_String8 src, Dqn_Allocator allocator)
|
||||
// NOTE: Windows UTF8 to String16 ==============================================
|
||||
DQN_API Dqn_String16 Dqn_Win_String8ToString16(Dqn_Arena *arena, Dqn_String8 src)
|
||||
{
|
||||
Dqn_String16 result = {};
|
||||
int required = Dqn_Win_String8ToCString16(src, nullptr, 0);
|
||||
if (required > 0) {
|
||||
result.data = Dqn_Allocator_NewArray(allocator, wchar_t, required + 1, Dqn_ZeroMem_No);
|
||||
if (result.data) {
|
||||
result.size = Dqn_Win_String8ToCString16(src, result.data, required + 1);
|
||||
DQN_ASSERT(result.size == DQN_CAST(Dqn_usize)required);
|
||||
}
|
||||
if (!arena || !Dqn_String8_IsValid(src))
|
||||
return result;
|
||||
|
||||
int required_size = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DQN_CAST(int)src.size, nullptr /*dest*/, 0 /*dest size*/);
|
||||
if (required_size <= 0)
|
||||
return result;
|
||||
|
||||
wchar_t *buffer = Dqn_Arena_NewArray(arena, wchar_t, required_size + 1, Dqn_ZeroMem_No);
|
||||
if (!buffer)
|
||||
return result;
|
||||
|
||||
int chars_written = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DQN_CAST(int)src.size, buffer, required_size);
|
||||
if (DQN_CHECK(chars_written == required_size)) {
|
||||
result.data = buffer;
|
||||
result.size = chars_written;
|
||||
result.data[result.size] = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: Windows String16 To UTF8
|
||||
// -----------------------------------------------------------------------------
|
||||
DQN_API int Dqn_Win_CString16ToCString8(const wchar_t* src, int src_size, char *dest, int dest_size)
|
||||
{
|
||||
int result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src, src_size, dest, dest_size, nullptr, nullptr);
|
||||
if (result && dest && dest_size > 0)
|
||||
dest[DQN_MIN(result, dest_size - 1)] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_Win_CString16ToString8Allocator(const wchar_t* src, int src_size, Dqn_Allocator allocator)
|
||||
{
|
||||
Dqn_String8 result = {};
|
||||
int required = Dqn_Win_CString16ToCString8(src, src_size, nullptr, 0);
|
||||
if (required > 0) {
|
||||
// NOTE: String allocate ensures there's one extra byte for
|
||||
// null-termination already so no-need to +1 the required size
|
||||
result = Dqn_String8_Allocate(allocator, DQN_CAST(Dqn_usize)required, Dqn_ZeroMem_No);
|
||||
if (Dqn_String8_IsValid(result)) {
|
||||
int next_required = Dqn_Win_CString16ToCString8(src, src_size, result.data, required + 1);
|
||||
DQN_ASSERT(required == next_required);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API int Dqn_Win_String16ToCString8(Dqn_String16 src, char *dest, int dest_size)
|
||||
DQN_API int Dqn_Win_String8ToString16Buffer(Dqn_String8 src, wchar_t *dest, Dqn_usize dest_size)
|
||||
{
|
||||
int result = 0;
|
||||
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
|
||||
if (src_size) {
|
||||
result = Dqn_Win_CString16ToCString8(src.data, src_size, dest, dest_size);
|
||||
}
|
||||
if (!Dqn_String8_IsValid(src))
|
||||
return result;
|
||||
|
||||
result = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DQN_CAST(int)src.size, nullptr /*dest*/, 0 /*dest size*/);
|
||||
if (result <= 0 || result > dest_size || !dest)
|
||||
return result;
|
||||
|
||||
result = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DQN_CAST(int)src.size, dest, DQN_CAST(int)dest_size);
|
||||
dest[DQN_MIN(result, dest_size - 1)] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_Win_String16ToString8Allocator(Dqn_String16 src, Dqn_Allocator allocator)
|
||||
// NOTE: Windows String16 To UTF8 ==================================================================
|
||||
DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *dest, Dqn_usize dest_size)
|
||||
{
|
||||
int result = 0;
|
||||
if (!Dqn_String8_IsValid(src))
|
||||
return result;
|
||||
|
||||
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
|
||||
if (src_size <= 0)
|
||||
return result;
|
||||
|
||||
result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, nullptr /*dest*/, 0 /*dest size*/, nullptr, nullptr);
|
||||
if (result <= 0 || result > dest_size || !dest)
|
||||
return result;
|
||||
|
||||
result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, dest, DQN_CAST(int)dest_size, nullptr, nullptr);
|
||||
dest[DQN_MIN(result, dest_size - 1)] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_Win_String16ToString8(Dqn_Arena *arena, Dqn_String16 src)
|
||||
{
|
||||
Dqn_String8 result = {};
|
||||
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
|
||||
if (src_size) {
|
||||
result = Dqn_Win_CString16ToString8Allocator(src.data, src_size, allocator);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: Windows Executable Directory
|
||||
// -----------------------------------------------------------------------------
|
||||
DQN_API Dqn_usize Dqn_Win_EXEDirW(wchar_t *buffer, Dqn_usize size)
|
||||
{
|
||||
wchar_t module_path[DQN_OS_WIN32_MAX_PATH];
|
||||
Dqn_usize module_size = DQN_CAST(Dqn_usize)GetModuleFileNameW(nullptr /*module*/, module_path, DQN_ARRAY_UCOUNT(module_path));
|
||||
DQN_HARD_ASSERTF(GetLastError() != ERROR_INSUFFICIENT_BUFFER, "How the hell?");
|
||||
|
||||
Dqn_usize result = 0;
|
||||
for (Dqn_usize index = module_size - 1; !result && index < module_size; index--)
|
||||
result = module_path[index] == '\\' ? index : 0;
|
||||
|
||||
if (!buffer || size < result) {
|
||||
if (!arena || !Dqn_String8_IsValid(src))
|
||||
return result;
|
||||
|
||||
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
|
||||
if (src_size <= 0)
|
||||
return result;
|
||||
|
||||
int required_size = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, nullptr /*dest*/, 0 /*dest size*/, nullptr, nullptr);
|
||||
if (required_size <= 0)
|
||||
return result;
|
||||
|
||||
// NOTE: String allocate ensures there's one extra byte for
|
||||
// null-termination already so no-need to +1 the required size
|
||||
Dqn_ArenaTempMemory temp_memory = Dqn_Arena_BeginTempMemory(arena);
|
||||
Dqn_String8 buffer = Dqn_String8_Allocate(Dqn_Arena_Allocator(arena), required_size, Dqn_ZeroMem_No);
|
||||
if (!Dqn_String8_IsValid(buffer))
|
||||
return result;
|
||||
|
||||
int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DQN_CAST(int)buffer.size, nullptr, nullptr);
|
||||
if (DQN_CHECK(chars_written == required_size)) {
|
||||
result = buffer;
|
||||
result.data[result.size] = 0;
|
||||
} else {
|
||||
// NOTE: Revert the temp memory because we encountered an error
|
||||
Dqn_Arena_EndTempMemory(temp_memory, false /*cancel*/);
|
||||
}
|
||||
|
||||
DQN_MEMCPY(buffer, module_path, sizeof(wchar_t) * result);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String16 Dqn_Win_EXEDirWArena(Dqn_Arena *arena)
|
||||
// NOTE: Windows Executable Directory ==========================================
|
||||
DQN_API Dqn_String16 Dqn_Win_EXEDirW(Dqn_Arena *arena)
|
||||
{
|
||||
wchar_t dir[DQN_OS_WIN32_MAX_PATH];
|
||||
Dqn_usize dir_size = Dqn_Win_EXEDirW(dir, DQN_ARRAY_ICOUNT(dir));
|
||||
DQN_HARD_ASSERTF(dir_size <= DQN_ARRAY_ICOUNT(dir), "How the hell?");
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
|
||||
Dqn_String16 result = {};
|
||||
Dqn_usize module_size = 0;
|
||||
wchar_t *module_path = nullptr;
|
||||
do {
|
||||
module_size += 256;
|
||||
module_path = Dqn_Arena_NewArray(scratch.arena, wchar_t, module_size, Dqn_ZeroMem_No);
|
||||
if (!module_path)
|
||||
return result;
|
||||
module_size = DQN_CAST(Dqn_usize)GetModuleFileNameW(nullptr /*module*/, module_path, DQN_CAST(int)module_size);
|
||||
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
Dqn_String16 result = {};
|
||||
if (dir_size > 0) {
|
||||
result.data = Dqn_Arena_NewArrayCopyZ(arena, wchar_t, dir, dir_size);
|
||||
if (result.data) {
|
||||
result.size = dir_size;
|
||||
}
|
||||
}
|
||||
Dqn_usize index_of_last_slash = 0;
|
||||
for (Dqn_usize index = module_size - 1; !index_of_last_slash && index < module_size; index--)
|
||||
index_of_last_slash = module_path[index] == '\\' ? index : 0;
|
||||
|
||||
result.data = Dqn_Arena_NewArray(arena, wchar_t, index_of_last_slash + 1, Dqn_ZeroMem_No);
|
||||
result.size = index_of_last_slash;
|
||||
DQN_MEMCPY(result.data, module_path, sizeof(wchar_t) * result.size);
|
||||
result.data[result.size] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_Win_WorkingDir(Dqn_Allocator allocator, Dqn_String8 suffix)
|
||||
{
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(allocator.user_context);
|
||||
Dqn_String16 suffix16 = Dqn_Win_String8ToString16Allocator(suffix, Dqn_Arena_Allocator(scratch.arena));
|
||||
Dqn_String16 suffix16 = Dqn_Win_String8ToString16(scratch.arena, suffix);
|
||||
Dqn_String16 dir16 = Dqn_Win_WorkingDirW(Dqn_Arena_Allocator(scratch.arena), suffix16);
|
||||
Dqn_String8 result = Dqn_Win_String16ToString8Allocator(dir16, allocator);
|
||||
Dqn_String8 result = Dqn_Win_String16ToString8(scratch.arena, dir16);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1367,11 +1373,9 @@ DQN_API bool Dqn_Win_FolderIterate(Dqn_String8 path, Dqn_Win_FolderIterator *it)
|
||||
if (!Dqn_String8_IsValid(path) || !it || path.size <= 0)
|
||||
return false;
|
||||
|
||||
wchar_t path16[DQN_OS_WIN32_MAX_PATH + 1];
|
||||
path16[0] = 0;
|
||||
Dqn_usize path16_size = 0;
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_Win_FolderIteratorW wide_it = {};
|
||||
Dqn_String16 path16 = {};
|
||||
if (it->handle) {
|
||||
wide_it.handle = it->handle;
|
||||
} else {
|
||||
@ -1380,34 +1384,26 @@ DQN_API bool Dqn_Win_FolderIterate(Dqn_String8 path, Dqn_Win_FolderIterator *it)
|
||||
bool has_glob = Dqn_String8_EndsWith(path, DQN_STRING8("\\*")) ||
|
||||
Dqn_String8_EndsWith(path, DQN_STRING8("/*"));
|
||||
|
||||
path16_size = Dqn_Win_String8ToCString16(path, path16, DQN_ARRAY_UCOUNT(path16));
|
||||
if (path16_size <= 0) // Conversion error
|
||||
return false;
|
||||
|
||||
Dqn_String8 adjusted_path = path;
|
||||
if (!has_glob) {
|
||||
// NOTE: We are missing the glob for enumerating the files, we will
|
||||
// add those characters in this branch, so overwrite the null
|
||||
// character, add the glob and re-null terminate the buffer.
|
||||
Dqn_usize space = DQN_OS_WIN32_MAX_PATH - path16_size;
|
||||
if (needs_asterisks) {
|
||||
if (space < 2)
|
||||
return false;
|
||||
path16[path16_size++] = L'*';
|
||||
} else {
|
||||
if (space < 3)
|
||||
return false;
|
||||
path16[path16_size++] = L'\\';
|
||||
path16[path16_size++] = L'*';
|
||||
}
|
||||
path16[path16_size++] = 0;
|
||||
if (needs_asterisks)
|
||||
adjusted_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s*", DQN_STRING_FMT(path));
|
||||
else
|
||||
adjusted_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/*", DQN_STRING_FMT(path));
|
||||
}
|
||||
DQN_ASSERT(path16_size <= DQN_OS_WIN32_MAX_PATH);
|
||||
|
||||
path16 = Dqn_Win_String8ToString16(scratch.arena, adjusted_path);
|
||||
if (path16.size <= 0) // Conversion error
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = Dqn_Win_FolderWIterate(Dqn_String16{path16, path16_size}, &wide_it);
|
||||
it->handle = wide_it.handle;
|
||||
bool result = Dqn_Win_FolderWIterate(path16, &wide_it);
|
||||
it->handle = wide_it.handle;
|
||||
if (result) {
|
||||
int size = Dqn_Win_String16ToCString8(wide_it.file_name, it->file_name_buf, DQN_ARRAY_ICOUNT(it->file_name_buf));
|
||||
int size = Dqn_Win_String16ToString8Buffer(wide_it.file_name, it->file_name_buf, DQN_ARRAY_UCOUNT(it->file_name_buf));
|
||||
it->file_name = Dqn_String8_Init(it->file_name_buf, size);
|
||||
}
|
||||
|
||||
@ -1427,7 +1423,14 @@ DQN_API Dqn_WinNetHandle Dqn_Win_NetHandleInitCString(char const *url, int url_s
|
||||
// Seperate the URL into bits and bobs
|
||||
Dqn_WinNetHandle result = {};
|
||||
if (!InternetCrackUrlA(url, url_size, 0 /*flags*/, &components)) {
|
||||
Dqn_Log_ErrorF("InternetCrackUrlA failed [reason=%.*s]", DQN_STRING_FMT(Dqn_Win_LastError()));
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("InternetCrackUrlA failed [reason=%.*s]", DQN_STRING_FMT(error.msg));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (components.lpszHostName == nullptr) {
|
||||
Dqn_Log_ErrorF("Windows returnd a null host-name after trying to crack the URL.\n\nURL: %.*s", url_size, url);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1602,10 +1605,12 @@ DQN_API Dqn_WinNetHandleResponse Dqn_Win_NetHandleSendRequest(Dqn_WinNetHandle *
|
||||
|
||||
if (!HttpSendRequestA(handle->http_handle, nullptr /*headers*/, 0 /*headers length*/, (char *)post_data, post_data_size)) {
|
||||
handle->state = Dqn_WinNetHandleState_RequestFailed;
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_WinError error = Dqn_Win_LastError(scratch.arena);
|
||||
Dqn_Log_ErrorF("Failed to send request to %.*s [reason=%.*s]",
|
||||
handle->host_name_size,
|
||||
handle->host_name,
|
||||
DQN_STRING_FMT(Dqn_Win_LastError()));
|
||||
DQN_STRING_FMT(error.msg));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1864,36 +1869,33 @@ DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size)
|
||||
}
|
||||
|
||||
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
|
||||
DQN_API Dqn_String8 Dqn_OS_EXEDir(Dqn_Allocator allocator)
|
||||
DQN_API Dqn_String8 Dqn_OS_EXEDir(Dqn_Arena *arena)
|
||||
{
|
||||
Dqn_String8 result = {};
|
||||
if (!arena)
|
||||
return result;
|
||||
|
||||
#if defined(DQN_OS_WIN32)
|
||||
wchar_t exe_dir[DQN_OS_WIN32_MAX_PATH];
|
||||
Dqn_usize exe_dir_size = Dqn_Win_EXEDirW(exe_dir, DQN_ARRAY_ICOUNT(exe_dir));
|
||||
result = Dqn_Win_CString16ToString8Allocator(exe_dir, DQN_CAST(int)exe_dir_size, allocator);
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
|
||||
Dqn_String16 exe_dir16 = Dqn_Win_EXEDirW(scratch.arena);
|
||||
result = Dqn_Win_String16ToString8(arena, exe_dir16);
|
||||
|
||||
#elif defined(DQN_OS_UNIX)
|
||||
|
||||
int required_size_wo_null_terminator = 0;
|
||||
for (int try_size = 128;
|
||||
;
|
||||
try_size *= 2)
|
||||
{
|
||||
for (int try_size = 128;; try_size *= 2) {
|
||||
auto scoped_arena = Dqn_ArenaTempMemoryScope(arena);
|
||||
char *try_buf = Dqn_Arena_NewArray(arena, char, try_size, Dqn_ZeroMem_No);
|
||||
int bytes_written = readlink("/proc/self/exe", try_buf, try_size);
|
||||
if (bytes_written == -1)
|
||||
{
|
||||
if (bytes_written == -1) {
|
||||
// Failed, we're unable to determine the executable directory
|
||||
break;
|
||||
}
|
||||
else if (bytes_written == try_size)
|
||||
{
|
||||
} else if (bytes_written == try_size) {
|
||||
// Try again, if returned size was equal- we may of prematurely
|
||||
// truncated according to the man pages
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// readlink will give us the path to the executable. Once we
|
||||
// determine the correct buffer size required to get the full file
|
||||
// path, we do some post-processing on said string and extract just
|
||||
@ -1906,12 +1908,8 @@ DQN_API Dqn_String8 Dqn_OS_EXEDir(Dqn_Allocator allocator)
|
||||
DQN_ASSERTF(bytes_written < try_size, "bytes_written can never be greater than the try size, function writes at most try_size");
|
||||
required_size_wo_null_terminator = bytes_written;
|
||||
|
||||
for (int index_of_last_slash = bytes_written;
|
||||
index_of_last_slash >= 0;
|
||||
index_of_last_slash--)
|
||||
{
|
||||
if (try_buf[index_of_last_slash] == '/')
|
||||
{
|
||||
for (Dqn_isize index_of_last_slash = bytes_written; index_of_last_slash >= 0; index_of_last_slash--) {
|
||||
if (try_buf[index_of_last_slash] == '/') {
|
||||
// NOTE: We take the index of the last slash and not
|
||||
// (index_of_last_slash + 1) because we want to exclude the
|
||||
// trailing backslash as a convention of this library.
|
||||
@ -1919,27 +1917,22 @@ DQN_API Dqn_String8 Dqn_OS_EXEDir(Dqn_Allocator allocator)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (required_size_wo_null_terminator)
|
||||
{
|
||||
if (required_size_wo_null_terminator) {
|
||||
Dqn_ArenaTempMemory scope = Dqn_Arena_BeginTempMemory(arena);
|
||||
char *exe_path = Dqn_Arena_NewArray(arena, char, required_size_wo_null_terminator + 1, Dqn_ZeroMem_No);
|
||||
exe_path[required_size_wo_null_terminator] = 0;
|
||||
|
||||
int bytes_written = readlink("/proc/self/exe", exe_path, required_size_wo_null_terminator);
|
||||
if (bytes_written == -1)
|
||||
{
|
||||
if (bytes_written == -1) {
|
||||
// Note that if read-link fails again can be because there's
|
||||
// a potential race condition here, our exe or directory could have
|
||||
// been deleted since the last call, so we need to be careful.
|
||||
Dqn_Arena_EndTempMemory(scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
result = Dqn_String8_Init(exe_path, required_size_wo_null_terminator);
|
||||
}
|
||||
}
|
||||
|
@ -48,20 +48,20 @@ DQN_API Dqn_PrintStyle Dqn_Print_StyleBold ();
|
||||
|
||||
// NOTE: Print =====================================================================================
|
||||
DQN_API void Dqn_Print_Std (Dqn_PrintStd std_handle, Dqn_String8 string);
|
||||
DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, char const *fmt, va_list args);
|
||||
DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
|
||||
DQN_API void Dqn_Print_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
|
||||
DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, va_list args);
|
||||
DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
|
||||
DQN_API void Dqn_Print_StdLn (Dqn_PrintStd std_handle, Dqn_String8 string);
|
||||
DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, char const *fmt, va_list args);
|
||||
DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
|
||||
DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string);
|
||||
DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, char const *fmt, va_list args);
|
||||
DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
|
||||
// NOTE: ANSI Formatting Codes =====================================================================
|
||||
Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b);
|
||||
@ -225,11 +225,11 @@ struct Dqn_FsPath
|
||||
|
||||
DQN_API bool Dqn_FsPath_AddRef (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_String8 path);
|
||||
DQN_API bool Dqn_FsPath_Add (Dqn_Arena *arena, Dqn_FsPath *fs_path, Dqn_String8 path);
|
||||
DQN_API bool Dqn_FsPath_AddF (Dqn_Arena *arena, Dqn_FsPath *fs_path, char const *fmt, ...);
|
||||
DQN_API bool Dqn_FsPath_AddF (Dqn_Arena *arena, Dqn_FsPath *fs_path, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API bool Dqn_FsPath_Pop (Dqn_FsPath *fs_path);
|
||||
DQN_API Dqn_String8 Dqn_FsPath_BuildWithSeparator(Dqn_Arena *arena, Dqn_FsPath const *fs_path, Dqn_String8 path_separator);
|
||||
DQN_API Dqn_String8 Dqn_FsPath_Convert (Dqn_Arena *arena, Dqn_String8 path);
|
||||
DQN_API Dqn_String8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, char const *fmt, ...);
|
||||
DQN_API Dqn_String8 Dqn_FsPath_ConvertF (Dqn_Arena *arena, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
#define Dqn_FsPath_BuildFwdSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("/"))
|
||||
#define Dqn_FsPath_BuildBackSlash(arena, fs_path) Dqn_FsPath_BuildWithSeparator(arena, fs_path, DQN_STRING8("\\"))
|
||||
|
||||
@ -285,15 +285,13 @@ DQN_API uint64_t Dqn_Date_EpochTime ();
|
||||
// DPI aware on Windows and ensure that application UI is scaled up
|
||||
// appropriately for the monitor.
|
||||
|
||||
struct Dqn_WinErrorMsg
|
||||
struct Dqn_WinError
|
||||
{
|
||||
unsigned long code;
|
||||
char data[DQN_KILOBYTES(64) - 1]; // Maximum error size
|
||||
unsigned long size;
|
||||
Dqn_String8 msg;
|
||||
};
|
||||
DQN_API void Dqn_Win_LastErrorToBuffer(Dqn_WinErrorMsg *msg);
|
||||
DQN_API Dqn_WinErrorMsg Dqn_Win_LastError();
|
||||
DQN_API void Dqn_Win_MakeProcessDPIAware();
|
||||
DQN_API Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena);
|
||||
DQN_API void Dqn_Win_MakeProcessDPIAware();
|
||||
|
||||
// NOTE: Windows String8 <-> String16 ===========================================
|
||||
// Convert a UTF8 <-> UTF16 string.
|
||||
@ -308,16 +306,12 @@ DQN_API void Dqn_Win_MakeProcessDPIAware();
|
||||
// written/required for conversion. 0 if there was a conversion error and can be
|
||||
// queried using 'Dqn_Win_LastError'
|
||||
|
||||
DQN_API int Dqn_Win_CString8ToCString16 (char const *src, int src_size, wchar_t *dest, int dest_size);
|
||||
DQN_API int Dqn_Win_String8ToCString16 (Dqn_String8 src, wchar_t *dest, int dest_size);
|
||||
DQN_API Dqn_String16 Dqn_Win_String8ToString16Allocator (Dqn_String8 src, Dqn_Allocator allocator);
|
||||
DQN_API Dqn_String16 Dqn_Win_String8ToString16(Dqn_Arena *arena, Dqn_String8 src);
|
||||
DQN_API int Dqn_Win_String8ToString16Buffer(Dqn_String16 src, char *dest, Dqn_usize dest_size);
|
||||
DQN_API Dqn_String8 Dqn_Win_String16ToString8(Dqn_Arena *arena, Dqn_String16 src);
|
||||
DQN_API int Dqn_Win_String16ToString8Buffer(Dqn_String16 src, char *dest, Dqn_usize dest_size);
|
||||
|
||||
DQN_API int Dqn_Win_CString16ToCString8 (wchar_t const *src, int src_size, char *dest, int dest_size);
|
||||
DQN_API Dqn_String8 Dqn_Win_CString16ToString8Allocator(wchar_t const *src, int src_size, Dqn_Allocator allocator);
|
||||
DQN_API int Dqn_Win_String16ToCString8 (Dqn_String16 src, char *dest, int dest_size);
|
||||
DQN_API Dqn_String8 Dqn_Win_String16ToString8Allocator (Dqn_String16 src, Dqn_Allocator allocator);
|
||||
|
||||
// NOTE: Path navigatoin ===========================================================================
|
||||
// NOTE: Path navigation ===========================================================================
|
||||
// NOTE: API =======================================================================================
|
||||
// @proc Dqn_Win_EXEDirW, Dqn_Win_EXEDirWArena
|
||||
// @desc Evaluate the current executable's directory that is running when this
|
||||
@ -354,8 +348,7 @@ struct Dqn_Win_FolderIterator
|
||||
char file_name_buf[512];
|
||||
};
|
||||
|
||||
DQN_API Dqn_usize Dqn_Win_EXEDirW (wchar_t *buffer, Dqn_usize size);
|
||||
DQN_API Dqn_String16 Dqn_Win_EXEDirWArena (Dqn_Arena *arena);
|
||||
DQN_API Dqn_String16 Dqn_Win_EXEDirW (Dqn_Arena *arena);
|
||||
DQN_API Dqn_String8 Dqn_Win_WorkingDir (Dqn_Allocator allocator, Dqn_String8 suffix);
|
||||
DQN_API Dqn_String16 Dqn_Win_WorkingDirW (Dqn_Allocator allocator, Dqn_String16 suffix);
|
||||
DQN_API bool Dqn_Win_FolderIterate (Dqn_String8 path, Dqn_Win_FolderIterator *it);
|
||||
@ -503,7 +496,7 @@ struct Dqn_OSTimer
|
||||
|
||||
DQN_API bool Dqn_OS_SecureRNGBytes (void *buffer, uint32_t size);
|
||||
#if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32)
|
||||
DQN_API Dqn_String8 Dqn_OS_EXEDir (Dqn_Allocator allocator);
|
||||
DQN_API Dqn_String8 Dqn_OS_EXEDir (Dqn_Arena* arena);
|
||||
#endif
|
||||
DQN_API void Dqn_OS_SleepMs (Dqn_uint milliseconds);
|
||||
DQN_API uint64_t Dqn_OS_PerfCounterNow ();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// NOTE: [$CSTR] Dqn_CString8 ======================================================================
|
||||
DQN_API Dqn_usize Dqn_CString8_FSize(char const *fmt, ...)
|
||||
DQN_API Dqn_usize Dqn_CString8_FSize(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -8,7 +8,7 @@ DQN_API Dqn_usize Dqn_CString8_FSize(char const *fmt, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_usize Dqn_CString8_FVSize(char const *fmt, va_list args)
|
||||
DQN_API Dqn_usize Dqn_CString8_FVSize(DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
@ -47,12 +47,6 @@ DQN_API Dqn_String8 Dqn_String8_InitCString8(char const *src)
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_String8_IsValid(Dqn_String8 string)
|
||||
{
|
||||
bool result = string.data;
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_String8_IsAll(Dqn_String8 string, Dqn_String8IsAll is_all)
|
||||
{
|
||||
bool result = Dqn_String8_IsValid(string);
|
||||
@ -364,14 +358,17 @@ DQN_API Dqn_String8 Dqn_String8_FileNameFromPath(Dqn_String8 path)
|
||||
if (!Dqn_String8_IsValid(result))
|
||||
return result;
|
||||
|
||||
for (Dqn_usize i = result.size - 1; i < result.size; --i) {
|
||||
if (result.data[i] == '\\' || result.data[i] == '/') {
|
||||
DQN_MSVC_WARNING_PUSH
|
||||
DQN_MSVC_WARNING_DISABLE(6293) // Ill-defined for-loop.
|
||||
for (Dqn_usize index = result.size - 1; index < result.size; --index) {
|
||||
if (result.data[index] == '\\' || result.data[index] == '/') {
|
||||
char const *end = result.data + result.size;
|
||||
result.data = result.data + (i + 1);
|
||||
result.data = result.data + (index + 1);
|
||||
result.size = end - result.data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DQN_MSVC_WARNING_POP
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -548,7 +545,7 @@ DQN_API bool operator!=(Dqn_String8 const &lhs, Dqn_String8 const &rhs)
|
||||
}
|
||||
#endif
|
||||
|
||||
DQN_API Dqn_String8 Dqn_String8_InitF(Dqn_Allocator allocator, char const *fmt, ...)
|
||||
DQN_API Dqn_String8 Dqn_String8_InitF(Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
@ -557,7 +554,7 @@ DQN_API Dqn_String8 Dqn_String8_InitF(Dqn_Allocator allocator, char const *fmt,
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_String8 Dqn_String8_InitFV(Dqn_Allocator allocator, char const *fmt, va_list args)
|
||||
DQN_API Dqn_String8 Dqn_String8_InitFV(Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_String8 result = {};
|
||||
if (!fmt)
|
||||
@ -632,7 +629,7 @@ DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_Stri
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_String8Builder_AppendFV(Dqn_String8Builder *builder, char const *fmt, va_list args)
|
||||
DQN_API bool Dqn_String8Builder_AppendFV(Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
Dqn_String8 string = Dqn_String8_InitFV(builder->allocator, fmt, args);
|
||||
if (string.size == 0)
|
||||
@ -644,7 +641,7 @@ DQN_API bool Dqn_String8Builder_AppendFV(Dqn_String8Builder *builder, char const
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, char const *fmt, ...)
|
||||
DQN_API bool Dqn_String8Builder_AppendF(Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@ -718,17 +715,18 @@ DQN_API uint8_t Dqn_Char_HexToU8(char ch)
|
||||
return result;
|
||||
}
|
||||
|
||||
char constexpr DQN_HEX_LUT[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
static char constexpr DQN_HEX_LUT[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
DQN_API char Dqn_Char_ToHex(char ch)
|
||||
{
|
||||
char result = DQN_CAST(char)-1;
|
||||
if (ch <= 16) result = DQN_HEX_LUT[DQN_CAST(unsigned)ch];
|
||||
if (ch < 16)
|
||||
result = DQN_HEX_LUT[ch];
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API char Dqn_Char_ToHexUnchecked(char ch)
|
||||
{
|
||||
char result = DQN_HEX_LUT[DQN_CAST(unsigned)ch];
|
||||
char result = DQN_HEX_LUT[ch];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CString8_ArrayUCount(char const (&literal)[N]) { (void)literal; return N - 1; }
|
||||
DQN_API template <Dqn_usize N> constexpr Dqn_usize Dqn_CString8_ArrayICount(char const (&literal)[N]) { (void)literal; return N - 1; }
|
||||
DQN_API Dqn_usize Dqn_CString8_FSize (char const *fmt, ...);
|
||||
DQN_API Dqn_usize Dqn_CString8_FVSize (char const *fmt, va_list args);
|
||||
DQN_API Dqn_usize Dqn_CString8_FSize (DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API Dqn_usize Dqn_CString8_FVSize (DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
DQN_API Dqn_usize Dqn_CString8_Size (char const *a);
|
||||
DQN_API Dqn_usize Dqn_CString16_Size (wchar_t const *a);
|
||||
|
||||
@ -308,11 +308,11 @@ struct Dqn_String8ToI64Result
|
||||
};
|
||||
|
||||
DQN_API Dqn_String8 Dqn_String8_InitCString8 (char const *src);
|
||||
DQN_API bool Dqn_String8_IsValid (Dqn_String8 string);
|
||||
#define Dqn_String8_IsValid(string) ((string).data)
|
||||
DQN_API bool Dqn_String8_IsAll (Dqn_String8 string, Dqn_String8IsAll is_all);
|
||||
|
||||
DQN_API Dqn_String8 Dqn_String8_InitF (Dqn_Allocator allocator, char const *fmt, ...);
|
||||
DQN_API Dqn_String8 Dqn_String8_InitFV (Dqn_Allocator allocator, char const *fmt, va_list args);
|
||||
DQN_API Dqn_String8 Dqn_String8_InitF (Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API Dqn_String8 Dqn_String8_InitFV (Dqn_Allocator allocator, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
DQN_API Dqn_String8 Dqn_String8_Allocate (Dqn_Allocator allocator, Dqn_usize size, Dqn_ZeroMem zero_mem);
|
||||
DQN_API Dqn_String8 Dqn_String8_CopyCString (Dqn_Allocator allocator, char const *string, Dqn_usize size);
|
||||
DQN_API Dqn_String8 Dqn_String8_Copy (Dqn_Allocator allocator, Dqn_String8 string);
|
||||
@ -438,11 +438,11 @@ template <Dqn_usize N> struct Dqn_FString8
|
||||
char const *end () const { return data + size; }
|
||||
};
|
||||
|
||||
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF (char const *fmt, ...);
|
||||
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF (DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
template <Dqn_usize N> Dqn_usize Dqn_FString8_Max (Dqn_FString8<N> const *string);
|
||||
template <Dqn_usize N> void Dqn_FString8_Clear (Dqn_FString8<N> *string);
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendFV (Dqn_FString8<N> *string, char const *fmt, va_list va);
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendF (Dqn_FString8<N> *string, char const *fmt, ...);
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendFV (Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list va);
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendF (Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendCString8 (Dqn_FString8<N> *string, char const *value, Dqn_usize size);
|
||||
template <Dqn_usize N> bool Dqn_FString8_Append (Dqn_FString8<N> *string, Dqn_String8 value);
|
||||
template <Dqn_usize N> Dqn_String8 Dqn_FString8_ToString8 (Dqn_FString8<N> const *string);
|
||||
@ -489,8 +489,8 @@ struct Dqn_String8Builder
|
||||
Dqn_usize count; ///< The number of links in the linked list of strings
|
||||
};
|
||||
|
||||
DQN_API bool Dqn_String8Builder_AppendF (Dqn_String8Builder *builder, char const *fmt, ...);
|
||||
DQN_API bool Dqn_String8Builder_AppendFV (Dqn_String8Builder *builder, char const *fmt, va_list args);
|
||||
DQN_API bool Dqn_String8Builder_AppendF (Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, ...);
|
||||
DQN_API bool Dqn_String8Builder_AppendFV (Dqn_String8Builder *builder, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args);
|
||||
DQN_API bool Dqn_String8Builder_AppendRef (Dqn_String8Builder *builder, Dqn_String8 string);
|
||||
DQN_API bool Dqn_String8Builder_AppendCopy(Dqn_String8Builder *builder, Dqn_String8 string);
|
||||
DQN_API Dqn_String8 Dqn_String8Builder_Build (Dqn_String8Builder const *builder, Dqn_Allocator allocator);
|
||||
@ -512,7 +512,7 @@ DQN_API int Dqn_UTF16_EncodeCodepoint(uint16_t utf16[2], uint32_t codepoint);
|
||||
|
||||
#if !defined(DQN_NO_FSTRING8)
|
||||
// NOTE: [$FSTR] Dqn_FString8 ======================================================================
|
||||
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF(char const *fmt, ...)
|
||||
template <Dqn_usize N> Dqn_FString8<N> Dqn_FString8_InitF(DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
Dqn_FString8<N> result = {};
|
||||
if (fmt) {
|
||||
@ -535,7 +535,7 @@ template <Dqn_usize N> void Dqn_FString8_Clear(Dqn_FString8<N> *string)
|
||||
*string = {};
|
||||
}
|
||||
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendFV(Dqn_FString8<N> *string, char const *fmt, va_list args)
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendFV(Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args)
|
||||
{
|
||||
bool result = false;
|
||||
if (!string || !fmt)
|
||||
@ -553,7 +553,7 @@ template <Dqn_usize N> bool Dqn_FString8_AppendFV(Dqn_FString8<N> *string, char
|
||||
return result;
|
||||
}
|
||||
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendF(Dqn_FString8<N> *string, char const *fmt, ...)
|
||||
template <Dqn_usize N> bool Dqn_FString8_AppendF(Dqn_FString8<N> *string, DQN_FMT_STRING_ANNOTATE char const *fmt, ...)
|
||||
{
|
||||
bool result = false;
|
||||
if (!string || !fmt)
|
||||
|
Loading…
Reference in New Issue
Block a user