#include "tim.h" i32 tim_ztrlen(cstr s) { if(s == NULL) return 0; i32 n = strlen(s); if(n < 0) n = 0; return n; } i32 tim_bsr8(u8 x) { #if defined __GNUC__ || defined __clang__ unsigned int b = x; b <<= sizeof(b) * CHAR_BIT - 8; b |= 1 << (sizeof(b) * CHAR_BIT - 9); return __builtin_clz(b); #elif defined _MSC_VER unsigned long n = 0; unsigned long b = x; b <<= sizeof(b) * CHAR_BIT - 8; b |= 1 << (sizeof(b) * CHAR_BIT - 9); _BitScanReverse(&n, b); return n; #else i32 n = 0; for (; n < 8 && !(x & 128); n++, x <<= 1) {} return n; #endif } i32 tim_utf8_to_i32(cstr s) { s = s ? s : ""; // use bit magic to mask out leading utf8 1s u32 c = s[0] & ((1 << (8 - tim_bsr8(~s[0]))) - 1); for (i32 i = 1; s[0] && s[i] && i < 4; i++) { c = (c << 6) | (s[i] & 63); } return (i32)c; } i32 tim_utf8_len(cstr s) { i32 n = 0; for (i32 i = 0; s && s[i]; i++) { n += (s[i] & 192) != 128; } return n; } i32 tim_utf8_pos(cstr s, i32 pos) { i32 i = 0; for (i32 n = 0; pos >= 0 && s && s[i]; i++) { n += (s[i] & 192) != 128; if (n == pos + 1) { return i; } } return i; } bool tim_utf8_is_wide_perhaps(const u8* s, i32 n) { // Character width depends on character, terminal and font. There is no // reliable method, however most frequently used characters are narrow. // Zero with characters are ignored, and hope that user input is benign. if (n < 3 || s[0] < 225) { // u+0000 - u+1000, basic latin - tibetan return false; } else if (s[0] == 226 && s[1] >= 148 && s[1] < 152) { // u+2500 - u+2600 box drawing, block elements, geometric shapes return false; } return true; } TimText tim_scan_str(cstr s) { if(s == NULL) s = ""; TimText t = { .width = 0, .lines = (s[0] != 0), }; i32 width = 0; for (t.size = 0; s[t.size]; t.size++) { char ch = s[t.size]; i32 newline = (ch == '\n'); width = newline ? 0 : width; width += (ch & 192) != 128 && (u8)ch > 31; t.lines += newline; t.width = MAX(t.width, width); } return t; } bool tim_next_line(TimLine* l) { if (!l->s || !l->s[0]) { return false; } l->line = l->s; l->size = 0; l->width = 0; for (cstr s = l->s; s[0] && s[0] != '\n'; s++) { l->size += 1; l->width += (s[0] & 192) != 128 && (u8)s[0] > 31; } l->s += l->size + !!l->s[l->size]; return true; }