Commit: 41b9f675f70e1b35f9b52b733470f807b913109d
Parent: a8dcf08697052f39a683fab4206e45d10bf77ef5
Author: Randy Palamar
Date: Mon, 24 Feb 2025 21:28:16 -0700
core: utf16 helpers, set thread name on w32
Diffstat:
7 files changed, 169 insertions(+), 61 deletions(-)
diff --git a/main_linux.c b/main_linux.c
@@ -37,7 +37,7 @@ dispatch_file_watch_events(Platform *platform, Arena arena)
if (event->wd != dir->handle)
continue;
- s8 file = cstr_to_s8(event->name);
+ s8 file = c_str_to_s8(event->name);
u64 hash = s8_hash(file);
for (u32 i = 0; i < dir->file_watch_count; i++) {
FileWatch *fw = dir->file_watches + i;
diff --git a/main_w32.c b/main_w32.c
@@ -35,23 +35,17 @@ typedef struct {
#include "static.c"
static void
-w32_wide_char_to_mb(Stream *s, u16 *wstr, u32 wide_char_length)
-{
- /* NOTE(rnp): this assumes the wstr is strictly ASCII */
- s->errors |= (s->cap - s->widx) < wide_char_length;
- if (!s->errors) {
- for (u32 i = 0; i < wide_char_length; i++)
- s->data[s->widx++] = wstr[i] & 0xFF;
- }
-}
-
-static void
dispatch_file_watch(Platform *platform, FileWatchDirectory *fw_dir, u8 *buf, Arena arena)
{
i64 offset = 0;
- Stream path = stream_alloc(&arena, 256);
+ TempArena save_point = {0};
w32_file_notify_info *fni = (w32_file_notify_info *)buf;
do {
+ end_temp_arena(save_point);
+ save_point = begin_temp_arena(&arena);
+
+ Stream path = {.data = arena_commit(&arena, KB(1)), .cap = KB(1)};
+
if (fni->action != FILE_ACTION_MODIFIED) {
path.widx = 0;
stream_append_s8(&path, s8("unknown file watch event: "));
@@ -60,12 +54,12 @@ dispatch_file_watch(Platform *platform, FileWatchDirectory *fw_dir, u8 *buf, Are
os_write_err_msg(stream_to_s8(&path));
}
- path.widx = 0;
stream_append_s8(&path, fw_dir->name);
stream_append_byte(&path, '\\');
- s8 file_name = {.data = path.data + path.widx, .len = fni->filename_size / 2};
- w32_wide_char_to_mb(&path, fni->filename, fni->filename_size / 2);
+ s8 file_name = s16_to_s8(&arena, (s16){.data = fni->filename,
+ .len = fni->filename_size / 2});
+ stream_append_s8(&path, file_name);
stream_append_byte(&path, 0);
path.widx--;
diff --git a/os_unix.c b/os_unix.c
@@ -80,7 +80,7 @@ static PLATFORM_READ_WHOLE_FILE_FN(os_read_whole_file)
struct stat sb;
i32 fd = open(file, O_RDONLY);
if (fd >= 0 && fstat(fd, &sb) >= 0) {
- result = s8alloc(arena, sb.st_size);
+ result = s8_alloc(arena, sb.st_size);
size rlen = read(fd, result.data, result.len);
if (rlen != result.len)
result = (s8){0};
@@ -186,8 +186,8 @@ os_load_library(char *name, char *temp_name, Stream *e)
}
void *res = dlopen(name, RTLD_NOW|RTLD_LOCAL);
if (!res && e) {
- s8 errs[] = {s8("WARNING: os_load_library("), cstr_to_s8(name), s8("): "),
- cstr_to_s8(dlerror()), s8("\n")};
+ s8 errs[] = {s8("WARNING: os_load_library("), c_str_to_s8(name), s8("): "),
+ c_str_to_s8(dlerror()), s8("\n")};
stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
os_write_err_msg(stream_to_s8(e));
e->widx = 0;
@@ -206,8 +206,8 @@ os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
return 0;
void *res = dlsym(h, name);
if (!res && e) {
- s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), cstr_to_s8(name), s8("): "),
- cstr_to_s8(dlerror()), s8("\n")};
+ s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), c_str_to_s8(name), s8("): "),
+ c_str_to_s8(dlerror()), s8("\n")};
stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
os_write_err_msg(stream_to_s8(e));
e->widx = 0;
@@ -238,11 +238,7 @@ static PLATFORM_ADD_FILE_WATCH_FN(os_add_file_watch)
dir = fwctx->directory_watches + fwctx->directory_watch_count++;
dir->hash = hash;
-
- dir->name = push_s8(a, directory);
- arena_commit(a, 1);
- dir->name.data[dir->name.len] = 0;
-
+ dir->name = push_s8_zero(a, directory);
i32 mask = IN_MOVED_TO|IN_CLOSE_WRITE;
dir->handle = inotify_add_watch(fwctx->handle, (c8 *)dir->name.data, mask);
}
@@ -252,11 +248,11 @@ static PLATFORM_ADD_FILE_WATCH_FN(os_add_file_watch)
i32 pthread_setname_np(pthread_t, char *);
static iptr
-os_create_thread(iptr user_context, char *name, platform_thread_entry_point_fn *fn)
+os_create_thread(Arena arena, iptr user_context, s8 name, platform_thread_entry_point_fn *fn)
{
pthread_t result;
pthread_create(&result, 0, (void *(*)(void *))fn, (void *)user_context);
- pthread_setname_np(result, name);
+ pthread_setname_np(result, (char *)name.data);
return (iptr)result;
}
diff --git a/os_win32.c b/os_win32.c
@@ -182,7 +182,7 @@ static PLATFORM_READ_WHOLE_FILE_FN(os_read_whole_file)
if (h >= 0 && GetFileInformationByHandle(h, &fileinfo)) {
size filesize = (size)fileinfo.nFileSizeHigh << 32;
filesize |= (size)fileinfo.nFileSizeLow;
- result = s8alloc(arena, filesize);
+ result = s8_alloc(arena, filesize);
ASSERT(filesize <= (size)U32_MAX);
@@ -254,7 +254,7 @@ os_load_library(char *name, char *temp_name, Stream *e)
void *res = LoadLibraryA(name);
if (!res && e) {
- s8 errs[] = {s8("WARNING: os_load_library("), cstr_to_s8(name), s8("): ")};
+ s8 errs[] = {s8("WARNING: os_load_library("), c_str_to_s8(name), s8("): ")};
stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
stream_append_i64(e, GetLastError());
stream_append_byte(e, '\n');
@@ -275,7 +275,7 @@ os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
return 0;
void *res = GetProcAddress(h, name);
if (!res && e) {
- s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), cstr_to_s8(name), s8("): ")};
+ s8 errs[] = {s8("WARNING: os_lookup_dynamic_symbol("), c_str_to_s8(name), s8("): ")};
stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
stream_append_i64(e, GetLastError());
stream_append_byte(e, '\n');
@@ -305,11 +305,7 @@ static PLATFORM_ADD_FILE_WATCH_FN(os_add_file_watch)
dir = fwctx->directory_watches + fwctx->directory_watch_count++;
dir->hash = hash;
-
- dir->name = push_s8(a, directory);
- arena_commit(a, 1);
- dir->name.data[dir->name.len] = 0;
-
+ dir->name = push_s8_zero(a, directory);
dir->handle = CreateFileA((c8 *)dir->name.data, GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0);
@@ -332,11 +328,10 @@ static PLATFORM_ADD_FILE_WATCH_FN(os_add_file_watch)
}
static iptr
-os_create_thread(iptr user_context, char *name, platform_thread_entry_point_fn *fn)
+os_create_thread(Arena arena, iptr user_context, s8 name, platform_thread_entry_point_fn *fn)
{
iptr result = CreateThread(0, 0, (iptr)fn, user_context, 0, 0);
- /* TODO(rnp): name needs to be utf16 encoded */
- //SetThreadDescription(result, s8_to_16(arena, name).data);
+ SetThreadDescription(result, s8_to_s16(&arena, name).data);
return result;
}
diff --git a/static.c b/static.c
@@ -89,7 +89,7 @@ get_gl_params(GLParams *gl, Stream *err)
case 'M': gl->vendor_id = GL_VENDOR_ARM; break;
default:
stream_append_s8(err, s8("Unknown GL Vendor: "));
- stream_append_s8(err, cstr_to_s8(vendor));
+ stream_append_s8(err, c_str_to_s8(vendor));
stream_append_byte(err, '\n');
os_fatal(stream_to_s8(err));
break;
@@ -276,7 +276,7 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
GLWorkerThreadContext *worker = &ctx->platform.compute_worker;
worker->window_handle = glfwCreateWindow(320, 240, "", 0, raylib_window_handle);
worker->sync_handle = os_create_sync_object(memory);
- worker->handle = os_create_thread((iptr)worker, "[compute]",
+ worker->handle = os_create_thread(*memory, (iptr)worker, s8("[compute]"),
compute_worker_thread_entry_point);
/* TODO(rnp): we should lock this down after we have something working */
worker->user_context = (iptr)ctx;
diff --git a/util.c b/util.c
@@ -39,11 +39,19 @@ mem_move(u8 *src, u8 *dest, size n)
}
-static void
+static u8 *
arena_commit(Arena *a, size size)
{
ASSERT(a->end - a->beg >= size);
+ u8 *result = a->beg;
a->beg += size;
+ return result;
+}
+
+static void
+arena_pop(Arena *a, size length)
+{
+ a->beg -= length;
}
#define alloc(a, t, n) (t *)alloc_(a, sizeof(t), _Alignof(t), n)
@@ -95,6 +103,67 @@ end_temp_arena(TempArena ta)
}
}
+static u32
+utf8_encode(u8 *out, u32 cp)
+{
+ u32 result = 1;
+ if (cp <= 0x7F) {
+ out[0] = cp & 0x7F;
+ } else if (cp <= 0x7FF) {
+ result = 2;
+ out[0] = ((cp >> 6) & 0x1F) | 0xC0;
+ out[1] = ((cp >> 0) & 0x3F) | 0x80;
+ } else if (cp <= 0xFFFF) {
+ result = 3;
+ out[0] = ((cp >> 12) & 0x0F) | 0xE0;
+ out[1] = ((cp >> 6) & 0x3F) | 0x80;
+ out[2] = ((cp >> 0) & 0x3F) | 0x80;
+ } else if (cp <= 0x10FFFF) {
+ result = 4;
+ out[0] = ((cp >> 18) & 0x07) | 0xF0;
+ out[1] = ((cp >> 12) & 0x3F) | 0x80;
+ out[2] = ((cp >> 6) & 0x3F) | 0x80;
+ out[3] = ((cp >> 0) & 0x3F) | 0x80;
+ } else {
+ out[0] = '?';
+ }
+ return result;
+}
+
+static UnicodeDecode
+utf16_decode(u16 *data, size length)
+{
+ UnicodeDecode result = {.cp = U32_MAX};
+ if (length) {
+ result.consumed = 1;
+ result.cp = data[0];
+ if (length > 1 && BETWEEN(data[0], 0xD800, 0xDBFF)
+ && BETWEEN(data[1], 0xDC00, 0xDFFF))
+ {
+ result.consumed = 2;
+ result.cp = ((data[0] - 0xD800) << 10) | ((data[1] - 0xDC00) + 0x10000);
+ }
+ }
+ return result;
+}
+
+static u32
+utf16_encode(u16 *out, u32 cp)
+{
+ u32 result = 1;
+ if (cp == U32_MAX) {
+ out[0] = '?';
+ } else if (cp < 0x10000) {
+ out[0] = cp;
+ } else {
+ u32 value = cp - 0x10000;
+ out[0] = 0xD800 + (value >> 10u);
+ out[1] = 0xDC00 + (value & 0x3FFu);
+ result = 2;
+ }
+ return result;
+}
+
static Stream
arena_stream(Arena *a)
{
@@ -270,7 +339,7 @@ s8_hash(s8 v)
}
static s8
-cstr_to_s8(char *cstr)
+c_str_to_s8(char *cstr)
{
s8 result = {.data = (u8 *)cstr};
while (*cstr) { result.len++; cstr++; }
@@ -299,15 +368,64 @@ s8_cut_head(s8 s, size cut)
}
static s8
-s8alloc(Arena *a, size len)
+s8_alloc(Arena *a, size len)
{
return (s8){ .data = alloc(a, u8, len), .len = len };
}
static s8
+s16_to_s8(Arena *a, s16 in)
+{
+ s8 result = {0};
+ if (in.len) {
+ size commit = in.len * 4;
+ size length = 0;
+ u8 *data = arena_commit(a, commit + 1);
+ u16 *beg = in.data;
+ u16 *end = in.data + in.len;
+ while (beg < end) {
+ UnicodeDecode decode = utf16_decode(beg, end - beg);
+ length += utf8_encode(data + length, decode.cp);
+ beg += decode.consumed;
+ }
+ data[length] = 0;
+ result = (s8){.len = length, .data = data};
+ arena_pop(a, commit - length);
+ }
+ return result;
+}
+
+static s16
+s8_to_s16(Arena *a, s8 in)
+{
+ s16 result = {0};
+ if (in.len) {
+ size required = 2 * in.len + 1;
+ u16 *data = alloc(a, u16, required);
+ size length = 0;
+ /* TODO(rnp): utf8_decode */
+ for (size i = 0; i < in.len; i++) {
+ u32 cp = in.data[i];
+ length += utf16_encode(data + length, cp);
+ }
+ result = (s16){.len = length, .data = data};
+ arena_pop(a, required - length);
+ }
+ return result;
+}
+
+static s8
push_s8(Arena *a, s8 str)
{
- s8 result = s8alloc(a, str.len);
+ s8 result = s8_alloc(a, str.len);
+ mem_copy(str.data, result.data, result.len);
+ return result;
+}
+
+static s8
+push_s8_zero(Arena *a, s8 str)
+{
+ s8 result = s8_alloc(a, str.len + 1);
mem_copy(str.data, result.data, result.len);
return result;
}
diff --git a/util.h b/util.h
@@ -37,22 +37,23 @@
#define static_assert _Static_assert
-#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a))
-#define ABS(x) ((x) < 0 ? (-x) : (x))
-#define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x))
-#define CLAMP01(x) CLAMP(x, 0, 1)
-#define ISPOWEROF2(a) (((a) & ((a) - 1)) == 0)
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define ORONE(x) ((x)? (x) : 1)
-#define SIGN(x) ((x) < 0? -1 : 1)
-
-#define KB(a) ((a) << 10ULL)
-#define MB(a) ((a) << 20ULL)
-#define GB(a) ((a) << 30ULL)
-
-#define U32_MAX (0xFFFFFFFFUL)
-#define F32_INFINITY (__builtin_inff())
+#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a))
+#define ABS(x) ((x) < 0 ? (-x) : (x))
+#define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b))
+#define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x))
+#define CLAMP01(x) CLAMP(x, 0, 1)
+#define ISPOWEROF2(a) (((a) & ((a) - 1)) == 0)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ORONE(x) ((x)? (x) : 1)
+#define SIGN(x) ((x) < 0? -1 : 1)
+
+#define KB(a) ((a) << 10ULL)
+#define MB(a) ((a) << 20ULL)
+#define GB(a) ((a) << 30ULL)
+
+#define U32_MAX (0xFFFFFFFFUL)
+#define F32_INFINITY (__builtin_inff())
typedef char c8;
typedef uint8_t u8;
@@ -78,6 +79,10 @@ typedef struct { Arena *arena; u8 *old_beg; } TempArena;
typedef struct { size len; u8 *data; } s8;
#define s8(s) (s8){.len = ARRAY_COUNT(s) - 1, .data = (u8 *)s}
+typedef struct { size len; u16 *data; } s16;
+
+typedef struct { u32 cp, consumed; } UnicodeDecode;
+
/* NOTE: raylib stubs */
#ifndef RAYLIB_H
typedef struct { f32 x, y; } Vector2;