]> mj.ucw.cz Git - libucw.git/blob - lib/unicode.h
c957c7971d1f162a590d457b9999d9c6c0b8d77b
[libucw.git] / lib / unicode.h
1 /*
2  *      Sherlock Library -- Unicode Characters
3  *
4  *      (c) 1997--2004 Martin Mares <mj@ucw.cz>
5  *      (c) 2004 Robert Spalek <robert@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #ifndef _UNICODE_H
12 #define _UNICODE_H
13
14 /* Macros for handling UTF-8 */
15
16 #define UNI_REPLACEMENT 0xfffc
17
18 static inline byte *
19 utf8_put(byte *p, uns u)
20 {
21   if (u < 0x80)
22     *p++ = u;
23   else if (u < 0x800)
24     {
25       *p++ = 0xc0 | (u >> 6);
26       *p++ = 0x80 | (u & 0x3f);
27     }
28   else
29     {
30       ASSERT(u < 0x10000);
31       *p++ = 0xe0 | (u >> 12);
32       *p++ = 0x80 | ((u >> 6) & 0x3f);
33       *p++ = 0x80 | (u & 0x3f);
34     }
35   return p;
36 }
37
38 static inline byte *
39 utf8_32_put(byte *p, uns u)
40 {
41   if (u < 0x80)
42     *p++ = u;
43   else if (u < 0x800)
44     {
45       *p++ = 0xc0 | (u >> 6);
46       goto put1;
47     }
48   else if (u < (1<<16))
49     {
50       *p++ = 0xe0 | (u >> 12);
51       goto put2;
52     }
53   else if (u < (1<<21))
54     {
55       *p++ = 0xf0 | (u >> 18);
56       goto put3;
57     }
58   else if (u < (1<<26))
59     {
60       *p++ = 0xf8 | (u >> 24);
61       goto put4;
62     }
63   else if (u < (1U<<31))
64     {
65       *p++ = 0xfc | (u >> 30);
66       *p++ = 0x80 | ((u >> 24) & 0x3f);
67 put4: *p++ = 0x80 | ((u >> 18) & 0x3f);
68 put3: *p++ = 0x80 | ((u >> 12) & 0x3f);
69 put2: *p++ = 0x80 | ((u >> 6) & 0x3f);
70 put1: *p++ = 0x80 | (u & 0x3f);
71     }
72   else
73     ASSERT(0);
74 }
75
76 #define UTF8_GET_NEXT if (unlikely((*p & 0xc0) != 0x80)) goto bad; u = (u << 6) | (*p++ & 0x3f)
77
78 static inline const byte *
79 utf8_get(const byte *p, uns *uu)
80 {
81   uns u = *p++;
82   if (u < 0x80)
83     ;
84   else if (unlikely(u < 0xc0))
85     {
86       /* Incorrect byte sequence */
87     bad:
88       u = UNI_REPLACEMENT;
89     }
90   else if (u < 0xe0)
91     {
92       u &= 0x1f;
93       UTF8_GET_NEXT;
94     }
95   else if (likely(u < 0xf0))
96     {
97       u &= 0x0f;
98       UTF8_GET_NEXT;
99       UTF8_GET_NEXT;
100     }
101   else
102     goto bad;
103   *uu = u;
104   return p;
105 }
106
107 static inline byte *
108 utf8_32_get(byte *p, uns *uu)
109 {
110   uns u = *p++;
111   if (u < 0x80)
112     ;
113   else if (unlikely(u < 0xc0))
114     {
115       /* Incorrect byte sequence */
116     bad:
117       u = UNI_REPLACEMENT;
118     }
119   else if (u < 0xe0)
120     {
121       u &= 0x1f;
122       goto get1;
123     }
124   else if (u < 0xf0)
125     {
126       u &= 0x0f;
127       goto get2;
128     }
129   else if (u < 0xf8)
130     {
131       u &= 0x07;
132       goto get3;
133     }
134   else if (u < 0xfc)
135     {
136       u &= 0x03;
137       goto get4;
138     }
139   else if (u < 0xfe)
140     {
141       u &= 0x01;
142       UTF8_GET_NEXT;
143 get4: UTF8_GET_NEXT;
144 get3: UTF8_GET_NEXT;
145 get2: UTF8_GET_NEXT;
146 get1: UTF8_GET_NEXT;
147     }
148   else
149     goto bad;
150   *uu = u;
151   return p;
152 }
153
154 #define PUT_UTF8(p,u) p = utf8_put(p, u)
155 #define GET_UTF8(p,u) p = (byte*)utf8_get(p, &(u))
156
157 #define PUT_UTF8_32(p,u) p = utf8_32_put(p, u)
158 #define GET_UTF8_32(p,u) p = (byte*)utf8_32_get(p, &(u))
159
160 #define UTF8_SKIP(p) do {                               \
161     uns c = *p++;                                       \
162     if (c >= 0xc0)                                      \
163       while (c & 0x40 && *p >= 0x80 && *p < 0xc0)       \
164         p++, c <<= 1;                                   \
165   } while (0)
166
167 #define UTF8_SKIP_BWD(p) while ((*--(p) & 0xc0) == 0x80)
168
169 static inline uns
170 utf8_space(uns u)
171 {
172   if (u < 0x80)
173     return 1;
174   if (u < 0x800)
175     return 2;
176   if (u < (1<<16))
177     return 3;
178   if (u < (1<<21))
179     return 4;
180   if (u < (1<<26))
181     return 5;
182   return 6;
183 }
184
185 static inline uns
186 utf8_encoding_len(uns c)
187 {
188   if (c < 0x80)
189     return 1;
190   ASSERT(c >= 0xc0 && c < 0xfe);
191   if (c < 0xe0)
192     return 2;
193   if (c < 0xf0)
194     return 3;
195   if (c < 0xf8)
196     return 4;
197   if (c < 0xfc)
198     return 5;
199   return 6;
200 }
201
202 /* unicode-utf8.c */
203
204 uns utf8_strlen(byte *str);
205 uns utf8_strnlen(byte *str, uns n);
206
207 #endif