diff options
Diffstat (limited to 'utf8.c')
-rw-r--r-- | utf8.c | 95 |
1 files changed, 78 insertions, 17 deletions
@@ -1,7 +1,7 @@ /** * UTF-8 utility functions * - * (c) 2010 Steve Bennett <steveb@workware.net.au> + * (c) 2010-2016 Steve Bennett <steveb@workware.net.au> * * See LICENCE for licence details. */ @@ -41,7 +41,7 @@ int utf8_fromunicode(char *p, unsigned uc) } } -#if defined(JIM_UTF8) && !defined(JIM_BOOTSTRAP) +#if defined(USE_UTF8) && !defined(JIM_BOOTSTRAP) int utf8_charlen(int c) { if ((c & 0x80) == 0) { @@ -56,8 +56,8 @@ int utf8_charlen(int c) if ((c & 0xf8) == 0xf0) { return 4; } - /* Invalid sequence */ - return -1; + /* Invalid sequence, so treat it as a single byte */ + return 1; } int utf8_strlen(const char *str, int bytelen) @@ -66,7 +66,7 @@ int utf8_strlen(const char *str, int bytelen) if (bytelen < 0) { bytelen = strlen(str); } - while (bytelen) { + while (bytelen > 0) { int c; int l = utf8_tounicode(str, &c); charlen++; @@ -76,12 +76,24 @@ 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; while (index--) { - int c; - s += utf8_tounicode(s, &c); + s += utf8_charlen(*s); } return s - str; } @@ -118,19 +130,28 @@ int utf8_tounicode(const char *str, int *uc) if (s[0] < 0xe0) { if ((s[1] & 0xc0) == 0x80) { *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80); - return 2; + if (*uc >= 0x80) { + return 2; + } + /* Otherwise this is an invalid sequence */ } } else if (s[0] < 0xf0) { if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) { *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80); - return 3; + if (*uc >= 0x800) { + return 3; + } + /* Otherwise this is an invalid sequence */ } } else if (s[0] < 0xf8) { if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80) && ((str[3] & 0xc0) == 0x80)) { *uc = ((s[0] & ~0xf0) << 18) | ((s[1] & ~0x80) << 12) | ((s[2] & ~0x80) << 6) | (s[3] & ~0x80); - return 4; + if (*uc >= 0x10000) { + return 4; + } + /* Otherwise this is an invalid sequence */ } } @@ -144,6 +165,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 +195,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; + unsigned ch = *(unsigned *)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 +237,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 */ |