diff options
author | Steve Bennett <steveb@workware.net.au> | 2016-09-04 13:54:59 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2016-09-05 09:40:26 +1000 |
commit | ed4923bc71b7630cc34328b32704e806bb10c614 (patch) | |
tree | 024ee39a3b430a447bc2fc1a49a0110a21cef013 /utf8.c | |
parent | c672379dca1fe3fa7b89e1d8c6b1a1e570bb4043 (diff) | |
download | jimtcl-ed4923bc71b7630cc34328b32704e806bb10c614.zip jimtcl-ed4923bc71b7630cc34328b32704e806bb10c614.tar.gz jimtcl-ed4923bc71b7630cc34328b32704e806bb10c614.tar.bz2 |
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 <steveb@workware.net.au>
Diffstat (limited to 'utf8.c')
-rw-r--r-- | utf8.c | 67 |
1 files changed, 60 insertions, 7 deletions
@@ -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 */ |