From 3bca236a7413d09636009d3f2c169ce03f7aa9e3 Mon Sep 17 00:00:00 2001 From: doylet Date: Mon, 25 Mar 2024 16:11:57 +1100 Subject: [PATCH] Compile on Linux again, fix comment warning, implement output capture on exec on posix --- Standalone/dqn_keccak.h | 5 + Standalone/dqn_utest.h | 4 + build.sh | 14 +- dqn.h | 5 + dqn_allocator.cpp | 4 +- dqn_allocator.h | 4 + dqn_base.cpp | 49 +++-- dqn_base.h | 14 +- dqn_containers.cpp | 2 + dqn_containers.h | 2 + dqn_debug.cpp | 4 +- dqn_debug.h | 2 + dqn_docs.cpp | 6 +- dqn_external.cpp | 2 + dqn_external.h | 4 +- dqn_hash.cpp | 2 + dqn_hash.h | 2 + dqn_helpers.cpp | 2 + dqn_helpers.h | 2 + dqn_math.cpp | 2 + dqn_math.h | 2 + dqn_os.cpp | 10 +- dqn_os.h | 10 +- dqn_os_posix.cpp | 454 +++++++++++++++++++++++++++++----------- dqn_os_win32.cpp | 40 ++-- dqn_string.cpp | 2 + dqn_string.h | 4 + dqn_thread_context.cpp | 2 + dqn_thread_context.h | 2 + dqn_type_info.cpp | 31 +++ dqn_type_info.h | 17 +- dqn_unit_tests.cpp | 59 +++--- 32 files changed, 534 insertions(+), 230 deletions(-) create mode 100644 dqn_type_info.cpp diff --git a/Standalone/dqn_keccak.h b/Standalone/dqn_keccak.h index 72723b1..7d854fe 100644 --- a/Standalone/dqn_keccak.h +++ b/Standalone/dqn_keccak.h @@ -1,5 +1,7 @@ #if !defined(DQN_KECCAK_H) #define DQN_KECCAK_H + +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ @@ -64,6 +66,9 @@ // code of the header file. // // #define DQN_KECCAK_IMPLEMENTATION +// +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ #if !defined(DQN_KECCAK_MEMCPY) #include diff --git a/Standalone/dqn_utest.h b/Standalone/dqn_utest.h index 9524f9b..31eee1b 100644 --- a/Standalone/dqn_utest.h +++ b/Standalone/dqn_utest.h @@ -1,6 +1,7 @@ #if !defined(DQN_UTEST_H) #define DQN_UTEST_H +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$$\ @@ -45,6 +46,9 @@ // #define DQN_UTEST_GOOD_COLOR // Define this to a terminal color code to specify what color sucess will be // presented as. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: Macros //////////////////////////////////////////////////////////////////////////////////// #include diff --git a/build.sh b/build.sh index 4245489..c354a4e 100755 --- a/build.sh +++ b/build.sh @@ -1,8 +1,20 @@ #!/bin/bash +set -ex + code_dir=${PWD} mkdir -p 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 diff --git a/dqn.h b/dqn.h index cfff121..e954df6 100644 --- a/dqn.h +++ b/dqn.h @@ -1,6 +1,7 @@ #if !defined(DQN_H) #define DQN_H +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ $$$$$$\ $$\ $$\ @@ -207,6 +208,7 @@ // 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 // visible before this header. +*/ #if defined(DQN_ONLY_VARRAY) || \ defined(DQN_ONLY_SARRAY) || \ @@ -344,6 +346,7 @@ #endif // DQN_H #if defined(DQN_IMPLEMENTATION) +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // /$$$$$$\ $$\ $$\ $$$$$$$\ $$\ @@ -358,6 +361,7 @@ // Implementation // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ #if defined(DQN_WITH_CGEN) #if !defined(DQN_NO_METADESK) @@ -383,6 +387,7 @@ #include "dqn_debug.cpp" #include "dqn_string.cpp" #include "dqn_containers.cpp" +#include "dqn_type_info.cpp" #if defined(DQN_PLATFORM_EMSCRIPTEN) || defined(DQN_PLATFORM_POSIX) || defined(DQN_PLATFORM_ARM64) #include "dqn_os_posix.cpp" diff --git a/dqn_allocator.cpp b/dqn_allocator.cpp index ca4e810..d9caed5 100644 --- a/dqn_allocator.cpp +++ b/dqn_allocator.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ @@ -12,6 +13,7 @@ // dqn_allocator.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$AREN] Dqn_Arena ///////////////////////////////////////////////////////////////////////// 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) Dqn_usize dist_to_next_msb = __lzcnt64(required_size) + 1; #else - Dqn_usize dist_to_next_msb = __builtin_clz(required_size) + 1; + Dqn_usize dist_to_next_msb = __builtin_clzll(required_size) + 1; #endif // NOTE: Round up if not PoT as the low bits are set. diff --git a/dqn_allocator.h b/dqn_allocator.h index ec1c2bb..2cecff6 100644 --- a/dqn_allocator.h +++ b/dqn_allocator.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ @@ -17,6 +18,9 @@ // [$CHUN] Dqn_ChunkPool -- Allocates reusable, free-able memory in PoT chunks // [$ACAT] Dqn_ArenaCatalog -- Collate, create & manage arenas in a catalog // +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + // NOTE: [$AREN] Dqn_Arena ///////////////////////////////////////////////////////////////////////// #if !defined(DQN_ARENA_RESERVE_SIZE) #define DQN_ARENA_RESERVE_SIZE DQN_MEGABYTES(64) diff --git a/dqn_base.cpp b/dqn_base.cpp index 815dfac..2e54591 100644 --- a/dqn_base.cpp +++ b/dqn_base.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ @@ -12,6 +13,7 @@ // dqn_base.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$INTR] Intrinsics //////////////////////////////////////////////////////////////////////// #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_OSDateTimeStr8 const time = Dqn_OS_DateLocalTimeStr8Now(); Dqn_Str8 header = Dqn_Str8_InitF(arena, - "%.*s " // date - "%.*s " // hms - "%.*s" // colour - "%.*s" // bold - "%.*s" // type - "%*s" // type padding - "%.*s" // reset - " %.*s" // file name - ":%05I32u " // line number - , - DQN_CAST(int)time.date_size - 2, time.date + 2, // date - DQN_CAST(int)time.hms_size, time.hms, // hms - DQN_STR_FMT(colour_esc), // colour - DQN_STR_FMT(bold_esc), // bold - DQN_STR_FMT(type), // type - DQN_CAST(int)type_padding, "", // type padding - DQN_STR_FMT(reset_esc), // reset - DQN_STR_FMT(file_name), // file name - call_site.line); // line number + "%.*s " // date + "%.*s " // hms + "%.*s" // colour + "%.*s" // bold + "%.*s" // type + "%*s" // type padding + "%.*s" // reset + " %.*s" // file name + ":%05I32u " // line number + , + DQN_CAST(int)time.date_size - 2, time.date + 2, // date + DQN_CAST(int)time.hms_size, time.hms, // hms + DQN_STR_FMT(colour_esc), // colour + DQN_STR_FMT(bold_esc), // bold + DQN_STR_FMT(type), // type + DQN_CAST(int)type_padding, "", // type padding + DQN_STR_FMT(reset_esc), // reset + DQN_STR_FMT(file_name), // file name + call_site.line); // line number Dqn_usize header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetStr8.size; // NOTE: Header padding //////////////////////////////////////////////////////////////////////// @@ -332,9 +334,12 @@ DQN_API Dqn_Str8 Dqn_Log_MakeStr8(Dqn_Arena *arena, // NOTE: Construct final log /////////////////////////////////////////////////////////////////// Dqn_Str8 user_msg = Dqn_Str8_InitFV(arena, fmt, args); Dqn_Str8 result = Dqn_Str8_Alloc(arena, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No); - DQN_MEMCPY(result.data, header.data, header.size); - DQN_MEMSET(result.data + header.size, ' ', header_padding); - DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size); + if (Dqn_Str8_HasData(result)) { + DQN_MEMCPY(result.data, header.data, header.size); + DQN_MEMSET(result.data + header.size, ' ', header_padding); + if (Dqn_Str8_HasData(user_msg)) + DQN_MEMCPY(result.data + header.size + header_padding, user_msg.data, user_msg.size); + } return result; } diff --git a/dqn_base.h b/dqn_base.h index efd2baa..6aa3b53 100644 --- a/dqn_base.h +++ b/dqn_base.h @@ -1,4 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////////////////////////// +/* +/////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ // $$ __$$\ @@ -21,6 +22,9 @@ // [$PRIN] Dqn_Print -- Console printing // [$LLOG] Dqn_Log -- Console logging macros // +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + // NOTE: [$MACR] Macros //////////////////////////////////////////////////////////////////////////// #define DQN_STRINGIFY(x) #x #define DQN_TOKEN_COMBINE2(x, y) x ## y @@ -214,10 +218,10 @@ #define DQN_CHAR_COUNT(string) (sizeof(string) - 1) // NOTE: SI Byte /////////////////////////////////////////////////////////////////////////////////// -#define DQN_BYTES(val) (val) -#define DQN_KILOBYTES(val) (1024ULL * DQN_BYTES(val)) -#define DQN_MEGABYTES(val) (1024ULL * DQN_KILOBYTES(val)) -#define DQN_GIGABYTES(val) (1024ULL * DQN_MEGABYTES(val)) +#define DQN_BYTES(val) ((uint64_t)val) +#define DQN_KILOBYTES(val) ((uint64_t)1024 * DQN_BYTES(val)) +#define DQN_MEGABYTES(val) ((uint64_t)1024 * DQN_KILOBYTES(val)) +#define DQN_GIGABYTES(val) ((uint64_t)1024 * DQN_MEGABYTES(val)) // NOTE: Time ////////////////////////////////////////////////////////////////////////////////////// #define DQN_SECONDS_TO_MS(val) ((val) * 1000) diff --git a/dqn_containers.cpp b/dqn_containers.cpp index b8c0f46..7c6e00a 100644 --- a/dqn_containers.cpp +++ b/dqn_containers.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_containers.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$SLIC] Dqn_Slice ///////////////////////////////////////////////////////////////////////// DQN_API Dqn_Str8 Dqn_Slice_Str8Render(Dqn_Arena *arena, Dqn_Slice array, Dqn_Str8 separator) diff --git a/dqn_containers.h b/dqn_containers.h index 3cd73ba..41f15b1 100644 --- a/dqn_containers.h +++ b/dqn_containers.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ @@ -22,6 +23,7 @@ // [$LIST] Dqn_List -- DQN_LIST -- Chunked linked lists, append only // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$CARR] Dqn_CArray //////////////////////////////////////////////////////////////////////// enum Dqn_ArrayErase diff --git a/dqn_debug.cpp b/dqn_debug.cpp index 3785fd4..237bb33 100644 --- a/dqn_debug.cpp +++ b/dqn_debug.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_debug.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$ASAN] Dqn_Asan ////////////////////////////////////////////////////////////////////////// /// 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++) { raw_frame.base_addr = walk->base_addr[index]; 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"); } } diff --git a/dqn_debug.h b/dqn_debug.h index 4e17c9c..9b55592 100644 --- a/dqn_debug.h +++ b/dqn_debug.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ @@ -18,6 +19,7 @@ // [$DEBG] Dqn_Debug -- Allocation leak tracking API // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$ASAN] Dqn_Asan ////////////////////////////////////////////////////////////////////////// #if !defined(DQN_ASAN_POISON) diff --git a/dqn_docs.cpp b/dqn_docs.cpp index ee25610..02d6d17 100644 --- a/dqn_docs.cpp +++ b/dqn_docs.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ @@ -24,6 +25,7 @@ // and/or conciseness of being able to learn the breadth of the APIs. // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_DISABLE(4702) // unreachable code @@ -577,7 +579,7 @@ void Dqn_Docs_Demo() // Print the result like so if (0) { - printf("%.*s[%u] %llu cycles (%.1fms)\n", + printf("%.*s[%u] %" PRIu64 " cycles (%.1fms)\n", DQN_STR_FMT(anchor->name), anchor->hit_count, anchor->tsc_inclusive, @@ -691,7 +693,7 @@ void Dqn_Docs_Demo() // You may then print out the frame like so 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 diff --git a/dqn_external.cpp b/dqn_external.cpp index e5f6b16..80f53af 100644 --- a/dqn_external.cpp +++ b/dqn_external.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\ @@ -12,6 +13,7 @@ // dqn_external.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ #if !defined(DQN_USE_STD_PRINTF) && !defined(DQN_STB_SPRINTF_HEADER_ONLY) // NOTE: [$STBS] stb_sprintf /////////////////////////////////////////////////////////////////////// diff --git a/dqn_external.h b/dqn_external.h index 3f1b7c8..e4dca21 100644 --- a/dqn_external.h +++ b/dqn_external.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$$$\ $$$$$$$\ $$\ $$\ $$$$$$\ $$\ @@ -12,6 +13,7 @@ // dqn_external.h -- Third party dependencies // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$OS_H] OS Headers //////////////////////////////////////////////////////////////////////// #if !defined(DQN_OS_WIN32) || defined(DQN_OS_WIN32_USE_PTHREADS) @@ -56,7 +58,7 @@ #define DQN_VSNPRINTF(...) STB_SPRINTF_DECORATE(vsnprintf)(__VA_ARGS__) #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 // always true, however, reading past the end of a string whose size is not diff --git a/dqn_hash.cpp b/dqn_hash.cpp index 24023d7..fc10cf1 100644 --- a/dqn_hash.cpp +++ b/dqn_hash.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ @@ -12,6 +13,7 @@ // dqn_hash.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$FNV1] Dqn_FNV1A ///////////////////////////////////////////////////////////////////////// // Default values recommended by: http://isthe.com/chongo/tech/comp/fnv/ diff --git a/dqn_hash.h b/dqn_hash.h index 75ed240..7abc289 100644 --- a/dqn_hash.h +++ b/dqn_hash.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ @@ -17,6 +18,7 @@ // [$MMUR] Dqn_MurmurHash3 -- Hash(x) -> 32/128bit via MurmurHash3 // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$FNV1] Dqn_FNV1A ///////////////////////////////////////////////////////////////////////// #if !defined(DQN_FNV1A32_SEED) diff --git a/dqn_helpers.cpp b/dqn_helpers.cpp index c0a2ab6..cd25774 100644 --- a/dqn_helpers.cpp +++ b/dqn_helpers.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_helpers.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$PCGX] Dqn_PCG32 ///////////////////////////////////////////////////////////////////////// #define DQN_PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL diff --git a/dqn_helpers.h b/dqn_helpers.h index b48a451..ed732c7 100644 --- a/dqn_helpers.h +++ b/dqn_helpers.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$$$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ @@ -24,6 +25,7 @@ // [$PROF] Dqn_Profiler -- DQN_PROFILER -- Profiler that measures using a timestamp counter // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$PCGX] Dqn_PCG32 ///////////////////////////////////////////////////////////////////////// struct Dqn_PCG32 { uint64_t state; }; diff --git a/dqn_math.cpp b/dqn_math.cpp index fe2d475..f503301 100644 --- a/dqn_math.cpp +++ b/dqn_math.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\ @@ -12,6 +13,7 @@ // dqn_math.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ #if !defined(DQN_NO_V2) // NOTE: [$VEC2] Vector2 /////////////////////////////////////////////////////////////////////////// diff --git a/dqn_math.h b/dqn_math.h index 0978dcf..8c80bf3 100644 --- a/dqn_math.h +++ b/dqn_math.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$\ $$\ $$$$$$\ $$$$$$$$\ $$\ $$\ @@ -22,6 +23,7 @@ // [$MATH] Other -- // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_DISABLE(4201) // warning C4201: nonstandard extension used: nameless struct/union diff --git a/dqn_os.cpp b/dqn_os.cpp index 64db290..248be80 100644 --- a/dqn_os.cpp +++ b/dqn_os.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_os.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$DATE] Date ////////////////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Slice cmd_line, Dqn_Str8 working_dir, - uint8_t exec_flag, + uint8_t exec_flags, Dqn_Arena *arena, 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); return result; } -DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena) +DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena) { 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) { Dqn_ErrorSink_EndAndExitIfErrorF( error, diff --git a/dqn_os.h b/dqn_os.h index 220b3de..5b29ee6 100644 --- a/dqn_os.h +++ b/dqn_os.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$\ @@ -24,6 +25,7 @@ // [$HTTP] Dqn_OSHttp -- -- // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$OMEM] Dqn_OSMem ////////////////////////////////////////////////////////////////////////// enum Dqn_OSMemCommit @@ -184,12 +186,10 @@ struct Dqn_OSExecAsyncHandle uint32_t os_error_code; uint32_t exit_code; void *process; - #if defined(DQN_OS_WIN32) void *stdout_read; void *stdout_write; void *stderr_read; void *stderr_write; - #endif }; struct Dqn_OSExecResult @@ -364,9 +364,9 @@ DQN_API Dqn_Str8 Dqn_OS_PathConvertF (Dqn_Arena *arena // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// 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_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_ErrorSink *error); -DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena, Dqn_ErrorSink *error); -DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena); +DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_ErrorSink *error); +DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice 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 cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_Arena *arena); // NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// #if !defined(DQN_NO_SEMAPHORE) diff --git a/dqn_os_posix.cpp b/dqn_os_posix.cpp index c14635b..65d05e7 100644 --- a/dqn_os_posix.cpp +++ b/dqn_os_posix.cpp @@ -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) { 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) 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) result = nullptr; 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) return 0; - static Dqn_Str8 const ALIGNMENT_ERROR_MSG = - DQN_STR8("Page protection requires pointers to be page aligned because we " - "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(size, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data); + static Dqn_Str8 const ALIGNMENT_ERROR_MSG = DQN_STR8( + "Page protection requires pointers to be page aligned because we " + "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(size, g_dqn_library->os_page_size), "%s", ALIGNMENT_ERROR_MSG.data); unsigned long os_page_flags = Dqn_OS_MemConvertPageToOSFlags_(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 ////////////////////////////////////////////////////////////////////////////// DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow() { - Dqn_OSDateTime result = {}; + Dqn_OSDateTime result = {}; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -105,9 +111,9 @@ DQN_API Dqn_OSDateTime Dqn_OS_DateLocalTimeNow() result.minutes = time.tm_min; result.seconds = time.tm_sec; - result.day = DQN_CAST(uint8_t)time.tm_mday; - result.month = DQN_CAST(uint8_t)time.tm_mon + 1; - result.year = 1900 + DQN_CAST(int16_t)time.tm_year; + result.day = DQN_CAST(uint8_t) time.tm_mday; + result.month = DQN_CAST(uint8_t) time.tm_mon + 1; + result.year = 1900 + DQN_CAST(int16_t) time.tm_year; 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) { #if defined(DQN_PLATFORM_EMSCRIPTEN) - (void)buffer; (void)size; + (void)buffer; + (void)size; return false; #else if (!buffer || size < 0) @@ -144,13 +151,16 @@ DQN_API bool Dqn_OS_SecureRNGBytes(void *buffer, uint32_t size) return true; 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"); - // 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 uint32_t read_bytes = 0; 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); return true; #endif @@ -164,9 +174,9 @@ DQN_API Dqn_Str8 Dqn_OS_EXEPath(Dqn_Arena *arena) int required_size_wo_null_terminator = 0; for (int try_size = 128;; try_size *= 2) { - auto scoped_arena = Dqn_ArenaTempMemScope(arena); - char *try_buf = Dqn_Arena_NewArray(arena, char, try_size, Dqn_ZeroMem_No); - int bytes_written = readlink("/proc/self/exe", try_buf, try_size); + auto scoped_arena = Dqn_ArenaTempMemScope(arena); + char *try_buf = Dqn_Arena_NewArray(arena, char, try_size, Dqn_ZeroMem_No); + int bytes_written = readlink("/proc/self/exe", try_buf, try_size); if (bytes_written == -1) { // Failed, we're unable to determine the executable directory 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 // arena. Instead we just get the size and redo the call one last // 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; break; } @@ -192,7 +204,8 @@ DQN_API Dqn_Str8 Dqn_OS_EXEPath(Dqn_Arena *arena) if (required_size_wo_null_terminator) { 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; 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; // TODO(dqn): Seems linux does not support creation time via stat. We // 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; } @@ -281,7 +295,8 @@ DQN_API bool Dqn_OS_CopyFile(Dqn_Str8 src, Dqn_Str8 dest, bool overwrite, Dqn_Er strerror(error_code)); return result; } - DQN_DEFER { + DQN_DEFER + { 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)); return result; } - DQN_DEFER { + DQN_DEFER + { close(dest_fd); }; struct stat stat_existing; - int fstat_result = fstat(src_fd, &stat_existing); + int fstat_result = fstat(src_fd, &stat_existing); if (fstat_result == -1) { int error_code = errno; 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); result = (bytes_written == stat_existing.st_size); if (!result) { - int error_code = errno; - 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 bytes_written_str8 = Dqn_U64ToByteSizeStr8(scratch.arena, bytes_written, Dqn_U64ByteSizeType_Auto); + int error_code = errno; + 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 bytes_written_str8 = + Dqn_U64ToByteSizeStr8(scratch.arena, bytes_written, Dqn_U64ByteSizeType_Auto); Dqn_ErrorSink_MakeF(error, 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(dest), 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); if (unlink_result == -1) { int error_code = errno; - Dqn_ErrorSink_MakeF(error, - error_code, - "File '%.*s' was moved but failed to be unlinked from old location: (%d) %s", - DQN_STR_FMT(src), - error_code, - strerror(error_code)); + Dqn_ErrorSink_MakeF( + error, + error_code, + "File '%.*s' was moved but failed to be unlinked from old location: (%d) %s", + DQN_STR_FMT(src), + error_code, + strerror(error_code)); } } return result; @@ -378,10 +398,10 @@ DQN_API bool Dqn_OS_MakeDir(Dqn_Str8 path) Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); 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. 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); 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 // invalid. 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 { - 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 { - // 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; - } + // NOTE: There's nothing that exists at this path, we can + // create a directory here + path_indexes[path_indexes_size++] = DQN_CAST(uint16_t) index; } } } for (Dqn_usize index = path_indexes_size - 1; result && index < path_indexes_size; index--) { uint16_t path_index = path_indexes[index]; - 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; - if (index != 0) copy.data[path_index] = temp; + if (index != 0) + copy.data[path_index] = temp; } return result; } // 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 = {}; 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) { 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 return result; } @@ -456,32 +483,41 @@ DQN_API Dqn_OSFile Dqn_OS_FileOpen(Dqn_Str8 path, Dqn_OSFileOpen open_mode, uint FILE *handle = nullptr; switch (open_mode) { case Dqn_OSFileOpen_CreateAlways: handle = fopen(path.data, "w"); break; - case Dqn_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break; - case Dqn_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break; + case Dqn_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break; + case Dqn_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break; default: DQN_INVALID_CODE_PATH; break; } if (!handle) { // TODO(doyle): FileOpen flag to string 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; } fclose(handle); } char const *fopen_mode = nullptr; - if (access & Dqn_OSFileAccess_AppendOnly) { + if (access & Dqn_OSFileAccess_AppendOnly) fopen_mode = "a+"; - } else if (access & Dqn_OSFileAccess_Write) { + else if (access & Dqn_OSFileAccess_Write) fopen_mode = "w+"; - } else if (access & Dqn_OSFileAccess_Read) { + else if (access & Dqn_OSFileAccess_Read) fopen_mode = "r+"; - } FILE *handle = fopen(path.data, fopen_mode); if (!handle) { 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; } 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) return false; - if (fread(buffer, size, 1, DQN_CAST(FILE *)file->handle) != 1) { - Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); - Dqn_Str8 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)); + if (fread(buffer, size, 1, DQN_CAST(FILE *) file->handle) != 1) { + Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); + Dqn_Str8 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 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) 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) { - Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); - Dqn_Str8 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)); + Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); + Dqn_Str8 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; } @@ -520,7 +563,7 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file) { if (!file || !file->handle || file->error) return; - fclose(DQN_CAST(FILE *)file->handle); + fclose(DQN_CAST(FILE *) file->handle); *file = {}; } #endif // !defined(DQN_NO_OS_FILE_API) @@ -528,26 +571,39 @@ DQN_API void Dqn_OS_FileClose(Dqn_OSFile *file) // NOTE: [$EXEC] Dqn_OSExec //////////////////////////////////////////////////////////////////////// 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 = {}; - if (!handle.process || handle.os_error_code) { - result.os_error_code = handle.os_error_code; + if (!handle.process || handle.os_error_code || handle.exit_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; } - if (handle.exit_code) { - result.exit_code = handle.exit_code; - return result; - } +#if defined(DQN_PLATFORM_EMSCRIPTEN) + DQN_INVALID_CODE_PATHF("Unsupported operation"); +#endif - #if defined(DQN_PLATFORM_EMSCRIPTEN) - DQN_ASSERTF(false, "Unsupported operation"); - #else - static_assert(sizeof(pid_t) <= sizeof(handle.process), "We store the PID opaquely in a register sized pointer"); + static_assert(sizeof(pid_t) <= sizeof(handle.process), + "We store the PID opaquely in a register sized pointer"); pid_t process = {}; DQN_MEMCPY(&process, &handle.process, sizeof(process)); for (;;) { @@ -567,28 +623,143 @@ DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle) 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; } -DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn_Str8 working_dir) +DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice 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 = {}; if (cmd_line.size == 0) return result; - Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); - // TODO: This API will need to switch to an array of strings for unix + Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr); + 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(); if (child_pid < 0) { result.os_error_code = errno; 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 - 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) { result.exit_code = -1; return result; @@ -596,16 +767,20 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn for (Dqn_usize arg_index = 0; arg_index < cmd_line.size; 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 char *prev_working_dir = nullptr; - DQN_DEFER { + DQN_DEFER + { if (!prev_working_dir) return; - if (result.os_error_code == 0) - chdir(prev_working_dir); + if (result.os_error_code == 0) { + int chdir_result = chdir(prev_working_dir); + (void)chdir_result; + } free(prev_working_dir); }; @@ -619,12 +794,29 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn // NOTE: Execute the command. We reuse argv because the first arg, the // 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; 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)); return result; } @@ -633,8 +825,8 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn // NOTE: [$SEMA] Dqn_OSSemaphore /////////////////////////////////////////////////////////////////// DQN_API Dqn_OSSemaphore Dqn_OS_SemaphoreInit(uint32_t initial_count) { - Dqn_OSSemaphore result = {}; - int pshared = 0; // Share the semaphore across all threads in the process + Dqn_OSSemaphore result = {}; + int pshared = 0; // Share the semaphore across all threads in the process if (sem_init(&result.posix_handle, pshared, initial_count) == 0) result.posix_init = true; 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) { bool result = false; - if (semaphore) { + if (semaphore) result = semaphore->posix_init; - } 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 #else DQN_FOR_UINDEX(index, amount) - sem_post(&semaphore->posix_handle); + sem_post(&semaphore->posix_handle); #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 = {}; if (!Dqn_OS_SemaphoreIsValid(semaphore)) @@ -707,12 +899,10 @@ DQN_API Dqn_OSSemaphoreWaitResult Dqn_OS_SemaphoreWait(Dqn_OSSemaphore *semaphor struct timespec abs_timeout = {}; abs_timeout.tv_sec = timeout_ms / 1000; 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; - } else { - if (errno == ETIMEDOUT) - result = Dqn_OSSemaphoreWaitResult_Timeout; - } + else if (errno == ETIMEDOUT) + result = Dqn_OSSemaphoreWaitResult_Timeout; } return result; } @@ -755,7 +945,7 @@ DQN_API void Dqn_OS_MutexUnlock(Dqn_OSMutex *mutex) // NOTE: [$THRD] Dqn_OSThread ///////////////////////////////////////////////////////////////////// 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); thread->func(thread); return nullptr; @@ -789,7 +979,7 @@ DQN_API bool Dqn_OS_ThreadInit(Dqn_OSThread *thread, Dqn_OSThreadFunc *func, voi pthread_attr_destroy(&attribs); 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)); } @@ -821,7 +1011,7 @@ DQN_API uint32_t Dqn_OS_ThreadID() { pid_t result = gettid(); DQN_ASSERT(gettid() >= 0); - return DQN_CAST(uint32_t)result; + return DQN_CAST(uint32_t) result; } #endif // !defined(DQN_NO_THREAD) @@ -871,11 +1061,11 @@ static EM_BOOL EMWebSocketOnCloseCallback(int type, const EmscriptenWebSocketClo #if defined(DQN_PLATFORM_EMSCRIPTEN) 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)) 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); if (response->body.data) 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) { - Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *)fetch->userData; + Dqn_OSHttpResponse *response = DQN_CAST(Dqn_OSHttpResponse *) fetch->userData; if (!DQN_CHECK(response)) 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); if (response->body.size) 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) return; - response->arena = arena; - response->builder.arena = response->scratch_arena ? response->scratch_arena : &response->tmp_arena; + response->arena = arena; + response->builder.arena = + response->scratch_arena ? response->scratch_arena : &response->tmp_arena; Dqn_Arena *scratch_arena = response->scratch_arena; Dqn_Scratch scratch_ = Dqn_Scratch_Get(arena); if (!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_init(&fetch_attribs); if (method.size >= sizeof(fetch_attribs.requestMethod)) { - response->error_msg = Dqn_Str8_InitF(arena, - "Request method in EM has a size limit of 31 characters, method was '%.*s' which is %zu characters long", - DQN_STR_FMT(method), - 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; + response->error_msg = + Dqn_Str8_InitF(arena, + "Request method in EM has a size limit of 31 characters, method was " + "'%.*s' which is %zu characters long", + DQN_STR_FMT(method), + 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); return; } @@ -944,24 +1139,27 @@ DQN_API void Dqn_OS_HttpRequestAsync(Dqn_OSHttpResponse *response, fetch_attribs.onerror = Dqn_OS_HttpRequestEMFetchOnErrorCallback; fetch_attribs.userData = response; - 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_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)); response->on_complete_semaphore = Dqn_OS_SemaphoreInit(0); 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"); - #endif +#endif } DQN_API void Dqn_OS_HttpRequestFree(Dqn_OSHttpResponse *response) { - // NOTE: Cleanup - #if defined(DQN_PLATFORM_EMSCRIPTEN) +// NOTE: Cleanup +#if defined(DQN_PLATFORM_EMSCRIPTEN) if (response->em_handle) { emscripten_fetch_close(response->em_handle); response->em_handle = nullptr; } - #endif // #elif defined(DQN_OS_WIN32) +#endif // #elif defined(DQN_OS_WIN32) Dqn_Arena_Deinit(&response->tmp_arena); if (Dqn_OS_SemaphoreIsValid(&response->on_complete_semaphore)) diff --git a/dqn_os_win32.cpp b/dqn_os_win32.cpp index e88d108..9da28a9 100644 --- a/dqn_os_win32.cpp +++ b/dqn_os_win32.cpp @@ -633,7 +633,7 @@ DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle, Dqn_Arena return result; } -DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t flags, Dqn_ErrorSink *error) +DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn_Str8 working_dir, uint8_t exec_flags, Dqn_ErrorSink *error) { // NOTE: Pre-amble ///////////////////////////////////////////////////////////////////////////// Dqn_OSExecAsyncHandle result = {}; @@ -653,7 +653,14 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn // NOTE: Redirect stdout /////////////////////////////////////////////////////////////////////// HANDLE stdout_read = {}; 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)) { Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); result.os_error_code = win_error.code; @@ -666,13 +673,6 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn return result; } - DQN_DEFER { - if (result.os_error_code) { - CloseHandle(stdout_read); - CloseHandle(stdout_write); - } - }; - if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) { Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); result.os_error_code = win_error.code; @@ -689,8 +689,15 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn // NOTE: Redirect stderr /////////////////////////////////////////////////////////////////////// HANDLE stderr_read = {}; HANDLE stderr_write = {}; - if (flags & Dqn_OSExecFlag_SaveStderr) { - if (flags & Dqn_OSExecFlag_MergeStderrToStdout) { + DQN_DEFER { + 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_write = stdout_write; } else { @@ -706,13 +713,6 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn return result; } - DQN_DEFER { - if (result.os_error_code) { - CloseHandle(stderr_read); - CloseHandle(stderr_write); - } - }; - if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) { Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena); result.os_error_code = win_error.code; @@ -752,11 +752,11 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice cmd_line, Dqn result.process = proc_info.hProcess; result.stdout_read = stdout_read; 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_write = stderr_write; } - result.exec_flags = flags; + result.exec_flags = exec_flags; return result; } diff --git a/dqn_string.cpp b/dqn_string.cpp index 6cbcb00..a6eaee3 100644 --- a/dqn_string.cpp +++ b/dqn_string.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_string.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ // NOTE: [$CSTR] Dqn_CStr8 ///////////////////////////////////////////////////////////////////////// DQN_API Dqn_usize Dqn_CStr8_FSize(DQN_FMT_ATTRIB char const *fmt, ...) diff --git a/dqn_string.h b/dqn_string.h index d36bbaa..605719d 100644 --- a/dqn_string.h +++ b/dqn_string.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$\ $$$$$$$$\ $$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$\ @@ -20,6 +21,9 @@ // [$CHAR] Dqn_Char -- Character ascii/digit.. helpers // [$UTFX] Dqn_UTF -- Unicode helpers // +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + // NOTE: [$STR8] Dqn_Str8 ////////////////////////////////////////////////////////////////////////// struct Dqn_Str8Link { diff --git a/dqn_thread_context.cpp b/dqn_thread_context.cpp index 81c21af..54af773 100644 --- a/dqn_thread_context.cpp +++ b/dqn_thread_context.cpp @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ @@ -21,6 +22,7 @@ // dqn_thread_context.cpp // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ DQN_THREAD_LOCAL Dqn_ThreadContext g_dqn_thread_context; diff --git a/dqn_thread_context.h b/dqn_thread_context.h index f8c5669..5b12bd3 100644 --- a/dqn_thread_context.h +++ b/dqn_thread_context.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ @@ -21,6 +22,7 @@ // dqn_thread_context.h -- Per thread data (e.g. scratch arenas) // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ struct Dqn_ThreadContext { diff --git a/dqn_type_info.cpp b/dqn_type_info.cpp new file mode 100644 index 0000000..e346dc2 --- /dev/null +++ b/dqn_type_info.cpp @@ -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; +} diff --git a/dqn_type_info.h b/dqn_type_info.h index 2514977..7467f79 100644 --- a/dqn_type_info.h +++ b/dqn_type_info.h @@ -1,3 +1,4 @@ +/* //////////////////////////////////////////////////////////////////////////////////////////////////// // // $$$$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$$\ $$$$$$\ @@ -12,6 +13,7 @@ // dqn_type_info.h -- C++ type introspection // //////////////////////////////////////////////////////////////////////////////////////////////////// +*/ enum Dqn_TypeKind { @@ -51,17 +53,4 @@ struct Dqn_TypeGetField Dqn_TypeField *field; }; -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; -} +Dqn_TypeGetField Dqn_Type_GetField(Dqn_TypeInfo const *type_info, Dqn_Str8 name); diff --git a/dqn_unit_tests.cpp b/dqn_unit_tests.cpp index 7ef66f2..12cb5ec 100644 --- a/dqn_unit_tests.cpp +++ b/dqn_unit_tests.cpp @@ -1,6 +1,8 @@ #define DQN_UTEST_IMPLEMENTATION #include "Standalone/dqn_utest.h" +#include + static Dqn_UTest Dqn_Test_Arena() { Dqn_UTest test = {}; @@ -85,7 +87,12 @@ static Dqn_UTest Dqn_Test_Arena() } Dqn_Arena_TempMemEnd(temp_memory); 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; @@ -98,57 +105,57 @@ static Dqn_UTest Dqn_Test_Bin() DQN_UTEST_GROUP(test, "Dqn_Bin") { DQN_UTEST_TEST("Convert 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") { 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") { 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") { 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") { 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") { 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") { 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") { 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") { 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") { 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") { 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; @@ -696,7 +703,7 @@ static Dqn_UTest Dqn_Test_FStr8() static Dqn_UTest Dqn_Test_Fs() { 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_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"); @@ -829,7 +836,7 @@ static Dqn_UTest Dqn_Test_Intrinsics() DQN_UTEST_TEST("Dqn_Atomic_AddU64") { uint64_t val = 0; 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") { @@ -841,7 +848,7 @@ static Dqn_UTest Dqn_Test_Intrinsics() DQN_UTEST_TEST("Dqn_Atomic_SubU64") { uint64_t 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") { @@ -855,7 +862,7 @@ static Dqn_UTest Dqn_Test_Intrinsics() int64_t a = 0; int64_t b = 111; 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"); @@ -1216,7 +1223,7 @@ static Dqn_UTest Dqn_Test_OS() DQN_UTEST_TEST("Consecutive ticks are ordered") { uint64_t a = 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") { @@ -1561,55 +1568,55 @@ static Dqn_UTest Dqn_Test_Str8() DQN_UTEST_TEST("To U64: Convert nullptr") { Dqn_Str8ToU64Result result = Dqn_Str8_ToU64(Dqn_Str8_Init(nullptr, 5), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8(""), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1"), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-0"), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("-1"), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1.2"), 0); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,234"), ','); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("1,2"), ','); 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_Str8ToU64Result result = Dqn_Str8_ToU64(DQN_STR8("12a3"), 0); 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