xref: /dragonfly/lib/i18n_module/HZ/citrus_hz.c (revision 71ea2de5)
1bdcf3f2bSJohn Marino /* $FreeBSD: head/lib/libiconv_modules/HZ/citrus_hz.c 281550 2015-04-15 09:09:20Z tijl $ */
20d5acd74SJohn Marino /* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */
30d5acd74SJohn Marino 
40d5acd74SJohn Marino /*-
50d5acd74SJohn Marino  * Copyright (c)2004, 2006 Citrus Project,
60d5acd74SJohn Marino  * All rights reserved.
70d5acd74SJohn Marino  *
80d5acd74SJohn Marino  * Redistribution and use in source and binary forms, with or without
90d5acd74SJohn Marino  * modification, are permitted provided that the following conditions
100d5acd74SJohn Marino  * are met:
110d5acd74SJohn Marino  * 1. Redistributions of source code must retain the above copyright
120d5acd74SJohn Marino  *    notice, this list of conditions and the following disclaimer.
130d5acd74SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
140d5acd74SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
150d5acd74SJohn Marino  *    documentation and/or other materials provided with the distribution.
160d5acd74SJohn Marino  *
170d5acd74SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180d5acd74SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190d5acd74SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200d5acd74SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
210d5acd74SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220d5acd74SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230d5acd74SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240d5acd74SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250d5acd74SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260d5acd74SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270d5acd74SJohn Marino  * SUCH DAMAGE.
280d5acd74SJohn Marino  *
290d5acd74SJohn Marino  */
300d5acd74SJohn Marino 
310d5acd74SJohn Marino #include <sys/cdefs.h>
320d5acd74SJohn Marino #include <sys/queue.h>
330d5acd74SJohn Marino #include <sys/types.h>
340d5acd74SJohn Marino 
350d5acd74SJohn Marino #include <assert.h>
360d5acd74SJohn Marino #include <errno.h>
370d5acd74SJohn Marino #include <limits.h>
380d5acd74SJohn Marino #include <stddef.h>
390d5acd74SJohn Marino #include <stdint.h>
400d5acd74SJohn Marino #include <stdlib.h>
410d5acd74SJohn Marino #include <string.h>
420d5acd74SJohn Marino #include <wchar.h>
430d5acd74SJohn Marino 
440d5acd74SJohn Marino #include "citrus_namespace.h"
450d5acd74SJohn Marino #include "citrus_types.h"
460d5acd74SJohn Marino #include "citrus_bcs.h"
470d5acd74SJohn Marino #include "citrus_module.h"
480d5acd74SJohn Marino #include "citrus_stdenc.h"
490d5acd74SJohn Marino 
500d5acd74SJohn Marino #include "citrus_hz.h"
510d5acd74SJohn Marino #include "citrus_prop.h"
520d5acd74SJohn Marino 
530d5acd74SJohn Marino /*
540d5acd74SJohn Marino  * wchar_t mapping:
550d5acd74SJohn Marino  *
560d5acd74SJohn Marino  * CTRL/ASCII	00000000 00000000 00000000 gxxxxxxx
570d5acd74SJohn Marino  * GB2312	00000000 00000000 0xxxxxxx gxxxxxxx
580d5acd74SJohn Marino  * 94/96*n (~M)	0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
590d5acd74SJohn Marino  */
600d5acd74SJohn Marino 
610d5acd74SJohn Marino #define ESCAPE_CHAR	'~'
620d5acd74SJohn Marino 
630d5acd74SJohn Marino typedef enum {
640d5acd74SJohn Marino 	CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4
650d5acd74SJohn Marino } charset_t;
660d5acd74SJohn Marino 
670d5acd74SJohn Marino typedef struct {
680d5acd74SJohn Marino 	int	 start;
690db70a6aSJohn Marino 	int	 end;
700d5acd74SJohn Marino 	int	 width;
710d5acd74SJohn Marino } range_t;
720d5acd74SJohn Marino 
730d5acd74SJohn Marino static const range_t ranges[] = {
740d5acd74SJohn Marino #define RANGE(start, end) { start, end, (end - start) + 1 }
750d5acd74SJohn Marino /* CTRL   */ RANGE(0x00, 0x1F),
760d5acd74SJohn Marino /* ASCII  */ RANGE(0x20, 0x7F),
770d5acd74SJohn Marino /* GB2312 */ RANGE(0x21, 0x7E),
780d5acd74SJohn Marino /* CS94   */ RANGE(0x21, 0x7E),
790d5acd74SJohn Marino /* CS96   */ RANGE(0x20, 0x7F),
800d5acd74SJohn Marino #undef RANGE
810d5acd74SJohn Marino };
820d5acd74SJohn Marino 
830d5acd74SJohn Marino typedef struct escape_t escape_t;
840d5acd74SJohn Marino typedef struct {
850d5acd74SJohn Marino 	charset_t	 charset;
860d5acd74SJohn Marino 	escape_t	*escape;
870d5acd74SJohn Marino 	ssize_t		 length;
880d5acd74SJohn Marino #define ROWCOL_MAX	3
890d5acd74SJohn Marino } graphic_t;
900d5acd74SJohn Marino 
910d5acd74SJohn Marino typedef TAILQ_HEAD(escape_list, escape_t) escape_list;
920d5acd74SJohn Marino struct escape_t {
930d5acd74SJohn Marino 	TAILQ_ENTRY(escape_t)	 entry;
940d5acd74SJohn Marino 	escape_list		*set;
950d5acd74SJohn Marino 	graphic_t		*left;
960d5acd74SJohn Marino 	graphic_t		*right;
970d5acd74SJohn Marino 	int			 ch;
980d5acd74SJohn Marino };
990d5acd74SJohn Marino 
1000d5acd74SJohn Marino #define GL(escape)	((escape)->left)
1010d5acd74SJohn Marino #define GR(escape)	((escape)->right)
1020d5acd74SJohn Marino #define SET(escape)	((escape)->set)
1030d5acd74SJohn Marino #define ESC(escape)	((escape)->ch)
1040d5acd74SJohn Marino #define INIT(escape)	(TAILQ_FIRST(SET(escape)))
1050d5acd74SJohn Marino 
1060d5acd74SJohn Marino static __inline escape_t *
find_escape(escape_list * set,int ch)1070d5acd74SJohn Marino find_escape(escape_list *set, int ch)
1080d5acd74SJohn Marino {
1090d5acd74SJohn Marino 	escape_t *escape;
1100d5acd74SJohn Marino 
1110d5acd74SJohn Marino 	TAILQ_FOREACH(escape, set, entry) {
1120d5acd74SJohn Marino 		if (ESC(escape) == ch)
1130d5acd74SJohn Marino 			break;
1140d5acd74SJohn Marino 	}
1150d5acd74SJohn Marino 
1160d5acd74SJohn Marino 	return (escape);
1170d5acd74SJohn Marino }
1180d5acd74SJohn Marino 
1190d5acd74SJohn Marino typedef struct {
1200d5acd74SJohn Marino 	escape_list	 e0;
1210d5acd74SJohn Marino 	escape_list	 e1;
1220d5acd74SJohn Marino 	graphic_t	*ascii;
1230d5acd74SJohn Marino 	graphic_t	*gb2312;
1240d5acd74SJohn Marino } _HZEncodingInfo;
1250d5acd74SJohn Marino 
1260d5acd74SJohn Marino #define E0SET(ei)	(&(ei)->e0)
1270d5acd74SJohn Marino #define E1SET(ei)	(&(ei)->e1)
1280d5acd74SJohn Marino #define INIT0(ei)	(TAILQ_FIRST(E0SET(ei)))
1290d5acd74SJohn Marino #define INIT1(ei)	(TAILQ_FIRST(E1SET(ei)))
1300d5acd74SJohn Marino 
1310d5acd74SJohn Marino typedef struct {
1320d5acd74SJohn Marino 	escape_t	*inuse;
1330d5acd74SJohn Marino 	int		 chlen;
1340d5acd74SJohn Marino 	char		 ch[ROWCOL_MAX];
1350d5acd74SJohn Marino } _HZState;
1360d5acd74SJohn Marino 
1370d5acd74SJohn Marino #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
1380d5acd74SJohn Marino #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
1390d5acd74SJohn Marino 
1400d5acd74SJohn Marino #define _FUNCNAME(m)			_citrus_HZ_##m
1410d5acd74SJohn Marino #define _ENCODING_INFO			_HZEncodingInfo
1420d5acd74SJohn Marino #define _ENCODING_STATE			_HZState
1430d5acd74SJohn Marino #define _ENCODING_MB_CUR_MAX(_ei_)	MB_LEN_MAX
1440d5acd74SJohn Marino #define _ENCODING_IS_STATE_DEPENDENT		1
1450d5acd74SJohn Marino #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	((_ps_)->inuse == NULL)
1460d5acd74SJohn Marino 
1470d5acd74SJohn Marino static __inline void
_citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,_HZState * __restrict psenc)1480d5acd74SJohn Marino _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,
1490d5acd74SJohn Marino     _HZState * __restrict psenc)
1500d5acd74SJohn Marino {
1510d5acd74SJohn Marino 
1520d5acd74SJohn Marino 	psenc->chlen = 0;
1530d5acd74SJohn Marino 	psenc->inuse = INIT0(ei);
1540d5acd74SJohn Marino }
1550d5acd74SJohn Marino 
156*71ea2de5SJohn Marino #if 0
1570d5acd74SJohn Marino static __inline void
1580d5acd74SJohn Marino /*ARGSUSED*/
1590d5acd74SJohn Marino _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei __unused,
1600d5acd74SJohn Marino     void *__restrict pspriv, const _HZState * __restrict psenc)
1610d5acd74SJohn Marino {
1620d5acd74SJohn Marino 
1630d5acd74SJohn Marino 	memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
1640d5acd74SJohn Marino }
1650d5acd74SJohn Marino 
1660d5acd74SJohn Marino static __inline void
1670d5acd74SJohn Marino /*ARGSUSED*/
1680d5acd74SJohn Marino _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei __unused,
1690d5acd74SJohn Marino     _HZState * __restrict psenc, const void * __restrict pspriv)
1700d5acd74SJohn Marino {
1710d5acd74SJohn Marino 
1720d5acd74SJohn Marino 	memcpy((void *)psenc, pspriv, sizeof(*psenc));
1730d5acd74SJohn Marino }
174*71ea2de5SJohn Marino #endif
1750d5acd74SJohn Marino 
1760d5acd74SJohn Marino static int
_citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,wchar_t * __restrict pwc,char ** __restrict s,size_t n,_HZState * __restrict psenc,size_t * __restrict nresult)1770d5acd74SJohn Marino _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
1780db70a6aSJohn Marino     wchar_t * __restrict pwc, char ** __restrict s, size_t n,
1790d5acd74SJohn Marino     _HZState * __restrict psenc, size_t * __restrict nresult)
1800d5acd74SJohn Marino {
1810d5acd74SJohn Marino 	escape_t *candidate, *init;
1820d5acd74SJohn Marino 	graphic_t *graphic;
1830d5acd74SJohn Marino 	const range_t *range;
1840db70a6aSJohn Marino 	char *s0;
1850d5acd74SJohn Marino 	wchar_t wc;
1860d5acd74SJohn Marino 	int bit, ch, head, len, tail;
1870d5acd74SJohn Marino 
1880d5acd74SJohn Marino 	if (*s == NULL) {
1890d5acd74SJohn Marino 		_citrus_HZ_init_state(ei, psenc);
1900d5acd74SJohn Marino 		*nresult = 1;
1910d5acd74SJohn Marino 		return (0);
1920d5acd74SJohn Marino 	}
1930d5acd74SJohn Marino 	s0 = *s;
1940d5acd74SJohn Marino 	if (psenc->chlen < 0 || psenc->inuse == NULL)
1950d5acd74SJohn Marino 		return (EINVAL);
1960d5acd74SJohn Marino 
1970d5acd74SJohn Marino 	wc = (wchar_t)0;
1980d5acd74SJohn Marino 	bit = head = tail = 0;
1990d5acd74SJohn Marino 	graphic = NULL;
2000d5acd74SJohn Marino 	for (len = 0; len <= MB_LEN_MAX;) {
2010d5acd74SJohn Marino 		if (psenc->chlen == tail) {
2020d5acd74SJohn Marino 			if (n-- < 1) {
2030d5acd74SJohn Marino 				*s = s0;
2040d5acd74SJohn Marino 				*nresult = (size_t)-2;
2050d5acd74SJohn Marino 				return (0);
2060d5acd74SJohn Marino 			}
2070d5acd74SJohn Marino 			psenc->ch[psenc->chlen++] = *s0++;
2080d5acd74SJohn Marino 			++len;
2090d5acd74SJohn Marino 		}
2100d5acd74SJohn Marino 		ch = (unsigned char)psenc->ch[tail++];
2110d5acd74SJohn Marino 		if (tail == 1) {
2120d5acd74SJohn Marino 			if ((ch & ~0x80) <= 0x1F) {
2130d5acd74SJohn Marino 				if (psenc->inuse != INIT0(ei))
2140d5acd74SJohn Marino 					break;
2150d5acd74SJohn Marino 				wc = (wchar_t)ch;
2160d5acd74SJohn Marino 				goto done;
2170d5acd74SJohn Marino 			}
2180d5acd74SJohn Marino 			if (ch & 0x80) {
2190d5acd74SJohn Marino 				graphic = GR(psenc->inuse);
2200d5acd74SJohn Marino 				bit = 0x80;
2210d5acd74SJohn Marino 				ch &= ~0x80;
2220d5acd74SJohn Marino 			} else {
2230d5acd74SJohn Marino 				graphic = GL(psenc->inuse);
2240d5acd74SJohn Marino 				if (ch == ESCAPE_CHAR)
2250d5acd74SJohn Marino 					continue;
2260d5acd74SJohn Marino 				bit = 0x0;
2270d5acd74SJohn Marino 			}
2280d5acd74SJohn Marino 			if (graphic == NULL)
2290d5acd74SJohn Marino 				break;
2300d5acd74SJohn Marino 		} else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) {
2310d5acd74SJohn Marino 			if (tail < psenc->chlen)
2320d5acd74SJohn Marino 				return (EINVAL);
2330d5acd74SJohn Marino 			if (ch == ESCAPE_CHAR) {
2340d5acd74SJohn Marino 				++head;
2350d5acd74SJohn Marino 			} else if (ch == '\n') {
2360d5acd74SJohn Marino 				if (psenc->inuse != INIT0(ei))
2370d5acd74SJohn Marino 					break;
2380d5acd74SJohn Marino 				tail = psenc->chlen = 0;
2390d5acd74SJohn Marino 				continue;
2400d5acd74SJohn Marino 			} else {
2410d5acd74SJohn Marino 				candidate = NULL;
2420d5acd74SJohn Marino 				init = INIT0(ei);
2430d5acd74SJohn Marino 				if (psenc->inuse == init) {
2440d5acd74SJohn Marino 					init = INIT1(ei);
2450d5acd74SJohn Marino 				} else if (INIT(psenc->inuse) == init) {
2460d5acd74SJohn Marino 					if (ESC(init) != ch)
2470d5acd74SJohn Marino 						break;
2480d5acd74SJohn Marino 					candidate = init;
2490d5acd74SJohn Marino 				}
2500d5acd74SJohn Marino 				if (candidate == NULL) {
2510d5acd74SJohn Marino 					candidate = find_escape(
2520d5acd74SJohn Marino 					    SET(psenc->inuse), ch);
2530d5acd74SJohn Marino 					if (candidate == NULL) {
2540d5acd74SJohn Marino 						if (init == NULL ||
2550d5acd74SJohn Marino 						    ESC(init) != ch)
2560d5acd74SJohn Marino 							break;
2570d5acd74SJohn Marino 						candidate = init;
2580d5acd74SJohn Marino 					}
2590d5acd74SJohn Marino 				}
2600d5acd74SJohn Marino 				psenc->inuse = candidate;
2610d5acd74SJohn Marino 				tail = psenc->chlen = 0;
2620d5acd74SJohn Marino 				continue;
2630d5acd74SJohn Marino 			}
2640d5acd74SJohn Marino 		} else if (ch & 0x80) {
2650d5acd74SJohn Marino 			if (graphic != GR(psenc->inuse))
2660d5acd74SJohn Marino 				break;
2670d5acd74SJohn Marino 			ch &= ~0x80;
2680d5acd74SJohn Marino 		} else {
2690d5acd74SJohn Marino 			if (graphic != GL(psenc->inuse))
2700d5acd74SJohn Marino 				break;
2710d5acd74SJohn Marino 		}
2720d5acd74SJohn Marino 		range = &ranges[(size_t)graphic->charset];
2730d5acd74SJohn Marino 		if (range->start > ch || range->end < ch)
2740d5acd74SJohn Marino 			break;
2750d5acd74SJohn Marino 		wc <<= 8;
2760d5acd74SJohn Marino 		wc |= ch;
2770d5acd74SJohn Marino 		if (graphic->length == (tail - head)) {
2780d5acd74SJohn Marino 			if (graphic->charset > GB2312)
2790d5acd74SJohn Marino 				bit |= ESC(psenc->inuse) << 24;
2800d5acd74SJohn Marino 			wc |= bit;
2810d5acd74SJohn Marino 			goto done;
2820d5acd74SJohn Marino 		}
2830d5acd74SJohn Marino 	}
2840d5acd74SJohn Marino 	*nresult = (size_t)-1;
2850d5acd74SJohn Marino 	return (EILSEQ);
2860d5acd74SJohn Marino done:
2870d5acd74SJohn Marino 	if (tail < psenc->chlen)
2880d5acd74SJohn Marino 		return (EINVAL);
2890d5acd74SJohn Marino 	*s = s0;
2900d5acd74SJohn Marino 	if (pwc != NULL)
2910d5acd74SJohn Marino 		*pwc = wc;
2920d5acd74SJohn Marino 	psenc->chlen = 0;
2930d5acd74SJohn Marino 	*nresult = (wc == 0) ? 0 : len;
2940d5acd74SJohn Marino 
2950d5acd74SJohn Marino 	return (0);
2960d5acd74SJohn Marino }
2970d5acd74SJohn Marino 
2980d5acd74SJohn Marino static int
_citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei,char * __restrict s,size_t n,wchar_t wc,_HZState * __restrict psenc,size_t * __restrict nresult)2990d5acd74SJohn Marino _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei,
3000d5acd74SJohn Marino     char * __restrict s, size_t n, wchar_t wc,
3010d5acd74SJohn Marino     _HZState * __restrict psenc, size_t * __restrict nresult)
3020d5acd74SJohn Marino {
3030d5acd74SJohn Marino 	escape_t *candidate, *init;
3040d5acd74SJohn Marino 	graphic_t *graphic;
3050d5acd74SJohn Marino 	const range_t *range;
3060d5acd74SJohn Marino 	size_t len;
3070d5acd74SJohn Marino 	int bit, ch;
3080d5acd74SJohn Marino 
3090d5acd74SJohn Marino 	if (psenc->chlen != 0 || psenc->inuse == NULL)
3100d5acd74SJohn Marino 		return (EINVAL);
3110d5acd74SJohn Marino 	if (wc & 0x80) {
3120d5acd74SJohn Marino 		bit = 0x80;
3130d5acd74SJohn Marino 		wc &= ~0x80;
3140d5acd74SJohn Marino 	} else {
3150d5acd74SJohn Marino 		bit = 0x0;
3160d5acd74SJohn Marino 	}
3170d5acd74SJohn Marino 	if ((uint32_t)wc <= 0x1F) {
3180d5acd74SJohn Marino 		candidate = INIT0(ei);
3190d5acd74SJohn Marino 		graphic = (bit == 0) ? candidate->left : candidate->right;
3200d5acd74SJohn Marino 		if (graphic == NULL)
3210d5acd74SJohn Marino 			goto ilseq;
3220d5acd74SJohn Marino 		range = &ranges[(size_t)CTRL];
3230d5acd74SJohn Marino 		len = 1;
3240d5acd74SJohn Marino 	} else if ((uint32_t)wc <= 0x7F) {
3250d5acd74SJohn Marino 		graphic = ei->ascii;
3260d5acd74SJohn Marino 		if (graphic == NULL)
3270d5acd74SJohn Marino 			goto ilseq;
3280d5acd74SJohn Marino 		candidate = graphic->escape;
3290d5acd74SJohn Marino 		range = &ranges[(size_t)graphic->charset];
3300d5acd74SJohn Marino 		len = graphic->length;
3310d5acd74SJohn Marino 	} else if ((uint32_t)wc <= 0x7F7F) {
3320d5acd74SJohn Marino 		graphic = ei->gb2312;
3330d5acd74SJohn Marino 		if (graphic == NULL)
3340d5acd74SJohn Marino 			goto ilseq;
3350d5acd74SJohn Marino 		candidate = graphic->escape;
3360d5acd74SJohn Marino 		range = &ranges[(size_t)graphic->charset];
3370d5acd74SJohn Marino 		len = graphic->length;
3380d5acd74SJohn Marino 	} else {
3390d5acd74SJohn Marino 		ch = (wc >> 24) & 0xFF;
3400d5acd74SJohn Marino 		candidate = find_escape(E0SET(ei), ch);
3410d5acd74SJohn Marino 		if (candidate == NULL) {
3420d5acd74SJohn Marino 			candidate = find_escape(E1SET(ei), ch);
3430d5acd74SJohn Marino 			if (candidate == NULL)
3440d5acd74SJohn Marino 				goto ilseq;
3450d5acd74SJohn Marino 		}
3460d5acd74SJohn Marino 		wc &= ~0xFF000000;
3470d5acd74SJohn Marino 		graphic = (bit == 0) ? candidate->left : candidate->right;
3480d5acd74SJohn Marino 		if (graphic == NULL)
3490d5acd74SJohn Marino 			goto ilseq;
3500d5acd74SJohn Marino 		range = &ranges[(size_t)graphic->charset];
3510d5acd74SJohn Marino 		len = graphic->length;
3520d5acd74SJohn Marino 	}
3530d5acd74SJohn Marino 	if (psenc->inuse != candidate) {
3540d5acd74SJohn Marino 		init = INIT0(ei);
3550d5acd74SJohn Marino 		if (SET(psenc->inuse) == SET(candidate)) {
3560d5acd74SJohn Marino 			if (INIT(psenc->inuse) != init ||
3570d5acd74SJohn Marino 			    psenc->inuse == init || candidate == init)
3580d5acd74SJohn Marino 				init = NULL;
3590d5acd74SJohn Marino 		} else if (candidate == (init = INIT(candidate))) {
3600d5acd74SJohn Marino 			init = NULL;
3610d5acd74SJohn Marino 		}
3620d5acd74SJohn Marino 		if (init != NULL) {
3630d5acd74SJohn Marino 			if (n < 2)
3640d5acd74SJohn Marino 				return (E2BIG);
3650d5acd74SJohn Marino 			n -= 2;
3660d5acd74SJohn Marino 			psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
3670d5acd74SJohn Marino 			psenc->ch[psenc->chlen++] = ESC(init);
3680d5acd74SJohn Marino 		}
3690d5acd74SJohn Marino 		if (n < 2)
3700d5acd74SJohn Marino 			return (E2BIG);
3710d5acd74SJohn Marino 		n -= 2;
3720d5acd74SJohn Marino 		psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
3730d5acd74SJohn Marino 		psenc->ch[psenc->chlen++] = ESC(candidate);
3740d5acd74SJohn Marino 		psenc->inuse = candidate;
3750d5acd74SJohn Marino 	}
3760d5acd74SJohn Marino 	if (n < len)
3770d5acd74SJohn Marino 		return (E2BIG);
3780d5acd74SJohn Marino 	while (len-- > 0) {
3790d5acd74SJohn Marino 		ch = (wc >> (len * 8)) & 0xFF;
3800d5acd74SJohn Marino 		if (range->start > ch || range->end < ch)
3810d5acd74SJohn Marino 			goto ilseq;
3820d5acd74SJohn Marino 		psenc->ch[psenc->chlen++] = ch | bit;
3830d5acd74SJohn Marino 	}
3840d5acd74SJohn Marino 	memcpy(s, psenc->ch, psenc->chlen);
3850d5acd74SJohn Marino 	*nresult = psenc->chlen;
3860d5acd74SJohn Marino 	psenc->chlen = 0;
3870d5acd74SJohn Marino 
3880d5acd74SJohn Marino 	return (0);
3890d5acd74SJohn Marino 
3900d5acd74SJohn Marino ilseq:
3910d5acd74SJohn Marino 	*nresult = (size_t)-1;
3920d5acd74SJohn Marino 	return (EILSEQ);
3930d5acd74SJohn Marino }
3940d5acd74SJohn Marino 
3950d5acd74SJohn Marino static __inline int
_citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,char * __restrict s,size_t n,_HZState * __restrict psenc,size_t * __restrict nresult)3960d5acd74SJohn Marino _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,
3970d5acd74SJohn Marino     char * __restrict s, size_t n, _HZState * __restrict psenc,
3980d5acd74SJohn Marino     size_t * __restrict nresult)
3990d5acd74SJohn Marino {
4000d5acd74SJohn Marino 	escape_t *candidate;
4010d5acd74SJohn Marino 
4020d5acd74SJohn Marino 	if (psenc->chlen != 0 || psenc->inuse == NULL)
4030d5acd74SJohn Marino 		return (EINVAL);
4040d5acd74SJohn Marino 	candidate = INIT0(ei);
4050d5acd74SJohn Marino 	if (psenc->inuse != candidate) {
4060d5acd74SJohn Marino 		if (n < 2)
4070d5acd74SJohn Marino 			return (E2BIG);
4080d5acd74SJohn Marino 		n -= 2;
4090d5acd74SJohn Marino 		psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
4100d5acd74SJohn Marino 		psenc->ch[psenc->chlen++] = ESC(candidate);
4110d5acd74SJohn Marino 	}
4120d5acd74SJohn Marino 	if (n < 1)
4130d5acd74SJohn Marino 		return (E2BIG);
4140d5acd74SJohn Marino 	if (psenc->chlen > 0)
4150d5acd74SJohn Marino 		memcpy(s, psenc->ch, psenc->chlen);
4160d5acd74SJohn Marino 	*nresult = psenc->chlen;
4170d5acd74SJohn Marino 	_citrus_HZ_init_state(ei, psenc);
4180d5acd74SJohn Marino 
4190d5acd74SJohn Marino 	return (0);
4200d5acd74SJohn Marino }
4210d5acd74SJohn Marino 
4220d5acd74SJohn Marino static __inline int
_citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,_HZState * __restrict psenc,int * __restrict rstate)4230d5acd74SJohn Marino _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,
4240d5acd74SJohn Marino     _HZState * __restrict psenc, int * __restrict rstate)
4250d5acd74SJohn Marino {
4260d5acd74SJohn Marino 
4270d5acd74SJohn Marino 	if (psenc->chlen < 0 || psenc->inuse == NULL)
4280d5acd74SJohn Marino 		return (EINVAL);
4290d5acd74SJohn Marino 	*rstate = (psenc->chlen == 0)
4300d5acd74SJohn Marino 	    ? ((psenc->inuse == INIT0(ei))
4310d5acd74SJohn Marino 	        ? _STDENC_SDGEN_INITIAL
4320d5acd74SJohn Marino 	        : _STDENC_SDGEN_STABLE)
4330d5acd74SJohn Marino 	    : ((psenc->ch[0] == ESCAPE_CHAR)
4340d5acd74SJohn Marino 	        ? _STDENC_SDGEN_INCOMPLETE_SHIFT
4350d5acd74SJohn Marino 	        : _STDENC_SDGEN_INCOMPLETE_CHAR);
4360d5acd74SJohn Marino 
4370d5acd74SJohn Marino 	return (0);
4380d5acd74SJohn Marino }
4390d5acd74SJohn Marino 
4400d5acd74SJohn Marino static __inline int
4410d5acd74SJohn Marino /*ARGSUSED*/
_citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)4420d5acd74SJohn Marino _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused,
4430d5acd74SJohn Marino     _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
4440d5acd74SJohn Marino {
4450d5acd74SJohn Marino 	int bit;
4460d5acd74SJohn Marino 
4470d5acd74SJohn Marino 	if (wc & 0x80) {
4480d5acd74SJohn Marino 		bit = 0x80;
4490d5acd74SJohn Marino 		wc &= ~0x80;
4500d5acd74SJohn Marino 	} else
4510d5acd74SJohn Marino 		bit = 0x0;
4520d5acd74SJohn Marino 	if ((uint32_t)wc <= 0x7F) {
4530d5acd74SJohn Marino 		*csid = (_csid_t)bit;
4540d5acd74SJohn Marino 		*idx = (_index_t)wc;
4550d5acd74SJohn Marino 	} else if ((uint32_t)wc <= 0x7F7F) {
4560d5acd74SJohn Marino 		*csid = (_csid_t)(bit | 0x8000);
4570d5acd74SJohn Marino 		*idx = (_index_t)wc;
4580d5acd74SJohn Marino 	} else {
4590d5acd74SJohn Marino 		*csid = (_index_t)(wc & ~0x00FFFF7F);
4600d5acd74SJohn Marino 		*idx = (_csid_t)(wc & 0x00FFFF7F);
4610d5acd74SJohn Marino 	}
4620d5acd74SJohn Marino 
4630d5acd74SJohn Marino 	return (0);
4640d5acd74SJohn Marino }
4650d5acd74SJohn Marino 
4660d5acd74SJohn Marino static __inline int
4670d5acd74SJohn Marino /*ARGSUSED*/
_citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused,wchar_t * __restrict wc,_csid_t csid,_index_t idx)4680d5acd74SJohn Marino _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused,
4690d5acd74SJohn Marino     wchar_t * __restrict wc, _csid_t csid, _index_t idx)
4700d5acd74SJohn Marino {
4710d5acd74SJohn Marino 
4720d5acd74SJohn Marino 	*wc = (wchar_t)idx;
4730d5acd74SJohn Marino 	switch (csid) {
4740d5acd74SJohn Marino 	case 0x80:
4750d5acd74SJohn Marino 	case 0x8080:
4760d5acd74SJohn Marino 		*wc |= (wchar_t)0x80;
4770d5acd74SJohn Marino 		/*FALLTHROUGH*/
4780d5acd74SJohn Marino 	case 0x0:
4790d5acd74SJohn Marino 	case 0x8000:
4800d5acd74SJohn Marino 		break;
4810d5acd74SJohn Marino 	default:
4820d5acd74SJohn Marino 		*wc |= (wchar_t)csid;
4830d5acd74SJohn Marino 	}
4840d5acd74SJohn Marino 
4850d5acd74SJohn Marino 	return (0);
4860d5acd74SJohn Marino }
4870d5acd74SJohn Marino 
4880d5acd74SJohn Marino static void
_citrus_HZ_encoding_module_uninit(_HZEncodingInfo * ei)4890d5acd74SJohn Marino _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei)
4900d5acd74SJohn Marino {
4910d5acd74SJohn Marino 	escape_t *escape;
4920d5acd74SJohn Marino 
4930d5acd74SJohn Marino 	while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) {
4940d5acd74SJohn Marino 		TAILQ_REMOVE(E0SET(ei), escape, entry);
4950d5acd74SJohn Marino 		free(GL(escape));
4960d5acd74SJohn Marino 		free(GR(escape));
4970d5acd74SJohn Marino 		free(escape);
4980d5acd74SJohn Marino 	}
4990d5acd74SJohn Marino 	while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) {
5000d5acd74SJohn Marino 		TAILQ_REMOVE(E1SET(ei), escape, entry);
5010d5acd74SJohn Marino 		free(GL(escape));
5020d5acd74SJohn Marino 		free(GR(escape));
5030d5acd74SJohn Marino 		free(escape);
5040d5acd74SJohn Marino 	}
5050d5acd74SJohn Marino }
5060d5acd74SJohn Marino 
5070d5acd74SJohn Marino static int
_citrus_HZ_parse_char(void * context,const char * name __unused,const char * s)508bdcf3f2bSJohn Marino _citrus_HZ_parse_char(void *context, const char *name __unused, const char *s)
5090d5acd74SJohn Marino {
5100d5acd74SJohn Marino 	escape_t *escape;
5110d5acd74SJohn Marino 	void **p;
5120d5acd74SJohn Marino 
513bdcf3f2bSJohn Marino 	p = (void **)context;
5140d5acd74SJohn Marino 	escape = (escape_t *)p[0];
5150d5acd74SJohn Marino 	if (escape->ch != '\0')
5160d5acd74SJohn Marino 		return (EINVAL);
5170d5acd74SJohn Marino 	escape->ch = *s++;
5180d5acd74SJohn Marino 	if (escape->ch == ESCAPE_CHAR || *s != '\0')
5190d5acd74SJohn Marino 		return (EINVAL);
5200d5acd74SJohn Marino 
5210d5acd74SJohn Marino 	return (0);
5220d5acd74SJohn Marino }
5230d5acd74SJohn Marino 
5240d5acd74SJohn Marino static int
_citrus_HZ_parse_graphic(void * context,const char * name,const char * s)525bdcf3f2bSJohn Marino _citrus_HZ_parse_graphic(void *context, const char *name, const char *s)
5260d5acd74SJohn Marino {
5270d5acd74SJohn Marino 	_HZEncodingInfo *ei;
5280d5acd74SJohn Marino 	escape_t *escape;
5290d5acd74SJohn Marino 	graphic_t *graphic;
5300d5acd74SJohn Marino 	void **p;
5310d5acd74SJohn Marino 
532bdcf3f2bSJohn Marino 	p = (void **)context;
5330d5acd74SJohn Marino 	escape = (escape_t *)p[0];
5340d5acd74SJohn Marino 	ei = (_HZEncodingInfo *)p[1];
5350db70a6aSJohn Marino 	graphic = calloc(1, sizeof(*graphic));
5360d5acd74SJohn Marino 	if (graphic == NULL)
5370d5acd74SJohn Marino 		return (ENOMEM);
5380d5acd74SJohn Marino 	if (strcmp("GL", name) == 0) {
5390d5acd74SJohn Marino 		if (GL(escape) != NULL)
5400d5acd74SJohn Marino 			goto release;
5410d5acd74SJohn Marino 		GL(escape) = graphic;
5420d5acd74SJohn Marino 	} else if (strcmp("GR", name) == 0) {
5430d5acd74SJohn Marino 		if (GR(escape) != NULL)
5440d5acd74SJohn Marino 			goto release;
5450d5acd74SJohn Marino 		GR(escape) = graphic;
5460d5acd74SJohn Marino 	} else {
5470d5acd74SJohn Marino release:
5480d5acd74SJohn Marino 		free(graphic);
5490d5acd74SJohn Marino 		return (EINVAL);
5500d5acd74SJohn Marino 	}
5510d5acd74SJohn Marino 	graphic->escape = escape;
5520d5acd74SJohn Marino 	if (_bcs_strncasecmp("ASCII", s, 5) == 0) {
5530d5acd74SJohn Marino 		if (s[5] != '\0')
5540d5acd74SJohn Marino 			return (EINVAL);
5550d5acd74SJohn Marino 		graphic->charset = ASCII;
5560d5acd74SJohn Marino 		graphic->length = 1;
5570d5acd74SJohn Marino 		ei->ascii = graphic;
5580d5acd74SJohn Marino 		return (0);
5590d5acd74SJohn Marino 	} else if (_bcs_strncasecmp("GB2312", s, 6) == 0) {
5600d5acd74SJohn Marino 		if (s[6] != '\0')
5610d5acd74SJohn Marino 			return (EINVAL);
5620d5acd74SJohn Marino 		graphic->charset = GB2312;
5630d5acd74SJohn Marino 		graphic->length = 2;
5640d5acd74SJohn Marino 		ei->gb2312 = graphic;
5650d5acd74SJohn Marino 		return (0);
5660d5acd74SJohn Marino 	} else if (strncmp("94*", s, 3) == 0)
5670d5acd74SJohn Marino 		graphic->charset = CS94;
5680d5acd74SJohn Marino 	else if (strncmp("96*", s, 3) == 0)
5690d5acd74SJohn Marino 		graphic->charset = CS96;
5700d5acd74SJohn Marino 	else
5710d5acd74SJohn Marino 		return (EINVAL);
5720d5acd74SJohn Marino 	s += 3;
5730d5acd74SJohn Marino 	switch(*s) {
5740d5acd74SJohn Marino 	case '1': case '2': case '3':
5750d5acd74SJohn Marino 		graphic->length = (size_t)(*s - '0');
5760d5acd74SJohn Marino 		if (*++s == '\0')
5770d5acd74SJohn Marino 			break;
5780d5acd74SJohn Marino 	/*FALLTHROUGH*/
5790d5acd74SJohn Marino 	default:
5800d5acd74SJohn Marino 		return (EINVAL);
5810d5acd74SJohn Marino 	}
5820d5acd74SJohn Marino 	return (0);
5830d5acd74SJohn Marino }
5840d5acd74SJohn Marino 
5850d5acd74SJohn Marino static const _citrus_prop_hint_t escape_hints[] = {
5860d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char),
5870d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic),
5880d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic),
5890d5acd74SJohn Marino _CITRUS_PROP_HINT_END
5900d5acd74SJohn Marino };
5910d5acd74SJohn Marino 
5920d5acd74SJohn Marino static int
_citrus_HZ_parse_escape(void * context,const char * name,const char * s)593bdcf3f2bSJohn Marino _citrus_HZ_parse_escape(void *context, const char *name, const char *s)
5940d5acd74SJohn Marino {
5950d5acd74SJohn Marino 	_HZEncodingInfo *ei;
5960d5acd74SJohn Marino 	escape_t *escape;
5970d5acd74SJohn Marino 	void *p[2];
5980d5acd74SJohn Marino 
599bdcf3f2bSJohn Marino 	ei = (_HZEncodingInfo *)context;
6000db70a6aSJohn Marino 	escape = calloc(1, sizeof(*escape));
6010d5acd74SJohn Marino 	if (escape == NULL)
6020d5acd74SJohn Marino 		return (EINVAL);
6030d5acd74SJohn Marino 	if (strcmp("0", name) == 0) {
6040d5acd74SJohn Marino 		escape->set = E0SET(ei);
6050d5acd74SJohn Marino 		TAILQ_INSERT_TAIL(E0SET(ei), escape, entry);
6060d5acd74SJohn Marino 	} else if (strcmp("1", name) == 0) {
6070d5acd74SJohn Marino 		escape->set = E1SET(ei);
6080d5acd74SJohn Marino 		TAILQ_INSERT_TAIL(E1SET(ei), escape, entry);
6090d5acd74SJohn Marino 	} else {
6100d5acd74SJohn Marino 		free(escape);
6110d5acd74SJohn Marino 		return (EINVAL);
6120d5acd74SJohn Marino 	}
6130d5acd74SJohn Marino 	p[0] = (void *)escape;
6140d5acd74SJohn Marino 	p[1] = (void *)ei;
6150d5acd74SJohn Marino 	return (_citrus_prop_parse_variable(
6160d5acd74SJohn Marino 	    escape_hints, (void *)&p[0], s, strlen(s)));
6170d5acd74SJohn Marino }
6180d5acd74SJohn Marino 
6190d5acd74SJohn Marino static const _citrus_prop_hint_t root_hints[] = {
6200d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape),
6210d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape),
6220d5acd74SJohn Marino _CITRUS_PROP_HINT_END
6230d5acd74SJohn Marino };
6240d5acd74SJohn Marino 
6250d5acd74SJohn Marino static int
_citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)6260d5acd74SJohn Marino _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,
6270d5acd74SJohn Marino     const void * __restrict var, size_t lenvar)
6280d5acd74SJohn Marino {
6290d5acd74SJohn Marino 	int errnum;
6300d5acd74SJohn Marino 
6310d5acd74SJohn Marino 	memset(ei, 0, sizeof(*ei));
6320d5acd74SJohn Marino 	TAILQ_INIT(E0SET(ei));
6330d5acd74SJohn Marino 	TAILQ_INIT(E1SET(ei));
6340d5acd74SJohn Marino 	errnum = _citrus_prop_parse_variable(
6350d5acd74SJohn Marino 	    root_hints, (void *)ei, var, lenvar);
6360d5acd74SJohn Marino 	if (errnum != 0)
6370d5acd74SJohn Marino 		_citrus_HZ_encoding_module_uninit(ei);
6380d5acd74SJohn Marino 	return (errnum);
6390d5acd74SJohn Marino }
6400d5acd74SJohn Marino 
6410d5acd74SJohn Marino /* ----------------------------------------------------------------------
6420d5acd74SJohn Marino  * public interface for stdenc
6430d5acd74SJohn Marino  */
6440d5acd74SJohn Marino 
6450d5acd74SJohn Marino _CITRUS_STDENC_DECLS(HZ);
6460d5acd74SJohn Marino _CITRUS_STDENC_DEF_OPS(HZ);
6470d5acd74SJohn Marino 
6480d5acd74SJohn Marino #include "citrus_stdenc_template.h"
649