summaryrefslogtreecommitdiff
path: root/utf8.c
diff options
context:
space:
mode:
Diffstat (limited to 'utf8.c')
-rw-r--r--utf8.c95
1 files changed, 78 insertions, 17 deletions
diff --git a/utf8.c b/utf8.c
index 603e8ac..405c20d 100644
--- a/utf8.c
+++ b/utf8.c
@@ -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 */