Merge branch 'vendor/OPENSSL'
[dragonfly.git] / lib / libc / citrus / modules / citrus_mskanji.c
1 /* $NetBSD: citrus_mskanji.c,v 1.12 2007/03/05 16:57:06 tnozaki Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_mskanji.c,v 1.2 2008/04/10 10:21:02 hasso 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  *    ja_JP.SJIS locale table for BSD4.4/rune
32  *    version 1.0
33  *    (C) Sin'ichiro MIYATANI / Phase One, Inc
34  *    May 12, 1995
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *      This product includes software developed by Phase One, Inc.
47  * 4. The name of Phase One, Inc. may be used to endorse or promote products
48  *    derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  
60  * SUCH DAMAGE.  
61  */  
62
63
64 #include <sys/types.h>
65 #include <assert.h>
66 #include <errno.h>
67 #include <limits.h>
68 #include <string.h>
69 #include <locale.h>
70 #include <stddef.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <wchar.h>
74
75 #include "citrus_namespace.h"
76 #include "citrus_types.h"
77 #include "citrus_bcs.h"
78 #include "citrus_module.h"
79 #include "citrus_ctype.h"
80 #include "citrus_stdenc.h"
81 #include "citrus_mskanji.h"
82
83
84 /* ----------------------------------------------------------------------
85  * private stuffs used by templates
86  */
87
88 typedef struct _MSKanjiState {
89         char ch[2];
90         int chlen;
91 } _MSKanjiState;
92
93 typedef struct {
94         int mode;
95 #define MODE_JIS2004    1
96 } _MSKanjiEncodingInfo;
97
98 typedef struct {
99         _MSKanjiEncodingInfo    ei;
100         struct {
101                 /* for future multi-locale facility */
102                 _MSKanjiState   s_mblen;
103                 _MSKanjiState   s_mbrlen;
104                 _MSKanjiState   s_mbrtowc;
105                 _MSKanjiState   s_mbtowc;
106                 _MSKanjiState   s_mbsrtowcs;
107                 _MSKanjiState   s_wcrtomb;
108                 _MSKanjiState   s_wcsrtombs;
109                 _MSKanjiState   s_wctomb;
110         } states;
111 } _MSKanjiCTypeInfo;
112
113 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
114 #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
115
116 #define _FUNCNAME(m)                    _citrus_MSKanji_##m
117 #define _ENCODING_INFO                  _MSKanjiEncodingInfo
118 #define _CTYPE_INFO                     _MSKanjiCTypeInfo
119 #define _ENCODING_STATE                 _MSKanjiState
120 #define _ENCODING_MB_CUR_MAX(_ei_)      2
121 #define _ENCODING_IS_STATE_DEPENDENT    0
122 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
123
124
125 static int
126 _mskanji1(int c)
127 {
128
129         if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc))
130                 return 1;
131         else
132                 return 0;
133 }
134
135 static int
136 _mskanji2(int c)
137 {
138
139         if ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc))
140                 return 1;
141         else
142                 return 0;
143 }
144
145 static __inline void
146 /*ARGSUSED*/
147 _citrus_MSKanji_init_state(_MSKanjiEncodingInfo * __restrict ei,
148                            _MSKanjiState * __restrict s)
149 {
150         s->chlen = 0;
151 }
152
153 static __inline void
154 /*ARGSUSED*/
155 _citrus_MSKanji_pack_state(_MSKanjiEncodingInfo * __restrict ei,
156                            void * __restrict pspriv,
157                            const _MSKanjiState * __restrict s)
158 {
159         memcpy(pspriv, (const void *)s, sizeof(*s));
160 }
161
162 static __inline void
163 /*ARGSUSED*/
164 _citrus_MSKanji_unpack_state(_MSKanjiEncodingInfo * __restrict ei,
165                              _MSKanjiState * __restrict s,
166                              const void * __restrict pspriv)
167 {
168         memcpy((void *)s, pspriv, sizeof(*s));
169 }
170
171 static int
172 /*ARGSUSED*/
173 _citrus_MSKanji_mbrtowc_priv(_MSKanjiEncodingInfo * __restrict ei,
174                              wchar_t * __restrict pwc,
175                              const char ** __restrict s, size_t n,
176                              _MSKanjiState * __restrict psenc,
177                              size_t * __restrict nresult)
178 {
179         wchar_t wchar;
180         int len;
181         int chlenbak;
182         const char *s0;
183
184         _DIAGASSERT(nresult != 0);
185         _DIAGASSERT(ei != NULL);
186         _DIAGASSERT(s != NULL);
187         _DIAGASSERT(psenc != NULL);
188
189         s0 = *s;
190
191         if (s0 == NULL) {
192                 _citrus_MSKanji_init_state(ei, psenc);
193                 *nresult = 0; /* state independent */
194                 return (0);
195         }
196
197         chlenbak = psenc->chlen;
198
199         /* make sure we have the first byte in the buffer */
200         switch (psenc->chlen) {
201         case 0:
202                 if (n < 1)
203                         goto restart;
204                 psenc->ch[0] = *s0++;
205                 psenc->chlen = 1;
206                 n--;
207                 break;
208         case 1:
209                 break;
210         default:
211                 /* illegal state */
212                 goto encoding_error;
213         }
214
215         len = _mskanji1(psenc->ch[0] & 0xff) ? 2 : 1;
216         while (psenc->chlen < len) {
217                 if (n < 1)
218                         goto restart;
219                 psenc->ch[psenc->chlen] = *s0++;
220                 psenc->chlen++;
221                 n--;
222         }
223
224         *s = s0;
225
226         switch (len) {
227         case 1:
228                 wchar = psenc->ch[0] & 0xff;
229                 break;
230         case 2:
231                 if (!_mskanji2(psenc->ch[1] & 0xff))
232                         goto encoding_error;
233                 wchar = ((psenc->ch[0] & 0xff) << 8) | (psenc->ch[1] & 0xff);
234                 break;
235         default:
236                 /* illegal state */
237                 goto encoding_error;
238         }
239
240         psenc->chlen = 0;
241
242         if (pwc)
243                 *pwc = wchar;
244
245         if (!wchar)
246                 *nresult = 0;
247         else
248                 *nresult = len - chlenbak;
249
250         return (0);
251
252 encoding_error:
253         psenc->chlen = 0;
254         *nresult = (size_t)-1;
255         return (EILSEQ);
256
257 restart:
258         *nresult = (size_t)-2;
259         *s = s0;
260         return (0);
261 }
262
263
264 static int
265 _citrus_MSKanji_wcrtomb_priv(_MSKanjiEncodingInfo * __restrict ei,
266                              char * __restrict s, size_t n, wchar_t wc,
267                              _MSKanjiState * __restrict psenc,
268                              size_t * __restrict nresult)
269 {
270         int ret;
271
272         _DIAGASSERT(ei != NULL);
273         _DIAGASSERT(psenc != NULL);
274         _DIAGASSERT(s != NULL);
275
276         /* check invalid sequence */
277         if (wc & ~0xffff) {
278                 ret = EILSEQ;
279                 goto err;
280         }
281
282         if (wc & 0xff00) {
283                 if (n < 2) {
284                         ret = E2BIG;
285                         goto err;
286                 }
287
288                 s[0] = (wc >> 8) & 0xff;
289                 s[1] = wc & 0xff;
290                 if (!_mskanji1(s[0] & 0xff) || !_mskanji2(s[1] & 0xff)) {
291                         ret = EILSEQ;
292                         goto err;
293                 }
294
295                 *nresult = 2;
296                 return 0;
297         } else {
298                 if (n < 1) {
299                         ret = E2BIG;
300                         goto err;
301                 }
302
303                 s[0] = wc & 0xff;
304                 if (_mskanji1(s[0] & 0xff)) {
305                         ret = EILSEQ;
306                         goto err;
307                 }
308
309                 *nresult = 1;
310                 return 0;
311         }
312
313 err:
314         *nresult = (size_t)-1;
315         return ret;
316 }
317
318
319 static __inline int
320 /*ARGSUSED*/
321 _citrus_MSKanji_stdenc_wctocs(_MSKanjiEncodingInfo * __restrict ei,
322                               _csid_t * __restrict csid,
323                               _index_t * __restrict idx, wchar_t wc)
324 {
325         _index_t row, col;
326         int offset;
327
328         _DIAGASSERT(csid != NULL && idx != NULL);
329
330         if ((_wc_t)wc < 0x80) {
331                 /* ISO-646 */
332                 *csid = 0;
333                 *idx = (_index_t)wc;
334         } else if ((_wc_t)wc < 0x100) {
335                 /* KANA */
336                 *csid = 1;
337                 *idx = (_index_t)wc & 0x7F;
338         } else {
339                 /* Kanji (containing Gaiji zone) */
340                 /*
341                  * 94^2 zone (contains a part of Gaiji (0xED40 - 0xEEFC)):
342                  * 0x8140 - 0x817E -> 0x2121 - 0x215F
343                  * 0x8180 - 0x819E -> 0x2160 - 0x217E
344                  * 0x819F - 0x81FC -> 0x2221 - 0x227E
345                  *
346                  * 0x8240 - 0x827E -> 0x2321 - 0x235F
347                  *  ...
348                  * 0x9F9F - 0x9FFc -> 0x5E21 - 0x5E7E
349                  *
350                  * 0xE040 - 0xE07E -> 0x5F21 - 0x5F5F
351                  *  ...
352                  * 0xEF9F - 0xEFFC -> 0x7E21 - 0x7E7E
353                  *
354                  * extended Gaiji zone:
355                  * 0xF040 - 0xFCFC
356                  *
357                  * JIS X0213-plane2:
358                  * 0xF040 - 0xF09E -> 0x2121 - 0x217E
359                  * 0xF140 - 0xF19E -> 0x2321 - 0x237E
360                  * ...
361                  * 0xF240 - 0xF29E -> 0x2521 - 0x257E
362                  *
363                  * 0xF09F - 0xF0FC -> 0x2821 - 0x287E
364                  * 0xF29F - 0xF2FC -> 0x2C21 - 0x2C7E
365                  * ...
366                  * 0xF44F - 0xF49E -> 0x2F21 - 0x2F7E
367                  *
368                  * 0xF49F - 0xF4FC -> 0x6E21 - 0x6E7E
369                  * ...
370                  * 0xFC9F - 0xFCFC -> 0x7E21 - 0x7E7E
371                  */
372                 row = ((_wc_t)wc >> 8) & 0xFF;
373                 col = (_wc_t)wc & 0xFF;
374                 if (!_mskanji1(row) || !_mskanji2(col))
375                         return EILSEQ;
376                 if ((ei->mode & MODE_JIS2004) == 0 || row < 0xF0) {
377                         *csid = 2;
378                         offset = 0x81;
379                 } else {
380                         *csid = 3;
381                         if ((_wc_t)wc <= 0xF49E) {
382                                 offset = (_wc_t)wc >= 0xF29F ||
383                                   ((_wc_t)wc >= 0xF09F && (_wc_t)wc <= 0xF0FC)
384                                     ? 0xED : 0xF0;
385                         } else
386                                 offset = 0xCE;
387                 }
388                 row -= offset;
389                 if (row >= 0x5F)
390                         row -= 0x40;
391                 row = row * 2 + 0x21;
392                 col -= 0x1F;
393                 if (col >= 0x61)
394                         col -= 1;
395                 if (col > 0x7E) {
396                         row += 1;
397                         col -= 0x5E;
398                 }
399                 *idx = ((_index_t)row << 8) | col;
400         }
401
402         return 0;
403 }
404
405 static __inline int
406 /*ARGSUSED*/
407 _citrus_MSKanji_stdenc_cstowc(_MSKanjiEncodingInfo * __restrict ei,
408                               wchar_t * __restrict wc,
409                               _csid_t csid, _index_t idx)
410 {
411         u_int32_t row, col;
412         int offset;
413
414         _DIAGASSERT(wc != NULL);
415
416         switch (csid) {
417         case 0:
418                 /* ISO-646 */
419                 if (idx >= 0x80)
420                         return EILSEQ;
421                 *wc = (wchar_t)idx;
422                 break;
423         case 1:
424                 /* kana */
425                 if (idx >= 0x80)
426                         return EILSEQ;
427                 *wc = (wchar_t)idx + 0x80;
428                 break;
429         case 3:
430                 if ((ei->mode & MODE_JIS2004) == 0)
431                         return EILSEQ;
432         /*FALLTHROUGH*/
433         case 2:
434                 /* kanji */
435                 row = (idx >> 8);
436                 if (row < 0x21)
437                         return EILSEQ;
438                 if (csid == 3) {
439                         if (row <= 0x2F)
440                                 offset = (row == 0x22 || row >= 0x26)
441                                     ? 0xED : 0xF0;
442                         else if (row >= 0x4D && row <= 0x7E)
443                                 offset = 0xCE;
444                         else
445                                 return EILSEQ;
446                 } else {
447                         if (row > 0x97)
448                                 return EILSEQ;
449                         offset = (row < 0x5F) ? 0x81 : 0xC1;
450                 }
451                 col = idx & 0xFF;
452                 if (col < 0x21 || col > 0x7E)
453                         return EILSEQ;
454                 row -= 0x21; col -= 0x21;
455                 if ((row & 1) == 0) {
456                         col += 0x40;
457                         if (col >= 0x7F)
458                                 col += 1;
459                 } else
460                         col += 0x9F;
461                 row = row / 2 + offset;
462                 *wc = ((wchar_t)row << 8) | col;
463                 break;
464         default:
465                 return EILSEQ;
466         }
467
468         return 0;
469 }
470
471 static __inline int
472 /*ARGSUSED*/
473 _citrus_MSKanji_stdenc_get_state_desc_generic(_MSKanjiEncodingInfo * __restrict ei,
474                                               _MSKanjiState * __restrict psenc,
475                                               int * __restrict rstate)
476 {
477
478         if (psenc->chlen == 0)
479                 *rstate = _STDENC_SDGEN_INITIAL;
480         else
481                 *rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
482
483         return 0;
484 }
485
486 static int
487 /*ARGSUSED*/
488 _citrus_MSKanji_encoding_module_init(_MSKanjiEncodingInfo *  __restrict ei,
489                                      const void * __restrict var,
490                                      size_t lenvar)
491 {
492         const char *p;
493
494         _DIAGASSERT(ei != NULL);
495
496         p = var;
497 #define MATCH(x, act)                                           \
498 do {                                                            \
499         if (lenvar >= (sizeof(#x)-1) &&                         \
500             _bcs_strncasecmp(p, #x, sizeof(#x)-1) == 0) {       \
501                 act;                                            \
502                 lenvar -= sizeof(#x)-1;                         \
503                 p += sizeof(#x)-1;                              \
504         }                                                       \
505 } while (/*CONSTCOND*/0)
506         memset((void *)ei, 0, sizeof(*ei));
507         while (lenvar > 0) {
508                 switch (_bcs_toupper(*p)) {
509                 case 'J':
510                         MATCH(JIS2004, ei->mode |= MODE_JIS2004);
511                         break;
512                 }
513                 ++p;
514                 --lenvar;
515         }
516
517         return 0;
518
519 }
520
521 static void
522 _citrus_MSKanji_encoding_module_uninit(_MSKanjiEncodingInfo *ei)
523 {
524 }
525
526 /* ----------------------------------------------------------------------
527  * public interface for ctype
528  */
529
530 _CITRUS_CTYPE_DECLS(MSKanji);
531 _CITRUS_CTYPE_DEF_OPS(MSKanji);
532
533 #include "citrus_ctype_template.h"
534
535 /* ----------------------------------------------------------------------
536  * public interface for stdenc
537  */
538
539 _CITRUS_STDENC_DECLS(MSKanji);
540 _CITRUS_STDENC_DEF_OPS(MSKanji);
541
542 #include "citrus_stdenc_template.h"