1 /* $NetBSD: citrus_hz.c,v 1.1 2006/11/22 23:38:27 tnozaki Exp $ */
4 * Copyright (c)2004, 2006 Citrus Project,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 #if defined(LIBC_SCCS) && !defined(lint)
32 __RCSID("$NetBSD: citrus_hz.c,v 1.1 2006/11/22 23:38:27 tnozaki Exp $");
33 #endif /* LIBC_SCCS and not lint */
35 #include <sys/queue.h>
36 #include <sys/types.h>
46 #include "citrus_namespace.h"
47 #include "citrus_types.h"
48 #include "citrus_bcs.h"
49 #include "citrus_module.h"
50 #include "citrus_ctype.h"
51 #include "citrus_stdenc.h"
53 #include "citrus_hz.h"
54 #include "citrus_prop.h"
59 * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx
60 * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx
61 * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
64 #define ESCAPE_CHAR '~'
67 CTRL
= 0, ASCII
= 1, GB2312
= 2, CS94
= 3, CS96
= 4
71 int start
, end
, width
;
74 static const range_t ranges
[] = {
75 #define RANGE(start, end) { start, end, (end - start) + 1 }
76 /* CTRL */ RANGE(0x00, 0x1F),
77 /* ASCII */ RANGE(0x20, 0x7F),
78 /* GB2312 */ RANGE(0x21, 0x7E),
79 /* CS94 */ RANGE(0x21, 0x7E),
80 /* CS96 */ RANGE(0x20, 0x7F),
84 typedef struct escape_t escape_t
;
92 typedef TAILQ_HEAD(escape_list
, escape_t
) escape_list
;
94 TAILQ_ENTRY(escape_t
) entry
;
96 graphic_t
*left
, *right
;
100 #define GL(escape) ((escape)->left)
101 #define GR(escape) ((escape)->right)
102 #define SET(escape) ((escape)->set)
103 #define ESC(escape) ((escape)->ch)
104 #define INIT(escape) (TAILQ_FIRST(SET(escape)))
106 static __inline escape_t
*
107 find_escape(escape_list
*set
, int ch
)
111 _DIAGASSERT(set
!= NULL
);
113 TAILQ_FOREACH(escape
, set
, entry
) {
114 if (ESC(escape
) == ch
)
123 graphic_t
*ascii
, *gb2312
;
126 #define E0SET(ei) (&(ei)->e0)
127 #define E1SET(ei) (&(ei)->e1)
128 #define INIT0(ei) (TAILQ_FIRST(E0SET(ei)))
129 #define INIT1(ei) (TAILQ_FIRST(E1SET(ei)))
140 /* for future multi-locale facility */
145 _HZState s_mbsrtowcs
;
147 _HZState s_wcsrtombs
;
152 #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
153 #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
155 #define _FUNCNAME(m) _citrus_HZ_##m
156 #define _ENCODING_INFO _HZEncodingInfo
157 #define _CTYPE_INFO _HZCTypeInfo
158 #define _ENCODING_STATE _HZState
159 #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX
160 #define _ENCODING_IS_STATE_DEPENDENT 1
161 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL)
164 _citrus_HZ_init_state(_HZEncodingInfo
* __restrict ei
,
165 _HZState
* __restrict psenc
)
167 _DIAGASSERT(ei
!= NULL
);
168 _DIAGASSERT(psenc
!= NULL
);
171 psenc
->inuse
= INIT0(ei
);
176 _citrus_HZ_pack_state(_HZEncodingInfo
* __restrict ei
,
177 void *__restrict pspriv
, const _HZState
* __restrict psenc
)
179 /* ei may be unused */
180 _DIAGASSERT(pspriv
!= NULL
);
181 _DIAGASSERT(psenc
!= NULL
);
183 memcpy(pspriv
, (const void *)psenc
, sizeof(*psenc
));
188 _citrus_HZ_unpack_state(_HZEncodingInfo
* __restrict ei
,
189 _HZState
* __restrict psenc
, const void * __restrict pspriv
)
191 /* ei may be unused */
192 _DIAGASSERT(psenc
!= NULL
);
193 _DIAGASSERT(pspriv
!= NULL
);
195 memcpy((void *)psenc
, pspriv
, sizeof(*psenc
));
199 _citrus_HZ_mbrtowc_priv(_HZEncodingInfo
* __restrict ei
,
200 wchar_t * __restrict pwc
, const char ** __restrict s
, size_t n
,
201 _HZState
* __restrict psenc
, size_t * __restrict nresult
)
205 int bit
, head
, tail
, len
, ch
;
207 escape_t
*candidate
, *init
;
208 const range_t
*range
;
210 _DIAGASSERT(ei
!= NULL
);
211 /* pwc may be null */
212 _DIAGASSERT(s
!= NULL
);
213 _DIAGASSERT(psenc
!= NULL
);
214 _DIAGASSERT(nresult
!= NULL
);
217 _citrus_HZ_init_state(ei
, psenc
);
222 if (psenc
->chlen
< 0 || psenc
->inuse
== NULL
)
226 bit
= head
= tail
= 0;
228 for (len
= 0; len
<= MB_LEN_MAX
; /**/) {
229 if (psenc
->chlen
== tail
) {
232 *nresult
= (size_t)-2;
235 psenc
->ch
[psenc
->chlen
++] = *s0
++;
238 ch
= (unsigned char)psenc
->ch
[tail
++];
240 if ((ch
& ~0x80) <= 0x1F) {
241 if (psenc
->inuse
!= INIT0(ei
))
247 graphic
= GR(psenc
->inuse
);
251 graphic
= GL(psenc
->inuse
);
252 if (ch
== ESCAPE_CHAR
)
258 } else if (tail
== 2 && psenc
->ch
[0] == ESCAPE_CHAR
) {
259 if (tail
< psenc
->chlen
)
261 if (ch
== ESCAPE_CHAR
) {
263 } else if (ch
== '\n') {
264 if (psenc
->inuse
!= INIT0(ei
))
266 tail
= psenc
->chlen
= 0;
271 _DIAGASSERT(init
!= NULL
);
272 if (psenc
->inuse
== init
) {
274 } else if (INIT(psenc
->inuse
) == init
) {
279 if (candidate
== NULL
) {
280 candidate
= find_escape(
281 SET(psenc
->inuse
), ch
);
282 if (candidate
== NULL
) {
289 psenc
->inuse
= candidate
;
290 tail
= psenc
->chlen
= 0;
293 } else if (ch
& 0x80) {
294 if (graphic
!= GR(psenc
->inuse
))
298 if (graphic
!= GL(psenc
->inuse
))
301 _DIAGASSERT(graphic
!= NULL
);
302 range
= &ranges
[(size_t)graphic
->charset
];
303 if (range
->start
> ch
|| range
->end
< ch
)
307 if (graphic
->length
== (tail
- head
)) {
308 if (graphic
->charset
> GB2312
)
309 bit
|= ESC(psenc
->inuse
) << 24;
314 *nresult
= (size_t)-1;
317 if (tail
< psenc
->chlen
)
323 *nresult
= (wc
== 0) ? 0 : len
;
329 _citrus_HZ_wcrtomb_priv(_HZEncodingInfo
* __restrict ei
,
330 char * __restrict s
, size_t n
, wchar_t wc
,
331 _HZState
* __restrict psenc
, size_t * __restrict nresult
)
334 escape_t
*candidate
, *init
;
337 const range_t
*range
;
339 _DIAGASSERT(ei
!= NULL
);
340 _DIAGASSERT(s
!= NULL
);
341 _DIAGASSERT(psenc
!= NULL
);
342 _DIAGASSERT(nresult
!= NULL
);
344 if (psenc
->chlen
!= 0 || psenc
->inuse
== NULL
)
352 if ((uint32_t)wc
<= 0x1F) {
353 candidate
= INIT0(ei
);
355 ? candidate
->left
: candidate
->right
;
358 range
= &ranges
[(size_t)CTRL
];
360 } else if ((uint32_t)wc
<= 0x7F) {
364 candidate
= graphic
->escape
;
365 range
= &ranges
[(size_t)graphic
->charset
];
366 len
= graphic
->length
;
367 } else if ((uint32_t)wc
<= 0x7F7F) {
368 graphic
= ei
->gb2312
;
371 candidate
= graphic
->escape
;
372 range
= &ranges
[(size_t)graphic
->charset
];
373 len
= graphic
->length
;
375 ch
= (wc
>> 24) & 0xFF;
376 candidate
= find_escape(E0SET(ei
), ch
);
377 if (candidate
== NULL
) {
378 candidate
= find_escape(E1SET(ei
), ch
);
379 if (candidate
== NULL
)
384 ? candidate
->left
: candidate
->right
;
387 range
= &ranges
[(size_t)graphic
->charset
];
388 len
= graphic
->length
;
390 if (psenc
->inuse
!= candidate
) {
392 if (SET(psenc
->inuse
) == SET(candidate
)) {
393 if (INIT(psenc
->inuse
) != init
||
394 psenc
->inuse
== init
|| candidate
== init
)
396 } else if (candidate
== (init
= INIT(candidate
))) {
403 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
404 psenc
->ch
[psenc
->chlen
++] = ESC(init
);
409 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
410 psenc
->ch
[psenc
->chlen
++] = ESC(candidate
);
411 psenc
->inuse
= candidate
;
416 ch
= (wc
>> (len
* 8)) & 0xFF;
417 if (range
->start
> ch
|| range
->end
< ch
)
419 psenc
->ch
[psenc
->chlen
++] = ch
| bit
;
421 memcpy(s
, psenc
->ch
, psenc
->chlen
);
422 *nresult
= psenc
->chlen
;
428 *nresult
= (size_t)-1;
433 _citrus_HZ_put_state_reset(_HZEncodingInfo
* __restrict ei
,
434 char * __restrict s
, size_t n
, _HZState
* __restrict psenc
,
435 size_t * __restrict nresult
)
439 _DIAGASSERT(ei
!= NULL
);
440 _DIAGASSERT(s
!= NULL
);
441 _DIAGASSERT(psenc
!= NULL
);
442 _DIAGASSERT(nresult
!= NULL
);
444 if (psenc
->chlen
!= 0 || psenc
->inuse
== NULL
)
446 candidate
= INIT0(ei
);
447 if (psenc
->inuse
!= candidate
) {
451 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
452 psenc
->ch
[psenc
->chlen
++] = ESC(candidate
);
456 if (psenc
->chlen
> 0)
457 memcpy(s
, psenc
->ch
, psenc
->chlen
);
458 *nresult
= psenc
->chlen
;
459 _citrus_HZ_init_state(ei
, psenc
);
465 _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo
* __restrict ei
,
466 _HZState
* __restrict psenc
, int * __restrict rstate
)
468 _DIAGASSERT(ei
!= NULL
);
469 _DIAGASSERT(psenc
!= NULL
);
470 _DIAGASSERT(rstate
!= NULL
);
472 if (psenc
->chlen
< 0 || psenc
->inuse
== NULL
)
474 *rstate
= (psenc
->chlen
== 0)
475 ? ((psenc
->inuse
== INIT0(ei
))
476 ? _STDENC_SDGEN_INITIAL
477 : _STDENC_SDGEN_STABLE
)
478 : ((psenc
->ch
[0] == ESCAPE_CHAR
)
479 ? _STDENC_SDGEN_INCOMPLETE_SHIFT
480 : _STDENC_SDGEN_INCOMPLETE_CHAR
);
487 _citrus_HZ_stdenc_wctocs(_HZEncodingInfo
* __restrict ei
,
488 _csid_t
* __restrict csid
, _index_t
* __restrict idx
, wchar_t wc
)
492 _DIAGASSERT(csid
!= NULL
);
493 _DIAGASSERT(idx
!= NULL
);
501 if ((uint32_t)wc
<= 0x7F) {
502 *csid
= (_csid_t
)bit
;
504 } else if ((uint32_t)wc
<= 0x7F7F) {
505 *csid
= (_csid_t
)(bit
| 0x8000);
508 *csid
= (_index_t
)(wc
& ~0x00FFFF7F);
509 *idx
= (_csid_t
)(wc
& 0x00FFFF7F);
517 _citrus_HZ_stdenc_cstowc(_HZEncodingInfo
* __restrict ei
,
518 wchar_t * __restrict wc
, _csid_t csid
, _index_t idx
)
520 _DIAGASSERT(ei
!= NULL
);
521 _DIAGASSERT(wc
!= NULL
);
527 *wc
|= (wchar_t)0x80;
533 *wc
|= (wchar_t)csid
;
540 _citrus_HZ_encoding_module_uninit(_HZEncodingInfo
*ei
)
544 _DIAGASSERT(ei
!= NULL
);
545 while ((escape
= TAILQ_FIRST(E0SET(ei
))) != NULL
) {
546 TAILQ_REMOVE(E0SET(ei
), escape
, entry
);
551 while ((escape
= TAILQ_FIRST(E1SET(ei
))) != NULL
) {
552 TAILQ_REMOVE(E1SET(ei
), escape
, entry
);
560 _citrus_HZ_parse_char(void **context
, const char *name
, const char *s
)
565 _DIAGASSERT(context
!= NULL
&& *context
!= NULL
);
566 _DIAGASSERT(name
!= NULL
);
567 _DIAGASSERT(s
!= NULL
);
569 p
= (void **)*context
;
570 escape
= (escape_t
*)p
[0];
571 if (escape
->ch
!= '\0')
574 if (escape
->ch
== ESCAPE_CHAR
|| *s
!= '\0')
581 _citrus_HZ_parse_graphic(void **context
, const char *name
, const char *s
)
588 _DIAGASSERT(context
!= NULL
&& *context
!= NULL
);
589 _DIAGASSERT(name
!= NULL
);
590 _DIAGASSERT(s
!= NULL
);
592 p
= (void **)*context
;
593 escape
= (escape_t
*)p
[0];
594 ei
= (_HZEncodingInfo
*)p
[1];
595 graphic
= malloc(sizeof(*graphic
));
598 memset(graphic
, 0, sizeof(*graphic
));
599 if (strcmp("GL", name
) == 0) {
600 if (GL(escape
) != NULL
)
602 GL(escape
) = graphic
;
603 } else if (strcmp("GR", name
) == 0) {
604 if (GR(escape
) != NULL
)
606 GR(escape
) = graphic
;
612 graphic
->escape
= escape
;
613 if (_bcs_strncasecmp("ASCII", s
, 5) == 0) {
616 graphic
->charset
= ASCII
;
620 } else if (_bcs_strncasecmp("GB2312", s
, 6) == 0) {
623 graphic
->charset
= GB2312
;
625 ei
->gb2312
= graphic
;
627 } else if (strncmp("94*", s
, 3) == 0) {
628 graphic
->charset
= CS94
;
629 } else if (strncmp("96*", s
, 3) == 0) {
630 graphic
->charset
= CS96
;
636 case '1': case '2': case '3':
637 graphic
->length
= (size_t)(*s
- '0');
647 static const _citrus_prop_hint_t escape_hints
[] = {
648 _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char
),
649 _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic
),
650 _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic
),
651 _CITRUS_PROP_HINT_END
655 _citrus_HZ_parse_escape(void **context
, const char *name
, const char *s
)
661 _DIAGASSERT(context
!= NULL
);
662 _DIAGASSERT(name
!= NULL
);
663 _DIAGASSERT(s
!= NULL
);
665 ei
= (_HZEncodingInfo
*)*context
;
666 escape
= malloc(sizeof(*escape
));
669 memset(escape
, 0, sizeof(*escape
));
670 if (strcmp("0", name
) == 0) {
671 escape
->set
= E0SET(ei
);
672 TAILQ_INSERT_TAIL(E0SET(ei
), escape
, entry
);
673 } else if (strcmp("1", name
) == 0) {
674 escape
->set
= E1SET(ei
);
675 TAILQ_INSERT_TAIL(E1SET(ei
), escape
, entry
);
680 p
[0] = (void *)escape
;
682 return _citrus_prop_parse_variable(
683 escape_hints
, (void *)&p
[0], s
, strlen(s
));
686 static const _citrus_prop_hint_t root_hints
[] = {
687 _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape
),
688 _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape
),
689 _CITRUS_PROP_HINT_END
693 _citrus_HZ_encoding_module_init(_HZEncodingInfo
* __restrict ei
,
694 const void * __restrict var
, size_t lenvar
)
698 _DIAGASSERT(ei
!= NULL
);
700 memset(ei
, 0, sizeof(*ei
));
701 TAILQ_INIT(E0SET(ei
));
702 TAILQ_INIT(E1SET(ei
));
703 errnum
= _citrus_prop_parse_variable(
704 root_hints
, (void *)ei
, var
, lenvar
);
706 _citrus_HZ_encoding_module_uninit(ei
);
710 /* ----------------------------------------------------------------------
711 * public interface for ctype
714 _CITRUS_CTYPE_DECLS(HZ
);
715 _CITRUS_CTYPE_DEF_OPS(HZ
);
717 #include "citrus_ctype_template.h"
719 /* ----------------------------------------------------------------------
720 * public interface for stdenc
723 _CITRUS_STDENC_DECLS(HZ
);
724 _CITRUS_STDENC_DEF_OPS(HZ
);
726 #include "citrus_stdenc_template.h"