master ohmu/fastfetch-openbsd / src / common / impl / strutil.c
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}