From a7507bb43160aa133e32b1ae848ad8835bbd11f8 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Thu, 23 Jul 2026 00:18:08 +0200 Subject: [PATCH] sorta kinda working on strings for cmenu. being lazy --- cmenu/justfile | 2 ++ cmenu/platform.h | 36 +++++++++++++++++++++------ cmenu/str.c | 43 ++++++++++++++++++++++++++++++++ cmenu/str.h | 10 ++++++++ cmenu/utf.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ cmenu/utf.h | 9 +++++++ 6 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 cmenu/justfile create mode 100644 cmenu/str.c create mode 100644 cmenu/str.h create mode 100644 cmenu/utf.c create mode 100644 cmenu/utf.h diff --git a/cmenu/justfile b/cmenu/justfile new file mode 100644 index 0000000..8d70c8f --- /dev/null +++ b/cmenu/justfile @@ -0,0 +1,2 @@ +tag: + ctags --langmap=c:.c.h --languages=c -R . diff --git a/cmenu/platform.h b/cmenu/platform.h index b27eaf0..5858057 100644 --- a/cmenu/platform.h +++ b/cmenu/platform.h @@ -4,6 +4,8 @@ #include #include +#include "utf.h" + typedef struct Color { uint8_t r, g, b; } Color; @@ -22,23 +24,41 @@ typedef enum Key { Count_Key } Key; -typedef uint32_t CodePoint; - bool KeyPressed(Key key); bool InputGetNextPrintable(CodePoint const *out_key); +typedef struct Cell { + CodePoint character; + Color foreground; + Color background; +} Cell; + typedef struct Window { - int const width; - int const height; - CodePoint *characters; - Color *foreground; - Color *background; + int width; + int height; + Cell *cells; } Window; -Window *WindowCreate(); +typedef struct PlatformState { + Window *prev; + Window *curr; +} PlatformState; + +// Options for the backend. These options don't necessarily apply for all platforms. +typedef struct PlatformOpts { + float window_width_fraction; // decide the width of the window as a fraction of the total resolution. for gui backends + float window_height_fraction; // decide the height of the window as a fraction of the total resolution. for gui backends +} PlatformOpts; + +PlatformOpts WindowCreateOptsDefault(); +Window *WindowCreate(PlatformOpts opts); void WindowClear(Window *window, Color color); void WindowFlip(Window *window); +void PlatformInit(PlatformOpts opts); +int PlatformGetWidth(); +int PlatformGetHeight(); + // TODO: the platform layer would really update the keys being pressed, and // receive a diff in the form of actions. print this line from here and change // colors at these points. diff --git a/cmenu/str.c b/cmenu/str.c new file mode 100644 index 0000000..f0fb08c --- /dev/null +++ b/cmenu/str.c @@ -0,0 +1,43 @@ +#include + +#include "str.h" + +static bool intToIndex(String string, int i, size_t *out_index) { + int val = 0; + bool is_ok = true; + if (i >= 0) { + val = i; + } else { + val = string.size + 1 + i; + } + + if (val < 0) { + val = 0; + is_ok = false; + } else if (val > string.size) { + val = string.size; + is_ok = false; + } + + *out_index = val; + return is_ok; +} + +bool StringSub(String string, int start, int end, String *out_substr) { + + size_t start_index = 0; + bool start_ok = intToIndex(string, start, &start_index); + size_t end_index = 0; + bool end_ok = intToIndex(string, end, &end_index); + + if (string.size == 0 || start_index >= end_index) { + out_substr->size=0; + out_substr->buffer=NULL; + return false; + } + + out_substr->buffer = &string.buffer[start_index]; + out_substr->size = end_index - start_index; + + return start_ok && end_ok; +} diff --git a/cmenu/str.h b/cmenu/str.h new file mode 100644 index 0000000..82aefa7 --- /dev/null +++ b/cmenu/str.h @@ -0,0 +1,10 @@ +#include + +typedef struct String { + unsigned char const *buffer; + size_t size; +} String; + +#define STRING(content) ((String){.buffer=#content, .size=sizeof(#content)-1}) + +bool StringSub(String string, int start, int end, String *out_substr); diff --git a/cmenu/utf.c b/cmenu/utf.c new file mode 100644 index 0000000..7abb917 --- /dev/null +++ b/cmenu/utf.c @@ -0,0 +1,65 @@ +#include + +#include "utf.h" +#include "str.h" + +typedef struct Utf8Parser { + String str; +} Utf8Parser; + +bool Utf8ParserNextCodePoint(Utf8Parser *this, CodePoint *out_codepoint) { + uitn8_t const flag_1_bytes = 0; + uint8_t const mask_1_bytes = 1 << 7; + + uint8_t const flag_continuation = mask_1_bytes; + uint8_t const mask_continuation = (1 << 7) | (1 << 6); + + uint8_t const flag_2_bytes = mask_continuation; + uint8_t const mask_2_bytes = (1 << 7) | (1 << 6) | (1 << 5); + + uint8_t const flag_3_bytes = mask_2_bytes; + uint8_t const mask_3_bytes = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4); + + uint8_t const flag_4_bytes = mask_3_bytes; + uint8_t const mask_4_bytes = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3); + + if (this->str.size == 0) { + *out_codepoint = 0; + return false; + } + + if ((this->str.buffer[0] & mask_1_bytes) == flag_1_bytes) { + *out_codepoint = (CodePoint) str[0]; + bool ok = StringSub(this->str, 1, -1, &this->str); + assert(ok && "has to be ok since the size is not 0"); + return ok; + } else +} + +// max must be less than or equal to the capacity of target. +bool CodePointsFromUtf8String( + uint8_t const *str, + CodePoint *target, + int max +) { + + for (size_t i = 0; str[i] != '\0' && max > 0;) { + if ((str[i] & mask_1_bytes) == flag_1_bytes) { + *target = (CodePoint) str[i]; + + target += 1; + max -= 1; + i += 1; + } else + if ((str[i] & mask_2_bytes) == flag_2_bytes) { + } else + if ((str[i] & mask_3_bytes) == flag_3_bytes) { + } else + if ((str[i] & mask_4_bytes) == flag_4_bytes) { + } else { + false; + } + } + + return true; +} diff --git a/cmenu/utf.h b/cmenu/utf.h new file mode 100644 index 0000000..29f2af4 --- /dev/null +++ b/cmenu/utf.h @@ -0,0 +1,9 @@ +#ifndef UTF +#define UTF + +typedef uint32_t CodePoint; + +int CodePointsFromUtf8String(char const *str, CodePoint *target, unsigned int max); + +#endif // UTF +