1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/**
* UTF-8 utility functions
*
* (c) 2010-2016 Steve Bennett <steveb@workware.net.au>
*
* See LICENCE for licence details.
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "utf8.h"
/* This one is always implemented */
int utf8_fromunicode(char *p, unsigned uc)
{
if (uc <= 0x7f) {
*p = uc;
return 1;
}
else if (uc <= 0x7ff) {
*p++ = 0xc0 | ((uc & 0x7c0) >> 6);
*p = 0x80 | (uc & 0x3f);
return 2;
}
else if (uc <= 0xffff) {
*p++ = 0xe0 | ((uc & 0xf000) >> 12);
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
*p = 0x80 | (uc & 0x3f);
return 3;
}
/* Note: We silently truncate to 21 bits here: 0x1fffff */
else {
*p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
*p++ = 0x80 | ((uc & 0x3f000) >> 12);
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
*p = 0x80 | (uc & 0x3f);
return 4;
}
}
#if defined(USE_UTF8) && !defined(JIM_BOOTSTRAP)
int utf8_charlen(int c)
{
if ((c & 0x80) == 0) {
return 1;
}
if ((c & 0xe0) == 0xc0) {
return 2;
}
if ((c & 0xf0) == 0xe0) {
return 3;
}
if ((c & 0xf8) == 0xf0) {
return 4;
}
/* Invalid sequence, so treat it as a single byte */
return 1;
}
int utf8_index(const char *str, int index)
{
const char *s = str;
while (index--) {
s += utf8_charlen(*s);
}
return s - str;
}
int utf8_tounicode(const char *str, int *uc)
{
unsigned const char *s = (unsigned const char *)str;
if (s[0] < 0xc0) {
*uc = s[0];
return 1;
}
if (s[0] < 0xe0) {
if ((s[1] & 0xc0) == 0x80) {
*uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
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);
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);
if (*uc >= 0x10000) {
return 4;
}
/* Otherwise this is an invalid sequence */
}
}
/* Invalid sequence, so just return the byte */
*uc = *s;
return 1;
}
struct casemap {
unsigned short code; /* code point */
unsigned short altcode; /* alternate case code point */
};
/* Generated mapping tables */
#include "_unicode_mapping.c"
#define ARRAYSIZE(A) sizeof(A) / sizeof(*(A))
static int cmp_casemap(const void *key, const void *cm)
{
return *(int *)key - (int)((const struct casemap *)cm)->code;
}
static int utf8_map_case(const struct casemap *mapping, int num, int ch)
{
/* We only support 16 bit case mapping */
if (ch <= 0xffff) {
const struct casemap *cm =
bsearch(&ch, mapping, num, sizeof(*mapping), cmp_casemap);
if (cm) {
return cm->altcode;
}
}
return ch;
}
int utf8_upper(int ch)
{
if (isascii(ch)) {
return toupper(ch);
}
return utf8_map_case(unicode_case_mapping_upper, ARRAYSIZE(unicode_case_mapping_upper), ch);
}
#endif /* JIM_BOOTSTRAP */
|