]> git.leonardobizzoni.com Git - CBuild/commitdiff
Stuff that i forgot about master
authorLeonardoBizzoni <leo2002714@gmail.com>
Mon, 18 May 2026 18:33:09 +0000 (20:33 +0200)
committerLeonardoBizzoni <leo2002714@gmail.com>
Mon, 18 May 2026 18:33:09 +0000 (20:33 +0200)
cbuild.h
extra/cbuild_biblo.h
extra/cbuild_linagen.h
extra/cbuild_tests.h

index 3de54bc239a6fa0c1b80d6ef4f40f5ecbb2196d0..f7dece567b8e6ffbc0269812f8ea8971332ed162 100644 (file)
--- a/cbuild.h
+++ b/cbuild.h
@@ -195,17 +195,29 @@ static time64 time64_from_systemtime(const SYSTEMTIME *in);
 
 // ================================================================================
 // Strings & Arrays
-typedef struct CB_StringView CB_StringView;
-struct CB_StringView {
+typedef struct CB_String8 CB_String8;
+struct CB_String8 {
   u8 *data;
   int64_t length;
 };
 
+typedef struct CB_String16 CB_String16;
+struct CB_String16 {
+  u16 *data;
+  int64_t length;
+};
+
+typedef struct CB_UTFCodepoint CB_UTFCodepoint;
+struct CB_UTFCodepoint {
+  u32 codepoint;
+  u8 size;
+};
+
 typedef struct CB_StringBuilder_Node CB_StringBuilder_Node;
 struct CB_StringBuilder_Node {
   struct CB_StringBuilder_Node *prev;
   struct CB_StringBuilder_Node *next;
-  CB_StringView value;
+  CB_String8 value;
 };
 
 typedef struct CB_StringBuilder CB_StringBuilder;
@@ -231,9 +243,9 @@ enum {
   CB_LogLevel_COUNT,
 };
 
-#define cb_strlit(cstr) (CB_StringView) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
+#define cb_strlit(cstr) (CB_String8) { .data = (u8*)(cstr), .length = cb_arrlength(cstr) - 1 }
 #define cb_strinit(cstr) { .data = (cstr), .length = cb_arrlength(cstr) - 1 }
-#define cb_view_expand(view) (s32)(view).length, (view).data
+#define cb_str8_expand(str8) (s32)(str8).length, (str8).data
 
 #define cb_array(CArrayLitteral) (CB_Array) { .data = (CArrayLitteral), .length = cb_arrlength((CArrayLitteral)) }
 
@@ -336,18 +348,23 @@ enum {
 static void cb_print(CB_LogLevel level, const char *fmt, ...);
 
 static char* cb_format(const char *format, ...);
-static char* cb_cstr_from_view(CB_StringView view);
+static char* cb_cstr_from_str8(CB_String8 str8);
+static wchar_t* cb_wstr_from_str8(CB_String8 str8);
 
-static CB_StringView cb_view_from_cstr(const char *cstr);
-static b8 cb_view_starts_with(const char *string, CB_StringView sv);
-static void cb_view_trim(CB_StringView *sv);
-static CB_StringBuilder cb_view_split(CB_StringView sv, char delim);
+static CB_String16 cb_str16_from_str8(CB_String8 in);
+static CB_String8 cb_str8_from_str16(CB_String16 in);
 
-static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv);
+static CB_String8 cb_str8_from_cstr(const char *cstr);
+static CB_String8 cb_str8_from_cstr_copy(const char *cstr);
+static b8 cb_str8_starts_with(const char *string, CB_String8 sv);
+static void cb_str8_trim(CB_String8 *sv);
+static CB_StringBuilder cb_str8_split(CB_String8 sv, char delim);
+
+static void cb_sb_append(CB_StringBuilder *sb, CB_String8 sv);
 static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other);
-static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch);
+static CB_String8 cb_sb_join_with_ch(CB_StringBuilder sb, char ch);
 
-static b8 cb_cli_contains(int32_t argc, char **argv, const char *target);
+static s32 cb_cli_find(int32_t argc, char **argv, const char *target);
 
 internal char* cb_format_va(const char *format, va_list args);
 
@@ -441,10 +458,10 @@ struct CB_FileIterator {
 #endif
 
 static CB_FileProperties cb_file_properties(CB_FileHandle hfile);
-static CB_StringView cb_file_read(CB_FileHandle hfile, s64 size, s64 offset);
+static CB_String8 cb_file_read(CB_FileHandle hfile, s64 size, s64 offset);
 static u8* cb_file_memory_map(CB_FileHandle hfile, s64 size, s64 offset);
-static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_StringView content);
-static void cb_file_write_at_offset(CB_FileHandle hfile, CB_StringView content, s64 offset);
+static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_String8 content);
+static void cb_file_write_at_offset(CB_FileHandle hfile, CB_String8 content, s64 offset);
 static b8 cb_file_pointer_set_position_absolute(CB_FileHandle hfile, s64 position);
 static b8 cb_file_pointer_set_position_relative(CB_FileHandle hfile, s64 offset);
 static b8 cb_file_flush(CB_FileHandle hfile);
@@ -452,21 +469,21 @@ static b8 cb_file_set_size(CB_FileHandle hfile, s64 new_size);
 static void cb_file_memory_unmap(u8 *file_map, s64 size);
 static void cb_file_close(CB_FileHandle hfile);
 
-static CB_FileHandle cb_filesystem_open(CB_StringView path, CB_AccessFlag flags);
-static CB_FileHandle cb_filesystem_open_temp(CB_StringView *path);
-static CB_FileProperties cb_filesystem_properties(CB_StringView path);
-static void cb_filesystem_delete(CB_StringView path);
-static b8 cb_filesystem_exists(CB_StringView path);
-static b8 cb_filesystem_rename(CB_StringView old, CB_StringView new);
-static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest);
-static b8 cb_filesystem_link_create_symbolic(CB_StringView realpath, CB_StringView linkpath);
-static b8 cb_filesystem_link_create_physical(CB_StringView realpath, CB_StringView linkpath);
-static CB_StringView cb_filesystem_link_read(CB_StringView linkpath);
-static b8 cb_filesystem_directory_create(CB_StringView path);
-static b8 cb_filesystem_directory_copy(CB_StringView path, CB_StringView new);
-static b8 cb_filesystem_directory_delete(CB_StringView path, b8 recursive);
-static CB_StringView cb_filesystem_filename_from_path(CB_StringView path);
-static CB_StringView cb_filesystem_path_canonicalize(CB_StringView path);
+static CB_FileHandle cb_filesystem_open(CB_String8 path, CB_AccessFlag flags);
+static CB_FileHandle cb_filesystem_open_temp(CB_String8 *path);
+static CB_FileProperties cb_filesystem_properties(CB_String8 path);
+static void cb_filesystem_delete(CB_String8 path);
+static b8 cb_filesystem_exists(CB_String8 path);
+static b8 cb_filesystem_rename(CB_String8 old, CB_String8 new);
+static b8 cb_filesystem_copy(CB_String8 path_source, CB_String8 path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest);
+static b8 cb_filesystem_link_create_symbolic(CB_String8 realpath, CB_String8 linkpath);
+static b8 cb_filesystem_link_create_physical(CB_String8 realpath, CB_String8 linkpath);
+static CB_String8 cb_filesystem_link_read(CB_String8 linkpath);
+static b8 cb_filesystem_directory_create(CB_String8 path);
+static b8 cb_filesystem_directory_copy(CB_String8 path, CB_String8 new);
+static b8 cb_filesystem_directory_delete(CB_String8 path, b8 recursive);
+static CB_String8 cb_filesystem_filename_from_path(CB_String8 path);
+static CB_String8 cb_filesystem_path_canonicalize(CB_String8 path);
 
 static void cb_filesystem_iter_begin(CB_FileIterator *it, const char *rootpath);
 static b8 cb_filesystem_iter_next(CB_FileIterator *it, CB_FileInfo *output);
@@ -583,12 +600,11 @@ static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_A
 #  define MAX_ENVVAR 32767
 #endif
 
-static char* cb_getenv(const char *varname);
-static b8 cb_setenv(const char *varname, const char *value);
-
-// ==============================================================================
-// Implementation
+static CB_String8 cb_getenv(CB_String8 varname);
+static b8 cb_setenv(CB_String8 varname, CB_String8 value);
+static b8 cb_unsetenv(CB_String8 varname);
 
+#ifndef CBUILD_NOIMPL
 // ================================================================================
 // Static arena impl
 static inline u64 cb_align_forward(u64 x, u64 align)
@@ -713,19 +729,142 @@ static char* cb_format(const char *format, ...)
   return res;
 }
 
-static char* cb_cstr_from_view(CB_StringView view)
+static char* cb_cstr_from_str8(CB_String8 str8)
+{
+  assert(str8.length > 0);
+  assert(str8.data != NULL);
+  char *res = cb_arena_push_many(char, str8.length + 1);
+  cb_memcopy(res, str8.data, str8.length);
+  res[str8.length] = '\0';
+  return res;
+}
+
+static wchar_t* cb_wstr_from_str8(CB_String8 str8)
 {
-  assert(view.length > 0);
-  assert(view.data != NULL);
-  char *res = cb_arena_push_many(char, view.length + 1);
-  cb_memcopy(res, view.data, view.length);
-  res[view.length] = '\0';
+  CB_String16 str16 = cb_str16_from_str8(str8);
+  assert(str16.length > 0);
+  assert(str16.data != NULL);
+  wchar_t *res = cb_arena_push_many(wchar_t, str16.length + 1);
+  cb_memcopy(res, str16.data, str16.length * (s64)sizeof(u16));
+  res[str16.length] = (u16)0;
+  return res;
+}
+
+
+static CB_String8 cb_str8_from_str16(CB_String16 in)
+{
+  assert(in.length > 0);
+  assert(in.data != NULL);
+  CB_String8 res = {0};
+
+  // Worst case: every UTF-16 code unit becomes 3 UTF-8 bytes
+  s64 approx_size = in.length * 3;
+  u8 *bytes = cb_arena_push_many(u8, approx_size);
+  if (!bytes) { return res; }
+
+  u8 *dst = bytes;
+
+  for (u16 *src = in.data, *end = src + in.length; src < end; ) {
+    u32 codepoint;
+
+    // Handle surrogate pairs
+    if (*src >= 0xD800 && *src <= 0xDBFF && src + 1 < end &&
+        src[1] >= 0xDC00 && src[1] <= 0xDFFF) {
+      codepoint = (((src[0] - 0xD800U) << 10U) |
+                   (src[1] - 0xDC00U)) + 0x10000U;
+      src += 2;
+    } else {
+      codepoint = *src++;
+    }
+
+    // Encode UTF-8
+    if (codepoint < 0x80) {
+      *dst++ = (u8)codepoint;
+    } else if (codepoint < 0x800) {
+      *dst++ = (u8)(0xC0 | (codepoint >> 6));
+      *dst++ = (u8)(0x80 | (codepoint & 0x3F));
+    } else if (codepoint < 0x10000) {
+      *dst++ = (u8)(0xE0 | (codepoint >> 12));
+      *dst++ = (u8)(0x80 | ((codepoint >> 6) & 0x3F));
+      *dst++ = (u8)(0x80 | (codepoint & 0x3F));
+    } else {
+      *dst++ = (u8)(0xF0 | (codepoint >> 18));
+      *dst++ = (u8)(0x80 | ((codepoint >> 12) & 0x3F));
+      *dst++ = (u8)(0x80 | ((codepoint >> 6) & 0x3F));
+      *dst++ = (u8)(0x80 | (codepoint & 0x3F));
+    }
+  }
+
+  s64 res_size = dst - bytes;
+  cb_arena_pop(approx_size - res_size);
+
+  res.data = bytes;
+  res.length = res_size;
   return res;
 }
 
-static CB_StringView cb_view_from_cstr(const char *cstr)
+static CB_String16 cb_str16_from_str8(CB_String8 in)
 {
-  CB_StringView res = {0};
+  assert(in.length > 0);
+  assert(in.data != NULL);
+
+  CB_String16 res = {0};
+  s64 res_size = 0, approx_size = in.length * 2;
+  u16 *words = cb_arena_push_many(u16, approx_size), *res_offset = words;
+  if (!words) { return res; }
+
+  CB_UTFCodepoint codepoint = {0};
+  for (const u8 *start = in.data, *end = in.data + in.length;
+       start < end;
+       start += codepoint.size) {
+    if ((*start & 0x80) == 0) {
+      codepoint.codepoint = *start;
+      codepoint.size = 1;
+    } else if ((*start & 0xE0) == 0xC0) {
+      codepoint.codepoint = start[1] & 0x3F;
+      codepoint.codepoint |= (u32)(start[0] & 0x1F) << 6;
+      codepoint.size = 2;
+    } else if ((*start & 0xF0) == 0xE0) {
+      codepoint.codepoint = start[2] & 0x3F;
+      codepoint.codepoint |= (u32)(start[1] & 0x3F) << 6;
+      codepoint.codepoint |= (u32)(start[0] & 0xf) << 12;
+      codepoint.size = 3;
+    } else if ((*start & 0xF8) == 0xF0) {
+      codepoint.codepoint = start[3] & 0x3F;
+      codepoint.codepoint |= (u32)(start[2] & 0x3F) << 6;
+      codepoint.codepoint |= (u32)(start[1] & 0x3F) << 12;
+      codepoint.codepoint |= (u32)(start[0] & 0x7) << 18;
+      codepoint.size = 4;
+    } else {
+      assert(false && "unreachable reached");
+    }
+
+    s64 utf16_codepoint_size;
+    if (codepoint.codepoint <= 0xD7FF || (codepoint.codepoint >= 0xE000 && codepoint.codepoint <= 0xFFFF)) {
+      res_offset[0] = (u16)codepoint.codepoint;
+      utf16_codepoint_size = 1;
+    } else if (codepoint.codepoint >= 0x10000 && codepoint.codepoint <= 0x10FFFF) {
+      res_offset[0] = (u16)(((codepoint.codepoint - 0x10000) >> 10) + 0xD800);
+      res_offset[1] = ((codepoint.codepoint - 0x10000) & 0x3FF) + 0xDC00;
+      utf16_codepoint_size = 2;
+    } else {
+      assert(false && "unreachable reached");
+    }
+
+    res_size += utf16_codepoint_size;
+    res_offset += utf16_codepoint_size;
+  }
+
+  assert(res_size >= 0);
+  cb_arena_pop(approx_size - res_size);
+  res.data = words;
+  res.length = res_size;
+  return res;
+}
+
+static CB_String8 cb_str8_from_cstr(const char *cstr)
+{
+  CB_String8 res = {0};
   res.data = (u8*)cstr;
   if (cstr != NULL) {
     const char *start = cstr;
@@ -735,7 +874,19 @@ static CB_StringView cb_view_from_cstr(const char *cstr)
   return res;
 }
 
-static b8 cb_view_starts_with(const char *string, CB_StringView sv)
+static CB_String8 cb_str8_from_cstr_copy(const char *cstr)
+{
+  CB_String8 res = {0};
+  if (cstr == NULL || *cstr == '\0') { return res; }
+  const char *start = cstr;
+  for (; *cstr; ++cstr);
+  res.length = cstr - start;
+  res.data = cb_arena_push_many(u8, res.length);
+  cb_memcopy(res.data, start, res.length);
+  return res;
+}
+
+static b8 cb_str8_starts_with(const char *string, CB_String8 sv)
 {
   if (string == NULL || sv.length == 0 || sv.data == NULL) { return false; }
   for (int32_t i = 0; i < sv.length; ++i) {
@@ -744,7 +895,7 @@ static b8 cb_view_starts_with(const char *string, CB_StringView sv)
   return true;
 }
 
-static void cb_view_trim(CB_StringView *sv)
+static void cb_str8_trim(CB_String8 *sv)
 {
   cb_assert(sv != NULL);
   if (sv->length <= 0) { return; }
@@ -758,17 +909,17 @@ static void cb_view_trim(CB_StringView *sv)
        sv->length -= 1) {}
 }
 
-static CB_StringBuilder cb_view_split(CB_StringView sv, char delim)
+static CB_StringBuilder cb_str8_split(CB_String8 sv, char delim)
 {
   CB_StringBuilder res = {0};
   if (sv.data == NULL || sv.length == 0) { return res; }
-  ssize_t prev = 0;
-  for (ssize_t i = 0; i < sv.length;) {
+  s64 prev = 0;
+  for (s64 i = 0; i < sv.length;) {
     if (sv.data[i] == delim) {
       if (prev != i) {
-        cb_sb_append(&res, (CB_StringView) {
+        cb_sb_append(&res, (CB_String8) {
           .data = sv.data + prev,
-          .length = (int64_t)(i - prev),
+          .length = (s64)(i - prev),
         });
       }
       do {
@@ -779,16 +930,16 @@ static CB_StringBuilder cb_view_split(CB_StringView sv, char delim)
     }
   }
   if (prev != sv.length) {
-    cb_sb_append(&res, (CB_StringView) {
+    cb_sb_append(&res, (CB_String8) {
       .data = sv.data + prev,
-      .length = (int64_t)(sv.length - prev),
+      .length = (s64)(sv.length - prev),
     });
   }
   cb_assert(res.node_count > 0);
   return res;
 }
 
-static void cb_sb_append(CB_StringBuilder *sb, CB_StringView sv)
+static void cb_sb_append(CB_StringBuilder *sb, CB_String8 sv)
 {
   cb_assert(sb != NULL);
   if (sv.length == 0 || sv.data == NULL) { return; }
@@ -815,9 +966,9 @@ static void cb_sb_concat(CB_StringBuilder *sb, const CB_StringBuilder *other)
   sb->last = other->last;
 }
 
-static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch)
+static CB_String8 cb_sb_join_with_ch(CB_StringBuilder sb, char ch)
 {
-  CB_StringView sv = {0};
+  CB_String8 sv = {0};
   sv.data = malloc((uint32_t)(sb.total_length + sb.node_count));
   sv.length = sb.total_length + sb.node_count - 1;
   int32_t offset = 0;
@@ -833,14 +984,14 @@ static CB_StringView cb_sb_join_with_ch(CB_StringBuilder sb, char ch)
   return sv;
 }
 
-static b8 cb_cli_contains(int32_t argc, char **argv, const char *target)
+static s32 cb_cli_find(int32_t argc, char **argv, const char *target)
 {
   for (int32_t i = 0; i < argc; ++i) {
     if (!strcmp(argv[i], target)) {
-      return true;
+      return i;
     }
   }
-  return false;
+  return -1;
 }
 
 internal char* cb_format_va(const char *format, va_list args)
@@ -871,13 +1022,13 @@ static CB_FileProperties cb_file_properties(CB_FileHandle hfile)
   assert(properties.size >= 0);
 
   if (file_info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL || file_info.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
-    properties.type = OS_FileType_Regular;
+    properties.type = CB_FileType_Regular;
   } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
-    properties.type = OS_FileType_Device_Block;
+    properties.type = CB_FileType_Device_Disk;
   } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-    properties.type = OS_FileType_Link;
+    properties.type = CB_FileType_Link;
   } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-    properties.type = OS_FileType_Directory;
+    properties.type = CB_FileType_Directory;
   } else {
     unreachable();
   }
@@ -885,7 +1036,7 @@ static CB_FileProperties cb_file_properties(CB_FileHandle hfile)
   assert((((u64)file_info.ftLastAccessTime.dwHighDateTime << 32) | file_info.ftLastAccessTime.dwLowDateTime) <= 0x8000000000000000);
   assert((((u64)file_info.ftLastWriteTime.dwHighDateTime << 32) | file_info.ftLastWriteTime.dwLowDateTime) <= 0x8000000000000000);
   SYSTEMTIME last_access_time = {0}, last_write_time = {0};
-  res = FileTimeToSystemTime(&file_info.ftLastAccessTime, &last_access_time);
+  BOOL res = FileTimeToSystemTime(&file_info.ftLastAccessTime, &last_access_time);
   assert(res == TRUE);
   res = FileTimeToSystemTime(&file_info.ftLastWriteTime, &last_write_time);
   assert(res == TRUE);
@@ -903,18 +1054,29 @@ static CB_FileProperties cb_file_properties(CB_FileHandle hfile)
 #endif
 }
 
-static CB_StringView cb_file_read(CB_FileHandle hfile, s64 size, s64 offset)
+static CB_String8 cb_file_read(CB_FileHandle hfile, s64 size, s64 offset)
 {
   assert(hfile != CB_FILEHANDLE_INVALID);
   assert(size > 0);
   assert(offset >= 0);
   assert(offset < size);
 
-  CB_StringView result = {0};
+  CB_String8 result = {0};
   u8 *buffer = cb_arena_push_many(u8, size);
 
 #if OS_WINDOWS
-  // TODO(lb): win32
+  LONG pointer_position_high = 0;
+  DWORD pointer_position_low = SetFilePointer(hfile, 0, &pointer_position_high, FILE_CURRENT);
+
+  DWORD bytes_read = 0;
+  SetFilePointer(hfile, 0, NULL, FILE_BEGIN);
+  BOOL res_read = ReadFile(hfile, buffer, (DWORD)size, &bytes_read, NULL);
+  SetFilePointer(hfile, (LONG)pointer_position_low, &pointer_position_high, FILE_BEGIN);
+  assert(bytes_read > 0);
+  assert(bytes_read <= size);
+  result.data = buffer;
+  result.length = bytes_read;
+  return result;
 #else
   s64 bytes_read = pread(hfile, buffer, (u64)size, offset);
   assert(bytes_read != -1);
@@ -934,6 +1096,7 @@ static u8* cb_file_memory_map(CB_FileHandle hfile, s64 size, s64 offset)
 
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   u8 *res = mmap(NULL, (u64)size, O_RDWR, MAP_SHARED, hfile, offset);
   assert(res != MAP_FAILED);
@@ -941,7 +1104,7 @@ static u8* cb_file_memory_map(CB_FileHandle hfile, s64 size, s64 offset)
 #endif
 }
 
-static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_StringView content)
+static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_String8 content)
 {
   assert(hfile != CB_FILEHANDLE_INVALID);
   assert(content.length > 0);
@@ -949,15 +1112,16 @@ static void cb_file_write_at_pointer(CB_FileHandle hfile, CB_StringView content)
 
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s64 bytes_wrote = write(hfile, cb_cstr_from_view(content), (u64)content.length);
+  s64 bytes_wrote = write(hfile, cb_cstr_from_str8(content), (u64)content.length);
   cb_scratch_end(scratch);
   assert(bytes_wrote == content.length);
 #endif
 }
 
-static void cb_file_write_at_offset(CB_FileHandle hfile, CB_StringView content, s64 offset)
+static void cb_file_write_at_offset(CB_FileHandle hfile, CB_String8 content, s64 offset)
 {
   assert(hfile != CB_FILEHANDLE_INVALID);
   assert(content.length > 0);
@@ -966,9 +1130,10 @@ static void cb_file_write_at_offset(CB_FileHandle hfile, CB_StringView content,
 
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s64 bytes_wrote = pwrite(hfile, cb_cstr_from_view(content), (u64)content.length, offset);
+  s64 bytes_wrote = pwrite(hfile, cb_cstr_from_str8(content), (u64)content.length, offset);
   cb_scratch_end(scratch);
   assert(bytes_wrote <= content.length);
 #endif
@@ -980,6 +1145,7 @@ static b8 cb_file_pointer_set_position_absolute(CB_FileHandle hfile, s64 positio
   assert(position > 0);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   off_t res = lseek(hfile, position, SEEK_SET);
   return res == 0;
@@ -991,6 +1157,7 @@ static b8 cb_file_pointer_set_position_relative(CB_FileHandle hfile, s64 offset)
   assert(hfile != CB_FILEHANDLE_INVALID);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   off_t res = lseek(hfile, offset, SEEK_CUR);
   return res == 0;
@@ -1002,6 +1169,7 @@ static b8 cb_file_flush(CB_FileHandle hfile)
   assert(hfile != CB_FILEHANDLE_INVALID);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   s32 res = fsync(hfile);
   return res == 0;
@@ -1014,6 +1182,7 @@ static b8 cb_file_set_size(CB_FileHandle hfile, s64 new_size)
   assert(new_size >= 0);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   s32 res = ftruncate(hfile, new_size);
   return res == 0;
@@ -1026,6 +1195,7 @@ static void cb_file_memory_unmap(u8 *file_map, s64 size)
   assert(size > 0);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   s32 res = munmap(file_map, (u64)size);
   assert(res == 0);
@@ -1036,20 +1206,38 @@ static void cb_file_close(CB_FileHandle hfile)
 {
   assert(hfile != CB_FILEHANDLE_INVALID);
 #if OS_WINDOWS
-  // TODO(lb): win32
+  BOOL res = CloseHandle(hfile);
+  assert(res == TRUE);
 #else
   s32 res = close(hfile);
   assert(res == 0);
 #endif
 }
 
-static CB_FileHandle cb_filesystem_open(CB_StringView path, CB_AccessFlag flags)
+static CB_FileHandle cb_filesystem_open(CB_String8 path, CB_AccessFlag flags)
 {
   assert(path.length > 0);
   assert(path.data != NULL);
 
 #if OS_WINDOWS
-  // TODO(lb): win32
+  DWORD access_flags = 0;
+  DWORD share_mode = FILE_SHARE_DELETE;
+  if (flags & CB_AccessFlag_Read) {
+    access_flags |= GENERIC_READ;
+    share_mode |= FILE_SHARE_READ;
+  }
+  if (flags & CB_AccessFlag_Write) {
+    access_flags |= GENERIC_WRITE;
+    share_mode |= FILE_SHARE_WRITE;
+  }
+  if (flags & CB_AccessFlag_Append) {
+    access_flags |= FILE_APPEND_DATA;
+  }
+
+  CB_Scratch scratch = cb_scratch_begin();
+  CB_FileHandle res = CreateFileW(cb_wstr_from_str8(path), access_flags, share_mode, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+  cb_scratch_end(scratch);
+  return res;
 #else
   s32 mode = O_CREAT;
   if ((flags & CB_AccessFlag_Read) && ((flags & CB_AccessFlag_Write) || (flags & CB_AccessFlag_Append))) {
@@ -1063,18 +1251,19 @@ static CB_FileHandle cb_filesystem_open(CB_StringView path, CB_AccessFlag flags)
   }
   if (flags & CB_AccessFlag_Append) { mode |= O_APPEND; }
   CB_Scratch scratch = cb_scratch_begin();
-  int32_t res = open(cb_cstr_from_view(path), mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+  int32_t res = open(cb_cstr_from_str8(path), mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
   cb_scratch_end(scratch);
   if (res == -1) { return CB_FILEHANDLE_INVALID; }
   return (CB_FileHandle)res;
 #endif
 }
 
-static CB_FileHandle cb_filesystem_open_temp(CB_StringView *path)
+static CB_FileHandle cb_filesystem_open_temp(CB_String8 *path)
 {
   assert(path != NULL);
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   path->length = cb_arrlength("/tmp/XXXXXX");
   char *bytes = cb_arena_push_many(char, path->length);
@@ -1086,66 +1275,105 @@ static CB_FileHandle cb_filesystem_open_temp(CB_StringView *path)
 #endif
 }
 
-static CB_FileProperties cb_filesystem_properties(CB_StringView path)
+static CB_FileProperties cb_filesystem_properties(CB_String8 path)
 {
   assert(path.length > 0);
   assert(path.data != NULL);
 
 #if OS_WINDOWS
-  // TODO(lb): get file properties from path on win32
-  CB_FileProperties res = {0};
-  return res;
+  CB_FileProperties properties = {0};
+
+  BY_HANDLE_FILE_INFORMATION file_info = {0};
+  CB_FileHandle fd = cb_filesystem_open(path, CB_AccessFlag_Read);
+  BOOL res = GetFileInformationByHandle(fd, &file_info);
+  cb_file_close(fd);
+  assert(res == TRUE);
+
+  properties.size = (((s64)file_info.nFileSizeHigh << 32) | file_info.nFileSizeLow);
+  assert(properties.size >= 0);
+
+  if (file_info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL ||
+      file_info.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
+    properties.type = CB_FileType_Regular;
+  } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
+    properties.type = CB_FileType_Device_Disk;
+  } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+    properties.type = CB_FileType_Link;
+  } else if (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+    properties.type = CB_FileType_Directory;
+  } else {
+    assert(false && "unreachable reached");
+  }
+
+  assert((((u64)file_info.ftLastAccessTime.dwHighDateTime << 32) | file_info.ftLastAccessTime.dwLowDateTime) <= 0x8000000000000000);
+  assert((((u64)file_info.ftLastWriteTime.dwHighDateTime << 32) | file_info.ftLastWriteTime.dwLowDateTime) <= 0x8000000000000000);
+  SYSTEMTIME last_access_time = {0}, last_write_time = {0};
+  res = FileTimeToSystemTime(&file_info.ftLastAccessTime, &last_access_time);
+  assert(res == TRUE);
+  res = FileTimeToSystemTime(&file_info.ftLastWriteTime, &last_write_time);
+  assert(res == TRUE);
+
+  properties.time_last_access = time64_from_systemtime(&last_access_time);
+  properties.time_last_status_change = time64_from_systemtime(&last_write_time);
+  properties.time_last_modification = properties.time_last_status_change;
+
+  return properties;
 #else
   struct stat file_stat = {0};
   CB_Scratch scratch = cb_scratch_begin();
-  s32 stat_res = stat(cb_cstr_from_view(path), &file_stat);
+  s32 stat_res = stat(cb_cstr_from_str8(path), &file_stat);
   cb_scratch_end(scratch);
   assert(stat_res == 0);
   return cb_fileproperties_from_stat(&file_stat);
 #endif
 }
 
-static void cb_filesystem_delete(CB_StringView path)
+static void cb_filesystem_delete(CB_String8 path)
 {
   assert(path.length > 0);
   assert(path.data != NULL);
 #if OS_WINDOWS
   // TODO(lb): implement file delete on win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  unlink(cb_cstr_from_view(path));
+  unlink(cb_cstr_from_str8(path));
   cb_scratch_end(scratch);
 #endif
 }
 
-static b8 cb_filesystem_exists(CB_StringView path)
+static b8 cb_filesystem_exists(CB_String8 path)
 {
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #  define F_OK 0
 #  define access _access
 #endif
   CB_Scratch scratch = cb_scratch_begin();
-  b8 res = (access(cb_cstr_from_view(path), F_OK) == 0);
+  b8 res = (access(cb_cstr_from_str8(path), F_OK) == 0);
   cb_scratch_end(scratch);
   return res;
 }
 
-static b8 cb_filesystem_rename(CB_StringView old, CB_StringView new)
+static b8 cb_filesystem_rename(CB_String8 old, CB_String8 new)
 {
 #if OS_WINDOWS
-  // TODO(lb): implement file rename on win32
+  CB_Scratch scratch = cb_scratch_begin();
+  BOOL res = MoveFileExW(cb_wstr_from_str8(old), cb_wstr_from_str8(new), MOVEFILE_REPLACE_EXISTING);
+  cb_scratch_end(scratch);
+  return res;
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  char *old_cstr = cb_cstr_from_view(old);
-  char *new_cstr = cb_cstr_from_view(new);
+  char *old_cstr = cb_cstr_from_str8(old);
+  char *new_cstr = cb_cstr_from_str8(new);
   b8 res = (rename(old_cstr, new_cstr) == 0);
   cb_scratch_end(scratch);
   return res;
 #endif
 }
 
-static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest)
+static b8 cb_filesystem_copy(CB_String8 path_source, CB_String8 path_dest, s64 bytes_to_copy, s64 offset_source, s64 offset_dest)
 {
   assert(bytes_to_copy > 0);
   assert(offset_source >= 0);
@@ -1154,10 +1382,11 @@ static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest,
   if (!cb_filesystem_exists(path_dest)) { assert(offset_dest == 0); }
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s32 src = open(cb_cstr_from_view(path_source), O_RDONLY, 0);
-  s32 dest = open(cb_cstr_from_view(path_dest), O_WRONLY | O_CREAT, 0644);
+  s32 src = open(cb_cstr_from_str8(path_source), O_RDONLY, 0);
+  s32 dest = open(cb_cstr_from_str8(path_dest), O_WRONLY | O_CREAT, 0644);
   cb_scratch_end(scratch);
   assert(src != -1);
   assert(dest != -1);
@@ -1177,47 +1406,50 @@ static b8 cb_filesystem_copy(CB_StringView path_source, CB_StringView path_dest,
 #endif
 }
 
-static b8 cb_filesystem_link_create_symbolic(CB_StringView realpath, CB_StringView linkpath)
+static b8 cb_filesystem_link_create_symbolic(CB_String8 realpath, CB_String8 linkpath)
 {
   assert(cb_filesystem_exists(realpath));
   assert(!cb_filesystem_exists(linkpath));
 #if OS_WINDOWS
   // TODO(lb): create symlink on win32
+  assert(false);
   return false;
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s32 res = symlink(cb_cstr_from_view(realpath), cb_cstr_from_view(linkpath));
+  s32 res = symlink(cb_cstr_from_str8(cb_filesystem_path_canonicalize(realpath)), cb_cstr_from_str8(linkpath));
   cb_scratch_end(scratch);
   return res == 0;
 #endif
 }
 
-static b8 cb_filesystem_link_create_physical(CB_StringView realpath, CB_StringView linkpath)
+static b8 cb_filesystem_link_create_physical(CB_String8 realpath, CB_String8 linkpath)
 {
   assert(cb_filesystem_properties(realpath).type != CB_FileType_Directory);
   assert(!cb_filesystem_exists(linkpath));
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s32 res = link(cb_cstr_from_view(realpath), cb_cstr_from_view(linkpath));
+  s32 res = link(cb_cstr_from_str8(realpath), cb_cstr_from_str8(linkpath));
   cb_scratch_end(scratch);
   return res == 0;
 #endif
 }
 
-static CB_StringView cb_filesystem_link_read(CB_StringView linkpath)
+static CB_String8 cb_filesystem_link_read(CB_String8 linkpath)
 {
   assert(cb_filesystem_exists(linkpath));
   assert(cb_filesystem_properties(linkpath).type == CB_FileType_Link);
-  CB_StringView res = {0};
+  CB_String8 res = {0};
 #if OS_WINDOWS
   // TODO(lb): win32
+  assert(false);
 #else
   s64 approx_length = 1024;
   char *buffer = cb_arena_push_many(char, approx_length);
   CB_Scratch scratch = cb_scratch_begin();
-  s64 length = readlink(cb_cstr_from_view(linkpath), buffer, (u64)approx_length);
+  s64 length = readlink(cb_cstr_from_str8(linkpath), buffer, (u64)approx_length);
   assert(length > 0);
   cb_scratch_end(scratch);
   cb_arena_pop(approx_length - length);
@@ -1227,20 +1459,25 @@ static CB_StringView cb_filesystem_link_read(CB_StringView linkpath)
   return res;
 }
 
-static b8 cb_filesystem_directory_create(CB_StringView path)
+static b8 cb_filesystem_directory_create(CB_String8 path)
 {
-  assert(!cb_filesystem_exists(path));
+  assert(path.length > 0);
+  assert(path.data != NULL);
+  if (cb_filesystem_exists(path)) { return false; }
 #if OS_WINDOWS
-  // TODO(lb): win32
+  CB_Scratch scratch = cb_scratch_begin();
+  BOOL res = CreateDirectoryW(cb_wstr_from_str8(path), NULL);
+  cb_scratch_end(scratch);
+  return res;
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  s32 res = mkdir(cb_cstr_from_view(path), (S_IRWXU) | (S_IRWXG) | (S_IROTH | S_IXOTH));
+  s32 res = mkdir(cb_cstr_from_str8(path), (S_IRWXU) | (S_IRWXG) | (S_IROTH | S_IXOTH));
   cb_scratch_end(scratch);
   return res == 0;
 #endif
 }
 
-static b8 cb_filesystem_directory_copy(CB_StringView dirpath, CB_StringView new)
+static b8 cb_filesystem_directory_copy(CB_String8 dirpath, CB_String8 new)
 {
   assert(cb_filesystem_exists(dirpath));
   assert(cb_filesystem_properties(dirpath).type == CB_FileType_Directory);
@@ -1249,38 +1486,78 @@ static b8 cb_filesystem_directory_copy(CB_StringView dirpath, CB_StringView new)
   return false;
 }
 
-static b8 cb_filesystem_directory_delete(CB_StringView path, b8 recursive)
+static b8 cb_filesystem_directory_delete(CB_String8 path, b8 recursive)
 {
   assert(cb_filesystem_exists(path));
   assert(cb_filesystem_properties(path).type == CB_FileType_Directory);
-  // TODO(lb): directory delete
+
+#if OS_WINDOWS
+  // TODO(lb): win32
+#else
+  if (!recursive) {
+    CB_Scratch scratch = cb_scratch_begin();
+    s32 res = rmdir(cb_cstr_from_str8(path));
+    cb_scratch_end(scratch);
+    return res == 0;
+  }
+
+  CB_Scratch scratch = cb_scratch_begin();
+  const char *dirpath = cb_cstr_from_str8(path);
+  DIR *dir = opendir(dirpath);
+  if (dir == NULL) {
+    cb_scratch_end(scratch);
+    return false;
+  }
+
+  struct dirent *entry = NULL;
+  while ((entry = readdir(dir)) != NULL) {
+    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; }
+    CB_String8 child = cb_str8_from_cstr(cb_format("%.*s/%s", cb_str8_expand(path), entry->d_name));
+    CB_FileProperties props = cb_filesystem_properties(child);
+    if (props.type == CB_FileType_Directory) {
+      if (!cb_filesystem_directory_delete(child, true)) { goto fail; }
+    } else {
+      if (unlink(cb_cstr_from_str8(child)) != 0) { goto fail; }
+    }
+  }
+  closedir(dir);
+  b8 result = rmdir(dirpath) == 0;
+  cb_scratch_end(scratch);
+  return result;
+ fail:
+  closedir(dir);
+  cb_scratch_end(scratch);
   return false;
+#endif
 }
 
-static CB_StringView cb_filesystem_filename_from_path(CB_StringView path)
+static CB_String8 cb_filesystem_filename_from_path(CB_String8 path)
 {
   assert(cb_filesystem_exists(path));
 #if OS_WINDOWS
-    // TODO(lb): win32
+  // TODO(lb): win32
+  assert(false);
 #else
-  const char *fullname = basename(cb_cstr_from_view(path));
+  const char *fullname = basename(cb_cstr_from_str8(path));
   assert(fullname != NULL);
-  CB_StringView res = cb_view_from_cstr(fullname);
+  CB_String8 res = cb_str8_from_cstr(fullname);
   return res;
 #endif
 }
 
-static CB_StringView cb_filesystem_path_canonicalize(CB_StringView path)
+static CB_String8 cb_filesystem_path_canonicalize(CB_String8 path)
 {
   assert(cb_filesystem_exists(path));
 #if OS_WINDOWS
-    // TODO(lb): win32
+  // TODO(lb): win32
+  assert(false);
 #else
   CB_Scratch scratch = cb_scratch_begin();
-  char *cstr_fullpath = realpath(cb_cstr_from_view(path), NULL);
+  char *cstr_fullpath = realpath(cb_cstr_from_str8(path), NULL);
   assert(cstr_fullpath != NULL);
   cb_scratch_end(scratch);
-  CB_StringView res = cb_view_from_cstr(cstr_fullpath);
+  CB_String8 res = cb_str8_from_cstr_copy(cstr_fullpath);
+  free(cstr_fullpath);
   return res;
 #endif
 }
@@ -1290,6 +1567,7 @@ static void cb_filesystem_iter_begin(CB_FileIterator *it, const char *rootpath)
   memset(&it->handle, 0, sizeof it->handle);
 #if OS_WINDOWS
   // TODO(lb): file iteration on win32
+  assert(false);
 #else
   it->handle.path = rootpath;
   it->handle.dir = opendir(rootpath);
@@ -1303,6 +1581,7 @@ static b8 cb_filesystem_iter_next(CB_FileIterator *it, CB_FileInfo *output)
 
 #if OS_WINDOWS
   // TODO(lb): file iteration on win32
+  assert(false);
   return false;
 #else
   struct dirent *entry = NULL;
@@ -1362,6 +1641,7 @@ static void cb_filesystem_iter_end(CB_FileIterator *it)
 {
 #if OS_WINDOWS
   // TODO(lb): file iteration on win32
+  assert(false);
 #else
   closedir(it->handle.dir);
 #endif
@@ -1539,11 +1819,14 @@ static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_A
   assert(build_options.length >= 0);
   if (build_options.length > 0) { assert(build_options.data != NULL); }
 
+  CB_String8 executable = cb_str8_from_cstr(argv[0]);
+  cb_str8_trim(&executable);
+  assert(executable.length > 0);
+  assert(executable.data != NULL);
+
   b8 should_rebuild = false;
-  CB_StringView executable = cb_view_from_cstr(argv[0]);
-  cb_view_trim(&executable);
   time64 last_edit_executable = cb_filesystem_properties(executable).time_last_modification;
-  CB_StringView *str_sources = sources.data;
+  CB_String8 *str_sources = sources.data;
   for (s64 i = 0; i < sources.length; ++i) {
     time64 last_edit_source = cb_filesystem_properties(str_sources[i]).time_last_modification;
     if (last_edit_executable < last_edit_source) {
@@ -1554,11 +1837,11 @@ static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_A
   if (!should_rebuild) { return; }
 
 #if OS_WINDOWS
+  CB_String8 executable_old = cb_str8_from_cstr(cb_format("%.*s.old", cb_str8_expand(executable)));
   {
     CB_Scratch scratch = cb_scratch_begin();
-    CB_StringView executable_old = cb_view_from_cstr(cb_format("%.*s.old", executable));
-    if (!cb_file_rename(executable, executable_old)) {
-      cb_print(CB_LogLevel_Info, "File rename failed: %.*s -> %.*s\n", cb_view_expand(executable), cb_view_expand(executable_old));
+    if (!cb_filesystem_rename(executable, executable_old)) {
+      cb_print(CB_LogLevel_Info, "File rename failed: %.*s -> %.*s\n", cb_str8_expand(executable), cb_str8_expand(executable_old));
       exit(-1);
     }
     cb_scratch_end(scratch);
@@ -1569,28 +1852,28 @@ static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_A
   cb_cmd_push(&cmd, CC);
 #if COMPILER_CL
   cb_cmd_append(&cmd, "/std:c11", "/nologo");
-  cb_cmd_push(&cmd, cb_format("/Fe:%.*s", cb_view_expand(executable)));
-  cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_sources[0])));
+  cb_cmd_push(&cmd, cb_format("/Fe:%.*s", cb_str8_expand(executable)));
+  cb_cmd_push(&cmd, cb_format("%.*s", cb_str8_expand(str_sources[0])));
 #else
   cb_cmd_push(&cmd, "-o");
-  cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(executable)));
-  cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_sources[0])));
+  cb_cmd_push(&cmd, cb_format("%.*s", cb_str8_expand(executable)));
+  cb_cmd_push(&cmd, cb_format("%.*s", cb_str8_expand(str_sources[0])));
 #endif
-  CB_StringView *str_build_options = build_options.data;
+  CB_String8 *str_build_options = build_options.data;
   for (s64 i = 0; i < build_options.length; ++i) {
-    cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(str_build_options[i])));
+    cb_cmd_push(&cmd, cb_format("%.*s", cb_str8_expand(str_build_options[i])));
   }
 
   cb_cmd_print(&cmd);
   CB_Process compilation_proc = cb_cmd_exec(&cmd);
   if (compilation_proc.status_code != 0) {
 #if OS_WINDOWS
-    cb_file_rename(executable_old, executable);
+    cb_filesystem_rename(executable_old, executable);
 #endif
     exit(-1);
   }
 
-  cb_cmd_push(&cmd, cb_format("%.*s", cb_view_expand(executable)));
+  cb_cmd_push(&cmd, cb_format("%.*s", cb_str8_expand(executable)));
   cb_cmd_append_dyn(&cmd, argv, (size_t)argc);
   (void)cb_cmd_exec(&cmd);
   exit(0);
@@ -1598,30 +1881,61 @@ static void cb_rebuild_and_restart(s32 argc, char **argv, CB_Array sources, CB_A
 
 // ==============================================================================
 // Environment variables
-static char* cb_getenv(const char *varname)
+static CB_String8 cb_getenv(CB_String8 varname)
 {
-  cb_assert(varname != NULL);
+  assert(varname.length > 0);
+  assert(varname.data != NULL);
 #if OS_WINDOWS
-  char *res = cb_arena_push_many(char, MAX_ENVVAR);
-  if (!GetEnvironmentVariableA(varname, res, MAX_ENVVAR)) {
-    cb_arena_pop(sizeof(char) * MAX_ENVVAR);
-    res = 0;
-  }
-  return res;
+  wchar_t *res = cb_arena_push_many(wchar_t, MAX_ENVVAR);
+  CB_Scratch scratch = cb_scratch_begin();
+  DWORD length = GetEnvironmentVariableW(cb_wstr_from_str8(varname), res, MAX_ENVVAR);
+  cb_scratch_end(scratch);
+  assert(length > 0);
+  return cb_str8_from_str16((CB_String16) {
+      .data = res,
+      .length = length,
+    });
 #else
-  return getenv(varname);
+  CB_Scratch scratch = cb_scratch_begin();
+  char *cstr = getenv(cb_cstr_from_str8(varname));
+  cb_scratch_end(scratch);
+  return cb_str8_from_cstr(cstr);
 #endif
 }
 
-static b8 cb_setenv(const char *varname, const char *value)
+static b8 cb_setenv(CB_String8 varname, CB_String8 value)
 {
-  cb_assert(varname != NULL);
-  cb_assert(value != NULL);
+  cb_assert(varname.length > 0);
+  cb_assert(varname.data != NULL);
+  cb_assert(value.length > 0);
+  cb_assert(value.data != NULL);
 #if OS_WINDOWS
-  return SetEnvironmentVariableA(varname, value);
+  CB_Scratch scratch = cb_scratch_begin();
+  BOOL res = SetEnvironmentVariableW(cb_wstr_from_str8(varname), cb_wstr_from_str8(value));
+  cb_scratch_end(scratch);
+  return res;
 #else
-  return !setenv(varname, value, true);
+  CB_Scratch scratch = cb_scratch_begin();
+  s32 res = setenv(cb_cstr_from_str8(varname), cb_cstr_from_str8(value), true);
+  cb_scratch_end(scratch);
+  return res == 0;
 #endif
 }
 
+static b8 cb_unsetenv(CB_String8 varname)
+{
+  assert(varname.length > 0);
+  assert(varname.data != NULL);
+#if OS_WINDOWS
+  // TODO(lb): win32
+  assert(false);
+#else
+  CB_Scratch scratch = cb_scratch_begin();
+  s32 res = unsetenv(cb_cstr_from_str8(varname));
+  cb_scratch_end(scratch);
+  return res == 0;
 #endif
+}
+
+#endif // CBUILD_NOIMPL
+#endif // Header guard
index 11a09db2a34f580d6fefee6a7c02cd95a959b93a..eda3d08b5e656e18fcd45cdbc3599600d0c76402 100755 (executable)
@@ -7,27 +7,27 @@
 #endif
 
 typedef struct CB_BibloElement {
-  CB_StringView name;
-  CB_StringView brief;
-  CB_StringView description;
-  CB_StringView ref_block;
+  CB_String8 name;
+  CB_String8 brief;
+  CB_String8 description;
+  CB_String8 ref_block;
   CB_StringBuilder aliases;
 } CB_BibloElement;
 
 struct CB_BibloParser {
-  CB_StringView prefix;
-  CB_StringView content;
-  ssize_t offset;
-  CB_Handle hfile;
+  CB_String8 prefix;
+  CB_String8 content;
+  int64_t offset;
+  CB_FileHandle 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_generate_troff(const CB_BibloElement *element, CB_String8 path_dirdoc, const char *source_path);
+internal CB_BibloElement cb_biblo_parse(CB_FileHandle 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 char cb_biblo_parser_peek(struct CB_BibloParser *parser, int64_t offset);
+internal void cb_biblo_parser_until_newline(struct CB_BibloParser *parser, CB_String8 *sv);
 internal void cb_biblo_find_prefix(struct CB_BibloParser *parser);
 
 // ===============================================================
@@ -43,7 +43,7 @@ enum {
   CB_BibloAnnotationID_ReferenceEnd,
 };
 
-static CB_StringView cb_biblo_annotation[] = {
+static CB_String8 cb_biblo_annotation[] = {
   [CB_BibloAnnotationID_Name] = cb_strinit("@name"),
   [CB_BibloAnnotationID_Brief] = cb_strinit("@brief"),
   [CB_BibloAnnotationID_Long] = cb_strinit("@long"),
@@ -55,48 +55,50 @@ static CB_StringView cb_biblo_annotation[] = {
 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);
+  cb_filesystem_iter_begin(&it, rootpath);
 
-  for (CB_FileInfo file = {0}; cb_file_iter_next(&it, &file); free(file.path)) {
+  for (CB_FileInfo file = {0}; cb_filesystem_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);
+      CB_FileHandle fd = cb_filesystem_open(cb_str8_from_cstr(file.path), CB_AccessFlag_Read);
+      assert(fd != CB_FILEHANDLE_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_str8_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_String8 doc_fullpath = cb_sb_join_with_ch(sb, '/');
+        cb_filesystem_directory_create(doc_fullpath);
         cb_biblo_generate_troff(&doc, doc_fullpath, file.path);
       }
       cb_file_close(fd);
     }
   }
+
+  cb_filesystem_iter_end(&it);
 }
 
-internal void cb_biblo_generate_troff(const CB_BibloElement *element, CB_StringView path_dirdoc, const char *source_path)
+internal void cb_biblo_generate_troff(const CB_BibloElement *element, CB_String8 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_String8 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_String8 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);
+  cb_filesystem_delete(cb_str8_from_cstr(troff_filepath.data));
+  CB_FileHandle troff_fd = cb_filesystem_open(cb_str8_from_cstr(troff_filepath.data), CB_AccessFlag_Write);
+  assert(troff_fd != CB_FILEHANDLE_INVALID);
 
   char *date = NULL;
 #if OS_WINDOWS
@@ -113,53 +115,53 @@ internal void cb_biblo_generate_troff(const CB_BibloElement *element, CB_StringV
 #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");
+  cb_file_write_at_pointer(troff_fd, cb_strlit(".TH "));
+  cb_file_write_at_pointer(troff_fd, element->name);
+  cb_file_write_at_pointer(troff_fd, cb_strlit(" 3 "));
+  cb_file_write_at_pointer(troff_fd, cb_str8_from_cstr(date));
+  cb_file_write_at_pointer(troff_fd, cb_strlit(" GNU\n.SH NAME\n"));
   if (element->aliases.node_count == 0) {
-    cb_file_write(troff_fd, element->name);
+    cb_file_write_at_pointer(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, ",\\ "); }
+      cb_file_write_at_pointer(troff_fd, curr->value);
+      if (curr->next) { cb_file_write_at_pointer(troff_fd, cb_strlit(",\\ ")); }
     }
   }
   if (element->brief.length > 0) {
-    cb_file_write(troff_fd, " \\- ");
-    cb_file_write(troff_fd, element->brief);
+    cb_file_write_at_pointer(troff_fd, cb_strlit(" \\- "));
+    cb_file_write_at_pointer(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");
+  cb_file_write_at_pointer(troff_fd, cb_strlit("\n.SH SYNOPSIS\n.RS\n.nf\n"));
+  cb_file_write_at_pointer(troff_fd, element->ref_block);
+  cb_file_write_at_pointer(troff_fd, cb_strlit("\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_at_pointer(troff_fd, cb_strlit("\n.SH DESCRIPTION\n"));
+    cb_file_write_at_pointer(troff_fd, element->description);
   }
-  cb_file_write(troff_fd, "\n.SH FILES\n.TP\n.I ");
-  cb_file_write(troff_fd, source_path);
+  cb_file_write_at_pointer(troff_fd, cb_strlit("\n.SH FILES\n.TP\n.I "));
+  cb_file_write_at_pointer(troff_fd, cb_str8_from_cstr(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, '/');
+      CB_String8 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_filesystem_link_create_symbolic(troff_filename, link_filepath);
     }
   }
 
   cb_file_close(troff_fd);
 }
 
-internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *parser)
+internal CB_BibloElement cb_biblo_parse(CB_FileHandle file, struct CB_BibloParser *parser)
 {
   CB_BibloElement res = {0};
 
@@ -167,7 +169,7 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
   if (parser->hfile == 0) {
     assert(file != 0);
     parser->hfile = file;
-    parser->content = cb_file_read(file);
+    parser->content = cb_file_read(file, -1, 0);
     parser->offset = 0;
     if (parser->content.length == 0) { return res; }
     cb_biblo_find_prefix(parser);
@@ -175,12 +177,12 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
   assert(parser->content.data != NULL);
   assert(parser->content.length > 0);
 
-  bool has_explicit_ref_block = false, started_ref_block = false;
+  b8 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));) {
+    for (; !(cb_str8_starts_with(&parser->content.data[parser->offset], parser->prefix));) {
       cb_biblo_parser_until_newline(parser, NULL);
       if (parser->offset >= parser->content.length) { return res; }
     }
@@ -191,11 +193,11 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
     }
   }
 
-  for (CB_StringView line = {0}; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix);) {
+  for (CB_String8 line = {0}; cb_str8_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])) {
+    if (cb_str8_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");
@@ -205,23 +207,23 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
         cb_biblo_parser_advance(parser, 1);
       } else {
         cb_biblo_parser_until_newline(parser, &line);
-        cb_view_trim(&line);
+        cb_str8_trim(&line);
         cb_sb_append(&sb, line);
       }
-      for (; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) &&
+      for (; cb_str8_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_str8_trim(&line);
         cb_sb_append(&sb, line);
       }
-      if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) {
+      if (cb_str8_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);
+      cb_str8_trim(&res.brief);
     }
-    else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Name])) {
+    else if (cb_str8_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");
@@ -232,15 +234,15 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
         assert(false);
       }
       cb_biblo_parser_until_newline(parser, &line);
-      cb_view_trim(&line);
+      cb_str8_trim(&line);
       cb_sb_append(&sb, line);
-      if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) {
+      if (cb_str8_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);
+      cb_str8_trim(&res.name);
     }
-    else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Long])) {
+    else if (cb_str8_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");
@@ -250,23 +252,23 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
         cb_biblo_parser_advance(parser, 1);
       } else {
         cb_biblo_parser_until_newline(parser, &line);
-        cb_view_trim(&line);
+        cb_str8_trim(&line);
         cb_sb_append(&sb, line);
       }
-      for (; cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) &&
+      for (; cb_str8_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_str8_trim(&line);
         cb_sb_append(&sb, line);
       }
-      if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix)) {
+      if (cb_str8_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);
+      cb_str8_trim(&res.description);
     }
-    else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_Alias])) {
+    else if (cb_str8_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");
@@ -274,30 +276,30 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
       }
       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));
+        assert(cb_str8_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, ',');
+        CB_StringBuilder split_line = cb_str8_split(line, ',');
         for (struct CB_StringBuilder_Node *curr = split_line.first; curr; curr = curr->next) {
-          cb_view_trim(&curr->value);
+          cb_str8_trim(&curr->value);
         }
         cb_sb_concat(&res.aliases, &split_line);
-        if (cb_view_starts_with(&parser->content.data[parser->offset], parser->prefix) &&
+        if (cb_str8_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)) {
+      if (cb_str8_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])) {
+    else if (cb_str8_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);
@@ -307,16 +309,16 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
         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_str8_starts_with(&parser->content.data[parser->offset], parser->prefix) &&
+               cb_str8_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);
+      cb_str8_trim(&res.ref_block);
     }
-    else if (cb_view_starts_with(&parser->content.data[parser->offset], cb_biblo_annotation[CB_BibloAnnotationID_ReferenceEnd])) {
+    else if (cb_str8_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);
     }
@@ -328,13 +330,13 @@ internal CB_BibloElement cb_biblo_parse(CB_Handle file, struct CB_BibloParser *p
   }
   if (!has_explicit_ref_block) {
     CB_StringBuilder sb = {0};
-    for (CB_StringView line = {0};
+    for (CB_String8 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);
+    cb_str8_trim(&res.ref_block);
   }
   if (res.name.length <= 0) {
     cb_print(CB_LogLevel_Error, "Missing mandatory biblo name annotation.\n");
@@ -356,7 +358,7 @@ internal void cb_biblo_parser_advance(struct CB_BibloParser *parser, size_t by)
   assert(parser->offset <= parser->content.length);
 }
 
-internal char cb_biblo_parser_peek(struct CB_BibloParser *parser, ssize_t offset)
+internal char cb_biblo_parser_peek(struct CB_BibloParser *parser, int64_t offset)
 {
   assert(parser != NULL);
   assert(parser->content.data != NULL);
@@ -366,7 +368,7 @@ internal char cb_biblo_parser_peek(struct CB_BibloParser *parser, ssize_t offset
   return parser->content.data[parser->offset + offset];
 }
 
-internal void cb_biblo_parser_until_newline(struct CB_BibloParser *parser, CB_StringView *sv)
+internal void cb_biblo_parser_until_newline(struct CB_BibloParser *parser, CB_String8 *sv)
 {
   assert(parser != NULL);
   assert(parser->content.data != NULL);
@@ -398,7 +400,7 @@ internal void cb_biblo_find_prefix(struct CB_BibloParser *parser)
     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])) {
+        if (cb_str8_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;
index e70b9d89c02a5dca21f6d4633c7caf9b02a3350e..a7a95d44455c5217cb068663a5a1394a26226dd7 100644 (file)
 #include <assert.h>
 
 internal void
-cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type,
+cb_linagen_defun_vecn_element_wise(CB_Generator *gen, const char *type,
                                    int32_t n, b8 implementation,
-                                   char *func_name, char op);
+                                   const char *func_name, char op);
 
 internal void
-cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type,
+cb_linagen_defun_matnn_element_wise(CB_Generator *gen, const char *type,
                                     int32_t n, b8 implementation,
-                                    char *func_name, char op);
+                                    const char *func_name, char op);
 
 internal char char_toupper(char ch);
 
 static void
-cb_linagen_typedef_vecn(CB_Generator *gen, char *type, int32_t n, ...);
+cb_linagen_typedef_vecn(CB_Generator *gen, const char *type, int32_t n, ...);
 static void
-cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, char *type, int32_t n);
+cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, const char *type, int32_t n);
 static void
-cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n);
+cb_linagen_typedef_matnn(CB_Generator *gen, const char *type, int32_t n);
 
 static inline void
-cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_add(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_sub(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_equal(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_near(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_lerp(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_scale(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_normalize(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_dot(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_mulm(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_magnitude(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_distance(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_vecn_distance2(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 
 static inline void
-cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_vec3_cross(CB_Generator *gen, const char *type, b8 implementation);
 
 static void
-cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_scale(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_add(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_sub(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static inline void
-cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_dot(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_mulv(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 static void
-cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, b8 implementation);
+cb_linagen_defun_matnn_identity(CB_Generator *gen, const char *type, int32_t n, b8 implementation);
 
 static void
-cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, const char *type, b8 implementation);
 static void
-cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, b8 implementation);
+cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, const char *type, b8 implementation);
 
 // ======================================================================
 // Implementations
 static void
-cb_linagen_typedef_vecn(CB_Generator *gen, char *type, int32_t n, ...) {
+cb_linagen_typedef_vecn(CB_Generator *gen, const char *type, int32_t n, ...) {
   va_list args = {0};
   va_start(args, n);
   char *suffix = strdup(type);
@@ -113,7 +113,7 @@ cb_linagen_typedef_vecn(CB_Generator *gen, char *type, int32_t n, ...) {
                              "\n  struct {", type, n));
   b8 found_last_named_field = false;
   for (int32_t i = 0; i < n; ++i) {
-    char *prefix = " ";
+    const char *prefix = " ";
     if (i % 4 == 0) {
       prefix = "\n    ";
     }
@@ -136,7 +136,7 @@ cb_linagen_typedef_vecn(CB_Generator *gen, char *type, int32_t n, ...) {
 }
 
 static void
-cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, char *type, int32_t n) {
+cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, const char *type, int32_t n) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push(gen, cb_format("typedef struct Vec%d%s {"
@@ -146,7 +146,7 @@ cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, char *type, int32_t n) {
 }
 
 static void
-cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n) {
+cb_linagen_typedef_matnn(CB_Generator *gen, const char *type, int32_t n) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push(gen, cb_format("typedef union Mat%d%s {"
@@ -162,7 +162,7 @@ cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n) {
 }
 
 static inline void
-cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s",
@@ -182,29 +182,29 @@ cb_linagen_defun_vecn(CB_Generator *gen, char *type, int32_t n, b8 implementatio
 }
 
 static inline void
-cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_add(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_vecn_element_wise(gen, type, n, implementation, "add", '+');
 }
 
 static inline void
-cb_linagen_defun_vecn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_sub(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_vecn_element_wise(gen, type, n, implementation, "sub", '-');
 }
 
 static inline void
-cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_hadamard_prod(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_vecn_element_wise(gen, type, n, implementation,
                                      "hadamard_prod", '*');
 }
 
 static inline void
-cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_vecn_element_wise(gen, type, n, implementation,
                                      "hadamard_div", '/');
 }
 
 static inline void
-cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_equal(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -223,7 +223,7 @@ cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, b8 impleme
 }
 
 static inline void
-cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_near(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -244,7 +244,7 @@ cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, b8 implemen
 }
 
 static inline void
-cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_lerp(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -278,7 +278,7 @@ cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, b8 implemen
 }
 
 static void
-cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_scale(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -310,7 +310,7 @@ cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, b8 impleme
 }
 
 static void
-cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_normalize(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -351,7 +351,7 @@ cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, b8 imp
 }
 
 static void
-cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_dot(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -370,7 +370,7 @@ cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, b8 implement
 }
 
 static void
-cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_mulm(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -382,7 +382,7 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implemen
     if (!implementation) { return; }
     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 = "";
+      const char *prefix = "";
       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])",
@@ -403,7 +403,7 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implemen
 
     cb_gen_push(gen, "{\n");
     for (int32_t i = 0; i < n; ++i) {
-      char *prefix = "";
+      const char *prefix = "";
       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])",
@@ -417,7 +417,7 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, b8 implemen
 }
 
 static void
-cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_magnitude(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -437,7 +437,7 @@ cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, b8 imp
 }
 
 static void
-cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -457,7 +457,7 @@ cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, b8 i
 }
 
 static void
-cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_distance(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -483,7 +483,7 @@ cb_linagen_defun_vecn_distance(CB_Generator *gen, char *type, int32_t n, b8 impl
 }
 
 static void
-cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_vecn_distance2(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn float vec%d%s_distance2",
@@ -507,7 +507,7 @@ cb_linagen_defun_vecn_distance2(CB_Generator *gen, char *type, int32_t n, b8 imp
 }
 
 static inline void
-cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_vec3_cross(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec3%s vec3%s_cross", suffix, type));
@@ -525,7 +525,7 @@ cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, b8 implementation) {
 }
 
 static void
-cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_scale(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -563,29 +563,29 @@ cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, b8 implem
 }
 
 static inline void
-cb_linagen_defun_matnn_add(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_add(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_matnn_element_wise(gen, type, n, implementation, "add", '+');
 }
 
 static inline void
-cb_linagen_defun_matnn_sub(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_sub(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_matnn_element_wise(gen, type, n, implementation, "sub", '-');
 }
 
 static inline void
-cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_hadamard_prod(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_matnn_element_wise(gen, type, n, implementation,
                                       "hadamard_prod", '*');
 }
 
 static inline void
-cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_hadamard_div(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   cb_linagen_defun_matnn_element_wise(gen, type, n, implementation,
                                       "hadamard_div", '/');
 }
 
 static void
-cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_dot(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -600,7 +600,7 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implemen
     for (int32_t col = 0; col < n; ++col) {
       for (int32_t row = 0; row < n; ++row) {
         cb_gen_push(gen, cb_format("  res.values[%d][%d] = ", col, row));
-        char *prefix = "";
+        const 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));
@@ -623,7 +623,7 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implemen
     for (int32_t col = 0; col < n; ++col) {
       for (int32_t row = 0; row < n; ++row) {
         cb_gen_push(gen, cb_format("  res->values[%d][%d] = ", col, row));
-        char *prefix = "";
+        const 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));
@@ -637,7 +637,7 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, b8 implemen
 }
 
 static void
-cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_mulv(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -650,7 +650,7 @@ cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 impleme
 
     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 = "";
+      const char *prefix = "";
       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])",
@@ -671,7 +671,7 @@ cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 impleme
 
     cb_gen_push(gen, "{\n");
     for (int32_t i = 0; i < n; ++i) {
-      char *prefix = "";
+      const char *prefix = "";
       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])",
@@ -685,7 +685,7 @@ cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, int32_t n, b8 impleme
 }
 
 static void
-cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, b8 implementation) {
+cb_linagen_defun_matnn_identity(CB_Generator *gen, const char *type, int32_t n, b8 implementation) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -715,7 +715,7 @@ cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, b8 imp
 }
 
 static void
-cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_by", suffix, type));
@@ -733,7 +733,7 @@ cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, b8 i
 }
 
 static void
-cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_to", suffix, type));
@@ -751,7 +751,7 @@ cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, b8 i
 }
 
 static void
-cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate", suffix, type));
@@ -773,7 +773,7 @@ cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 impleme
   for (int32_t i = 0; i < 4; ++i) {
     for (int32_t j = 0; j < 4; ++j) {
       cb_gen_push(gen, cb_format("  res.values[%d][%d] = ", i, j));
-      char *prefix = "";
+      const 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));
@@ -787,7 +787,7 @@ cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, b8 impleme
 }
 
 static void
-cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate_rad", suffix, type));
@@ -807,7 +807,7 @@ cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 imp
   for (int32_t i = 0; i < 4; ++i) {
     for (int32_t j = 0; j < 4; ++j) {
       cb_gen_push(gen, cb_format("  res.values[%d][%d] = ", i, j));
-      char *prefix = "";
+      const 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));
@@ -821,7 +821,7 @@ cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, b8 imp
 }
 
 static void
-cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_scale", suffix, type));
@@ -840,7 +840,7 @@ cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implemen
   for (int32_t i = 0; i < 4; ++i) {
     for (int32_t j = 0; j < 4; ++j) {
       cb_gen_push(gen, cb_format("  res.values[%d][%d] = ", i, j));
-      char *prefix = "";
+      const 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));
@@ -854,7 +854,7 @@ cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, b8 implemen
 }
 
 static void
-cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_orthographic", suffix, type));
@@ -877,7 +877,7 @@ cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, b8
 }
 
 static void
-cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_perspective", suffix, type));
@@ -900,7 +900,7 @@ cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, b8 i
 }
 
 static void
-cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type, b8 implementation) {
+cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, const char *type, b8 implementation) {
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
   cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_perspective_rad", suffix, type));
@@ -923,9 +923,9 @@ cb_linagen_defun_mat4_projection_perspective_rad(CB_Generator *gen, char *type,
 
 
 internal void
-cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type,
+cb_linagen_defun_vecn_element_wise(CB_Generator *gen, const char *type,
                                    int32_t n, b8 implementation,
-                                   char *func_name, char op) {
+                                   const char *func_name, char op) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
@@ -961,9 +961,9 @@ cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type,
 }
 
 internal void
-cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type,
+cb_linagen_defun_matnn_element_wise(CB_Generator *gen, const char *type,
                                     int32_t n, b8 implementation,
-                                    char *func_name, char op) {
+                                    const char *func_name, char op) {
   assert(n > 1);
   char *suffix = strdup(type);
   *suffix = char_toupper(*type);
index 3213174c560e36b73681a1ced9b09faacab7ca54..b41aa53682bc189a8b2b5a10c6bc5cedf2c00c57 100644 (file)
@@ -65,20 +65,22 @@ static void cb_test_run(void) {
     }
   }
   cb_assertion_handler = cb_assertion_break;
-  cb_print(CB_LogLevel_Info, "Summary: %d/%d tests passed\n",
-           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) {
-  cb_dyn_push_custom(&cb_tests, test,
-                     tests, count, capacity);
+  cb_dyn_push_custom(&cb_tests, test, tests, count, capacity);
 }
 
-internal void cb_assertion_test(char *condition,
-                                char *file, int32_t line) {
-  printf(ANSI_COLOR_RED "FAILED" ANSI_COLOR_RESET
-         ": `%s` (%s:%d)\n", condition, file, line);
+internal void cb_assertion_test(char *condition, char *file, int32_t line) {
+  printf(ANSI_COLOR_RED "FAILED" ANSI_COLOR_RESET ": `%s` (%s:%d)\n", condition, file, line);
   longjmp(test_runner_jmpbuf, 1);
 }
 
+#ifdef CBUILD_TEST_INCLUDE_SELFTEST
+// TODO(lb): test `cbuild.h` stuff.
+//           the other extras can be tested by having `cbuild_test.h` included last
+//           and by placing the tests behind include guards.
+#endif // CBUILD_TEST_INCLUDE_SELFTEST
+
 #endif