Compare commits

...

2 Commits

Author SHA1 Message Date
2868993ebc dqn: Add MSVC SAL annotations 2023-08-25 23:42:09 +10:00
8f129e7893 dqn: Upgrade to latest lib 2023-08-25 20:35:04 +10:00
16 changed files with 490 additions and 436 deletions

View File

@ -479,7 +479,7 @@ Dqn_UTest TestDSMap()
uint64_t value = 0;
uint64_t grow_threshold = map_start_size * 3 / 4;
for (; map.occupied != grow_threshold; value++) {
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value, 1);
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value);
Dqn_DSMapKey key = Dqn_DSMap_KeyBuffer(&map, (char *)val_copy, sizeof(*val_copy));
DQN_UTEST_ASSERT(&test, !Dqn_DSMap_Find<uint64_t>(&map, key));
DQN_UTEST_ASSERT(&test, !Dqn_DSMap_FindSlot<uint64_t>(&map, key));
@ -498,7 +498,7 @@ Dqn_UTest TestDSMap()
DQN_UTEST_ASSERT(&test, map.occupied == 1 /*Sentinel*/ + value);
{ // NOTE: One more item should cause the table to grow by 2x
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value, 1);
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value);
Dqn_DSMapKey key = Dqn_DSMap_KeyBuffer(&map, (char *)val_copy, sizeof(*val_copy));
bool found = false;
if (test_type == DSMapTestType_Set) {
@ -548,7 +548,7 @@ Dqn_UTest TestDSMap()
uint64_t value = 0;
uint64_t shrink_threshold = map.size * 1 / 4;
for (; map.occupied != shrink_threshold; value++) {
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value, 1);
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value);
Dqn_DSMapKey key = Dqn_DSMap_KeyBuffer(&map, (char *)val_copy, sizeof(*val_copy));
DQN_UTEST_ASSERT(&test, Dqn_DSMap_Find<uint64_t>(&map, key));
@ -561,7 +561,7 @@ Dqn_UTest TestDSMap()
DQN_UTEST_ASSERT(&test, map.occupied == start_map_occupied - value);
{ // NOTE: One more item should cause the table to grow by 2x
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value, 1);
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value);
Dqn_DSMapKey key = Dqn_DSMap_KeyBuffer(&map, (char *)val_copy, sizeof(*val_copy));
Dqn_DSMap_Erase(&map, key);
value++;
@ -600,7 +600,7 @@ Dqn_UTest TestDSMap()
}
for (; map.occupied != 1; value++) { // NOTE: Remove all items from the table
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value, 1);
uint64_t *val_copy = Dqn_Arena_NewCopy(scratch.arena, uint64_t, &value);
Dqn_DSMapKey key = Dqn_DSMap_KeyBuffer(&map, (char *)val_copy, sizeof(*val_copy));
DQN_UTEST_ASSERT(&test, Dqn_DSMap_Find<uint64_t>(&map, key));
Dqn_DSMap_Erase(&map, key);
@ -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,7 +1254,7 @@ 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]);
@ -1251,7 +1264,7 @@ Dqn_UTest TestString8()
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;
}

View File

@ -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

View File

@ -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++)

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -309,12 +309,24 @@ DQN_API Dqn_V2 operator-(Dqn_V2 lhs, Dqn_V2 rhs)
return result;
}
DQN_API Dqn_V2 operator-(Dqn_V2 lhs, Dqn_f32 rhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x - rhs, lhs.y - rhs);
return result;
}
DQN_API Dqn_V2 operator+(Dqn_V2 lhs, Dqn_V2 rhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x + rhs.x, lhs.y + rhs.y);
return result;
}
DQN_API Dqn_V2 operator+(Dqn_V2 lhs, Dqn_f32 rhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x + rhs, lhs.y + rhs);
return result;
}
DQN_API Dqn_V2 operator*(Dqn_V2 lhs, Dqn_V2 rhs)
{
Dqn_V2 result = Dqn_V2_InitNx2(lhs.x * rhs.x, lhs.y * rhs.y);

View File

@ -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 ===========================================================================
@ -88,7 +86,9 @@ DQN_API bool operator<=(Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API bool operator< (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API bool operator> (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator- (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator- (Dqn_V2 lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 operator+ (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator+ (Dqn_V2 lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 operator* (Dqn_V2 lhs, Dqn_V2 rhs);
DQN_API Dqn_V2 operator* (Dqn_V2 lhs, Dqn_f32 rhs);
DQN_API Dqn_V2 operator* (Dqn_V2 lhs, int32_t rhs);
@ -157,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; };
@ -192,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)
@ -306,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

View File

@ -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;
}

View File

@ -242,9 +242,11 @@ enum Dqn_ArenaCommit
// NOTE: Allocation ================================================================================
#define Dqn_Arena_New(arena, Type, zero_mem) (Type *)Dqn_Arena_Alloc(arena, sizeof(Type), alignof(Type), zero_mem)
#define Dqn_Arena_NewCopy(arena, Type, src) (Type *)Dqn_Arena_Copy(arena, src, sizeof(*src), alignof(Type))
#define Dqn_Arena_NewCopyZ(arena, Type, src) (Type *)Dqn_Arena_Copy(arena, src, sizeof(*src), alignof(Type))
#define Dqn_Arena_NewArray(arena, Type, count, zero_mem) (Type *)Dqn_Arena_Alloc(arena, sizeof(Type) * count, alignof(Type), zero_mem)
#define Dqn_Arena_NewCopy(arena, Type, src, count) (Type *)Dqn_Arena_Copy(arena, src, sizeof(*src) * count, alignof(Type))
#define Dqn_Arena_NewCopyZ(arena, Type, src, count) (Type *)Dqn_Arena_CopyZ(arena, src, sizeof(*src) * count, alignof(Type))
#define Dqn_Arena_NewArrayCopy(arena, Type, src, count) (Type *)Dqn_Arena_Copy(arena, src, sizeof(*src) * count, alignof(Type))
#define Dqn_Arena_NewArrayCopyZ(arena, Type, src, count) (Type *)Dqn_Arena_CopyZ(arena, src, sizeof(*src) * count, alignof(Type))
DQN_API Dqn_Allocator Dqn_Arena_Allocator (Dqn_Arena *arena);
DQN_API Dqn_MemBlock * Dqn_Arena_Grow (Dqn_Arena *arena, Dqn_usize size, Dqn_usize commit, uint8_t flags);

View File

@ -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;
}
}
}
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;
}
if (!first_char)
path16.data[index] = temp; // Undo null termination
}
}
#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
// -------------------------------------------------------------------------
// 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 = {};
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;
if (msg->code >= 12000 && msg->code <= 12175) { // WinINET Errors
if (result.code >= 12000 && result.code <= 12175) { // WinINET Errors
flags |= FORMAT_MESSAGE_FROM_HMODULE;
module_to_get_errors_from = GetModuleHandleA("wininet.dll");
}
msg->size = FormatMessageA(flags,
int32_t size = FormatMessageA(flags,
module_to_get_errors_from, // LPCVOID lpSource,
msg->code, // unsigned long dwMessageId,
result.code, // unsigned long dwMessageId,
0, // unsigned long dwLanguageId,
msg->data, // LPSTR lpBuffer,
DQN_ARRAY_ICOUNT(msg->data), // unsigned long nSize,
nullptr, // LPSTR lpBuffer,
0, // 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;
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;
}
}
}
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)
DQN_API int Dqn_Win_String8ToString16Buffer(Dqn_String8 src, wchar_t *dest, Dqn_usize dest_size)
{
int result = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src, src_size, dest, dest_size, nullptr, nullptr);
if (result && dest && dest_size > 0)
int result = 0;
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_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)
// 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) {
result = Dqn_Win_CString16ToCString8(src.data, src_size, dest, dest_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_String16ToString8Allocator(Dqn_String16 src, Dqn_Allocator allocator)
DQN_API Dqn_String8 Dqn_Win_String16ToString8(Dqn_Arena *arena, Dqn_String16 src)
{
Dqn_String8 result = {};
if (!arena || !Dqn_String8_IsValid(src))
return result;
int src_size = Dqn_Safe_SaturateCastISizeToInt(src.size);
if (src_size) {
result = Dqn_Win_CString16ToString8Allocator(src.data, src_size, allocator);
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*/);
}
return result;
}
// NOTE: Windows Executable Directory
// -----------------------------------------------------------------------------
DQN_API Dqn_usize Dqn_Win_EXEDirW(wchar_t *buffer, Dqn_usize size)
// NOTE: Windows Executable Directory ==========================================
DQN_API Dqn_String16 Dqn_Win_EXEDirW(Dqn_Arena *arena)
{
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) {
return result;
}
DQN_MEMCPY(buffer, module_path, sizeof(wchar_t) * result);
return result;
}
DQN_API Dqn_String16 Dqn_Win_EXEDirWArena(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 = {};
if (dir_size > 0) {
result.data = Dqn_Arena_NewCopyZ(arena, wchar_t, dir, dir_size);
if (result.data) {
result.size = dir_size;
}
}
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_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;
}
DQN_ASSERT(path16_size <= DQN_OS_WIN32_MAX_PATH);
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));
}
bool result = Dqn_Win_FolderWIterate(Dqn_String16{path16, path16_size}, &wide_it);
path16 = Dqn_Win_String8ToString16(scratch.arena, adjusted_path);
if (path16.size <= 0) // Conversion error
return false;
}
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);
}
}

View File

@ -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,14 +285,12 @@ 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 Dqn_WinError Dqn_Win_LastError(Dqn_Arena *arena);
DQN_API void Dqn_Win_MakeProcessDPIAware();
// NOTE: Windows String8 <-> String16 ===========================================
@ -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 ();

View File

@ -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);
@ -90,6 +84,12 @@ DQN_API Dqn_String8 Dqn_String8_Slice(Dqn_String8 string, Dqn_usize offset, Dqn_
return result;
}
DQN_API Dqn_String8 Dqn_String8_Advance(Dqn_String8 string, Dqn_usize amount)
{
Dqn_String8 result = Dqn_String8_Slice(string, amount, UINT64_MAX);
return result;
}
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplitArray(Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size)
{
Dqn_String8BinarySplitResult result = {};
@ -176,6 +176,7 @@ DQN_API Dqn_String8FindResult Dqn_String8_FindFirstStringArray(Dqn_String8 strin
if (Dqn_String8_Eq(string_slice, find_item)) {
result.found = true;
result.index = index;
result.start_to_before_match = Dqn_String8_Init(string.data, index);
result.match = Dqn_String8_Init(string.data + index, find_item.size);
result.match_to_end_of_buffer = Dqn_String8_Init(result.match.data, string.size - index);
break;
@ -357,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;
}
@ -541,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);
@ -550,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)
@ -625,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)
@ -637,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);
@ -711,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;
}

View File

@ -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);
@ -248,10 +248,11 @@ struct Dqn_String8BinarySplitResult
struct Dqn_String8FindResult
{
bool found;
Dqn_usize index;
Dqn_String8 match;
Dqn_String8 match_to_end_of_buffer;
bool found; // True if string was found. If false, the subsequent fields below are not set.
Dqn_usize index; // The index in the buffer where the found string starts
Dqn_String8 match; // The matching string in the buffer that was searched
Dqn_String8 match_to_end_of_buffer; // The substring containing the found string to the end of the buffer
Dqn_String8 start_to_before_match; // The substring from the start of the buffer up until the found string, not including it
};
// NOTE: Macros ====================================================================================
@ -307,16 +308,17 @@ 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);
DQN_API Dqn_String8 Dqn_String8_Slice (Dqn_String8 string, Dqn_usize offset, Dqn_usize size);
DQN_API Dqn_String8 Dqn_String8_Advance (Dqn_String8 string, Dqn_usize amount);
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplitArray (Dqn_String8 string, Dqn_String8 const *find, Dqn_usize find_size);
DQN_API Dqn_String8BinarySplitResult Dqn_String8_BinarySplit (Dqn_String8 string, Dqn_String8 find);
DQN_API Dqn_usize Dqn_String8_Split (Dqn_String8 string, Dqn_String8 delimiter, Dqn_String8 *splits, Dqn_usize splits_count);
@ -436,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);
@ -487,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);
@ -510,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) {
@ -533,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)
@ -551,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)