From 916777c2b5dd212751175cbe5c079616067605fa Mon Sep 17 00:00:00 2001 From: Musa Mahmood Date: Sat, 29 Nov 2025 10:13:09 -0500 Subject: [PATCH] Refactoring, add basic file module (Win32) --- lib/Base/Allocator.cpp | 6 +- lib/Base/Arena.cpp | 2 +- lib/Base/Arena.h | 2 +- lib/Base/Array.h | 15 +- lib/Base/Base.h | 41 ++++- lib/Base/Base_Thread_Context.cpp | 33 +--- lib/Base/Base_Thread_Context.h | 4 +- lib/Base/Expandable_Arena.cpp | 2 +- lib/Base/Expandable_Arena.h | 2 +- lib/Base/General_Purpose_Allocator.cpp | 2 +- lib/Base/Logger.cpp | 31 +++- lib/Base/Logger.h | 6 +- lib/Base/String.cpp | 4 +- lib/Base/String.h | 2 +- lib/Base/Thread_Group.cpp | 4 +- lib/Base/Timing.h | 4 +- lib/OS/OS_Win32.cpp | 210 ++++++++++++++++++++++++- lib/OS/OS_Win32.h | 34 ++++ lib_main.cpp | 8 +- src/Base_Entry_Point.cpp | 14 +- 20 files changed, 354 insertions(+), 72 deletions(-) diff --git a/lib/Base/Allocator.cpp b/lib/Base/Allocator.cpp index 1f88362..0f0feee 100644 --- a/lib/Base/Allocator.cpp +++ b/lib/Base/Allocator.cpp @@ -1,18 +1,18 @@ void* internal_alloc (s64 size) { - Allocator allocator = get_context_allocator(); + Allocator allocator = context_allocator(); void* result = allocator.proc(Allocator_Mode::ALLOCATE, size, 0, nullptr, allocator.data); return result; } // #NOTE: internal_realloc does NOT copy anything! It just hands you new memory to work with! void* internal_realloc (void* memory, s64 size, s64 old_size) { - Allocator allocator = get_context_allocator(); + Allocator allocator = context_allocator(); void* result = allocator.proc(Allocator_Mode::RESIZE, size, old_size, memory, allocator.data); return result; } void internal_free (void* memory) { - Allocator allocator = get_context_allocator(); + Allocator allocator = context_allocator(); allocator.proc(Allocator_Mode::DEALLOCATE, 0, 0, memory, allocator.data); } diff --git a/lib/Base/Arena.cpp b/lib/Base/Arena.cpp index 3ef5a8a..f185ea6 100644 --- a/lib/Base/Arena.cpp +++ b/lib/Base/Arena.cpp @@ -204,6 +204,6 @@ s64 arena_usage_bytes (Arena* arena) { return (s64)(arena->current_point - arena s64 arena_usage_committed_bytes (Arena* arena) { return (s64)(arena->first_uncommitted_page - arena->memory_base); } // for arena details, I need to setup my string builder first. -Allocator get_allocator (Arena* arena) { +Allocator allocator (Arena* arena) { return { arena_allocator_proc, arena }; } diff --git a/lib/Base/Arena.h b/lib/Base/Arena.h index 213e304..e8946c2 100644 --- a/lib/Base/Arena.h +++ b/lib/Base/Arena.h @@ -105,7 +105,7 @@ s64 arena_usage_committed_bytes (Arena* arena); s64 reserve_size (Arena* arena); s64 reserve_size (Arena_Reserve ar); bool is_valid (Arena* arena); -Allocator get_allocator (Arena* arena); +Allocator allocator (Arena* arena); // Platform-Specific Implementations (forward-declared) void platform_init (Arena* arena, s64 new_reserve); diff --git a/lib/Base/Array.h b/lib/Base/Array.h index ab73669..ea85394 100644 --- a/lib/Base/Array.h +++ b/lib/Base/Array.h @@ -19,7 +19,7 @@ struct Array { // downcasts to an ArrayView. Array(s64 new_count, bool initialize=false) { // old: NewArray ::, array_new : count = new_count; - allocator = get_context_allocator(); + allocator = context_allocator(); data = NewArray(new_count, initialize); allocated = new_count; } @@ -29,7 +29,7 @@ struct Array { // downcasts to an ArrayView. count = new_count; data = (T*)new_data; allocated = _allocated; - allocator = get_context_allocator(); + allocator = context_allocator(); } Array(s64 new_count, void* new_data, s64 _allocated, Allocator _allocator) { @@ -124,7 +124,7 @@ void array_reserve (Array& src, s64 desired_items) { src.data = nullptr; if (src.allocator.proc == nullptr) { - src.allocator = get_context_allocator(); + src.allocator = context_allocator(); } Assert(src.allocator.proc != nullptr); @@ -249,7 +249,8 @@ struct ArrayView { s64 count; T* data; - ArrayView(Array array) { + // #TODO: Add initializers ArrayView from string, ArrayView from ArenaArray + ArrayView(Array array) { // auto-downcast from Array count = array.count; data = array.data; } @@ -266,7 +267,6 @@ struct ArrayView { count = _count; data = _data; } - T& operator[](s64 index) { #if ARRAY_ENABLE_BOUNDS_CHECKING if (index < 0 || index >= count) { debug_break(); } // index out of bounds @@ -275,6 +275,11 @@ struct ArrayView { } }; +template ArrayView to_byte_view (ArrayView src) { + ArrayView byte_view = { src.count * sizeof(T), src.data }; + return byte_view; +} + template bool is_empty (ArrayView src) { if (src.count == 0) return true; diff --git a/lib/Base/Base.h b/lib/Base/Base.h index 8989cf6..fee8ff2 100644 --- a/lib/Base/Base.h +++ b/lib/Base/Base.h @@ -188,7 +188,46 @@ force_inline s64 Next_Power_Of_Two(s64 v) { #define push_expandable_arena(x) \ Push_Expandable_Arena Concat(_push_ex_arena_guard_, __LINE__)(x) #define auto_release_temp() \ - auto_release(get_temp_allocator()); + auto_release(temp()); #define auto_release(x) \ Auto_Release Concat(_auto_release_guard_, __LINE__)(x) + +#define thread_context() thread_local_context +#define temp() allocator(thread_context()->temp) +#define context_allocator() thread_context()->allocator +#define context_logger() &thread_context()->logger + +// #TODO #constexpr #MATH - make these constexpr +/* +TAU :: cast(float32) 6.283185; +TAU64 :: 6.28318530717958648; + +PI :: cast(float32) 3.1415927; +PI64 :: 3.141592653589793; + +FLOAT16_MAX : float : 65504.0; + +FLOAT32_MIN :: 0h00800000; +FLOAT32_MAX :: 0h7F7FFFFF; +FLOAT32_INFINITY :: 0h7F800000; +FLOAT32_NAN :: 0h7FBFFFFF; + +FLOAT64_MIN :: 0h00100000_00000000; +FLOAT64_MAX :: 0h7FEFFFFF_FFFFFFFF; +FLOAT64_INFINITY :: 0h7FF00000_00000000; +FLOAT64_NAN :: 0h7FF7FFFF_FFFFFFFF; + +S8_MIN :s8: -128; +S8_MAX :s8: 127; +U8_MAX :u8: 255; +S16_MIN :s16: -32768; +S16_MAX :s16: 32767; +U16_MAX :u16: 0xffff; +S32_MIN :s32: 0x8000_0000; +S32_MAX :s32: 0x7fff_ffff; +U32_MAX :u32: 0xffff_ffff; +S64_MIN :s64: 0x8000_0000_0000_0000; +S64_MAX :s64: 0x7fff_ffff_ffff_ffff; +U64_MAX :u64: 0xffff_ffff_ffff_ffff; +*/ \ No newline at end of file diff --git a/lib/Base/Base_Thread_Context.cpp b/lib/Base/Base_Thread_Context.cpp index f693a13..9b2e285 100644 --- a/lib/Base/Base_Thread_Context.cpp +++ b/lib/Base/Base_Thread_Context.cpp @@ -14,10 +14,10 @@ internal void Bootstrap_Main_Thread_Context () { // #NewContext ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16); - thread_local_context = New(get_allocator(arena_ex)); + thread_local_context = New(allocator(arena_ex)); thread_local_context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16); thread_local_context->arena = arena_ex; - thread_local_context->allocator = get_allocator(arena_ex); + thread_local_context->allocator = allocator(arena_ex); thread_local_context->thread_idx = 0; thread_local_context->thread_name = "Main Thread"; thread_local_context->log_builder = new_string_builder(Arena_Reserve::Size_64M); @@ -32,18 +32,18 @@ struct Push_Arena { Push_Arena(ExpandableArena* arena_ex) { Assert(is_valid(arena_ex)); - context = get_thread_context(); + context = thread_context(); Assert(context != nullptr); original_allocator = context->allocator; - context->allocator = get_allocator(arena_ex); + context->allocator = allocator(arena_ex); } Push_Arena(Arena* arena) { Assert(is_valid(arena)); - context = get_thread_context(); + context = thread_context(); Assert(context != nullptr); original_allocator = context->allocator; - context->allocator = get_allocator(arena); + context->allocator = allocator(arena); } ~Push_Arena() { @@ -55,29 +55,12 @@ force_inline void set_thread_context (Thread_Context* new_context) { thread_local_context = new_context; } -Thread_Context* get_thread_context () { - return (Thread_Context*)thread_local_context; -} - -Logger* get_context_logger () { - return &get_thread_context()->logger; -} - -force_inline Allocator get_temp_allocator () { - return get_allocator(get_thread_context()->temp); -} - -force_inline Allocator get_context_allocator() { - Thread_Context* context = get_thread_context(); - return context->allocator; -} - void temp_reset_keeping_memory() { - Thread_Context* context = get_thread_context(); + Thread_Context* context = thread_context(); arena_reset(context->temp, false); } void temp_reset() { // alias: reset_temporary_storage. - Thread_Context* context = get_thread_context(); + Thread_Context* context = thread_context(); arena_reset(context->temp, true); } \ No newline at end of file diff --git a/lib/Base/Base_Thread_Context.h b/lib/Base/Base_Thread_Context.h index 8b241d6..db9104d 100644 --- a/lib/Base/Base_Thread_Context.h +++ b/lib/Base/Base_Thread_Context.h @@ -25,8 +25,6 @@ struct Thread_Context { // C_LINKAGE thread_static TCTX* tctx_thread_local; thread_static Thread_Context* thread_local_context; -Thread_Context* get_thread_context (); - // #TODO #NewContext void create_thread_context (Thread_Context** context, string thread_name, bool is_main_thread); internal void Bootstrap_Main_Thread_Context (); @@ -36,7 +34,7 @@ struct Push_Allocator { Allocator old_allocator; Push_Allocator (Allocator new_allocator) { - context = get_thread_context(); + context = thread_context(); old_allocator = context->allocator; context->allocator = new_allocator; } diff --git a/lib/Base/Expandable_Arena.cpp b/lib/Base/Expandable_Arena.cpp index 787d8ed..e331232 100644 --- a/lib/Base/Expandable_Arena.cpp +++ b/lib/Base/Expandable_Arena.cpp @@ -89,7 +89,7 @@ u8* expandable_arena_start (ExpandableArena* arena_ex) { return Align(arena_ex->memory_base + sizeof(ExpandableArena), ARENA_DEFAULT_ALIGNMENT); } -Allocator get_allocator (ExpandableArena* arena_ex) { +Allocator allocator (ExpandableArena* arena_ex) { return { expandable_arena_allocator_proc, arena_ex }; } diff --git a/lib/Base/Expandable_Arena.h b/lib/Base/Expandable_Arena.h index 13c34a2..b0e516f 100644 --- a/lib/Base/Expandable_Arena.h +++ b/lib/Base/Expandable_Arena.h @@ -23,6 +23,6 @@ void* expandable_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, bool is_valid (ExpandableArena* arena); void* expandable_arena_alloc (ExpandableArena* arena_ex, s64 byte_count); u8* expandable_arena_start (ExpandableArena* arena_ex); -Allocator get_allocator (ExpandableArena* arena_ex); +Allocator allocator (ExpandableArena* arena_ex); void arena_reset (ExpandableArena* arena_ex, bool free_extra_pages=true); force_inline void arena_delete (ExpandableArena* arena_ex); diff --git a/lib/Base/General_Purpose_Allocator.cpp b/lib/Base/General_Purpose_Allocator.cpp index d3a13cc..30bbe0c 100644 --- a/lib/Base/General_Purpose_Allocator.cpp +++ b/lib/Base/General_Purpose_Allocator.cpp @@ -145,7 +145,7 @@ Allocator GPAllocator () { void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data) { u16 alignment = 16; // default alignment - Thread_Context* tctx = get_thread_context(); + Thread_Context* tctx = thread_context(); if (tctx) alignment = tctx->GPAllocator_alignment; switch (mode) { diff --git a/lib/Base/Logger.cpp b/lib/Base/Logger.cpp index b1a8c6b..0682ab3 100644 --- a/lib/Base/Logger.cpp +++ b/lib/Base/Logger.cpp @@ -1,5 +1,5 @@ -void log (string fmt, ...) { - String_Builder* sb = get_thread_context()->log_builder; +void log_error (string fmt, ...) { + String_Builder* sb = thread_context()->log_builder; va_list args; va_start(args, fmt); @@ -15,13 +15,36 @@ void log (string fmt, ...) { string message = string_view(sb); - Logger* logger = get_context_logger(); + Logger* logger = context_logger(); + logger->proc(message, Log_Level::Error, logger->data); + + reset_string_builder(sb); +} + +void log (string fmt, ...) { + String_Builder* sb = thread_context()->log_builder; + + va_list args; + va_start(args, fmt); + print_to_builder(sb, fmt, args); + va_end(args); + + // Append newline if needed + string result = string_view(sb); + bool ends_with_newline = (result.data[result.count-1] == '\n'); + if (!ends_with_newline) { + append(sb, "\n"); + } + + string message = string_view(sb); + + Logger* logger = context_logger(); logger->proc(message, Log_Level::None, logger->data); reset_string_builder(sb); } void print (string message) { - Logger* logger = get_context_logger(); + Logger* logger = context_logger(); logger->proc(message, Log_Level::None, logger->data); } diff --git a/lib/Base/Logger.h b/lib/Base/Logger.h index 60f60ca..a193c7a 100644 --- a/lib/Base/Logger.h +++ b/lib/Base/Logger.h @@ -65,11 +65,7 @@ void default_logger_initialize() { #endif } -// more hacky forward declares -Logger* get_context_logger (); -Allocator get_temp_allocator (); -Allocator get_context_allocator (); - +void log_error (string fmt, ...); void log (string fmt, ...); void print (string message); diff --git a/lib/Base/String.cpp b/lib/Base/String.cpp index 99b05f8..4168faa 100644 --- a/lib/Base/String.cpp +++ b/lib/Base/String.cpp @@ -90,7 +90,9 @@ string wide_to_utf8 (u16* source, s32 length) { if (query_result <= 0) return { }; // Make room for a null terminator: - query_result += 1; + if (length != -1) { + query_result += 1; + } u8* memory = NewArray(query_result); diff --git a/lib/Base/String.h b/lib/Base/String.h index 238dc12..387e816 100644 --- a/lib/Base/String.h +++ b/lib/Base/String.h @@ -84,7 +84,7 @@ bool strings_match (string first_string, string second_string); // #Unicode // #TODO: Make a raw version that returns the raw pointer? -string wide_to_utf8 (u16* source, s32 length); +string wide_to_utf8 (u16* source, s32 length=-1); wstring utf8_to_wide (string source); string format_string (char* format, ...); diff --git a/lib/Base/Thread_Group.cpp b/lib/Base/Thread_Group.cpp index 2795c02..2709dc8 100644 --- a/lib/Base/Thread_Group.cpp +++ b/lib/Base/Thread_Group.cpp @@ -121,7 +121,7 @@ void init (Thread_Group* group, s32 group_thread_count, Thread_Group_Proc group_ bool enable_work_stealing = false) { // Set allocator if not already set: if (!group->allocator.proc) { - group->allocator = get_context_allocator(); + group->allocator = context_allocator(); } push_allocator(group->allocator); @@ -253,7 +253,7 @@ void add_work (Thread_Group* group, void* work) { ArrayView get_completed_work (Thread_Group* group) { Array results = Array(); - results.allocator = get_temp_allocator(); + results.allocator = temp(); push_allocator(group->allocator); diff --git a/lib/Base/Timing.h b/lib/Base/Timing.h index 8a5671a..67b39c6 100644 --- a/lib/Base/Timing.h +++ b/lib/Base/Timing.h @@ -85,7 +85,7 @@ struct timed_block_print { u64 tick_difference = end_tick - start_tick; f64 ticks_f64 = (f64)tick_difference; f64 elapsed_time_seconds = ticks_f64 / (f64)((s64)g_cpu_base_frequency_megahertz * 1000000); - push_allocator(get_temp_allocator()); + push_allocator(temp()); log("[Timed_Block %s]: %s (%s)", block_name.data, format_time_seconds(elapsed_time_seconds).data, format_cycles(tick_difference).data); } }; @@ -124,7 +124,7 @@ struct system_timed_block_print { ~system_timed_block_print() { f64 end_time = GetUnixTimestamp(); f64 elapsed_time_seconds = end_time - start_time; - push_allocator(get_temp_allocator()); + push_allocator(temp()); log("[Timed_Block %s]: %s", block_name.data, format_time_seconds(elapsed_time_seconds).data); } }; diff --git a/lib/OS/OS_Win32.cpp b/lib/OS/OS_Win32.cpp index c84eece..eb2fbb2 100644 --- a/lib/OS/OS_Win32.cpp +++ b/lib/OS/OS_Win32.cpp @@ -100,7 +100,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) { // } // } - push_arena(get_thread_context()->arena); + push_arena(thread_context()->arena); { OS_System_Info* info = &os_state_w32.system_info; info->logical_processor_count = (s32)sysinfo.dwNumberOfProcessors; @@ -166,7 +166,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) { { OS_Process_Info* info = &os_state_w32.process_info; DWORD length = GetCurrentDirectoryW(0, 0); // This can be freed later when we call temp_reset(); - u16* memory = NewArray(get_temp_allocator(), length + 1); + u16* memory = NewArray(temp(), length + 1); length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory); info->working_path = wide_to_utf8(memory, length); Assert(is_valid(info->working_path)); @@ -205,10 +205,10 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name= // #NewContext ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16); - thread->context = New(get_allocator(arena_ex)); + thread->context = New(allocator(arena_ex)); thread->context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16); thread->context->arena = arena_ex; - thread->context->allocator = get_allocator(arena_ex); + thread->context->allocator = allocator(arena_ex); thread->context->thread_idx = (s32)this_thread_index; thread->context->thread_name = copy_string(thread_name); thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M); @@ -302,6 +302,208 @@ internal void wake_all (Condition_Variable* cv) { WakeAllConditionVariable(&cv->condition_variable); } +internal string get_error_string (OS_Error_Code error_code) { + u16* lpMsgBuf; + bool success = (bool)FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPWSTR)&lpMsgBuf, 0, nullptr); + if (!success) { return ""; } + + push_allocator(temp()); + + string result = wide_to_utf8(lpMsgBuf); + + LocalFree(lpMsgBuf); + + return result; // trim_right(result, "\r\n"); +} + +internal bool file_is_valid (File file) { + if (file.handle == INVALID_HANDLE_VALUE) return false; + if (file.handle == 0) return false; + + return true; +} + +internal File file_open (string file_path, bool for_writing, bool keep_existing_content, bool log_errors) { + HANDLE handle; + + push_allocator(temp()); // for utf8 -> wide conversions: + + if (for_writing) { + u32 creation = (keep_existing_content) ? OPEN_ALWAYS : CREATE_ALWAYS; + handle = CreateFileW( + (LPCWSTR)utf8_to_wide(file_path).data, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_SHARE_READ, + nullptr, creation, 0, nullptr); + } else { + u32 creation = OPEN_EXISTING; + handle = CreateFileW( + (LPCWSTR)utf8_to_wide(file_path).data, + FILE_GENERIC_READ, + FILE_SHARE_READ, + nullptr, creation, 0, nullptr); + } + + if (handle == INVALID_HANDLE_VALUE && log_errors) { + OS_Error_Code error_code = GetLastError(); + log_error("Could not open file `%s`, code: %d, %s", file_path, error_code, get_error_string(error_code).data); + } + + File file; + file.handle = handle; + + return file; +} + +internal void file_close (File* file) { + CloseHandle(file->handle); +} + +internal bool file_read (File file, u8* data, s64 bytes_to_read_count, s64* bytes_read_count) { + // ignore bytes_read_count if null. + if (data == nullptr) { + log_error("file_read called with null destination pointer.\n"); + if (bytes_read_count) (*bytes_read_count) = 0; + return false; + } + if (bytes_to_read_count <= 0) { + if (bytes_read_count) (*bytes_read_count) = 0; + return false; + } + + bool read_success = false; + s64 total_read = 0; + + // loop to read more data than can be specified by the DWORD param ReadFile takes: + while (total_read < bytes_to_read_count) { + s64 remaining = bytes_to_read_count - total_read; + DWORD to_read; + if (remaining <= 0x7FFFFFFF) { + to_read = (DWORD)remaining; + } else { + to_read = 0x7FFFFFFF; // 2147483647 bytes ~2GB + } + + DWORD single_read_length = 0; + read_success = (bool)ReadFile(file.handle, data + total_read, to_read, &single_read_length, nullptr); + + total_read += single_read_length; + if (!read_success || single_read_length == 0) { + break; + } + } + + if (bytes_read_count) (*bytes_read_count) = total_read; + return read_success; +} + +internal bool file_length (File file, s64* length) { + if (length == nullptr) { + log_error("Calling file_length with null `length` param!"); + return false; + } + if (!file_is_valid(file)) { return false; } + s64 size; + bool success = (bool)GetFileSizeEx(file.handle, (PLARGE_INTEGER)&size); + + (*length) = size; + + return true; +} + +internal bool file_length (string file_path, s64* length) { + if (length == nullptr) { + log_error("Calling file_length with null `length` param!"); + return false; + } + File f = file_open(file_path); + + if (!file_is_valid(f)) { return false; } + bool success = file_length(f, length); + + return success; +} + +internal s64 file_current_position (File file) { + constexpr s64 invalid_file_position = -1; + if (!file_is_valid(file)) { return invalid_file_position; } + s64 offset = 0; + LARGE_INTEGER liDistanceToMove; + bool result = (bool)SetFilePointerEx(file.handle, liDistanceToMove, (PLARGE_INTEGER)&offset, FILE_CURRENT); + if (!result) { return invalid_file_position; } + return (s64)offset; +} + +internal bool file_set_position (File file, s64 position) { + if (!file_is_valid(file)) { return false; } + if (position < 0) { Assert(false); return false; } + + LARGE_INTEGER position_li; position_li.QuadPart = position; + return (bool)SetFilePointerEx(file.handle, position_li, nullptr, FILE_BEGIN); +} + +internal ArrayView read_entire_file (File file) { + ArrayView file_data; + + bool result = file_length(file, &file_data.count); + if (!result) return {}; + result = file_set_position(file, 0); + if (!result) return {}; + + file_data.data = NewArray(file_data.count, false); + if (file_data.data == nullptr) return {}; + + s64 bytes_read = 0; + result = file_read(file, file_data.data, file_data.count, &bytes_read); + if (!result) { + array_free(file_data); + return {}; + } + + Assert(bytes_read == file_data.count); + file_data.count = bytes_read; + + return file_data; +} + +internal ArrayView read_entire_file (string file_path, bool log_errors) { + File f = file_open(file_path, log_errors=log_errors); + if (!file_is_valid(f)) return {}; + + ArrayView file_data = read_entire_file(f); + + file_close(&f); + + return file_data; +} + +internal bool file_write (File* file, void* data, s64 length) { + // @incomplete - deal with inputs > 32 bits (>2GB) + u32 length_u32 = (u32)length; + Assert(length == length_u32); + + u32 bytes_written; + bool result = (bool)WriteFile(file->handle, data, length_u32, (LPDWORD)&bytes_written, nullptr); + + return result; +} + +internal bool write_entire_file (string file_path, void* file_data, s64 count) { + File f = file_open(file_path, true, false); + if (!file_is_valid(f)) return false; + + bool result = file_write(&f, file_data, count); + + file_close(&f); + return result; +} + +internal bool write_entire_file (string file_path, ArrayView file_data) { + return write_entire_file(file_path, file_data.data, file_data.count); +} + // #window_creation Window_Type create_window (string new_window_name) { return 0; diff --git a/lib/OS/OS_Win32.h b/lib/OS/OS_Win32.h index 3cfaca0..5ef8b45 100644 --- a/lib/OS/OS_Win32.h +++ b/lib/OS/OS_Win32.h @@ -5,6 +5,15 @@ struct Condition_Variable; struct Semaphore; struct Mutex; struct OS_Thread; +struct File { + HANDLE handle; +}; + +// struct File_Contents { +// File file = {}; +// ArrayView file_data = {}; +// bool read_success = false; +// }; enum class Wait_For_Result : s32 { SUCCESS = 0, @@ -28,5 +37,30 @@ internal void wait (Condition_Variable* cv, Mutex* mutex, s32 wait_time_ms = -1) internal void wake (Condition_Variable* cv); internal void wake_all (Condition_Variable* cv); +typedef u32 OS_Error_Code; +internal string get_error_string (OS_Error_Code error_code); + +internal bool file_is_valid (File file); +internal File file_open (string file_path, bool for_writing=false, bool keep_existing_content=false, bool log_errors=false); +internal void file_close (File* file); +internal bool file_read (File file, void* data, s64 bytes_to_read_count, s64* bytes_read_count=nullptr); +internal bool file_length (File file, s64* length); +internal bool file_length (string file_path, s64* length); +internal s64 file_current_position (File file); +internal bool file_set_position (File file, s64 position); +internal ArrayView read_entire_file (File file); +internal ArrayView read_entire_file (string file_path, bool log_errors=false); + +// use to_byte_view to convert ArrayView to ArrayView +internal bool file_write (File* file, void* data, s64 length); +internal bool write_entire_file (string file_path, void* file_data, s64 count); +internal bool write_entire_file (string file_path, ArrayView file_data); + +// file_write +// write_entire_file... + +// #TODO #fs File System Operations +// file_move, file_delete + // #window_creation typedef HWND Window_Type; diff --git a/lib_main.cpp b/lib_main.cpp index cfe40bc..9ad88cd 100644 --- a/lib_main.cpp +++ b/lib_main.cpp @@ -12,13 +12,13 @@ #include "lib/Base/Array.h" #include "lib/Base/General_Purpose_Allocator.h" -#if OS_WINDOWS -# include "lib/OS/OS_Win32.h" -#endif #include "lib/Base/Arena.h" #include "lib/Base/Arena_Array.h" #include "lib/Base/String.h" +#if OS_WINDOWS +# include "lib/OS/OS_Win32.h" +#endif #include "lib/Base/Logger.h" #include "lib/Base/String.cpp" @@ -27,9 +27,9 @@ #include "lib/Base/ErrorType.cpp" #include "lib/Base/Base_Thread_Context.h" +#include "lib/Base/Expandable_Arena.h" #include "lib/Base/Timing.h" #include "lib/Base/Arena_Table.cpp" -#include "lib/Base/Expandable_Arena.h" #include "lib/Base/Arena.cpp" diff --git a/src/Base_Entry_Point.cpp b/src/Base_Entry_Point.cpp index 82749a3..71b94b0 100644 --- a/src/Base_Entry_Point.cpp +++ b/src/Base_Entry_Point.cpp @@ -197,8 +197,8 @@ internal void Main_Entry_Point (int argc, WCHAR **argv) { // See: main_thread_base_entry_point { Timed_Block_Print("string_builder_testing"); temp_reset(); - push_allocator(get_temp_allocator()); - // tip: use auto_reset or auto_release with `get_thread_context()->arena` + push_allocator(temp()); + // tip: use auto_reset or auto_release with `thread_context()->arena` // String builder example: // OK. I can work with this. @@ -223,11 +223,11 @@ internal void Main_Entry_Point (int argc, WCHAR **argv) { print("Hello, I am just a printed message to stdout\n\n"); } - { string s = "hello I am cool"; - wstring sw = utf8_to_wide(s); - printf("testing operator overload: %d\n", !s); - printf("testing utf8_to_wide: %ls\n", sw.data); - } + // { string s = "hello I am cool"; + // wstring sw = utf8_to_wide(s); + // printf("testing operator overload: %d\n", !s); + // printf("testing utf8_to_wide: %ls\n", (wchar_t*)sw.data); + // } // debug_break(); // ImGui_Application();