diff options
Diffstat (limited to 'src/visualizer/grid.c')
| -rw-r--r-- | src/visualizer/grid.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/visualizer/grid.c b/src/visualizer/grid.c new file mode 100644 index 0000000..5f95efc --- /dev/null +++ b/src/visualizer/grid.c @@ -0,0 +1,136 @@ +#include "visualizer/grid.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +static size_t glyph_bytes(unsigned char lead) +{ + if (lead < 0x80) + return 1; + if ((lead >> 5) == 0x6) + return 2; + if ((lead >> 4) == 0xE) + return 3; + if ((lead >> 3) == 0x1E) + return 4; + + return 1; +} + +size_t psi_utf8_count(const char *s) +{ + size_t count = 0; + while (*s) + { + s += glyph_bytes((unsigned char)*s); + count++; + } + + return count; +} + +struct PsiStringBuilder psi_new_string_builder(void) +{ + return (struct PsiStringBuilder) + { + NULL, + 0, + 0, + }; +} + +void psi_string_builder_append(struct PsiStringBuilder *sb, const char *s) +{ + size_t n = strlen(s); + if (sb->len + n + 1 > sb->cap) + { + size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2; + while (new_cap < sb->len + n + 1) + new_cap *= 2; + + sb->data = realloc(sb->data, new_cap); + assert(sb->data != NULL); + sb->cap = new_cap; + } + + memcpy(sb->data + sb->len, s, n + 1); + sb->len += n; +} + +char *psi_string_builder_finish(struct PsiStringBuilder *sb) +{ + if (sb->data == NULL) + psi_string_builder_append(sb, ""); + + return sb->data; +} + +struct PsiGlyphRow psi_new_glyph_row(size_t width) +{ + char (*cells)[5] = malloc(width * sizeof(*cells)); + assert(cells != NULL || width == 0); + + for (size_t i = 0; i < width; i++) + memcpy(cells[i], " ", 2); + + return (struct PsiGlyphRow) + { + cells, + width, + }; +} + +void psi_free_glyph_row(struct PsiGlyphRow *row) +{ + free(row->cells); + row->cells = NULL; + row->width = 0; +} + +void psi_glyph_row_set(struct PsiGlyphRow *row, size_t index, const char *glyph) +{ + if (index >= row->width) + return; + + size_t n = glyph_bytes((unsigned char)glyph[0]); + memcpy(row->cells[index], glyph, n); + row->cells[index][n] = '\0'; +} + +size_t psi_glyph_row_place(struct PsiGlyphRow *row, size_t start, const char *utf8) +{ + size_t count = 0; + const char *p = utf8; + + while (*p) + { + size_t n = glyph_bytes((unsigned char)*p); + size_t index = start + count; + if (index < row->width) + { + memcpy(row->cells[index], p, n); + row->cells[index][n] = '\0'; + } + + p += n; + count++; + } + + return count; +} + +void psi_glyph_row_fill_space(struct PsiGlyphRow *row, size_t from, size_t to, const char *glyph) +{ + for (size_t i = from; i < to && i < row->width; i++) + if (strcmp(row->cells[i], " ") == 0) + psi_glyph_row_set(row, i, glyph); +} + +void psi_glyph_row_render(struct PsiGlyphRow row, struct PsiStringBuilder *sb) +{ + for (size_t i = 0; i < row.width; i++) + psi_string_builder_append(sb, row.cells[i]); + + psi_string_builder_append(sb, "\n"); +} |
