nsxiv3c7d6f3
Replace utf8codepoint with Chris Wellons' utf8_decode
Code under a different license should be kept in a separate file. This implemention is a single header file with ~65 lines, so it better fits this requirement.
+75 −34
4 files changed
| @@ -361,7 +361,6 @@ int r_opendir(r_dir_t*, const char*, bool); | |||
| 361 | 361 | int r_closedir(r_dir_t*); | |
| 362 | 362 | char* r_readdir(r_dir_t*); | |
| 363 | 363 | int r_mkdir(char*); | |
| 364 | − | void* utf8codepoint(const void * __restrict__ str, long * __restrict__ out_codepoint); | |
| 365 | 364 | ||
| 366 | 365 | ||
| 367 | 366 | /* window.c */ | |
| @@ -0,0 +1,68 @@ | |||
| 1 | + | /* Branchless UTF-8 decoder | |
| 2 | + | * | |
| 3 | + | * This is free and unencumbered software released into the public domain. | |
| 4 | + | */ | |
| 5 | + | #ifndef UTF8_H | |
| 6 | + | #define UTF8_H | |
| 7 | + | ||
| 8 | + | #include <stdint.h> | |
| 9 | + | ||
| 10 | + | /* Decode the next character, C, from BUF, reporting errors in E. | |
| 11 | + | * | |
| 12 | + | * Since this is a branchless decoder, four bytes will be read from the | |
| 13 | + | * buffer regardless of the actual length of the next character. This | |
| 14 | + | * means the buffer _must_ have at least three bytes of zero padding | |
| 15 | + | * following the end of the data stream. | |
| 16 | + | * | |
| 17 | + | * Errors are reported in E, which will be non-zero if the parsed | |
| 18 | + | * character was somehow invalid: invalid byte sequence, non-canonical | |
| 19 | + | * encoding, or a surrogate half. | |
| 20 | + | * | |
| 21 | + | * The function returns a pointer to the next character. When an error | |
| 22 | + | * occurs, this pointer will be a guess that depends on the particular | |
| 23 | + | * error, but it will always advance at least one byte. | |
| 24 | + | */ | |
| 25 | + | static void * | |
| 26 | + | utf8_decode(void *buf, uint32_t *c, int *e) | |
| 27 | + | { | |
| 28 | + | static const char lengths[] = { | |
| 29 | + | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 30 | + | 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 | |
| 31 | + | }; | |
| 32 | + | static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; | |
| 33 | + | static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; | |
| 34 | + | static const int shiftc[] = {0, 18, 12, 6, 0}; | |
| 35 | + | static const int shifte[] = {0, 6, 4, 2, 0}; | |
| 36 | + | ||
| 37 | + | unsigned char *s = buf; | |
| 38 | + | int len = lengths[s[0] >> 3]; | |
| 39 | + | ||
| 40 | + | /* Compute the pointer to the next character early so that the next | |
| 41 | + | * iteration can start working on the next character. Neither Clang | |
| 42 | + | * nor GCC figure out this reordering on their own. | |
| 43 | + | */ | |
| 44 | + | unsigned char *next = s + len + !len; | |
| 45 | + | ||
| 46 | + | /* Assume a four-byte character and load four bytes. Unused bits are | |
| 47 | + | * shifted out. | |
| 48 | + | */ | |
| 49 | + | *c = (uint32_t)(s[0] & masks[len]) << 18; | |
| 50 | + | *c |= (uint32_t)(s[1] & 0x3f) << 12; | |
| 51 | + | *c |= (uint32_t)(s[2] & 0x3f) << 6; | |
| 52 | + | *c |= (uint32_t)(s[3] & 0x3f) << 0; | |
| 53 | + | *c >>= shiftc[len]; | |
| 54 | + | ||
| 55 | + | /* Accumulate the various error conditions. */ | |
| 56 | + | *e = (*c < mins[len]) << 6; // non-canonical encoding | |
| 57 | + | *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? | |
| 58 | + | *e |= (*c > 0x10FFFF) << 8; // out of range? | |
| 59 | + | *e |= (s[1] & 0xc0) >> 2; | |
| 60 | + | *e |= (s[2] & 0xc0) >> 4; | |
| 61 | + | *e |= (s[3] ) >> 6; | |
| 62 | + | *e ^= 0x2a; // top two bits of each tail byte correct? | |
| 63 | + | *e >>= shifte[len]; | |
| 64 | + | ||
| 65 | + | return next; | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | #endif | |
| @@ -205,31 +205,3 @@ int r_mkdir(char *path) | |||
| 205 | 205 | return 0; | |
| 206 | 206 | } | |
| 207 | 207 | ||
| 208 | − | /* copied from sheredom's utf8.h (public domain) https://github.com/sheredom/utf8.h */ | |
| 209 | − | ||
| 210 | − | void* utf8codepoint(const void* __restrict__ str, long* __restrict__ out_codepoint) | |
| 211 | − | { | |
| 212 | − | const char *s = (const char *)str; | |
| 213 | − | ||
| 214 | − | if (0xf0 == (0xf8 & s[0])) { | |
| 215 | − | // 4 byte utf8 codepoint | |
| 216 | − | *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | | |
| 217 | − | ((0x3f & s[2]) << 6) | (0x3f & s[3]); | |
| 218 | − | s += 4; | |
| 219 | − | } else if (0xe0 == (0xf0 & s[0])) { | |
| 220 | − | // 3 byte utf8 codepoint | |
| 221 | − | *out_codepoint = ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); | |
| 222 | − | s += 3; | |
| 223 | − | } else if (0xc0 == (0xe0 & s[0])) { | |
| 224 | − | // 2 byte utf8 codepoint | |
| 225 | − | *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); | |
| 226 | − | s += 2; | |
| 227 | − | } else { | |
| 228 | − | // 1 byte utf8 codepoint otherwise | |
| 229 | − | *out_codepoint = s[0]; | |
| 230 | − | s += 1; | |
| 231 | − | } | |
| 232 | − | ||
| 233 | − | return (void *)s; | |
| 234 | − | } | |
| 235 | − | ||
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | #define _WINDOW_CONFIG | |
| 21 | 21 | #include "config.h" | |
| 22 | 22 | #include "icon/data.h" | |
| 23 | + | #include "utf8.h" | |
| 23 | 24 | ||
| 24 | 25 | #include <stdlib.h> | |
| 25 | 26 | #include <string.h> | |
| @@ -131,8 +132,9 @@ void win_init(win_t *win) | |||
| 131 | 132 | ||
| 132 | 133 | win->bar.l.size = BAR_L_LEN; | |
| 133 | 134 | win->bar.r.size = BAR_R_LEN; | |
| 134 | − | win->bar.l.buf = emalloc(win->bar.l.size); | |
| 135 | − | win->bar.r.buf = emalloc(win->bar.r.size); | |
| 135 | + | /* 3 padding bytes needed by utf8_decode */ | |
| 136 | + | win->bar.l.buf = emalloc(win->bar.l.size + 3); | |
| 137 | + | win->bar.r.buf = emalloc(win->bar.r.size + 3); | |
| 136 | 138 | win->bar.h = options->hide_bar ? 0 : barheight; | |
| 137 | 139 | ||
| 138 | 140 | INIT_ATOM_(WM_DELETE_WINDOW); | |
| @@ -371,14 +373,14 @@ int win_textwidth(const win_env_t *e, const char *text, unsigned int len, bool w | |||
| 371 | 373 | void win_draw_bar_text(win_t *win, XftDraw *d, XftColor *color, XftFont *font, int x, int y, char *text, int maxlen, int maximum_x) | |
| 372 | 374 | { | |
| 373 | 375 | size_t len = 0; | |
| 374 | − | int xshift = 0, newshift; | |
| 375 | − | long codep; | |
| 376 | + | int err, xshift = 0, newshift; | |
| 377 | + | uint32_t codep; | |
| 376 | 378 | char *p, *nextp; | |
| 377 | 379 | FcCharSet* fccharset; | |
| 378 | 380 | XftFont* fallback = NULL; | |
| 379 | 381 | ||
| 380 | 382 | for (p = text; *p && (len < maxlen); p = nextp, len++) { | |
| 381 | − | nextp = utf8codepoint(p, &codep); | |
| 383 | + | nextp = utf8_decode(p, &codep, &err); | |
| 382 | 384 | if (!XftCharExists(win->env.dpy, font, codep)) { | |
| 383 | 385 | fccharset = FcCharSetCreate(); | |
| 384 | 386 | FcCharSetAddChar(fccharset, codep); | |