# define COMPILER_CLANG 1
#elif defined(_MSC_VER)
# define COMPILER_CL 1
+# if defined(_M_IX86)
+# define ARCH_X86_32 1
+# elif defined(_M_AMD64)
+# define ARCH_X86_64 1
+# elif defined(_M_ARM)
+# define ARCH_ARM32 1
+# elif defined(_M_ARM64)
+# define ARCH_ARM64 1
+# else
+# error Unsupported platform
+# endif
#else
# error Unsupported compiler
#endif
# error Unknown operating system
#endif
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
+# define ARCH_X86_64 1
+#elif defined(i386) || defined(__i386) || defined(__i386__)
+# define ARCH_X86_32 1
+#elif defined(__aarch64__)
+# define ARCH_ARM64 1
+#elif defined(__arm__)
+# define ARCH_ARM32 1
+#else
+# error Unknown architecture
+#endif
+
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
#endif
# define OS_NONE 0
#endif
+#ifdef alignof
+# undef alignof
+#endif
+#if COMPILER_GCC
+# define alignof(TYPE) __alignof__(TYPE)
+#elif COMPILER_CLANG || COMPILER_CL
+# define alignof(TYPE) __alignof(TYPE)
+#else
+# error undefined alignof macro
+#endif
+
#define internal static
-#define BOOL_DEFINED 1
-#if __STDC_VERSION__ >= 199901L
-# include <stdbool.h>
-#else
- typedef enum {false, true} bool;
+#if !OS_WINDOWS && !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
-
-#if OS_WINDOWS
-# if COMPILER_CL
-# define CC "cl"
-# else
-# define CC "x86_64-w64-mingw32-gcc"
-# endif
-#else
-# define CC "cc"
-#endif
-
#if OS_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef stdin
# undef stdout
# undef stderr
-# define _cb_platform_mkdir(Path) _mkdir((Path));
-# define MAX_ENVVAR 32767
-# define CB_PROC_INVALID INVALID_HANDLE_VALUE
-# define CB_HANDLE_INVALID INVALID_HANDLE_VALUE
+#endif
- typedef HANDLE CB_Handle;
- typedef HANDLE CB_ProcHandle;
+typedef float f32;
+typedef double f64;
+typedef uint8_t b8;
+typedef uint32_t b32;
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef uintptr_t usize;
+typedef intptr_t ssize;
+
+typedef u64 time64;
+typedef u64 unix_time;
+
+#define false 0
+#define true 1
+
+#define UNIX_MINUTE 60
+#define UNIX_HOUR 3600
+#define UNIX_DAY 86400
+#define UNIX_WEEK 604800
+#define UNIX_YEAR 31536000
+#define UNIX_LEAP_YEAR 31622400
+
+#if COMPILER_CL
+# define CC "cl"
+#elif COMPILER_GCC
+# define CC "gcc"
+#elif COMPILER_CLANG
+# define CC "clang"
#else
-# include <unistd.h>
-# include <fcntl.h>
-# include <sys/stat.h>
-# include <sys/wait.h>
-# include <sys/stat.h>
-# define _cb_platform_mkdir(Path) mkdir((Path), S_IRWXU | (S_IRGRP | S_IXGRP) | (S_IROTH | S_IXOTH));
-# define CB_PROC_INVALID -1
-# define CB_HANDLE_INVALID -1
- typedef int32_t CB_Handle;
- typedef pid_t CB_ProcHandle;
+# define CC "cc"
#endif
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
+#define cb_memcopy(Destination, Source, Size) memcpy((Destination), (Source), (u64)(Size))
+#define cb_memzero(Destination, Size) memset((Destination), 0, (u64)(Size))
+
+#define cb_arrlength(Arr) (sizeof((Arr)) / sizeof(*(Arr)))
+
+// ================================================================================
+// Static arena
+#define CB_ARENA_SIZE 4 * 1024 * 1024
+
+static struct {
+ u8 data[CB_ARENA_SIZE];
+ s64 head;
+} cb_arena = {0};
+
+typedef struct CB_Scratch CB_Scratch;
+struct CB_Scratch {
+ s64 restore_point;
+};
+
+#define cb_arena_push(type) cb_arena_push_many(type, 1)
+#define cb_arena_push_many(type, count) ((type*)_cb_arena_push(sizeof(type) * (u64)(count), alignof(type)))
+#define cb_arena_push_explicit(bytes, alignment) (_cb_arena_push((bytes), (alignment)))
+
+#define cb_scratch_begin() ((CB_Scratch) { .restore_point = cb_arena.head })
+#define cb_scratch_end(scratch) cb_arena_pop(cb_arena.head - (scratch).restore_point)
+
+static void cb_arena_pop(s64 bytes);
+internal void* _cb_arena_push(u64 bytes, u64 alignment);
+
+static inline u64 cb_align_forward(u64 x, u64 align);
+
+// ================================================================================
+// Compact time format
+static time64 cb_time64_from_unix(unix_time timestamp);
+#if OS_WINDOWS
+static time64 time64_from_systemtime(const SYSTEMTIME *in);
+#endif
+
+// ================================================================================
+// Strings & Arrays
+typedef struct CB_StringView CB_StringView;
+struct CB_StringView {
+ u8 *data;
+ int64_t length;
+};
+
+typedef struct CB_StringBuilder_Node CB_StringBuilder_Node;
+struct CB_StringBuilder_Node {
+ struct CB_StringBuilder_Node *prev;
+ struct CB_StringBuilder_Node *next;
+ CB_StringView value;
+};
+
+typedef struct CB_StringBuilder CB_StringBuilder;
+struct CB_StringBuilder {
+ struct CB_StringBuilder_Node *first;
+ struct CB_StringBuilder_Node *last;
+ int32_t total_length;
+ int32_t node_count;
+};
+
+typedef struct CB_Array CB_Array;
+struct CB_Array {
+ s64 length;
+ void *data;
+};
+
+typedef uint8_t CB_LogLevel;
+enum {
+ CB_LogLevel_None,
+ CB_LogLevel_Info,
+ CB_LogLevel_Warn,
+ CB_LogLevel_Error,
+ CB_LogLevel_COUNT,
+};
+
+#define cb_strlit(cstr) (CB_StringView) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
+#define cb_strinit(cstr) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
+#define cb_view_expand(view) (s32)(view).length, (view).data
+
+#define cb_array(CArrayLitteral) (CB_Array) { .data = (CArrayLitteral), .length = cb_arrlength((CArrayLitteral)) }
+
+#ifndef CB_DYN_DEFAULT_CAPACITY
+# define CB_DYN_DEFAULT_CAPACITY 8
+#endif
+
+#define cb_dyn_reserve(Dynarr, HowMany) cb_dyn_reserve_custom((Dynarr), (HowMany), values, count, capacity)
+#define cb_dyn_free(Dynarr) cb_dyn_free_custom((Dynarr), values, count)
+#define cb_dyn_push(Dynarr, Node) cb_dyn_push_custom((Dynarr), (Node), values, count, capacity)
+#define cb_dyn_append(Dynarr, Array, Size) cb_dyn_append_custom((Dynarr), (Array), (Size), values, count, capacity)
+
+#define cb_stack_push(Head, Nodeptr) cb_ull_push_front_custom((Head), (Head), (Nodeptr), next)
+#define cb_stack_pop(Head) (Head ? (Head = Head->next) : 0)
+
+#define cb_ull_push_front_custom(Head, Last, Nodeptr, Next) \
+ (!(Head) ? (Head) = (Nodeptr), (Last) = (Nodeptr) \
+ : ((Nodeptr)->Next = (Head), (Head) = (Nodeptr)))
+
+#define cb_queue_push(Head, Last, Nodeptr) cb_ull_push_back_custom((Head), (Last), (Nodeptr), next)
+#define cb_queue_pop(Head) (Head ? (Head = Head->next) : 0)
+
+#define cb_ull_push_back_custom(Head, Last, Nodeptr, Next) \
+ (!(Head) ? (Head) = (Last) = (Nodeptr) \
+ : ((Last) ? ((Last)->Next = (Nodeptr), (Last) = (Nodeptr)) \
+ : ((Head)->Next = (Last) = (Nodeptr))))
+
+#define cb_bll_push_front(Head, Last, Nodeptr) cb_bll_push_front_custom(Head, Last, Nodeptr, next, prev)
+#define cb_bll_push_back(Head, Last, Nodeptr) cb_bll_push_back_custom(Head, Last, Nodeptr, next, prev)
+
+#define cb_bll_push_front_custom(Head, Last, Nodeptr, Next, Prev) \
+ (!(Head) ? (Head) = (Last) = (Nodeptr) \
+ : ((Nodeptr)->Next = (Head), (Head)->Prev = (Nodeptr), \
+ (Head) = (Nodeptr)))
+
+#define cb_bll_push_back_custom(DLLNodeHead, DLLNodeLast, NodeToInsertptr, Next, Prev) \
+ (!DLLNodeHead \
+ ? DLLNodeHead = DLLNodeLast = NodeToInsertptr \
+ : (DLLNodeLast->Next = NodeToInsertptr, \
+ NodeToInsertptr->Prev = DLLNodeLast, DLLNodeLast = NodeToInsertptr))
+
+#define cb_bll_remove(Head, Last, Nodeptr) \
+ ((Head) == (Last) && (Head) == (Nodeptr) \
+ ? (Head) = (Last) = 0 \
+ : ((Last) == (Nodeptr) \
+ ? ((Last) = (Last)->prev, (Last)->next = 0) \
+ : ((Head) == (Nodeptr) \
+ ? ((Head) = (Head)->next, (Head)->prev = 0) \
+ : ((Nodeptr)->prev->next = (Nodeptr)->next, \
+ (Nodeptr)->next->prev = (Nodeptr)->prev))))
+
+#define cb_bll_pop(Head, Last) cb_bll_pop_back(Head, Last)
+
+#define cb_bll_pop_back(Head, Last) \
+ (!(Last) \
+ ? 0 \
+ : (!(Last)->prev ? (Head) = (Last) = 0 \
+ : ((Last)->prev->next = 0, (Last) = (Last)->prev)))
+
+#define cb_bll_pop_front(Head, Last) \
+ (!(Head) \
+ ? 0 \
+ : (!(Head)->next ? (Head) = (Last) = 0 \
+ : ((Head)->next->prev = 0, (Head) = (Head)->next)))
+
+#define cb_dyn_free_custom(Dynarr, Values, Count) \
+ do { \
+ free((Dynarr)->Values); \
+ (Dynarr)->Count = 0; \
+ } while (0)
+
+#define cb_dyn_reserve_custom(Dynarr, HowMany, Values, Count, Capacity) \
+ do { \
+ if (!(Dynarr)->Capacity) { \
+ (Dynarr)->Capacity = CB_DYN_DEFAULT_CAPACITY; \
+ } \
+ while ((HowMany) > (Dynarr)->Capacity) { \
+ (Dynarr)->Capacity *= 2; \
+ } \
+ (Dynarr)->Values = realloc((Dynarr)->Values, \
+ (Dynarr)->Capacity * sizeof((Dynarr)->Values[0])); \
+ cb_assert((Dynarr)->Values); \
+ } while(0)
+
+#define cb_dyn_push_custom(Dynarr, Node, Values, Count, Capacity) \
+ do { \
+ cb_dyn_reserve_custom((Dynarr), (Dynarr)->Count + 1, \
+ Values, Count, Capacity); \
+ (Dynarr)->Values[(Dynarr)->Count++] = (Node); \
+ } while(0)
+
+#define cb_dyn_append_custom(Dynarr, Array, Size, Values, Count, Capacity) \
+ do { \
+ cb_dyn_reserve((Dynarr), (Dynarr)->Count + (Size)); \
+ memcpy((Dynarr)->Values + (Dynarr)->Count, (Array), \
+ (Size) * sizeof((Dynarr)->Values[0])); \
+ (Dynarr)->Count += (Size); \
+ } while(0)
+
+static void cb_print(CB_LogLevel level, const char *fmt, ...);
+
+static char* cb_format(const char *format, ...);
+static char* cb_cstr_from_view(CB_StringView view);
+
+static CB_StringView cb_view_from_cstr(const char *cstr);
+static b8 cb_view_starts_with(const char *string, CB_StringView sv);
+static void cb_view_trim(CB_StringView *sv);
+static CB_StringBuilder cb_view_split(CB_StringView sv, char delim);
+
+static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv);
+static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other);
+static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch);
+
+static b8 cb_cli_contains(int32_t argc, char **argv, const char *target);
+
+internal char* cb_format_va(const char *format, va_list args);
+
+// ================================================================================
+// File-system interaction
+#if !OS_WINDOWS
+# include <unistd.h>
+# include <fcntl.h>
+# include <dirent.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+#endif
+
+typedef u8 CB_FileType;
+enum {
+ CB_FileType_Unknown = 0,
+ CB_FileType_Device_Disk,
+ CB_FileType_Device_Terminal,
+ CB_FileType_Directory,
+ CB_FileType_Pipe,
+ CB_FileType_Link,
+ CB_FileType_Socket,
+ CB_FileType_Regular,
+ CB_FileType_COUNT,
+};
+
+typedef u8 CB_FilePermission;
+enum {
+ CB_FilePermission_Unknown = 0,
+ CB_FilePermission_Read = 1 << 0,
+ CB_FilePermission_Write = 1 << 1,
+ CB_FilePermission_Execute = 1 << 2,
+};
+
+typedef u8 CB_AccessFlag;
+enum {
+ CB_AccessFlag_Read = 1 << 0,
+ CB_AccessFlag_Write = 1 << 1,
+ CB_AccessFlag_Append = 1 << 2,
+};
+
+typedef struct CB_FileProperties CB_FileProperties;
+struct CB_FileProperties {
+ s64 size;
+ time64 time_last_access;
+ time64 time_last_modification;
+ time64 time_last_status_change;
+ CB_FileType type;
+ union {
+ CB_FilePermission values[3];
+ struct {
+ CB_FilePermission user;
+ CB_FilePermission group;
+ CB_FilePermission other;
+ };
+ } permission;
+};
+
+typedef struct CB_FileInfo CB_FileInfo;
+struct CB_FileInfo {
+ s64 size;
+ char *path;
+ CB_FileType type;
+};
+
+typedef struct CB_FileIterator_Handle CB_FileIterator_Handle;
+#if OS_WINDOWS
+struct CB_FileIterator_Handle {
+ const char *path;
+};
+#else
+struct CB_FileIterator_Handle {
+ DIR *dir;
+ const char *path;
+ struct dirent *dir_entry;
+};
+#endif
+
+typedef struct CB_FileIterator CB_FileIterator;
+struct CB_FileIterator {
+ CB_FileType filter_allowed;
+ CB_FileIterator_Handle handle;
+};
+
+#if OS_WINDOWS
+# define CB_FILEHANDLE_INVALID INVALID_HANDLE_VALUE
+ typedef HANDLE CB_FileHandle;
+#else
+# define CB_FILEHANDLE_INVALID -1
+ typedef int32_t CB_FileHandle;
+#endif
+
+static CB_FileProperties cb_file_properties(CB_FileHandle hfile);
+static CB_StringView cb_file_read(CB_FileHandle hfile, s64 size, s64 offset);
+static u8* cb_file_memory_map(CB_FileHandle hfile, s64 size, s64 offset);
+static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_StringView content);
+static void cb_file_write_at_offset(CB_FileHandle hfile, CB_StringView content, s64 offset);
+static b8 cb_file_pointer_set_position_absolute(CB_FileHandle hfile, s64 position);
+static b8 cb_file_pointer_set_position_relative(CB_FileHandle hfile, s64 offset);
+static b8 cb_file_flush(CB_FileHandle hfile);
+static b8 cb_file_set_size(CB_FileHandle hfile, s64 new_size);
+static void cb_file_memory_unmap(u8 *file_map, s64 size);
+static void cb_file_close(CB_FileHandle hfile);
+
+static CB_FileHandle cb_filesystem_open(CB_StringView path, CB_AccessFlag flags);
+static CB_FileHandle cb_filesystem_open_temp(CB_StringView *path);
+static CB_FileProperties cb_filesystem_properties(CB_StringView path);
+static void cb_filesystem_delete(CB_StringView path);
+static b8 cb_filesystem_exists(CB_StringView path);
+static b8 cb_filesystem_rename(CB_StringView old, CB_StringView new);
+static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest);
+static b8 cb_filesystem_link_create_symbolic(CB_StringView realpath, CB_StringView linkpath);
+static b8 cb_filesystem_link_create_physical(CB_StringView realpath, CB_StringView linkpath);
+static CB_StringView cb_filesystem_link_read(CB_StringView linkpath);
+static b8 cb_filesystem_directory_create(CB_StringView path);
+static b8 cb_filesystem_directory_copy(CB_StringView path, CB_StringView new);
+static b8 cb_filesystem_directory_delete(CB_StringView path, b8 recursive);
+static CB_StringView cb_filesystem_filename_from_path(CB_StringView path);
+static CB_StringView cb_filesystem_path_canonicalize(CB_StringView path);
+
+static void cb_filesystem_iter_begin(CB_FileIterator *it, const char *rootpath);
+static b8 cb_filesystem_iter_next(CB_FileIterator *it, CB_FileInfo *output);
+static void cb_filesystem_iter_end(CB_FileIterator *it);
+
+#if !OS_WINDOWS
+internal CB_FileProperties cb_fileproperties_from_stat(struct stat *file_stat);
+#endif
+
+// ================================================================================
+// Custom assertion handler
+// TODO(lb): rename to `expect` and move to "test" extra
#ifndef _assert_break
# if OS_WINDOWS
# define _assert_break() __debugbreak()
} \
} while (0)
-struct CB_PathList {
- const char **values;
- size_t count;
- size_t capacity;
-};
-typedef struct CB_PathList CB_Cmd;
-
-struct CB_Cmd_RunArgs {
- CB_Handle stdin;
- CB_Handle stdout;
- CB_Handle stderr;
- bool async;
- bool reset;
-};
+// ================================================================================
+// Processes
+#if OS_WINDOWS
+# define CB_PROC_INVALID INVALID_HANDLE_VALUE
+ typedef HANDLE CB_ProcHandle;
+#else
+# include <sys/wait.h>
+# include <sys/stat.h>
+# define CB_PROC_INVALID -1
+ typedef pid_t CB_ProcHandle;
+#endif
-typedef struct {
+typedef struct CB_Process CB_Process;
+struct CB_Process {
CB_ProcHandle handle;
int32_t status_code;
-} CB_Process;
+};
-typedef struct {
+typedef struct CB_ProcessList CB_ProcessList;
+struct CB_ProcessList {
CB_Process *values;
size_t count;
size_t capacity;
-} CB_ProcessList;
-
-typedef uint8_t CB_AccessFlag;
-enum {
- CB_AccessFlag_Read = 1 << 0,
- CB_AccessFlag_Write = 1 << 1,
- CB_AccessFlag_Append = 1 << 2,
};
-typedef uint8_t CB_LogLevel;
-enum {
- CB_LogLevel_None,
- CB_LogLevel_Info,
- CB_LogLevel_Warn,
- CB_LogLevel_Error,
- CB_LogLevel_COUNT,
-};
-
-typedef uint8_t CB_FileType;
-enum {
- CB_FileType_Device_Block = 1 << 0,
- CB_FileType_Device_Char = 1 << 1,
- CB_FileType_Directory = 1 << 2,
- CB_FileType_Pipe = 1 << 3,
- CB_FileType_Link = 1 << 4,
- CB_FileType_Socket = 1 << 5,
- CB_FileType_Regular = 1 << 6,
-};
-
-#if OS_WINDOWS
-#else
-# include <dirent.h>
- struct CB_FileIterator_Handle {
- const char *path;
- DIR *dir;
- struct dirent *dir_entry;
- };
-#endif
-
-typedef struct {
- CB_FileType filter_allowed;
- struct CB_FileIterator_Handle handle;
-} CB_FileIterator;
-
-typedef struct {
- size_t size;
- char *path;
- CB_FileType type;
-} CB_FileInfo;
+#define cb_proclist_push(Dynarr, Value) cb_dyn_push(Dynarr, Value)
-typedef struct CB_StringView {
- const char *data;
- ssize_t length;
-} CB_StringView;
+static void cb_process_wait(CB_Process *handle);
+static void cb_proclist_wait(CB_ProcessList *procs);
-struct CB_StringBuilder_Node {
- struct CB_StringBuilder_Node *prev;
- struct CB_StringBuilder_Node *next;
- CB_StringView value;
+// ================================================================================
+// Commands
+typedef struct CB_Cmd CB_Cmd;
+struct CB_Cmd {
+ const char **values;
+ u64 count;
+ u64 capacity;
};
-typedef struct CB_StringBuilder {
- struct CB_StringBuilder_Node *first;
- struct CB_StringBuilder_Node *last;
- int32_t total_length;
- int32_t node_count;
-} CB_StringBuilder;
-
-#ifndef CB_DYN_DEFAULT_CAPACITY
-# define CB_DYN_DEFAULT_CAPACITY 8
-#endif
-
-#if COMPILER_CL
-# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) CC, "/Fe:", (Exe_name), (Builder_src), "/nologo"
-#else
-# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) CC, "-o", (Exe_name), (Builder_src)
-#endif
-#define CB_CMD_REBUILD_SELF_WITH_OPTION(Exe_name, Builder_src, ...) CB_CMD_REBUILD_SELF(Exe_name, Builder_src), __VA_ARGS__
+typedef struct CB_Cmd_RunArgs CB_Cmd_RunArgs;
+struct CB_Cmd_RunArgs {
+ CB_FileHandle stream_in;
+ CB_FileHandle stream_out;
+ CB_FileHandle stream_err;
+ b8 async;
+ b8 reset;
+};
-#define cb_strlit(cstr) (CB_StringView) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
-#define cb_strinit(cstr) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
-#define cb_arrlength(Arr) (sizeof((Arr)) / sizeof(*(Arr)))
-#define cb_dyn_reserve(Dynarr, HowMany) cb_dyn_reserve_custom((Dynarr), (HowMany), values, count, capacity)
-#define cb_dyn_free(Dynarr) cb_dyn_free_custom((Dynarr), values, count)
-#define cb_dyn_push(Dynarr, Node) cb_dyn_push_custom((Dynarr), (Node), values, count, capacity)
-#define cb_dyn_append(Dynarr, Array, Size) cb_dyn_append_custom((Dynarr), (Array), (Size), values, count, capacity)
#define cb_cmd_push(Dynarr, Value) cb_dyn_push(Dynarr, Value)
#define cb_cmd_append_dyn(Dynarr, Values, Count) cb_dyn_append((Dynarr), (Values), (Count));
#define cb_cmd_append(Dynarr, ...) cb_dyn_append((Dynarr), ((const char*[]){__VA_ARGS__}), (sizeof((const char*[]){__VA_ARGS__}) / sizeof(char*)))
-#define cb_rebuild_self(argc, argv) _cb_rebuild(argc, argv, __FILE__, NULL)
-#define cb_rebuild_self_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, NULL)
-#define cb_is_outdated(OutputFile, ...) _cb_is_outdated((OutputFile), __VA_ARGS__, 0)
-#define cb_proclist_push(Dynarr, Value) cb_dyn_push(Dynarr, Value)
-#define cb_cmd_exec(Cmd) \
- _cb_cmd_run((Cmd), \
- (struct CB_Cmd_RunArgs) { \
- .async = false, \
- .reset = true, \
+
+#define cb_cmd_exec(Cmd) \
+ _cb_cmd_run((Cmd), \
+ (CB_Cmd_RunArgs) { \
+ .async = false, \
+ .reset = true, \
})
+
#define cb_cmd_exec_with_option(Cmd, ...) \
_cb_cmd_run((Cmd), \
- (struct CB_Cmd_RunArgs) { \
+ (CB_Cmd_RunArgs) { \
.async = false, \
.reset = true, \
__VA_ARGS__ \
})
-#define cb_dyn_free_custom(Dynarr, Values, Count) \
- do { \
- free((Dynarr)->Values); \
- (Dynarr)->Count = 0; \
- } while (0)
-#define cb_dyn_reserve_custom(Dynarr, HowMany, Values, Count, Capacity) \
- do { \
- if (!(Dynarr)->Capacity) { \
- (Dynarr)->Capacity = CB_DYN_DEFAULT_CAPACITY; \
- } \
- while ((HowMany) > (Dynarr)->Capacity) { \
- (Dynarr)->Capacity *= 2; \
- } \
- (Dynarr)->Values = realloc((Dynarr)->Values, \
- (Dynarr)->Capacity * sizeof((Dynarr)->Values[0])); \
- cb_assert((Dynarr)->Values); \
- } while(0)
-#define cb_dyn_push_custom(Dynarr, Node, Values, Count, Capacity) \
- do { \
- cb_dyn_reserve_custom((Dynarr), (Dynarr)->Count + 1, \
- Values, Count, Capacity); \
- (Dynarr)->Values[(Dynarr)->Count++] = (Node); \
- } while(0)
-#define cb_dyn_append_custom(Dynarr, Array, Size, Values, Count, Capacity) \
- do { \
- cb_dyn_reserve((Dynarr), (Dynarr)->Count + (Size)); \
- memcpy((Dynarr)->Values + (Dynarr)->Count, (Array), \
- (Size) * sizeof((Dynarr)->Values[0])); \
- (Dynarr)->Count += (Size); \
- } while(0)
+static void cb_cmd_print(const CB_Cmd *cmd);
+static void cb_cmd_clear(CB_Cmd *cmd);
+internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct CB_Cmd_RunArgs args);
-#define stack_push(Head, Nodeptr) ull_push_front_custom((Head), (Head), (Nodeptr), next)
-#define stack_pop(Head) (Head ? (Head = Head->next) : 0)
-#define ull_push_front_custom(Head, Last, Nodeptr, Next) \
- (!(Head) ? (Head) = (Nodeptr), (Last) = (Nodeptr) \
- : ((Nodeptr)->Next = (Head), (Head) = (Nodeptr)))
+static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_Array build_options);
-#define queue_push(Head, Last, Nodeptr) ull_push_back_custom((Head), (Last), (Nodeptr), next)
-#define queue_pop(Head) (Head ? (Head = Head->next) : 0)
-#define ull_push_back_custom(Head, Last, Nodeptr, Next) \
- (!(Head) ? (Head) = (Last) = (Nodeptr) \
- : ((Last) ? ((Last)->Next = (Nodeptr), (Last) = (Nodeptr)) \
- : ((Head)->Next = (Last) = (Nodeptr))))
-
-#define bll_push_front(Head, Last, Nodeptr) bll_push_front_custom(Head, Last, Nodeptr, next, prev)
-#define bll_push_back(Head, Last, Nodeptr) bll_push_back_custom(Head, Last, Nodeptr, next, prev)
-#define bll_push_front_custom(Head, Last, Nodeptr, Next, Prev) \
- (!(Head) ? (Head) = (Last) = (Nodeptr) \
- : ((Nodeptr)->Next = (Head), (Head)->Prev = (Nodeptr), \
- (Head) = (Nodeptr)))
-#define bll_push_back_custom(DLLNodeHead, DLLNodeLast, NodeToInsertptr, Next, Prev) \
- (!DLLNodeHead \
- ? DLLNodeHead = DLLNodeLast = NodeToInsertptr \
- : (DLLNodeLast->Next = NodeToInsertptr, \
- NodeToInsertptr->Prev = DLLNodeLast, DLLNodeLast = NodeToInsertptr))
-#define bll_remove(Head, Last, Nodeptr) \
- ((Head) == (Last) && (Head) == (Nodeptr) \
- ? (Head) = (Last) = 0 \
- : ((Last) == (Nodeptr) \
- ? ((Last) = (Last)->prev, (Last)->next = 0) \
- : ((Head) == (Nodeptr) \
- ? ((Head) = (Head)->next, (Head)->prev = 0) \
- : ((Nodeptr)->prev->next = (Nodeptr)->next, \
- (Nodeptr)->next->prev = (Nodeptr)->prev))))
-#define bll_pop(Head, Last) bll_pop_back(Head, Last)
-#define bll_pop_back(Head, Last) \
- (!(Last) \
- ? 0 \
- : (!(Last)->prev ? (Head) = (Last) = 0 \
- : ((Last)->prev->next = 0, (Last) = (Last)->prev)))
-#define bll_pop_front(Head, Last) \
- (!(Head) \
- ? 0 \
- : (!(Head)->next ? (Head) = (Last) = 0 \
- : ((Head)->next->prev = 0, (Head) = (Head)->next)))
-
-#define cb_file_write(Handle, Content) _Generic((Content), \
- char *: cb_file_write_cstr, \
- const char *: cb_file_write_cstr, \
- CB_StringView: cb_file_write_sv \
- )((Handle), (Content))
+// ==============================================================================
+// Environment variables
+#if OS_WINDOWS
+# define MAX_ENVVAR 32767
+#endif
-static char* cb_format(const char *format, ...);
-static void cb_print(CB_LogLevel level, const char *fmt, ...);
static char* cb_getenv(const char *varname);
-static bool cb_setenv(const char *varname, const char *value);
-static void cb_cmd_print(const CB_Cmd *cmd);
-static void cb_process_wait(CB_Process *handle);
-static void cb_proclist_wait(CB_ProcessList *procs);
-static bool cb_dir_create(const char *path);
-static void cb_dir_delete(const char *path);
-static CB_Handle cb_file_open(const char *path, CB_AccessFlag permission);
-static void cb_file_close(CB_Handle fd);
-static CB_StringView cb_file_read(CB_Handle fd);
-static void cb_file_write_cstr(CB_Handle fd, const char *cstr);
-static void cb_file_write_sv(CB_Handle fd, CB_StringView sv);
-static void cb_file_delete(const char *path);
-static bool cb_file_rename(const char *path, const char *to);
-static bool cb_file_exists(const char *path);
-static bool cb_symlink_create(const char *target, const char *linkpath);
-static bool cb_cli_contains(int32_t argc, char **argv, const char *target);
-static bool cb_view_starts_with(const char *string, CB_StringView sv);
-static void cb_view_trim(CB_StringView *sv);
-static CB_StringBuilder cb_view_split(CB_StringView sv, char delim);
-static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv);
-static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other);
-
-internal void _cb_file_write_buffer(CB_Handle fd, const char *buffer, size_t size);
-internal char* cb_format_va(const char *format, va_list args);
-internal bool _cb_need_rebuild(const char *output_path, struct CB_PathList sources);
-internal void _cb_rebuild(int argc, char **argv, const char *cb_src, ...);
-internal bool _cb_is_outdated(const char *output, ...);
-internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct CB_Cmd_RunArgs args);
-internal size_t _last_occurance_of(const char *string, char ch);
-
+static b8 cb_setenv(const char *varname, const char *value);
// ==============================================================================
// Implementation
-static char* cb_format(const char *format, ...) {
- va_list args = {0};
- va_start(args, format);
- char *res = cb_format_va(format, args);
- va_end(args);
+
+// ================================================================================
+// Static arena impl
+static inline u64 cb_align_forward(u64 x, u64 align)
+{
+ assert(align > 0);
+ assert((align & (align - 1)) == 0);
+ u64 mod = x & (align - 1);
+ return (mod ? x = x + align - mod : x);
+}
+
+static void cb_arena_pop(s64 bytes)
+{
+ assert(bytes >= 0);
+ if ((u64)bytes == (u64)-1) {
+ cb_arena.head = 0;
+ } else {
+ cb_arena.head -= bytes;
+ }
+}
+
+internal void* _cb_arena_push(u64 bytes, u64 alignment)
+{
+ u64 res = cb_align_forward((u64)cb_arena.data + (u32)cb_arena.head, alignment);
+ assert(res >= (u64)cb_arena.data);
+ s32 offset = (s32)(res - ((u64)cb_arena.data + (u32)cb_arena.head));
+ assert(offset >= 0 && (u64)offset <= alignment);
+ cb_arena.head += bytes + (u32)offset;
+ assert(cb_arena.head < CB_ARENA_SIZE);
+ return (void*)res;
+}
+
+// ================================================================================
+// Compact time format
+static time64 cb_time64_from_unix(unix_time timestamp)
+{
+ static const u8 daysXmonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ time64 res = 1ULL << 63;
+ s32 year = 1970;
+ b8 is_leap_year = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
+ for (u64 secondsXyear = is_leap_year ? UNIX_LEAP_YEAR : UNIX_YEAR;
+ timestamp >= secondsXyear;
+ ++year, timestamp -= secondsXyear,
+ secondsXyear = is_leap_year ? UNIX_LEAP_YEAR : UNIX_YEAR);
+
+ res |= (u64)((s64)year & ~(1 << 27)) << 36;
+ u64 month = 1;
+ for (;;) {
+ u8 days = daysXmonth[month - 1];
+ if (month == 2 && is_leap_year) { ++days; }
+ u64 secondsXmonth = days * UNIX_DAY;
+ if (timestamp < secondsXmonth) { break; }
+ timestamp -= secondsXmonth;
+ ++month;
+ }
+ res |= month << 32;
+ res |= (timestamp / UNIX_DAY + 1) << 27;
+ timestamp %= UNIX_DAY;
+ res |= (timestamp / UNIX_HOUR) << 22;
+ timestamp %= UNIX_HOUR;
+ res |= (timestamp / UNIX_MINUTE) << 16;
+ timestamp %= UNIX_MINUTE;
+ res |= timestamp << 10;
return res;
}
-static void cb_print(CB_LogLevel level, const char *fmt, ...) {
+#if OS_WINDOWS
+static time64 time64_from_systemtime(const SYSTEMTIME *in)
+{
+ assert(in);
+ assert(in->wMilliseconds <= 999);
+ assert(in->wSecond <= 60);
+ assert(in->wMinute <= 60);
+ assert(in->wHour <= 23);
+ assert(in->wDay <= 31);
+ assert(in->wMonth >= 1 && in->wMonth <= 12);
+ s16 year = (s16)in->wYear;
+ time64 res = (year >= 0 ? 1ULL << 63 : 0);
+ res |= (u64)((year >= 0 ? year : -year) & ~(1 << 27)) << 36;
+ res |= (u64)(in->wMonth) << 32;
+ res |= (u64)(in->wDay) << 27;
+ res |= (u64)(in->wHour) << 22;
+ res |= (u64)(in->wMinute) << 16;
+ res |= (u64)(in->wSecond) << 10;
+ res |= (u64)in->wMilliseconds;
+ return res;
+}
+#endif
+
+// ================================================================================
+// Strings & Arrays
+static void cb_print(CB_LogLevel level, const char *fmt, ...)
+{
cb_assert(fmt != NULL);
cb_assert(level >= CB_LogLevel_None && level <= CB_LogLevel_COUNT);
switch (level) {
va_end(args);
}
-static char* cb_getenv(const char *varname) {
- cb_assert(varname != NULL);
+static char* cb_format(const char *format, ...)
+{
+ va_list args = {0};
+ va_start(args, format);
+ char *res = cb_format_va(format, args);
+ va_end(args);
+ return res;
+}
+
+static char* cb_cstr_from_view(CB_StringView view)
+{
+ assert(view.length > 0);
+ assert(view.data != NULL);
+ char *res = cb_arena_push_many(char, view.length + 1);
+ cb_memcopy(res, view.data, view.length);
+ res[view.length] = '\0';
+ return res;
+}
+
+static CB_StringView cb_view_from_cstr(const char *cstr)
+{
+ CB_StringView res = {0};
+ res.data = (u8*)cstr;
+ if (cstr != NULL) {
+ const char *start = cstr;
+ for (; *cstr; ++cstr);
+ res.length = cstr - start;
+ }
+ return res;
+}
+
+static b8 cb_view_starts_with(const char *string, CB_StringView sv)
+{
+ if (string == NULL || sv.length == 0 || sv.data == NULL) { return false; }
+ for (int32_t i = 0; i < sv.length; ++i) {
+ if (string[i] == 0 || string[i] != sv.data[i]) { return false; }
+ }
+ return true;
+}
+
+static void cb_view_trim(CB_StringView *sv)
+{
+ cb_assert(sv != NULL);
+ if (sv->length <= 0) { return; }
+ cb_assert(sv->data != NULL);
+ cb_assert(sv->length > 0);
+
+ for (; sv->data[0] == ' ' || sv->data[0] == '\n' || sv->data[0] == '\r' || sv->data[0] == '\t';
+ sv->length -= 1, sv->data += 1) {}
+ for (; sv->data[sv->length - 1] == ' ' || sv->data[sv->length - 1] == '\n' ||
+ sv->data[sv->length - 1] == '\r' || sv->data[sv->length - 1] == '\t';
+ sv->length -= 1) {}
+}
+
+static CB_StringBuilder cb_view_split(CB_StringView sv, char delim)
+{
+ CB_StringBuilder res = {0};
+ if (sv.data == NULL || sv.length == 0) { return res; }
+ ssize_t prev = 0;
+ for (ssize_t i = 0; i < sv.length;) {
+ if (sv.data[i] == delim) {
+ if (prev != i) {
+ cb_sb_append(&res, (CB_StringView) {
+ .data = sv.data + prev,
+ .length = (int64_t)(i - prev),
+ });
+ }
+ do {
+ prev = ++i;
+ } while (sv.data[i] == delim);
+ } else {
+ ++i;
+ }
+ }
+ if (prev != sv.length) {
+ cb_sb_append(&res, (CB_StringView) {
+ .data = sv.data + prev,
+ .length = (int64_t)(sv.length - prev),
+ });
+ }
+ cb_assert(res.node_count > 0);
+ return res;
+}
+
+static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv)
+{
+ cb_assert(sb != NULL);
+ if (sv.length == 0 || sv.data == NULL) { return; }
+ CB_StringBuilder_Node *node = cb_arena_push(CB_StringBuilder_Node);
+ cb_assert(node != NULL);
+ memset(node, 0, sizeof *node);
+ node->value = sv;
+ cb_bll_push_back(sb->first, sb->last, node);
+ sb->total_length += sv.length;
+ sb->node_count += 1;
+}
+
+static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other)
+{
+ cb_assert(sb != NULL);
+ cb_assert(sb->node_count >= 0);
+ cb_assert(sb->total_length >= 0);
+ cb_assert(other != NULL);
+ cb_assert(other->node_count >= 0);
+ cb_assert(other->total_length >= 0);
+ sb->node_count += other->node_count;
+ sb->total_length += other->total_length;
+ cb_bll_push_back(sb->first, sb->last, other->first);
+ sb->last = other->last;
+}
+
+static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch)
+{
+ CB_StringView sv = {0};
+ sv.data = malloc((uint32_t)(sb.total_length + sb.node_count));
+ sv.length = sb.total_length + sb.node_count - 1;
+ int32_t offset = 0;
+ for (struct CB_StringBuilder_Node *curr = sb.first; curr;) {
+ memcpy((char*)(sv.data + offset), curr->value.data, (uint32_t)curr->value.length);
+ offset += curr->value.length;
+ ((char*)sv.data)[offset++] = ch;
+ struct CB_StringBuilder_Node *next = curr->next;
+ free(curr);
+ curr = next;
+ }
+ ((char*)sv.data)[sv.length] = 0;
+ return sv;
+}
+
+static b8 cb_cli_contains(int32_t argc, char **argv, const char *target)
+{
+ for (int32_t i = 0; i < argc; ++i) {
+ if (!strcmp(argv[i], target)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+internal char* cb_format_va(const char *format, va_list args)
+{
+ va_list args2;
+ va_copy(args2, args);
+ size_t needed_bytes = (size_t)vsnprintf(0, 0, format, args2) + 1;
+ va_end(args2);
+
+ char *res = cb_arena_push_many(char, needed_bytes);
+ (void)vsnprintf(res, needed_bytes, format, args);
+ return res;
+}
+
+// ================================================================================
+// File-system interaction
+static CB_FileProperties cb_file_properties(CB_FileHandle hfile)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
#if OS_WINDOWS
- char *res = malloc(MAX_ENVVAR);
- if (!GetEnvironmentVariableA(varname, res, MAX_ENVVAR)) {
- free(res);
- res = 0;
+ CB_FileProperties properties = {0};
+
+ BY_HANDLE_FILE_INFORMATION file_info = {0};
+ BOOL get_info_res = GetFileInformationByHandle(hfile, &file_info);
+ assert(get_info_res == TRUE);
+
+ properties.size = (((s64)file_info.nFileSizeHigh << 32) | file_info.nFileSizeLow);
+ assert(properties.size >= 0);
+
+ if (file_info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL || file_info.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
+ properties.type = OS_FileType_Regular;
+ } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
+ properties.type = OS_FileType_Device_Block;
+ } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ properties.type = OS_FileType_Link;
+ } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ properties.type = OS_FileType_Directory;
+ } else {
+ unreachable();
}
+
+ assert((((u64)file_info.ftLastAccessTime.dwHighDateTime << 32) | file_info.ftLastAccessTime.dwLowDateTime) <= 0x8000000000000000);
+ assert((((u64)file_info.ftLastWriteTime.dwHighDateTime << 32) | file_info.ftLastWriteTime.dwLowDateTime) <= 0x8000000000000000);
+ SYSTEMTIME last_access_time = {0}, last_write_time = {0};
+ res = FileTimeToSystemTime(&file_info.ftLastAccessTime, &last_access_time);
+ assert(res == TRUE);
+ res = FileTimeToSystemTime(&file_info.ftLastWriteTime, &last_write_time);
+ assert(res == TRUE);
+
+ properties.time_last_access = time64_from_systemtime(&last_access_time);
+ properties.time_last_status_change = time64_from_systemtime(&last_write_time);
+ properties.time_last_modification = properties.time_last_status_change;
+
+ return properties;
+#else
+ struct stat file_stat = {0};
+ s32 stat_res = fstat(hfile, &file_stat);
+ assert(stat_res == 0);
+ return cb_fileproperties_from_stat(&file_stat);
+#endif
+}
+
+static CB_StringView cb_file_read(CB_FileHandle hfile, s64 size, s64 offset)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(size > 0);
+ assert(offset >= 0);
+ assert(offset < size);
+
+ CB_StringView result = {0};
+ u8 *buffer = cb_arena_push_many(u8, size);
+
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ s64 bytes_read = pread(hfile, buffer, (u64)size, offset);
+ assert(bytes_read != -1);
+ cb_arena_pop(size - bytes_read);
+ result.data = (u8*)buffer;
+ result.length = bytes_read;
+ return result;
+#endif
+}
+
+static u8* cb_file_memory_map(CB_FileHandle hfile, s64 size, s64 offset)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(size > 0);
+ assert(offset >= 0);
+ assert(offset < size);
+
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ u8 *res = mmap(NULL, (u64)size, O_RDWR, MAP_SHARED, hfile, offset);
+ assert(res != MAP_FAILED);
return res;
+#endif
+}
+
+static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_StringView content)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(content.length > 0);
+ assert(content.data != NULL);
+
+#if OS_WINDOWS
+ // TODO(lb): win32
#else
- return getenv(varname);
+ CB_Scratch scratch = cb_scratch_begin();
+ s64 bytes_wrote = write(hfile, cb_cstr_from_view(content), (u64)content.length);
+ cb_scratch_end(scratch);
+ assert(bytes_wrote == content.length);
+#endif
+}
+
+static void cb_file_write_at_offset(CB_FileHandle hfile, CB_StringView content, s64 offset)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(content.length > 0);
+ assert(content.data != NULL);
+ assert(offset >= 0);
+
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ CB_Scratch scratch = cb_scratch_begin();
+ s64 bytes_wrote = pwrite(hfile, cb_cstr_from_view(content), (u64)content.length, offset);
+ cb_scratch_end(scratch);
+ assert(bytes_wrote <= content.length);
+#endif
+}
+
+static b8 cb_file_pointer_set_position_absolute(CB_FileHandle hfile, s64 position)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(position > 0);
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ off_t res = lseek(hfile, position, SEEK_SET);
+ return res == 0;
+#endif
+}
+
+static b8 cb_file_pointer_set_position_relative(CB_FileHandle hfile, s64 offset)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ off_t res = lseek(hfile, offset, SEEK_CUR);
+ return res == 0;
#endif
}
-static bool cb_setenv(const char *varname, const char *value) {
- cb_assert(varname != NULL);
- cb_assert(value != NULL);
+static b8 cb_file_flush(CB_FileHandle hfile)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
#if OS_WINDOWS
- return SetEnvironmentVariableA(varname, value);
+ // TODO(lb): win32
#else
- return !setenv(varname, value, true);
+ s32 res = fsync(hfile);
+ return res == 0;
#endif
}
-static void cb_cmd_print(const CB_Cmd *cmd) {
- cb_assert(cmd != NULL);
- cb_print(CB_LogLevel_Info, "Command: `");
- for (size_t i = 0; i < cmd->count; ++i) {
- printf("%s ", cmd->values[i]);
- }
- printf("\b`\n");
+static b8 cb_file_set_size(CB_FileHandle hfile, s64 new_size)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+ assert(new_size >= 0);
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ s32 res = ftruncate(hfile, new_size);
+ return res == 0;
+#endif
}
-static void cb_process_wait(CB_Process *proc) {
- cb_assert(proc != NULL);
- if (proc->handle == CB_PROC_INVALID) {
- cb_print(CB_LogLevel_Error, "Waiting on invalid process handle\n");
- cb_assert(false);
- }
-
+static void cb_file_memory_unmap(u8 *file_map, s64 size)
+{
+ assert(file_map != NULL);
+ assert(size > 0);
#if OS_WINDOWS
- WaitForSingleObject(proc->handle, INFINITE);
- GetExitCodeProcess(proc->handle, (LPDWORD)&proc->status_code);
- CloseHandle(proc->handle);
+ // TODO(lb): win32
#else
- int32_t status = 0;
- int32_t wait_res = waitpid(proc->handle, &status, 0);
- cb_assert(wait_res == proc->handle);
- if (WIFEXITED(status)) {
- proc->status_code = WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- proc->status_code = WTERMSIG(status);
- } else {
- proc->status_code = 0;
- }
+ s32 res = munmap(file_map, (u64)size);
+ assert(res == 0);
#endif
}
-static void cb_proclist_wait(CB_ProcessList *procs) {
- cb_assert(procs != NULL);
- if (procs->count == 0) { return; }
- for (size_t i = 0; i < procs->count; ++i) {
- cb_process_wait(&procs->values[i]);
- }
- cb_dyn_free(procs);
+static void cb_file_close(CB_FileHandle hfile)
+{
+ assert(hfile != CB_FILEHANDLE_INVALID);
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ s32 res = close(hfile);
+ assert(res == 0);
+#endif
}
-static CB_Handle cb_file_open(const char *path, CB_AccessFlag permission) {
- cb_assert(path != NULL);
+static CB_FileHandle cb_filesystem_open(CB_StringView path, CB_AccessFlag flags)
+{
+ assert(path.length > 0);
+ assert(path.data != NULL);
#if OS_WINDOWS
- SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), 0, 0};
- DWORD access_flags = 0;
- DWORD share_mode = 0;
- DWORD creation_disposition = OPEN_EXISTING;
-
- if(permission & CB_AccessFlag_Read) { access_flags |= GENERIC_READ; }
- if(permission & CB_AccessFlag_Write) {
- access_flags |= GENERIC_WRITE;
- creation_disposition = CREATE_ALWAYS;
- }
- if(permission & CB_AccessFlag_Append) {
- access_flags |= FILE_APPEND_DATA;
- creation_disposition = OPEN_ALWAYS;
- }
- return CreateFileA(path, access_flags,
- share_mode, &security_attributes,
- creation_disposition,
- FILE_ATTRIBUTE_NORMAL, 0);
+ // TODO(lb): win32
#else
- int32_t flags = O_CREAT;
- if ((permission & CB_AccessFlag_Read) && ((permission & CB_AccessFlag_Write) ||
- (permission & CB_AccessFlag_Append))) {
- flags |= O_RDWR;
+ s32 mode = O_CREAT;
+ if ((flags & CB_AccessFlag_Read) && ((flags & CB_AccessFlag_Write) || (flags & CB_AccessFlag_Append))) {
+ mode |= O_RDWR;
} else {
- if (permission & CB_AccessFlag_Read) {
- flags |= O_RDONLY;
- } else if ((permission & CB_AccessFlag_Write) ||
- (permission & CB_AccessFlag_Append)) {
- flags |= O_WRONLY;
+ if (flags & CB_AccessFlag_Read) {
+ mode |= O_RDONLY;
+ } else if ((flags & CB_AccessFlag_Write) || (flags & CB_AccessFlag_Append)) {
+ mode |= O_WRONLY;
}
}
- if (permission & CB_AccessFlag_Append) { flags |= O_APPEND; }
- int32_t res = open(path, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (res == -1) { return CB_HANDLE_INVALID; }
- return (CB_Handle)res;
+ if (flags & CB_AccessFlag_Append) { mode |= O_APPEND; }
+ CB_Scratch scratch = cb_scratch_begin();
+ int32_t res = open(cb_cstr_from_view(path), mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ cb_scratch_end(scratch);
+ if (res == -1) { return CB_FILEHANDLE_INVALID; }
+ return (CB_FileHandle)res;
#endif
}
-static void cb_file_close(CB_Handle fd) {
- if (fd == CB_HANDLE_INVALID) {
- cb_print(CB_LogLevel_Error, "Closing invalid handle\n");
- cb_assert(false);
- }
-
+static CB_FileHandle cb_filesystem_open_temp(CB_StringView *path)
+{
+ assert(path != NULL);
#if OS_WINDOWS
- FlushFileBuffers(fd);
- CloseHandle(fd);
+ // TODO(lb): win32
#else
- close(fd);
+ path->length = cb_arrlength("/tmp/XXXXXX");
+ char *bytes = cb_arena_push_many(char, path->length);
+ cb_memcopy(bytes, "/tmp/XXXXXX", path->length);
+ path->data = (u8*)(bytes);
+ CB_FileHandle res = mkstemp(bytes);
+ assert(res != -1);
+ return res;
#endif
}
-static CB_StringView cb_file_read(CB_Handle fd) {
- if (fd == CB_HANDLE_INVALID) {
- cb_print(CB_LogLevel_Warn, "Reading from invalid handle\n");
- return (CB_StringView) {0};
- }
+static CB_FileProperties cb_filesystem_properties(CB_StringView path)
+{
+ assert(path.length > 0);
+ assert(path.data != NULL);
#if OS_WINDOWS
- LARGE_INTEGER file_size = {0};
- GetFileSizeEx(fd, &file_size);
-
- LONGLONG size = file_size.QuadPart;
- LONGLONG total_read = 0;
- char *buffer = malloc((size_t)(size + 1));
- ReadFile(fd, buffer, (DWORD)size, NULL, NULL);
- buffer[size] = 0;
- return (CB_StringView) {
- .data = buffer,
- .length = size,
- };
+ // TODO(lb): get file properties from path on win32
+ CB_FileProperties res = {0};
+ return res;
#else
struct stat file_stat = {0};
- if (fstat(fd, &file_stat) == -1 || file_stat.st_size <= 0) { return (CB_StringView) {0}; }
- char *res = malloc(file_stat.st_size + 1);
- if (pread(fd, res, file_stat.st_size, 0) == -1) { return (CB_StringView) {0}; }
- res[file_stat.st_size] = 0;
- return (CB_StringView) {
- .data = res,
- .length = file_stat.st_size,
- };
+ CB_Scratch scratch = cb_scratch_begin();
+ s32 stat_res = stat(cb_cstr_from_view(path), &file_stat);
+ cb_scratch_end(scratch);
+ assert(stat_res == 0);
+ return cb_fileproperties_from_stat(&file_stat);
#endif
}
-static void cb_file_write_sv(CB_Handle fd, CB_StringView sv) {
- _cb_file_write_buffer(fd, sv.data, sv.length);
+static void cb_filesystem_delete(CB_StringView path)
+{
+ assert(path.length > 0);
+ assert(path.data != NULL);
+#if OS_WINDOWS
+ // TODO(lb): implement file delete on win32
+#else
+ CB_Scratch scratch = cb_scratch_begin();
+ unlink(cb_cstr_from_view(path));
+ cb_scratch_end(scratch);
+#endif
}
-static void cb_file_write_cstr(CB_Handle fd, const char *buffer) {
- if (fd == CB_HANDLE_INVALID) {
- cb_print(CB_LogLevel_Error, "Writing to invalid handle\n");
- assert(false);
- }
- size_t buffsize = strlen(buffer);
- _cb_file_write_buffer(fd, buffer, buffsize);
+static b8 cb_filesystem_exists(CB_StringView path)
+{
+#if OS_WINDOWS
+ // TODO(lb): win32
+# define F_OK 0
+# define access _access
+#endif
+ CB_Scratch scratch = cb_scratch_begin();
+ b8 res = (access(cb_cstr_from_view(path), F_OK) == 0);
+ cb_scratch_end(scratch);
+ return res;
}
-static bool cb_dir_create(const char *path) {
- cb_assert(path != NULL);
- int32_t mkdir_res = _cb_platform_mkdir(path);
- if (mkdir_res < 0 && errno == ENOENT) {
- size_t parent_end = _last_occurance_of(path, '/');
- if (!parent_end) { return false; }
- char *parent = (char *)malloc(parent_end + 1);
- memcpy(parent, path, parent_end);
- parent[parent_end] = 0;
- cb_dir_create(parent);
- free(parent);
- _cb_platform_mkdir(path);
- }
- return !mkdir_res;
+static b8 cb_filesystem_rename(CB_StringView old, CB_StringView new)
+{
+#if OS_WINDOWS
+ // TODO(lb): implement file rename on win32
+#else
+ CB_Scratch scratch = cb_scratch_begin();
+ char *old_cstr = cb_cstr_from_view(old);
+ char *new_cstr = cb_cstr_from_view(new);
+ b8 res = (rename(old_cstr, new_cstr) == 0);
+ cb_scratch_end(scratch);
+ return res;
+#endif
}
-static void cb_dir_delete(const char *path) {
+static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest)
+{
+ assert(bytes_to_copy > 0);
+ assert(offset_source >= 0);
+ assert(offset_dest >= 0);
+ assert(cb_filesystem_exists(path_source));
+ if (!cb_filesystem_exists(path_dest)) { assert(offset_dest == 0); }
#if OS_WINDOWS
- _rmdir(path);
+ // TODO(lb): win32
#else
- rmdir(path);
+ CB_Scratch scratch = cb_scratch_begin();
+ s32 src = open(cb_cstr_from_view(path_source), O_RDONLY, 0);
+ s32 dest = open(cb_cstr_from_view(path_dest), O_WRONLY | O_CREAT, 0644);
+ cb_scratch_end(scratch);
+ assert(src != -1);
+ assert(dest != -1);
+
+ s64 bytes_copied = copy_file_range(src, &offset_source, dest, &offset_dest, (u64)bytes_to_copy, 0);
+ assert(bytes_copied != -1);
+
+ struct stat stat_src = {0};
+ s32 res_fstat = fstat(src, &stat_src);
+ assert(res_fstat == 0);
+ fchmod(dest, stat_src.st_mode & 0777);
+
+ fdatasync(dest);
+ close(src);
+ close(dest);
+ return bytes_copied == bytes_to_copy;
#endif
}
-static void cb_file_delete(const char *path) {
+static b8 cb_filesystem_link_create_symbolic(CB_StringView realpath, CB_StringView linkpath)
+{
+ assert(cb_filesystem_exists(realpath));
+ assert(!cb_filesystem_exists(linkpath));
#if OS_WINDOWS
- _unlink(path);
+ // TODO(lb): create symlink on win32
+ return false;
#else
- unlink(path);
+ CB_Scratch scratch = cb_scratch_begin();
+ s32 res = symlink(cb_cstr_from_view(realpath), cb_cstr_from_view(linkpath));
+ cb_scratch_end(scratch);
+ return res == 0;
#endif
}
-static bool cb_file_rename(const char *path, const char *to) {
+static b8 cb_filesystem_link_create_physical(CB_StringView realpath, CB_StringView linkpath)
+{
+ assert(cb_filesystem_properties(realpath).type != CB_FileType_Directory);
+ assert(!cb_filesystem_exists(linkpath));
#if OS_WINDOWS
- return MoveFileExA(path, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
+ // TODO(lb): win32
#else
- return !rename(path, to);
+ CB_Scratch scratch = cb_scratch_begin();
+ s32 res = link(cb_cstr_from_view(realpath), cb_cstr_from_view(linkpath));
+ cb_scratch_end(scratch);
+ return res == 0;
#endif
}
-static bool cb_file_exists(const char *path) {
+static CB_StringView cb_filesystem_link_read(CB_StringView linkpath)
+{
+ assert(cb_filesystem_exists(linkpath));
+ assert(cb_filesystem_properties(linkpath).type == CB_FileType_Link);
+ CB_StringView res = {0};
#if OS_WINDOWS
-# define F_OK 0
-# define access _access
+ // TODO(lb): win32
+#else
+ s64 approx_length = 1024;
+ char *buffer = cb_arena_push_many(char, approx_length);
+ CB_Scratch scratch = cb_scratch_begin();
+ s64 length = readlink(cb_cstr_from_view(linkpath), buffer, (u64)approx_length);
+ assert(length > 0);
+ cb_scratch_end(scratch);
+ cb_arena_pop(approx_length - length);
+ res.length = length;
+ res.data = (u8*)buffer;
#endif
- return access(path, F_OK) == 0;
+ return res;
}
-static bool cb_symlink_create(const char *target, const char *linkpath) {
- cb_assert(target != NULL);
- cb_assert(linkpath != NULL);
-
+static b8 cb_filesystem_directory_create(CB_StringView path)
+{
+ assert(!cb_filesystem_exists(path));
#if OS_WINDOWS
+ // TODO(lb): win32
#else
- int32_t res = symlink(target, linkpath);
+ CB_Scratch scratch = cb_scratch_begin();
+ s32 res = mkdir(cb_cstr_from_view(path), (S_IRWXU) | (S_IRWXG) | (S_IROTH | S_IXOTH));
+ cb_scratch_end(scratch);
return res == 0;
#endif
}
-static void cb_file_iter_begin(CB_FileIterator *it, const char *rootpath) {
+static b8 cb_filesystem_directory_copy(CB_StringView dirpath, CB_StringView new)
+{
+ assert(cb_filesystem_exists(dirpath));
+ assert(cb_filesystem_properties(dirpath).type == CB_FileType_Directory);
+ assert(!cb_filesystem_exists(new));
+ // TODO(lb): directory copy
+ return false;
+}
+
+static b8 cb_filesystem_directory_delete(CB_StringView path, b8 recursive)
+{
+ assert(cb_filesystem_exists(path));
+ assert(cb_filesystem_properties(path).type == CB_FileType_Directory);
+ // TODO(lb): directory delete
+ return false;
+}
+
+static CB_StringView cb_filesystem_filename_from_path(CB_StringView path)
+{
+ assert(cb_filesystem_exists(path));
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ const char *fullname = basename(cb_cstr_from_view(path));
+ assert(fullname != NULL);
+ CB_StringView res = cb_view_from_cstr(fullname);
+ return res;
+#endif
+}
+
+static CB_StringView cb_filesystem_path_canonicalize(CB_StringView path)
+{
+ assert(cb_filesystem_exists(path));
+#if OS_WINDOWS
+ // TODO(lb): win32
+#else
+ CB_Scratch scratch = cb_scratch_begin();
+ char *cstr_fullpath = realpath(cb_cstr_from_view(path), NULL);
+ assert(cstr_fullpath != NULL);
+ cb_scratch_end(scratch);
+ CB_StringView res = cb_view_from_cstr(cstr_fullpath);
+ return res;
+#endif
+}
+
+static void cb_filesystem_iter_begin(CB_FileIterator *it, const char *rootpath)
+{
memset(&it->handle, 0, sizeof it->handle);
#if OS_WINDOWS
// TODO(lb): file iteration on win32
#endif
}
-static bool cb_file_iter_next(CB_FileIterator *it, CB_FileInfo *output) {
+static b8 cb_filesystem_iter_next(CB_FileIterator *it, CB_FileInfo *output)
+{
static const char *const currdir = ".";
static const char *const parentdir = "..";
#if OS_WINDOWS
// TODO(lb): file iteration on win32
+ return false;
#else
struct dirent *entry = NULL;
char *filepath = NULL;
if (!filename) { return false; }
int32_t filepath_size = snprintf(NULL, 0, "%s/%s", it->handle.path, filename) + 1;
- filepath = malloc(filepath_size);
+ filepath = malloc((uint32_t)filepath_size);
if (!filepath) { return false; }
- snprintf(filepath, filepath_size, "%s/%s", it->handle.path, filename);
+ snprintf(filepath, (uint32_t)filepath_size, "%s/%s", it->handle.path, filename);
struct stat file_stat = {0};
if (stat(filepath, &file_stat) != 0) {
CB_FileType filetype = 0;
switch (file_stat.st_mode & S_IFMT) {
- case S_IFBLK: filetype = CB_FileType_Device_Block; break;
- case S_IFCHR: filetype = CB_FileType_Device_Char; break;
- case S_IFDIR: filetype = CB_FileType_Directory; break;
- case S_IFIFO: filetype = CB_FileType_Pipe; break;
- case S_IFLNK: filetype = CB_FileType_Link; break;
- case S_IFSOCK: filetype = CB_FileType_Socket; break;
- case S_IFREG: filetype = CB_FileType_Regular; break;
+ case S_IFBLK: filetype = CB_FileType_Device_Disk; break;
+ case S_IFCHR: filetype = CB_FileType_Device_Terminal; break;
+ case S_IFDIR: filetype = CB_FileType_Directory; break;
+ case S_IFIFO: filetype = CB_FileType_Pipe; break;
+ case S_IFLNK: filetype = CB_FileType_Link; break;
+ case S_IFSOCK: filetype = CB_FileType_Socket; break;
+ case S_IFREG: filetype = CB_FileType_Regular; break;
}
if (!(it->filter_allowed & filetype)) {
} else {
output->path = filepath;
output->type = filetype;
- output->size = file_stat.st_size;
+ output->size = (uint32_t)file_stat.st_size;
}
return true;
}
#endif
}
-static void cb_file_iter_end(CB_FileIterator *it) {
+static void cb_filesystem_iter_end(CB_FileIterator *it)
+{
#if OS_WINDOWS
// TODO(lb): file iteration on win32
#else
#endif
}
-static bool cb_cli_contains(int32_t argc, char **argv, const char *target) {
- for (int32_t i = 0; i < argc; ++i) {
- if (!strcmp(argv[i], target)) {
- return true;
- }
- }
- return false;
-}
-
-static bool cb_view_starts_with(const char *string, CB_StringView sv) {
- if (string == NULL || sv.length == 0 || sv.data == NULL) { return false; }
- for (int32_t i = 0; i < sv.length; ++i) {
- if (string[i] == 0 || string[i] != sv.data[i]) { return false; }
- }
- return true;
-}
-
-static void cb_view_trim(CB_StringView *sv) {
- cb_assert(sv != NULL);
- if (sv->length <= 0) { return; }
- cb_assert(sv->data != NULL);
- cb_assert(sv->length > 0);
-
- for (; sv->data[0] == ' ' || sv->data[0] == '\n' || sv->data[0] == '\r' || sv->data[0] == '\t';
- sv->length -= 1, sv->data += 1) {}
- for (; sv->data[sv->length - 1] == ' ' || sv->data[sv->length - 1] == '\n' ||
- sv->data[sv->length - 1] == '\r' || sv->data[sv->length - 1] == '\t';
- sv->length -= 1) {}
-}
-
-static CB_StringBuilder cb_view_split(CB_StringView sv, char delim) {
- CB_StringBuilder res = {0};
- if (sv.data == NULL || sv.length == 0) { return res; }
- size_t prev = 0;
- for (size_t i = 0; i < sv.length;) {
- if (sv.data[i] == delim) {
- if (prev != i) {
- cb_sb_append(&res, (CB_StringView) {
- .data = sv.data + prev,
- .length = i - prev,
- });
- }
- do {
- prev = ++i;
- } while (sv.data[i] == delim);
- } else {
- ++i;
- }
- }
- if (prev != sv.length) {
- cb_sb_append(&res, (CB_StringView) {
- .data = sv.data + prev,
- .length = sv.length - prev,
- });
+#if !OS_WINDOWS
+internal CB_FileProperties cb_fileproperties_from_stat(struct stat *file_stat)
+{
+ CB_FileProperties res = {0};
+ res.size = file_stat->st_size;
+ res.time_last_access = cb_time64_from_unix((unix_time)file_stat->st_atime);
+ res.time_last_modification = cb_time64_from_unix((unix_time)file_stat->st_mtime);
+ res.time_last_status_change = cb_time64_from_unix((unix_time)file_stat->st_ctime);
+ switch (file_stat->st_mode & S_IFMT) {
+ case S_IFBLK: res.type = CB_FileType_Device_Disk; break;
+ case S_IFCHR: res.type = CB_FileType_Device_Terminal; break;
+ case S_IFDIR: res.type = CB_FileType_Directory; break;
+ case S_IFIFO: res.type = CB_FileType_Pipe; break;
+ case S_IFLNK: res.type = CB_FileType_Link; break;
+ case S_IFSOCK: res.type = CB_FileType_Socket; break;
+ case S_IFREG: res.type = CB_FileType_Regular; break;
}
- cb_assert(res.node_count > 0);
- return res;
-}
-
-static CB_StringView cb_view_from_cstr(const char *cstr) {
- CB_StringView res = {0};
- res.data = cstr;
- res.length = strlen(cstr);
+ res.permission.user = CB_FilePermission_Unknown;
+ if (file_stat->st_mode & S_IRUSR) { res.permission.user |= CB_FilePermission_Read; }
+ if (file_stat->st_mode & S_IWUSR) { res.permission.user |= CB_FilePermission_Write; }
+ if (file_stat->st_mode & S_IXUSR) { res.permission.user |= CB_FilePermission_Execute; }
+ res.permission.group = CB_FilePermission_Unknown;
+ if (file_stat->st_mode & S_IRGRP) { res.permission.group |= CB_FilePermission_Read; }
+ if (file_stat->st_mode & S_IWGRP) { res.permission.group |= CB_FilePermission_Write; }
+ if (file_stat->st_mode & S_IXGRP) { res.permission.group |= CB_FilePermission_Execute; }
+ res.permission.other = CB_FilePermission_Unknown;
+ if (file_stat->st_mode & S_IROTH) { res.permission.other |= CB_FilePermission_Read; }
+ if (file_stat->st_mode & S_IWOTH) { res.permission.other |= CB_FilePermission_Write; }
+ if (file_stat->st_mode & S_IXOTH) { res.permission.other |= CB_FilePermission_Execute; }
return res;
}
+#endif
-static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv) {
- cb_assert(sb != NULL);
- if (sv.length == 0 || sv.data == NULL) { return; }
- struct CB_StringBuilder_Node *node = malloc(sizeof *node);
- cb_assert(node != NULL);
- memset(node, 0, sizeof *node);
- node->value = sv;
- bll_push_back(sb->first, sb->last, node);
- sb->total_length += sv.length;
- sb->node_count += 1;
-}
-
-static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other) {
- cb_assert(sb != NULL);
- cb_assert(sb->node_count >= 0);
- cb_assert(sb->total_length >= 0);
- cb_assert(other != NULL);
- cb_assert(other->node_count >= 0);
- cb_assert(other->total_length >= 0);
- sb->node_count += other->node_count;
- sb->total_length += other->total_length;
- bll_push_back(sb->first, sb->last, other->first);
- sb->last = other->last;
-}
-
-static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch) {
- CB_StringView sv = {0};
- sv.data = malloc(sb.total_length + sb.node_count);
- sv.length = sb.total_length + sb.node_count - 1;
- int32_t offset = 0;
- for (struct CB_StringBuilder_Node *curr = sb.first; curr;) {
- memcpy((char*)(sv.data + offset), curr->value.data, curr->value.length);
- offset += curr->value.length;
- ((char*)sv.data)[offset++] = ch;
- struct CB_StringBuilder_Node *next = curr->next;
- free(curr);
- curr = next;
+// ================================================================================
+// Processes
+static void cb_process_wait(CB_Process *proc)
+{
+ cb_assert(proc != NULL);
+ if (proc->handle == CB_PROC_INVALID) {
+ cb_print(CB_LogLevel_Error, "Waiting on invalid process handle\n");
+ cb_assert(false);
}
- ((char*)sv.data)[sv.length] = 0;
- return sv;
-}
-internal void _cb_file_write_buffer(CB_Handle fd, const char *buffer, size_t size) {
- cb_assert(fd != CB_HANDLE_INVALID);
- cb_assert(buffer != NULL);
- cb_assert(size > 0);
- while (!buffer[size - 1]) { size -= 1; }
#if OS_WINDOWS
- uint64_t to_write = buffsize;
- uint64_t total_write = 0;
- char *ptr = buffer;
- for(;total_write < to_write;) {
- uint64_t amount64 = to_write - total_write;;
- uint32_t amount32 = amount64 > 0xFFFFFFFF ? 0xFFFFFFFF : (uint32_t)amount64;
- DWORD bytes_written = 0;
- WriteFile(fd, ptr + total_write, amount32, &bytes_written, 0);
- total_write += bytes_written;
- if(bytes_written != amount32) { break; }
- }
+ WaitForSingleObject(proc->handle, INFINITE);
+ GetExitCodeProcess(proc->handle, (LPDWORD)&proc->status_code);
+ CloseHandle(proc->handle);
#else
- write(fd, buffer, size);
+ int32_t status = 0;
+ int32_t wait_res = waitpid(proc->handle, &status, 0);
+ cb_assert(wait_res == proc->handle);
+ if (WIFEXITED(status)) {
+ proc->status_code = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ proc->status_code = WTERMSIG(status);
+ } else {
+ proc->status_code = 0;
+ }
#endif
}
-internal bool _cb_is_outdated(const char *output, ...) {
- struct CB_PathList sources = {0};
- va_list args;
- va_start(args, output);
- for (;;) {
- char *path = va_arg(args, char*);
- if (!path) { break; }
- cb_dyn_push(&sources, path);
+static void cb_proclist_wait(CB_ProcessList *procs)
+{
+ cb_assert(procs != NULL);
+ if (procs->count == 0) { return; }
+ for (size_t i = 0; i < procs->count; ++i) {
+ cb_process_wait(&procs->values[i]);
}
- va_end(args);
- return _cb_need_rebuild(output, sources);
+ cb_dyn_free(procs);
}
+// ================================================================================
+// Commands
+static void cb_cmd_print(const CB_Cmd *cmd)
+{
+ cb_assert(cmd != NULL);
+ cb_print(CB_LogLevel_Info, "Command: `");
+ for (size_t i = 0; i < cmd->count; ++i) {
+ printf("%s ", cmd->values[i]);
+ }
+ printf("\b`\n");
+}
-internal char* cb_format_va(const char *format, va_list args) {
- va_list args2;
- va_copy(args2, args);
- size_t needed_bytes = (size_t)vsnprintf(0, 0, format, args2) + 1;
- va_end(args2);
-
- char *res = malloc(needed_bytes);
- (void)vsnprintf(res, needed_bytes, format, args);
- return res;
+static void cb_cmd_clear(CB_Cmd *cmd)
+{
+ free(cmd->values);
+ cmd->capacity = cmd->count = 0;
+ cmd->values = NULL;
}
-internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct CB_Cmd_RunArgs args) {
+internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct CB_Cmd_RunArgs args)
+{
CB_Process res = {0};
#if OS_WINDOWS
STARTUPINFOA si = {0};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = args.stdin ? args.stdin : GetStdHandle(STD_INPUT_HANDLE);
- si.hStdOutput = args.stdout ? args.stdout : GetStdHandle(STD_OUTPUT_HANDLE);
- si.hStdError = args.stderr ? args.stderr : GetStdHandle(STD_ERROR_HANDLE);
+ si.hStdInput = args.stream_in ? args.stream_in : GetStdHandle(STD_INPUT_HANDLE);
+ si.hStdOutput = args.stream_out ? args.stream_out : GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = args.stream_err ? args.stream_err : GetStdHandle(STD_ERROR_HANDLE);
PROCESS_INFORMATION pi = {0};
if (!CreateProcessA(0, cmdline, 0, 0, TRUE, 0, 0, 0, &si, &pi)) {
cmd->values[0], errno, strerror(errno));
exit(-1);
} else if (!res.handle) {
- if (args.stdout) { dup2(args.stdout, STDOUT_FILENO); }
- if (args.stderr) { dup2(args.stderr, STDERR_FILENO); }
- if (args.stdin) {
- lseek(args.stdin, 0, SEEK_SET);
- dup2(args.stdin, STDIN_FILENO);
+ if (args.stream_out) { dup2(args.stream_out, STDOUT_FILENO); }
+ if (args.stream_err) { dup2(args.stream_err, STDERR_FILENO); }
+ if (args.stream_in) {
+ lseek(args.stream_in, 0, SEEK_SET);
+ dup2(args.stream_in, STDIN_FILENO);
}
CB_Cmd _cmd = {0};
return res;
}
-internal void _cb_rebuild(int argc, char **argv, const char *builder_src, ...) {
- cb_assert(argc >= 1);
- char *exe_name = argv[0];
-
- struct CB_PathList sources = {0};
- cb_dyn_push(&sources, builder_src);
- va_list args;
- va_start(args, builder_src);
- for (;;) {
- char *path = va_arg(args, char*);
- if (!path) { break; }
- cb_dyn_push(&sources, path);
- }
- va_end(args);
-
- if (!_cb_need_rebuild(exe_name, sources)) {
- cb_dyn_free(&sources);
- return;
+static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_Array build_options)
+{
+ assert(argc >= 1);
+ assert(argv != NULL);
+ assert(sources.length >= 1);
+ assert(sources.data != NULL);
+ assert(build_options.length >= 0);
+ if (build_options.length > 0) { assert(build_options.data != NULL); }
+
+ b8 should_rebuild = false;
+ CB_StringView executable = cb_view_from_cstr(argv[0]);
+ cb_view_trim(&executable);
+ time64 last_edit_executable = cb_filesystem_properties(executable).time_last_modification;
+ CB_StringView *str_sources = sources.data;
+ for (s64 i = 0; i < sources.length; ++i) {
+ time64 last_edit_source = cb_filesystem_properties(str_sources[i]).time_last_modification;
+ if (last_edit_executable < last_edit_source) {
+ should_rebuild = true;
+ break;
+ }
}
- cb_print(CB_LogLevel_Info, "rebuilding %s\n", exe_name);
+ if (!should_rebuild) { return; }
#if OS_WINDOWS
- char *exe_name_old = cb_format("%s.old", exe_name);
- if (!cb_file_rename(exe_name, exe_name_old)) {
- cb_print(CB_LogLevel_Info, "File rename failed: %s -> %s\n",
- exe_name, exe_name_old);
- exit(-1);
+ {
+ CB_Scratch scratch = cb_scratch_begin();
+ CB_StringView executable_old = cb_view_from_cstr(cb_format("%.*s.old", executable));
+ if (!cb_file_rename(executable, executable_old)) {
+ cb_print(CB_LogLevel_Info, "File rename failed: %.*s -> %.*s\n", cb_view_expand(executable), cb_view_expand(executable_old));
+ exit(-1);
+ }
+ cb_scratch_end(scratch);
}
#endif
CB_Cmd cmd = {0};
- cb_cmd_append(&cmd, CB_CMD_REBUILD_SELF(exe_name, builder_src));
- cb_print(CB_LogLevel_Info, "running: `");
- for (size_t i = 0; i < cmd.count; ++i) {
- printf("%s ", cmd.values[i]);
+ cb_cmd_push(&cmd, CC);
+#if COMPILER_CL
+ cb_cmd_append(&cmd, "/std:c11", "/nologo");
+ cb_cmd_push(&cmd, cb_format("/Fe:%.*s", cb_view_expand(executable)));
+ cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_sources[0])));
+#else
+ cb_cmd_push(&cmd, "-o");
+ cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(executable)));
+ cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_sources[0])));
+#endif
+ CB_StringView *str_build_options = build_options.data;
+ for (s64 i = 0; i < build_options.length; ++i) {
+ cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_build_options[i])));
}
- printf("\b`\n");
- CB_Process recompiler = cb_cmd_exec(&cmd);
- if (recompiler.status_code) {
+
+ cb_cmd_print(&cmd);
+ CB_Process compilation_proc = cb_cmd_exec(&cmd);
+ if (compilation_proc.status_code != 0) {
#if OS_WINDOWS
- cb_file_rename(exe_name_old, exe_name);
+ cb_file_rename(executable_old, executable);
#endif
exit(-1);
}
- cb_cmd_push(&cmd, exe_name);
+ cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(executable)));
cb_cmd_append_dyn(&cmd, argv, (size_t)argc);
(void)cb_cmd_exec(&cmd);
exit(0);
}
-internal bool _cb_need_rebuild(const char *output_path, struct CB_PathList sources) {
+// ==============================================================================
+// Environment variables
+static char* cb_getenv(const char *varname)
+{
+ cb_assert(varname != NULL);
#if OS_WINDOWS
- FILETIME output_mtime_large = {0};
- HANDLE output_handle = CreateFileA(output_path, GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
- if (output_handle == INVALID_HANDLE_VALUE ||
- !GetFileTime(output_handle, 0, 0, &output_mtime_large)) {
- CloseHandle(output_handle);
- return true;
- }
- CloseHandle(output_handle);
-
- ULARGE_INTEGER output_mtime = {0};
- output_mtime.LowPart = output_mtime_large.dwLowDateTime;
- output_mtime.HighPart = output_mtime_large.dwHighDateTime;
-
- for (size_t i = 0; i < sources.count; ++i) {
- FILETIME source_mtime_large = {0};
- HANDLE source_handle = CreateFileA(sources.values[i], GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
- if (source_handle == INVALID_HANDLE_VALUE) { return true; }
- if (!GetFileTime(source_handle, 0, 0, &source_mtime_large)) {
- CloseHandle(output_handle);
- return true;
- }
- CloseHandle(output_handle);
-
- ULARGE_INTEGER source_mtime = {0};
- source_mtime.LowPart = source_mtime_large.dwLowDateTime;
- source_mtime.HighPart = source_mtime_large.dwHighDateTime;
- if (output_mtime.QuadPart < source_mtime.QuadPart) {
- return true;
- }
+ char *res = cb_arena_push_many(char, MAX_ENVVAR);
+ if (!GetEnvironmentVariableA(varname, res, MAX_ENVVAR)) {
+ cb_arena_pop(sizeof(char) * MAX_ENVVAR);
+ res = 0;
}
- return false;
+ return res;
#else
- struct stat output_stat = {};
- if (stat(output_path, &output_stat) < 0) { return true; }
- for (size_t i = 0; i < sources.count; ++i) {
- struct stat source_stat = {};
- if (stat(sources.values[i], &source_stat) < 0) {
- rebuild_failure:
- cb_print(CB_LogLevel_Error,
- "`%s` modification time unreadable: %s\n",
- sources.values[i], strerror(errno));
- exit(-1);
- }
- if (output_stat.st_mtime < source_stat.st_mtime) { return true; }
- }
- return false;
+ return getenv(varname);
#endif
}
-internal size_t _last_occurance_of(const char *string, char ch) {
- const char *res = string;
- for (const char *curr = string; curr && *curr; ++curr) {
- if (*curr == ch) { res = curr; }
- }
- return (size_t)(res - string);
+static b8 cb_setenv(const char *varname, const char *value)
+{
+ cb_assert(varname != NULL);
+ cb_assert(value != NULL);
+#if OS_WINDOWS
+ return SetEnvironmentVariableA(varname, value);
+#else
+ return !setenv(varname, value, true);
+#endif
}
#endif
internal void
cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type,
- int32_t n, bool implementation,
+ int32_t n, b8 implementation,
char *func_name, char op);
internal void
cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type,
- int32_t n, bool implementation,
+ int32_t n, b8 implementation,
char *func_name, char op);
internal char char_toupper(char ch);
cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n);
static inline void
-cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static inline void
-cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, bool implementation);
+cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, b8 implementation);
static void
-cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, b8 implementation);
static void
-cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, bool implementation);
+cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, b8 implementation);
// ======================================================================
// Implementations
cb_gen_push(gen, cb_format("typedef union {"
"\n %s values[%d];"
"\n struct {", type, n));
- bool found_last_named_field = false;
+ b8 found_last_named_field = false;
for (int32_t i = 0; i < n; ++i) {
char *prefix = " ";
if (i % 4 == 0) {
}
static inline void
-cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s",
}
static inline void
-cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_vecn_element_wise(gen, type, n, implementation, "add", '+');
}
static inline void
-cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_vecn_element_wise(gen, type, n, implementation, "sub", '-');
}
static inline void
-cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_vecn_element_wise(gen, type, n, implementation,
"hadamard_prod", '*');
}
static inline void
-cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_vecn_element_wise(gen, type, n, implementation,
"hadamard_div", '/');
}
static inline void
-cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
- cb_gen_push_func_begin(gen, cb_format("linagen_fn bool vec%d%s_equal", n, type));
+ cb_gen_push_func_begin(gen, cb_format("linagen_fn b8 vec%d%s_equal", n, type));
cb_gen_push_func_arg(gen, cb_format("Vec%d%s *v1", n, suffix));
cb_gen_push_func_arg(gen, cb_format("Vec%d%s *v2", n, suffix));
cb_gen_push_func_end(gen, implementation);
}
static inline void
-cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
- cb_gen_push_func_begin(gen, cb_format("linagen_fn bool vec%d%s_near",
+ cb_gen_push_func_begin(gen, cb_format("linagen_fn b8 vec%d%s_near",
n, type));
cb_gen_push_func_arg(gen, cb_format("Vec%d%s *v1", n, suffix));
cb_gen_push_func_arg(gen, cb_format("Vec%d%s *v2", n, suffix));
}
static inline void
-cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn float vec%d%s_distance2",
}
static inline void
-cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec3%s vec3%s_cross", suffix, type));
}
static void
-cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static inline void
-cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_matnn_element_wise(gen, type, n, implementation, "add", '+');
}
static inline void
-cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_matnn_element_wise(gen, type, n, implementation, "sub", '-');
}
static inline void
-cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_matnn_element_wise(gen, type, n, implementation,
"hadamard_prod", '*');
}
static inline void
-cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
cb_linagen_defun_matnn_element_wise(gen, type, n, implementation,
"hadamard_div", '/');
}
static void
-cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, bool implementation) {
+cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
assert(n > 1);
char *suffix = strdup(type);
*suffix = char_toupper(*type);
}
static void
-cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_by", suffix, type));
}
static void
-cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_to", suffix, type));
}
static void
-cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate", suffix, type));
}
static void
-cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate_rad", suffix, type));
}
static void
-cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_scale", suffix, type));
}
static void
-cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_orthographic", suffix, type));
}
static void
-cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_perspective", suffix, type));
}
static void
-cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, bool implementation) {
+cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, b8 implementation) {
char *suffix = strdup(type);
*suffix = char_toupper(*type);
cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_perspective_rad", suffix, type));
internal void
cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type,
- int32_t n, bool implementation,
+ int32_t n, b8 implementation,
char *func_name, char op) {
assert(n > 1);
char *suffix = strdup(type);
internal void
cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type,
- int32_t n, bool implementation,
+ int32_t n, b8 implementation,
char *func_name, char op) {
assert(n > 1);
char *suffix = strdup(type);