ohmu
·
2026-10-15
1#include "common/strutil.h"
2#include "common/wcwidth.h"
3
4uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width) {
5 if (__builtin_expect(length == 0 || *str == '\0', false)) {
6 if (width) {
7 *width = 0;
8 }
9 return 0;
10 }
11
12 unsigned char first = (unsigned char) *str;
13 if (__builtin_expect(first < 0x80, true)) {
14 if (width) {
15 *width = 1;
16 }
17 return 1;
18 }
19
20 uint8_t bytes;
21 if ((first & 0xE0) == 0xC0) {
22 bytes = 2;
23 } else if ((first & 0xF0) == 0xE0) {
24 bytes = 3;
25 } else if ((first & 0xF8) == 0xF0) {
26 bytes = 4;
27 } else {
28 if (width) {
29 *width = 1;
30 }
31 return 1;
32 }
33
34 if (length < bytes) {
35 if (width) {
36 *width = 1;
37 }
38 return 1;
39 }
40
41 for (uint8_t i = 1; i < bytes; ++i) {
42 unsigned char continuation = (unsigned char) str[i];
43 if (continuation == '\0' || (continuation & 0xC0) != 0x80) {
44 if (width) {
45 *width = 1;
46 }
47 return 1;
48 }
49 }
50
51 uint32_t ucs = (uint32_t) (first & ((1U << (8 - bytes)) - 1));
52 for (uint8_t i = 1; i < bytes; ++i) {
53 ucs <<= 6;
54 ucs |= (uint32_t) ((unsigned char) str[i] & 0x3F);
55 }
56
57 int wcWidth = mk_wcwidth(ucs);
58 if (width) {
59 *width = (uint8_t) (wcWidth < 0 ? 0 : wcWidth);
60 }
61 return bytes;
62}
63
64uint32_t ffUtf8StrWidth(const char* str, uint32_t length) {
65 uint32_t result = 0;
66 const char* ptr = str;
67
68 while (length > 0 && *ptr != '\0') {
69 uint8_t width = 0;
70 uint8_t bytes = ffUtf8CharLenWidth(ptr, length, &width);
71 if (__builtin_expect(bytes == 0, false)) {
72 break;
73 }
74
75 result += width;
76 ptr += bytes;
77 length -= bytes;
78 }
79
80 return result > 0 ? result : (uint32_t) (ptr - str);
81}