Merge from vendor branch LESS:
[dragonfly.git] / lib / libc / citrus / modules / citrus_big5.c
1 /*      $NetBSD: src/lib/libc/citrus/modules/citrus_big5.c,v 1.8 2003/08/07 16:42:38 agc Exp $  */
2 /*      $DragonFly: src/lib/libc/citrus/modules/citrus_big5.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_big5.h"
79
80 /* ----------------------------------------------------------------------
81  * private stuffs used by templates
82  */
83
84 typedef struct {
85         char ch[2];
86         int chlen;
87 } _BIG5State;
88
89 typedef struct {
90         int dummy;
91 } _BIG5EncodingInfo;
92
93 typedef struct {
94         _BIG5EncodingInfo       ei;
95         struct {
96                 /* for future multi-locale facility */
97                 _BIG5State      s_mblen;
98                 _BIG5State      s_mbrlen;
99                 _BIG5State      s_mbrtowc;
100                 _BIG5State      s_mbtowc;
101                 _BIG5State      s_mbsrtowcs;
102                 _BIG5State      s_wcrtomb;
103                 _BIG5State      s_wcsrtombs;
104                 _BIG5State      s_wctomb;
105         } states;
106 } _BIG5CTypeInfo;
107
108 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
109 #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
110
111 #define _FUNCNAME(m)                    _citrus_BIG5_##m
112 #define _ENCODING_INFO                  _BIG5EncodingInfo
113 #define _CTYPE_INFO                     _BIG5CTypeInfo
114 #define _ENCODING_STATE                 _BIG5State
115 #define _ENCODING_MB_CUR_MAX(_ei_)      2
116 #define _ENCODING_IS_STATE_DEPENDENT    0
117 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
118
119
120 static __inline void
121 /*ARGSUSED*/
122 _citrus_BIG5_init_state(_BIG5EncodingInfo * __restrict ei,
123                         _BIG5State * __restrict s)
124 {
125         memset(s, 0, sizeof(*s));
126 }
127
128 static __inline void
129 /*ARGSUSED*/
130 _citrus_BIG5_pack_state(_BIG5EncodingInfo * __restrict ei,
131                         void * __restrict pspriv,
132                         const _BIG5State * __restrict s)
133 {
134         memcpy(pspriv, (const void *)s, sizeof(*s));
135 }
136
137 static __inline void
138 /*ARGSUSED*/
139 _citrus_BIG5_unpack_state(_BIG5EncodingInfo * __restrict ei,
140                           _BIG5State * __restrict s,
141                           const void * __restrict pspriv)
142 {
143         memcpy((void *)s, pspriv, sizeof(*s));
144 }
145
146 static __inline int
147 _citrus_BIG5_check(u_int c)
148 {
149         c &= 0xff;
150         return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1);
151 }
152
153 static __inline int
154 _citrus_BIG5_check2(u_int c)
155 {
156         c &= 0xff;
157         if ((c >= 0x40 && c <= 0x7f) || (c >= 0xa1 && c <= 0xfe))
158                 return 1;
159         else
160                 return 0;
161 }
162
163 static int
164 /*ARGSUSED*/
165 _citrus_BIG5_encoding_module_init(_BIG5EncodingInfo * __restrict ei,
166                                   const void * __restrict var, size_t lenvar)
167 {
168         _DIAGASSERT(ei != NULL);
169
170         memset((void *)ei, 0, sizeof(*ei));
171
172         return (0);
173 }
174
175 static void
176 /*ARGSUSED*/
177 _citrus_BIG5_encoding_module_uninit(_BIG5EncodingInfo *ei)
178 {
179 }
180
181 static int
182 /*ARGSUSED*/
183 _citrus_BIG5_mbrtowc_priv(_BIG5EncodingInfo * __restrict ei,
184                           wchar_t * __restrict pwc,
185                           const char ** __restrict s, size_t n,
186                           _BIG5State * __restrict psenc,
187                           size_t * __restrict nresult)
188 {
189         wchar_t wchar;
190         int c;
191         int chlenbak;
192         const char *s0;
193
194         _DIAGASSERT(nresult != 0);
195         _DIAGASSERT(ei != NULL);
196         _DIAGASSERT(psenc != NULL);
197         _DIAGASSERT(s != NULL && *s != NULL);
198
199         s0 = *s;
200
201         if (s0 == NULL) {
202                 _citrus_BIG5_init_state(ei, psenc);
203                 *nresult = 0;
204                 return (0);
205         }
206
207         chlenbak = psenc->chlen;
208
209         /* make sure we have the first byte in the buffer */
210         switch (psenc->chlen) {
211         case 0:
212                 if (n < 1)
213                         goto restart;
214                 psenc->ch[0] = *s0++;
215                 psenc->chlen = 1;
216                 n--;
217                 break;
218         case 1:
219                 break;
220         default:
221                 /* illegal state */
222                 goto ilseq;
223         }
224
225         c = _citrus_BIG5_check(psenc->ch[0] & 0xff);
226         if (c == 0)
227                 goto ilseq;
228         while (psenc->chlen < c) {
229                 if (n < 1) {
230                         goto restart;
231                 }
232                 psenc->ch[psenc->chlen] = *s0++;
233                 psenc->chlen++;
234                 n--;
235         }
236
237         switch (c) {
238         case 1:
239                 wchar = psenc->ch[0] & 0xff;
240                 break;
241         case 2:
242                 if (!_citrus_BIG5_check2(psenc->ch[1] & 0xff))
243                         goto ilseq;
244                 wchar = ((psenc->ch[0] & 0xff) << 8) | (psenc->ch[1] & 0xff);
245                 break;
246         default:
247                 /* illegal state */
248                 goto ilseq;
249         }
250
251         *s = s0;
252         psenc->chlen = 0;
253         if (pwc)
254                 *pwc = wchar;
255         if (!wchar)
256                 *nresult = 0;
257         else
258                 *nresult = c - chlenbak;
259
260         return (0);
261
262 ilseq:
263         psenc->chlen = 0;
264         *nresult = (size_t)-1;
265         return (EILSEQ);
266
267 restart:
268         *s = s0;
269         *nresult = (size_t)-2;
270         return (0);
271 }
272
273 static int
274 /*ARGSUSED*/
275 _citrus_BIG5_wcrtomb_priv(_BIG5EncodingInfo * __restrict ei,
276                           char * __restrict s,
277                           size_t n, wchar_t wc, _BIG5State * __restrict psenc,
278                           size_t * __restrict nresult)
279 {
280         int l, ret;
281
282         _DIAGASSERT(ei != NULL);
283         _DIAGASSERT(nresult != 0);
284         _DIAGASSERT(s != NULL);
285
286         /* check invalid sequence */
287         if (wc & ~0xffff) {
288                 ret = EILSEQ;
289                 goto err;
290         }
291
292         if (wc & 0x8000) {
293                 if (_citrus_BIG5_check((wc >> 8) & 0xff) != 2 ||
294                     !_citrus_BIG5_check2(wc & 0xff)) {
295                         ret = EILSEQ;
296                         goto err;
297                 }
298                 l = 2;
299         } else {
300                 if (wc & ~0xff || !_citrus_BIG5_check(wc & 0xff)) {
301                         ret = EILSEQ;
302                         goto err;
303                 }
304                 l = 1;
305         }
306
307         if (n < l) {
308                 /* bound check failure */
309                 ret = E2BIG;
310                 goto err;
311         }
312
313         if (l == 2) {
314                 s[0] = (wc >> 8) & 0xff;
315                 s[1] = wc & 0xff;
316         } else
317                 s[0] = wc & 0xff;
318
319         *nresult = l;
320
321         return 0;
322
323 err:
324         *nresult = (size_t)-1;
325         return ret;
326 }
327
328 static __inline int
329 /*ARGSUSED*/
330 _citrus_BIG5_stdenc_wctocs(_BIG5EncodingInfo * __restrict ei,
331                            _csid_t * __restrict csid,
332                            _index_t * __restrict idx, wchar_t wc)
333 {
334
335         _DIAGASSERT(csid != NULL && idx != NULL);
336
337         if (wc<0x100)
338                 *csid = 0;
339         else
340                 *csid = 1;
341         *idx = (_index_t)wc;
342                 
343         return 0;
344 }
345
346 static __inline int
347 /*ARGSUSED*/
348 _citrus_BIG5_stdenc_cstowc(_BIG5EncodingInfo * __restrict ei,
349                            wchar_t * __restrict wc,
350                            _csid_t csid, _index_t idx)
351 {
352         u_int8_t h, l;
353
354         _DIAGASSERT(wc != NULL);
355
356         switch (csid) {
357         case 0:
358                 if (idx>=0x80U)
359                         return EILSEQ;
360                 *wc = (wchar_t)idx;
361                 break;
362         case 1:
363                 if (idx>=0x10000U)
364                         return EILSEQ;
365                 h = idx >> 8;
366                 l = idx;
367                 if (h<0xA1 || h>0xF9 || l<0x40 || l>0xFE)
368                         return EILSEQ;
369                 *wc = (wchar_t)idx;
370                 break;
371         default:
372                 return EILSEQ;
373         }
374
375         return 0;
376 }
377
378 /* ----------------------------------------------------------------------
379  * public interface for ctype
380  */
381
382 _CITRUS_CTYPE_DECLS(BIG5);
383 _CITRUS_CTYPE_DEF_OPS(BIG5);
384
385 #include "citrus_ctype_template.h"
386
387
388 /* ----------------------------------------------------------------------
389  * public interface for stdenc
390  */
391
392 _CITRUS_STDENC_DECLS(BIG5);
393 _CITRUS_STDENC_DEF_OPS(BIG5);
394
395 #include "citrus_stdenc_template.h"