Home | History | Annotate | Line # | Download | only in modules
citrus_hz.c revision 1.3
      1  1.3    joerg /* $NetBSD: citrus_hz.c,v 1.3 2013/05/28 16:57:56 joerg Exp $ */
      2  1.1  tnozaki 
      3  1.1  tnozaki /*-
      4  1.1  tnozaki  * Copyright (c)2004, 2006 Citrus Project,
      5  1.1  tnozaki  * All rights reserved.
      6  1.1  tnozaki  *
      7  1.1  tnozaki  * Redistribution and use in source and binary forms, with or without
      8  1.1  tnozaki  * modification, are permitted provided that the following conditions
      9  1.1  tnozaki  * are met:
     10  1.1  tnozaki  * 1. Redistributions of source code must retain the above copyright
     11  1.1  tnozaki  *    notice, this list of conditions and the following disclaimer.
     12  1.1  tnozaki  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  tnozaki  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  tnozaki  *    documentation and/or other materials provided with the distribution.
     15  1.1  tnozaki  *
     16  1.1  tnozaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  1.1  tnozaki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1  tnozaki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1  tnozaki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  1.1  tnozaki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1  tnozaki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.1  tnozaki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.1  tnozaki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.1  tnozaki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.1  tnozaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.1  tnozaki  * SUCH DAMAGE.
     27  1.1  tnozaki  *
     28  1.1  tnozaki  */
     29  1.1  tnozaki 
     30  1.1  tnozaki #include <sys/cdefs.h>
     31  1.1  tnozaki #if defined(LIBC_SCCS) && !defined(lint)
     32  1.3    joerg __RCSID("$NetBSD: citrus_hz.c,v 1.3 2013/05/28 16:57:56 joerg Exp $");
     33  1.1  tnozaki #endif /* LIBC_SCCS and not lint */
     34  1.1  tnozaki 
     35  1.1  tnozaki #include <sys/queue.h>
     36  1.1  tnozaki #include <sys/types.h>
     37  1.1  tnozaki #include <assert.h>
     38  1.1  tnozaki #include <errno.h>
     39  1.1  tnozaki #include <string.h>
     40  1.1  tnozaki #include <stdint.h>
     41  1.1  tnozaki #include <stdlib.h>
     42  1.1  tnozaki #include <stddef.h>
     43  1.1  tnozaki #include <limits.h>
     44  1.1  tnozaki #include <wchar.h>
     45  1.1  tnozaki 
     46  1.1  tnozaki #include "citrus_namespace.h"
     47  1.1  tnozaki #include "citrus_types.h"
     48  1.1  tnozaki #include "citrus_bcs.h"
     49  1.1  tnozaki #include "citrus_module.h"
     50  1.1  tnozaki #include "citrus_ctype.h"
     51  1.1  tnozaki #include "citrus_stdenc.h"
     52  1.1  tnozaki 
     53  1.1  tnozaki #include "citrus_hz.h"
     54  1.1  tnozaki #include "citrus_prop.h"
     55  1.1  tnozaki 
     56  1.1  tnozaki /*
     57  1.1  tnozaki  * wchar_t mapping:
     58  1.1  tnozaki  *
     59  1.1  tnozaki  * CTRL/ASCII	00000000 00000000 00000000 gxxxxxxx
     60  1.1  tnozaki  * GB2312	00000000 00000000 0xxxxxxx gxxxxxxx
     61  1.1  tnozaki  * 94/96*n (~M)	0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
     62  1.1  tnozaki  */
     63  1.1  tnozaki 
     64  1.1  tnozaki #define ESCAPE_CHAR	'~'
     65  1.1  tnozaki 
     66  1.1  tnozaki typedef enum {
     67  1.1  tnozaki 	CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4
     68  1.1  tnozaki } charset_t;
     69  1.1  tnozaki 
     70  1.1  tnozaki typedef struct {
     71  1.1  tnozaki 	int start, end, width;
     72  1.1  tnozaki } range_t;
     73  1.1  tnozaki 
     74  1.1  tnozaki static const range_t ranges[] = {
     75  1.1  tnozaki #define RANGE(start, end) { start, end, (end - start) + 1 }
     76  1.1  tnozaki /* CTRL   */ RANGE(0x00, 0x1F),
     77  1.1  tnozaki /* ASCII  */ RANGE(0x20, 0x7F),
     78  1.1  tnozaki /* GB2312 */ RANGE(0x21, 0x7E),
     79  1.1  tnozaki /* CS94   */ RANGE(0x21, 0x7E),
     80  1.1  tnozaki /* CS96   */ RANGE(0x20, 0x7F),
     81  1.1  tnozaki #undef RANGE
     82  1.1  tnozaki };
     83  1.1  tnozaki 
     84  1.1  tnozaki typedef struct escape_t escape_t;
     85  1.1  tnozaki typedef struct {
     86  1.1  tnozaki 	charset_t charset;
     87  1.1  tnozaki 	size_t length;
     88  1.1  tnozaki #define ROWCOL_MAX	3
     89  1.1  tnozaki 	escape_t *escape;
     90  1.1  tnozaki } graphic_t;
     91  1.1  tnozaki 
     92  1.1  tnozaki typedef TAILQ_HEAD(escape_list, escape_t) escape_list;
     93  1.1  tnozaki struct escape_t {
     94  1.1  tnozaki 	TAILQ_ENTRY(escape_t) entry;
     95  1.1  tnozaki 	int ch;
     96  1.1  tnozaki 	graphic_t *left, *right;
     97  1.1  tnozaki 	escape_list *set;
     98  1.1  tnozaki };
     99  1.1  tnozaki 
    100  1.1  tnozaki #define GL(escape)	((escape)->left)
    101  1.1  tnozaki #define GR(escape)	((escape)->right)
    102  1.1  tnozaki #define SET(escape)	((escape)->set)
    103  1.1  tnozaki #define ESC(escape)	((escape)->ch)
    104  1.1  tnozaki #define INIT(escape)	(TAILQ_FIRST(SET(escape)))
    105  1.1  tnozaki 
    106  1.1  tnozaki static __inline escape_t *
    107  1.1  tnozaki find_escape(escape_list *set, int ch)
    108  1.1  tnozaki {
    109  1.1  tnozaki 	escape_t *escape;
    110  1.1  tnozaki 
    111  1.1  tnozaki 	_DIAGASSERT(set != NULL);
    112  1.1  tnozaki 
    113  1.1  tnozaki 	TAILQ_FOREACH(escape, set, entry) {
    114  1.1  tnozaki 		if (ESC(escape) == ch)
    115  1.1  tnozaki 			break;
    116  1.1  tnozaki 	}
    117  1.1  tnozaki 
    118  1.1  tnozaki 	return escape;
    119  1.1  tnozaki }
    120  1.1  tnozaki 
    121  1.1  tnozaki typedef struct {
    122  1.1  tnozaki 	escape_list e0, e1;
    123  1.1  tnozaki 	graphic_t *ascii, *gb2312;
    124  1.1  tnozaki } _HZEncodingInfo;
    125  1.1  tnozaki 
    126  1.1  tnozaki #define E0SET(ei)	(&(ei)->e0)
    127  1.1  tnozaki #define E1SET(ei)	(&(ei)->e1)
    128  1.1  tnozaki #define INIT0(ei)	(TAILQ_FIRST(E0SET(ei)))
    129  1.1  tnozaki #define INIT1(ei)	(TAILQ_FIRST(E1SET(ei)))
    130  1.1  tnozaki 
    131  1.1  tnozaki typedef struct {
    132  1.1  tnozaki 	int chlen;
    133  1.1  tnozaki 	char ch[ROWCOL_MAX];
    134  1.1  tnozaki 	escape_t *inuse;
    135  1.1  tnozaki } _HZState;
    136  1.1  tnozaki 
    137  1.1  tnozaki typedef struct {
    138  1.1  tnozaki 	_HZEncodingInfo		ei;
    139  1.1  tnozaki 	struct {
    140  1.1  tnozaki 		/* for future multi-locale facility */
    141  1.1  tnozaki 		_HZState	s_mblen;
    142  1.1  tnozaki 		_HZState	s_mbrlen;
    143  1.1  tnozaki 		_HZState	s_mbrtowc;
    144  1.1  tnozaki 		_HZState	s_mbtowc;
    145  1.1  tnozaki 		_HZState	s_mbsrtowcs;
    146  1.3    joerg 		_HZState	s_mbsnrtowcs;
    147  1.1  tnozaki 		_HZState	s_wcrtomb;
    148  1.1  tnozaki 		_HZState	s_wcsrtombs;
    149  1.3    joerg 		_HZState	s_wcsnrtombs;
    150  1.1  tnozaki 		_HZState	s_wctomb;
    151  1.1  tnozaki 	} states;
    152  1.1  tnozaki } _HZCTypeInfo;
    153  1.1  tnozaki 
    154  1.1  tnozaki #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
    155  1.1  tnozaki #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
    156  1.1  tnozaki 
    157  1.1  tnozaki #define _FUNCNAME(m)			_citrus_HZ_##m
    158  1.1  tnozaki #define _ENCODING_INFO			_HZEncodingInfo
    159  1.1  tnozaki #define _CTYPE_INFO			_HZCTypeInfo
    160  1.1  tnozaki #define _ENCODING_STATE			_HZState
    161  1.1  tnozaki #define _ENCODING_MB_CUR_MAX(_ei_)	MB_LEN_MAX
    162  1.1  tnozaki #define _ENCODING_IS_STATE_DEPENDENT		1
    163  1.1  tnozaki #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	((_ps_)->inuse == NULL)
    164  1.1  tnozaki 
    165  1.1  tnozaki static __inline void
    166  1.1  tnozaki _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,
    167  1.1  tnozaki 	_HZState * __restrict psenc)
    168  1.1  tnozaki {
    169  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    170  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    171  1.1  tnozaki 
    172  1.1  tnozaki 	psenc->chlen = 0;
    173  1.1  tnozaki 	psenc->inuse = INIT0(ei);
    174  1.1  tnozaki }
    175  1.1  tnozaki 
    176  1.1  tnozaki static __inline void
    177  1.1  tnozaki /*ARGSUSED*/
    178  1.1  tnozaki _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei,
    179  1.1  tnozaki 	void *__restrict pspriv, const _HZState * __restrict psenc)
    180  1.1  tnozaki {
    181  1.1  tnozaki 	/* ei may be unused */
    182  1.1  tnozaki 	_DIAGASSERT(pspriv != NULL);
    183  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    184  1.1  tnozaki 
    185  1.1  tnozaki 	memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
    186  1.1  tnozaki }
    187  1.1  tnozaki 
    188  1.1  tnozaki static __inline void
    189  1.1  tnozaki /*ARGSUSED*/
    190  1.1  tnozaki _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei,
    191  1.1  tnozaki 	_HZState * __restrict psenc, const void * __restrict pspriv)
    192  1.1  tnozaki {
    193  1.1  tnozaki 	/* ei may be unused */
    194  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    195  1.1  tnozaki 	_DIAGASSERT(pspriv != NULL);
    196  1.1  tnozaki 
    197  1.1  tnozaki 	memcpy((void *)psenc, pspriv, sizeof(*psenc));
    198  1.1  tnozaki }
    199  1.1  tnozaki 
    200  1.1  tnozaki static int
    201  1.1  tnozaki _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
    202  1.1  tnozaki 	wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
    203  1.1  tnozaki 	_HZState * __restrict psenc, size_t * __restrict nresult)
    204  1.1  tnozaki {
    205  1.1  tnozaki 	const char *s0;
    206  1.1  tnozaki 	wchar_t wc;
    207  1.1  tnozaki 	int bit, head, tail, len, ch;
    208  1.1  tnozaki 	graphic_t *graphic;
    209  1.1  tnozaki 	escape_t *candidate, *init;
    210  1.1  tnozaki 	const range_t *range;
    211  1.1  tnozaki 
    212  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    213  1.1  tnozaki 	/* pwc may be null */
    214  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    215  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    216  1.1  tnozaki 	_DIAGASSERT(nresult != NULL);
    217  1.1  tnozaki 
    218  1.1  tnozaki 	if (*s == NULL) {
    219  1.1  tnozaki 		_citrus_HZ_init_state(ei, psenc);
    220  1.1  tnozaki 		*nresult = 1;
    221  1.1  tnozaki 		return 0;
    222  1.1  tnozaki 	}
    223  1.1  tnozaki 	s0 = *s;
    224  1.1  tnozaki 	if (psenc->chlen < 0 || psenc->inuse == NULL)
    225  1.1  tnozaki 		return EINVAL;
    226  1.1  tnozaki 
    227  1.1  tnozaki 	wc = (wchar_t)0;
    228  1.1  tnozaki 	bit = head = tail = 0;
    229  1.1  tnozaki 	graphic = NULL;
    230  1.1  tnozaki 	for (len = 0; len <= MB_LEN_MAX; /**/) {
    231  1.1  tnozaki 		if (psenc->chlen == tail) {
    232  1.1  tnozaki 			if (n-- < 1) {
    233  1.1  tnozaki 				*s = s0;
    234  1.1  tnozaki 				*nresult = (size_t)-2;
    235  1.1  tnozaki 				return 0;
    236  1.1  tnozaki 			}
    237  1.1  tnozaki 			psenc->ch[psenc->chlen++] = *s0++;
    238  1.1  tnozaki 			++len;
    239  1.1  tnozaki 		}
    240  1.1  tnozaki 		ch = (unsigned char)psenc->ch[tail++];
    241  1.1  tnozaki 		if (tail == 1) {
    242  1.1  tnozaki 			if ((ch & ~0x80) <= 0x1F) {
    243  1.1  tnozaki 				if (psenc->inuse != INIT0(ei))
    244  1.1  tnozaki 					break;
    245  1.1  tnozaki 				wc = (wchar_t)ch;
    246  1.1  tnozaki 				goto done;
    247  1.1  tnozaki 			}
    248  1.1  tnozaki 			if (ch & 0x80) {
    249  1.1  tnozaki 				graphic = GR(psenc->inuse);
    250  1.1  tnozaki 				bit = 0x80;
    251  1.1  tnozaki 				ch &= ~0x80;
    252  1.1  tnozaki 			} else {
    253  1.1  tnozaki 				graphic = GL(psenc->inuse);
    254  1.1  tnozaki 				if (ch == ESCAPE_CHAR)
    255  1.1  tnozaki 					continue;
    256  1.1  tnozaki 				bit = 0x0;
    257  1.1  tnozaki 			}
    258  1.1  tnozaki 			if (graphic == NULL)
    259  1.1  tnozaki 				break;
    260  1.1  tnozaki 		} else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) {
    261  1.1  tnozaki 			if (tail < psenc->chlen)
    262  1.1  tnozaki 				return EINVAL;
    263  1.1  tnozaki 			if (ch == ESCAPE_CHAR) {
    264  1.1  tnozaki 				++head;
    265  1.1  tnozaki 			} else if (ch == '\n') {
    266  1.1  tnozaki 				if (psenc->inuse != INIT0(ei))
    267  1.1  tnozaki 					break;
    268  1.1  tnozaki 				tail = psenc->chlen = 0;
    269  1.1  tnozaki 				continue;
    270  1.1  tnozaki 			} else {
    271  1.1  tnozaki 				candidate = NULL;
    272  1.1  tnozaki 				init = INIT0(ei);
    273  1.1  tnozaki 				_DIAGASSERT(init != NULL);
    274  1.1  tnozaki 				if (psenc->inuse == init) {
    275  1.1  tnozaki 					init = INIT1(ei);
    276  1.1  tnozaki 				} else if (INIT(psenc->inuse) == init) {
    277  1.1  tnozaki 					if (ESC(init) != ch)
    278  1.1  tnozaki 						break;
    279  1.1  tnozaki 					candidate = init;
    280  1.1  tnozaki 				}
    281  1.1  tnozaki 				if (candidate == NULL) {
    282  1.1  tnozaki 					candidate = find_escape(
    283  1.1  tnozaki 					    SET(psenc->inuse), ch);
    284  1.1  tnozaki 					if (candidate == NULL) {
    285  1.1  tnozaki 						if (init == NULL ||
    286  1.1  tnozaki 						    ESC(init) != ch)
    287  1.1  tnozaki 							break;
    288  1.1  tnozaki 						candidate = init;
    289  1.1  tnozaki 					}
    290  1.1  tnozaki 				}
    291  1.1  tnozaki 				psenc->inuse = candidate;
    292  1.1  tnozaki 				tail = psenc->chlen = 0;
    293  1.1  tnozaki 				continue;
    294  1.1  tnozaki 			}
    295  1.1  tnozaki 		} else if (ch & 0x80) {
    296  1.1  tnozaki 			if (graphic != GR(psenc->inuse))
    297  1.1  tnozaki 				break;
    298  1.1  tnozaki 			ch &= ~0x80;
    299  1.1  tnozaki 		} else {
    300  1.1  tnozaki 			if (graphic != GL(psenc->inuse))
    301  1.1  tnozaki 				break;
    302  1.1  tnozaki 		}
    303  1.1  tnozaki 		_DIAGASSERT(graphic != NULL);
    304  1.1  tnozaki 		range = &ranges[(size_t)graphic->charset];
    305  1.1  tnozaki 		if (range->start > ch || range->end < ch)
    306  1.1  tnozaki 			break;
    307  1.1  tnozaki 		wc <<= 8;
    308  1.1  tnozaki 		wc |= ch;
    309  1.1  tnozaki 		if (graphic->length == (tail - head)) {
    310  1.1  tnozaki 			if (graphic->charset > GB2312)
    311  1.1  tnozaki 				bit |= ESC(psenc->inuse) << 24;
    312  1.1  tnozaki 			wc |= bit;
    313  1.1  tnozaki 			goto done;
    314  1.1  tnozaki 		}
    315  1.1  tnozaki 	}
    316  1.1  tnozaki 	*nresult = (size_t)-1;
    317  1.1  tnozaki 	return EILSEQ;
    318  1.1  tnozaki done:
    319  1.1  tnozaki 	if (tail < psenc->chlen)
    320  1.1  tnozaki 		return EINVAL;
    321  1.1  tnozaki 	*s = s0;
    322  1.1  tnozaki 	if (pwc != NULL)
    323  1.1  tnozaki 		*pwc = wc;
    324  1.1  tnozaki 	psenc->chlen = 0;
    325  1.1  tnozaki 	*nresult = (wc == 0) ? 0 : len;
    326  1.1  tnozaki 
    327  1.1  tnozaki 	return 0;
    328  1.1  tnozaki }
    329  1.1  tnozaki 
    330  1.1  tnozaki static int
    331  1.1  tnozaki _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei,
    332  1.1  tnozaki 	char * __restrict s, size_t n, wchar_t wc,
    333  1.1  tnozaki 	_HZState * __restrict psenc, size_t * __restrict nresult)
    334  1.1  tnozaki {
    335  1.1  tnozaki 	int bit, ch;
    336  1.1  tnozaki 	escape_t *candidate, *init;
    337  1.1  tnozaki 	graphic_t *graphic;
    338  1.1  tnozaki 	size_t len;
    339  1.1  tnozaki 	const range_t *range;
    340  1.1  tnozaki 
    341  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    342  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    343  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    344  1.1  tnozaki 	_DIAGASSERT(nresult != NULL);
    345  1.1  tnozaki 
    346  1.1  tnozaki 	if (psenc->chlen != 0 || psenc->inuse == NULL)
    347  1.1  tnozaki 		return EINVAL;
    348  1.1  tnozaki 	if (wc & 0x80) {
    349  1.1  tnozaki 		bit = 0x80;
    350  1.1  tnozaki 		wc &= ~0x80;
    351  1.1  tnozaki 	} else {
    352  1.1  tnozaki 		bit = 0x0;
    353  1.1  tnozaki 	}
    354  1.1  tnozaki 	if ((uint32_t)wc <= 0x1F) {
    355  1.1  tnozaki 		candidate = INIT0(ei);
    356  1.1  tnozaki 		graphic = (bit == 0)
    357  1.1  tnozaki 		    ? candidate->left : candidate->right;
    358  1.1  tnozaki 		if (graphic == NULL)
    359  1.1  tnozaki 			goto ilseq;
    360  1.1  tnozaki 		range = &ranges[(size_t)CTRL];
    361  1.1  tnozaki 		len = 1;
    362  1.1  tnozaki 	} else if ((uint32_t)wc <= 0x7F) {
    363  1.1  tnozaki 		graphic = ei->ascii;
    364  1.1  tnozaki 		if (graphic == NULL)
    365  1.1  tnozaki 			goto ilseq;
    366  1.1  tnozaki 		candidate = graphic->escape;
    367  1.1  tnozaki 		range = &ranges[(size_t)graphic->charset];
    368  1.1  tnozaki 		len = graphic->length;
    369  1.1  tnozaki 	} else if ((uint32_t)wc <= 0x7F7F) {
    370  1.1  tnozaki 		graphic = ei->gb2312;
    371  1.1  tnozaki 		if (graphic == NULL)
    372  1.1  tnozaki 			goto ilseq;
    373  1.1  tnozaki 		candidate = graphic->escape;
    374  1.1  tnozaki 		range = &ranges[(size_t)graphic->charset];
    375  1.1  tnozaki 		len = graphic->length;
    376  1.1  tnozaki 	} else {
    377  1.1  tnozaki 		ch = (wc >> 24) & 0xFF;
    378  1.1  tnozaki 		candidate = find_escape(E0SET(ei), ch);
    379  1.1  tnozaki 		if (candidate == NULL) {
    380  1.1  tnozaki 			candidate = find_escape(E1SET(ei), ch);
    381  1.1  tnozaki 			if (candidate == NULL)
    382  1.1  tnozaki 				goto ilseq;
    383  1.1  tnozaki 		}
    384  1.1  tnozaki 		wc &= ~0xFF000000;
    385  1.1  tnozaki 		graphic = (bit == 0)
    386  1.1  tnozaki 		    ? candidate->left : candidate->right;
    387  1.1  tnozaki 		if (graphic == NULL)
    388  1.1  tnozaki 			goto ilseq;
    389  1.1  tnozaki 		range = &ranges[(size_t)graphic->charset];
    390  1.1  tnozaki 		len = graphic->length;
    391  1.1  tnozaki 	}
    392  1.1  tnozaki 	if (psenc->inuse != candidate) {
    393  1.1  tnozaki 		init = INIT0(ei);
    394  1.1  tnozaki 		if (SET(psenc->inuse) == SET(candidate)) {
    395  1.1  tnozaki 			if (INIT(psenc->inuse) != init ||
    396  1.1  tnozaki 			    psenc->inuse == init || candidate == init)
    397  1.1  tnozaki 				init = NULL;
    398  1.1  tnozaki 		} else if (candidate == (init = INIT(candidate))) {
    399  1.1  tnozaki 			init = NULL;
    400  1.1  tnozaki 		}
    401  1.1  tnozaki 		if (init != NULL) {
    402  1.1  tnozaki 			if (n < 2)
    403  1.1  tnozaki 				return E2BIG;
    404  1.1  tnozaki 			n -= 2;
    405  1.1  tnozaki 			psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
    406  1.1  tnozaki 			psenc->ch[psenc->chlen++] = ESC(init);
    407  1.1  tnozaki 		}
    408  1.1  tnozaki 		if (n < 2)
    409  1.1  tnozaki 			return E2BIG;
    410  1.1  tnozaki 		n -= 2;
    411  1.1  tnozaki 		psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
    412  1.1  tnozaki 		psenc->ch[psenc->chlen++] = ESC(candidate);
    413  1.1  tnozaki 		psenc->inuse = candidate;
    414  1.1  tnozaki 	}
    415  1.1  tnozaki 	if (n < len)
    416  1.1  tnozaki 		return E2BIG;
    417  1.1  tnozaki 	while (len-- > 0) {
    418  1.1  tnozaki 		ch = (wc >> (len * 8)) & 0xFF;
    419  1.1  tnozaki 		if (range->start > ch || range->end < ch)
    420  1.1  tnozaki 			goto ilseq;
    421  1.1  tnozaki 		psenc->ch[psenc->chlen++] = ch | bit;
    422  1.1  tnozaki 	}
    423  1.1  tnozaki 	memcpy(s, psenc->ch, psenc->chlen);
    424  1.1  tnozaki 	*nresult = psenc->chlen;
    425  1.1  tnozaki 	psenc->chlen = 0;
    426  1.1  tnozaki 
    427  1.1  tnozaki 	return 0;
    428  1.1  tnozaki 
    429  1.1  tnozaki ilseq:
    430  1.1  tnozaki 	*nresult = (size_t)-1;
    431  1.1  tnozaki 	return EILSEQ;
    432  1.1  tnozaki }
    433  1.1  tnozaki 
    434  1.1  tnozaki static __inline int
    435  1.1  tnozaki _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,
    436  1.1  tnozaki 	char * __restrict s, size_t n, _HZState * __restrict psenc,
    437  1.1  tnozaki 	size_t * __restrict nresult)
    438  1.1  tnozaki {
    439  1.1  tnozaki 	escape_t *candidate;
    440  1.1  tnozaki 
    441  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    442  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    443  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    444  1.1  tnozaki 	_DIAGASSERT(nresult != NULL);
    445  1.1  tnozaki 
    446  1.1  tnozaki 	if (psenc->chlen != 0 || psenc->inuse == NULL)
    447  1.1  tnozaki 		return EINVAL;
    448  1.1  tnozaki 	candidate = INIT0(ei);
    449  1.1  tnozaki 	if (psenc->inuse != candidate) {
    450  1.1  tnozaki 		if (n < 2)
    451  1.1  tnozaki 			return E2BIG;
    452  1.1  tnozaki 		n -= 2;
    453  1.1  tnozaki 		psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
    454  1.1  tnozaki 		psenc->ch[psenc->chlen++] = ESC(candidate);
    455  1.1  tnozaki 	}
    456  1.1  tnozaki 	if (n < 1)
    457  1.1  tnozaki 		return E2BIG;
    458  1.1  tnozaki 	if (psenc->chlen > 0)
    459  1.1  tnozaki 		memcpy(s, psenc->ch, psenc->chlen);
    460  1.1  tnozaki 	*nresult = psenc->chlen;
    461  1.1  tnozaki 	_citrus_HZ_init_state(ei, psenc);
    462  1.1  tnozaki 
    463  1.1  tnozaki 	return 0;
    464  1.1  tnozaki }
    465  1.1  tnozaki 
    466  1.1  tnozaki static __inline int
    467  1.1  tnozaki _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,
    468  1.1  tnozaki 	_HZState * __restrict psenc, int * __restrict rstate)
    469  1.1  tnozaki {
    470  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    471  1.1  tnozaki 	_DIAGASSERT(psenc != NULL);
    472  1.1  tnozaki 	_DIAGASSERT(rstate != NULL);
    473  1.1  tnozaki 
    474  1.1  tnozaki 	if (psenc->chlen < 0 || psenc->inuse == NULL)
    475  1.1  tnozaki 		return EINVAL;
    476  1.1  tnozaki 	*rstate = (psenc->chlen == 0)
    477  1.1  tnozaki 	    ? ((psenc->inuse == INIT0(ei))
    478  1.1  tnozaki 	        ? _STDENC_SDGEN_INITIAL
    479  1.1  tnozaki 	        : _STDENC_SDGEN_STABLE)
    480  1.1  tnozaki 	    : ((psenc->ch[0] == ESCAPE_CHAR)
    481  1.1  tnozaki 	        ? _STDENC_SDGEN_INCOMPLETE_SHIFT
    482  1.1  tnozaki 	        : _STDENC_SDGEN_INCOMPLETE_CHAR);
    483  1.1  tnozaki 
    484  1.1  tnozaki 	return 0;
    485  1.1  tnozaki }
    486  1.1  tnozaki 
    487  1.1  tnozaki static __inline int
    488  1.1  tnozaki /*ARGSUSED*/
    489  1.1  tnozaki _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei,
    490  1.1  tnozaki 	_csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
    491  1.1  tnozaki {
    492  1.1  tnozaki 	int bit;
    493  1.1  tnozaki 
    494  1.1  tnozaki 	_DIAGASSERT(csid != NULL);
    495  1.1  tnozaki 	_DIAGASSERT(idx != NULL);
    496  1.1  tnozaki 
    497  1.1  tnozaki 	if (wc & 0x80) {
    498  1.1  tnozaki 		bit = 0x80;
    499  1.1  tnozaki 		wc &= ~0x80;
    500  1.1  tnozaki 	} else {
    501  1.1  tnozaki 		bit = 0x0;
    502  1.1  tnozaki 	}
    503  1.1  tnozaki 	if ((uint32_t)wc <= 0x7F) {
    504  1.1  tnozaki 		*csid = (_csid_t)bit;
    505  1.1  tnozaki 		*idx = (_index_t)wc;
    506  1.1  tnozaki 	} else if ((uint32_t)wc <= 0x7F7F) {
    507  1.1  tnozaki 		*csid = (_csid_t)(bit | 0x8000);
    508  1.1  tnozaki 		*idx = (_index_t)wc;
    509  1.1  tnozaki 	} else {
    510  1.1  tnozaki 		*csid = (_index_t)(wc & ~0x00FFFF7F);
    511  1.1  tnozaki 		*idx = (_csid_t)(wc & 0x00FFFF7F);
    512  1.1  tnozaki 	}
    513  1.1  tnozaki 
    514  1.1  tnozaki 	return 0;
    515  1.1  tnozaki }
    516  1.1  tnozaki 
    517  1.1  tnozaki static __inline int
    518  1.1  tnozaki /*ARGSUSED*/
    519  1.1  tnozaki _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei,
    520  1.1  tnozaki 	wchar_t * __restrict wc, _csid_t csid, _index_t idx)
    521  1.1  tnozaki {
    522  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    523  1.1  tnozaki 	_DIAGASSERT(wc != NULL);
    524  1.1  tnozaki 
    525  1.1  tnozaki 	*wc = (wchar_t)idx;
    526  1.1  tnozaki 	switch (csid) {
    527  1.1  tnozaki 	case 0x80:
    528  1.1  tnozaki 	case 0x8080:
    529  1.1  tnozaki 		*wc |= (wchar_t)0x80;
    530  1.1  tnozaki 	/*FALLTHROUGH*/
    531  1.1  tnozaki 	case 0x0:
    532  1.1  tnozaki 	case 0x8000:
    533  1.1  tnozaki 		break;
    534  1.1  tnozaki 	default:
    535  1.1  tnozaki 		*wc |= (wchar_t)csid;
    536  1.1  tnozaki 	}
    537  1.1  tnozaki 
    538  1.1  tnozaki 	return 0;
    539  1.1  tnozaki }
    540  1.1  tnozaki 
    541  1.1  tnozaki static void
    542  1.1  tnozaki _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei)
    543  1.1  tnozaki {
    544  1.1  tnozaki 	escape_t *escape;
    545  1.1  tnozaki 
    546  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    547  1.1  tnozaki 	while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) {
    548  1.1  tnozaki 		TAILQ_REMOVE(E0SET(ei), escape, entry);
    549  1.1  tnozaki 		free(GL(escape));
    550  1.1  tnozaki 		free(GR(escape));
    551  1.1  tnozaki 		free(escape);
    552  1.1  tnozaki 	}
    553  1.1  tnozaki 	while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) {
    554  1.1  tnozaki 		TAILQ_REMOVE(E1SET(ei), escape, entry);
    555  1.1  tnozaki 		free(GL(escape));
    556  1.1  tnozaki 		free(GR(escape));
    557  1.1  tnozaki 		free(escape);
    558  1.1  tnozaki 	}
    559  1.1  tnozaki }
    560  1.1  tnozaki 
    561  1.1  tnozaki static int
    562  1.1  tnozaki _citrus_HZ_parse_char(void **context, const char *name, const char *s)
    563  1.1  tnozaki {
    564  1.1  tnozaki 	void **p;
    565  1.1  tnozaki 	escape_t *escape;
    566  1.1  tnozaki 
    567  1.1  tnozaki 	_DIAGASSERT(context != NULL && *context != NULL);
    568  1.1  tnozaki 	_DIAGASSERT(name != NULL);
    569  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    570  1.1  tnozaki 
    571  1.1  tnozaki 	p = (void **)*context;
    572  1.1  tnozaki 	escape = (escape_t *)p[0];
    573  1.1  tnozaki 	if (escape->ch != '\0')
    574  1.1  tnozaki 		return EINVAL;
    575  1.1  tnozaki 	escape->ch = *s++;
    576  1.1  tnozaki 	if (escape->ch == ESCAPE_CHAR || *s != '\0')
    577  1.1  tnozaki 		return EINVAL;
    578  1.1  tnozaki 
    579  1.1  tnozaki 	return 0;
    580  1.1  tnozaki }
    581  1.1  tnozaki 
    582  1.1  tnozaki static int
    583  1.1  tnozaki _citrus_HZ_parse_graphic(void **context, const char *name, const char *s)
    584  1.1  tnozaki {
    585  1.1  tnozaki 	void **p;
    586  1.1  tnozaki 	_HZEncodingInfo *ei;
    587  1.1  tnozaki 	escape_t *escape;
    588  1.1  tnozaki 	graphic_t *graphic;
    589  1.1  tnozaki 
    590  1.1  tnozaki 	_DIAGASSERT(context != NULL && *context != NULL);
    591  1.1  tnozaki 	_DIAGASSERT(name != NULL);
    592  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    593  1.1  tnozaki 
    594  1.1  tnozaki 	p = (void **)*context;
    595  1.1  tnozaki 	escape = (escape_t *)p[0];
    596  1.1  tnozaki 	ei = (_HZEncodingInfo *)p[1];
    597  1.1  tnozaki 	graphic = malloc(sizeof(*graphic));
    598  1.1  tnozaki 	if (graphic == NULL)
    599  1.1  tnozaki 		return ENOMEM;
    600  1.1  tnozaki 	memset(graphic, 0, sizeof(*graphic));
    601  1.1  tnozaki 	if (strcmp("GL", name) == 0) {
    602  1.1  tnozaki 		if (GL(escape) != NULL)
    603  1.1  tnozaki 			goto release;
    604  1.1  tnozaki 		GL(escape) = graphic;
    605  1.1  tnozaki 	} else if (strcmp("GR", name) == 0) {
    606  1.1  tnozaki 		if (GR(escape) != NULL)
    607  1.1  tnozaki 			goto release;
    608  1.1  tnozaki 		GR(escape) = graphic;
    609  1.1  tnozaki 	} else {
    610  1.1  tnozaki release:
    611  1.1  tnozaki 		free(graphic);
    612  1.1  tnozaki 		return EINVAL;
    613  1.1  tnozaki 	}
    614  1.1  tnozaki 	graphic->escape = escape;
    615  1.1  tnozaki 	if (_bcs_strncasecmp("ASCII", s, 5) == 0) {
    616  1.1  tnozaki 		if (s[5] != '\0')
    617  1.1  tnozaki 			return EINVAL;
    618  1.1  tnozaki 		graphic->charset = ASCII;
    619  1.1  tnozaki 		graphic->length = 1;
    620  1.1  tnozaki 		ei->ascii = graphic;
    621  1.1  tnozaki 		return 0;
    622  1.1  tnozaki 	} else if (_bcs_strncasecmp("GB2312", s, 6) == 0) {
    623  1.1  tnozaki 		if (s[6] != '\0')
    624  1.1  tnozaki 			return EINVAL;
    625  1.1  tnozaki 		graphic->charset = GB2312;
    626  1.1  tnozaki 		graphic->length = 2;
    627  1.1  tnozaki 		ei->gb2312 = graphic;
    628  1.1  tnozaki 		return 0;
    629  1.1  tnozaki 	} else if (strncmp("94*", s, 3) == 0) {
    630  1.1  tnozaki 		graphic->charset = CS94;
    631  1.1  tnozaki 	} else if (strncmp("96*", s, 3) == 0) {
    632  1.1  tnozaki 		graphic->charset = CS96;
    633  1.1  tnozaki 	} else {
    634  1.1  tnozaki 		return EINVAL;
    635  1.1  tnozaki 	}
    636  1.1  tnozaki 	s += 3;
    637  1.1  tnozaki 	switch(*s) {
    638  1.1  tnozaki 	case '1': case '2': case '3':
    639  1.1  tnozaki 		graphic->length = (size_t)(*s - '0');
    640  1.1  tnozaki 		if (*++s == '\0')
    641  1.1  tnozaki 			break;
    642  1.1  tnozaki 	/*FALLTHROUGH*/
    643  1.1  tnozaki 	default:
    644  1.1  tnozaki 		return EINVAL;
    645  1.1  tnozaki 	}
    646  1.1  tnozaki 	return 0;
    647  1.1  tnozaki }
    648  1.1  tnozaki 
    649  1.1  tnozaki static const _citrus_prop_hint_t escape_hints[] = {
    650  1.1  tnozaki _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char),
    651  1.1  tnozaki _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic),
    652  1.1  tnozaki _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic),
    653  1.1  tnozaki _CITRUS_PROP_HINT_END
    654  1.1  tnozaki };
    655  1.1  tnozaki 
    656  1.1  tnozaki static int
    657  1.1  tnozaki _citrus_HZ_parse_escape(void **context, const char *name, const char *s)
    658  1.1  tnozaki {
    659  1.1  tnozaki 	_HZEncodingInfo *ei;
    660  1.1  tnozaki 	escape_t *escape;
    661  1.1  tnozaki 	void *p[2];
    662  1.1  tnozaki 
    663  1.1  tnozaki 	_DIAGASSERT(context != NULL);
    664  1.1  tnozaki 	_DIAGASSERT(name != NULL);
    665  1.1  tnozaki 	_DIAGASSERT(s != NULL);
    666  1.1  tnozaki 
    667  1.1  tnozaki 	ei = (_HZEncodingInfo *)*context;
    668  1.1  tnozaki 	escape = malloc(sizeof(*escape));
    669  1.1  tnozaki 	if (escape == NULL)
    670  1.1  tnozaki 		return EINVAL;
    671  1.1  tnozaki 	memset(escape, 0, sizeof(*escape));
    672  1.1  tnozaki 	if (strcmp("0", name) == 0) {
    673  1.1  tnozaki 		escape->set = E0SET(ei);
    674  1.1  tnozaki 		TAILQ_INSERT_TAIL(E0SET(ei), escape, entry);
    675  1.1  tnozaki 	} else if (strcmp("1", name) == 0) {
    676  1.1  tnozaki 		escape->set = E1SET(ei);
    677  1.1  tnozaki 		TAILQ_INSERT_TAIL(E1SET(ei), escape, entry);
    678  1.1  tnozaki 	} else {
    679  1.1  tnozaki 		free(escape);
    680  1.1  tnozaki 		return EINVAL;
    681  1.1  tnozaki 	}
    682  1.1  tnozaki 	p[0] = (void *)escape;
    683  1.1  tnozaki 	p[1] = (void *)ei;
    684  1.1  tnozaki 	return _citrus_prop_parse_variable(
    685  1.1  tnozaki 	    escape_hints, (void *)&p[0], s, strlen(s));
    686  1.1  tnozaki }
    687  1.1  tnozaki 
    688  1.1  tnozaki static const _citrus_prop_hint_t root_hints[] = {
    689  1.1  tnozaki _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape),
    690  1.1  tnozaki _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape),
    691  1.1  tnozaki _CITRUS_PROP_HINT_END
    692  1.1  tnozaki };
    693  1.1  tnozaki 
    694  1.1  tnozaki static int
    695  1.1  tnozaki _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,
    696  1.1  tnozaki 	const void * __restrict var, size_t lenvar)
    697  1.1  tnozaki {
    698  1.1  tnozaki 	int errnum;
    699  1.1  tnozaki 
    700  1.1  tnozaki 	_DIAGASSERT(ei != NULL);
    701  1.1  tnozaki 
    702  1.1  tnozaki 	memset(ei, 0, sizeof(*ei));
    703  1.1  tnozaki 	TAILQ_INIT(E0SET(ei));
    704  1.1  tnozaki 	TAILQ_INIT(E1SET(ei));
    705  1.1  tnozaki 	errnum = _citrus_prop_parse_variable(
    706  1.1  tnozaki 	    root_hints, (void *)ei, var, lenvar);
    707  1.1  tnozaki 	if (errnum != 0)
    708  1.1  tnozaki 		_citrus_HZ_encoding_module_uninit(ei);
    709  1.1  tnozaki 	return errnum;
    710  1.1  tnozaki }
    711  1.1  tnozaki 
    712  1.1  tnozaki /* ----------------------------------------------------------------------
    713  1.1  tnozaki  * public interface for ctype
    714  1.1  tnozaki  */
    715  1.1  tnozaki 
    716  1.1  tnozaki _CITRUS_CTYPE_DECLS(HZ);
    717  1.1  tnozaki _CITRUS_CTYPE_DEF_OPS(HZ);
    718  1.1  tnozaki 
    719  1.1  tnozaki #include "citrus_ctype_template.h"
    720  1.1  tnozaki 
    721  1.1  tnozaki /* ----------------------------------------------------------------------
    722  1.1  tnozaki  * public interface for stdenc
    723  1.1  tnozaki  */
    724  1.1  tnozaki 
    725  1.1  tnozaki _CITRUS_STDENC_DECLS(HZ);
    726  1.1  tnozaki _CITRUS_STDENC_DEF_OPS(HZ);
    727  1.1  tnozaki 
    728  1.1  tnozaki #include "citrus_stdenc_template.h"
    729