From ed4923bc71b7630cc34328b32704e806bb10c614 Mon Sep 17 00:00:00 2001 From: Steve Bennett Date: Sun, 4 Sep 2016 13:54:59 +1000 Subject: Add utf-8 display width info Needed when using linenoise line editing with utf-8 support Note that variable width support is not yet added to linenoise Signed-off-by: Steve Bennett --- utf8.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 7 deletions(-) (limited to 'utf8.c') diff --git a/utf8.c b/utf8.c index 3f00f39..0d94c0e 100644 --- a/utf8.c +++ b/utf8.c @@ -76,6 +76,19 @@ int utf8_strlen(const char *str, int bytelen) return charlen; } +int utf8_strwidth(const char *str, int charlen) +{ + int width = 0; + while (charlen) { + int c; + int l = utf8_tounicode(str, &c); + width += utf8_width(c); + str += l; + charlen--; + } + return width; +} + int utf8_index(const char *str, int index) { const char *s = str; @@ -144,6 +157,12 @@ struct casemap { unsigned short altcode; /* alternate case code point */ }; +struct utf8range { + unsigned lower; /* lower inclusive */ + unsigned upper; /* upper exclusive */ +}; + + /* Generated mapping tables */ #include "_unicode_mapping.c" @@ -168,10 +187,29 @@ static int utf8_map_case(const struct casemap *mapping, int num, int ch) return ch; } -/* Some platforms don't have isascii */ -#ifndef isascii -#define isascii(C) (!((C) & ~0x7f)) -#endif +static int cmp_range(const void *key, const void *cm) +{ + const struct utf8range *range = (const struct utf8range *)cm; + int ch = *(int *)key; + if (ch < range->lower) { + return -1; + } + if (ch >= range->upper) { + return 1; + } + return 0; +} + +static int utf8_in_range(const struct utf8range *range, int num, int ch) +{ + const struct utf8range *r = + bsearch(&ch, range, num, sizeof(*range), cmp_range); + + if (r) { + return 1; + } + return 0; +} int utf8_upper(int ch) { @@ -191,11 +229,26 @@ int utf8_lower(int ch) int utf8_title(int ch) { - int newch = utf8_map_case(unicode_case_mapping_title, ARRAYSIZE(unicode_case_mapping_title), ch); - if (newch != ch) { - return newch ? newch : ch; + if (!isascii(ch)) { + int newch = utf8_map_case(unicode_case_mapping_title, ARRAYSIZE(unicode_case_mapping_title), ch); + if (newch != ch) { + return newch ? newch : ch; + } } return utf8_upper(ch); } +int utf8_width(int ch) +{ + if (!isascii(ch)) { + if (utf8_in_range(unicode_range_combining, ARRAYSIZE(unicode_range_combining), ch)) { + return 0; + } + if (utf8_in_range(unicode_range_wide, ARRAYSIZE(unicode_range_wide), ch)) { + return 2; + } + } + return 1; +} + #endif /* JIM_BOOTSTRAP */ -- cgit v1.1