initial upload

This commit is contained in:
Ryan Fleury
2024-01-10 19:53:18 -08:00
commit a42ec6aeff
308 changed files with 162362 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+88
View File
@@ -0,0 +1,88 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef LINUX_H
#define LINUX_H
////////////////////////////////
//~ NOTE(allen): Get all these linux includes
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <time.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <signal.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/sysinfo.h>
////////////////////////////////
//~ NOTE(allen): File Iterator
struct LNX_FileIter{
int fd;
DIR *dir;
};
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(LNX_FileIter), file_iter_memory_size);
////////////////////////////////
//~ NOTE(allen): Threading Entities
enum LNX_EntityKind{
LNX_EntityKind_Null,
LNX_EntityKind_Thread,
LNX_EntityKind_Mutex,
LNX_EntityKind_ConditionVariable,
};
struct LNX_Entity{
LNX_Entity *next;
LNX_EntityKind kind;
volatile U32 reference_mask;
union{
struct{
OS_ThreadFunctionType *func;
void *ptr;
pthread_t handle;
} thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
};
////////////////////////////////
//~ NOTE(allen): Safe Call Chain
struct LNX_SafeCallChain{
LNX_SafeCallChain *next;
OS_ThreadFunctionType *fail_handler;
void *ptr;
};
////////////////////////////////
//~ NOTE(allen): Helpers
internal B32 lnx_write_list_to_file_descriptor(int fd, String8List list);
internal void lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec);
internal void lnx_tm_from_date_time(struct tm *out, DateTime *in);
internal void lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in);
internal void lnx_file_properties_from_stat(FileProperties *out, struct stat *in);
internal String8 lnx_string_from_signal(int signum);
internal String8 lnx_string_from_errno(int error_number);
internal LNX_Entity* lnx_alloc_entity(LNX_EntityKind kind);
internal void lnx_free_entity(LNX_Entity *entity);
internal void* lnx_thread_base(void *ptr);
internal void lnx_safe_call_sig_handler(int);
#endif //LINUX_H
+265
View File
@@ -0,0 +1,265 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
internal OS_Handle
os_handle_zero(void)
{
OS_Handle handle = {0};
return handle;
}
internal B32
os_handle_match(OS_Handle a, OS_Handle b)
{
return a.u64[0] == b.u64[0];
}
internal void
os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle)
{
OS_HandleNode *n = push_array(arena, OS_HandleNode, 1);
n->v = handle;
SLLQueuePush(handles->first, handles->last, n);
handles->count += 1;
}
internal OS_HandleArray
os_handle_array_from_list(Arena *arena, OS_HandleList *list)
{
OS_HandleArray result = {0};
result.count = list->count;
result.v = push_array_no_zero(arena, OS_Handle, result.count);
U64 idx = 0;
for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
{
result.v[idx] = n->v;
}
return result;
}
////////////////////////////////
//~ rjf: System Path Helper (Helper, Implemented Once)
internal String8
os_string_from_system_path(Arena *arena, OS_SystemPath path)
{
String8List strs = {0};
os_string_list_from_system_path(arena, path, &strs);
String8 result = str8_list_first(&strs);
return result;
}
////////////////////////////////
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal String8List
os_string_list_from_argcv(Arena *arena, int argc, char **argv)
{
String8List result = {0};
for(int i = 0; i < argc; i += 1)
{
String8 str = str8_cstring(argv[i]);
str8_list_push(arena, &result, str);
}
return result;
}
////////////////////////////////
//~ rjf: Process Helpers (Helper, Implemented Once)
internal void
os_relaunch_self(void){
Temp scratch = scratch_begin(0, 0);
OS_LaunchOptions opts = {0};
opts.cmd_line = os_get_command_line_arguments();
opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Initial);
os_launch_process(&opts, 0);
scratch_end(scratch);
}
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8
os_data_from_file_path(Arena *arena, String8 path)
{
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path);
FileProperties props = os_properties_from_file(file);
String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size));
os_file_close(file);
return data;
}
internal B32
os_write_data_to_file_path(String8 path, String8 data)
{
B32 good = 0;
OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
if(!os_handle_match(file, os_handle_zero()))
{
good = 1;
os_file_write(file, r1u64(0, data.size), data.str);
os_file_close(file);
}
return good;
}
internal B32
os_write_data_list_to_file_path(String8 path, String8List list)
{
B32 good = 0;
OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
if(!os_handle_match(file, os_handle_zero()))
{
good = 1;
U64 off = 0;
for(String8Node *n = list.first; n != 0; n = n->next)
{
os_file_write(file, r1u64(off, off+n->string.size), n->string.str);
off += n->string.size;
}
os_file_close(file);
}
return good;
}
internal FileProperties
os_properties_from_file_path(String8 path)
{
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path);
FileProperties props = os_properties_from_file(file);
os_file_close(file);
return props;
}
internal OS_FileID
os_id_from_file_path(String8 path)
{
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Shared, path);
OS_FileID id = os_id_from_file(file);
os_file_close(file);
return id;
}
internal S64
os_file_id_compare(OS_FileID a, OS_FileID b)
{
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
return cmp;
}
internal String8
os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range)
{
U64 pre_pos = arena_pos(arena);
String8 result;
result.size = dim_1u64(range);
result.str = push_array_no_zero(arena, U8, result.size);
U64 actual_read_size = os_file_read(file, range, result.str);
if(actual_read_size < result.size)
{
arena_pop_to(arena, pre_pos + actual_read_size);
result.size = actual_read_size;
}
return result;
}
////////////////////////////////
//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once)
internal void
os_mutex_take(OS_Handle mutex){
ProfBeginLockWait((void *)(mutex.u64[0]), "take mutex");
os_mutex_take_(mutex);
ProfEndLockWait();
ProfLockTake((void *)(mutex.u64[0]), "take mutex");
}
internal void
os_mutex_drop(OS_Handle mutex){
os_mutex_drop_(mutex);
ProfLockDrop((void *)(mutex.u64[0]));
}
internal void
os_rw_mutex_take_r(OS_Handle rw_mutex){
ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take r");
os_rw_mutex_take_r_(rw_mutex);
ProfEndLockWait();
ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take r");
}
internal void
os_rw_mutex_drop_r(OS_Handle rw_mutex){
os_rw_mutex_drop_r_(rw_mutex);
ProfLockDrop((void *)(rw_mutex.u64[0]));
}
internal void
os_rw_mutex_take_w(OS_Handle rw_mutex){
ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take rw");
os_rw_mutex_take_w_(rw_mutex);
ProfEndLockWait();
ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take rw");
}
internal void
os_rw_mutex_drop_w(OS_Handle rw_mutex){
os_rw_mutex_drop_w_(rw_mutex);
ProfLockDrop((void *)(rw_mutex.u64[0]));
}
internal B32
os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us){
ProfLockDrop((void *)(mutex.u64[0]));
B32 result = os_condition_variable_wait_(cv, mutex, endt_us);
ProfLockTake((void *)(mutex.u64[0]), "wait cv");
return(result);
}
internal B32
os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){
ProfLockDrop((void *)(mutex_rw.u64[0]));
B32 result = os_condition_variable_wait_rw_r_(cv, mutex_rw, endt_us);
ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw r");
return(result);
}
internal B32
os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){
ProfLockDrop((void *)(mutex_rw.u64[0]));
B32 result = os_condition_variable_wait_rw_w_(cv, mutex_rw, endt_us);
ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw w");
return(result);
}
internal void
os_condition_variable_signal(OS_Handle cv){
os_condition_variable_signal_(cv);
}
internal void
os_condition_variable_broadcast(OS_Handle cv){
os_condition_variable_broadcast_(cv);
}
internal String8
os_string_from_guid(Arena *arena, OS_Guid guid)
{
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]);
return result;
}
+365
View File
@@ -0,0 +1,365 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_CORE_H
#define OS_CORE_H
////////////////////////////////
//~ rjf: Access Flags
typedef U32 OS_AccessFlags;
enum
{
OS_AccessFlag_Read = (1<<0),
OS_AccessFlag_Write = (1<<1),
OS_AccessFlag_Execute = (1<<2),
OS_AccessFlag_Shared = (1<<3),
};
////////////////////////////////
//~ allen: Files
typedef U32 OS_FileIterFlags;
enum
{
OS_FileIterFlag_SkipFolders = (1 << 0),
OS_FileIterFlag_SkipFiles = (1 << 1),
OS_FileIterFlag_SkipHiddenFiles = (1 << 2),
OS_FileIterFlag_Done = (1 << 31),
};
typedef struct OS_FileIter OS_FileIter;
struct OS_FileIter
{
OS_FileIterFlags flags;
U8 memory[600];
};
typedef struct OS_FileInfo OS_FileInfo;
struct OS_FileInfo
{
String8 name;
FileProperties props;
};
// nick: on-disk file identifier
typedef struct OS_FileID OS_FileID;
struct OS_FileID
{
U64 v[3];
};
////////////////////////////////
//~ rjf: System Paths
typedef enum OS_SystemPath
{
OS_SystemPath_Binary,
OS_SystemPath_Initial,
OS_SystemPath_Current,
OS_SystemPath_UserProgramData,
OS_SystemPath_ModuleLoad,
}
OS_SystemPath;
typedef enum OS_PathFromUserKind
{
OS_PathFromUserKind_Save,
OS_PathFromUserKind_Load,
}
OS_PathFromUserKind;
typedef struct OS_PathFromUser OS_PathFromUser;
struct OS_PathFromUser
{
OS_PathFromUserKind kind;
String8 path;
U64 filter_count;
String8 *filter_extensions;
String8 *filter_names;
};
////////////////////////////////
//~ allen: Launch Input
typedef struct OS_LaunchOptions OS_LaunchOptions;
struct OS_LaunchOptions
{
String8List cmd_line;
String8 path;
String8List env;
B32 inherit_env;
B32 consoleless;
};
////////////////////////////////
//~ rjf: Handle Type
typedef struct OS_Handle OS_Handle;
struct OS_Handle
{
U64 u64[1];
};
typedef struct OS_HandleNode OS_HandleNode;
struct OS_HandleNode
{
OS_HandleNode *next;
OS_Handle v;
};
typedef struct OS_HandleList OS_HandleList;
struct OS_HandleList
{
OS_HandleNode *first;
OS_HandleNode *last;
U64 count;
};
typedef struct OS_HandleArray OS_HandleArray;
struct OS_HandleArray
{
OS_Handle *v;
U64 count;
};
////////////////////////////////
// Time
#define OS_UNIX_TIME_MAX max_U32
typedef U32 OS_UnixTime;
////////////////////////////////
// Global Unique ID
typedef struct OS_Guid
{
U32 data1;
U16 data2;
U16 data3;
U8 data4[8];
} OS_Guid;
StaticAssert(sizeof(OS_Guid) == 16, os_guid_check);
////////////////////////////////
//~ rjf: Thread Types
typedef void OS_ThreadFunctionType(void *ptr);
////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
internal OS_Handle os_handle_zero(void);
internal B32 os_handle_match(OS_Handle a, OS_Handle b);
internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle);
internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list);
////////////////////////////////
//~ rjf: System Path Helper (Helper, Implemented Once)
internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path);
////////////////////////////////
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
////////////////////////////////
//~ rjf: Process Helpers (Helper, Implemented Once)
internal void os_relaunch_self(void);
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8 os_data_from_file_path(Arena *arena, String8 path);
internal B32 os_write_data_to_file_path(String8 path, String8 data);
internal B32 os_write_data_list_to_file_path(String8 path, String8List list);
internal FileProperties os_properties_from_file_path(String8 path);
internal OS_FileID os_id_from_file_path(String8 path);
internal S64 os_file_id_compare(OS_FileID a, OS_FileID b);
internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range);
////////////////////////////////
//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once)
internal void os_mutex_take(OS_Handle mutex);
internal void os_mutex_drop(OS_Handle mutex);
internal void os_rw_mutex_take_r(OS_Handle rw_mutex);
internal void os_rw_mutex_drop_r(OS_Handle rw_mutex);
internal void os_rw_mutex_take_w(OS_Handle rw_mutex);
internal void os_rw_mutex_drop_w(OS_Handle rw_mutex);
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us);
internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us);
internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us);
internal void os_condition_variable_signal(OS_Handle cv);
internal void os_condition_variable_broadcast(OS_Handle cv);
#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex))
#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex))
#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex))
////////////////////////////////
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
internal void os_init(int argc, char **argv);
////////////////////////////////
//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS)
internal void* os_reserve(U64 size);
internal B32 os_commit(void *ptr, U64 size);
internal void* os_reserve_large(U64 size);
internal B32 os_commit_large(void *ptr, U64 size);
internal void os_decommit(void *ptr, U64 size);
internal void os_release(void *ptr, U64 size);
internal B32 os_set_large_pages(B32 flag);
internal B32 os_large_pages_enabled(void);
internal U64 os_large_page_size(void);
internal void* os_alloc_ring_buffer(U64 size, U64 *actual_size_out);
internal void os_free_ring_buffer(void *ring_buffer, U64 actual_size);
////////////////////////////////
//~ rjf: @os_hooks System Info (Implemented Per-OS)
internal String8 os_machine_name(void);
internal U64 os_page_size(void);
internal U64 os_allocation_granularity(void);
internal U64 os_logical_core_count(void);
////////////////////////////////
//~ rjf: @os_hooks Process Info (Implemented Per-OS)
internal String8List os_get_command_line_arguments(void);
internal S32 os_get_pid(void);
internal S32 os_get_tid(void);
internal String8List os_get_environment(void);
internal U64 os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out);
////////////////////////////////
//~ rjf: @os_hooks Process Control (Implemented Per-OS)
internal void os_exit_process(S32 exit_code);
////////////////////////////////
//~ rjf: @os_hooks File System (Implemented Per-OS)
//- rjf: files
internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path);
internal void os_file_close(OS_Handle file);
internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data);
internal void os_file_write(OS_Handle file, Rng1U64 rng, void *data);
internal B32 os_file_set_times(OS_Handle file, DateTime time);
internal FileProperties os_properties_from_file(OS_Handle file);
internal OS_FileID os_id_from_file(OS_Handle file);
internal B32 os_delete_file_at_path(String8 path);
internal B32 os_copy_file_path(String8 dst, String8 src);
internal String8 os_full_path_from_path(Arena *arena, String8 path);
internal B32 os_file_path_exists(String8 path);
//- rjf: file maps
internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file);
internal void os_file_map_close(OS_Handle map);
internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range);
internal void os_file_map_view_close(OS_Handle map, void *ptr);
//- rjf: directory iteration
internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags);
internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out);
internal void os_file_iter_end(OS_FileIter *iter);
//- rjf: directory creation
internal B32 os_make_directory(String8 path);
////////////////////////////////
//~ rjf: @os_hooks Shared Memory (Implemented Per-OS)
internal OS_Handle os_shared_memory_alloc(U64 size, String8 name);
internal OS_Handle os_shared_memory_open(String8 name);
internal void os_shared_memory_close(OS_Handle handle);
internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range);
internal void os_shared_memory_view_close(OS_Handle handle, void *ptr);
////////////////////////////////
//~ rjf: @os_hooks Time (Implemented Per-OS)
internal OS_UnixTime os_now_unix(void);
internal DateTime os_now_universal_time(void);
internal DateTime os_universal_time_from_local_time(DateTime *local_time);
internal DateTime os_local_time_from_universal_time(DateTime *universal_time);
internal U64 os_now_microseconds(void);
internal void os_sleep_milliseconds(U32 msec);
////////////////////////////////
//~ rjf: @os_hooks Child Processes (Implemented Per-OS)
internal B32 os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out);
internal B32 os_process_wait(OS_Handle handle, U64 endt_us);
internal void os_process_release_handle(OS_Handle handle);
////////////////////////////////
//~ rjf: @os_hooks Threads (Implemented Per-OS)
internal OS_Handle os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params);
internal void os_release_thread_handle(OS_Handle thread);
////////////////////////////////
//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS)
// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting
// on a single thread
//- rjf: recursive mutexes
internal OS_Handle os_mutex_alloc(void);
internal void os_mutex_release(OS_Handle mutex);
internal void os_mutex_take_(OS_Handle mutex);
internal void os_mutex_drop_(OS_Handle mutex);
//- rjf: reader/writer mutexes
internal OS_Handle os_rw_mutex_alloc(void);
internal void os_rw_mutex_release(OS_Handle rw_mutex);
internal void os_rw_mutex_take_r_(OS_Handle mutex);
internal void os_rw_mutex_drop_r_(OS_Handle mutex);
internal void os_rw_mutex_take_w_(OS_Handle mutex);
internal void os_rw_mutex_drop_w_(OS_Handle mutex);
//- rjf: condition variables
internal OS_Handle os_condition_variable_alloc(void);
internal void os_condition_variable_release(OS_Handle cv);
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
internal B32 os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us);
internal B32 os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
internal B32 os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
internal void os_condition_variable_signal_(OS_Handle cv);
internal void os_condition_variable_broadcast_(OS_Handle cv);
//- rjf: cross-process semaphores
internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
internal void os_semaphore_release(OS_Handle semaphore);
internal OS_Handle os_semaphore_open(String8 name);
internal void os_semaphore_close(OS_Handle semaphore);
internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us);
internal void os_semaphore_drop(OS_Handle semaphore);
////////////////////////////////
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
internal OS_Handle os_library_open(String8 path);
internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name);
internal void os_library_close(OS_Handle lib);
////////////////////////////////
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr);
////////////////////////////////
//~ rjf: @os_hooks GUIDs (Implemented Per-OS)
internal OS_Guid os_make_guid(void);
internal String8 os_string_from_guid(Arena *arena, OS_Guid guid);
#endif // OS_CORE_H
File diff suppressed because it is too large Load Diff
+91
View File
@@ -0,0 +1,91 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_H
#define WIN32_H
////////////////////////////////
//~ NOTE(allen): Negotiate the windows header include order
#if OS_FEATURE_SOCKET
#include <WinSock2.h>
#endif
#include <Windows.h>
#include <Shlobj.h>
#if OS_FEATURE_GRAPHICAL
#include <shellscalingapi.h>
#endif
#if OS_FEATURE_SOCKET
#include <WS2tcpip.h>
#include <Mswsock.h>
#endif
#include <processthreadsapi.h>
////////////////////////////////
//~ NOTE(allen): File Iterator
typedef struct W32_FileIter W32_FileIter;
struct W32_FileIter
{
HANDLE handle;
WIN32_FIND_DATAW find_data;
};
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(W32_FileIter), file_iter_memory_size);
////////////////////////////////
//~ NOTE(allen): Threading Entities
typedef enum W32_EntityKind
{
W32_EntityKind_Null,
W32_EntityKind_Thread,
W32_EntityKind_Mutex,
W32_EntityKind_RWMutex,
W32_EntityKind_ConditionVariable,
}
W32_EntityKind;
typedef struct W32_Entity W32_Entity;
struct W32_Entity
{
W32_Entity *next;
W32_EntityKind kind;
volatile U32 reference_mask;
union{
struct{
OS_ThreadFunctionType *func;
void *ptr;
HANDLE handle;
DWORD tid;
} thread;
CRITICAL_SECTION mutex;
SRWLOCK rw_mutex;
CONDITION_VARIABLE cv;
};
};
////////////////////////////////
//~ rjf: Helpers
//- rjf: files
internal FilePropertyFlags w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes);
internal void w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes);
//- rjf: time
internal void w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in);
internal void w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in);
internal void w32_dense_time_from_file_time(DenseTime *out, FILETIME *in);
internal U32 w32_sleep_ms_from_endt_us(U64 endt_us);
//- rjf: entities
internal W32_Entity* w32_alloc_entity(W32_EntityKind kind);
internal void w32_free_entity(W32_Entity *entity);
//- rjf: threads
internal DWORD w32_thread_base(void *ptr);
#endif //WIN32_H
+5
View File
@@ -0,0 +1,5 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
+452
View File
@@ -0,0 +1,452 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
//- GENERATED CODE
#ifndef OS_GFX_META_H
#define OS_GFX_META_H
typedef enum OS_Key
{
OS_Key_Null,
OS_Key_Esc,
OS_Key_F1,
OS_Key_F2,
OS_Key_F3,
OS_Key_F4,
OS_Key_F5,
OS_Key_F6,
OS_Key_F7,
OS_Key_F8,
OS_Key_F9,
OS_Key_F10,
OS_Key_F11,
OS_Key_F12,
OS_Key_F13,
OS_Key_F14,
OS_Key_F15,
OS_Key_F16,
OS_Key_F17,
OS_Key_F18,
OS_Key_F19,
OS_Key_F20,
OS_Key_F21,
OS_Key_F22,
OS_Key_F23,
OS_Key_F24,
OS_Key_Tick,
OS_Key_0,
OS_Key_1,
OS_Key_2,
OS_Key_3,
OS_Key_4,
OS_Key_5,
OS_Key_6,
OS_Key_7,
OS_Key_8,
OS_Key_9,
OS_Key_Minus,
OS_Key_Equal,
OS_Key_Backspace,
OS_Key_Tab,
OS_Key_Q,
OS_Key_W,
OS_Key_E,
OS_Key_R,
OS_Key_T,
OS_Key_Y,
OS_Key_U,
OS_Key_I,
OS_Key_O,
OS_Key_P,
OS_Key_LeftBracket,
OS_Key_RightBracket,
OS_Key_BackSlash,
OS_Key_CapsLock,
OS_Key_A,
OS_Key_S,
OS_Key_D,
OS_Key_F,
OS_Key_G,
OS_Key_H,
OS_Key_J,
OS_Key_K,
OS_Key_L,
OS_Key_Semicolon,
OS_Key_Quote,
OS_Key_Return,
OS_Key_Shift,
OS_Key_Z,
OS_Key_X,
OS_Key_C,
OS_Key_V,
OS_Key_B,
OS_Key_N,
OS_Key_M,
OS_Key_Comma,
OS_Key_Period,
OS_Key_Slash,
OS_Key_Ctrl,
OS_Key_Alt,
OS_Key_Space,
OS_Key_Menu,
OS_Key_ScrollLock,
OS_Key_Pause,
OS_Key_Insert,
OS_Key_Home,
OS_Key_PageUp,
OS_Key_Delete,
OS_Key_End,
OS_Key_PageDown,
OS_Key_Up,
OS_Key_Left,
OS_Key_Down,
OS_Key_Right,
OS_Key_Ex0,
OS_Key_Ex1,
OS_Key_Ex2,
OS_Key_Ex3,
OS_Key_Ex4,
OS_Key_Ex5,
OS_Key_Ex6,
OS_Key_Ex7,
OS_Key_Ex8,
OS_Key_Ex9,
OS_Key_Ex10,
OS_Key_Ex11,
OS_Key_Ex12,
OS_Key_Ex13,
OS_Key_Ex14,
OS_Key_Ex15,
OS_Key_Ex16,
OS_Key_Ex17,
OS_Key_Ex18,
OS_Key_Ex19,
OS_Key_Ex20,
OS_Key_Ex21,
OS_Key_Ex22,
OS_Key_Ex23,
OS_Key_Ex24,
OS_Key_Ex25,
OS_Key_Ex26,
OS_Key_Ex27,
OS_Key_Ex28,
OS_Key_Ex29,
OS_Key_NumLock,
OS_Key_NumSlash,
OS_Key_NumStar,
OS_Key_NumMinus,
OS_Key_NumPlus,
OS_Key_NumPeriod,
OS_Key_Num0,
OS_Key_Num1,
OS_Key_Num2,
OS_Key_Num3,
OS_Key_Num4,
OS_Key_Num5,
OS_Key_Num6,
OS_Key_Num7,
OS_Key_Num8,
OS_Key_Num9,
OS_Key_LeftMouseButton,
OS_Key_MiddleMouseButton,
OS_Key_RightMouseButton,
OS_Key_COUNT
} OS_Key;
String8 os_g_key_display_string_table[] =
{
str8_lit_comp("Invalid Key"),
str8_lit_comp("Escape"),
str8_lit_comp("F1"),
str8_lit_comp("F2"),
str8_lit_comp("F3"),
str8_lit_comp("F4"),
str8_lit_comp("F5"),
str8_lit_comp("F6"),
str8_lit_comp("F7"),
str8_lit_comp("F8"),
str8_lit_comp("F9"),
str8_lit_comp("F10"),
str8_lit_comp("F11"),
str8_lit_comp("F12"),
str8_lit_comp("F13"),
str8_lit_comp("F14"),
str8_lit_comp("F15"),
str8_lit_comp("F16"),
str8_lit_comp("F17"),
str8_lit_comp("F18"),
str8_lit_comp("F19"),
str8_lit_comp("F20"),
str8_lit_comp("F21"),
str8_lit_comp("F22"),
str8_lit_comp("F23"),
str8_lit_comp("F24"),
str8_lit_comp("Tick"),
str8_lit_comp("0"),
str8_lit_comp("1"),
str8_lit_comp("2"),
str8_lit_comp("3"),
str8_lit_comp("4"),
str8_lit_comp("5"),
str8_lit_comp("6"),
str8_lit_comp("7"),
str8_lit_comp("8"),
str8_lit_comp("9"),
str8_lit_comp("Minus"),
str8_lit_comp("Equal"),
str8_lit_comp("Backspace"),
str8_lit_comp("Tab"),
str8_lit_comp("Q"),
str8_lit_comp("W"),
str8_lit_comp("E"),
str8_lit_comp("R"),
str8_lit_comp("T"),
str8_lit_comp("Y"),
str8_lit_comp("U"),
str8_lit_comp("I"),
str8_lit_comp("O"),
str8_lit_comp("P"),
str8_lit_comp("Left Bracket"),
str8_lit_comp("Right Bracket"),
str8_lit_comp("Back Slash"),
str8_lit_comp("Caps Lock"),
str8_lit_comp("A"),
str8_lit_comp("S"),
str8_lit_comp("D"),
str8_lit_comp("F"),
str8_lit_comp("G"),
str8_lit_comp("H"),
str8_lit_comp("J"),
str8_lit_comp("K"),
str8_lit_comp("L"),
str8_lit_comp("Semicolon"),
str8_lit_comp("Quote"),
str8_lit_comp("Return"),
str8_lit_comp("Shift"),
str8_lit_comp("Z"),
str8_lit_comp("X"),
str8_lit_comp("C"),
str8_lit_comp("V"),
str8_lit_comp("B"),
str8_lit_comp("N"),
str8_lit_comp("M"),
str8_lit_comp("Comma"),
str8_lit_comp("Period"),
str8_lit_comp("Slash"),
str8_lit_comp("Ctrl"),
str8_lit_comp("Alt"),
str8_lit_comp("Space"),
str8_lit_comp("Menu"),
str8_lit_comp("Scroll Lock"),
str8_lit_comp("Pause"),
str8_lit_comp("Insert"),
str8_lit_comp("Home"),
str8_lit_comp("Page Up"),
str8_lit_comp("Delete"),
str8_lit_comp("End"),
str8_lit_comp("Page Down"),
str8_lit_comp("Up"),
str8_lit_comp("Left"),
str8_lit_comp("Down"),
str8_lit_comp("Right"),
str8_lit_comp("Ex0"),
str8_lit_comp("Ex1"),
str8_lit_comp("Ex2"),
str8_lit_comp("Ex3"),
str8_lit_comp("Ex4"),
str8_lit_comp("Ex5"),
str8_lit_comp("Ex6"),
str8_lit_comp("Ex7"),
str8_lit_comp("Ex8"),
str8_lit_comp("Ex9"),
str8_lit_comp("Ex10"),
str8_lit_comp("Ex11"),
str8_lit_comp("Ex12"),
str8_lit_comp("Ex13"),
str8_lit_comp("Ex14"),
str8_lit_comp("Ex15"),
str8_lit_comp("Ex16"),
str8_lit_comp("Ex17"),
str8_lit_comp("Ex18"),
str8_lit_comp("Ex19"),
str8_lit_comp("Ex20"),
str8_lit_comp("Ex21"),
str8_lit_comp("Ex22"),
str8_lit_comp("Ex23"),
str8_lit_comp("Ex24"),
str8_lit_comp("Ex25"),
str8_lit_comp("Ex26"),
str8_lit_comp("Ex27"),
str8_lit_comp("Ex28"),
str8_lit_comp("Ex29"),
str8_lit_comp("Num Lock"),
str8_lit_comp("Numpad Slash"),
str8_lit_comp("Numpad Star"),
str8_lit_comp("Numpad Minus"),
str8_lit_comp("Numpad Plus"),
str8_lit_comp("Numpad Period"),
str8_lit_comp("Numpad 0"),
str8_lit_comp("Numpad 1"),
str8_lit_comp("Numpad 2"),
str8_lit_comp("Numpad 3"),
str8_lit_comp("Numpad 4"),
str8_lit_comp("Numpad 5"),
str8_lit_comp("Numpad 6"),
str8_lit_comp("Numpad 7"),
str8_lit_comp("Numpad 8"),
str8_lit_comp("Numpad 9"),
str8_lit_comp("Left Mouse Button"),
str8_lit_comp("Middle Mouse Button"),
str8_lit_comp("Right Mouse Button"),
};
String8 os_g_key_cfg_string_table[] =
{
str8_lit_comp("null"),
str8_lit_comp("esc"),
str8_lit_comp("f1"),
str8_lit_comp("f2"),
str8_lit_comp("f3"),
str8_lit_comp("f4"),
str8_lit_comp("f5"),
str8_lit_comp("f6"),
str8_lit_comp("f7"),
str8_lit_comp("f8"),
str8_lit_comp("f9"),
str8_lit_comp("f10"),
str8_lit_comp("f11"),
str8_lit_comp("f12"),
str8_lit_comp("f13"),
str8_lit_comp("f14"),
str8_lit_comp("f15"),
str8_lit_comp("f16"),
str8_lit_comp("f17"),
str8_lit_comp("f18"),
str8_lit_comp("f19"),
str8_lit_comp("f20"),
str8_lit_comp("f21"),
str8_lit_comp("f22"),
str8_lit_comp("f23"),
str8_lit_comp("f24"),
str8_lit_comp("tick"),
str8_lit_comp("0"),
str8_lit_comp("1"),
str8_lit_comp("2"),
str8_lit_comp("3"),
str8_lit_comp("4"),
str8_lit_comp("5"),
str8_lit_comp("6"),
str8_lit_comp("7"),
str8_lit_comp("8"),
str8_lit_comp("9"),
str8_lit_comp("minus"),
str8_lit_comp("equal"),
str8_lit_comp("backspace"),
str8_lit_comp("tab"),
str8_lit_comp("q"),
str8_lit_comp("w"),
str8_lit_comp("e"),
str8_lit_comp("r"),
str8_lit_comp("t"),
str8_lit_comp("y"),
str8_lit_comp("u"),
str8_lit_comp("i"),
str8_lit_comp("o"),
str8_lit_comp("p"),
str8_lit_comp("left_bracket"),
str8_lit_comp("right_bracket"),
str8_lit_comp("backslash"),
str8_lit_comp("caps_lock"),
str8_lit_comp("a"),
str8_lit_comp("s"),
str8_lit_comp("d"),
str8_lit_comp("f"),
str8_lit_comp("g"),
str8_lit_comp("h"),
str8_lit_comp("j"),
str8_lit_comp("k"),
str8_lit_comp("l"),
str8_lit_comp("semicolon"),
str8_lit_comp("quote"),
str8_lit_comp("return"),
str8_lit_comp("shift"),
str8_lit_comp("z"),
str8_lit_comp("x"),
str8_lit_comp("c"),
str8_lit_comp("v"),
str8_lit_comp("b"),
str8_lit_comp("n"),
str8_lit_comp("m"),
str8_lit_comp("comma"),
str8_lit_comp("period"),
str8_lit_comp("slash"),
str8_lit_comp("ctrl"),
str8_lit_comp("alt"),
str8_lit_comp("space"),
str8_lit_comp("menu"),
str8_lit_comp("scroll_lock"),
str8_lit_comp("pause"),
str8_lit_comp("insert"),
str8_lit_comp("home"),
str8_lit_comp("page_up"),
str8_lit_comp("delete"),
str8_lit_comp("end"),
str8_lit_comp("page_down"),
str8_lit_comp("up"),
str8_lit_comp("left"),
str8_lit_comp("down"),
str8_lit_comp("right"),
str8_lit_comp("ex0"),
str8_lit_comp("ex1"),
str8_lit_comp("ex2"),
str8_lit_comp("ex3"),
str8_lit_comp("ex4"),
str8_lit_comp("ex5"),
str8_lit_comp("ex6"),
str8_lit_comp("ex7"),
str8_lit_comp("ex8"),
str8_lit_comp("ex9"),
str8_lit_comp("ex10"),
str8_lit_comp("ex11"),
str8_lit_comp("ex12"),
str8_lit_comp("ex13"),
str8_lit_comp("ex14"),
str8_lit_comp("ex15"),
str8_lit_comp("ex16"),
str8_lit_comp("ex17"),
str8_lit_comp("ex18"),
str8_lit_comp("ex19"),
str8_lit_comp("ex20"),
str8_lit_comp("ex21"),
str8_lit_comp("ex22"),
str8_lit_comp("ex23"),
str8_lit_comp("ex24"),
str8_lit_comp("ex25"),
str8_lit_comp("ex26"),
str8_lit_comp("ex27"),
str8_lit_comp("ex28"),
str8_lit_comp("ex29"),
str8_lit_comp("num_lock"),
str8_lit_comp("numpad_slash"),
str8_lit_comp("numpad_star"),
str8_lit_comp("numpad_minus"),
str8_lit_comp("numpad_plus"),
str8_lit_comp("numpad_period"),
str8_lit_comp("numpad_0"),
str8_lit_comp("numpad_1"),
str8_lit_comp("numpad_2"),
str8_lit_comp("numpad_3"),
str8_lit_comp("numpad_4"),
str8_lit_comp("numpad_5"),
str8_lit_comp("numpad_6"),
str8_lit_comp("numpad_7"),
str8_lit_comp("numpad_8"),
str8_lit_comp("numpad_9"),
str8_lit_comp("left_mouse"),
str8_lit_comp("middle_mouse"),
str8_lit_comp("right_mouse"),
};
#endif // OS_GFX_META_H
+191
View File
@@ -0,0 +1,191 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Event Functions (Helpers, Implemented Once)
internal String8List
os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags)
{
String8List result = {0};
String8 flag_strs[] =
{
str8_lit("Ctrl"),
str8_lit("Shift"),
str8_lit("Alt"),
};
str8_list_from_flags(arena, &result, flags, flag_strs, ArrayCount(flag_strs));
return result;
}
internal U32
os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key)
{
U32 result = 0;
// rjf: special-case map
local_persist read_only struct {U32 character; OS_Key key; OS_EventFlags flags;} map[] =
{
{'!', OS_Key_1, OS_EventFlag_Shift},
{'@', OS_Key_2, OS_EventFlag_Shift},
{'#', OS_Key_3, OS_EventFlag_Shift},
{'$', OS_Key_4, OS_EventFlag_Shift},
{'%', OS_Key_5, OS_EventFlag_Shift},
{'^', OS_Key_6, OS_EventFlag_Shift},
{'&', OS_Key_7, OS_EventFlag_Shift},
{'*', OS_Key_8, OS_EventFlag_Shift},
{'(', OS_Key_9, OS_EventFlag_Shift},
{')', OS_Key_0, OS_EventFlag_Shift},
{'_', OS_Key_Minus, OS_EventFlag_Shift},
{'_', OS_Key_Minus, OS_EventFlag_Shift},
{'-', OS_Key_Minus, 0},
{'=', OS_Key_Equal, 0},
{'+', OS_Key_Equal, OS_EventFlag_Shift},
{'`', OS_Key_Tick, 0},
{'~', OS_Key_Tick, OS_EventFlag_Shift},
{'[', OS_Key_LeftBracket, 0},
{']', OS_Key_RightBracket, 0},
{'{', OS_Key_LeftBracket, OS_EventFlag_Shift},
{'}', OS_Key_RightBracket, OS_EventFlag_Shift},
{'\\', OS_Key_BackSlash, 0},
{'|', OS_Key_BackSlash, OS_EventFlag_Shift},
{';', OS_Key_Semicolon, 0},
{':', OS_Key_Semicolon, OS_EventFlag_Shift},
{'\'', OS_Key_Quote, 0},
{'"', OS_Key_Quote, OS_EventFlag_Shift},
{'.', OS_Key_Period, 0},
{',', OS_Key_Comma, 0},
{'<', OS_Key_Period, OS_EventFlag_Shift},
{'>', OS_Key_Comma, OS_EventFlag_Shift},
{'/', OS_Key_Slash, 0},
{'?', OS_Key_Slash, OS_EventFlag_Shift},
{'a', OS_Key_A, 0},
{'b', OS_Key_B, 0},
{'c', OS_Key_C, 0},
{'d', OS_Key_D, 0},
{'e', OS_Key_E, 0},
{'f', OS_Key_F, 0},
{'g', OS_Key_G, 0},
{'h', OS_Key_H, 0},
{'i', OS_Key_I, 0},
{'j', OS_Key_J, 0},
{'k', OS_Key_K, 0},
{'l', OS_Key_L, 0},
{'m', OS_Key_M, 0},
{'n', OS_Key_N, 0},
{'o', OS_Key_O, 0},
{'p', OS_Key_P, 0},
{'q', OS_Key_Q, 0},
{'r', OS_Key_R, 0},
{'s', OS_Key_S, 0},
{'t', OS_Key_T, 0},
{'u', OS_Key_U, 0},
{'v', OS_Key_V, 0},
{'w', OS_Key_W, 0},
{'x', OS_Key_X, 0},
{'y', OS_Key_Y, 0},
{'z', OS_Key_Z, 0},
{'A', OS_Key_A, OS_EventFlag_Shift},
{'B', OS_Key_B, OS_EventFlag_Shift},
{'C', OS_Key_C, OS_EventFlag_Shift},
{'D', OS_Key_D, OS_EventFlag_Shift},
{'E', OS_Key_E, OS_EventFlag_Shift},
{'F', OS_Key_F, OS_EventFlag_Shift},
{'G', OS_Key_G, OS_EventFlag_Shift},
{'H', OS_Key_H, OS_EventFlag_Shift},
{'I', OS_Key_I, OS_EventFlag_Shift},
{'J', OS_Key_J, OS_EventFlag_Shift},
{'K', OS_Key_K, OS_EventFlag_Shift},
{'L', OS_Key_L, OS_EventFlag_Shift},
{'M', OS_Key_M, OS_EventFlag_Shift},
{'N', OS_Key_N, OS_EventFlag_Shift},
{'O', OS_Key_O, OS_EventFlag_Shift},
{'P', OS_Key_P, OS_EventFlag_Shift},
{'Q', OS_Key_Q, OS_EventFlag_Shift},
{'R', OS_Key_R, OS_EventFlag_Shift},
{'S', OS_Key_S, OS_EventFlag_Shift},
{'T', OS_Key_T, OS_EventFlag_Shift},
{'U', OS_Key_U, OS_EventFlag_Shift},
{'V', OS_Key_V, OS_EventFlag_Shift},
{'W', OS_Key_W, OS_EventFlag_Shift},
{'X', OS_Key_X, OS_EventFlag_Shift},
{'Y', OS_Key_Y, OS_EventFlag_Shift},
{'Z', OS_Key_Z, OS_EventFlag_Shift},
};
// rjf: check numeric
if(OS_Key_0 <= key && key <= OS_Key_9)
{
result = '0' + (key - OS_Key_0);
}
// rjf: check special-case map
for(U64 idx = 0; idx < ArrayCount(map); idx += 1)
{
if(map[idx].key == key && map[idx].flags == flags)
{
result = map[idx].character;
break;
}
}
return result;
}
internal void
os_eat_event(OS_EventList *events, OS_Event *event)
{
DLLRemove(events->first, events->last, event);
events->count -= 1;
}
internal B32
os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key)
{
B32 result = 0;
for(OS_Event *event = events->first; event != 0; event = event->next)
{
if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) &&
event->kind == OS_EventKind_Press && event->key == key && event->flags == flags)
{
result = 1;
os_eat_event(events, event);
break;
}
}
return result;
}
internal B32
os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key)
{
B32 result = 0;
for(OS_Event *event = events->first; event != 0; event = event->next)
{
if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) &&
event->kind == OS_EventKind_Release && event->key == key && event->flags == flags)
{
result = 1;
os_eat_event(events, event);
break;
}
}
return result;
}
internal B32
os_text(OS_EventList *events, OS_Handle window, U32 character)
{
B32 result = 0;
for(OS_Event *event = events->first; event != 0; event = event->next)
{
if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) &&
event->kind == OS_EventKind_Text && event->character == character)
{
result = 1;
os_eat_event(events, event);
break;
}
}
return result;
}
+162
View File
@@ -0,0 +1,162 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_GRAPHICAL_H
#define OS_GRAPHICAL_H
////////////////////////////////
//~ rjf: Window Types
typedef void OS_WindowRepaintFunctionType(OS_Handle window, void *user_data);
////////////////////////////////
//~ rjf: Cursor Types
typedef enum OS_Cursor
{
OS_Cursor_Pointer,
OS_Cursor_IBar,
OS_Cursor_LeftRight,
OS_Cursor_UpDown,
OS_Cursor_DownRight,
OS_Cursor_UpRight,
OS_Cursor_UpDownLeftRight,
OS_Cursor_HandPoint,
OS_Cursor_Disabled,
OS_Cursor_COUNT,
}
OS_Cursor;
////////////////////////////////
//~ rjf: Generated Code
#include "os/gfx/generated/os_gfx.meta.h"
////////////////////////////////
//~ rjf: Event Types
typedef enum OS_EventKind
{
OS_EventKind_Null,
OS_EventKind_Press,
OS_EventKind_Release,
OS_EventKind_Text,
OS_EventKind_Scroll,
OS_EventKind_WindowLoseFocus,
OS_EventKind_WindowClose,
OS_EventKind_FileDrop,
OS_EventKind_Wakeup,
OS_EventKind_COUNT
}
OS_EventKind;
typedef U32 OS_EventFlags;
enum
{
OS_EventFlag_Ctrl = (1<<0),
OS_EventFlag_Shift = (1<<1),
OS_EventFlag_Alt = (1<<2),
};
typedef struct OS_Event OS_Event;
struct OS_Event
{
OS_Event *next;
OS_Event *prev;
OS_Handle window;
OS_EventKind kind;
OS_EventFlags flags;
OS_Key key;
B32 is_repeat;
B32 right_sided;
U32 character;
U32 repeat_count;
Vec2F32 delta;
String8List strings;
};
typedef struct OS_EventList OS_EventList;
struct OS_EventList
{
U64 count;
OS_Event *first;
OS_Event *last;
};
////////////////////////////////
//~ rjf: Event Functions (Helpers, Implemented Once)
internal String8List os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags);
internal U32 os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key);
internal void os_eat_event(OS_EventList *events, OS_Event *event);
internal B32 os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key);
internal B32 os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key);
internal B32 os_text(OS_EventList *events, OS_Handle window, U32 character);
////////////////////////////////
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
internal void os_graphical_init(void);
////////////////////////////////
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)
internal void os_set_clipboard_text(String8 string);
internal String8 os_get_clipboard_text(Arena *arena);
////////////////////////////////
//~ rjf: @os_hooks Windows (Implemented Per-OS)
internal OS_Handle os_window_open(Vec2F32 resolution, String8 title);
internal void os_window_close(OS_Handle window);
internal void os_window_first_paint(OS_Handle window);
internal void os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data);
internal void os_window_focus(OS_Handle window);
internal B32 os_window_is_focused(OS_Handle window);
internal B32 os_window_is_fullscreen(OS_Handle window);
internal void os_window_set_fullscreen(OS_Handle window, B32 fullscreen);
internal B32 os_window_is_maximized(OS_Handle window);
internal void os_window_set_maximized(OS_Handle window, B32 maximized);
internal void os_window_bring_to_front(OS_Handle window);
internal void os_window_set_monitor(OS_Handle window, OS_Handle monitor);
internal Rng2F32 os_rect_from_window(OS_Handle window);
internal Rng2F32 os_client_rect_from_window(OS_Handle window);
internal F32 os_dpi_from_window(OS_Handle window);
////////////////////////////////
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
internal OS_HandleArray os_push_monitors_array(Arena *arena);
internal OS_Handle os_primary_monitor(void);
internal OS_Handle os_monitor_from_window(OS_Handle window);
internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor);
internal Vec2F32 os_dim_from_monitor(OS_Handle monitor);
////////////////////////////////
//~ rjf: @os_hooks Events (Implemented Per-OS)
internal void os_send_wakeup_event(void);
internal OS_EventList os_get_events(Arena *arena, B32 wait);
internal OS_EventFlags os_get_event_flags(void);
internal B32 os_key_is_down(OS_Key key);
internal Vec2F32 os_mouse_from_window(OS_Handle window);
////////////////////////////////
//~ rjf: @os_hooks Cursors (Implemented Per-OS)
internal void os_set_cursor(OS_Cursor cursor);
////////////////////////////////
//~ rjf: @os_hooks System Properties (Implemented Per-OS)
internal F32 os_double_click_time(void);
internal F32 os_caret_blink_time(void);
internal F32 os_default_refresh_rate(void);
internal B32 os_granular_sleep_enabled(void);
////////////////////////////////
//~ rjf: @os_hooks Native Messages & Panics (Implemented Per-OS)
internal void os_graphical_message(B32 error, String8 title, String8 message);
#endif // OS_GRAPHICAL_H
+175
View File
@@ -0,0 +1,175 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Tables
@table(name, display_string, cfg_string)
OS_KeyTable:
{
{Null "Invalid Key" "null" }
{Esc "Escape" "esc" }
{F1 "F1" "f1" }
{F2 "F2" "f2" }
{F3 "F3" "f3" }
{F4 "F4" "f4" }
{F5 "F5" "f5" }
{F6 "F6" "f6" }
{F7 "F7" "f7" }
{F8 "F8" "f8" }
{F9 "F9" "f9" }
{F10 "F10" "f10" }
{F11 "F11" "f11" }
{F12 "F12" "f12" }
{F13 "F13" "f13" }
{F14 "F14" "f14" }
{F15 "F15" "f15" }
{F16 "F16" "f16" }
{F17 "F17" "f17" }
{F18 "F18" "f18" }
{F19 "F19" "f19" }
{F20 "F20" "f20" }
{F21 "F21" "f21" }
{F22 "F22" "f22" }
{F23 "F23" "f23" }
{F24 "F24" "f24" }
{Tick "Tick" "tick" }
{0 "0" "0" }
{1 "1" "1" }
{2 "2" "2" }
{3 "3" "3" }
{4 "4" "4" }
{5 "5" "5" }
{6 "6" "6" }
{7 "7" "7" }
{8 "8" "8" }
{9 "9" "9" }
{Minus "Minus" "minus" }
{Equal "Equal" "equal" }
{Backspace "Backspace" "backspace" }
{Tab "Tab" "tab" }
{Q "Q" "q" }
{W "W" "w" }
{E "E" "e" }
{R "R" "r" }
{T "T" "t" }
{Y "Y" "y" }
{U "U" "u" }
{I "I" "i" }
{O "O" "o" }
{P "P" "p" }
{LeftBracket "Left Bracket" "left_bracket" }
{RightBracket "Right Bracket" "right_bracket" }
{BackSlash "Back Slash" "backslash" }
{CapsLock "Caps Lock" "caps_lock" }
{A "A" "a" }
{S "S" "s" }
{D "D" "d" }
{F "F" "f" }
{G "G" "g" }
{H "H" "h" }
{J "J" "j" }
{K "K" "k" }
{L "L" "l" }
{Semicolon "Semicolon" "semicolon" }
{Quote "Quote" "quote" }
{Return "Return" "return" }
{Shift "Shift" "shift" }
{Z "Z" "z" }
{X "X" "x" }
{C "C" "c" }
{V "V" "v" }
{B "B" "b" }
{N "N" "n" }
{M "M" "m" }
{Comma "Comma" "comma" }
{Period "Period" "period" }
{Slash "Slash" "slash" }
{Ctrl "Ctrl" "ctrl" }
{Alt "Alt" "alt" }
{Space "Space" "space" }
{Menu "Menu" "menu" }
{ScrollLock "Scroll Lock" "scroll_lock" }
{Pause "Pause" "pause" }
{Insert "Insert" "insert" }
{Home "Home" "home" }
{PageUp "Page Up" "page_up" }
{Delete "Delete" "delete" }
{End "End" "end" }
{PageDown "Page Down" "page_down" }
{Up "Up" "up" }
{Left "Left" "left" }
{Down "Down" "down" }
{Right "Right" "right" }
{Ex0 "Ex0" "ex0" }
{Ex1 "Ex1" "ex1" }
{Ex2 "Ex2" "ex2" }
{Ex3 "Ex3" "ex3" }
{Ex4 "Ex4" "ex4" }
{Ex5 "Ex5" "ex5" }
{Ex6 "Ex6" "ex6" }
{Ex7 "Ex7" "ex7" }
{Ex8 "Ex8" "ex8" }
{Ex9 "Ex9" "ex9" }
{Ex10 "Ex10" "ex10" }
{Ex11 "Ex11" "ex11" }
{Ex12 "Ex12" "ex12" }
{Ex13 "Ex13" "ex13" }
{Ex14 "Ex14" "ex14" }
{Ex15 "Ex15" "ex15" }
{Ex16 "Ex16" "ex16" }
{Ex17 "Ex17" "ex17" }
{Ex18 "Ex18" "ex18" }
{Ex19 "Ex19" "ex19" }
{Ex20 "Ex20" "ex20" }
{Ex21 "Ex21" "ex21" }
{Ex22 "Ex22" "ex22" }
{Ex23 "Ex23" "ex23" }
{Ex24 "Ex24" "ex24" }
{Ex25 "Ex25" "ex25" }
{Ex26 "Ex26" "ex26" }
{Ex27 "Ex27" "ex27" }
{Ex28 "Ex28" "ex28" }
{Ex29 "Ex29" "ex29" }
{NumLock "Num Lock" "num_lock" }
{NumSlash "Numpad Slash" "numpad_slash" }
{NumStar "Numpad Star" "numpad_star" }
{NumMinus "Numpad Minus" "numpad_minus" }
{NumPlus "Numpad Plus" "numpad_plus" }
{NumPeriod "Numpad Period" "numpad_period" }
{Num0 "Numpad 0" "numpad_0" }
{Num1 "Numpad 1" "numpad_1" }
{Num2 "Numpad 2" "numpad_2" }
{Num3 "Numpad 3" "numpad_3" }
{Num4 "Numpad 4" "numpad_4" }
{Num5 "Numpad 5" "numpad_5" }
{Num6 "Numpad 6" "numpad_6" }
{Num7 "Numpad 7" "numpad_7" }
{Num8 "Numpad 8" "numpad_8" }
{Num9 "Numpad 9" "numpad_9" }
{LeftMouseButton "Left Mouse Button" "left_mouse" }
{MiddleMouseButton "Middle Mouse Button" "middle_mouse" }
{RightMouseButton "Right Mouse Button" "right_mouse" }
}
////////////////////////////////
//~ rjf: Generators
@table_gen_enum
OS_Key:
{
@expand(OS_KeyTable a) `OS_Key_$(a.name),`;
`OS_Key_COUNT`;
}
@table_gen_data(type: String8, fallback:`{0}`)
os_g_key_display_string_table:
{
@expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)"),`;
}
@table_gen_data(type: String8, fallback:`{0}`)
os_g_key_cfg_string_table:
{
@expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)"),`;
}
File diff suppressed because it is too large Load Diff
+62
View File
@@ -0,0 +1,62 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_GRAPHICAL_H
#define WIN32_GRAPHICAL_H
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "winmm")
////////////////////////////////
//~ rjf: Windows
typedef struct W32_Window W32_Window;
struct W32_Window
{
W32_Window *next;
W32_Window *prev;
HWND hwnd;
WINDOWPLACEMENT last_window_placement;
OS_WindowRepaintFunctionType *repaint;
void *repaint_user_data;
F32 dpi;
B32 first_paint_done;
B32 maximized;
};
////////////////////////////////
//~ rjf: Monitor Gathering Bundle
typedef struct W32_MonitorGatherBundle W32_MonitorGatherBundle;
struct W32_MonitorGatherBundle
{
Arena *arena;
OS_HandleList *list;
};
////////////////////////////////
//~ rjf: Basic Helpers
internal Rng2F32 w32_base_rect_from_win32_rect(RECT rect);
////////////////////////////////
//~ rjf: Windows
internal OS_Handle os_window_from_w32_window(W32_Window *window);
internal W32_Window * w32_window_from_os_window(OS_Handle window);
internal W32_Window * w32_window_from_hwnd(HWND hwnd);
internal HWND w32_hwnd_from_window(W32_Window *window);
internal W32_Window * w32_allocate_window(void);
internal void w32_free_window(W32_Window *window);
internal OS_Event * w32_push_event(OS_EventKind kind, W32_Window *window);
internal OS_Key w32_os_key_from_vkey(WPARAM vkey);
internal WPARAM w32_vkey_from_os_key(OS_Key key);
internal LRESULT w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
////////////////////////////////
//~ rjf: Monitors
internal BOOL w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr);
#endif // WIN32_GRAPHICAL_H
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Include OS features for extra features and target OS
#include "core/os_core.c"
#if OS_FEATURE_SOCKET
#include "socket/os_socket.c"
#endif
#if OS_FEATURE_GRAPHICAL
#include "gfx/os_gfx.c"
#endif
#if OS_WINDOWS
# include "core/win32/os_core_win32.c"
# if OS_FEATURE_SOCKET
# include "socket/win32/os_socket_win32.c"
# endif
# if OS_FEATURE_GRAPHICAL
# include "gfx/win32/os_gfx_win32.c"
# endif
#elif OS_LINUX
# include "core/linux/os_core_linux.c"
#else
# error no OS layer setup
#endif
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_INC_H
#define OS_INC_H
#if !defined(OS_FEATURE_SOCKET)
# define OS_FEATURE_SOCKET 0
#endif
#if !defined(OS_FEATURE_GRAPHICAL)
# define OS_FEATURE_GRAPHICAL 0
#endif
#include "core/os_core.h"
#if OS_FEATURE_SOCKET
#include "socket/os_socket.h"
#endif
#if OS_FEATURE_GRAPHICAL
#include "gfx/os_gfx.h"
#endif
#if OS_WINDOWS
# include "core/win32/os_core_win32.h"
# if OS_FEATURE_SOCKET
# include "socket/win32/os_socket_win32.h"
# endif
# if OS_FEATURE_GRAPHICAL
# include "gfx/win32/os_gfx_win32.h"
# endif
#elif OS_LINUX
# include "core/linux/os_core_linux.h"
#else
# error no OS layer setup
#endif
#endif //OS_SWITCH_H
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Helper
internal B32
os_socket_write(OS_Socket *socket, String8 data){
String8Node node = {0};
String8List list = {0};
str8_list_push(&list, &node, data);
B32 result = os_socket_write(socket, list);
return(result);
}
#endif
+49
View File
@@ -0,0 +1,49 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_SOCKET_H
#define OS_SOCKET_H
enum OS_SocketStatus{
OS_SocketStatus_Uninitialized,
OS_SocketStatus_Connected,
OS_SocketStatus_GracefullyClosed,
OS_SocketStatus_Error,
};
typedef U16 OS_SocketError;
enum{
OS_SocketError_None,
OS_SocketError_SocketSystemNotInitialized,
OS_SocketError_BadPortArgument,
OS_SocketError_BadIPArgument,
OS_SocketError_WSAError,
};
struct OS_Socket{
U8 memory[32];
};
////////////////////////////////
//~ NOTE(allen): Implemented Per Operating System
internal void os_socket_init(void);
internal void os_socket_listen(OS_Socket *socket, String8 port);
internal void os_socket_connect(OS_Socket *socket, String8 ip, String8 port);
internal void os_socket_close(OS_Socket *socket);
internal String8 os_socket_read(Arena *arena, OS_Socket *socket);
internal B32 os_socket_write(OS_Socket *socket, String8List list);
internal B32 os_socket_status(OS_Socket *socket, OS_SocketStatus status);
internal String8 os_socket_error_string(Arena *arena, OS_Socket *socket);
internal void os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error);
////////////////////////////////
//~ NOTE(allen): Helpers - Portable Implementation
internal B32 os_socket_write(OS_Socket *socket, String8 data);
#endif //OS_SOCKET_H
+353
View File
@@ -0,0 +1,353 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal void
w32_socket_set_error(W32_Socket *socket, OS_SocketError error){
socket->error = error;
// NOTE(allen): This flag was set earlier so that the socket would assert
// when an error occurs. The "bug" or issue is whatever caused this error
// not the fact the flag is set. Unless the flag wasn't supposed to be set!
Assert(!(socket->flags & W32_SocketFlag_AssertOnError));
}
internal void
w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error){
switch (wsa_error){
default:
{
socket->wsa_error = wsa_error;
w32_socket_set_error(socket, OS_SocketError_WSAError);
}break;
case WSANOTINITIALISED:
{
w32_socket_set_error(socket, OS_SocketError_SocketSystemNotInitialized);
}break;
}
}
internal B32
w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size){
U32 p = 0;
CHAR *ptr = (CHAR*)buffer;
for (;p < size;){
DWORD amt = (DWORD)(size - p);
WSABUF wsabuf = {amt, ptr};
// NOTE(allen): The flags pointer is _NOT_ optional but we can ignore it.
// We have to zero it because it's an in/out pointer.
DWORD ignore = 0;
if (WSARecv(w32_socket->socket, &wsabuf, 1, &amt, &ignore, 0, 0) != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
break;
}
if (amt == 0){
w32_socket->flags |= W32_SocketFlag_Closed;
break;
}
p += amt;
ptr += amt;
}
B32 result = (p == size);
return(result);
}
////////////////////////////////
//~ rjf: Per-OS Hook Implementations
internal void
os_socket_init(void){
WSADATA wsaData;
WORD vreq = MAKEWORD(2,2);
WSAStartup(vreq, &wsaData);
}
internal void
os_socket_listen(OS_Socket *s, String8 port){
W32_Socket *w32_socket = (W32_Socket*)s->memory;
// NOTE(allen): check port string
char port_buffer[6];
if (port.size == 0 || port.size >= sizeof(port_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument);
return;
}
MemoryCopy(port_buffer, port.str, port.size);
port_buffer[port.size] = 0;
// NOTE(allen): listen socket addrinfo
addrinfo listen_hint = {0};
listen_hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV;
listen_hint.ai_family = AF_UNSPEC;
listen_hint.ai_socktype = SOCK_STREAM;
listen_hint.ai_protocol = AF_UNSPEC;
addrinfo *addr = {0};
INT error = getaddrinfo(0, port_buffer, &listen_hint, &addr);
if (error != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): init listen socket
SOCKET socket_listener = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
W32_SocketCloser listener_closer(&socket_listener);
// NOTE(allen): reuseraddr
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(socket_listener, SOL_SOCKET, SO_REUSEADDR, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): bind
if (bind(socket_listener, addr->ai_addr, (int)addr->ai_addrlen) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): listen
if (listen(socket_listener, 1) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): accept
SOCKET client_socket = accept(socket_listener, 0, 0);
W32_SocketCloser client_closer(&client_socket);
// NOTE(allen): TCP_NODELAY
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(client_socket, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): success
w32_socket->flags |= W32_SocketFlag_Connected;
w32_socket->socket = client_socket;
w32_socket->error = OS_SocketError_None;
client_closer.do_not_close();
}
internal void
os_socket_connect(OS_Socket *s, String8 ip, String8 port){
W32_Socket *w32_socket = (W32_Socket*)s->memory;
// NOTE(allen): check port string
char port_buffer[6];
if (port.size == 0 || port.size >= sizeof(port_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument);
return;
}
MemoryCopy(port_buffer, port.str, port.size);
port_buffer[port.size] = 0;
// NOTE(allen): check ip string
if (ip.size == 0){
ip = str8_lit("localhost");
}
char ip_buffer[KB(1)];
if (ip.size >= sizeof(ip_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadIPArgument);
return;
}
MemoryCopy(ip_buffer, ip.str, ip.size);
ip_buffer[ip.size] = 0;
// NOTE(allen): socket addrinfo
addrinfo hint = {0};
hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = AF_UNSPEC;
addrinfo *addr = {0};
INT error = getaddrinfo(ip_buffer, port_buffer, &hint, &addr);
if (error != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): init socket
SOCKET socket_server = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
W32_SocketCloser closer(&socket_server);
// NOTE(allen): TCP_NODELAY
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(socket_server, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): connect
if (connect(socket_server, addr->ai_addr, (int)addr->ai_addrlen) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): success
w32_socket->flags |= W32_SocketFlag_Connected;
w32_socket->socket = socket_server;
w32_socket->error = OS_SocketError_None;
closer.do_not_close();
}
internal void
os_socket_close(OS_Socket *socket){
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
closesocket(w32_socket->socket);
MemoryZeroStruct(w32_socket);
}
internal String8
os_socket_read(Arena *arena, OS_Socket *socket){
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
String8 result = {0};
U32 size = 0;
if (w32_socket_read_looped(w32_socket, &size, sizeof(size))){
Temp restore = temp_begin(arena);
result.str = push_array_no_zero(arena, U8, size);
if (w32_socket_read_looped(w32_socket, result.str, size)){
result.size = size;
}
else{
temp_end(restore);
result.str = 0;
}
}
return(result);
}
internal B32
os_socket_write(OS_Socket *socket, String8List list){
U32 size = (U32)list.total_size;
String8Node node = {0};
str8_list_push_front(&list, &node, str8_struct(&size));
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
WSABUF wsabuf[64];
Assert(list.node_count <= ArrayCount(wsabuf));
U64 wsabuf_count = 0;
for (String8Node *node = list.first;
node != 0;
node = node->next){
wsabuf[wsabuf_count].len = (U32)node->string.size;
wsabuf[wsabuf_count].buf = (CHAR*)node->string.str;
wsabuf_count += 1;
}
B32 result = false;
DWORD amt = 0;
if (WSASend(w32_socket->socket, wsabuf, wsabuf_count, &amt, 0, 0, 0) != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
}
else if (amt == 0){
w32_socket->flags |= W32_SocketFlag_Connected;
}
else{
result = true;
}
return(result);
}
internal B32
os_socket_status(OS_Socket *socket, OS_SocketStatus status){
W32_Socket *w32_socket = (W32_Socket*)socket;
B32 result = false;
switch (status){
case OS_SocketStatus_Uninitialized:
{
result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == 0) &&
(w32_socket->error == 0));
}break;
case OS_SocketStatus_Connected:
{
result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == W32_SocketFlag_Connected) &&
(w32_socket->error == 0));
}break;
case OS_SocketStatus_GracefullyClosed:
{
result = (((w32_socket->flags & W32_SocketFlag_Closed) == W32_SocketFlag_Closed) && (w32_socket->error == 0));
}break;
case OS_SocketStatus_Error:
{
result = (w32_socket->error != 0);
}break;
}
return(result);
}
internal String8
os_socket_error_string(Arena *arena, OS_Socket *socket){
String8 result = str8_lit("no error");
W32_Socket *w32_socket = (W32_Socket*)socket;
switch (w32_socket->error){
default:
{
result = str8_lit("Bad error code");
}break;
case OS_SocketError_None:break;
case OS_SocketError_SocketSystemNotInitialized:
{
result = str8_lit("Missing call to os_socket_init");
}break;
case OS_SocketError_BadPortArgument:
{
result = str8_lit("Invalid port argument to socket API");
}break;
case OS_SocketError_BadIPArgument:
{
result = str8_lit("Invalid ip argument to socket API");
}break;
case OS_SocketError_WSAError:
{
DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM;
CHAR *message = 0;
DWORD size = FormatMessageA(flags, 0, w32_socket->wsa_error, 0, (CHAR*)&message, 0, 0);
if (size == 0){
result = str8_lit("Unknown WSA error");
}
else{
String8 string = str8_skip_chop_whitespace(str8((U8*)message, size));
result = push_str8_copy(arena, string);
LocalFree(message);
}
}break;
}
return(result);
}
internal void
os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error){
W32_Socket *w32_socket = (W32_Socket*)socket;
if (assert_on_error){
w32_socket->flags |= W32_SocketFlag_AssertOnError;
}
else{
w32_socket->flags &= ~W32_SocketFlag_AssertOnError;
}
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_SOCKET_H
#define WIN32_SOCKET_H
////////////////////////////////
//~ rjf: Types
typedef U16 W32_SocketFlags;
enum{
W32_SocketFlag_Connected = (1 << 0),
W32_SocketFlag_Closed = (1 << 1),
W32_SocketFlag_AssertOnError = (1 << 2),
};
struct W32_Socket{
W32_SocketFlags flags;
OS_SocketError error;
int wsa_error;
SOCKET socket;
};
struct W32_SocketCloser{
B32 need_to_close;
SOCKET *socket;
W32_SocketCloser(SOCKET *s){
this->need_to_close = true;
this->socket = s;
}
~W32_SocketCloser(){
this->close_now();
}
void close_now(){
if (this->need_to_close){
closesocket(*this->socket);
this->need_to_close = false;
}
}
void do_not_close(){
this->need_to_close = false;
}
};
StaticAssert(sizeof(Member(OS_Socket, memory)) >= sizeof(W32_Socket), socket_memory_size);
////////////////////////////////
//~ rjf: Helpers
internal void w32_socket_set_error(W32_Socket *socket, OS_SocketError error);
internal void w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error);
internal B32 w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size);
#endif // WIN32_SOCKET_H