]> mj.ucw.cz Git - libucw.git/blob - lib/unicode.h
Another thing about the C standard I didn't know: passing a va_list to
[libucw.git] / lib / unicode.h
1 /*
2  *      UCW 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   return p;
75 }
76
77 #define UTF8_GET_NEXT if (unlikely((*p & 0xc0) != 0x80)) goto bad; u = (u << 6) | (*p++ & 0x3f)
78
79 static inline const byte *
80 utf8_get(const byte *p, uns *uu)
81 {
82   uns u = *p++;
83   if (u < 0x80)
84     ;
85   else if (unlikely(u < 0xc0))
86     {
87       /* Incorrect byte sequence */
88     bad:
89       u = UNI_REPLACEMENT;
90     }
91   else if (u < 0xe0)
92     {
93       u &= 0x1f;
94       UTF8_GET_NEXT;
95     }
96   else if (likely(u < 0xf0))
97     {
98       u &= 0x0f;
99       UTF8_GET_NEXT;
100       UTF8_GET_NEXT;
101     }
102   else
103     goto bad;
104   *uu = u;
105   return p;
106 }
107
108 static inline byte *
109 utf8_32_get(byte *p, uns *uu)
110 {
111   uns u = *p++;
112   if (u < 0x80)
113     ;
114   else if (unlikely(u < 0xc0))
115     {
116       /* Incorrect byte sequence */
117     bad:
118       u = UNI_REPLACEMENT;
119     }
120   else if (u < 0xe0)
121     {
122       u &= 0x1f;
123       goto get1;
124     }
125   else if (u < 0xf0)
126     {
127       u &= 0x0f;
128       goto get2;
129     }
130   else if (u < 0xf8)
131     {
132       u &= 0x07;
133       goto get3;
134     }
135   else if (u < 0xfc)
136     {
137       u &= 0x03;
138       goto get4;
139     }
140   else if (u < 0xfe)
141     {
142       u &= 0x01;
143       UTF8_GET_NEXT;
144 get4: UTF8_GET_NEXT;
145 get3: UTF8_GET_NEXT;
146 get2: UTF8_GET_NEXT;
147 get1: UTF8_GET_NEXT;
148     }
149   else
150     goto bad;
151   *uu = u;
152   return p;
153 }
154
155 #define PUT_UTF8(p,u) p = utf8_put(p, u)
156 #define GET_UTF8(p,u) p = (byte*)utf8_get(p, &(u))
157
158 #define PUT_UTF8_32(p,u) p = utf8_32_put(p, u)
159 #define GET_UTF8_32(p,u) p = (byte*)utf8_32_get(p, &(u))
160
161 #define UTF8_SKIP(p) do {                               \
162     uns c = *p++;                                       \
163     if (c >= 0xc0)                                      \
164       while (c & 0x40 && *p >= 0x80 && *p < 0xc0)       \
165         p++, c <<= 1;                                   \
166   } while (0)
167
168 #define UTF8_SKIP_BWD(p) while ((*--(p) & 0xc0) == 0x80)
169
170 static inline uns
171 utf8_space(uns u)
172 {
173   if (u < 0x80)
174     return 1;
175   if (u < 0x800)
176     return 2;
177   if (u < (1<<16))
178     return 3;
179   if (u < (1<<21))
180     return 4;
181   if (u < (1<<26))
182     return 5;
183   return 6;
184 }
185
186 static inline uns
187 utf8_encoding_len(uns c)
188 {
189   if (c < 0x80)
190     return 1;
191   ASSERT(c >= 0xc0 && c < 0xfe);
192   if (c < 0xe0)
193     return 2;
194   if (c < 0xf0)
195     return 3;
196   if (c < 0xf8)
197     return 4;
198   if (c < 0xfc)
199     return 5;
200   return 6;
201 }
202
203 /* unicode-utf8.c */
204
205 uns utf8_strlen(byte *str);
206 uns utf8_strnlen(byte *str, uns n);
207
208 #endif