Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / lib / libc / citrus / modules / citrus_dechanyu.c
1 /* $NetBSD: citrus_dechanyu.c,v 1.2 2007/04/24 15:42:08 tnozaki Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_dechanyu.c,v 1.1 2008/04/10 10:21:01 hasso Exp $ */
3
4 /*-
5  * Copyright (c)2007 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 #include <sys/types.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <locale.h>
39 #include <wchar.h>
40 #include <limits.h>
41
42 #include "citrus_namespace.h"
43 #include "citrus_types.h"
44 #include "citrus_bcs.h"
45 #include "citrus_module.h"
46 #include "citrus_ctype.h"
47 #include "citrus_stdenc.h"
48 #include "citrus_dechanyu.h"
49
50 /* ----------------------------------------------------------------------
51  * private stuffs used by templates
52  */
53
54 typedef struct {
55         int chlen;
56         char ch[4];
57 } _DECHanyuState;
58
59 typedef struct {
60         int dummy;
61 } _DECHanyuEncodingInfo;
62
63 typedef struct {
64         _DECHanyuEncodingInfo   ei;
65         struct {
66                 /* for future multi-locale facility */
67                 _DECHanyuState  s_mblen;
68                 _DECHanyuState  s_mbrlen;
69                 _DECHanyuState  s_mbrtowc;
70                 _DECHanyuState  s_mbtowc;
71                 _DECHanyuState  s_mbsrtowcs;
72                 _DECHanyuState  s_wcrtomb;
73                 _DECHanyuState  s_wcsrtombs;
74                 _DECHanyuState  s_wctomb;
75         } states;
76 } _DECHanyuCTypeInfo;
77
78 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
79 #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.__CONCAT(s_,_func_)
80
81 #define _FUNCNAME(m)                    __CONCAT(_citrus_DECHanyu_,m)
82 #define _ENCODING_INFO                  _DECHanyuEncodingInfo
83 #define _CTYPE_INFO                     _DECHanyuCTypeInfo
84 #define _ENCODING_STATE                 _DECHanyuState
85 #define _ENCODING_MB_CUR_MAX(_ei_)              4
86 #define _ENCODING_IS_STATE_DEPENDENT            0
87 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
88
89 static __inline void
90 /*ARGSUSED*/
91 _citrus_DECHanyu_init_state(_DECHanyuEncodingInfo * __restrict ei,
92         _DECHanyuState * __restrict psenc)
93 {
94         /* ei may be null */
95         _DIAGASSERT(psenc != NULL);
96
97         psenc->chlen = 0;
98 }
99
100 static __inline void
101 /*ARGSUSED*/
102 _citrus_DECHanyu_pack_state(_DECHanyuEncodingInfo * __restrict ei,
103         void * __restrict pspriv,
104         const _DECHanyuState * __restrict psenc)
105 {
106         /* ei may be null */
107         _DIAGASSERT(pspriv != NULL);
108         _DIAGASSERT(psenc != NULL);
109
110         memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
111 }
112
113 static __inline void
114 /*ARGSUSED*/
115 _citrus_DECHanyu_unpack_state(_DECHanyuEncodingInfo * __restrict ei,
116         _DECHanyuState * __restrict psenc,
117         const void * __restrict pspriv)
118 {
119         /* ei may be null */
120         _DIAGASSERT(psenc != NULL);
121         _DIAGASSERT(pspriv != NULL);
122
123         memcpy((void *)psenc, pspriv, sizeof(*psenc));
124 }
125
126 static void
127 /*ARGSUSED*/
128 _citrus_DECHanyu_encoding_module_uninit(_DECHanyuEncodingInfo *ei)
129 {
130         /* ei may be null */
131 }
132
133 static int
134 /*ARGSUSED*/
135 _citrus_DECHanyu_encoding_module_init(_DECHanyuEncodingInfo * __restrict ei,
136         const void * __restrict var, size_t lenvar)
137 {
138         /* ei may be null */
139         return 0;
140 }
141
142 static __inline int
143 is_singlebyte(int c)
144 {
145         return c <= 0x7F;
146 }
147
148 static __inline int
149 is_leadbyte(int c)
150 {
151         return c >= 0xA1 && c <= 0xFE;
152 }
153
154 static __inline int
155 is_trailbyte(int c)
156 {
157         c &= ~0x80;
158         return c >= 0x21 && c <= 0x7E;
159 }
160
161 static __inline int
162 is_hanyu1(int c)
163 {
164         return c == 0xC2;
165 }
166
167 static __inline int
168 is_hanyu2(int c)
169 {
170         return c == 0xCB;
171 }
172
173 #define HANYUBIT        0xC2CB0000
174
175 static __inline int
176 is_94charset(int c)
177 {
178         return c >= 0x21 && c <= 0x7E;
179 }
180
181 static int
182 /*ARGSUSED*/
183 _citrus_DECHanyu_mbrtowc_priv(_DECHanyuEncodingInfo * __restrict ei,
184         wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
185         _DECHanyuState * __restrict psenc, size_t * __restrict nresult)
186 {
187         const char *s0;
188         int ch, i;
189         wchar_t wc;
190
191         /* ei may be unused */
192         _DIAGASSERT(s != NULL);
193         _DIAGASSERT(psenc != NULL);
194         _DIAGASSERT(nresult != NULL);
195
196         if (*s == NULL) {
197                 _citrus_DECHanyu_init_state(ei, psenc);
198                 *nresult = _ENCODING_IS_STATE_DEPENDENT;
199                 return 0;
200         } 
201         s0 = *s;
202
203         wc = (wchar_t)0;
204         switch (psenc->chlen) {
205         case 0:
206                 if (n-- < 1)
207                         goto restart;
208                 ch = *s0++ & 0xFF;
209                 if (is_singlebyte(ch) != 0) {
210                         if (pwc != NULL)
211                                 *pwc = (wchar_t)ch;
212                         *nresult = (size_t)((ch == 0) ? 0 : 1);
213                         *s = s0;
214                         return 0;
215                 }
216                 if (is_leadbyte(ch) == 0)
217                         goto ilseq;
218                 psenc->ch[psenc->chlen++] = ch;
219                 break;
220         case 1:
221                 ch = psenc->ch[0] & 0xFF;
222                 if (is_leadbyte(ch) == 0)
223                         return EINVAL;
224                 break;
225         case 2: case 3:
226                 ch = psenc->ch[0] & 0xFF;
227                 if (is_hanyu1(ch) != 0) {
228                         ch = psenc->ch[1] & 0xFF;
229                         if (is_hanyu2(ch) != 0) {
230                                 wc |= (wchar_t)HANYUBIT;
231                                 break;
232                         }
233                 }
234         /*FALLTHROUGH*/
235         default:
236                 return EINVAL;
237         }
238
239         switch (psenc->chlen) {
240         case 1:
241                 if (is_hanyu1(ch) != 0) {
242                         if (n-- < 1)
243                                 goto restart;
244                         ch = *s0++ & 0xFF;
245                         if (is_hanyu2(ch) == 0)
246                                 goto ilseq;
247                         psenc->ch[psenc->chlen++] = ch;
248                         wc |= (wchar_t)HANYUBIT;
249                         if (n-- < 1)
250                                 goto restart;
251                         ch = *s0++ & 0xFF;
252                         if (is_leadbyte(ch) == 0)
253                                 goto ilseq;
254                         psenc->ch[psenc->chlen++] = ch;
255                 }
256                 break;
257         case 2:
258                 if (n-- < 1)
259                         goto restart;
260                 ch = *s0++ & 0xFF;
261                 if (is_leadbyte(ch) == 0)
262                         goto ilseq;
263                 psenc->ch[psenc->chlen++] = ch;
264                 break;
265         case 3:
266                 ch = psenc->ch[2] & 0xFF;
267                 if (is_leadbyte(ch) == 0)
268                         return EINVAL;
269         }
270         if (n-- < 1)
271                 goto restart;
272         wc |= (wchar_t)(ch << 8);
273         ch = *s0++ & 0xFF;
274         if (is_trailbyte(ch) == 0)
275                 goto ilseq;
276         wc |= (wchar_t)ch;
277         if (pwc != NULL)
278                 *pwc = wc;
279         *nresult = (size_t)(s0 - *s);
280         *s = s0;
281         psenc->chlen = 0;
282
283         return 0;
284
285 restart:
286         *nresult = (size_t)-2;
287         *s = s0;
288         return 0;
289
290 ilseq:
291         *nresult = (size_t)-1;
292         return EILSEQ;
293 }
294
295 static int
296 /*ARGSUSED*/
297 _citrus_DECHanyu_wcrtomb_priv(_DECHanyuEncodingInfo * __restrict ei,
298         char * __restrict s, size_t n, wchar_t wc,
299         _DECHanyuState * __restrict psenc, size_t * __restrict nresult)
300 {
301         int ch;
302
303         /* ei may be unused */
304         _DIAGASSERT(s != NULL);
305         _DIAGASSERT(psenc != NULL);
306         _DIAGASSERT(nresult != NULL);
307
308         if (psenc->chlen != 0)
309                 return EINVAL;
310
311         /* XXX: assume wchar_t as int */
312         if ((uint32_t)wc <= 0x7F) {
313                 ch = wc & 0xFF;
314         } else {
315                 if ((uint32_t)wc > 0xFFFF) {
316                         if ((wc & ~0xFFFF) != HANYUBIT)
317                                 goto ilseq;
318                         psenc->ch[psenc->chlen++] = (wc >> 24) & 0xFF;
319                         psenc->ch[psenc->chlen++] = (wc >> 16) & 0xFF;
320                         wc &= 0xFFFF;
321                 }
322                 ch = (wc >> 8) & 0xFF;
323                 if (!is_leadbyte(ch))
324                         goto ilseq;
325                 psenc->ch[psenc->chlen++] = ch;
326                 ch = wc & 0xFF;
327                 if (is_trailbyte(ch) == 0)
328                         goto ilseq;
329         }
330         psenc->ch[psenc->chlen++] = ch;
331         if (n < psenc->chlen) {
332                 *nresult = (size_t)-1;
333                 return E2BIG;
334         }
335         memcpy(s, psenc->ch, psenc->chlen);
336         *nresult = psenc->chlen;
337         psenc->chlen = 0;
338
339         return 0;
340
341 ilseq:
342         *nresult = (size_t)-1;
343         return EILSEQ;
344 }
345
346 static __inline int
347 /*ARGSUSED*/
348 _citrus_DECHanyu_stdenc_wctocs(_DECHanyuEncodingInfo * __restrict ei,
349         _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
350 {
351         int plane;
352         wchar_t mask;
353
354         /* ei may be unused */
355         _DIAGASSERT(csid != NULL);
356         _DIAGASSERT(idx != NULL);
357
358         plane = 0;
359         mask = 0x7F;
360         /* XXX: assume wchar_t as int */
361         if ((uint32_t)wc > 0x7F) {
362                 if ((uint32_t)wc > 0xFFFF) {
363                         if ((wc & ~0xFFFF) != HANYUBIT)
364                                 return EILSEQ;
365                         plane += 2;
366                 }
367                 if (is_leadbyte((wc >> 8) & 0xFF) == 0 ||
368                     is_trailbyte(wc & 0xFF) == 0)
369                         return EILSEQ;
370                 plane += (wc & 0x80) ? 1 : 2;
371                 mask |= 0x7F00;
372         }
373         *csid = plane;
374         *idx = (_index_t)(wc & mask);
375
376         return 0;
377 }
378
379 static __inline int
380 /*ARGSUSED*/
381 _citrus_DECHanyu_stdenc_cstowc(_DECHanyuEncodingInfo * __restrict ei,
382         wchar_t * __restrict wc, _csid_t csid, _index_t idx)
383 {
384         /* ei may be unused */
385         _DIAGASSERT(wc != NULL);
386
387         if (csid == 0) {
388                 if (idx > 0x7F)
389                         return EILSEQ;
390         } else if (csid <= 4) {
391                 if (is_94charset(idx >> 8) == 0)
392                         return EILSEQ;
393                 if (is_94charset(idx & 0xFF) == 0)
394                         return EILSEQ;
395                 if (csid % 2)
396                         idx |= 0x80;
397                 idx |= 0x8000;
398                 if (csid > 2)
399                         idx |= HANYUBIT;
400         } else
401                 return EILSEQ;
402         *wc = (wchar_t)idx;
403         return 0;
404 }
405
406 static __inline int
407 /*ARGSUSED*/
408 _citrus_DECHanyu_stdenc_get_state_desc_generic(
409         _DECHanyuEncodingInfo * __restrict ei,
410         _DECHanyuState * __restrict psenc, int * __restrict rstate)
411 {
412         /* ei may be unused */
413         _DIAGASSERT(psenc != NULL);
414         _DIAGASSERT(rstate != NULL);
415
416         *rstate = (psenc->chlen == 0)
417             ? _STDENC_SDGEN_INITIAL
418             : _STDENC_SDGEN_INCOMPLETE_CHAR;
419         return 0;
420 }
421
422 /* ----------------------------------------------------------------------
423  * public interface for ctype
424  */
425
426 _CITRUS_CTYPE_DECLS(DECHanyu);
427 _CITRUS_CTYPE_DEF_OPS(DECHanyu);
428
429 #include "citrus_ctype_template.h"
430
431
432 /* ----------------------------------------------------------------------
433  * public interface for stdenc
434  */
435
436 _CITRUS_STDENC_DECLS(DECHanyu);
437 _CITRUS_STDENC_DEF_OPS(DECHanyu);
438
439 #include "citrus_stdenc_template.h"