From 8b0de2aa1bce1db580828fe9fba7ab5aa2501376 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 2 Jan 2021 22:06:28 -0500 Subject: [PATCH] introduce ncwidth() to handle sextants on pre-U13 libcs #1274 --- src/lib/egcpool.h | 5 +++-- src/lib/internal.h | 2 +- src/lib/layout.c | 2 +- src/lib/ncwidth.h | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 src/lib/ncwidth.h diff --git a/src/lib/egcpool.h b/src/lib/egcpool.h index 3706722cb..67d7711a5 100644 --- a/src/lib/egcpool.h +++ b/src/lib/egcpool.h @@ -11,6 +11,7 @@ #include #include #include +#include "ncwidth.h" #include "notcurses/notcurses.h" #ifdef __cplusplus @@ -66,7 +67,7 @@ egcpool_grow(egcpool* pool, size_t len){ // any NUL terminator. Neither the number of bytes nor columns is necessarily // equal to the number of decoded code points. Such are the ways of Unicode. // uc_is_grapheme_break() wants UTF-32, which is fine, because we need wchar_t -// to use wcwidth() anyway FIXME except this doesn't work with 16-bit wchar_t! +// to use ncwidth() anyway FIXME except this doesn't work with 16-bit wchar_t! static inline int utf8_egc_len(const char* gcluster, int* colcount){ size_t ret = 0; @@ -83,7 +84,7 @@ utf8_egc_len(const char* gcluster, int* colcount){ if(prevw && uc_is_grapheme_break(prevw, wc)){ break; // starts a new EGC, exit and do not claim } - int cols = wcwidth(wc); + int cols = ncwidth(wc); if(cols < 0){ if(iswspace(wc)){ // newline or tab return ret + 1; diff --git a/src/lib/internal.h b/src/lib/internal.h index aefafc012..ccb413903 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -397,7 +397,7 @@ mbstr_find_codepoint(const char* s, char32_t cp, int* col){ if(towlower(cp) == towlower(w)){ return bytes; } - *col += wcwidth(w); + *col += ncwidth(w); bytes += r; } return -1; diff --git a/src/lib/layout.c b/src/lib/layout.c index dccd2e53d..f35be4b33 100644 --- a/src/lib/layout.c +++ b/src/lib/layout.c @@ -95,7 +95,7 @@ puttext_line(ncplane* n, ncalign_e align, const char* text, size_t* bytes){ return cols; } b += consumed; - int width = wcwidth(w); + int width = ncwidth(w); if(width < 0){ width = 0; // FIXME } diff --git a/src/lib/ncwidth.h b/src/lib/ncwidth.h new file mode 100644 index 000000000..42725f8a5 --- /dev/null +++ b/src/lib/ncwidth.h @@ -0,0 +1,18 @@ +#include + +// wcwidth() might be missing some lengths (for instance, glibc didn't get +// Unicode 13 support until 2.31). ncwidth() handles some characters on the +// wcwidth() error path. it ought generally be used rather than wcwidth(). +static inline int +ncwidth(wchar_t c){ + int r = wcwidth(c); + if(r >= 0){ + return r; + } + // Symbols for Legacy Computing were only added to glibc in 2.32 (along with + // the rest of Unicode 13). Handle them explicitly if wcwidth() failed. + if(c >= 0x1fb00 && c <= 0x1fb3b){ + return 1; + } + return -1; +}