Merge from vendor branch BIND:
[dragonfly.git] / lib / libc / citrus / modules / citrus_utf8.c
1 /*      $NetBSD: src/lib/libc/citrus/modules/citrus_utf8.c,v 1.11 2004/12/21 11:25:43 yamt Exp $        */
2 /*      $DragonFly: src/lib/libc/citrus/modules/citrus_utf8.c,v 1.1 2005/03/11 23:33:53 joerg Exp $ */
3
4 /*-
5  * Copyright (c)2002 Citrus Project,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*-
31  * Copyright (c) 1993
32  *      The Regents of the University of California.  All rights reserved.
33  *
34  * This code is derived from software contributed to Berkeley by
35  * Paul Borman at Krystal Technologies.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  */
61
62 #include <sys/types.h>
63 #include <assert.h>
64 #include <errno.h>
65 #include <limits.h>
66 #include <locale.h>
67 #include <stddef.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <wchar.h>
72
73 #include "citrus_namespace.h"
74 #include "citrus_types.h"
75 #include "citrus_module.h"
76 #include "citrus_ctype.h"
77 #include "citrus_stdenc.h"
78 #include "citrus_utf8.h"
79
80
81 /* ----------------------------------------------------------------------
82  * private stuffs used by templates
83  */
84
85 static int _UTF8_count_array[256];
86 static int const *_UTF8_count = NULL;
87
88 static const u_int32_t _UTF8_range[] = {
89         0,      /*dummy*/
90         0x00000000, 0x00000080, 0x00000800, 0x00010000, 
91         0x00200000, 0x04000000, 0x80000000,
92 };
93
94 typedef struct {
95         char ch[6];
96         int chlen;
97 } _UTF8State;
98
99 typedef struct {
100 } _UTF8EncodingInfo;
101
102 typedef struct {
103         _UTF8EncodingInfo       ei;
104         struct {
105                 /* for future multi-locale facility */
106                 _UTF8State      s_mblen;
107                 _UTF8State      s_mbrlen;
108                 _UTF8State      s_mbrtowc;
109                 _UTF8State      s_mbtowc;
110                 _UTF8State      s_mbsrtowcs;
111                 _UTF8State      s_wcrtomb;
112                 _UTF8State      s_wcsrtombs;
113                 _UTF8State      s_wctomb;
114         } states;
115 } _UTF8CTypeInfo;
116
117 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
118 #define _CEI_TO_STATE(_ei_, _func_)     (_ei_)->states.s_##_func_
119
120 #define _FUNCNAME(m)                    _citrus_UTF8_##m
121 #define _ENCODING_INFO                  _UTF8EncodingInfo
122 #define _CTYPE_INFO                     _UTF8CTypeInfo
123 #define _ENCODING_STATE                 _UTF8State
124 #define _ENCODING_MB_CUR_MAX(_ei_)      6
125 #define _ENCODING_IS_STATE_DEPENDENT    0
126 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
127
128
129 static __inline void
130 _UTF8_init_count(void)
131 {
132         int i;
133         if (!_UTF8_count) {
134                 memset(_UTF8_count_array, 0, sizeof(_UTF8_count_array));
135                 for (i = 0; i <= 0x7f; i++)
136                         _UTF8_count_array[i] = 1;
137                 for (i = 0xc0; i <= 0xdf; i++)
138                         _UTF8_count_array[i] = 2;
139                 for (i = 0xe0; i <= 0xef; i++)
140                         _UTF8_count_array[i] = 3;
141                 for (i = 0xf0; i <= 0xf7; i++)
142                         _UTF8_count_array[i] = 4;
143                 for (i = 0xf8; i <= 0xfb; i++)
144                         _UTF8_count_array[i] = 5;
145                 for (i = 0xfc; i <= 0xfd; i++)
146                         _UTF8_count_array[i] = 6;
147                 _UTF8_count = _UTF8_count_array;
148         }
149 }
150
151 static int
152 _UTF8_findlen(wchar_t v)
153 {
154         int i;
155         u_int32_t c;
156
157         c = (u_int32_t)v;       /*XXX*/
158         for (i = 1; i < sizeof(_UTF8_range) / sizeof(_UTF8_range[0]); i++)
159                 if (c >= _UTF8_range[i] && c < _UTF8_range[i + 1])
160                         return i;
161
162         return -1;      /*out of range*/
163 }
164
165 static __inline void
166 /*ARGSUSED*/
167 _citrus_UTF8_init_state(_UTF8EncodingInfo *ei, _UTF8State *s)
168 {
169         memset(s, 0, sizeof(*s));
170 }
171
172 static __inline void
173 /*ARGSUSED*/
174 _citrus_UTF8_pack_state(_UTF8EncodingInfo *ei, void *pspriv,
175                         const _UTF8State *s)
176 {
177         memcpy(pspriv, (const void *)s, sizeof(*s));
178 }
179
180 static __inline void
181 /*ARGSUSED*/
182 _citrus_UTF8_unpack_state(_UTF8EncodingInfo *ei, _UTF8State *s,
183                           const void *pspriv)
184 {
185         memcpy((void *)s, pspriv, sizeof(*s));
186 }
187
188 static int
189 _citrus_UTF8_mbrtowc_priv(_UTF8EncodingInfo *ei, wchar_t *pwc, const char **s,
190                           size_t n, _UTF8State *psenc, size_t *nresult)
191 {
192         wchar_t wchar;
193         const char *s0;
194         int c;
195         int i;
196         int chlenbak;
197
198         _DIAGASSERT(nresult != 0);
199         _DIAGASSERT(s != NULL);
200         _DIAGASSERT(psenc != NULL);
201
202         s0 = *s;
203
204         if (s0 == NULL) {
205                 _citrus_UTF8_init_state(ei, psenc);
206                 *nresult = 0; /* state independent */
207                 return (0);
208         }
209
210         chlenbak = psenc->chlen;
211
212         /* make sure we have the first byte in the buffer */
213         switch (psenc->chlen) {
214         case 0:
215                 if (n < 1) {
216                         goto restart;
217                 }
218                 psenc->ch[0] = *s0++;
219                 psenc->chlen = 1;
220                 n--;
221                 break;
222         case 1: case 2: case 3: case 4: case 5:
223                 break;
224         default:
225                 /* illegal state */
226                 goto ilseq;
227         }
228
229         c = _UTF8_count[psenc->ch[0] & 0xff];
230         if (c == 0)
231                 goto ilseq;
232         while (psenc->chlen < c) {
233                 if (n < 1) {
234                         goto restart;
235                 }
236                 psenc->ch[psenc->chlen] = *s0++;
237                 psenc->chlen++;
238                 n--;
239         }
240
241         switch (c) {
242         case 1:
243                 wchar = psenc->ch[0] & 0xff;
244                 break;
245         case 2: case 3: case 4: case 5: case 6:
246                 wchar = psenc->ch[0] & (0x7f >> c);
247                 for (i = 1; i < c; i++) {
248                         if ((psenc->ch[i] & 0xc0) != 0x80)
249                                 goto ilseq;
250                         wchar <<= 6;
251                         wchar |= (psenc->ch[i] & 0x3f);
252                 }
253
254                 break;
255         }
256
257         *s = s0;
258
259         psenc->chlen = 0;
260
261         if (pwc)
262                 *pwc = wchar;
263
264         if (!wchar)
265                 *nresult = 0;
266         else
267                 *nresult = c - chlenbak;
268
269         return (0);
270
271 ilseq:
272         psenc->chlen = 0;
273         *nresult = (size_t)-1;
274         return (EILSEQ);
275
276 restart:
277         *s = s0;
278         *nresult = (size_t)-2;
279         return (0);
280 }
281
282 static int
283 _citrus_UTF8_wcrtomb_priv(_UTF8EncodingInfo *ei, char *s, size_t n, wchar_t wc,
284                           _UTF8State *psenc, size_t *nresult)
285 {
286         int cnt, i, ret;
287         wchar_t c;
288
289         _DIAGASSERT(nresult != 0);
290         _DIAGASSERT(s != NULL);
291
292         cnt = _UTF8_findlen(wc);
293         if (cnt <= 0 || cnt > 6) {
294                 /* invalid UCS4 value */
295                 ret = EILSEQ;
296                 goto err;
297         }
298         if (n < cnt) {
299                 /* bound check failure */
300                 ret = E2BIG;
301                 goto err;
302         }
303
304         c = wc;
305         if (s) {
306                 for (i = cnt - 1; i > 0; i--) {
307                         s[i] = 0x80 | (c & 0x3f);
308                         c >>= 6;
309                 }
310                 s[0] = c;
311                 if (cnt == 1)
312                         s[0] &= 0x7f;
313                 else {
314                         s[0] &= (0x7f >> cnt);
315                         s[0] |= ((0xff00 >> cnt) & 0xff);
316                 }
317         }
318
319         *nresult = (size_t)cnt;
320         return 0;
321
322 err:
323         *nresult = (size_t)-1;
324         return ret;
325 }
326
327 static __inline int
328 /*ARGSUSED*/
329 _citrus_UTF8_stdenc_wctocs(_UTF8EncodingInfo * __restrict ei,
330                            _csid_t * __restrict csid,
331                            _index_t * __restrict idx,
332                            wchar_t wc)
333 {
334
335         _DIAGASSERT(csid != NULL && idx != NULL);
336
337         *csid = 0;
338         *idx = (_citrus_index_t)wc;
339
340         return (0);
341 }
342
343 static __inline int
344 /*ARGSUSED*/
345 _citrus_UTF8_stdenc_cstowc(_UTF8EncodingInfo * __restrict ei,
346                            wchar_t * __restrict wc,
347                            _csid_t csid, _index_t idx)
348 {
349
350         _DIAGASSERT(wc != NULL);
351
352         if (csid != 0)
353                 return (EILSEQ);
354
355         *wc = (wchar_t)idx;
356
357         return (0);
358 }
359
360 static int
361 /*ARGSUSED*/
362 _citrus_UTF8_encoding_module_init(_UTF8EncodingInfo * __restrict ei,
363                                   const void * __restrict var, size_t lenvar)
364 {
365         _UTF8_init_count();
366
367         memset(ei, 0, sizeof(*ei));
368
369         return 0;
370 }
371
372 static void
373 /*ARGSUSED*/
374 _citrus_UTF8_encoding_module_uninit(_UTF8EncodingInfo *ei)
375 {
376 }
377
378
379 /* ----------------------------------------------------------------------
380  * public interface for ctype
381  */
382
383 _CITRUS_CTYPE_DECLS(UTF8);
384 _CITRUS_CTYPE_DEF_OPS(UTF8);
385
386 #include "citrus_ctype_template.h"
387
388 /* ----------------------------------------------------------------------
389  * public interface for stdenc
390  */
391
392 _CITRUS_STDENC_DECLS(UTF8);
393 _CITRUS_STDENC_DEF_OPS(UTF8);
394
395 #include "citrus_stdenc_template.h"