Compile on Linux again, fix comment warning, implement output capture on exec on posix

This commit is contained in:
doylet 2024-03-25 16:11:57 +11:00
parent b1eab3abdf
commit 3bca236a74
32 changed files with 534 additions and 230 deletions

View File

@ -1,5 +1,7 @@
#if !defined(DQN_KECCAK_H) #if !defined(DQN_KECCAK_H)
#define DQN_KECCAK_H #define DQN_KECCAK_H
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ // $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
@ -64,6 +66,9 @@
// code of the header file. // code of the header file.
// //
// #define DQN_KECCAK_IMPLEMENTATION // #define DQN_KECCAK_IMPLEMENTATION
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if !defined(DQN_KECCAK_MEMCPY) #if !defined(DQN_KECCAK_MEMCPY)
#include <string.h> #include <string.h>

View File

@ -1,6 +1,7 @@
#if !defined(DQN_UTEST_H) #if !defined(DQN_UTEST_H)
#define DQN_UTEST_H #define DQN_UTEST_H
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$$\ // $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$$\
@ -45,6 +46,9 @@
// #define DQN_UTEST_GOOD_COLOR // #define DQN_UTEST_GOOD_COLOR
// Define this to a terminal color code to specify what color sucess will be // Define this to a terminal color code to specify what color sucess will be
// presented as. // presented as.
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: Macros //////////////////////////////////////////////////////////////////////////////////// // NOTE: Macros ////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h> #include <stdio.h>

View File

@ -1,8 +1,20 @@
#!/bin/bash #!/bin/bash
set -ex
code_dir=${PWD} code_dir=${PWD}
mkdir -p Build mkdir -p Build
pushd Build pushd Build
g++ ${code_dir}/dqn_unit_tests.cpp -D DQN_TEST_WITH_MAIN -std=c++17 -o dqn_unit_tests g++ \
-Wall \
-Werror \
-fsanitize=address \
-std=c++17 \
-D DQN_IMPLEMENTATION \
-D DQN_UNIT_TESTS_WITH_MAIN \
-D DQN_UNIT_TESTS_WITH_KECCAK \
-x c++ ${code_dir}/dqn.h \
-g \
-o dqn_unit_tests
popd popd

5
dqn.h
View File

@ -1,6 +1,7 @@
#if !defined(DQN_H) #if !defined(DQN_H)
#define DQN_H #define DQN_H
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ $$$$$$\ $$\ $$\ // $$$$$$$\ $$$$$$\ $$\ $$\
@ -207,6 +208,7 @@
// library from being included. This might be useful if you are including the // library from being included. This might be useful if you are including the
// library in your project yourself. The library must still be defined and // library in your project yourself. The library must still be defined and
// visible before this header. // visible before this header.
*/
#if defined(DQN_ONLY_VARRAY) || \ #if defined(DQN_ONLY_VARRAY) || \
defined(DQN_ONLY_SARRAY) || \ defined(DQN_ONLY_SARRAY) || \
@ -344,6 +346,7 @@
#endif // DQN_H #endif // DQN_H
#if defined(DQN_IMPLEMENTATION) #if defined(DQN_IMPLEMENTATION)
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// /$$$$$$\ $$\ $$\ $$$$$$$\ $$\ // /$$$$$$\ $$\ $$\ $$$$$$$\ $$\
@ -358,6 +361,7 @@
// Implementation // Implementation
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if defined(DQN_WITH_CGEN) #if defined(DQN_WITH_CGEN)
#if !defined(DQN_NO_METADESK) #if !defined(DQN_NO_METADESK)
@ -383,6 +387,7 @@
#include "dqn_debug.cpp" #include "dqn_debug.cpp"
#include "dqn_string.cpp" #include "dqn_string.cpp"
#include "dqn_containers.cpp" #include "dqn_containers.cpp"
#include "dqn_type_info.cpp"
#if defined(DQN_PLATFORM_EMSCRIPTEN) || defined(DQN_PLATFORM_POSIX) || defined(DQN_PLATFORM_ARM64) #if defined(DQN_PLATFORM_EMSCRIPTEN) || defined(DQN_PLATFORM_POSIX) || defined(DQN_PLATFORM_ARM64)
#include "dqn_os_posix.cpp" #include "dqn_os_posix.cpp"

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ // $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\
@ -12,6 +13,7 @@
// dqn_allocator.cpp // dqn_allocator.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$AREN] Dqn_Arena ///////////////////////////////////////////////////////////////////////// // NOTE: [$AREN] Dqn_Arena /////////////////////////////////////////////////////////////////////////
DQN_API Dqn_ArenaBlock *Dqn_Arena_BlockInit(uint64_t reserve, uint64_t commit, bool track_alloc, bool alloc_can_leak) DQN_API Dqn_ArenaBlock *Dqn_Arena_BlockInit(uint64_t reserve, uint64_t commit, bool track_alloc, bool alloc_can_leak)
@ -300,7 +302,7 @@ DQN_API void *Dqn_ChunkPool_Alloc(Dqn_ChunkPool *pool, Dqn_usize size)
#if defined(DQN_OS_WIN32) #if defined(DQN_OS_WIN32)
Dqn_usize dist_to_next_msb = __lzcnt64(required_size) + 1; Dqn_usize dist_to_next_msb = __lzcnt64(required_size) + 1;
#else #else
Dqn_usize dist_to_next_msb = __builtin_clz(required_size) + 1; Dqn_usize dist_to_next_msb = __builtin_clzll(required_size) + 1;
#endif #endif
// NOTE: Round up if not PoT as the low bits are set. // NOTE: Round up if not PoT as the low bits are set.

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ // $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\
@ -17,6 +18,9 @@
// [$CHUN] Dqn_ChunkPool -- Allocates reusable, free-able memory in PoT chunks // [$CHUN] Dqn_ChunkPool -- Allocates reusable, free-able memory in PoT chunks
// [$ACAT] Dqn_ArenaCatalog -- Collate, create & manage arenas in a catalog // [$ACAT] Dqn_ArenaCatalog -- Collate, create & manage arenas in a catalog
// //
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$AREN] Dqn_Arena ///////////////////////////////////////////////////////////////////////// // NOTE: [$AREN] Dqn_Arena /////////////////////////////////////////////////////////////////////////
#if !defined(DQN_ARENA_RESERVE_SIZE) #if !defined(DQN_ARENA_RESERVE_SIZE)
#define DQN_ARENA_RESERVE_SIZE DQN_MEGABYTES(64) #define DQN_ARENA_RESERVE_SIZE DQN_MEGABYTES(64)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ // $$$$$$$\
@ -12,6 +13,7 @@
// dqn_base.cpp // dqn_base.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$INTR] Intrinsics //////////////////////////////////////////////////////////////////////// // NOTE: [$INTR] Intrinsics ////////////////////////////////////////////////////////////////////////
#if !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN) #if !defined(DQN_PLATFORM_ARM64) && !defined(DQN_PLATFORM_EMSCRIPTEN)
@ -303,25 +305,25 @@ DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Arena *arena,
Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(call_site.file); Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(call_site.file);
Dqn_OSDateTimeStr8 const time = Dqn_OS_DateLocalTimeStr8Now(); Dqn_OSDateTimeStr8 const time = Dqn_OS_DateLocalTimeStr8Now();
Dqn_Str8 header = Dqn_Str8_InitF(arena, Dqn_Str8 header = Dqn_Str8_InitF(arena,
"%.*s " // date "%.*s " // date
"%.*s " // hms "%.*s " // hms
"%.*s" // colour "%.*s" // colour
"%.*s" // bold "%.*s" // bold
"%.*s" // type "%.*s" // type
"%*s" // type padding "%*s" // type padding
"%.*s" // reset "%.*s" // reset
" %.*s" // file name " %.*s" // file name
":%05I32u " // line number ":%05I32u " // line number
, ,
DQN_CAST(int)time.date_size - 2, time.date + 2, // date DQN_CAST(int)time.date_size - 2, time.date + 2, // date
DQN_CAST(int)time.hms_size, time.hms, // hms DQN_CAST(int)time.hms_size, time.hms, // hms
DQN_STR_FMT(colour_esc), // colour DQN_STR_FMT(colour_esc), // colour
DQN_STR_FMT(bold_esc), // bold DQN_STR_FMT(bold_esc), // bold
DQN_STR_FMT(type), // type DQN_STR_FMT(type), // type
DQN_CAST(int)type_padding, "", // type padding DQN_CAST(int)type_padding, "", // type padding
DQN_STR_FMT(reset_esc), // reset DQN_STR_FMT(reset_esc), // reset
DQN_STR_FMT(file_name), // file name DQN_STR_FMT(file_name), // file name
call_site.line); // line number call_site.line); // line number
Dqn_usize header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size; Dqn_usize header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size;
// NOTE: Header padding //////////////////////////////////////////////////////////////////////// // NOTE: Header padding ////////////////////////////////////////////////////////////////////////
@ -332,9 +334,12 @@ DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Arena *arena,
// NOTE: Construct final log /////////////////////////////////////////////////////////////////// // NOTE: Construct final log ///////////////////////////////////////////////////////////////////
Dqn_Str8 user_msg = Dqn_Str8_InitFV(arena, fmt, args); Dqn_Str8 user_msg = Dqn_Str8_InitFV(arena, fmt, args);
Dqn_Str8 result = Dqn_Str8_Alloc(arena, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No); Dqn_Str8 result = Dqn_Str8_Alloc(arena, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No);
DQN_MEMCPY(result.data, header.data, header.size); if (Dqn_Str8_HasData(result)) {
DQN_MEMSET(result.data + header.size, ' ', header_padding); DQN_MEMCPY(result.data, header.data, header.size);
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size); DQN_MEMSET(result.data + header.size, ' ', header_padding);
if (Dqn_Str8_HasData(user_msg))
DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size);
}
return result; return result;
} }

View File

@ -1,4 +1,5 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// /*
///////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ // $$$$$$$\
// $$ __$$\ // $$ __$$\
@ -21,6 +22,9 @@
// [$PRIN] Dqn_Print -- Console printing // [$PRIN] Dqn_Print -- Console printing
// [$LLOG] Dqn_Log -- Console logging macros // [$LLOG] Dqn_Log -- Console logging macros
// //
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$MACR] Macros //////////////////////////////////////////////////////////////////////////// // NOTE: [$MACR] Macros ////////////////////////////////////////////////////////////////////////////
#define DQN_STRINGIFY(x) #x #define DQN_STRINGIFY(x) #x
#define DQN_TOKEN_COMBINE2(x, y) x ## y #define DQN_TOKEN_COMBINE2(x, y) x ## y
@ -214,10 +218,10 @@
#define DQN_CHAR_COUNT(string) (sizeof(string) - 1) #define DQN_CHAR_COUNT(string) (sizeof(string) - 1)
// NOTE: SI Byte /////////////////////////////////////////////////////////////////////////////////// // NOTE: SI Byte ///////////////////////////////////////////////////////////////////////////////////
#define DQN_BYTES(val) (val) #define DQN_BYTES(val) ((uint64_t)val)
#define DQN_KILOBYTES(val) (1024ULL * DQN_BYTES(val)) #define DQN_KILOBYTES(val) ((uint64_t)1024 * DQN_BYTES(val))
#define DQN_MEGABYTES(val) (1024ULL * DQN_KILOBYTES(val)) #define DQN_MEGABYTES(val) ((uint64_t)1024 * DQN_KILOBYTES(val))
#define DQN_GIGABYTES(val) (1024ULL * DQN_MEGABYTES(val)) #define DQN_GIGABYTES(val) ((uint64_t)1024 * DQN_MEGABYTES(val))
// NOTE: Time ////////////////////////////////////////////////////////////////////////////////////// // NOTE: Time //////////////////////////////////////////////////////////////////////////////////////
#define DQN_SECONDS_TO_MS(val) ((val) * 1000) #define DQN_SECONDS_TO_MS(val) ((val) * 1000)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ // $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_containers.cpp // dqn_containers.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$SLIC] Dqn_Slice ///////////////////////////////////////////////////////////////////////// // NOTE: [$SLIC] Dqn_Slice /////////////////////////////////////////////////////////////////////////
DQN_API Dqn_Str8 Dqn_Slice_Str8Render(Dqn_Arena *arena, Dqn_Slice<Dqn_Str8> array, Dqn_Str8 separator) DQN_API Dqn_Str8 Dqn_Slice_Str8Render(Dqn_Arena *arena, Dqn_Slice<Dqn_Str8> array, Dqn_Str8 separator)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ // $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
@ -22,6 +23,7 @@
// [$LIST] Dqn_List -- DQN_LIST -- Chunked linked lists, append only // [$LIST] Dqn_List -- DQN_LIST -- Chunked linked lists, append only
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$CARR] Dqn_CArray //////////////////////////////////////////////////////////////////////// // NOTE: [$CARR] Dqn_CArray ////////////////////////////////////////////////////////////////////////
enum Dqn_ArrayErase enum Dqn_ArrayErase

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ // $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_debug.cpp // dqn_debug.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$ASAN] Dqn_Asan ////////////////////////////////////////////////////////////////////////// /// // NOTE: [$ASAN] Dqn_Asan ////////////////////////////////////////////////////////////////////////// ///
DQN_API void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) DQN_API void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size)
@ -123,7 +125,7 @@ static void Dqn_StackTrace_AddWalkToStr8Builder_(Dqn_StackTraceWalkResult const
for (Dqn_usize index = skip; index < walk->size; index++) { for (Dqn_usize index = skip; index < walk->size; index++) {
raw_frame.base_addr = walk->base_addr[index]; raw_frame.base_addr = walk->base_addr[index];
Dqn_StackTraceFrame frame = Dqn_StackTrace_RawFrameToFrame(builder->arena, raw_frame); Dqn_StackTraceFrame frame = Dqn_StackTrace_RawFrameToFrame(builder->arena, raw_frame);
Dqn_Str8Builder_AppendF(builder, "%.*s(%I64u): %.*s%s", DQN_STR_FMT(frame.file_name), frame.line_number, DQN_STR_FMT(frame.function_name), (index == walk->size - 1) ? "" : "\n"); Dqn_Str8Builder_AppendF(builder, "%.*s(%zu): %.*s%s", DQN_STR_FMT(frame.file_name), frame.line_number, DQN_STR_FMT(frame.function_name), (DQN_CAST(int)index == walk->size - 1) ? "" : "\n");
} }
} }

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ // $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\
@ -18,6 +19,7 @@
// [$DEBG] Dqn_Debug -- Allocation leak tracking API // [$DEBG] Dqn_Debug -- Allocation leak tracking API
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$ASAN] Dqn_Asan ////////////////////////////////////////////////////////////////////////// // NOTE: [$ASAN] Dqn_Asan //////////////////////////////////////////////////////////////////////////
#if !defined(DQN_ASAN_POISON) #if !defined(DQN_ASAN_POISON)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ // $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\
@ -24,6 +25,7 @@
// and/or conciseness of being able to learn the breadth of the APIs. // and/or conciseness of being able to learn the breadth of the APIs.
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4702) // unreachable code DQN_MSVC_WARNING_DISABLE(4702) // unreachable code
@ -577,7 +579,7 @@ void Dqn_Docs_Demo()
// Print the result like so // Print the result like so
if (0) { if (0) {
printf("%.*s[%u] %llu cycles (%.1fms)\n", printf("%.*s[%u] %" PRIu64 " cycles (%.1fms)\n",
DQN_STR_FMT(anchor->name), DQN_STR_FMT(anchor->name),
anchor->hit_count, anchor->hit_count,
anchor->tsc_inclusive, anchor->tsc_inclusive,
@ -691,7 +693,7 @@ void Dqn_Docs_Demo()
// You may then print out the frame like so // You may then print out the frame like so
if (0) if (0)
printf("%.*s(%llu): %.*s\n", DQN_STR_FMT(frame.file_name), frame.line_number, DQN_STR_FMT(frame.function_name)); printf("%.*s(%" PRIu64 "): %.*s\n", DQN_STR_FMT(frame.file_name), frame.line_number, DQN_STR_FMT(frame.function_name));
} }
// If you load new shared-libraries into the address space it maybe // If you load new shared-libraries into the address space it maybe

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\ // $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\
@ -12,6 +13,7 @@
// dqn_external.cpp // dqn_external.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if !defined(DQN_USE_STD_PRINTF) && !defined(DQN_STB_SPRINTF_HEADER_ONLY) #if !defined(DQN_USE_STD_PRINTF) && !defined(DQN_STB_SPRINTF_HEADER_ONLY)
// NOTE: [$STBS] stb_sprintf /////////////////////////////////////////////////////////////////////// // NOTE: [$STBS] stb_sprintf ///////////////////////////////////////////////////////////////////////

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\ // $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\
@ -12,6 +13,7 @@
// dqn_external.h -- Third party dependencies // dqn_external.h -- Third party dependencies
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$OS_H] OS Headers //////////////////////////////////////////////////////////////////////// // NOTE: [$OS_H] OS Headers ////////////////////////////////////////////////////////////////////////
#if !defined(DQN_OS_WIN32) || defined(DQN_OS_WIN32_USE_PTHREADS) #if !defined(DQN_OS_WIN32) || defined(DQN_OS_WIN32_USE_PTHREADS)
@ -56,7 +58,7 @@
#define DQN_VSNPRINTF(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) #define DQN_VSNPRINTF(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__)
#if (DQN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)) && defined(DQN_COMPILER_MSVC) #if (DQN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)) && defined(DQN_COMPILER_MSVC)
#error The STB implementation of sprintf triggers MSVC's implementation of ASAN. Compiling ASAN with STB sprintf is not supported. #error The STB implementation of sprintf triggers MSVCs implementation of ASAN. Compiling ASAN with STB sprintf is not supported.
// NOTE: stb_sprintf assumes c-string literals are 4 byte aligned which is // NOTE: stb_sprintf assumes c-string literals are 4 byte aligned which is
// always true, however, reading past the end of a string whose size is not // always true, however, reading past the end of a string whose size is not

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ // $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\
@ -12,6 +13,7 @@
// dqn_hash.cpp // dqn_hash.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$FNV1] Dqn_FNV1A ///////////////////////////////////////////////////////////////////////// // NOTE: [$FNV1] Dqn_FNV1A /////////////////////////////////////////////////////////////////////////
// Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/ // Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ // $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\
@ -17,6 +18,7 @@
// [$MMUR] Dqn_MurmurHash3 -- Hash(x) -> 32/128bit via MurmurHash3 // [$MMUR] Dqn_MurmurHash3 -- Hash(x) -> 32/128bit via MurmurHash3
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$FNV1] Dqn_FNV1A ///////////////////////////////////////////////////////////////////////// // NOTE: [$FNV1] Dqn_FNV1A /////////////////////////////////////////////////////////////////////////
#if !defined(DQN_FNV1A32_SEED) #if !defined(DQN_FNV1A32_SEED)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ // $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_helpers.cpp // dqn_helpers.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$PCGX] Dqn_PCG32 ///////////////////////////////////////////////////////////////////////// // NOTE: [$PCGX] Dqn_PCG32 /////////////////////////////////////////////////////////////////////////
#define DQN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL #define DQN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ // $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\
@ -24,6 +25,7 @@
// [$PROF] Dqn_Profiler -- DQN_PROFILER -- Profiler that measures using a timestamp counter // [$PROF] Dqn_Profiler -- DQN_PROFILER -- Profiler that measures using a timestamp counter
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$PCGX] Dqn_PCG32 ///////////////////////////////////////////////////////////////////////// // NOTE: [$PCGX] Dqn_PCG32 /////////////////////////////////////////////////////////////////////////
struct Dqn_PCG32 { uint64_t state; }; struct Dqn_PCG32 { uint64_t state; };

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\ // $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\
@ -12,6 +13,7 @@
// dqn_math.cpp // dqn_math.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
#if !defined(DQN_NO_V2) #if !defined(DQN_NO_V2)
// NOTE: [$VEC2] Vector2 /////////////////////////////////////////////////////////////////////////// // NOTE: [$VEC2] Vector2 ///////////////////////////////////////////////////////////////////////////

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\ // $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\
@ -22,6 +23,7 @@
// [$MATH] Other -- // [$MATH] Other --
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$\ // $$$$$$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_os.cpp // dqn_os.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$DATE] Date ////////////////////////////////////////////////////////////////////////////// // NOTE: [$DATE] Date //////////////////////////////////////////////////////////////////////////////
DQN_API Dqn_OSDateTimeStr8 Dqn_OS_DateLocalTimeStr8(Dqn_OSDateTime time, char date_separator, char hms_separator) DQN_API Dqn_OSDateTimeStr8 Dqn_OS_DateLocalTimeStr8(Dqn_OSDateTime time, char date_separator, char hms_separator)
@ -442,19 +444,19 @@ DQN_API Dqn_Str8 Dqn_OS_PathBuildWithSeparator(Dqn_Arena *arena, Dqn_OSPath cons
// NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// // NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Slice<Dqn_Str8> cmd_line, DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Slice<Dqn_Str8> cmd_line,
Dqn_Str8 working_dir, Dqn_Str8 working_dir,
uint8_t exec_flag, uint8_t exec_flags,
Dqn_Arena *arena, Dqn_Arena *arena,
Dqn_ErrorSink *error) Dqn_ErrorSink *error)
{ {
Dqn_OSExecAsyncHandle async_handle = Dqn_OS_ExecAsync(cmd_line, working_dir, exec_flag, error); Dqn_OSExecAsyncHandle async_handle = Dqn_OS_ExecAsync(cmd_line, working_dir, exec_flags, error);
Dqn_OSExecResult result = Dqn_OS_ExecWait(async_handle, arena, error); Dqn_OSExecResult result = Dqn_OS_ExecWait(async_handle, arena, error);
return result; return result;
} }
DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena) DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena)
{ {
Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil); Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
Dqn_OSExecResult result = Dqn_OS_Exec(cmd_line, working_dir, exec_flag, arena, error); Dqn_OSExecResult result = Dqn_OS_Exec(cmd_line, working_dir, exec_flags, arena, error);
if (result.os_error_code) { if (result.os_error_code) {
Dqn_ErrorSink_EndAndExitIfErrorF( Dqn_ErrorSink_EndAndExitIfErrorF(
error, error,

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$\ // $$$$$$\ $$$$$$\
@ -24,6 +25,7 @@
// [$HTTP] Dqn_OSHttp -- -- // [$HTTP] Dqn_OSHttp -- --
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$OMEM] Dqn_OSMem ////////////////////////////////////////////////////////////////////////// // NOTE: [$OMEM] Dqn_OSMem //////////////////////////////////////////////////////////////////////////
enum Dqn_OSMemCommit enum Dqn_OSMemCommit
@ -184,12 +186,10 @@ struct Dqn_OSExecAsyncHandle
uint32_t os_error_code; uint32_t os_error_code;
uint32_t exit_code; uint32_t exit_code;
void *process; void *process;
#if defined(DQN_OS_WIN32)
void *stdout_read; void *stdout_read;
void *stdout_write; void *stdout_write;
void *stderr_read; void *stderr_read;
void *stderr_write; void *stderr_write;
#endif
}; };
struct Dqn_OSExecResult struct Dqn_OSExecResult
@ -364,9 +364,9 @@ DQN_API Dqn_Str8 Dqn_OS_PathConvertF (Dqn_Arena *arena
// NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// // NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
DQN_API void Dqn_OS_Exit (int32_t exit_code); DQN_API void Dqn_OS_Exit (int32_t exit_code);
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle, Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle, Dqn_Arena *arena, Dqn_ErrorSink *error);
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_ErrorSink *error); DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_ErrorSink *error);
DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena, Dqn_ErrorSink *error); DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena, Dqn_ErrorSink *error);
DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena); DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena);
// NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// // NOTE: [$SEMA] Dqn_OSSemaphore ///////////////////////////////////////////////////////////////////
#if !defined(DQN_NO_SEMAPHORE) #if !defined(DQN_NO_SEMAPHORE)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ // $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
@ -9,11 +10,13 @@
// $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ | // $$$$$$ |\$$$$$$ | $$ | $$$$$$ |\$$$$$$ |$$$$$$\ $$ / $$ |
// \______/ \______/ \__| \______/ \______/ \______|\__| \__| // \______/ \______/ \__| \______/ \______/ \______|\__| \__|
// //
// dqn_os_posix.cpp -- Posix implementation of the OS layer // dqn_os_posix.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$VMEM] Dqn_OSMem ////////////////////////////////////////////////////////////////////////// // NOTE: [$VMEM] Dqn_OSMem
// //////////////////////////////////////////////////////////////////////////
static uint32_t Dqn_OS_MemConvertPageToOSFlags_(uint32_t protect) static uint32_t Dqn_OS_MemConvertPageToOSFlags_(uint32_t protect)
{ {
DQN_ASSERT((protect & ~Dqn_OSMemPage_All) == 0); DQN_ASSERT((protect & ~Dqn_OSMemPage_All) == 0);
@ -38,7 +41,7 @@ DQN_API void *Dqn_OS_MemReserve(Dqn_usize size, Dqn_OSMemCommit commit, uint32_t
if (commit == Dqn_OSMemCommit_Yes) if (commit == Dqn_OSMemCommit_Yes)
os_page_flags |= (PROT_READ | PROT_WRITE); os_page_flags |= (PROT_READ | PROT_WRITE);
void *result = mmap(nullptr, size, os_page_flags, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); void *result = mmap(nullptr, size, os_page_flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (result == MAP_FAILED) if (result == MAP_FAILED)
result = nullptr; result = nullptr;
return result; return result;
@ -71,11 +74,14 @@ DQN_API int Dqn_OS_MemProtect(void *ptr, Dqn_usize size, uint32_t page_flags)
if (!ptr || size == 0) if (!ptr || size == 0)
return 0; return 0;
static Dqn_Str8 const ALIGNMENT_ERROR_MSG = static Dqn_Str8 const ALIGNMENT_ERROR_MSG = DQN_STR8(
DQN_STR8("Page protection requires pointers to be page aligned because we " "Page protection requires pointers to be page aligned because we "
"can only guard memory at a multiple of the page boundary."); "can only guard memory at a multiple of the page boundary.");
DQN_ASSERTF(Dqn_IsPowerOfTwoAligned(DQN_CAST(uintptr_t)ptr, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data); DQN_ASSERTF(Dqn_IsPowerOfTwoAligned(DQN_CAST(uintptr_t) ptr, g_dqn_library->os_page_size),
DQN_ASSERTF(Dqn_IsPowerOfTwoAligned(size, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data); "%s",
ALIGNMENT_ERROR_MSG.data);
DQN_ASSERTF(
Dqn_IsPowerOfTwoAligned(size, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data);
unsigned long os_page_flags = Dqn_OS_MemConvertPageToOSFlags_(page_flags); unsigned long os_page_flags = Dqn_OS_MemConvertPageToOSFlags_(page_flags);
int result = mprotect(ptr, size, os_page_flags); int result = mprotect(ptr, size, os_page_flags);
@ -86,7 +92,7 @@ DQN_API int Dqn_OS_MemProtect(void *ptr, Dqn_usize size, uint32_t page_flags)
// NOTE: [$DATE] Date ////////////////////////////////////////////////////////////////////////////// // NOTE: [$DATE] Date //////////////////////////////////////////////////////////////////////////////
DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow() DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow()
{ {
Dqn_OSDateTime result = {}; Dqn_OSDateTime result = {};
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
@ -105,9 +111,9 @@ DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow()
result.minutes = time.tm_min; result.minutes = time.tm_min;
result.seconds = time.tm_sec; result.seconds = time.tm_sec;
result.day = DQN_CAST(uint8_t)time.tm_mday; result.day = DQN_CAST(uint8_t) time.tm_mday;
result.month = DQN_CAST(uint8_t)time.tm_mon + 1; result.month = DQN_CAST(uint8_t) time.tm_mon + 1;
result.year = 1900 + DQN_CAST(int16_t)time.tm_year; result.year = 1900 + DQN_CAST(int16_t) time.tm_year;
return result; return result;
} }
@ -134,7 +140,8 @@ DQN_API uint64_t Dqn_OS_DateToUnixTime(Dqn_OSDateTime date)
DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size) DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size)
{ {
#if defined(DQN_PLATFORM_EMSCRIPTEN) #if defined(DQN_PLATFORM_EMSCRIPTEN)
(void)buffer; (void)size; (void)buffer;
(void)size;
return false; return false;
#else #else
if (!buffer || size < 0) if (!buffer || size < 0)
@ -144,13 +151,16 @@ DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size)
return true; return true;
DQN_ASSERTF(size <= 32, DQN_ASSERTF(size <= 32,
"We can increase this by chunking the buffer and filling 32 bytes at a time. *Nix guarantees 32 " "We can increase this by chunking the buffer and filling 32 bytes at a time. *Nix "
"guarantees 32 "
"bytes can always be fulfilled by this system at a time"); "bytes can always be fulfilled by this system at a time");
// TODO(doyle): https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c // TODO(doyle):
// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
// TODO(doyle): https://man7.org/linux/man-pages/man2/getrandom.2.html // TODO(doyle): https://man7.org/linux/man-pages/man2/getrandom.2.html
uint32_t read_bytes = 0; uint32_t read_bytes = 0;
do { do {
read_bytes = getrandom(buffer, size, 0); // NOTE: EINTR can not be triggered if size <= 32 bytes read_bytes =
getrandom(buffer, size, 0); // NOTE: EINTR can not be triggered if size <= 32 bytes
} while (read_bytes != size || errno == EAGAIN); } while (read_bytes != size || errno == EAGAIN);
return true; return true;
#endif #endif
@ -164,9 +174,9 @@ DQN_API Dqn_Str8 Dqn_OS_EXEPath(Dqn_Arena *arena)
int required_size_wo_null_terminator = 0; 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_ArenaTempMemScope(arena); auto scoped_arena = Dqn_ArenaTempMemScope(arena);
char *try_buf = Dqn_Arena_NewArray(arena, char, try_size, Dqn_ZeroMem_No); char *try_buf = Dqn_Arena_NewArray(arena, char, try_size, Dqn_ZeroMem_No);
int bytes_written = readlink("/proc/self/exe", try_buf, try_size); 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 // Failed, we're unable to determine the executable directory
break; break;
@ -184,7 +194,9 @@ DQN_API Dqn_Str8 Dqn_OS_EXEPath(Dqn_Arena *arena)
// try_buf around, memcopy the byte and trash the try_buf from the // try_buf around, memcopy the byte and trash the try_buf from the
// arena. Instead we just get the size and redo the call one last // arena. Instead we just get the size and redo the call one last
// time after this "calculate" step. // time after this "calculate" step.
DQN_ASSERTF(bytes_written < try_size, "bytes_written can never be greater than the try size, function writes at most try_size"); 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; required_size_wo_null_terminator = bytes_written;
break; break;
} }
@ -192,7 +204,8 @@ DQN_API Dqn_Str8 Dqn_OS_EXEPath(Dqn_Arena *arena)
if (required_size_wo_null_terminator) { if (required_size_wo_null_terminator) {
Dqn_ArenaTempMem temp_mem = Dqn_Arena_TempMemBegin(arena); Dqn_ArenaTempMem temp_mem = Dqn_Arena_TempMemBegin(arena);
char *exe_path = Dqn_Arena_NewArray(arena, char, required_size_wo_null_terminator + 1, Dqn_ZeroMem_No); 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; exe_path[required_size_wo_null_terminator] = 0;
int bytes_written = readlink("/proc/self/exe", exe_path, required_size_wo_null_terminator); int bytes_written = readlink("/proc/self/exe", exe_path, required_size_wo_null_terminator);
@ -239,7 +252,8 @@ DQN_API Dqn_OSPathInfo Dqn_OS_PathInfo(Dqn_Str8 path)
result.last_write_time_in_s = file_stat.st_mtime; result.last_write_time_in_s = file_stat.st_mtime;
// TODO(dqn): Seems linux does not support creation time via stat. We // TODO(dqn): Seems linux does not support creation time via stat. We
// shoddily deal with this. // shoddily deal with this.
result.create_time_in_s = DQN_MIN(result.last_access_time_in_s, result.last_write_time_in_s); result.create_time_in_s =
DQN_MIN(result.last_access_time_in_s, result.last_write_time_in_s);
} }
return result; return result;
} }
@ -281,7 +295,8 @@ DQN_API bool Dqn_OS_CopyFile(Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_Er
strerror(error_code)); strerror(error_code));
return result; return result;
} }
DQN_DEFER { DQN_DEFER
{
close(src_fd); close(src_fd);
}; };
@ -296,12 +311,13 @@ DQN_API bool Dqn_OS_CopyFile(Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_Er
strerror(error_code)); strerror(error_code));
return result; return result;
} }
DQN_DEFER { DQN_DEFER
{
close(dest_fd); close(dest_fd);
}; };
struct stat stat_existing; struct stat stat_existing;
int fstat_result = fstat(src_fd, &stat_existing); int fstat_result = fstat(src_fd, &stat_existing);
if (fstat_result == -1) { if (fstat_result == -1) {
int error_code = errno; int error_code = errno;
Dqn_ErrorSink_MakeF(error, Dqn_ErrorSink_MakeF(error,
@ -316,13 +332,16 @@ DQN_API bool Dqn_OS_CopyFile(Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_Er
ssize_t bytes_written = sendfile64(dest_fd, src_fd, 0, stat_existing.st_size); ssize_t bytes_written = sendfile64(dest_fd, src_fd, 0, stat_existing.st_size);
result = (bytes_written == stat_existing.st_size); result = (bytes_written == stat_existing.st_size);
if (!result) { if (!result) {
int error_code = errno; int error_code = errno;
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_Str8 file_size_str8 = Dqn_U64ToByteSizeStr8(scratch.arena, stat_existing.st_size, Dqn_U64ByteSizeType_Auto); Dqn_Str8 file_size_str8 =
Dqn_Str8 bytes_written_str8 = Dqn_U64ToByteSizeStr8(scratch.arena, bytes_written, Dqn_U64ByteSizeType_Auto); Dqn_U64ToByteSizeStr8(scratch.arena, stat_existing.st_size, Dqn_U64ByteSizeType_Auto);
Dqn_Str8 bytes_written_str8 =
Dqn_U64ToByteSizeStr8(scratch.arena, bytes_written, Dqn_U64ByteSizeType_Auto);
Dqn_ErrorSink_MakeF(error, Dqn_ErrorSink_MakeF(error,
error_code, error_code,
"Failed to copy file '%.*s' to '%.*s', we copied %.*s but the file size is %.*s: (%d) %s", "Failed to copy file '%.*s' to '%.*s', we copied %.*s but the file "
"size is %.*s: (%d) %s",
DQN_STR_FMT(src), DQN_STR_FMT(src),
DQN_STR_FMT(dest), DQN_STR_FMT(dest),
DQN_STR_FMT(bytes_written_str8), DQN_STR_FMT(bytes_written_str8),
@ -350,12 +369,13 @@ DQN_API bool Dqn_OS_MoveFile(Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_Er
int unlink_result = unlink(src.data); int unlink_result = unlink(src.data);
if (unlink_result == -1) { if (unlink_result == -1) {
int error_code = errno; int error_code = errno;
Dqn_ErrorSink_MakeF(error, Dqn_ErrorSink_MakeF(
error_code, error,
"File '%.*s' was moved but failed to be unlinked from old location: (%d) %s", error_code,
DQN_STR_FMT(src), "File '%.*s' was moved but failed to be unlinked from old location: (%d) %s",
error_code, DQN_STR_FMT(src),
strerror(error_code)); error_code,
strerror(error_code));
} }
} }
return result; return result;
@ -378,10 +398,10 @@ DQN_API bool Dqn_OS_MakeDir(Dqn_Str8 path)
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
bool result = true; bool result = true;
// TODO(doyle): Implement this without using the path indexes, it's not // TODO(doyle): Implement this without using the path indexes, it's not
// necessary. See Windows implementation. // necessary. See Windows implementation.
Dqn_usize path_indexes_size = 0; Dqn_usize path_indexes_size = 0;
uint16_t path_indexes[64] = {}; uint16_t path_indexes[64] = {};
Dqn_Str8 copy = Dqn_Str8_Copy(scratch.arena, path); Dqn_Str8 copy = Dqn_Str8_Copy(scratch.arena, path);
for (Dqn_usize index = copy.size - 1; index < copy.size; index--) { for (Dqn_usize index = copy.size - 1; index < copy.size; index--) {
@ -403,34 +423,37 @@ DQN_API bool Dqn_OS_MakeDir(Dqn_Str8 path)
// it's not a directory. This request to make a directory is // it's not a directory. This request to make a directory is
// invalid. // invalid.
return false; return false;
} else if (Dqn_OS_DirExists(copy)) {
// 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;
} else { } else {
if (Dqn_OS_DirExists(copy)) { // NOTE: There's nothing that exists at this path, we can
// NOTE: We found a directory, we can stop here and start // create a directory here
// building up all the directories that didn't exist up to path_indexes[path_indexes_size++] = DQN_CAST(uint16_t) index;
// this point.
break;
} 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--) { for (Dqn_usize index = path_indexes_size - 1; result && index < path_indexes_size; index--) {
uint16_t path_index = path_indexes[index]; uint16_t path_index = path_indexes[index];
char temp = copy.data[path_index]; char temp = copy.data[path_index];
if (index != 0) copy.data[path_index] = 0; if (index != 0)
copy.data[path_index] = 0;
result |= mkdir(copy.data, 0774) == 0; result |= mkdir(copy.data, 0774) == 0;
if (index != 0) copy.data[path_index] = temp; if (index != 0)
copy.data[path_index] = temp;
} }
return result; return result;
} }
// NOTE: R/W Stream API //////////////////////////////////////////////////////////////////////////// // NOTE: R/W Stream API ////////////////////////////////////////////////////////////////////////////
DQN_API Dqn_OSFile Dqn_OS_FileOpen(Dqn_Str8 path, Dqn_OSFileOpen open_mode, uint32_t access, Dqn_ErrorSink *error) DQN_API Dqn_OSFile Dqn_OS_FileOpen(Dqn_Str8 path,
Dqn_OSFileOpen open_mode,
uint32_t access,
Dqn_ErrorSink *error)
{ {
Dqn_OSFile result = {}; Dqn_OSFile result = {};
if (!Dqn_Str8_HasData(path) || path.size <= 0) if (!Dqn_Str8_HasData(path) || path.size <= 0)
@ -443,7 +466,11 @@ DQN_API Dqn_OSFile Dqn_OS_FileOpen(Dqn_Str8 path, Dqn_OSFileOpen open_mode, uint
if (access & Dqn_OSFileAccess_Execute) { if (access & Dqn_OSFileAccess_Execute) {
result.error = true; result.error = true;
Dqn_ErrorSink_MakeF(error, 1, "Failed to open file '%.*s': File access flag 'execute' is not supported", DQN_STR_FMT(path)); Dqn_ErrorSink_MakeF(
error,
1,
"Failed to open file '%.*s': File access flag 'execute' is not supported",
DQN_STR_FMT(path));
DQN_INVALID_CODE_PATH; // TODO: Not supported via fopen DQN_INVALID_CODE_PATH; // TODO: Not supported via fopen
return result; return result;
} }
@ -456,32 +483,41 @@ DQN_API Dqn_OSFile Dqn_OS_FileOpen(Dqn_Str8 path, Dqn_OSFileOpen open_mode, uint
FILE *handle = nullptr; FILE *handle = nullptr;
switch (open_mode) { switch (open_mode) {
case Dqn_OSFileOpen_CreateAlways: handle = fopen(path.data, "w"); break; case Dqn_OSFileOpen_CreateAlways: handle = fopen(path.data, "w"); break;
case Dqn_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break; case Dqn_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break;
case Dqn_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break; case Dqn_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break;
default: DQN_INVALID_CODE_PATH; break; default: DQN_INVALID_CODE_PATH; break;
} }
if (!handle) { // TODO(doyle): FileOpen flag to string if (!handle) { // TODO(doyle): FileOpen flag to string
result.error = true; result.error = true;
Dqn_ErrorSink_MakeF(error, 1, "Failed to open file '%.*s': File could not be opened in requested mode 'Dqn_OSFileOpen' flag %d", DQN_STR_FMT(path), open_mode); Dqn_ErrorSink_MakeF(error,
1,
"Failed to open file '%.*s': File could not be opened in requested "
"mode 'Dqn_OSFileOpen' flag %d",
DQN_STR_FMT(path),
open_mode);
return result; return result;
} }
fclose(handle); fclose(handle);
} }
char const *fopen_mode = nullptr; char const *fopen_mode = nullptr;
if (access & Dqn_OSFileAccess_AppendOnly) { if (access & Dqn_OSFileAccess_AppendOnly)
fopen_mode = "a+"; fopen_mode = "a+";
} else if (access & Dqn_OSFileAccess_Write) { else if (access & Dqn_OSFileAccess_Write)
fopen_mode = "w+"; fopen_mode = "w+";
} else if (access & Dqn_OSFileAccess_Read) { else if (access & Dqn_OSFileAccess_Read)
fopen_mode = "r+"; fopen_mode = "r+";
}
FILE *handle = fopen(path.data, fopen_mode); FILE *handle = fopen(path.data, fopen_mode);
if (!handle) { if (!handle) {
result.error = true; result.error = true;
Dqn_ErrorSink_MakeF(error, 1, "Failed to open file '%.*s': File could not be opened with requested access mode 'Dqn_OSFileAccess' %d", DQN_STR_FMT(path), fopen_mode); Dqn_ErrorSink_MakeF(error,
1,
"Failed to open file '%.*s': File could not be opened with requested "
"access mode 'Dqn_OSFileAccess' %d",
DQN_STR_FMT(path),
fopen_mode);
return result; return result;
} }
result.handle = handle; result.handle = handle;
@ -493,25 +529,32 @@ DQN_API bool Dqn_OS_FileRead(Dqn_OSFile *file, void *buffer, Dqn_usize size, Dqn
if (!file || !file->handle || file->error || !buffer || size <= 0) if (!file || !file->handle || file->error || !buffer || size <= 0)
return false; return false;
if (fread(buffer, size, 1, DQN_CAST(FILE *)file->handle) != 1) { if (fread(buffer, size, 1, DQN_CAST(FILE *) file->handle) != 1) {
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_Str8 buffer_size_str8 = Dqn_U64ToByteSizeStr8(scratch.arena, size, Dqn_U64ByteSizeType_Auto); Dqn_Str8 buffer_size_str8 =
Dqn_ErrorSink_MakeF(error, 1, "Failed to read %.*s from file", DQN_STR_FMT(buffer_size_str8)); Dqn_U64ToByteSizeStr8(scratch.arena, size, Dqn_U64ByteSizeType_Auto);
Dqn_ErrorSink_MakeF(
error, 1, "Failed to read %.*s from file", DQN_STR_FMT(buffer_size_str8));
return false; return false;
} }
return true; return true;
} }
DQN_API bool Dqn_OS_FileWritePtr(Dqn_OSFile *file, void const *buffer, Dqn_usize size, Dqn_ErrorSink *error) DQN_API bool
Dqn_OS_FileWritePtr(Dqn_OSFile *file, void const *buffer, Dqn_usize size, Dqn_ErrorSink *error)
{ {
if (!file || !file->handle || file->error || !buffer || size <= 0) if (!file || !file->handle || file->error || !buffer || size <= 0)
return false; return false;
bool result = fwrite(buffer, DQN_CAST(Dqn_usize)size, 1 /*count*/, DQN_CAST(FILE *)file->handle) == 1 /*count*/; bool result =
fwrite(buffer, DQN_CAST(Dqn_usize) size, 1 /*count*/, DQN_CAST(FILE *) file->handle) ==
1 /*count*/;
if (!result) { if (!result) {
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
Dqn_Str8 buffer_size_str8 = Dqn_U64ToByteSizeStr8(scratch.arena, size, Dqn_U64ByteSizeType_Auto); Dqn_Str8 buffer_size_str8 =
Dqn_ErrorSink_MakeF(error, 1, "Failed to write buffer (%s) to file handle", DQN_STR_FMT(buffer_size_str8)); Dqn_U64ToByteSizeStr8(scratch.arena, size, Dqn_U64ByteSizeType_Auto);
Dqn_ErrorSink_MakeF(
error, 1, "Failed to write buffer (%s) to file handle", DQN_STR_FMT(buffer_size_str8));
} }
return result; return result;
} }
@ -520,7 +563,7 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file)
{ {
if (!file || !file->handle || file->error) if (!file || !file->handle || file->error)
return; return;
fclose(DQN_CAST(FILE *)file->handle); fclose(DQN_CAST(FILE *) file->handle);
*file = {}; *file = {};
} }
#endif // !defined(DQN_NO_OS_FILE_API) #endif // !defined(DQN_NO_OS_FILE_API)
@ -528,26 +571,39 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file)
// NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// // NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
DQN_API void Dqn_OS_Exit(int32_t exit_code) DQN_API void Dqn_OS_Exit(int32_t exit_code)
{ {
exit(DQN_CAST(int)exit_code); exit(DQN_CAST(int) exit_code);
} }
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle) enum Dqn_OSPipeType_ {
Dqn_OSPipeType__Read,
Dqn_OSPipeType__Write,
Dqn_OSPipeType__Count,
};
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle,
Dqn_Arena *arena,
Dqn_ErrorSink *error)
{ {
Dqn_OSExecResult result = {}; Dqn_OSExecResult result = {};
if (!handle.process || handle.os_error_code) { if (!handle.process || handle.os_error_code || handle.exit_code) {
result.os_error_code = handle.os_error_code; if (handle.os_error_code)
result.os_error_code = handle.os_error_code;
else
result.exit_code = handle.exit_code;
DQN_ASSERT(!handle.stdout_read);
DQN_ASSERT(!handle.stdout_write);
DQN_ASSERT(!handle.stderr_read);
DQN_ASSERT(!handle.stderr_write);
return result; return result;
} }
if (handle.exit_code) { #if defined(DQN_PLATFORM_EMSCRIPTEN)
result.exit_code = handle.exit_code; DQN_INVALID_CODE_PATHF("Unsupported operation");
return result; #endif
}
#if defined(DQN_PLATFORM_EMSCRIPTEN) static_assert(sizeof(pid_t) <= sizeof(handle.process),
DQN_ASSERTF(false, "Unsupported operation"); "We store the PID opaquely in a register sized pointer");
#else
static_assert(sizeof(pid_t) <= sizeof(handle.process), "We store the PID opaquely in a register sized pointer");
pid_t process = {}; pid_t process = {};
DQN_MEMCPY(&process, &handle.process, sizeof(process)); DQN_MEMCPY(&process, &handle.process, sizeof(process));
for (;;) { for (;;) {
@ -567,28 +623,143 @@ DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle)
break; break;
} }
} }
#endif
int stdout_pipe[Dqn_OSPipeType__Count] = {};
int stderr_pipe[Dqn_OSPipeType__Count] = {};
DQN_MEMCPY(&stdout_pipe[Dqn_OSPipeType__Read],
&handle.stdout_read,
sizeof(stdout_pipe[Dqn_OSPipeType__Read]));
DQN_MEMCPY(&stdout_pipe[Dqn_OSPipeType__Write],
&handle.stdout_write,
sizeof(stdout_pipe[Dqn_OSPipeType__Write]));
DQN_MEMCPY(&stderr_pipe[Dqn_OSPipeType__Read],
&handle.stderr_read,
sizeof(stderr_pipe[Dqn_OSPipeType__Read]));
DQN_MEMCPY(&stderr_pipe[Dqn_OSPipeType__Write],
&handle.stderr_write,
sizeof(stderr_pipe[Dqn_OSPipeType__Write]));
// NOTE: Process has finished, stop the write end of the pipe
close(stdout_pipe[Dqn_OSPipeType__Write]);
close(stderr_pipe[Dqn_OSPipeType__Write]);
// NOTE: Read the data from the read end of the pipe
if (result.os_error_code == 0) {
Dqn_Scratch scratch = Dqn_Scratch_Get(arena);
if (arena && handle.stdout_read) {
char buffer[4096];
Dqn_Str8Builder builder = {};
builder.arena = scratch.arena;
for (;;) {
ssize_t bytes_read =
read(stdout_pipe[Dqn_OSPipeType__Read], buffer, sizeof(buffer));
if (bytes_read <= 0)
break;
Dqn_Str8Builder_AppendF(&builder, "%.*s", bytes_read, buffer);
}
result.stdout_text = Dqn_Str8Builder_Build(&builder, arena);
}
if (arena && handle.stderr_read) {
char buffer[4096];
Dqn_Str8Builder builder = {};
builder.arena = scratch.arena;
for (;;) {
ssize_t bytes_read =
read(stderr_pipe[Dqn_OSPipeType__Read], buffer, sizeof(buffer));
if (bytes_read <= 0)
break;
Dqn_Str8Builder_AppendF(&builder, "%.*s", bytes_read, buffer);
}
result.stderr_text = Dqn_Str8Builder_Build(&builder, arena);
}
}
close(stdout_pipe[Dqn_OSPipeType__Read]);
close(stderr_pipe[Dqn_OSPipeType__Read]);
return result; return result;
} }
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir) DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line,
Dqn_Str8 working_dir,
uint8_t exec_flags,
Dqn_ErrorSink *error)
{ {
#if defined(DQN_PLATFORM_EMSCRIPTEN)
DQN_INVALID_CODE_PATHF("Unsupported operation");
#endif
Dqn_OSExecAsyncHandle result = {}; Dqn_OSExecAsyncHandle result = {};
if (cmd_line.size == 0) if (cmd_line.size == 0)
return result; return result;
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
// TODO: This API will need to switch to an array of strings for unix int stdout_pipe[Dqn_OSPipeType__Count] = {};
int stderr_pipe[Dqn_OSPipeType__Count] = {};
// NOTE: Open stdout pipe //////////////////////////////////////////////////////////////////////
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStdout)) {
if (pipe(stdout_pipe) == -1) {
result.os_error_code = errno;
return result;
}
DQN_ASSERT(stdout_pipe[Dqn_OSPipeType__Read] != 0);
DQN_ASSERT(stdout_pipe[Dqn_OSPipeType__Write] != 0);
}
DQN_DEFER
{
if (result.os_error_code == 0 && result.exit_code == 0)
return;
close(stdout_pipe[Dqn_OSPipeType__Read]);
close(stdout_pipe[Dqn_OSPipeType__Write]);
};
// NOTE: Open stderr pipe //////////////////////////////////////////////////////////////////////
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStderr)) {
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_MergeStderrToStdout)) {
stderr_pipe[Dqn_OSPipeType__Read] = stdout_pipe[Dqn_OSPipeType__Read];
stderr_pipe[Dqn_OSPipeType__Write] = stdout_pipe[Dqn_OSPipeType__Write];
} else if (pipe(stderr_pipe) == -1) {
result.os_error_code = errno;
return result;
}
DQN_ASSERT(stderr_pipe[Dqn_OSPipeType__Read] != 0);
DQN_ASSERT(stderr_pipe[Dqn_OSPipeType__Write] != 0);
}
DQN_DEFER
{
if (result.os_error_code == 0 && result.exit_code == 0)
return;
close(stderr_pipe[Dqn_OSPipeType__Read]);
close(stderr_pipe[Dqn_OSPipeType__Write]);
};
pid_t child_pid = fork(); pid_t child_pid = fork();
if (child_pid < 0) { if (child_pid < 0) {
result.os_error_code = errno; result.os_error_code = errno;
return result; return result;
} }
if (child_pid == 0) { if (child_pid == 0) { // Child process
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStdout) &&
(dup2(stdout_pipe[Dqn_OSPipeType__Write], STDOUT_FILENO) == -1)) {
result.os_error_code = errno;
return result;
}
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStderr) &&
(dup2(stderr_pipe[Dqn_OSPipeType__Write], STDERR_FILENO) == -1)) {
result.os_error_code = errno;
return result;
}
// NOTE: Convert the command into something suitable for execvp // NOTE: Convert the command into something suitable for execvp
char **argv = Dqn_Arena_NewArray(scratch.arena, char*, cmd_line.size + 1 /*null*/, Dqn_ZeroMem_Yes); char **argv =
Dqn_Arena_NewArray(scratch.arena, char *, cmd_line.size + 1 /*null*/, Dqn_ZeroMem_Yes);
if (!argv) { if (!argv) {
result.exit_code = -1; result.exit_code = -1;
return result; return result;
@ -596,16 +767,20 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
for (Dqn_usize arg_index = 0; arg_index < cmd_line.size; arg_index++) { for (Dqn_usize arg_index = 0; arg_index < cmd_line.size; arg_index++) {
Dqn_Str8 arg = cmd_line.data[arg_index]; Dqn_Str8 arg = cmd_line.data[arg_index];
argv[arg_index] = Dqn_Str8_Copy(scratch.arena, arg).data; // NOTE: Copy string to guarantee it is null-terminated argv[arg_index] = Dqn_Str8_Copy(scratch.arena, arg)
.data; // NOTE: Copy string to guarantee it is null-terminated
} }
// NOTE: Change the working directory if there is one // NOTE: Change the working directory if there is one
char *prev_working_dir = nullptr; char *prev_working_dir = nullptr;
DQN_DEFER { DQN_DEFER
{
if (!prev_working_dir) if (!prev_working_dir)
return; return;
if (result.os_error_code == 0) if (result.os_error_code == 0) {
chdir(prev_working_dir); int chdir_result = chdir(prev_working_dir);
(void)chdir_result;
}
free(prev_working_dir); free(prev_working_dir);
}; };
@ -619,12 +794,29 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
// NOTE: Execute the command. We reuse argv because the first arg, the // NOTE: Execute the command. We reuse argv because the first arg, the
// binary to execute is guaranteed to be null-terminated. // binary to execute is guaranteed to be null-terminated.
if (execvp(argv[0], argv) < 0) { if (execvp(argv[0], argv) < 0) {
result.os_error_code = errno; result.os_error_code = errno;
return result; return result;
} }
} }
DQN_ASSERT(result.os_error_code == 0);
DQN_MEMCPY(&result.stdout_read,
&stdout_pipe[Dqn_OSPipeType__Read],
sizeof(stdout_pipe[Dqn_OSPipeType__Read]));
DQN_MEMCPY(&result.stdout_write,
&stdout_pipe[Dqn_OSPipeType__Write],
sizeof(stdout_pipe[Dqn_OSPipeType__Write]));
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStderr) && Dqn_Bit_IsNotSet(exec_flags, Dqn_OSExecFlag_MergeStderrToStdout)) {
DQN_MEMCPY(&result.stderr_read,
&stderr_pipe[Dqn_OSPipeType__Read],
sizeof(stderr_pipe[Dqn_OSPipeType__Read]));
DQN_MEMCPY(&result.stderr_write,
&stderr_pipe[Dqn_OSPipeType__Write],
sizeof(stderr_pipe[Dqn_OSPipeType__Write]));
}
result.exec_flags = exec_flags;
DQN_MEMCPY(&result.process, &child_pid, sizeof(child_pid)); DQN_MEMCPY(&result.process, &child_pid, sizeof(child_pid));
return result; return result;
} }
@ -633,8 +825,8 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
// NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// // NOTE: [$SEMA] Dqn_OSSemaphore ///////////////////////////////////////////////////////////////////
DQN_API Dqn_OSSemaphore Dqn_OS_SemaphoreInit(uint32_t initial_count) DQN_API Dqn_OSSemaphore Dqn_OS_SemaphoreInit(uint32_t initial_count)
{ {
Dqn_OSSemaphore result = {}; Dqn_OSSemaphore result = {};
int pshared = 0; // Share the semaphore across all threads in the process int pshared = 0; // Share the semaphore across all threads in the process
if (sem_init(&result.posix_handle, pshared, initial_count) == 0) if (sem_init(&result.posix_handle, pshared, initial_count) == 0)
result.posix_init = true; result.posix_init = true;
return result; return result;
@ -643,9 +835,8 @@ DQN_API Dqn_OSSemaphore Dqn_OS_SemaphoreInit(uint32_t initial_count)
DQN_API bool Dqn_OS_SemaphoreIsValid(Dqn_OSSemaphore *semaphore) DQN_API bool Dqn_OS_SemaphoreIsValid(Dqn_OSSemaphore *semaphore)
{ {
bool result = false; bool result = false;
if (semaphore) { if (semaphore)
result = semaphore->posix_init; result = semaphore->posix_init;
}
return result; return result;
} }
@ -685,11 +876,12 @@ DQN_API void Dqn_OS_SemaphoreIncrement(Dqn_OSSemaphore *semaphore, uint32_t amou
sem_post_multiple(&semaphore->posix_handle, amount); // mingw extension sem_post_multiple(&semaphore->posix_handle, amount); // mingw extension
#else #else
DQN_FOR_UINDEX(index, amount) DQN_FOR_UINDEX(index, amount)
sem_post(&semaphore->posix_handle); sem_post(&semaphore->posix_handle);
#endif // !defined(DQN_OS_WIN32) #endif // !defined(DQN_OS_WIN32)
} }
DQN_API Dqn_OSSemaphoreWaitResult Dqn_OS_SemaphoreWait(Dqn_OSSemaphore *semaphore, uint32_t timeout_ms) DQN_API Dqn_OSSemaphoreWaitResult Dqn_OS_SemaphoreWait(Dqn_OSSemaphore *semaphore,
uint32_t timeout_ms)
{ {
Dqn_OSSemaphoreWaitResult result = {}; Dqn_OSSemaphoreWaitResult result = {};
if (!Dqn_OS_SemaphoreIsValid(semaphore)) if (!Dqn_OS_SemaphoreIsValid(semaphore))
@ -707,12 +899,10 @@ DQN_API Dqn_OSSemaphoreWaitResult Dqn_OS_SemaphoreWait(Dqn_OSSemaphore *semaphor
struct timespec abs_timeout = {}; struct timespec abs_timeout = {};
abs_timeout.tv_sec = timeout_ms / 1000; abs_timeout.tv_sec = timeout_ms / 1000;
abs_timeout.tv_nsec = (timeout_ms % 1000) * 1'000'000; abs_timeout.tv_nsec = (timeout_ms % 1000) * 1'000'000;
if (sem_timedwait(&semaphore->posix_handle, &abs_timeout) == 0) { if (sem_timedwait(&semaphore->posix_handle, &abs_timeout) == 0)
result = Dqn_OSSemaphoreWaitResult_Success; result = Dqn_OSSemaphoreWaitResult_Success;
} else { else if (errno == ETIMEDOUT)
if (errno == ETIMEDOUT) result = Dqn_OSSemaphoreWaitResult_Timeout;
result = Dqn_OSSemaphoreWaitResult_Timeout;
}
} }
return result; return result;
} }
@ -755,7 +945,7 @@ DQN_API void Dqn_OS_MutexUnlock(Dqn_OSMutex *mutex)
// NOTE: [$THRD] Dqn_OSThread ///////////////////////////////////////////////////////////////////// // NOTE: [$THRD] Dqn_OSThread /////////////////////////////////////////////////////////////////////
static void *Dqn_OS_ThreadFunc_(void *user_context) static void *Dqn_OS_ThreadFunc_(void *user_context)
{ {
Dqn_OSThread *thread = DQN_CAST(Dqn_OSThread *)user_context; Dqn_OSThread *thread = DQN_CAST(Dqn_OSThread *) user_context;
Dqn_OS_SemaphoreWait(&thread->init_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT); Dqn_OS_SemaphoreWait(&thread->init_semaphore, DQN_OS_SEMAPHORE_INFINITE_TIMEOUT);
thread->func(thread); thread->func(thread);
return nullptr; return nullptr;
@ -789,7 +979,7 @@ DQN_API bool Dqn_OS_ThreadInit(Dqn_OSThread *thread, Dqn_OSThreadFunc *func, voi
pthread_attr_destroy(&attribs); pthread_attr_destroy(&attribs);
if (result) { if (result) {
DQN_MEMCPY(&thread->handle, &p_thread, sizeof(p_thread)); DQN_MEMCPY(&thread->handle, &p_thread, sizeof(p_thread));
DQN_MEMCPY(&thread->thread_id, &p_thread, sizeof(p_thread)); DQN_MEMCPY(&thread->thread_id, &p_thread, sizeof(p_thread));
} }
@ -821,7 +1011,7 @@ DQN_API uint32_t Dqn_OS_ThreadID()
{ {
pid_t result = gettid(); pid_t result = gettid();
DQN_ASSERT(gettid() >= 0); DQN_ASSERT(gettid() >= 0);
return DQN_CAST(uint32_t)result; return DQN_CAST(uint32_t) result;
} }
#endif // !defined(DQN_NO_THREAD) #endif // !defined(DQN_NO_THREAD)
@ -871,11 +1061,11 @@ static EM_BOOL EMWebSocketOnCloseCallback(int type, const EmscriptenWebSocketClo
#if defined(DQN_PLATFORM_EMSCRIPTEN) #if defined(DQN_PLATFORM_EMSCRIPTEN)
static void Dqn_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch) static void Dqn_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch)
{ {
Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *)fetch->userData; Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *) fetch->userData;
if (!DQN_CHECK(response)) if (!DQN_CHECK(response))
return; return;
response->http_status = DQN_CAST(uint32_t)fetch->status; response->http_status = DQN_CAST(uint32_t) fetch->status;
response->body = Dqn_Str8_Alloc(response->arena, fetch->numBytes, Dqn_ZeroMem_No); response->body = Dqn_Str8_Alloc(response->arena, fetch->numBytes, Dqn_ZeroMem_No);
if (response->body.data) if (response->body.data)
DQN_MEMCPY(response->body.data, fetch->data, fetch->numBytes); DQN_MEMCPY(response->body.data, fetch->data, fetch->numBytes);
@ -886,11 +1076,11 @@ static void Dqn_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch
static void Dqn_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch) static void Dqn_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch)
{ {
Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *)fetch->userData; Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *) fetch->userData;
if (!DQN_CHECK(response)) if (!DQN_CHECK(response))
return; return;
response->http_status = DQN_CAST(uint32_t)fetch->status; response->http_status = DQN_CAST(uint32_t) fetch->status;
response->body = Dqn_Str8_Alloc(response->arena, fetch->numBytes, Dqn_ZeroMem_No); response->body = Dqn_Str8_Alloc(response->arena, fetch->numBytes, Dqn_ZeroMem_No);
if (response->body.size) if (response->body.size)
DQN_MEMCPY(response->body.data, fetch->data, fetch->numBytes); DQN_MEMCPY(response->body.data, fetch->data, fetch->numBytes);
@ -912,25 +1102,30 @@ DQN_API void Dqn_OS_HttpRequestAsync(Dqn_OSHttpResponse *response,
if (!response || !arena) if (!response || !arena)
return; return;
response->arena = arena; response->arena = arena;
response->builder.arena = response->scratch_arena ? response->scratch_arena : &response->tmp_arena; response->builder.arena =
response->scratch_arena ? response->scratch_arena : &response->tmp_arena;
Dqn_Arena *scratch_arena = response->scratch_arena; Dqn_Arena *scratch_arena = response->scratch_arena;
Dqn_Scratch scratch_ = Dqn_Scratch_Get(arena); Dqn_Scratch scratch_ = Dqn_Scratch_Get(arena);
if (!scratch_arena) if (!scratch_arena)
scratch_arena = scratch_.arena; scratch_arena = scratch_.arena;
#if defined(DQN_PLATFORM_EMSCRIPTEN) #if defined(DQN_PLATFORM_EMSCRIPTEN)
emscripten_fetch_attr_t fetch_attribs = {}; emscripten_fetch_attr_t fetch_attribs = {};
emscripten_fetch_attr_init(&fetch_attribs); emscripten_fetch_attr_init(&fetch_attribs);
if (method.size >= sizeof(fetch_attribs.requestMethod)) { if (method.size >= sizeof(fetch_attribs.requestMethod)) {
response->error_msg = Dqn_Str8_InitF(arena, response->error_msg =
"Request method in EM has a size limit of 31 characters, method was '%.*s' which is %zu characters long", Dqn_Str8_InitF(arena,
DQN_STR_FMT(method), "Request method in EM has a size limit of 31 characters, method was "
method.size); "'%.*s' which is %zu characters long",
DQN_CHECKF(method.size < sizeof(fetch_attribs.requestMethod), "%.*s", DQN_STR_FMT(response->error_msg)); DQN_STR_FMT(method),
response->error_code = DQN_CAST(uint32_t)-1; method.size);
DQN_CHECKF(method.size < sizeof(fetch_attribs.requestMethod),
"%.*s",
DQN_STR_FMT(response->error_msg));
response->error_code = DQN_CAST(uint32_t) - 1;
Dqn_Atomic_AddU32(&response->done, 1); Dqn_Atomic_AddU32(&response->done, 1);
return; return;
} }
@ -944,24 +1139,27 @@ DQN_API void Dqn_OS_HttpRequestAsync(Dqn_OSHttpResponse *response,
fetch_attribs.onerror = Dqn_OS_HttpRequestEMFetchOnErrorCallback; fetch_attribs.onerror = Dqn_OS_HttpRequestEMFetchOnErrorCallback;
fetch_attribs.userData = response; fetch_attribs.userData = response;
Dqn_Str8 url = Dqn_Str8_InitF(scratch_arena, "%.*s%.*s", DQN_STR_FMT(host), DQN_STR_FMT(path)); Dqn_Str8 url = Dqn_Str8_InitF(scratch_arena, "%.*s%.*s", DQN_STR_FMT(host), DQN_STR_FMT(path));
Dqn_Log_InfoF("Initiating HTTP '%s' request to '%.*s' with payload '%.*s'", fetch_attribs.requestMethod, DQN_STR_FMT(url), DQN_STR_FMT(body)); Dqn_Log_InfoF("Initiating HTTP '%s' request to '%.*s' with payload '%.*s'",
fetch_attribs.requestMethod,
DQN_STR_FMT(url),
DQN_STR_FMT(body));
response->on_complete_semaphore = Dqn_OS_SemaphoreInit(0); response->on_complete_semaphore = Dqn_OS_SemaphoreInit(0);
response->em_handle = emscripten_fetch(&fetch_attribs, url.data); response->em_handle = emscripten_fetch(&fetch_attribs, url.data);
#else // #elif defined(DQN_OS_WIN32) #else // #elif defined(DQN_OS_WIN32)
DQN_INVALID_CODE_PATHF("Unimplemented function"); DQN_INVALID_CODE_PATHF("Unimplemented function");
#endif #endif
} }
DQN_API void Dqn_OS_HttpRequestFree(Dqn_OSHttpResponse *response) DQN_API void Dqn_OS_HttpRequestFree(Dqn_OSHttpResponse *response)
{ {
// NOTE: Cleanup // NOTE: Cleanup
#if defined(DQN_PLATFORM_EMSCRIPTEN) #if defined(DQN_PLATFORM_EMSCRIPTEN)
if (response->em_handle) { if (response->em_handle) {
emscripten_fetch_close(response->em_handle); emscripten_fetch_close(response->em_handle);
response->em_handle = nullptr; response->em_handle = nullptr;
} }
#endif // #elif defined(DQN_OS_WIN32) #endif // #elif defined(DQN_OS_WIN32)
Dqn_Arena_Deinit(&response->tmp_arena); Dqn_Arena_Deinit(&response->tmp_arena);
if (Dqn_OS_SemaphoreIsValid(&response->on_complete_semaphore)) if (Dqn_OS_SemaphoreIsValid(&response->on_complete_semaphore))

View File

@ -633,7 +633,7 @@ DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle, Dqn_Arena
return result; return result;
} }
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t flags, Dqn_ErrorSink *error) DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_ErrorSink *error)
{ {
// NOTE: Pre-amble ///////////////////////////////////////////////////////////////////////////// // NOTE: Pre-amble /////////////////////////////////////////////////////////////////////////////
Dqn_OSExecAsyncHandle result = {}; Dqn_OSExecAsyncHandle result = {};
@ -653,7 +653,14 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
// NOTE: Redirect stdout /////////////////////////////////////////////////////////////////////// // NOTE: Redirect stdout ///////////////////////////////////////////////////////////////////////
HANDLE stdout_read = {}; HANDLE stdout_read = {};
HANDLE stdout_write = {}; HANDLE stdout_write = {};
if (flags & Dqn_OSExecFlag_SaveStdout) { DQN_DEFER {
if (result.os_error_code || result.exit_code) {
CloseHandle(stdout_read);
CloseHandle(stdout_write);
}
};
if (Dqn_Bit_IsSet(exec_flags & Dqn_OSExecFlag_SaveStdout)) {
if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) { if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) {
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
result.os_error_code = win_error.code; result.os_error_code = win_error.code;
@ -666,13 +673,6 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
return result; return result;
} }
DQN_DEFER {
if (result.os_error_code) {
CloseHandle(stdout_read);
CloseHandle(stdout_write);
}
};
if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) { if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) {
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
result.os_error_code = win_error.code; result.os_error_code = win_error.code;
@ -689,8 +689,15 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
// NOTE: Redirect stderr /////////////////////////////////////////////////////////////////////// // NOTE: Redirect stderr ///////////////////////////////////////////////////////////////////////
HANDLE stderr_read = {}; HANDLE stderr_read = {};
HANDLE stderr_write = {}; HANDLE stderr_write = {};
if (flags & Dqn_OSExecFlag_SaveStderr) { DQN_DEFER {
if (flags & Dqn_OSExecFlag_MergeStderrToStdout) { if (result.os_error_code || result.exit_code) {
CloseHandle(stderr_read);
CloseHandle(stderr_write);
}
};
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStderr)) {
if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_MergeStderrToStdout)) {
stderr_read = stdout_read; stderr_read = stdout_read;
stderr_write = stdout_write; stderr_write = stdout_write;
} else { } else {
@ -706,13 +713,6 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
return result; return result;
} }
DQN_DEFER {
if (result.os_error_code) {
CloseHandle(stderr_read);
CloseHandle(stderr_write);
}
};
if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) { if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) {
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
result.os_error_code = win_error.code; result.os_error_code = win_error.code;
@ -752,11 +752,11 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
result.process = proc_info.hProcess; result.process = proc_info.hProcess;
result.stdout_read = stdout_read; result.stdout_read = stdout_read;
result.stdout_write = stdout_write; result.stdout_write = stdout_write;
if ((flags & Dqn_OSExecFlag_MergeStderrToStdout) == 0) { if (Dqn_Bit_IsSet(exec_flags, Dqn_OSExecFlag_SaveStderr) && Dqn_Bit_IsNotSet(exec_flags, Dqn_OSExecFlag_MergeStderrToStdout)) {
result.stderr_read = stderr_read; result.stderr_read = stderr_read;
result.stderr_write = stderr_write; result.stderr_write = stderr_write;
} }
result.exec_flags = flags; result.exec_flags = exec_flags;
return result; return result;
} }

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ // $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_string.cpp // dqn_string.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$CSTR] Dqn_CStr8 ///////////////////////////////////////////////////////////////////////// // NOTE: [$CSTR] Dqn_CStr8 /////////////////////////////////////////////////////////////////////////
DQN_API Dqn_usize Dqn_CStr8_FSize(DQN_FMT_ATTRIB char const *fmt, ...) DQN_API Dqn_usize Dqn_CStr8_FSize(DQN_FMT_ATTRIB char const *fmt, ...)

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ // $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\
@ -20,6 +21,9 @@
// [$CHAR] Dqn_Char -- Character ascii/digit.. helpers // [$CHAR] Dqn_Char -- Character ascii/digit.. helpers
// [$UTFX] Dqn_UTF -- Unicode helpers // [$UTFX] Dqn_UTF -- Unicode helpers
// //
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$STR8] Dqn_Str8 ////////////////////////////////////////////////////////////////////////// // NOTE: [$STR8] Dqn_Str8 //////////////////////////////////////////////////////////////////////////
struct Dqn_Str8Link struct Dqn_Str8Link
{ {

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\
@ -21,6 +22,7 @@
// dqn_thread_context.cpp // dqn_thread_context.cpp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
DQN_THREAD_LOCAL Dqn_ThreadContext g_dqn_thread_context; DQN_THREAD_LOCAL Dqn_ThreadContext g_dqn_thread_context;

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\
@ -21,6 +22,7 @@
// dqn_thread_context.h -- Per thread data (e.g. scratch arenas) // dqn_thread_context.h -- Per thread data (e.g. scratch arenas)
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
struct Dqn_ThreadContext struct Dqn_ThreadContext
{ {

31
dqn_type_info.cpp Normal file
View File

@ -0,0 +1,31 @@
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
// \__$$ __|\$$\ $$ |$$ __$$\ $$ _____| \_$$ _|$$$\ $$ |$$ _____|$$ __$$\
// $$ | \$$\ $$ / $$ | $$ |$$ | $$ | $$$$\ $$ |$$ | $$ / $$ |
// $$ | \$$$$ / $$$$$$$ |$$$$$\ $$ | $$ $$\$$ |$$$$$\ $$ | $$ |
// $$ | \$$ / $$ ____/ $$ __| $$ | $$ \$$$$ |$$ __| $$ | $$ |
// $$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |
// $$ | $$ | $$ | $$$$$$$$\ $$$$$$\ $$ | \$$ |$$ | $$$$$$ |
// \__| \__| \__| \________| \______|\__| \__|\__| \______/
//
// dqn_type_info.cpp
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
Dqn_TypeGetField Dqn_Type_GetField(Dqn_TypeInfo const *type_info, Dqn_Str8 name)
{
Dqn_TypeGetField result = {};
for (Dqn_usize index = 0; index < type_info->fields_count; index++) {
Dqn_TypeField const *type_field = type_info->fields + index;
if (type_field->name == name) {
result.success = true;
result.index = index;
result.field = DQN_CAST(Dqn_TypeField *)type_field;
break;
}
}
return result;
}

View File

@ -1,3 +1,4 @@
/*
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\
@ -12,6 +13,7 @@
// dqn_type_info.h -- C++ type introspection // dqn_type_info.h -- C++ type introspection
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
*/
enum Dqn_TypeKind enum Dqn_TypeKind
{ {
@ -51,17 +53,4 @@ struct Dqn_TypeGetField
Dqn_TypeField *field; Dqn_TypeField *field;
}; };
Dqn_TypeGetField Dqn_Type_GetField(Dqn_TypeInfo const *type_info, Dqn_Str8 name) Dqn_TypeGetField Dqn_Type_GetField(Dqn_TypeInfo const *type_info, Dqn_Str8 name);
{
Dqn_TypeGetField result = {};
for (Dqn_usize index = 0; index < type_info->fields_count; index++) {
Dqn_TypeField const *type_field = type_info->fields + index;
if (type_field->name == name) {
result.success = true;
result.index = index;
result.field = DQN_CAST(Dqn_TypeField *)type_field;
break;
}
}
return result;
}

View File

@ -1,6 +1,8 @@
#define DQN_UTEST_IMPLEMENTATION #define DQN_UTEST_IMPLEMENTATION
#include "Standalone/dqn_utest.h" #include "Standalone/dqn_utest.h"
#include <inttypes.h>
static Dqn_UTest Dqn_Test_Arena() static Dqn_UTest Dqn_Test_Arena()
{ {
Dqn_UTest test = {}; Dqn_UTest test = {};
@ -85,7 +87,12 @@ static Dqn_UTest Dqn_Test_Arena()
} }
Dqn_Arena_TempMemEnd(temp_memory); Dqn_Arena_TempMemEnd(temp_memory);
DQN_UTEST_ASSERT (&test, arena.curr->prev == nullptr); DQN_UTEST_ASSERT (&test, arena.curr->prev == nullptr);
DQN_UTEST_ASSERTF(&test, arena.curr->reserve >= DQN_MEGABYTES(1), "size=%lluMiB (%lluB), expect=%lluB", (arena.curr->reserve / 1024 / 1024), arena.curr->reserve, DQN_MEGABYTES(1)); DQN_UTEST_ASSERTF(&test,
arena.curr->reserve >= DQN_MEGABYTES(1),
"size=%" PRIu64 "MiB (%" PRIu64 "B), expect=%" PRIu64 "B",
(arena.curr->reserve / 1024 / 1024),
arena.curr->reserve,
DQN_MEGABYTES(1));
} }
} }
return test; return test;
@ -98,57 +105,57 @@ static Dqn_UTest Dqn_Test_Bin()
DQN_UTEST_GROUP(test, "Dqn_Bin") { DQN_UTEST_GROUP(test, "Dqn_Bin") {
DQN_UTEST_TEST("Convert 0x123") { DQN_UTEST_TEST("Convert 0x123") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0x123")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0x123"));
DQN_UTEST_ASSERTF(&test, result == 0x123, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0x123, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert 0xFFFF") { DQN_UTEST_TEST("Convert 0xFFFF") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0xFFFF")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0xFFFF"));
DQN_UTEST_ASSERTF(&test, result == 0xFFFF, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0xFFFF, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert FFFF") { DQN_UTEST_TEST("Convert FFFF") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("FFFF")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("FFFF"));
DQN_UTEST_ASSERTF(&test, result == 0xFFFF, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0xFFFF, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert abCD") { DQN_UTEST_TEST("Convert abCD") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("abCD")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("abCD"));
DQN_UTEST_ASSERTF(&test, result == 0xabCD, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0xabCD, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert 0xabCD") { DQN_UTEST_TEST("Convert 0xabCD") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0xabCD")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0xabCD"));
DQN_UTEST_ASSERTF(&test, result == 0xabCD, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0xabCD, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert 0x") { DQN_UTEST_TEST("Convert 0x") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0x")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0x"));
DQN_UTEST_ASSERTF(&test, result == 0x0, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0x0, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert 0X") { DQN_UTEST_TEST("Convert 0X") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0X")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("0X"));
DQN_UTEST_ASSERTF(&test, result == 0x0, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0x0, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert 3") { DQN_UTEST_TEST("Convert 3") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("3")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("3"));
DQN_UTEST_ASSERTF(&test, result == 3, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 3, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert f") { DQN_UTEST_TEST("Convert f") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("f")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("f"));
DQN_UTEST_ASSERTF(&test, result == 0xf, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0xf, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert g") { DQN_UTEST_TEST("Convert g") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("g")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("g"));
DQN_UTEST_ASSERTF(&test, result == 0, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0, "result: %" PRIu64, result);
} }
DQN_UTEST_TEST("Convert -0x3") { DQN_UTEST_TEST("Convert -0x3") {
uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("-0x3")); uint64_t result = Dqn_Bin_HexToU64(DQN_STR8("-0x3"));
DQN_UTEST_ASSERTF(&test, result == 0, "result: %llu", result); DQN_UTEST_ASSERTF(&test, result == 0, "result: %" PRIu64, result);
} }
uint32_t number = 0xd095f6; uint32_t number = 0xd095f6;
@ -696,7 +703,7 @@ static Dqn_UTest Dqn_Test_FStr8()
static Dqn_UTest Dqn_Test_Fs() static Dqn_UTest Dqn_Test_Fs()
{ {
Dqn_UTest test = {}; Dqn_UTest test = {};
DQN_UTEST_GROUP(test, "Dqn_Fs") { DQN_UTEST_GROUP(test, "Dqn_OS_[Path|File]") {
DQN_UTEST_TEST("Make directory recursive \"abcd/efgh\"") { DQN_UTEST_TEST("Make directory recursive \"abcd/efgh\"") {
DQN_UTEST_ASSERTF(&test, Dqn_OS_MakeDir(DQN_STR8("abcd/efgh")), "Failed to make directory"); DQN_UTEST_ASSERTF(&test, Dqn_OS_MakeDir(DQN_STR8("abcd/efgh")), "Failed to make directory");
DQN_UTEST_ASSERTF(&test, Dqn_OS_DirExists(DQN_STR8("abcd")), "Directory was not made"); DQN_UTEST_ASSERTF(&test, Dqn_OS_DirExists(DQN_STR8("abcd")), "Directory was not made");
@ -829,7 +836,7 @@ static Dqn_UTest Dqn_Test_Intrinsics()
DQN_UTEST_TEST("Dqn_Atomic_AddU64") { DQN_UTEST_TEST("Dqn_Atomic_AddU64") {
uint64_t val = 0; uint64_t val = 0;
Dqn_Atomic_AddU64(&val, 1); Dqn_Atomic_AddU64(&val, 1);
DQN_UTEST_ASSERTF(&test, val == 1, "val: %llu", val); DQN_UTEST_ASSERTF(&test, val == 1, "val: %" PRIu64, val);
} }
DQN_UTEST_TEST("Dqn_Atomic_SubU32") { DQN_UTEST_TEST("Dqn_Atomic_SubU32") {
@ -841,7 +848,7 @@ static Dqn_UTest Dqn_Test_Intrinsics()
DQN_UTEST_TEST("Dqn_Atomic_SubU64") { DQN_UTEST_TEST("Dqn_Atomic_SubU64") {
uint64_t val = 1; uint64_t val = 1;
Dqn_Atomic_SubU64(&val, 1); Dqn_Atomic_SubU64(&val, 1);
DQN_UTEST_ASSERTF(&test, val == 0, "val: %llu", val); DQN_UTEST_ASSERTF(&test, val == 0, "val: %" PRIu64, val);
} }
DQN_UTEST_TEST("Dqn_Atomic_SetValue32") { DQN_UTEST_TEST("Dqn_Atomic_SetValue32") {
@ -855,7 +862,7 @@ static Dqn_UTest Dqn_Test_Intrinsics()
int64_t a = 0; int64_t a = 0;
int64_t b = 111; int64_t b = 111;
Dqn_Atomic_SetValue64(DQN_CAST(uint64_t *)&a, b); Dqn_Atomic_SetValue64(DQN_CAST(uint64_t *)&a, b);
DQN_UTEST_ASSERTF(&test, a == b, "a: %lld, b: %lld", a, b); DQN_UTEST_ASSERTF(&test, a == b, "a: %" PRId64 ", b: %" PRId64, a, b);
} }
Dqn_UTest_Begin(&test, "Dqn_CPU_TSC"); Dqn_UTest_Begin(&test, "Dqn_CPU_TSC");
@ -1216,7 +1223,7 @@ static Dqn_UTest Dqn_Test_OS()
DQN_UTEST_TEST("Consecutive ticks are ordered") { DQN_UTEST_TEST("Consecutive ticks are ordered") {
uint64_t a = Dqn_OS_PerfCounterNow(); uint64_t a = Dqn_OS_PerfCounterNow();
uint64_t b = Dqn_OS_PerfCounterNow(); uint64_t b = Dqn_OS_PerfCounterNow();
DQN_UTEST_ASSERTF(&test, b >= a, "a: %llu, b: %llu", a, b); DQN_UTEST_ASSERTF(&test, b >= a, "a: %" PRIu64 ", b: %" PRIu64, a, b);
} }
DQN_UTEST_TEST("Ticks to time are a correct order of magnitude") { DQN_UTEST_TEST("Ticks to time are a correct order of magnitude") {
@ -1561,55 +1568,55 @@ static Dqn_UTest Dqn_Test_Str8()
DQN_UTEST_TEST("To U64: Convert nullptr") { DQN_UTEST_TEST("To U64: Convert nullptr") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(Dqn_Str8_Init(nullptr, 5), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(Dqn_Str8_Init(nullptr, 5), 0);
DQN_UTEST_ASSERT(&test, result.success); DQN_UTEST_ASSERT(&test, result.success);
DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert empty string") { DQN_UTEST_TEST("To U64: Convert empty string") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8(""), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8(""), 0);
DQN_UTEST_ASSERT(&test, result.success); DQN_UTEST_ASSERT(&test, result.success);
DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"1\"") { DQN_UTEST_TEST("To U64: Convert \"1\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1"), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1"), 0);
DQN_UTEST_ASSERT(&test, result.success); DQN_UTEST_ASSERT(&test, result.success);
DQN_UTEST_ASSERTF(&test, result.value == 1, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 1, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"-0\"") { DQN_UTEST_TEST("To U64: Convert \"-0\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-0"), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-0"), 0);
DQN_UTEST_ASSERT(&test, !result.success); DQN_UTEST_ASSERT(&test, !result.success);
DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"-1\"") { DQN_UTEST_TEST("To U64: Convert \"-1\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-1"), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-1"), 0);
DQN_UTEST_ASSERT(&test, !result.success); DQN_UTEST_ASSERT(&test, !result.success);
DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 0, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"1.2\"") { DQN_UTEST_TEST("To U64: Convert \"1.2\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1.2"), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1.2"), 0);
DQN_UTEST_ASSERT(&test, !result.success); DQN_UTEST_ASSERT(&test, !result.success);
DQN_UTEST_ASSERTF(&test, result.value == 1, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 1, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"1,234\"") { DQN_UTEST_TEST("To U64: Convert \"1,234\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,234"), ','); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,234"), ',');
DQN_UTEST_ASSERT(&test, result.success); DQN_UTEST_ASSERT(&test, result.success);
DQN_UTEST_ASSERTF(&test, result.value == 1234, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 1234, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"1,2\"") { DQN_UTEST_TEST("To U64: Convert \"1,2\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,2"), ','); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,2"), ',');
DQN_UTEST_ASSERT(&test, result.success); DQN_UTEST_ASSERT(&test, result.success);
DQN_UTEST_ASSERTF(&test, result.value == 12, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 12, "result: %" PRIu64, result.value);
} }
DQN_UTEST_TEST("To U64: Convert \"12a3\"") { DQN_UTEST_TEST("To U64: Convert \"12a3\"") {
Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("12a3"), 0); Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("12a3"), 0);
DQN_UTEST_ASSERT(&test, !result.success); DQN_UTEST_ASSERT(&test, !result.success);
DQN_UTEST_ASSERTF(&test, result.value == 12, "result: %llu", result.value); DQN_UTEST_ASSERTF(&test, result.value == 12, "result: %" PRIu64, result.value);
} }
// NOTE: Dqn_Str8_Find // NOTE: Dqn_Str8_Find