From c0a378886532b7fc9c953029b99ca884716ee133 Mon Sep 17 00:00:00 2001 From: LeonardoBizzoni Date: Wed, 4 Feb 2026 12:04:59 +0100 Subject: [PATCH] new extra lib + linagen reference to generator line Automatic recompilation might be broken on MSVC, haven't tried it. --- cbuild.h | 726 +++++++++++++++++++++++++++++------------ extra/cbuild_biblo.h | 423 ++++++++++++++++++++++++ extra/cbuild_codegen.h | 31 +- extra/cbuild_linagen.h | 451 ++++++++++++------------- extra/cbuild_tests.h | 4 +- 5 files changed, 1191 insertions(+), 444 deletions(-) create mode 100755 extra/cbuild_biblo.h diff --git a/cbuild.h b/cbuild.h index 0651bbd..4b12616 100644 --- a/cbuild.h +++ b/cbuild.h @@ -49,6 +49,8 @@ # define OS_NONE 0 #endif +#define internal static + #define BOOL_DEFINED 1 #if __STDC_VERSION__ >= 199901L # include @@ -62,6 +64,17 @@ #include #include #include +#include + +#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 @@ -69,10 +82,10 @@ # include # include # define win32_stdin stdin -# undef stdin # define win32_stdout stdout -# undef stdout # define win32_stderr stderr +# undef stdin +# undef stdout # undef stderr # define _cb_platform_mkdir(Path) _mkdir((Path)); # define MAX_ENVVAR 32767 @@ -102,7 +115,6 @@ #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m" -#define internal static #ifndef _assert_break # if OS_WINDOWS # define _assert_break() __debugbreak() @@ -111,14 +123,14 @@ # endif #endif - -internal void cb_assertion_break(char *condition, - char *file, int32_t line) { +internal void cb_assertion_break(char *condition, char *file, int32_t line) { + (void)condition; + (void)file; + (void)line; _assert_break(); } -typedef void (*cb_assertion_handler_fn)(char *condition, - char *file, int32_t line); +typedef void (*cb_assertion_handler_fn)(char *condition, char *file, int32_t line); internal cb_assertion_handler_fn cb_assertion_handler = cb_assertion_break; #define cb_assert(COND) \ @@ -128,39 +140,24 @@ internal cb_assertion_handler_fn cb_assertion_handler = cb_assertion_break; } \ } while (0) -#define StackPush(Head, Nodeptr) \ - LLPushFrontCustom((Head), (Head), (Nodeptr), next) -#define StackPop(Head) (Head ? (Head = Head->next) : 0) -#define LLPushFrontCustom(Head, Last, Nodeptr, Next) \ - (!(Head) ? (Head) = (Nodeptr), (Last) = (Nodeptr) \ - : ((Nodeptr)->Next = (Head), (Head) = (Nodeptr))) -#define QueuePush(Head, Last, Nodeptr) \ - LLPushBackCustom((Head), (Last), (Nodeptr), next) -#define QueuePop(Head) (Head ? (Head = Head->next) : 0) -#define LLPushBackCustom(Head, Last, Nodeptr, Next) \ - (!(Head) ? (Head) = (Last) = (Nodeptr) \ - : ((Last) ? ((Last)->Next = (Nodeptr), (Last) = (Nodeptr)) \ - : ((Head)->Next = (Last) = (Nodeptr)))) - struct CB_PathList { - char **values; + const char **values; size_t count; size_t capacity; }; typedef struct CB_PathList CB_Cmd; -struct Cb_Cmd_RunArgs { - bool async; - bool reset; - +struct CB_Cmd_RunArgs { CB_Handle stdin; CB_Handle stdout; CB_Handle stderr; + bool async; + bool reset; }; typedef struct { - int32_t status_code; CB_ProcHandle handle; + int32_t status_code; } CB_Process; typedef struct { @@ -178,47 +175,101 @@ enum { typedef uint8_t CB_LogLevel; enum { + CB_LogLevel_None, CB_LogLevel_Info, CB_LogLevel_Warn, CB_LogLevel_Error, + CB_LogLevel_COUNT, }; -#ifndef CB_DYN_DEFAULT_CAPACITY -# define CB_DYN_DEFAULT_CAPACITY 8 +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 + struct CB_FileIterator_Handle { + const char *path; + DIR *dir; + struct dirent *dir_entry; + }; #endif -#ifndef CB_RECOMPILE_OPTIONS -# define CB_RECOMPILE_OPTIONS +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; + +typedef struct CB_StringView { + const char *data; + ssize_t length; +} CB_StringView; + +struct CB_StringBuilder_Node { + struct CB_StringBuilder_Node *prev; + struct CB_StringBuilder_Node *next; + CB_StringView value; +}; + +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 OS_WINDOWS -# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cl.exe", "/Fe:", (Exe_name), \ - (Builder_src), "/nologo", \ - CB_RECOMPILE_OPTIONS +#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), \ - CB_RECOMPILE_OPTIONS +# 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__ +#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), \ - ((char*[]){__VA_ARGS__}), \ - (sizeof((char*[]){__VA_ARGS__}) / sizeof(char*))) -#define cb_println(Level, Fmt, ...) cb_print((Level), Fmt "\n", ##__VA_ARGS__) -#define cb_rebuild_self(argc, argv) _cb_rebuild(argc, argv, __FILE__, (char *)0) -#define cb_rebuild_self_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, (char*)0) +#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_cmd_run(Cmd, ...) _cb_cmd_run((Cmd), (struct Cb_Cmd_RunArgs) { \ - .async = false, \ - .reset = true, \ - __VA_ARGS__ \ - }) #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_with_option(Cmd, ...) \ + _cb_cmd_run((Cmd), \ + (struct CB_Cmd_RunArgs) { \ + .async = false, \ + .reset = true, \ + __VA_ARGS__ \ + }) #define cb_dyn_free_custom(Dynarr, Values, Count) \ do { \ @@ -251,53 +302,104 @@ enum { (Dynarr)->Count += (Size); \ } while(0) -#define cb_handle_write(Handle, Content) _is_literal(Content) ? _cb_handle_write_lit(Handle, Content) : _cb_handle_write_dyn(Handle, Content) -#define _cb_handle_write_lit(Handle, Content) \ - _cb_handle_write((Handle), (Content), (sizeof((Content)) / sizeof(*(Content)))) -#define _cb_handle_write_dyn(Handle, Content) \ - _cb_handle_write((Handle), (Content), strlen((Content))) -#define _is_literal(x) _is_literal_(x) -#define _is_literal_(x) _is_literal_f(#x, sizeof(#x) - 1) - -static char* cb_format(char *format, ...); -static void cb_print(CB_LogLevel level, char *fmt, ...); -static char* cb_getenv(char *varname); -static bool cb_setenv(char *varname, char *value); -static void cb_cmd_print(CB_Cmd *cmd); +#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))) + +#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)) + +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 CB_Handle cb_handle_open(char *path, CB_AccessFlag permission); -static void cb_handle_close(CB_Handle fd); -static char* cb_handle_read(CB_Handle fd); -static bool cb_dir_create(char *path); -static void cb_dir_delete(char *path); -static void cb_file_delete(char *path); -static bool cb_file_rename(char *path, char *to); -static bool cb_file_exists(char *path); -static bool cb_cli_contains(int32_t argc, char **argv, char *target); - -internal void _cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize); -internal char* _cb_format(char *format, va_list args); -internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources); -internal void _cb_rebuild(int argc, char **argv, char *cb_src, ...); -internal bool _cb_is_outdated(char *output, ...); -internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args); -internal size_t _last_occurance_of(char *string, char ch); -internal bool _is_literal_f(char *str, size_t l); +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); // ============================================================================== // Implementation -static char* cb_format(char *format, ...) { - va_list args; +static char* cb_format(const char *format, ...) { + va_list args = {0}; va_start(args, format); - char *res = _cb_format(format, args); + char *res = cb_format_va(format, args); va_end(args); return res; } -static void cb_print(CB_LogLevel level, char *fmt, ...) { - va_list args; +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) { case CB_LogLevel_Info: { printf(ANSI_COLOR_CYAN "[INFO] "); @@ -312,13 +414,15 @@ static void cb_print(CB_LogLevel level, char *fmt, ...) { } printf(ANSI_COLOR_RESET); - print_str: ; + print_str:; + va_list args = {0}; va_start(args, fmt); - printf("%s", _cb_format(fmt, args)); + printf("%s", cb_format_va(fmt, args)); va_end(args); } -static char* cb_getenv(char *varname) { +static char* cb_getenv(const char *varname) { + cb_assert(varname != NULL); #if OS_WINDOWS char *res = malloc(MAX_ENVVAR); if (!GetEnvironmentVariableA(varname, res, MAX_ENVVAR)) { @@ -331,7 +435,9 @@ static char* cb_getenv(char *varname) { #endif } -static bool cb_setenv(char *varname, char *value) { +static bool cb_setenv(const char *varname, const char *value) { + cb_assert(varname != NULL); + cb_assert(value != NULL); #if OS_WINDOWS return SetEnvironmentVariableA(varname, value); #else @@ -339,18 +445,20 @@ static bool cb_setenv(char *varname, char *value) { #endif } -static void cb_cmd_print(CB_Cmd *cmd) { +static void cb_cmd_print(const CB_Cmd *cmd) { + cb_assert(cmd != NULL); cb_print(CB_LogLevel_Info, "Command: `"); - for (int32_t i = 0; i < cmd->count; ++i) { + for (size_t i = 0; i < cmd->count; ++i) { printf("%s ", cmd->values[i]); } printf("\b`\n"); } static void cb_process_wait(CB_Process *proc) { + cb_assert(proc != NULL); if (proc->handle == CB_PROC_INVALID) { - cb_println(CB_LogLevel_Warn, "Waiting on invalid process handle"); - return; + cb_print(CB_LogLevel_Error, "Waiting on invalid process handle\n"); + cb_assert(false); } #if OS_WINDOWS @@ -359,7 +467,8 @@ static void cb_process_wait(CB_Process *proc) { CloseHandle(proc->handle); #else int32_t status = 0; - cb_assert(waitpid(proc->handle, &status, 0) == proc->handle); + 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)) { @@ -371,13 +480,17 @@ static void cb_process_wait(CB_Process *proc) { } 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 CB_Handle cb_handle_open(char *path, CB_AccessFlag permission) { +static CB_Handle cb_file_open(const char *path, CB_AccessFlag permission) { + cb_assert(path != NULL); + #if OS_WINDOWS SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES), 0, 0}; DWORD access_flags = 0; @@ -399,79 +512,85 @@ static CB_Handle cb_handle_open(char *path, CB_AccessFlag permission) { FILE_ATTRIBUTE_NORMAL, 0); #else int32_t flags = O_CREAT; - if (permission & CB_AccessFlag_Append) { - flags |= (permission & CB_AccessFlag_Read) ? O_RDWR : O_WRONLY; - flags |= O_APPEND; - } else if ((permission & CB_AccessFlag_Write) && - (permission & CB_AccessFlag_Read)) { + if ((permission & CB_AccessFlag_Read) && ((permission & CB_AccessFlag_Write) || + (permission & CB_AccessFlag_Append))) { flags |= O_RDWR; - } else if (permission & CB_AccessFlag_Read) { - flags |= O_RDONLY; - } else if (permission & CB_AccessFlag_Write) { - flags |= O_WRONLY | O_TRUNC; + } else { + if (permission & CB_AccessFlag_Read) { + flags |= O_RDONLY; + } else if ((permission & CB_AccessFlag_Write) || + (permission & CB_AccessFlag_Append)) { + flags |= O_WRONLY; + } } - return open(path, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + 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; #endif } -static void cb_handle_close(CB_Handle fd) { +static void cb_file_close(CB_Handle fd) { if (fd == CB_HANDLE_INVALID) { - cb_println(CB_LogLevel_Warn, "Closing invalid handle"); - return; + cb_print(CB_LogLevel_Error, "Closing invalid handle\n"); + cb_assert(false); } #if OS_WINDOWS FlushFileBuffers(fd); CloseHandle(fd); #else - fsync(fd); close(fd); #endif } -static char* cb_handle_read(CB_Handle fd) { +static CB_StringView cb_file_read(CB_Handle fd) { if (fd == CB_HANDLE_INVALID) { - cb_println(CB_LogLevel_Warn, "Reading from invalid handle"); - return 0; + cb_print(CB_LogLevel_Warn, "Reading from invalid handle\n"); + return (CB_StringView) {0}; } #if OS_WINDOWS LARGE_INTEGER file_size = {0}; GetFileSizeEx(fd, &file_size); - uint64_t to_read = file_size.QuadPart; - uint64_t total_read = 0; - uint8_t *ptr = malloc(to_read + 1); + 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, + }; +#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, + }; +#endif +} - for(;total_read < to_read;) { - uint64_t amount64 = to_read - total_read; - uint32_t amount32 = amount64 > 0xFFFFFFFF ? 0xFFFFFFFF : (uint32_t)amount64; - OVERLAPPED overlapped = {0}; - DWORD bytes_read = 0; - (void)ReadFile(fd, ptr + total_read, amount32, &bytes_read, &overlapped); - total_read += bytes_read; - if(bytes_read != amount32) { break; } - } +static void cb_file_write_sv(CB_Handle fd, CB_StringView sv) { + _cb_file_write_buffer(fd, sv.data, sv.length); +} - ptr[to_read] = 0; - if(total_read != to_read) { - free(ptr); - ptr = 0; - } - return ptr; -#else - struct stat file_stat; - if (!fstat(fd, &file_stat)) { - char *res = (char *)malloc(file_stat.st_size); - if (pread(fd, res, file_stat.st_size, 0) >= 0) { - return res; - } +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); } - return 0; -#endif + size_t buffsize = strlen(buffer); + _cb_file_write_buffer(fd, buffer, buffsize); } -static bool cb_dir_create(char *path) { +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, '/'); @@ -483,11 +602,10 @@ static bool cb_dir_create(char *path) { free(parent); _cb_platform_mkdir(path); } - return !mkdir_res; } -static void cb_dir_delete(char *path) { +static void cb_dir_delete(const char *path) { #if OS_WINDOWS _rmdir(path); #else @@ -495,7 +613,7 @@ static void cb_dir_delete(char *path) { #endif } -static void cb_file_delete(char *path) { +static void cb_file_delete(const char *path) { #if OS_WINDOWS _unlink(path); #else @@ -503,16 +621,15 @@ static void cb_file_delete(char *path) { #endif } -static bool cb_file_rename(char *path, char *to) { +static bool cb_file_rename(const char *path, const char *to) { #if OS_WINDOWS - return MoveFileEx(path, to, - MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); + return MoveFileExA(path, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); #else return !rename(path, to); #endif } -static bool cb_file_exists(char *path) { +static bool cb_file_exists(const char *path) { #if OS_WINDOWS # define F_OK 0 # define access _access @@ -520,7 +637,96 @@ static bool cb_file_exists(char *path) { return access(path, F_OK) == 0; } -static bool cb_cli_contains(int32_t argc, char **argv, char *target) { +static bool cb_symlink_create(const char *target, const char *linkpath) { + cb_assert(target != NULL); + cb_assert(linkpath != NULL); + +#if OS_WINDOWS +#else + int32_t res = symlink(target, linkpath); + return res == 0; +#endif +} + +static void cb_file_iter_begin(CB_FileIterator *it, const char *rootpath) { + memset(&it->handle, 0, sizeof it->handle); +#if OS_WINDOWS + // TODO(lb): file iteration on win32 +#else + it->handle.path = rootpath; + it->handle.dir = opendir(rootpath); +#endif +} + +static bool cb_file_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 +#else + struct dirent *entry = NULL; + char *filepath = NULL; + + if (!it->handle.dir) { return false; } + for (;;) { + const char *filename = NULL; + do { + filename = NULL; + entry = readdir(it->handle.dir); + if (!entry) { return false; } + filename = entry->d_name; + } while ((strcmp(filename, currdir) == 0) || (strcmp(filename, parentdir) == 0)); + if (!filename) { return false; } + + int32_t filepath_size = snprintf(NULL, 0, "%s/%s", it->handle.path, filename) + 1; + filepath = malloc(filepath_size); + if (!filepath) { return false; } + snprintf(filepath, filepath_size, "%s/%s", it->handle.path, filename); + + struct stat file_stat = {0}; + if (stat(filepath, &file_stat) != 0) { + free(filepath); + return false; + } + + 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; + } + + if (!(it->filter_allowed & filetype)) { + free(filepath); + } else { + if (!output) { + free(filepath); + } else { + output->path = filepath; + output->type = filetype; + output->size = file_stat.st_size; + } + return true; + } + } + return false; +#endif +} + +static void cb_file_iter_end(CB_FileIterator *it) { +#if OS_WINDOWS + // TODO(lb): file iteration on win32 +#else + closedir(it->handle.dir); +#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; @@ -529,27 +735,116 @@ static bool cb_cli_contains(int32_t argc, char **argv, char *target) { 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; +} -internal bool _cb_is_outdated(char *output, ...) { - struct CB_PathList sources = {}; - 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_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 (int32_t i = 0; + sv->data[i] == ' ' || sv->data[i] == '\n' || sv->data[i] == '\r' || sv->data[i] == '\t'; + ++i) { + sv->length -= 1; + sv->data += 1; + } + for (int32_t i = sv->length - 1; + i >= 0 && sv->data[i] == ' ' || sv->data[i] == '\n' || sv->data[i] == '\r' || sv->data[i] == '\t'; + --i) { + sv->length -= 1; } - va_end(args); - return _cb_need_rebuild(output, sources); } -internal void _cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize) { - if (fd == CB_HANDLE_INVALID) { - cb_println(CB_LogLevel_Warn, "Writing to invalid handle"); - return; +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, + }); + } + 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); + 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; } + 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; } + ((char*)sv.data)[sv.length] = 0; + return sv; +} - while (!buffer[buffsize - 1]) { buffsize -= 1; } +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; @@ -563,26 +858,40 @@ internal void _cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize) { if(bytes_written != amount32) { break; } } #else - write(fd, buffer, buffsize); + write(fd, buffer, size); #endif } -internal char* _cb_format(char *format, va_list args) { +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); + } + va_end(args); + return _cb_need_rebuild(output, sources); +} + + +internal char* cb_format_va(const char *format, va_list args) { va_list args2; va_copy(args2, args); - uint32_t needed_bytes = vsnprintf(0, 0, format, args2) + 1; + size_t needed_bytes = (size_t)vsnprintf(0, 0, format, args2) + 1; va_end(args2); - char *res = (char *)malloc(needed_bytes); + char *res = malloc(needed_bytes); (void)vsnprintf(res, needed_bytes, format, args); return res; } -internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { - CB_Process res = {}; +internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct CB_Cmd_RunArgs args) { + CB_Process res = {0}; #if OS_WINDOWS - char cmdline[32767] = {}; + char cmdline[32767] = {0}; size_t offset = 0; for (size_t i = 0; i < cmd->count; ++i) { strcat(cmdline, strstr(cmd->values[i], " ") || strstr(cmd->values[i], "\\") @@ -591,14 +900,14 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { if (i != cmd->count - 1) { strcat(cmdline, " "); } } - STARTUPINFO si = {0}; + 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); - PROCESS_INFORMATION pi = {}; + PROCESS_INFORMATION pi = {0}; if (!CreateProcessA(0, cmdline, 0, 0, TRUE, 0, 0, 0, &si, &pi)) { LPVOID lpMsgBuf; DWORD error = GetLastError(); @@ -607,8 +916,8 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, 0); - cb_println(CB_LogLevel_Error, "Child process `%s` creation failed with error %u: %s", - cmd->values[0], error, lpMsgBuf); + cb_print(CB_LogLevel_Error, "Child process `%s` creation failed with error %u: %s\n", + cmd->values[0], error, lpMsgBuf); exit(-1); } @@ -617,8 +926,8 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { #else res.handle = fork(); if (res.handle < 0) { - cb_println(CB_LogLevel_Error, "Child process `%s` creation failed with error %d: %s\n", - cmd->values[0], errno, strerror(errno)); + cb_print(CB_LogLevel_Error, "Child process `%s` creation failed with error %d: %s\n", + cmd->values[0], errno, strerror(errno)); exit(-1); } else if (!res.handle) { if (args.stdout) { dup2(args.stdout, STDOUT_FILENO); } @@ -628,12 +937,12 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { dup2(args.stdin, STDIN_FILENO); } - CB_Cmd _cmd = {}; + CB_Cmd _cmd = {0}; cb_cmd_append_dyn(&_cmd, cmd->values, cmd->count); cb_cmd_push(&_cmd, 0); if (execvp(_cmd.values[0], (char **)_cmd.values) < 0) { - cb_println(CB_LogLevel_Error, "Child process `%s` creation failed with error %d: %s\n", - cmd->values[0], errno, strerror(errno)); + cb_print(CB_LogLevel_Error, "Child process `%s` creation failed with error %d: %s\n", + cmd->values[0], errno, strerror(errno)); exit(-1); } // NOTE(lb): unreachable, execvp only returns on error. @@ -650,11 +959,11 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { return res; } -internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { +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 = {}; + struct CB_PathList sources = {0}; cb_dyn_push(&sources, builder_src); va_list args; va_start(args, builder_src); @@ -669,25 +978,25 @@ internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { cb_dyn_free(&sources); return; } - cb_println(CB_LogLevel_Info, "rebuilding %s", exe_name); + cb_print(CB_LogLevel_Info, "rebuilding %s\n", exe_name); #if OS_WINDOWS char *exe_name_old = cb_format("%s.old", exe_name); if (!cb_file_rename(exe_name, exe_name_old)) { - cb_println(CB_LogLevel_Info, "File rename failed: %s -> %s", - exe_name, exe_name_old); + cb_print(CB_LogLevel_Info, "File rename failed: %s -> %s\n", + exe_name, exe_name_old); exit(-1); } #endif - CB_Cmd cmd = {}; + CB_Cmd cmd = {0}; cb_cmd_append(&cmd, CB_CMD_REBUILD_SELF(exe_name, builder_src)); cb_print(CB_LogLevel_Info, "running: `"); - for (int32_t i = 0; i < cmd.count; ++i) { + for (size_t i = 0; i < cmd.count; ++i) { printf("%s ", cmd.values[i]); } printf("\b`\n"); - CB_Process recompiler = cb_cmd_run(&cmd); + CB_Process recompiler = cb_cmd_exec(&cmd); if (recompiler.status_code) { #if OS_WINDOWS cb_file_rename(exe_name_old, exe_name); @@ -696,14 +1005,14 @@ internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { } cb_cmd_push(&cmd, exe_name); - cb_cmd_append_dyn(&cmd, argv, argc); - (void)cb_cmd_run(&cmd); + cb_cmd_append_dyn(&cmd, argv, (size_t)argc); + (void)cb_cmd_exec(&cmd); exit(0); } -internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { +internal bool _cb_need_rebuild(const char *output_path, struct CB_PathList sources) { #if OS_WINDOWS - FILETIME output_mtime_large = {}; + FILETIME output_mtime_large = {0}; HANDLE output_handle = CreateFileA(output_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); @@ -714,12 +1023,12 @@ internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { } CloseHandle(output_handle); - ULARGE_INTEGER output_mtime = {}; + 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 = {}; + FILETIME source_mtime_large = {0}; HANDLE source_handle = CreateFileA(sources.values[i], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); @@ -730,7 +1039,7 @@ internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { } CloseHandle(output_handle); - ULARGE_INTEGER source_mtime = {}; + 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) { @@ -745,9 +1054,9 @@ internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { struct stat source_stat = {}; if (stat(sources.values[i], &source_stat) < 0) { rebuild_failure: - cb_println(CB_LogLevel_Error, - "`%s` modification time unreadable: %s", - sources.values[i], strerror(errno)); + 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; } @@ -756,27 +1065,12 @@ internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { #endif } -internal size_t _last_occurance_of(char *string, char ch) { - char *res = string; - for (char *curr = string; curr && *curr; ++curr) { +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 res - string; -} - -internal bool _is_literal_f(char *str, size_t l) { - char *e = str + l; - if (str[0] == 'L') str++; - if (str[0] != '"') return false; - for (; str != e; str = strchr(str + 1, '"')) { - if (!str) { return false; } - for (str++; - *str == '\f' || *str == '\n' || *str == '\r' || - *str == '\t' || *str == '\v'; - ++str); - if (*str != '"') { return false; } - } - return true; + return (size_t)(res - string); } #endif diff --git a/extra/cbuild_biblo.h b/extra/cbuild_biblo.h new file mode 100755 index 0000000..11a09db --- /dev/null +++ b/extra/cbuild_biblo.h @@ -0,0 +1,423 @@ +#ifndef CBUILD_BIBLO_H +#define CBUILD_BIBLO_H + +#if OS_WINDOWS +#else +# include +#endif + +typedef struct CB_BibloElement { + CB_StringView name; + CB_StringView brief; + CB_StringView description; + CB_StringView ref_block; + CB_StringBuilder aliases; +} CB_BibloElement; + +struct CB_BibloParser { + CB_StringView prefix; + CB_StringView content; + ssize_t offset; + CB_Handle hfile; +}; + +static void cb_biblo_build_man(const char *rootpath, const char *output_path); + +internal void cb_biblo_generate_troff(const CB_BibloElement *element, CB_StringView path_dirdoc, const char *source_path); +internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *parser); +internal void cb_biblo_parser_advance(struct CB_BibloParser *parser, size_t by); +internal char cb_biblo_parser_peek(struct CB_BibloParser *parser, ssize_t offset); +internal void cb_biblo_parser_until_newline(struct CB_BibloParser *parser, CB_StringView *sv); +internal void cb_biblo_find_prefix(struct CB_BibloParser *parser); + +// =============================================================== +// Implementation + +typedef uint8_t CB_BibloAnnotationID; +enum { + CB_BibloAnnotationID_Name, + CB_BibloAnnotationID_Brief, + CB_BibloAnnotationID_Long, + CB_BibloAnnotationID_Alias, + CB_BibloAnnotationID_ReferenceBegin, + CB_BibloAnnotationID_ReferenceEnd, +}; + +static CB_StringView cb_biblo_annotation[] = { + [CB_BibloAnnotationID_Name] = cb_strinit("@name"), + [CB_BibloAnnotationID_Brief] = cb_strinit("@brief"), + [CB_BibloAnnotationID_Long] = cb_strinit("@long"), + [CB_BibloAnnotationID_Alias] = cb_strinit("@alias"), + [CB_BibloAnnotationID_ReferenceBegin] = cb_strinit("@ref-begin"), + [CB_BibloAnnotationID_ReferenceEnd] = cb_strinit("@ref-end"), +}; + +static void cb_biblo_build_man(const char *rootpath, const char *output_path) +{ + CB_FileIterator it = { .filter_allowed = CB_FileType_Regular | CB_FileType_Directory }; + cb_file_iter_begin(&it, rootpath); + + for (CB_FileInfo file = {0}; cb_file_iter_next(&it, &file); free(file.path)) { + if (file.type == CB_FileType_Directory) { + cb_biblo_build_man(file.path, output_path); + } else { + int32_t line = 1; + CB_Handle fd = cb_file_open(file.path, CB_AccessFlag_Read); + assert(fd != CB_HANDLE_INVALID); + struct CB_BibloParser parser = {0}; + for (;;) { + CB_BibloElement doc = cb_biblo_parse(fd, &parser); + if (doc.name.length == 0) { break; } + CB_StringBuilder sb = {0}; + cb_sb_append(&sb, cb_view_from_cstr(output_path)); + cb_sb_append(&sb, cb_strlit("man3")); + CB_StringView doc_fullpath = cb_sb_join_with_ch(sb, '/'); + cb_dir_create(doc_fullpath.data); + cb_biblo_generate_troff(&doc, doc_fullpath, file.path); + } + cb_file_close(fd); + } + } +} + +internal void cb_biblo_generate_troff(const CB_BibloElement *element, CB_StringView path_dirdoc, const char *source_path) +{ + assert(element != NULL); + + CB_StringBuilder sb_target = {0}; + cb_sb_append(&sb_target, element->name); + cb_sb_append(&sb_target, cb_strlit("3")); + CB_StringView troff_filename = cb_sb_join_with_ch(sb_target, '.'); + + CB_StringBuilder sb = {0}; + cb_sb_append(&sb, path_dirdoc); + cb_sb_append(&sb, troff_filename); + CB_StringView troff_filepath = cb_sb_join_with_ch(sb, '/'); + + cb_file_delete(troff_filepath.data); + CB_Handle troff_fd = cb_file_open(troff_filepath.data, CB_AccessFlag_Write); + assert(troff_fd != CB_HANDLE_INVALID); + + char *date = NULL; +#if OS_WINDOWS + // TODO(lb): retrieve date on win32 +#else + { + time_t now = time(NULL); + struct tm *t = localtime(&now); + size_t length = snprintf(NULL, 0, "%4d-%02d-%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday) + 1; + date = malloc(length); + assert(date != NULL); + snprintf(date, length, "%4d-%02d-%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday); + } +#endif + assert(date != NULL); + + cb_file_write(troff_fd, ".TH "); + cb_file_write(troff_fd, element->name); + cb_file_write(troff_fd, " 3 "); + cb_file_write(troff_fd, date); + cb_file_write(troff_fd, " GNU\n.SH NAME\n"); + if (element->aliases.node_count == 0) { + cb_file_write(troff_fd, element->name); + } else { + for (struct CB_StringBuilder_Node *curr = element->aliases.first; curr; curr = curr->next) { + cb_file_write(troff_fd, curr->value); + if (curr->next) { cb_file_write(troff_fd, ",\\ "); } + } + } + if (element->brief.length > 0) { + cb_file_write(troff_fd, " \\- "); + cb_file_write(troff_fd, element->brief); + } + + cb_file_write(troff_fd, "\n.SH SYNOPSIS\n.RS\n.nf\n"); + cb_file_write(troff_fd, element->ref_block); + cb_file_write(troff_fd, "\n.fi\n.RE"); + + if (element->description.length > 0) { + cb_file_write(troff_fd, "\n.SH DESCRIPTION\n"); + cb_file_write(troff_fd, element->description); + } + cb_file_write(troff_fd, "\n.SH FILES\n.TP\n.I "); + cb_file_write(troff_fd, source_path); + + if (element->aliases.node_count > 0) { + for (struct CB_StringBuilder_Node *curr = element->aliases.first; curr; curr = curr->next) { + CB_StringBuilder sb_link = {0}; + cb_sb_append(&sb_link, path_dirdoc); + cb_sb_append(&sb_link, curr->value); + CB_StringView link_filepath = cb_sb_join_with_ch(sb_link, '/'); + memset(&sb_link, 0, sizeof sb_link); + cb_sb_append(&sb_link, link_filepath); + cb_sb_append(&sb_link, cb_strlit("3")); + link_filepath = cb_sb_join_with_ch(sb_link, '.'); + cb_symlink_create(troff_filename.data, link_filepath.data); + } + } + + cb_file_close(troff_fd); +} + +internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *parser) +{ + CB_BibloElement res = {0}; + + assert(parser != NULL); + if (parser->hfile == 0) { + assert(file != 0); + parser->hfile = file; + parser->content = cb_file_read(file); + parser->offset = 0; + if (parser->content.length == 0) { return res; } + cb_biblo_find_prefix(parser); + } + assert(parser->content.data != NULL); + assert(parser->content.length > 0); + + bool has_explicit_ref_block = false, started_ref_block = false; + if (parser->prefix.data == NULL || parser->prefix.length <= 0) { return res; } + + // NOTE(lb): skip lines until one that starts with `PREFIX@` + for (;;) { + for (; !(cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix));) { + cb_biblo_parser_until_newline(parser, NULL); + if (parser->offset >= parser->content.length) { return res; } + } + if (cb_biblo_parser_peek(parser, parser->prefix.length) != '@') { + cb_biblo_parser_until_newline(parser, NULL); + } else { + break; + } + } + + for (CB_StringView line = {0}; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix);) { + cb_biblo_parser_advance(parser, parser->prefix.length); + CB_StringBuilder sb = {0}; + + if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Brief])) { + cb_biblo_parser_advance(parser, cb_biblo_annotation[CB_BibloAnnotationID_Brief].length); + if (parser->offset >= parser->content.length) { + cb_print(CB_LogLevel_Error, "Missing brief description.\n"); + assert(false); + } + if (cb_biblo_parser_peek(parser, 0) == '\n') { + cb_biblo_parser_advance(parser, 1); + } else { + cb_biblo_parser_until_newline(parser, &line); + cb_view_trim(&line); + cb_sb_append(&sb, line); + } + for (; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) && + cb_biblo_parser_peek(parser, parser->prefix.length) != '@';) { + cb_biblo_parser_advance(parser, parser->prefix.length); + cb_biblo_parser_until_newline(parser, &line); + cb_view_trim(&line); + cb_sb_append(&sb, line); + } + if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) { + assert(cb_biblo_parser_peek(parser, parser->prefix.length) == '@'); + } + res.brief = cb_sb_join_with_ch(sb, ' '); + cb_view_trim(&res.brief); + } + else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Name])) { + cb_biblo_parser_advance(parser, cb_biblo_annotation[CB_BibloAnnotationID_Name].length); + if (parser->offset >= parser->content.length) { + cb_print(CB_LogLevel_Error, "Missing name.\n"); + assert(false); + } + if (cb_biblo_parser_peek(parser, 0) == '\n') { + cb_print(CB_LogLevel_Error, "Name field cannot be on a newline.\n"); + assert(false); + } + cb_biblo_parser_until_newline(parser, &line); + cb_view_trim(&line); + cb_sb_append(&sb, line); + if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) { + assert(cb_biblo_parser_peek(parser, parser->prefix.length) == '@'); + } + res.name = cb_sb_join_with_ch(sb, ' '); + cb_view_trim(&res.name); + } + else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Long])) { + cb_biblo_parser_advance(parser, cb_biblo_annotation[CB_BibloAnnotationID_Long].length); + if (parser->offset >= parser->content.length) { + cb_print(CB_LogLevel_Error, "Missing description.\n"); + assert(false); + } + if (cb_biblo_parser_peek(parser, 0) == '\n') { + cb_biblo_parser_advance(parser, 1); + } else { + cb_biblo_parser_until_newline(parser, &line); + cb_view_trim(&line); + cb_sb_append(&sb, line); + } + for (; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) && + cb_biblo_parser_peek(parser, parser->prefix.length) != '@';) { + cb_biblo_parser_advance(parser, parser->prefix.length); + cb_biblo_parser_until_newline(parser, &line); + cb_view_trim(&line); + cb_sb_append(&sb, line); + } + if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) { + assert(cb_biblo_parser_peek(parser, parser->prefix.length) == '@'); + } + res.description = cb_sb_join_with_ch(sb, ' '); + cb_view_trim(&res.description); + } + else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Alias])) { + cb_biblo_parser_advance(parser, cb_biblo_annotation[CB_BibloAnnotationID_Alias].length); + if (parser->offset >= parser->content.length) { + cb_print(CB_LogLevel_Error, "Missing alias list.\n"); + assert(false); + } + if (cb_biblo_parser_peek(parser, 0) == '\n') { + cb_biblo_parser_advance(parser, 1); + assert(cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)); + cb_biblo_parser_advance(parser, parser->prefix.length); + assert(cb_biblo_parser_peek(parser, 0) != '@'); + } + + for (; parser->offset < parser->content.length;) { + cb_biblo_parser_until_newline(parser, &line); + CB_StringBuilder split_line = cb_view_split(line, ','); + for (struct CB_StringBuilder_Node *curr = split_line.first; curr; curr = curr->next) { + cb_view_trim(&curr->value); + } + cb_sb_concat(&res.aliases, &split_line); + if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) && + cb_biblo_parser_peek(parser, parser->prefix.length) != '@') { + cb_biblo_parser_advance(parser, parser->prefix.length); + } else { + break; + } + } + if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) { + assert(cb_biblo_parser_peek(parser, parser->prefix.length) == '@'); + } + } + else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_ReferenceBegin])) { + has_explicit_ref_block = true; + started_ref_block = true; + cb_biblo_parser_advance(parser, cb_biblo_annotation[CB_BibloAnnotationID_ReferenceBegin].length); + cb_biblo_parser_until_newline(parser, NULL); + if (parser->offset >= parser->content.length) { + cb_print(CB_LogLevel_Error, "Biblo entry doesn't reference any code block.\n"); + assert(false); + } + for (; parser->offset < parser->content.length && + !(cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) && + cb_view_starts_with(&parser->content.data[parser->offset] + parser->prefix.length, + cb_biblo_annotation[CB_BibloAnnotationID_ReferenceEnd]));) { + cb_biblo_parser_until_newline(parser, &line); + cb_sb_append(&sb, line); + } + res.ref_block = cb_sb_join_with_ch(sb, '\n'); + cb_view_trim(&res.ref_block); + } + else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_ReferenceEnd])) { + assert(started_ref_block == true); + cb_biblo_parser_until_newline(parser, NULL); + } + else { + cb_print(CB_LogLevel_Error, "Invalid biblo annotation.\n"); + assert(false); + exit(-1); + } + } + if (!has_explicit_ref_block) { + CB_StringBuilder sb = {0}; + for (CB_StringView line = {0}; + parser->offset < parser->content.length && cb_biblo_parser_peek(parser, 0) != '\n';) { + cb_biblo_parser_until_newline(parser, &line); + cb_sb_append(&sb, line); + } + res.ref_block = cb_sb_join_with_ch(sb, '\n'); + cb_view_trim(&res.ref_block); + } + if (res.name.length <= 0) { + cb_print(CB_LogLevel_Error, "Missing mandatory biblo name annotation.\n"); + assert(false); + } + return res; +} + +internal void cb_biblo_parser_advance(struct CB_BibloParser *parser, size_t by) +{ + assert(parser != NULL); + assert(parser->content.data != NULL); + assert(parser->content.length > 0); + assert(parser->offset + by >= 0); + parser->offset += by; + if (parser->offset > parser->content.length) { + parser->offset = parser->content.length; + } + assert(parser->offset <= parser->content.length); +} + +internal char cb_biblo_parser_peek(struct CB_BibloParser *parser, ssize_t offset) +{ + assert(parser != NULL); + assert(parser->content.data != NULL); + assert(parser->content.length > 0); + assert(parser->offset + offset >= 0); + assert(parser->offset + offset <= parser->content.length); + return parser->content.data[parser->offset + offset]; +} + +internal void cb_biblo_parser_until_newline(struct CB_BibloParser *parser, CB_StringView *sv) +{ + assert(parser != NULL); + assert(parser->content.data != NULL); + assert(parser->content.length > 0); + if (parser->offset >= parser->content.length) { + parser->offset = parser->content.length; + return; + } + + size_t start = parser->offset; + if (sv) { sv->data = &parser->content.data[parser->offset]; } + for (; + parser->offset < parser->content.length && cb_biblo_parser_peek(parser, 0) != '\n'; + parser->offset += 1) {} + if (sv) { sv->length = parser->offset - start; } + if (parser->offset < parser->content.length) { + assert(cb_biblo_parser_peek(parser, 0) == '\n'); + parser->offset += 1; + } +} + +internal void cb_biblo_find_prefix(struct CB_BibloParser *parser) +{ + assert(parser != NULL); + assert(parser->content.data != NULL); + assert(parser->content.length > 0); + memset(&parser->prefix, 0, sizeof parser->prefix); + for (size_t line_start = 0; parser->prefix.data == NULL && parser->offset < parser->content.length; ) { + switch (cb_biblo_parser_peek(parser, 0)) { + case '@': { + for (int32_t i = 0; i < cb_arrlength(cb_biblo_annotation); ++i) { + if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[i])) { + parser->prefix.data = &parser->content.data[line_start]; + parser->prefix.length = parser->offset - line_start; + parser->offset = line_start; + goto found; + } + } + cb_print(CB_LogLevel_Error, "Unknown cbuild_biblo annotation.\n"); + exit(-1); + found:; + } break; + case '\n': { + line_start = parser->offset + 1; + } // fallthrough + default: { + parser->offset += 1; + } break; + } + } + if (parser->prefix.length > 0) { assert(parser->offset < parser->content.length); } +} + +#endif diff --git a/extra/cbuild_codegen.h b/extra/cbuild_codegen.h index 1eca80e..f7d3e73 100644 --- a/extra/cbuild_codegen.h +++ b/extra/cbuild_codegen.h @@ -9,7 +9,7 @@ typedef struct { size_t total_length; struct { int32_t has_args; - int32_t spacing; + size_t spacing; } signature; } CB_Generator; @@ -23,17 +23,17 @@ static void cb_gen_push_func_end(CB_Generator *gen, bool implementation); // ====================================================================== // Implementations static void cb_gen_write(CB_Generator *gen, char *filepath, bool append_mode) { - CB_Handle file = cb_handle_open(filepath, append_mode - ? CB_AccessFlag_Append - : CB_AccessFlag_Write); + CB_Handle file = cb_file_open(filepath, append_mode + ? CB_AccessFlag_Append + : CB_AccessFlag_Write); char *full_string = malloc(gen->total_length + 1); memset(full_string, 0, gen->total_length + 1); for (size_t i = 0; i < gen->count; ++i) { strcat(full_string, gen->values[i]); } - _cb_handle_write_dyn(file, full_string); + cb_file_write(file, full_string); free(full_string); - cb_handle_close(file); + cb_file_close(file); cb_dyn_free(gen); memset(gen, 0, sizeof *gen); } @@ -43,6 +43,16 @@ static void cb_gen_push(CB_Generator *gen, char *string) { gen->total_length += strlen(string); } +#define cb_gen_push_line(GeneratorPtr, String) \ + _cb_gen_push_line((GeneratorPtr), (String), __FILE__, __LINE__) + +static void _cb_gen_push_line(CB_Generator *gen, char *string, + const char *file, int32_t line) { + string = cb_format("%s // %s:%d\n", string, file, line); + cb_dyn_push(gen, string); + gen->total_length += strlen(string); +} + static void cb_gen_push_func_begin(CB_Generator *gen, char *signature_no_args) { cb_gen_push(gen, cb_format("%s(", signature_no_args)); gen->signature.spacing = strlen(signature_no_args) + 1; @@ -59,14 +69,19 @@ static void cb_gen_push_func_arg(CB_Generator *gen, char *argument) { cb_gen_push(gen, argument); } -static void cb_gen_push_func_end(CB_Generator *gen, bool implementation) { +#define cb_gen_push_func_end(GeneratorPtr, Implementation) \ + _cb_gen_push_func_end((GeneratorPtr), (Implementation), __FILE__, __LINE__) + +static void _cb_gen_push_func_end(CB_Generator *gen, bool implementation, + const char *file, int32_t line) { if (!gen->signature.has_args) { cb_gen_push(gen, "void"); } cb_gen_push(gen, ")"); if (!implementation) { - cb_gen_push(gen, ";\n"); + cb_gen_push(gen, ";"); } + cb_gen_push(gen, cb_format(" // %s:%d\n", file, line)); gen->signature.has_args = 0; gen->signature.spacing = 0; } diff --git a/extra/cbuild_linagen.h b/extra/cbuild_linagen.h index 77519a6..cf6f1f0 100644 --- a/extra/cbuild_linagen.h +++ b/extra/cbuild_linagen.h @@ -9,6 +9,7 @@ #define _USE_MATH_DEFINES #include #include +#include internal void cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type, @@ -103,18 +104,13 @@ cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, // Implementations static void cb_linagen_typedef_vecn(CB_Generator *gen, char *type, int32_t n, ...) { - va_list args = {}; + va_list args = {0}; va_start(args, n); char *suffix = strdup(type); *suffix = char_toupper(*type); cb_gen_push(gen, cb_format("typedef union {" "\n %s values[%d];" -#ifdef __cplusplus - "\n struct Fields {", -#else - "\n struct {", -#endif - type, n)); + "\n struct {", type, n)); bool found_last_named_field = false; for (int32_t i = 0; i < n; ++i) { char *prefix = " "; @@ -177,11 +173,12 @@ cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, bool implementat cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res.values[%d] = _%d;", i, i)); + cb_gen_push_line(gen, cb_format(" res.values[%d] = _%d;", i, i)); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static inline void @@ -208,6 +205,7 @@ cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, boo static inline void cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, bool 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)); @@ -216,16 +214,17 @@ cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, bool imple cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {\n return v1->values[0] == v2->values[0]"); + cb_gen_push_line(gen, "{\n return v1->values[0] == v2->values[0] "); for (int32_t i = 1; i < n; ++i) { - cb_gen_push(gen, cb_format(" &&\n v1->values[%d] == v2->values[%d]", - i, i)); + cb_gen_push_line(gen, cb_format(" && v1->values[%d] == v2->values[%d]%c", + i, i, (i == n - 1 ? ';' : ' '))); } - cb_gen_push(gen, ";\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } static inline void cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, bool 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", @@ -236,16 +235,17 @@ cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {\n return (v1->values[0] + eps >= v2->values[0] && v1->values[0] - eps <= v2->values[0])"); + cb_gen_push_line(gen, "{\n return (v1->values[0] + eps >= v2->values[0] && v1->values[0] - eps <= v2->values[0]) "); for (int32_t i = 1; i < n; ++i) { - cb_gen_push(gen, cb_format(" &&\n (v1->values[%d] + eps >= v2->values[%d] && v1->values[%d] - eps <= v2->values[%d])", - i, i, i, i)); + cb_gen_push_line(gen, cb_format(" && (v1->values[%d] + eps >= v2->values[%d] && v1->values[%d] - eps <= v2->values[%d])%c", + i, i, i, i, (i == n - 1 ? ';' : ' '))); } - cb_gen_push(gen, ";\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } static inline void cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_VECN_COPY_CAP) { @@ -255,11 +255,12 @@ cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_arg(gen, cb_format("%s t", type)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res.values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); + cb_gen_push_line(gen, cb_format(" res.values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen,"}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_lerp", n, type)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); @@ -268,16 +269,17 @@ cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_arg(gen, cb_format("%s t", type)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); + cb_gen_push_line(gen, cb_format(" res->values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_VECN_COPY_CAP) { @@ -286,11 +288,12 @@ cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool imple cb_gen_push_func_arg(gen, cb_format("%s k", type)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n v.values[%d] *= k;", i, i)); + cb_gen_push_line(gen, cb_format(" v.values[%d] *= k;", i, i)); } - cb_gen_push(gen, "\n return v;" "\n}\n\n"); + cb_gen_push_line(gen, " return v;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_scale", n, type)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); @@ -298,16 +301,17 @@ cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool imple cb_gen_push_func_arg(gen, cb_format("%s k", type)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] * k;", i, i)); + cb_gen_push_line(gen, cb_format(" res->values[%d] = v1->values[%d] * k;", i, i)); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_VECN_COPY_CAP) { @@ -315,38 +319,40 @@ cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, bool i cb_gen_push_func_arg(gen, cb_format("Vec%d%s v", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {\n %s dot = {0};", type)); + cb_gen_push_line(gen, cb_format("{\n %s dot = {0};", type)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += v.values[%d] * v.values[%d];", i, i)); + cb_gen_push_line(gen, cb_format(" dot += v.values[%d] * v.values[%d];", i, i)); } - cb_gen_push(gen, "\n float magnitude = sqrtf((float)dot);" - "\n if (magnitude == 0.f) { return v; }"); + cb_gen_push_line(gen, " float magnitude = sqrtf((float)dot);"); + cb_gen_push_line(gen, " if (magnitude == 0.f) { return v; }"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n v.values[%d] /= (%s)magnitude;", i, type)); + cb_gen_push_line(gen, cb_format(" v.values[%d] /= (%s)magnitude;", i, type)); } - cb_gen_push(gen, "\n return v;" "\n}\n\n"); + cb_gen_push_line(gen, " return v;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_normalize", n, type)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *v1", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {\n %s dot = {0};", type)); + cb_gen_push_line(gen, cb_format("{\n %s dot = {0};", type)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += v1->values[%d] * v1->values[%d];", i, i, i)); + cb_gen_push_line(gen, cb_format(" dot += v1->values[%d] * v1->values[%d];", i, i, i)); } - cb_gen_push(gen, "\n float magnitude = sqrtf((float)dot);" - "\n if (magnitude == 0.f) { return; }"); + cb_gen_push_line(gen, " float magnitude = sqrtf((float)dot);"); + cb_gen_push_line(gen, " if (magnitude == 0.f) { return; }"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] / magnitude;", - i, i, type)); + cb_gen_push_line(gen, cb_format(" res->values[%d] = v1->values[%d] / magnitude;", + i, i, type)); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn %s vec%d%s_dot", type, n, type)); @@ -355,15 +361,17 @@ cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, bool impleme cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n %s res = {0};", type)); + cb_gen_push_line(gen, cb_format("{" "\n %s res = {0};", type)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res += v1->values[%d] * v2->values[%d];", i, i, i)); + cb_gen_push_line(gen, cb_format(" res += v1->values[%d] * v2->values[%d];", i, i, i)); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n < MIN(CB_LINAGEN_VECN_COPY_CAP, CB_LINAGEN_MATNN_COPY_CAP)) { @@ -372,18 +380,19 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_arg(gen, cb_format("Mat%d%s m", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { char *prefix = ""; - cb_gen_push(gen, cb_format("\n res.values[%d] = ", i)); + cb_gen_push(gen, cb_format(" res.values[%d] = ", i)); for (int32_t j = 0; j < n; ++j) { cb_gen_push(gen, cb_format("%s(v.values[%d] * m.values[%d][%d])", prefix, j, i, j)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_mulm", n, type)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); @@ -392,23 +401,24 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { char *prefix = ""; - cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); + cb_gen_push(gen, cb_format(" res->values[%d] = ", i)); for (int32_t j = 0; j < n; ++j) { cb_gen_push(gen, cb_format("%s(v->values[%d] * m->values[%d][%d])", prefix, j, i, j)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn float vec%d%s_magnitude", @@ -417,18 +427,18 @@ cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, bool i cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {\n float dot = {0};"); + cb_gen_push_line(gen, "{\n float dot = {0};"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += (float)(v1->values[%d] * v1->values[%d]);", - i, i)); + cb_gen_push_line(gen, cb_format(" dot += (float)(v1->values[%d] * v1->values[%d]);", i, i)); } - cb_gen_push(gen, "\n float res = sqrtf(dot);" - "\n return res;" - "\n}\n\n"); + cb_gen_push_line(gen, " float res = sqrtf(dot);"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn double vec%d%s_magnitude64", @@ -437,18 +447,18 @@ cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, bool cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {\n double dot = {0};"); + cb_gen_push_line(gen, "{\n double dot = {0};"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += (double)(v1->values[%d] * v1->values[%d]);", - i, i)); + cb_gen_push_line(gen, cb_format(" dot += (double)(v1->values[%d] * v1->values[%d]);", i, i)); } - cb_gen_push(gen, "\n double res = sqrt(dot);" - "\n return res;" - "\n}\n\n"); + cb_gen_push_line(gen, " double res = sqrt(dot);"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn float vec%d%s_distance", @@ -458,19 +468,18 @@ cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, bool im cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s diff = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s diff = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n diff.values[%d] = v1->values[%d] - v2->values[%d];", i, i, i)); + cb_gen_push_line(gen, cb_format(" diff.values[%d] = v1->values[%d] - v2->values[%d];", i, i, i)); } - cb_gen_push(gen, "\n float dot = {0};"); + cb_gen_push_line(gen, " float dot = {0};"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += (float)(diff.values[%d] * diff.values[%d]);", - i, i)); + cb_gen_push_line(gen, cb_format(" dot += (float)(diff.values[%d] * diff.values[%d]);", i, i)); } - cb_gen_push(gen, "\n float res = sqrtf(dot);" - "\n return res;" - "\n}\n\n"); + cb_gen_push_line(gen, " float res = sqrtf(dot);"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void @@ -484,18 +493,17 @@ cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, bool i cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s diff = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s diff = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n diff.values[%d] = v1->values[%d] - v2->values[%d];", i, i, i)); + cb_gen_push_line(gen, cb_format(" diff.values[%d] = v1->values[%d] - v2->values[%d];", i, i, i)); } - cb_gen_push(gen, "\n float dot = {0};"); + cb_gen_push_line(gen, " float dot = {0};"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += (float)(diff.values[%d] * diff.values[%d]);", - i, i)); + cb_gen_push_line(gen, cb_format(" dot += (float)(diff.values[%d] * diff.values[%d]);", i, i)); } - cb_gen_push(gen, "\n return dot;" - "\n}\n\n"); + cb_gen_push_line(gen, " return dot;"); + cb_gen_push(gen, "}\n\n"); } static inline void @@ -508,15 +516,17 @@ cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, bool implementation) cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec3%s res = {0};", suffix)); - cb_gen_push(gen, "\n res.values[0] = v1.values[1] * v2.values[2] - v1.values[2] * v2.values[1];"); - cb_gen_push(gen, "\n res.values[1] = v1.values[2] * v2.values[0] - v1.values[0] * v2.values[2];"); - cb_gen_push(gen, "\n res.values[2] = v1.values[0] * v2.values[1] - v1.values[1] * v2.values[0];"); - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, cb_format("{" "\n Vec3%s res = {0};", suffix)); + cb_gen_push_line(gen, " res.values[0] = v1.values[1] * v2.values[2] - v1.values[2] * v2.values[1];"); + cb_gen_push_line(gen, " res.values[1] = v1.values[2] * v2.values[0] - v1.values[0] * v2.values[2];"); + cb_gen_push_line(gen, " res.values[2] = v1.values[0] * v2.values[1] - v1.values[1] * v2.values[0];"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n < CB_LINAGEN_MATNN_COPY_CAP) { @@ -526,13 +536,14 @@ cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool impl cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n m1.values[%d][%d] *= k;", i, j)); + cb_gen_push_line(gen, cb_format(" m1.values[%d][%d] *= k;", i, j)); } } - cb_gen_push(gen, "\n return m1;" "\n}\n\n"); + cb_gen_push_line(gen, " return m1;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_scale", n, type)); cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); @@ -541,14 +552,13 @@ cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool impl cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] * k;", - i, j, i, j)); + cb_gen_push_line(gen, cb_format(" res->values[%d][%d] = m1->values[%d][%d] * k;", i, j, i, j)); } } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } @@ -576,6 +586,7 @@ cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, bo static void cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_MATNN_COPY_CAP) { @@ -585,20 +596,21 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Mat%d%s res = {0};", n, suffix)); for (int32_t col = 0; col < n; ++col) { for (int32_t row = 0; row < n; ++row) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", col, row)); + cb_gen_push(gen, cb_format(" res.values[%d][%d] = ", col, row)); char *prefix = ""; for (int32_t k = 0; k < n; ++k) { cb_gen_push(gen, cb_format("%s(m1.values[%d][%d] * m2.values[%d][%d])", prefix, k, row, col, k)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_dot", n, type)); cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); @@ -607,25 +619,26 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implem cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t col = 0; col < n; ++col) { for (int32_t row = 0; row < n; ++row) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = ", col, row)); + cb_gen_push(gen, cb_format(" res->values[%d][%d] = ", col, row)); char *prefix = ""; for (int32_t k = 0; k < n; ++k) { cb_gen_push(gen, cb_format("%s(m1->values[%d][%d] * m2->values[%d][%d])", prefix, k, row, col, k)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_MATNN_COPY_CAP) { @@ -635,18 +648,19 @@ cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, bool imple cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Vec%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { char *prefix = ""; - cb_gen_push(gen, cb_format("\n res.values[%d] = ", i)); + cb_gen_push(gen, cb_format(" res.values[%d] = ", i)); for (int32_t j = 0; j < n; ++j) { cb_gen_push(gen, cb_format("%s(m.values[%d][%d] * v.values[%d])", prefix, j, i, j)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push_line(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_mulv", n, type)); cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); @@ -655,23 +669,24 @@ cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, bool imple cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { char *prefix = ""; - cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); + cb_gen_push(gen, cb_format(" res->values[%d] = ", i)); for (int32_t j = 0; j < n; ++j) { cb_gen_push(gen, cb_format("%s(m->values[%d][%d] * v->values[%d])", prefix, j, i, j)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } static void cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, bool implementation) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_MATNN_COPY_CAP) { @@ -679,23 +694,23 @@ cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, bool i cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Mat%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = 1;", i, i)); + cb_gen_push_line(gen, cb_format(" res.values[%d][%d] = 1;", i, i)); } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_identity", n, type)); cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); - cb_gen_push(gen, "\n memset(res, 0, sizeof *res);"); + cb_gen_push_line(gen, "{" "\n memset(res, 0, sizeof *res);"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = 1;", i, i)); + cb_gen_push_line(gen, cb_format(" res->values[%d][%d] = 1;", i, i)); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } @@ -709,11 +724,12 @@ cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, bool cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < 3; ++i) { - cb_gen_push(gen, cb_format("\n m.values[3][%d] += by.values[%d];", i, i)); + cb_gen_push_line(gen, cb_format(" m.values[3][%d] += by.values[%d];", i, i)); } - cb_gen_push(gen, "\n return m;" "\n}\n\n"); + cb_gen_push_line(gen, " return m;"); + cb_gen_push(gen, "}\n\n"); } static void @@ -726,11 +742,12 @@ cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, bool cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < 3; ++i) { - cb_gen_push(gen, cb_format("\n m.values[3][%d] = to.values[%d];", i, i)); + cb_gen_push_line(gen, cb_format(" m.values[3][%d] = to.values[%d];", i, i)); } - cb_gen_push(gen, "\n return m;" "\n}\n\n"); + cb_gen_push_line(gen, " return m;"); + cb_gen_push(gen, "}\n\n"); } static void @@ -744,28 +761,29 @@ cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, bool imple cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" - "\n Mat4%s res = {0};" - "\n float radians = degrees * %.16ff / 180.f;", suffix, (float)M_PI)); - cb_gen_push(gen, cb_format("\n Mat4%s rot = { .values = {" - "\n { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 }," - "\n { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 }," - "\n { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 }," - "\n { 0, 0, 0, 1 }" - "\n }};" , suffix)); + cb_gen_push(gen, "{\n"); + cb_gen_push_line(gen, cb_format(" Mat4%s res = {0};", suffix)); + cb_gen_push_line(gen, cb_format(" float radians = degrees * %.16ff / 180.f;", (double)M_PI)); + cb_gen_push_line(gen, cb_format(" Mat4%s rot = { .values = {", suffix)); + cb_gen_push_line(gen, " { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 },"); + cb_gen_push_line(gen, " { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 },"); + cb_gen_push_line(gen, " { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 },"); + cb_gen_push_line(gen, " { 0, 0, 0, 1 }"); + cb_gen_push_line(gen, " }};"); for (int32_t i = 0; i < 4; ++i) { for (int32_t j = 0; j < 4; ++j) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); + cb_gen_push(gen, cb_format(" res.values[%d][%d] = ", i, j)); char *prefix = ""; for (int32_t k = 0; k < 4; ++k) { cb_gen_push(gen, cb_format("%s(rot.values[%d][%d]) * m.values[%d][%d]", prefix, k, j, i, k)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } static void @@ -779,31 +797,31 @@ cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, bool i cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Mat4%s res = {0};", suffix)); - cb_gen_push(gen, cb_format("\n Mat4%s rot = { .values = {" - "\n { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 }," - "\n { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 }," - "\n { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 }," - "\n { 0, 0, 0, 1 }" - "\n }};" , suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Mat4%s res = {0};", suffix)); + cb_gen_push(gen, cb_format(" Mat4%s rot = { .values = {", suffix)); + cb_gen_push_line(gen, " { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 },"); + cb_gen_push_line(gen, " { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 },"); + cb_gen_push_line(gen, " { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 },"); + cb_gen_push_line(gen, " { 0, 0, 0, 1 }"); + cb_gen_push_line(gen, " }};"); for (int32_t i = 0; i < 4; ++i) { for (int32_t j = 0; j < 4; ++j) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); + cb_gen_push(gen, cb_format(" res.values[%d][%d] = ", i, j)); char *prefix = ""; for (int32_t k = 0; k < 4; ++k) { cb_gen_push(gen, cb_format("%s(rot.values[%d][%d]) * m.values[%d][%d]", prefix, k, j, i, k)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } 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, bool 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)); @@ -812,32 +830,31 @@ cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); - cb_gen_push(gen, cb_format("\n Mat4%s res = {0};" - "\n Mat4%s scale = {0};" - "\n scale.values[0][0] = v.values[0];" - "\n scale.values[1][1] = v.values[1];" - "\n scale.values[2][2] = v.values[2];" - "\n scale.values[3][3] = 1;", - suffix, suffix)); + cb_gen_push(gen, "{\n"); + cb_gen_push_line(gen, cb_format(" Mat4%s res = {0};", suffix)); + cb_gen_push_line(gen, cb_format(" Mat4%s scale = {0};", suffix)); + cb_gen_push_line(gen, " scale.values[0][0] = v.values[0];"); + cb_gen_push_line(gen, " scale.values[1][1] = v.values[1];"); + cb_gen_push_line(gen, " scale.values[2][2] = v.values[2];"); + cb_gen_push_line(gen, " scale.values[3][3] = 1;"); for (int32_t i = 0; i < 4; ++i) { for (int32_t j = 0; j < 4; ++j) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); + cb_gen_push(gen, cb_format(" res.values[%d][%d] = ", i, j)); char *prefix = ""; for (int32_t k = 0; k < 4; ++k) { cb_gen_push(gen, cb_format("%s(scale.values[%d][%d]) * m.values[%d][%d]", prefix, k, j, i, k)); prefix = " + "; } - cb_gen_push(gen, ";"); + cb_gen_push_line(gen, ";"); } } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } 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, bool 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)); @@ -846,22 +863,21 @@ cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); - cb_gen_push(gen, cb_format("\n Mat4%s res = {0};" - "\n res.values[0][0] = 2 / (right - left);" - "\n res.values[1][1] = 2 / (top - bottom);" - "\n res.values[2][2] = -2 / (far - near);" - "\n res.values[3][0] = -(right + left) / (right - left);" - "\n res.values[3][1] = -(top + bottom) / (top - bottom);" - "\n res.values[3][2] = -(far + near) / (far - near);" - "\n res.values[3][3] = 1;", - suffix, suffix)); - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push(gen, "{\n"); + cb_gen_push_line(gen, cb_format(" Mat4%s res = {0};", suffix)); + cb_gen_push_line(gen, " res.values[0][0] = 2 / (right - left);"); + cb_gen_push_line(gen, " res.values[1][1] = 2 / (top - bottom);"); + cb_gen_push_line(gen, " res.values[2][2] = -2 / (far - near);"); + cb_gen_push_line(gen, " res.values[3][0] = -(right + left) / (right - left);"); + cb_gen_push_line(gen, " res.values[3][1] = -(top + bottom) / (top - bottom);"); + cb_gen_push_line(gen, " res.values[3][2] = -(far + near) / (far - near);"); + cb_gen_push_line(gen, " res.values[3][3] = 1;"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } 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, bool 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)); @@ -869,23 +885,22 @@ cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" - "\n float yfov_radians = yfov_degree * %.16ff / 180.f;" - "\n %s top = near * tanf(yfov_radians/2);" - "\n %s right = top * aspect_ratio;" - "\n Mat4%s res = {0};" - "\n res.arr[0] = near / right;" - "\n res.arr[5] = near / top;" - "\n res.arr[10] = -(far + near) / (far - near);" - "\n res.arr[11] = -1;" - "\n res.arr[14] = -(2 * far * near) / (far - near);", - M_PI, type, type, suffix, suffix)); - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push(gen, "{\n"); + cb_gen_push_line(gen, cb_format(" float yfov_radians = yfov_degree * %.16ff / 180.f;", M_PI)); + cb_gen_push_line(gen, cb_format(" %s top = near * tanf(yfov_radians/2);", type)); + cb_gen_push_line(gen, cb_format(" %s right = top * aspect_ratio;", type)); + cb_gen_push_line(gen, cb_format(" Mat4%s res = {0};", suffix)); + cb_gen_push_line(gen, " res.arr[0] = near / right;"); + cb_gen_push_line(gen, " res.arr[5] = near / top;"); + cb_gen_push_line(gen, " res.arr[10] = -(far + near) / (far - near);"); + cb_gen_push_line(gen, " res.arr[11] = -1;"); + cb_gen_push_line(gen, " res.arr[14] = -(2 * far * near) / (far - near);"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } 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, bool 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)); @@ -893,17 +908,17 @@ cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); - cb_gen_push(gen, cb_format("\n %s top = near * tanf(yfov_radians/2);" - "\n %s right = top * aspect_ratio;" - "\n Mat4%s res = {0};" - "\n res.arr[0] = near / right;" - "\n res.arr[5] = near / top;" - "\n res.arr[10] = -(far + near) / (far - near);" - "\n res.arr[11] = -1;" - "\n res.arr[14] = -(2 * far * near) / (far - near);", - type, type, suffix, suffix)); - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push(gen, "{\n"); + cb_gen_push_line(gen, cb_format(" %s top = near * tanf(yfov_radians/2);", type)); + cb_gen_push_line(gen, cb_format(" %s right = top * aspect_ratio;", type)); + cb_gen_push_line(gen, cb_format(" Mat4%s res = {0};", suffix)); + cb_gen_push_line(gen, " res.arr[0] = near / right;"); + cb_gen_push_line(gen, " res.arr[5] = near / top;"); + cb_gen_push_line(gen, " res.arr[10] = -(far + near) / (far - near);"); + cb_gen_push_line(gen, " res.arr[11] = -1;"); + cb_gen_push_line(gen, " res.arr[14] = -(2 * far * near) / (far - near);"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } @@ -911,37 +926,37 @@ internal void cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type, int32_t n, bool implementation, char *func_name, char op) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n <= CB_LINAGEN_VECN_COPY_CAP) { cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_%s", n, suffix, n, type, func_name)); - 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_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); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n v1.values[%d] %c= v2.values[%d];", - i, op, i)); + cb_gen_push_line(gen, cb_format(" v1.values[%d] %c= v2.values[%d];", i, op, i)); } - cb_gen_push(gen, "\n return v1;" "\n}\n\n"); + cb_gen_push_line(gen, " return v1;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_%s", n, type, func_name)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); - 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_arg(gen, cb_format("Vec%d%s *res", n, suffix)); + 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); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] %c v2->values[%d];", - i, i, op, i)); + cb_gen_push_line(gen, cb_format(" res->values[%d] = v1->values[%d] %c v2->values[%d];", i, i, op, i)); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } @@ -949,6 +964,7 @@ internal void cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type, int32_t n, bool implementation, char *func_name, char op) { + assert(n > 1); char *suffix = strdup(type); *suffix = char_toupper(*type); if (n < CB_LINAGEN_MATNN_COPY_CAP) { @@ -959,14 +975,14 @@ cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + cb_gen_push_line(gen, cb_format("{" "\n Mat%d%s res = {0};", n, suffix)); for (int32_t i = 0; i < n; ++i) { for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n res.values[%d][%d] = m1.values[%d][%d] %c m2.values[%d][%d];", - i, j, i, j, op, i, j)); + cb_gen_push_line(gen, cb_format(" res.values[%d][%d] = m1.values[%d][%d] %c m2.values[%d][%d];", i, j, i, j, op, i, j)); } } - cb_gen_push(gen, "\n return res;" "\n}\n\n"); + cb_gen_push_line(gen, " return res;"); + cb_gen_push(gen, "}\n\n"); } else { cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_%s", n, type, func_name)); @@ -976,14 +992,13 @@ cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type, cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); + cb_gen_push(gen, "{\n"); for (int32_t i = 0; i < n; ++i) { for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] %c m2->values[%d][%d];", - i, j, i, j, op, i, j)); + cb_gen_push_line(gen, cb_format(" res->values[%d][%d] = m1->values[%d][%d] %c m2->values[%d][%d];", i, j, i, j, op, i, j)); } } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "}\n\n"); } } diff --git a/extra/cbuild_tests.h b/extra/cbuild_tests.h index f0a8d41..f79e0e7 100644 --- a/extra/cbuild_tests.h +++ b/extra/cbuild_tests.h @@ -67,8 +67,8 @@ static void cb_test_run(void) { } } cb_assertion_handler = cb_assertion_break; - cb_println(CB_LogLevel_Info, "Summary: %d/%d tests passed", - test_passed_count, cb_tests.count); + cb_print(CB_LogLevel_Info, "Summary: %d/%d tests passed\n", + test_passed_count, cb_tests.count); } internal void cb_test_register(struct CB_Test test) { -- 2.52.0