about summary refs log tree commit diff
path: root/boot/common.c
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-01-25 00:57:56 +0100
committerMel <mel@rnrd.eu>2026-01-25 00:57:56 +0100
commit4dc6b49db40eaebf700d5c26c93c5f33b3db60ac (patch)
tree8b1450f743e27016ae4d78780a5e0e4901622bdc /boot/common.c
parentfce4a99dbfab5af623bb05d9e10807efeced5a47 (diff)
downloadcatskill-4dc6b49db40eaebf700d5c26c93c5f33b3db60ac.tar.zst
catskill-4dc6b49db40eaebf700d5c26c93c5f33b3db60ac.zip
Allow different transpile pass output types
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/common.c')
-rw-r--r--boot/common.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/boot/common.c b/boot/common.c
index 79f5d63..1c65deb 100644
--- a/boot/common.c
+++ b/boot/common.c
@@ -343,6 +343,7 @@ _slice_at(const struct _Slice* slice, uint index)
 REGION(ascii, string)
 
 // a string.
+// an immutable sequence of ascii characters.
 struct String
 {
     ascii* data;
@@ -818,6 +819,154 @@ _internal_string_format(FILE* stream, uint string_length, const ascii* format, .
     va_end(args);
 }
 
+// a string buffer with a fixed capacity, the contents
+// of which can be modified.
+// essentially, a mutable string with a maximum size.
+struct String_Buffer
+{
+    ascii* data;
+    uint length;
+    uint capacity;
+};
+
+// creates a new string buffer with the given capacity.
+struct String_Buffer
+string_buffer_new(uint capacity)
+{
+    check(capacity + 1 < REGION_SIZE - region_string_cursor, "out of string memory for string buffer");
+
+    ascii* at = region_string + region_string_cursor;
+    region_string_cursor += capacity + 1;
+
+    at[0] = '\0';
+
+    return (struct String_Buffer){
+        .data = at,
+        .length = 0,
+        .capacity = capacity,
+    };
+}
+
+// creates a new empty string buffer.
+struct String_Buffer
+string_buffer_empty(void)
+{
+    // we still technically allocate one byte of string memory for the
+    // empty string buffer and its null-terminator, but that shouldn't be an issue.
+    return string_buffer_new(0);
+}
+
+// returns the length of the string buffer.
+uint
+string_buffer_length(const struct String_Buffer* buffer)
+{
+    return buffer->length;
+}
+
+// returns the capacity of the string buffer.
+uint
+string_buffer_capacity(const struct String_Buffer* buffer)
+{
+    return buffer->capacity;
+}
+
+// checks if the string buffer is empty.
+bool
+string_buffer_is_empty(const struct String_Buffer* buffer)
+{
+    return buffer->length == 0;
+}
+
+// returns the character at a given index.
+// does bounds-checking.
+ascii
+string_buffer_at(const struct String_Buffer* buffer, uint index)
+{
+    check(index < buffer->length, "index out of bounds");
+    return buffer->data[index];
+}
+
+// clears the string buffer, setting its length to zero.
+void
+string_buffer_clear(struct String_Buffer* buffer)
+{
+    buffer->length = 0;
+    buffer->data[0] = '\0';
+}
+
+// appends a character to the string buffer.
+void
+string_buffer_push(struct String_Buffer* buffer, ascii c)
+{
+    check(buffer->length < buffer->capacity, "string buffer is full: %u/%u", buffer->length, buffer->capacity);
+    buffer->data[buffer->length] = c;
+    ++buffer->length;
+    buffer->data[buffer->length] = '\0';
+}
+
+// removes the last character from the string buffer.
+// pass a non-nil pointer as `removed_char` to retrieve
+// the removed character.
+void
+string_buffer_pop(struct String_Buffer* buffer, ascii* removed_char)
+{
+    check(buffer->length > 0, "cannot pop from an empty string buffer");
+
+    --buffer->length;
+    if (removed_char) *removed_char = buffer->data[buffer->length];
+    buffer->data[buffer->length] = '\0';
+}
+
+// appends a string to the string buffer.
+void
+string_buffer_append(struct String_Buffer* buffer, struct String s)
+{
+    if (string_is_empty(s)) return;
+
+    check(buffer->length + s.length <= buffer->capacity,
+          "string buffer overflow: %u + %u > %u",
+          buffer->length, s.length, buffer->capacity);
+
+    for (uint i = 0; i < s.length; ++i) {
+        buffer->data[buffer->length + i] = s.data[i];
+    }
+    buffer->length += s.length;
+    buffer->data[buffer->length] = '\0';
+}
+
+// appends a C-style string to the string buffer.
+void
+string_buffer_append_c_str(struct String_Buffer* buffer, const ascii* c_str)
+{
+    uint c_str_len = strlen(c_str);
+    if (c_str_len == 0) return;
+
+    check(buffer->length + c_str_len <= buffer->capacity,
+          "string buffer overflow: %u + %u > %u",
+          buffer->length, c_str_len, buffer->capacity);
+
+    for (uint i = 0; i < c_str_len; ++i)
+        buffer->data[buffer->length + i] = c_str[i];
+
+    buffer->length += c_str_len;
+    buffer->data[buffer->length] = '\0';
+}
+
+// converts the string buffer to an immutable string.
+// allocates a new string in the string region.
+struct String
+string_buffer_to_string(const struct String_Buffer* buffer)
+{
+    return string_new(buffer->data, buffer->length);
+}
+
+// prints the contents of the string buffer to stdout.
+void
+string_buffer_print(const struct String_Buffer* buffer)
+{
+    printf("%.*s", (int32)buffer->length, buffer->data);
+}
+
 // a source file given to the compiler.
 struct Source_File
 {