xref: /netbsd/lib/libc/citrus/modules/citrus_zw.c (revision abd1934e)
1*abd1934eSrillig /* $NetBSD: citrus_zw.c,v 1.6 2022/04/19 20:32:14 rillig Exp $ */
28033a5b0Stnozaki 
38033a5b0Stnozaki /*-
48033a5b0Stnozaki  * Copyright (c)2004, 2006 Citrus Project,
58033a5b0Stnozaki  * All rights reserved.
68033a5b0Stnozaki  *
78033a5b0Stnozaki  * Redistribution and use in source and binary forms, with or without
88033a5b0Stnozaki  * modification, are permitted provided that the following conditions
98033a5b0Stnozaki  * are met:
108033a5b0Stnozaki  * 1. Redistributions of source code must retain the above copyright
118033a5b0Stnozaki  *    notice, this list of conditions and the following disclaimer.
128033a5b0Stnozaki  * 2. Redistributions in binary form must reproduce the above copyright
138033a5b0Stnozaki  *    notice, this list of conditions and the following disclaimer in the
148033a5b0Stnozaki  *    documentation and/or other materials provided with the distribution.
158033a5b0Stnozaki  *
168033a5b0Stnozaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178033a5b0Stnozaki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188033a5b0Stnozaki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198033a5b0Stnozaki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208033a5b0Stnozaki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218033a5b0Stnozaki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228033a5b0Stnozaki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238033a5b0Stnozaki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248033a5b0Stnozaki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258033a5b0Stnozaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268033a5b0Stnozaki  * SUCH DAMAGE.
278033a5b0Stnozaki  *
288033a5b0Stnozaki  */
298033a5b0Stnozaki 
308033a5b0Stnozaki #include <sys/cdefs.h>
318033a5b0Stnozaki #if defined(LIB_SCCS) && !defined(lint)
32*abd1934eSrillig __RCSID("$NetBSD: citrus_zw.c,v 1.6 2022/04/19 20:32:14 rillig Exp $");
338033a5b0Stnozaki #endif /* LIB_SCCS and not lint */
348033a5b0Stnozaki 
358033a5b0Stnozaki #include <sys/types.h>
368033a5b0Stnozaki #include <assert.h>
378033a5b0Stnozaki #include <errno.h>
388033a5b0Stnozaki #include <string.h>
398033a5b0Stnozaki #include <stdio.h>
408033a5b0Stnozaki #include <stdint.h>
418033a5b0Stnozaki #include <stdlib.h>
428033a5b0Stnozaki #include <stddef.h>
438033a5b0Stnozaki #include <wchar.h>
448033a5b0Stnozaki #include <limits.h>
458033a5b0Stnozaki 
468033a5b0Stnozaki #include "citrus_namespace.h"
478033a5b0Stnozaki #include "citrus_types.h"
488033a5b0Stnozaki #include "citrus_module.h"
498033a5b0Stnozaki #include "citrus_ctype.h"
508033a5b0Stnozaki #include "citrus_stdenc.h"
518033a5b0Stnozaki #include "citrus_zw.h"
528033a5b0Stnozaki 
538033a5b0Stnozaki /* ----------------------------------------------------------------------
548033a5b0Stnozaki  * private stuffs used by templates
558033a5b0Stnozaki  */
568033a5b0Stnozaki 
578033a5b0Stnozaki typedef struct {
588033a5b0Stnozaki 	int dummy;
598033a5b0Stnozaki } _ZWEncodingInfo;
608033a5b0Stnozaki 
618033a5b0Stnozaki typedef enum {
628033a5b0Stnozaki 	NONE, AMBIGIOUS, ASCII, GB2312
638033a5b0Stnozaki } _ZWCharset;
648033a5b0Stnozaki 
658033a5b0Stnozaki typedef struct {
668033a5b0Stnozaki 	int		chlen;
678033a5b0Stnozaki 	char		ch[4];
688033a5b0Stnozaki 	_ZWCharset	charset;
698033a5b0Stnozaki } _ZWState;
708033a5b0Stnozaki 
718033a5b0Stnozaki typedef struct {
728033a5b0Stnozaki 	_ZWEncodingInfo	ei;
738033a5b0Stnozaki 	struct {
748033a5b0Stnozaki 		/* for future multi-locale facility */
758033a5b0Stnozaki 		_ZWState	s_mblen;
768033a5b0Stnozaki 		_ZWState	s_mbrlen;
778033a5b0Stnozaki 		_ZWState	s_mbrtowc;
788033a5b0Stnozaki 		_ZWState	s_mbtowc;
798033a5b0Stnozaki 		_ZWState	s_mbsrtowcs;
80bf2f4b3eSjoerg 		_ZWState	s_mbsnrtowcs;
818033a5b0Stnozaki 		_ZWState	s_wcrtomb;
828033a5b0Stnozaki 		_ZWState	s_wcsrtombs;
83bf2f4b3eSjoerg 		_ZWState	s_wcsnrtombs;
848033a5b0Stnozaki 		_ZWState	s_wctomb;
858033a5b0Stnozaki 	} states;
868033a5b0Stnozaki } _ZWCTypeInfo;
878033a5b0Stnozaki 
888033a5b0Stnozaki #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
898033a5b0Stnozaki #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
908033a5b0Stnozaki 
918033a5b0Stnozaki #define _FUNCNAME(m)			_citrus_ZW_##m
928033a5b0Stnozaki #define _ENCODING_INFO			_ZWEncodingInfo
938033a5b0Stnozaki #define _CTYPE_INFO			_ZWCTypeInfo
948033a5b0Stnozaki #define _ENCODING_STATE			_ZWState
958033a5b0Stnozaki #define _ENCODING_MB_CUR_MAX(_ei_)	MB_LEN_MAX
968033a5b0Stnozaki #define _ENCODING_IS_STATE_DEPENDENT		1
978033a5b0Stnozaki #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	((_ps_)->charset != NONE)
988033a5b0Stnozaki 
998033a5b0Stnozaki static __inline void
1008033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_init_state(_ZWEncodingInfo * __restrict ei,_ZWState * __restrict psenc)1018033a5b0Stnozaki _citrus_ZW_init_state(_ZWEncodingInfo * __restrict ei,
1028033a5b0Stnozaki 	_ZWState * __restrict psenc)
1038033a5b0Stnozaki {
1048033a5b0Stnozaki 	/* ei my be unused */
1058033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
1068033a5b0Stnozaki 
1078033a5b0Stnozaki 	psenc->chlen = 0;
1088033a5b0Stnozaki 	psenc->charset = NONE;
1098033a5b0Stnozaki }
1108033a5b0Stnozaki 
1118033a5b0Stnozaki static __inline void
1128033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_pack_state(_ZWEncodingInfo * __restrict ei,void * __restrict pspriv,const _ZWState * __restrict psenc)1138033a5b0Stnozaki _citrus_ZW_pack_state(_ZWEncodingInfo * __restrict ei,
1148033a5b0Stnozaki 	void *__restrict pspriv, const _ZWState * __restrict psenc)
1158033a5b0Stnozaki {
1168033a5b0Stnozaki 	/* ei may be unused */
1178033a5b0Stnozaki 	_DIAGASSERT(pspriv != NULL);
1188033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
1198033a5b0Stnozaki 
1208033a5b0Stnozaki 	memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
1218033a5b0Stnozaki }
1228033a5b0Stnozaki 
1238033a5b0Stnozaki static __inline void
1248033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_unpack_state(_ZWEncodingInfo * __restrict ei,_ZWState * __restrict psenc,const void * __restrict pspriv)1258033a5b0Stnozaki _citrus_ZW_unpack_state(_ZWEncodingInfo * __restrict ei,
1268033a5b0Stnozaki 	_ZWState * __restrict psenc, const void * __restrict pspriv)
1278033a5b0Stnozaki {
1288033a5b0Stnozaki 	/* ei may be unused */
1298033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
1308033a5b0Stnozaki 	_DIAGASSERT(pspriv != NULL);
1318033a5b0Stnozaki 
1328033a5b0Stnozaki 	memcpy((void *)psenc, pspriv, sizeof(*psenc));
1338033a5b0Stnozaki }
1348033a5b0Stnozaki 
1358033a5b0Stnozaki static int
_citrus_ZW_mbrtowc_priv(_ZWEncodingInfo * __restrict ei,wchar_t * __restrict pwc,const char ** __restrict s,size_t n,_ZWState * __restrict psenc,size_t * __restrict nresult)1368033a5b0Stnozaki _citrus_ZW_mbrtowc_priv(_ZWEncodingInfo * __restrict ei,
1378033a5b0Stnozaki 	wchar_t * __restrict pwc, const char **__restrict s, size_t n,
1388033a5b0Stnozaki 	_ZWState * __restrict psenc, size_t * __restrict nresult)
1398033a5b0Stnozaki {
1408033a5b0Stnozaki 	const char *s0;
1413fb79e82Stnozaki 	int ch, len;
1428033a5b0Stnozaki 	wchar_t	 wc;
1438033a5b0Stnozaki 
1448033a5b0Stnozaki 	/* ei may be unused */
1458033a5b0Stnozaki 	/* pwc may be null */
1468033a5b0Stnozaki 	_DIAGASSERT(s != NULL);
1478033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
1488033a5b0Stnozaki 	_DIAGASSERT(nresult != NULL);
1498033a5b0Stnozaki 
1508033a5b0Stnozaki 	if (*s == NULL) {
1518033a5b0Stnozaki 		_citrus_ZW_init_state(ei, psenc);
1528033a5b0Stnozaki 		*nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
1538033a5b0Stnozaki 		return 0;
1548033a5b0Stnozaki 	}
1558033a5b0Stnozaki 	s0 = *s;
1563fb79e82Stnozaki 	len = 0;
1578033a5b0Stnozaki 
1588033a5b0Stnozaki #define	STORE				\
1598033a5b0Stnozaki do {					\
1608033a5b0Stnozaki 	if (n-- < 1) {			\
1618033a5b0Stnozaki 		*nresult = (size_t)-2;	\
1628033a5b0Stnozaki 		*s = s0;		\
1638033a5b0Stnozaki 		return 0;		\
1648033a5b0Stnozaki 	}				\
1658033a5b0Stnozaki 	ch = (unsigned char)*s0++;	\
1663fb79e82Stnozaki 	if (len++ > MB_LEN_MAX || ch > 0x7F)\
1678033a5b0Stnozaki 		goto ilseq;		\
1688033a5b0Stnozaki 	psenc->ch[psenc->chlen++] = ch;	\
169*abd1934eSrillig } while (0)
1708033a5b0Stnozaki 
1718033a5b0Stnozaki loop:
1728033a5b0Stnozaki 	switch (psenc->charset) {
1738033a5b0Stnozaki 	case ASCII:
1748033a5b0Stnozaki 		switch (psenc->chlen) {
1758033a5b0Stnozaki 		case 0:
1768033a5b0Stnozaki 			STORE;
1778033a5b0Stnozaki 			switch (psenc->ch[0]) {
1788033a5b0Stnozaki 			case '\0': case '\n':
1798033a5b0Stnozaki 				psenc->charset = NONE;
1808033a5b0Stnozaki 			}
1818033a5b0Stnozaki 		/*FALLTHROUGH*/
1828033a5b0Stnozaki 		case 1:
1838033a5b0Stnozaki 			break;
1848033a5b0Stnozaki 		default:
1858033a5b0Stnozaki 			return EINVAL;
1868033a5b0Stnozaki 		}
1878033a5b0Stnozaki 		ch = (unsigned char)psenc->ch[0];
1888033a5b0Stnozaki 		if (ch > 0x7F)
1898033a5b0Stnozaki 			goto ilseq;
1908033a5b0Stnozaki 		wc = (wchar_t)ch;
1918033a5b0Stnozaki 		psenc->chlen = 0;
1928033a5b0Stnozaki 		break;
1938033a5b0Stnozaki 	case NONE:
1948033a5b0Stnozaki 		if (psenc->chlen != 0)
1958033a5b0Stnozaki 			return EINVAL;
1968033a5b0Stnozaki 		STORE;
1978033a5b0Stnozaki 		ch = (unsigned char)psenc->ch[0];
1988033a5b0Stnozaki 		if (ch != 'z') {
1998033a5b0Stnozaki 			if (ch != '\n' && ch != '\0')
2008033a5b0Stnozaki 				psenc->charset = ASCII;
2018033a5b0Stnozaki 			wc = (wchar_t)ch;
2028033a5b0Stnozaki 			psenc->chlen = 0;
2038033a5b0Stnozaki 			break;
2048033a5b0Stnozaki 		}
2058033a5b0Stnozaki 		psenc->charset = AMBIGIOUS;
2068033a5b0Stnozaki 		psenc->chlen = 0;
2078033a5b0Stnozaki 	/* FALLTHROUGH */
2088033a5b0Stnozaki 	case AMBIGIOUS:
2098033a5b0Stnozaki 		if (psenc->chlen != 0)
2108033a5b0Stnozaki 			return EINVAL;
2118033a5b0Stnozaki 		STORE;
2128033a5b0Stnozaki 		if (psenc->ch[0] != 'W') {
2138033a5b0Stnozaki 			psenc->charset = ASCII;
2148033a5b0Stnozaki 			wc = L'z';
2158033a5b0Stnozaki 			break;
2168033a5b0Stnozaki 		}
2178033a5b0Stnozaki 		psenc->charset = GB2312;
2188033a5b0Stnozaki 		psenc->chlen = 0;
2198033a5b0Stnozaki 	/* FALLTHROUGH */
2208033a5b0Stnozaki 	case GB2312:
2218033a5b0Stnozaki 		switch (psenc->chlen) {
2228033a5b0Stnozaki 		case 0:
2238033a5b0Stnozaki 			STORE;
2248033a5b0Stnozaki 			ch = (unsigned char)psenc->ch[0];
2258033a5b0Stnozaki 			if (ch == '\0') {
2268033a5b0Stnozaki 				psenc->charset = NONE;
2278033a5b0Stnozaki 				wc = (wchar_t)ch;
2288033a5b0Stnozaki 				psenc->chlen = 0;
2298033a5b0Stnozaki 				break;
2308033a5b0Stnozaki 			} else if (ch == '\n') {
2318033a5b0Stnozaki 				psenc->charset = NONE;
2328033a5b0Stnozaki 				psenc->chlen = 0;
2338033a5b0Stnozaki 				goto loop;
2348033a5b0Stnozaki 			}
2358033a5b0Stnozaki 		/*FALLTHROUGH*/
2368033a5b0Stnozaki 		case 1:
2378033a5b0Stnozaki 			STORE;
2388033a5b0Stnozaki 			if (psenc->ch[0] == ' ') {
2398033a5b0Stnozaki 				ch = (unsigned char)psenc->ch[1];
2408033a5b0Stnozaki 				wc = (wchar_t)ch;
2418033a5b0Stnozaki 				psenc->chlen = 0;
2428033a5b0Stnozaki 				break;
2438033a5b0Stnozaki 			} else if (psenc->ch[0] == '#') {
2448033a5b0Stnozaki 				ch = (unsigned char)psenc->ch[1];
2458033a5b0Stnozaki 				if (ch == '\n') {
2468033a5b0Stnozaki 					psenc->charset = NONE;
2478033a5b0Stnozaki 					wc = (wchar_t)ch;
2488033a5b0Stnozaki 					psenc->chlen = 0;
2498033a5b0Stnozaki 					break;
2508033a5b0Stnozaki 				} else if (ch == ' ') {
2518033a5b0Stnozaki 					wc = (wchar_t)ch;
2528033a5b0Stnozaki 					psenc->chlen = 0;
2538033a5b0Stnozaki 					break;
2548033a5b0Stnozaki 				}
2558033a5b0Stnozaki 			}
2568033a5b0Stnozaki 			ch = (unsigned char)psenc->ch[0];
2578033a5b0Stnozaki 			if (ch < 0x21 || ch > 0x7E)
2588033a5b0Stnozaki 				goto ilseq;
2598033a5b0Stnozaki 			wc = (wchar_t)(ch << 8);
2608033a5b0Stnozaki 			ch = (unsigned char)psenc->ch[1];
2618033a5b0Stnozaki 			if (ch < 0x21 || ch > 0x7E) {
2628033a5b0Stnozaki ilseq:
2638033a5b0Stnozaki 				*nresult = (size_t)-1;
2648033a5b0Stnozaki 				return EILSEQ;
2658033a5b0Stnozaki 			}
2668033a5b0Stnozaki 			wc |= (wchar_t)ch;
2678033a5b0Stnozaki 			psenc->chlen = 0;
2688033a5b0Stnozaki 			break;
2698033a5b0Stnozaki 		default:
2708033a5b0Stnozaki 			return EINVAL;
2718033a5b0Stnozaki 		}
2728033a5b0Stnozaki 		break;
2738033a5b0Stnozaki 	default:
2748033a5b0Stnozaki 		return EINVAL;
2758033a5b0Stnozaki 	}
2768033a5b0Stnozaki 	if (pwc != NULL)
2778033a5b0Stnozaki 		*pwc = wc;
2788033a5b0Stnozaki 
2793fb79e82Stnozaki 	*nresult = (size_t)(wc == 0 ? 0 : len);
2808033a5b0Stnozaki 	*s = s0;
2818033a5b0Stnozaki 
2828033a5b0Stnozaki 	return 0;
2838033a5b0Stnozaki }
2848033a5b0Stnozaki 
2858033a5b0Stnozaki static int
2868033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_wcrtomb_priv(_ZWEncodingInfo * __restrict ei,char * __restrict s,size_t n,wchar_t wc,_ZWState * __restrict psenc,size_t * __restrict nresult)2878033a5b0Stnozaki _citrus_ZW_wcrtomb_priv(_ZWEncodingInfo * __restrict ei,
2888033a5b0Stnozaki 	char *__restrict s, size_t n, wchar_t wc,
2898033a5b0Stnozaki 	_ZWState * __restrict psenc, size_t * __restrict nresult)
2908033a5b0Stnozaki {
2918033a5b0Stnozaki 	int ch;
2928033a5b0Stnozaki 
2938033a5b0Stnozaki 	/* ei may be null */
2948033a5b0Stnozaki 	_DIAGASSERT(s != NULL);
2958033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
2968033a5b0Stnozaki 	_DIAGASSERT(nresult != NULL);
2978033a5b0Stnozaki 
2988033a5b0Stnozaki 	if (psenc->chlen != 0)
2998033a5b0Stnozaki 		return EINVAL;
3008033a5b0Stnozaki 	if ((uint32_t)wc <= 0x7F) {
3018033a5b0Stnozaki 		ch = (unsigned char)wc;
3028033a5b0Stnozaki 		switch (psenc->charset) {
3038033a5b0Stnozaki 		case NONE:
3048033a5b0Stnozaki 			if (ch == '\0' || ch == '\n') {
3058033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = ch;
3068033a5b0Stnozaki 			} else {
3078033a5b0Stnozaki 				if (n < 4)
3088033a5b0Stnozaki 					return E2BIG;
3098033a5b0Stnozaki 				n -= 4;
3108033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = 'z';
3118033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = 'W';
3128033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = ' ';
3138033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = ch;
3148033a5b0Stnozaki 				psenc->charset = GB2312;
3158033a5b0Stnozaki 			}
3168033a5b0Stnozaki 			break;
3178033a5b0Stnozaki 		case GB2312:
3188033a5b0Stnozaki 			if (n < 2)
3198033a5b0Stnozaki 				return E2BIG;
3208033a5b0Stnozaki 			n -= 2;
3218033a5b0Stnozaki 			if (ch == '\0') {
3228033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = '\n';
3238033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = '\0';
3248033a5b0Stnozaki 				psenc->charset = NONE;
3258033a5b0Stnozaki 			} else if (ch == '\n') {
3268033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = '#';
3278033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = '\n';
3288033a5b0Stnozaki 				psenc->charset = NONE;
3298033a5b0Stnozaki 			} else {
3308033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = ' ';
3318033a5b0Stnozaki 				psenc->ch[psenc->chlen++] = ch;
3328033a5b0Stnozaki 			}
3338033a5b0Stnozaki 			break;
3348033a5b0Stnozaki 		default:
3358033a5b0Stnozaki 			return EINVAL;
3368033a5b0Stnozaki 		}
3378033a5b0Stnozaki 	} else if ((uint32_t)wc <= 0x7E7E) {
3388033a5b0Stnozaki 		switch (psenc->charset) {
3398033a5b0Stnozaki 		case NONE:
3408033a5b0Stnozaki 			if (n < 2)
3418033a5b0Stnozaki 				return E2BIG;
3428033a5b0Stnozaki 			n -= 2;
3438033a5b0Stnozaki 			psenc->ch[psenc->chlen++] = 'z';
3448033a5b0Stnozaki 			psenc->ch[psenc->chlen++] = 'W';
3458033a5b0Stnozaki 			psenc->charset = GB2312;
3468033a5b0Stnozaki 		/* FALLTHROUGH*/
3478033a5b0Stnozaki 		case GB2312:
3488033a5b0Stnozaki 			if (n < 2)
3498033a5b0Stnozaki 				return E2BIG;
3508033a5b0Stnozaki 			n -= 2;
3518033a5b0Stnozaki 			ch = (wc >> 8) & 0xFF;
3528033a5b0Stnozaki 			if (ch < 0x21 || ch > 0x7E)
3538033a5b0Stnozaki 				goto ilseq;
3548033a5b0Stnozaki 			psenc->ch[psenc->chlen++] = ch;
3558033a5b0Stnozaki 			ch = wc & 0xFF;
3568033a5b0Stnozaki 			if (ch < 0x21 || ch > 0x7E)
3578033a5b0Stnozaki 				goto ilseq;
3588033a5b0Stnozaki 			psenc->ch[psenc->chlen++] = ch;
3598033a5b0Stnozaki 			break;
3608033a5b0Stnozaki 		default:
3618033a5b0Stnozaki 			return EINVAL;
3628033a5b0Stnozaki 		}
3638033a5b0Stnozaki 	} else {
3648033a5b0Stnozaki ilseq:
3658033a5b0Stnozaki 		*nresult = (size_t)-1;
3668033a5b0Stnozaki 		return EILSEQ;
3678033a5b0Stnozaki 	}
3688033a5b0Stnozaki 	memcpy(s, psenc->ch, psenc->chlen);
3698033a5b0Stnozaki 	*nresult = psenc->chlen;
3708033a5b0Stnozaki 	psenc->chlen = 0;
3718033a5b0Stnozaki 
3728033a5b0Stnozaki 	return 0;
3738033a5b0Stnozaki }
3748033a5b0Stnozaki 
3758033a5b0Stnozaki static int
3768033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_put_state_reset(_ZWEncodingInfo * __restrict ei,char * __restrict s,size_t n,_ZWState * __restrict psenc,size_t * __restrict nresult)3778033a5b0Stnozaki _citrus_ZW_put_state_reset(_ZWEncodingInfo * __restrict ei,
3788033a5b0Stnozaki 	char * __restrict s, size_t n,
3798033a5b0Stnozaki 	_ZWState * __restrict psenc, size_t * __restrict nresult)
3808033a5b0Stnozaki {
3818033a5b0Stnozaki 	/* ei may be unused */
3828033a5b0Stnozaki 	_DIAGASSERT(s != NULL);
3838033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
3848033a5b0Stnozaki 	_DIAGASSERT(nresult != NULL);
3858033a5b0Stnozaki 
3868033a5b0Stnozaki 	if (psenc->chlen != 0)
3878033a5b0Stnozaki 		return EINVAL;
3888033a5b0Stnozaki 	switch (psenc->charset) {
3898033a5b0Stnozaki 	case GB2312:
3908033a5b0Stnozaki 		if (n-- < 1)
3918033a5b0Stnozaki 			return E2BIG;
3928033a5b0Stnozaki 		psenc->ch[psenc->chlen++] = '\n';
3938033a5b0Stnozaki 		psenc->charset = NONE;
3948033a5b0Stnozaki 	/*FALLTHROUGH*/
3958033a5b0Stnozaki 	case NONE:
3968033a5b0Stnozaki 		*nresult = psenc->chlen;
3978033a5b0Stnozaki 		if (psenc->chlen > 0) {
3988033a5b0Stnozaki 			memcpy(s, psenc->ch, psenc->chlen);
3998033a5b0Stnozaki 			psenc->chlen = 0;
4008033a5b0Stnozaki 		}
4018033a5b0Stnozaki 		break;
4028033a5b0Stnozaki 	default:
4038033a5b0Stnozaki 		return EINVAL;
4048033a5b0Stnozaki 	}
4058033a5b0Stnozaki 
4068033a5b0Stnozaki 	return 0;
4078033a5b0Stnozaki }
4088033a5b0Stnozaki 
4098033a5b0Stnozaki static __inline int
4108033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_stdenc_get_state_desc_generic(_ZWEncodingInfo * __restrict ei,_ZWState * __restrict psenc,int * __restrict rstate)4118033a5b0Stnozaki _citrus_ZW_stdenc_get_state_desc_generic(_ZWEncodingInfo * __restrict ei,
4128033a5b0Stnozaki 	_ZWState * __restrict psenc, int * __restrict rstate)
4138033a5b0Stnozaki {
4148033a5b0Stnozaki 	/* ei may be unused */
4158033a5b0Stnozaki 	_DIAGASSERT(psenc != NULL);
4168033a5b0Stnozaki 	_DIAGASSERT(rstate != NULL);
4178033a5b0Stnozaki 
4188033a5b0Stnozaki 	switch (psenc->charset) {
4198033a5b0Stnozaki 	case NONE:
4208033a5b0Stnozaki 		if (psenc->chlen != 0)
4218033a5b0Stnozaki 			return EINVAL;
4228033a5b0Stnozaki 		*rstate = _STDENC_SDGEN_INITIAL;
4238033a5b0Stnozaki 		break;
4248033a5b0Stnozaki 	case AMBIGIOUS:
4258033a5b0Stnozaki 		if (psenc->chlen != 0)
4268033a5b0Stnozaki 			return EINVAL;
4278033a5b0Stnozaki 		*rstate = _STDENC_SDGEN_INCOMPLETE_SHIFT;
4288033a5b0Stnozaki 		break;
4298033a5b0Stnozaki 	case ASCII:
4308033a5b0Stnozaki 	case GB2312:
4318033a5b0Stnozaki 		switch (psenc->chlen) {
4328033a5b0Stnozaki 		case 0:
4338033a5b0Stnozaki 			*rstate = _STDENC_SDGEN_STABLE;
4348033a5b0Stnozaki 			break;
4358033a5b0Stnozaki 		case 1:
4368033a5b0Stnozaki 			*rstate = (psenc->ch[0] == '#')
4378033a5b0Stnozaki 			    ? _STDENC_SDGEN_INCOMPLETE_SHIFT
4388033a5b0Stnozaki 			    : _STDENC_SDGEN_INCOMPLETE_CHAR;
4398033a5b0Stnozaki 			break;
4408033a5b0Stnozaki 		default:
4418033a5b0Stnozaki 			return EINVAL;
4428033a5b0Stnozaki 		}
4438033a5b0Stnozaki 		break;
4448033a5b0Stnozaki 	default:
4458033a5b0Stnozaki 		return EINVAL;
4468033a5b0Stnozaki 	}
4478033a5b0Stnozaki 	return 0;
4488033a5b0Stnozaki }
4498033a5b0Stnozaki 
4508033a5b0Stnozaki static __inline int
4518033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_stdenc_wctocs(_ZWEncodingInfo * __restrict ei,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)4528033a5b0Stnozaki _citrus_ZW_stdenc_wctocs(_ZWEncodingInfo * __restrict ei,
4538033a5b0Stnozaki 	_csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
4548033a5b0Stnozaki {
4558033a5b0Stnozaki 	/* ei seems to be unused */
4568033a5b0Stnozaki 	_DIAGASSERT(csid != NULL);
4578033a5b0Stnozaki 	_DIAGASSERT(idx != NULL);
4588033a5b0Stnozaki 
4598033a5b0Stnozaki 	*csid = (_csid_t)(wc <= 0x7FU) ? 0 : 1;
4608033a5b0Stnozaki 	*idx = (_index_t)wc;
4618033a5b0Stnozaki 
4628033a5b0Stnozaki 	return 0;
4638033a5b0Stnozaki }
4648033a5b0Stnozaki 
4658033a5b0Stnozaki static __inline int
4668033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_stdenc_cstowc(_ZWEncodingInfo * __restrict ei,wchar_t * __restrict wc,_csid_t csid,_index_t idx)4678033a5b0Stnozaki _citrus_ZW_stdenc_cstowc(_ZWEncodingInfo * __restrict ei,
4688033a5b0Stnozaki 	 wchar_t * __restrict wc, _csid_t csid, _index_t idx)
4698033a5b0Stnozaki {
4708033a5b0Stnozaki 	/* ei seems to be unused */
4718033a5b0Stnozaki 	_DIAGASSERT(wc != NULL);
4728033a5b0Stnozaki 
4738033a5b0Stnozaki 	switch (csid) {
4748033a5b0Stnozaki 	case 0: case 1:
4758033a5b0Stnozaki 		break;
4768033a5b0Stnozaki 	default:
4778033a5b0Stnozaki 		return EINVAL;
4788033a5b0Stnozaki 	}
4798033a5b0Stnozaki 	*wc = (wchar_t)idx;
4808033a5b0Stnozaki 
4818033a5b0Stnozaki 	return 0;
4828033a5b0Stnozaki }
4838033a5b0Stnozaki 
4848033a5b0Stnozaki static void
4858033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_encoding_module_uninit(_ZWEncodingInfo * ei)4868033a5b0Stnozaki _citrus_ZW_encoding_module_uninit(_ZWEncodingInfo *ei)
4878033a5b0Stnozaki {
4888033a5b0Stnozaki }
4898033a5b0Stnozaki 
4908033a5b0Stnozaki static int
4918033a5b0Stnozaki /*ARGSUSED*/
_citrus_ZW_encoding_module_init(_ZWEncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)4928033a5b0Stnozaki _citrus_ZW_encoding_module_init(_ZWEncodingInfo * __restrict ei,
4938033a5b0Stnozaki 	const void *__restrict var, size_t lenvar)
4948033a5b0Stnozaki {
4958033a5b0Stnozaki 	return 0;
4968033a5b0Stnozaki }
4978033a5b0Stnozaki 
4988033a5b0Stnozaki /* ----------------------------------------------------------------------
4998033a5b0Stnozaki  * public interface for ctype
5008033a5b0Stnozaki  */
5018033a5b0Stnozaki 
5028033a5b0Stnozaki _CITRUS_CTYPE_DECLS(ZW);
5038033a5b0Stnozaki _CITRUS_CTYPE_DEF_OPS(ZW);
5048033a5b0Stnozaki 
5058033a5b0Stnozaki #include "citrus_ctype_template.h"
5068033a5b0Stnozaki 
5078033a5b0Stnozaki /* ----------------------------------------------------------------------
5088033a5b0Stnozaki  * public interface for stdenc
5098033a5b0Stnozaki  */
5108033a5b0Stnozaki 
5118033a5b0Stnozaki _CITRUS_STDENC_DECLS(ZW);
5128033a5b0Stnozaki _CITRUS_STDENC_DEF_OPS(ZW);
5138033a5b0Stnozaki 
5148033a5b0Stnozaki #include "citrus_stdenc_template.h"
515