xref: /minix3/lib/libc/citrus/modules/citrus_iso2022.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: citrus_iso2022.c,v 1.23 2013/05/28 16:57:56 joerg Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c)1999, 2002 Citrus Project,
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
82fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
92fe8fb19SBen Gras  * are met:
102fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
112fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
122fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
132fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
142fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
152fe8fb19SBen Gras  *
162fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262fe8fb19SBen Gras  * SUCH DAMAGE.
272fe8fb19SBen Gras  *
282fe8fb19SBen Gras  *	$Citrus: xpg4dl/FreeBSD/lib/libc/locale/iso2022.c,v 1.23 2001/06/21 01:51:44 yamt Exp $
292fe8fb19SBen Gras  */
302fe8fb19SBen Gras 
312fe8fb19SBen Gras #include <sys/cdefs.h>
322fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
33*84d9c625SLionel Sambuc __RCSID("$NetBSD: citrus_iso2022.c,v 1.23 2013/05/28 16:57:56 joerg Exp $");
342fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
352fe8fb19SBen Gras 
362fe8fb19SBen Gras #include <assert.h>
372fe8fb19SBen Gras #include <errno.h>
382fe8fb19SBen Gras #include <string.h>
392fe8fb19SBen Gras #include <stdio.h>
402fe8fb19SBen Gras #include <stdlib.h>
412fe8fb19SBen Gras #include <stddef.h>
422fe8fb19SBen Gras #include <wchar.h>
432fe8fb19SBen Gras #include <sys/types.h>
442fe8fb19SBen Gras #include <limits.h>
452fe8fb19SBen Gras 
462fe8fb19SBen Gras #include "citrus_namespace.h"
472fe8fb19SBen Gras #include "citrus_types.h"
482fe8fb19SBen Gras #include "citrus_module.h"
492fe8fb19SBen Gras #include "citrus_ctype.h"
502fe8fb19SBen Gras #include "citrus_stdenc.h"
512fe8fb19SBen Gras #include "citrus_iso2022.h"
522fe8fb19SBen Gras 
532fe8fb19SBen Gras 
542fe8fb19SBen Gras /* ----------------------------------------------------------------------
552fe8fb19SBen Gras  * private stuffs used by templates
562fe8fb19SBen Gras  */
572fe8fb19SBen Gras 
582fe8fb19SBen Gras 
592fe8fb19SBen Gras /*
602fe8fb19SBen Gras  * wchar_t mappings:
612fe8fb19SBen Gras  * ASCII (ESC ( B)		00000000 00000000 00000000 0xxxxxxx
622fe8fb19SBen Gras  * iso-8859-1 (ESC , A)		00000000 00000000 00000000 1xxxxxxx
632fe8fb19SBen Gras  * 94 charset (ESC ( F)		0fffffff 00000000 00000000 0xxxxxxx
642fe8fb19SBen Gras  * 94 charset (ESC ( M F)	0fffffff 1mmmmmmm 00000000 0xxxxxxx
652fe8fb19SBen Gras  * 96 charset (ESC , F)		0fffffff 00000000 00000000 1xxxxxxx
662fe8fb19SBen Gras  * 96 charset (ESC , M F)	0fffffff 1mmmmmmm 00000000 1xxxxxxx
672fe8fb19SBen Gras  * 94x94 charset (ESC $ ( F)	0fffffff 00000000 0xxxxxxx 0xxxxxxx
682fe8fb19SBen Gras  * 96x96 charset (ESC $ , F)	0fffffff 00000000 0xxxxxxx 1xxxxxxx
692fe8fb19SBen Gras  * 94x94 charset (ESC & V ESC $ ( F)
702fe8fb19SBen Gras  *				0fffffff 1vvvvvvv 0xxxxxxx 0xxxxxxx
712fe8fb19SBen Gras  * 94x94x94 charset (ESC $ ( F)	0fffffff 0xxxxxxx 0xxxxxxx 0xxxxxxx
722fe8fb19SBen Gras  * 96x96x96 charset (ESC $ , F)	0fffffff 0xxxxxxx 0xxxxxxx 1xxxxxxx
732fe8fb19SBen Gras  * reserved for UCS4 co-existence (UCS4 is 31bit encoding thanks to mohta bit)
742fe8fb19SBen Gras  *				1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
752fe8fb19SBen Gras  */
762fe8fb19SBen Gras 
772fe8fb19SBen Gras typedef struct {
782fe8fb19SBen Gras 	u_char	type;
792fe8fb19SBen Gras #define	CS94		(0U)
802fe8fb19SBen Gras #define	CS96		(1U)
812fe8fb19SBen Gras #define	CS94MULTI	(2U)
822fe8fb19SBen Gras #define	CS96MULTI	(3U)
832fe8fb19SBen Gras 
842fe8fb19SBen Gras 	u_char	final;
852fe8fb19SBen Gras 	u_char	interm;
862fe8fb19SBen Gras 	u_char	vers;
872fe8fb19SBen Gras } _ISO2022Charset;
882fe8fb19SBen Gras 
892fe8fb19SBen Gras static const _ISO2022Charset ascii    = { CS94, 'B', '\0', '\0' };
902fe8fb19SBen Gras static const _ISO2022Charset iso88591 = { CS96, 'A', '\0', '\0' };
912fe8fb19SBen Gras 
922fe8fb19SBen Gras typedef struct {
932fe8fb19SBen Gras 	_ISO2022Charset	g[4];
942fe8fb19SBen Gras 	/* need 3 bits to hold -1, 0, ..., 3 */
952fe8fb19SBen Gras 	int	gl:3,
962fe8fb19SBen Gras 		gr:3,
972fe8fb19SBen Gras 		singlegl:3,
982fe8fb19SBen Gras 		singlegr:3;
992fe8fb19SBen Gras 	char ch[7];	/* longest escape sequence (ESC & V ESC $ ( F) */
1002fe8fb19SBen Gras 	int chlen;
1012fe8fb19SBen Gras 	int flags;
1022fe8fb19SBen Gras #define _ISO2022STATE_FLAG_INITIALIZED	1
1032fe8fb19SBen Gras } _ISO2022State;
1042fe8fb19SBen Gras 
1052fe8fb19SBen Gras typedef struct {
1062fe8fb19SBen Gras 	_ISO2022Charset	*recommend[4];
1072fe8fb19SBen Gras 	size_t	recommendsize[4];
1082fe8fb19SBen Gras 	_ISO2022Charset	initg[4];
1092fe8fb19SBen Gras 	int	maxcharset;
1102fe8fb19SBen Gras 	int	flags;
1112fe8fb19SBen Gras #define	F_8BIT	0x0001
1122fe8fb19SBen Gras #define	F_NOOLD	0x0002
1132fe8fb19SBen Gras #define	F_SI	0x0010	/*0F*/
1142fe8fb19SBen Gras #define	F_SO	0x0020	/*0E*/
1152fe8fb19SBen Gras #define	F_LS0	0x0010	/*0F*/
1162fe8fb19SBen Gras #define	F_LS1	0x0020	/*0E*/
1172fe8fb19SBen Gras #define	F_LS2	0x0040	/*ESC n*/
1182fe8fb19SBen Gras #define	F_LS3	0x0080	/*ESC o*/
1192fe8fb19SBen Gras #define	F_LS1R	0x0100	/*ESC ~*/
1202fe8fb19SBen Gras #define	F_LS2R	0x0200	/*ESC }*/
1212fe8fb19SBen Gras #define	F_LS3R	0x0400	/*ESC |*/
1222fe8fb19SBen Gras #define	F_SS2	0x0800	/*ESC N*/
1232fe8fb19SBen Gras #define	F_SS3	0x1000	/*ESC O*/
1242fe8fb19SBen Gras #define	F_SS2R	0x2000	/*8E*/
1252fe8fb19SBen Gras #define	F_SS3R	0x4000	/*8F*/
1262fe8fb19SBen Gras } _ISO2022EncodingInfo;
1272fe8fb19SBen Gras typedef struct {
1282fe8fb19SBen Gras 	_ISO2022EncodingInfo ei;
1292fe8fb19SBen Gras 	struct {
1302fe8fb19SBen Gras 		/* for future multi-locale facility */
1312fe8fb19SBen Gras 		_ISO2022State	s_mblen;
1322fe8fb19SBen Gras 		_ISO2022State	s_mbrlen;
1332fe8fb19SBen Gras 		_ISO2022State	s_mbrtowc;
1342fe8fb19SBen Gras 		_ISO2022State	s_mbtowc;
1352fe8fb19SBen Gras 		_ISO2022State	s_mbsrtowcs;
136*84d9c625SLionel Sambuc 		_ISO2022State	s_mbsnrtowcs;
1372fe8fb19SBen Gras 		_ISO2022State	s_wcrtomb;
1382fe8fb19SBen Gras 		_ISO2022State	s_wcsrtombs;
139*84d9c625SLionel Sambuc 		_ISO2022State	s_wcsnrtombs;
1402fe8fb19SBen Gras 		_ISO2022State	s_wctomb;
1412fe8fb19SBen Gras 	} states;
1422fe8fb19SBen Gras } _ISO2022CTypeInfo;
1432fe8fb19SBen Gras 
1442fe8fb19SBen Gras #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
1452fe8fb19SBen Gras #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
1462fe8fb19SBen Gras 
1472fe8fb19SBen Gras #define _FUNCNAME(m)			_citrus_ISO2022_##m
1482fe8fb19SBen Gras #define _ENCODING_INFO			_ISO2022EncodingInfo
1492fe8fb19SBen Gras #define _CTYPE_INFO			_ISO2022CTypeInfo
1502fe8fb19SBen Gras #define _ENCODING_STATE			_ISO2022State
1512fe8fb19SBen Gras #define _ENCODING_MB_CUR_MAX(_ei_)	MB_LEN_MAX
1522fe8fb19SBen Gras #define _ENCODING_IS_STATE_DEPENDENT	1
1532fe8fb19SBen Gras #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	\
1542fe8fb19SBen Gras     (!((_ps_)->flags & _ISO2022STATE_FLAG_INITIALIZED))
1552fe8fb19SBen Gras 
1562fe8fb19SBen Gras 
1572fe8fb19SBen Gras #define _ISO2022INVALID (wchar_t)-1
1582fe8fb19SBen Gras 
isc0(__uint8_t x)1592fe8fb19SBen Gras static __inline int isc0(__uint8_t x) { return ((x & 0x1f) == x); }
isc1(__uint8_t x)1602fe8fb19SBen Gras static __inline int isc1(__uint8_t x) { return (0x80 <= x && x <= 0x9f); }
iscntl(__uint8_t x)1612fe8fb19SBen Gras static __inline int iscntl(__uint8_t x) { return (isc0(x) || isc1(x) || x == 0x7f); }
is94(__uint8_t x)1622fe8fb19SBen Gras static __inline int is94(__uint8_t x) { return (0x21 <= x && x <= 0x7e); }
is96(__uint8_t x)1632fe8fb19SBen Gras static __inline int is96(__uint8_t x) { return (0x20 <= x && x <= 0x7f); }
isecma(__uint8_t x)1642fe8fb19SBen Gras static __inline int isecma(__uint8_t x) { return (0x30 <= x && x <= 0x7f); }
isinterm(__uint8_t x)1652fe8fb19SBen Gras static __inline int isinterm(__uint8_t x) { return (0x20 <= x && x <= 0x2f); }
isthree(__uint8_t x)1662fe8fb19SBen Gras static __inline int isthree(__uint8_t x) { return (0x60 <= x && x <= 0x6f); }
1672fe8fb19SBen Gras 
1682fe8fb19SBen Gras static __inline int
getcs(const char * __restrict p,_ISO2022Charset * __restrict cs)1692fe8fb19SBen Gras getcs(const char * __restrict p, _ISO2022Charset * __restrict cs)
1702fe8fb19SBen Gras {
1712fe8fb19SBen Gras 
1722fe8fb19SBen Gras 	_DIAGASSERT(p != NULL);
1732fe8fb19SBen Gras 	_DIAGASSERT(cs != NULL);
1742fe8fb19SBen Gras 
1752fe8fb19SBen Gras 	if (!strncmp(p, "94$", 3) && p[3] && !p[4]) {
1762fe8fb19SBen Gras 		cs->final = (u_char)(p[3] & 0xff);
1772fe8fb19SBen Gras 		cs->interm = '\0';
1782fe8fb19SBen Gras 		cs->vers = '\0';
1792fe8fb19SBen Gras 		cs->type = CS94MULTI;
1802fe8fb19SBen Gras 	} else if (!strncmp(p, "96$", 3) && p[3] && !p[4]) {
1812fe8fb19SBen Gras 		cs->final = (u_char)(p[3] & 0xff);
1822fe8fb19SBen Gras 		cs->interm = '\0';
1832fe8fb19SBen Gras 		cs->vers = '\0';
1842fe8fb19SBen Gras 		cs->type = CS96MULTI;
1852fe8fb19SBen Gras 	} else if (!strncmp(p, "94", 2) && p[2] && !p[3]) {
1862fe8fb19SBen Gras 		cs->final = (u_char)(p[2] & 0xff);
1872fe8fb19SBen Gras 		cs->interm = '\0';
1882fe8fb19SBen Gras 		cs->vers = '\0';
1892fe8fb19SBen Gras 		cs->type = CS94;
1902fe8fb19SBen Gras 	} else if (!strncmp(p, "96", 2) && p[2] && !p[3]) {
1912fe8fb19SBen Gras 		cs->final = (u_char )(p[2] & 0xff);
1922fe8fb19SBen Gras 		cs->interm = '\0';
1932fe8fb19SBen Gras 		cs->vers = '\0';
1942fe8fb19SBen Gras 		cs->type = CS96;
1952fe8fb19SBen Gras 	} else {
1962fe8fb19SBen Gras 		return 1;
1972fe8fb19SBen Gras 	}
1982fe8fb19SBen Gras 
1992fe8fb19SBen Gras 	return 0;
2002fe8fb19SBen Gras }
2012fe8fb19SBen Gras 
2022fe8fb19SBen Gras 
2032fe8fb19SBen Gras #define _NOTMATCH	0
2042fe8fb19SBen Gras #define _MATCH		1
2052fe8fb19SBen Gras #define _PARSEFAIL	2
2062fe8fb19SBen Gras 
2072fe8fb19SBen Gras static __inline int
get_recommend(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)2082fe8fb19SBen Gras get_recommend(_ISO2022EncodingInfo * __restrict ei,
2092fe8fb19SBen Gras 	      const char * __restrict token)
2102fe8fb19SBen Gras {
2112fe8fb19SBen Gras 	int i;
2122fe8fb19SBen Gras 	_ISO2022Charset cs, *p;
2132fe8fb19SBen Gras 
2142fe8fb19SBen Gras 	if (!strchr("0123", token[0]) || token[1] != '=')
2152fe8fb19SBen Gras 		return (_NOTMATCH);
2162fe8fb19SBen Gras 
2172fe8fb19SBen Gras 	if (getcs(&token[2], &cs) == 0)
2182fe8fb19SBen Gras 		;
2192fe8fb19SBen Gras 	else if (!strcmp(&token[2], "94")) {
2202fe8fb19SBen Gras 		cs.final = (u_char)(token[4]);
2212fe8fb19SBen Gras 		cs.interm = '\0';
2222fe8fb19SBen Gras 		cs.vers = '\0';
2232fe8fb19SBen Gras 		cs.type = CS94;
2242fe8fb19SBen Gras 	} else if (!strcmp(&token[2], "96")) {
2252fe8fb19SBen Gras 		cs.final = (u_char)(token[4]);
2262fe8fb19SBen Gras 		cs.interm = '\0';
2272fe8fb19SBen Gras 		cs.vers = '\0';
2282fe8fb19SBen Gras 		cs.type = CS96;
2292fe8fb19SBen Gras 	} else if (!strcmp(&token[2], "94$")) {
2302fe8fb19SBen Gras 		cs.final = (u_char)(token[5]);
2312fe8fb19SBen Gras 		cs.interm = '\0';
2322fe8fb19SBen Gras 		cs.vers = '\0';
2332fe8fb19SBen Gras 		cs.type = CS94MULTI;
2342fe8fb19SBen Gras 	} else if (!strcmp(&token[2], "96$")) {
2352fe8fb19SBen Gras 		cs.final = (u_char)(token[5]);
2362fe8fb19SBen Gras 		cs.interm = '\0';
2372fe8fb19SBen Gras 		cs.vers = '\0';
2382fe8fb19SBen Gras 		cs.type = CS96MULTI;
2392fe8fb19SBen Gras 	} else {
2402fe8fb19SBen Gras 		return (_PARSEFAIL);
2412fe8fb19SBen Gras 	}
2422fe8fb19SBen Gras 
2432fe8fb19SBen Gras 	i = token[0] - '0';
2442fe8fb19SBen Gras 	if (!ei->recommend[i]) {
2452fe8fb19SBen Gras 		ei->recommend[i] = malloc(sizeof(_ISO2022Charset));
2462fe8fb19SBen Gras 	} else {
2472fe8fb19SBen Gras 		p = realloc(ei->recommend[i],
2482fe8fb19SBen Gras 		    sizeof(_ISO2022Charset) * (ei->recommendsize[i] + 1));
2492fe8fb19SBen Gras 		if (!p)
2502fe8fb19SBen Gras 			return (_PARSEFAIL);
2512fe8fb19SBen Gras 		ei->recommend[i] = p;
2522fe8fb19SBen Gras 	}
2532fe8fb19SBen Gras 	if (!ei->recommend[i])
2542fe8fb19SBen Gras 		return (_PARSEFAIL);
2552fe8fb19SBen Gras 	ei->recommendsize[i]++;
2562fe8fb19SBen Gras 
2572fe8fb19SBen Gras 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->final = cs.final;
2582fe8fb19SBen Gras 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->interm = cs.interm;
2592fe8fb19SBen Gras 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->vers = cs.vers;
2602fe8fb19SBen Gras 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->type = cs.type;
2612fe8fb19SBen Gras 
2622fe8fb19SBen Gras 	return (_MATCH);
2632fe8fb19SBen Gras }
2642fe8fb19SBen Gras 
2652fe8fb19SBen Gras static __inline int
get_initg(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)2662fe8fb19SBen Gras get_initg(_ISO2022EncodingInfo * __restrict ei,
2672fe8fb19SBen Gras 	  const char * __restrict token)
2682fe8fb19SBen Gras {
2692fe8fb19SBen Gras 	_ISO2022Charset cs;
2702fe8fb19SBen Gras 
2712fe8fb19SBen Gras 	if (strncmp("INIT", &token[0], 4) ||
2722fe8fb19SBen Gras 	    !strchr("0123", token[4]) ||
2732fe8fb19SBen Gras 	    token[5] != '=')
2742fe8fb19SBen Gras 		return (_NOTMATCH);
2752fe8fb19SBen Gras 
2762fe8fb19SBen Gras 	if (getcs(&token[6], &cs) != 0)
2772fe8fb19SBen Gras 		return (_PARSEFAIL);
2782fe8fb19SBen Gras 
2792fe8fb19SBen Gras 	ei->initg[token[4] - '0'].type = cs.type;
2802fe8fb19SBen Gras 	ei->initg[token[4] - '0'].final = cs.final;
2812fe8fb19SBen Gras 	ei->initg[token[4] - '0'].interm = cs.interm;
2822fe8fb19SBen Gras 	ei->initg[token[4] - '0'].vers = cs.vers;
2832fe8fb19SBen Gras 
2842fe8fb19SBen Gras 	return (_MATCH);
2852fe8fb19SBen Gras }
2862fe8fb19SBen Gras 
2872fe8fb19SBen Gras static __inline int
get_max(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)2882fe8fb19SBen Gras get_max(_ISO2022EncodingInfo * __restrict ei,
2892fe8fb19SBen Gras 	const char * __restrict token)
2902fe8fb19SBen Gras {
2912fe8fb19SBen Gras 	if (!strcmp(token, "MAX1")) {
2922fe8fb19SBen Gras 		ei->maxcharset = 1;
2932fe8fb19SBen Gras 	} else if (!strcmp(token, "MAX2")) {
2942fe8fb19SBen Gras 		ei->maxcharset = 2;
2952fe8fb19SBen Gras 	} else if (!strcmp(token, "MAX3")) {
2962fe8fb19SBen Gras 		ei->maxcharset = 3;
2972fe8fb19SBen Gras 	} else
2982fe8fb19SBen Gras 		return (_NOTMATCH);
2992fe8fb19SBen Gras 
3002fe8fb19SBen Gras 	return (_MATCH);
3012fe8fb19SBen Gras }
3022fe8fb19SBen Gras 
3032fe8fb19SBen Gras 
3042fe8fb19SBen Gras static __inline int
get_flags(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)3052fe8fb19SBen Gras get_flags(_ISO2022EncodingInfo * __restrict ei,
3062fe8fb19SBen Gras 	  const char * __restrict token)
3072fe8fb19SBen Gras {
3082fe8fb19SBen Gras 	int i;
3092fe8fb19SBen Gras 	static struct {
3102fe8fb19SBen Gras 		const char	*tag;
3112fe8fb19SBen Gras 		int		flag;
3122fe8fb19SBen Gras 	} const tags[] = {
3132fe8fb19SBen Gras 		{ "DUMMY",	0	},
3142fe8fb19SBen Gras 		{ "8BIT",	F_8BIT	},
3152fe8fb19SBen Gras 		{ "NOOLD",	F_NOOLD	},
3162fe8fb19SBen Gras 		{ "SI",		F_SI	},
3172fe8fb19SBen Gras 		{ "SO",		F_SO	},
3182fe8fb19SBen Gras 		{ "LS0",	F_LS0	},
3192fe8fb19SBen Gras 		{ "LS1",	F_LS1	},
3202fe8fb19SBen Gras 		{ "LS2",	F_LS2	},
3212fe8fb19SBen Gras 		{ "LS3",	F_LS3	},
3222fe8fb19SBen Gras 		{ "LS1R",	F_LS1R	},
3232fe8fb19SBen Gras 		{ "LS2R",	F_LS2R	},
3242fe8fb19SBen Gras 		{ "LS3R",	F_LS3R	},
3252fe8fb19SBen Gras 		{ "SS2",	F_SS2	},
3262fe8fb19SBen Gras 		{ "SS3",	F_SS3	},
3272fe8fb19SBen Gras 		{ "SS2R",	F_SS2R	},
3282fe8fb19SBen Gras 		{ "SS3R",	F_SS3R	},
3292fe8fb19SBen Gras 		{ NULL,		0 }
3302fe8fb19SBen Gras 	};
3312fe8fb19SBen Gras 
3322fe8fb19SBen Gras 	for (i = 0; tags[i].tag; i++) {
3332fe8fb19SBen Gras 		if (!strcmp(token, tags[i].tag)) {
3342fe8fb19SBen Gras 			ei->flags |= tags[i].flag;
3352fe8fb19SBen Gras 			return (_MATCH);
3362fe8fb19SBen Gras 		}
3372fe8fb19SBen Gras 	}
3382fe8fb19SBen Gras 
3392fe8fb19SBen Gras 	return (_NOTMATCH);
3402fe8fb19SBen Gras }
3412fe8fb19SBen Gras 
3422fe8fb19SBen Gras 
3432fe8fb19SBen Gras static __inline int
_citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)3442fe8fb19SBen Gras _citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * __restrict ei,
3452fe8fb19SBen Gras 			       const void * __restrict var, size_t lenvar)
3462fe8fb19SBen Gras {
3472fe8fb19SBen Gras 	char const *v, *e;
3482fe8fb19SBen Gras 	char buf[20];
3492fe8fb19SBen Gras 	int i, len, ret;
3502fe8fb19SBen Gras 
3512fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
3522fe8fb19SBen Gras 
3532fe8fb19SBen Gras 
3542fe8fb19SBen Gras 	/*
3552fe8fb19SBen Gras 	 * parse VARIABLE section.
3562fe8fb19SBen Gras 	 */
3572fe8fb19SBen Gras 
3582fe8fb19SBen Gras 	if (!var)
3592fe8fb19SBen Gras 		return (EFTYPE);
3602fe8fb19SBen Gras 
3612fe8fb19SBen Gras 	v = (const char *) var;
3622fe8fb19SBen Gras 
3632fe8fb19SBen Gras 	/* initialize structure */
3642fe8fb19SBen Gras 	ei->maxcharset = 0;
3652fe8fb19SBen Gras 	for (i = 0; i < 4; i++) {
3662fe8fb19SBen Gras 		ei->recommend[i] = NULL;
3672fe8fb19SBen Gras 		ei->recommendsize[i] = 0;
3682fe8fb19SBen Gras 	}
3692fe8fb19SBen Gras 	ei->flags = 0;
3702fe8fb19SBen Gras 
3712fe8fb19SBen Gras 	while (*v) {
3722fe8fb19SBen Gras 		while (*v == ' ' || *v == '\t')
3732fe8fb19SBen Gras 			++v;
3742fe8fb19SBen Gras 
3752fe8fb19SBen Gras 		/* find the token */
3762fe8fb19SBen Gras 		e = v;
3772fe8fb19SBen Gras 		while (*e && *e != ' ' && *e != '\t')
3782fe8fb19SBen Gras 			++e;
3792fe8fb19SBen Gras 
3802fe8fb19SBen Gras 		len = e-v;
3812fe8fb19SBen Gras 		if (len == 0)
3822fe8fb19SBen Gras 			break;
3832fe8fb19SBen Gras 		if (len>=sizeof(buf))
3842fe8fb19SBen Gras 			goto parsefail;
3852fe8fb19SBen Gras 		snprintf(buf, sizeof(buf), "%.*s", len, v);
3862fe8fb19SBen Gras 
3872fe8fb19SBen Gras 		if ((ret = get_recommend(ei, buf)) != _NOTMATCH)
3882fe8fb19SBen Gras 			;
3892fe8fb19SBen Gras 		else if ((ret = get_initg(ei, buf)) != _NOTMATCH)
3902fe8fb19SBen Gras 			;
3912fe8fb19SBen Gras 		else if ((ret = get_max(ei, buf)) != _NOTMATCH)
3922fe8fb19SBen Gras 			;
3932fe8fb19SBen Gras 		else if ((ret = get_flags(ei, buf)) != _NOTMATCH)
3942fe8fb19SBen Gras 			;
3952fe8fb19SBen Gras 		else
3962fe8fb19SBen Gras 			ret = _PARSEFAIL;
3972fe8fb19SBen Gras 		if (ret==_PARSEFAIL)
3982fe8fb19SBen Gras 			goto parsefail;
3992fe8fb19SBen Gras 		v = e;
4002fe8fb19SBen Gras 
4012fe8fb19SBen Gras 	}
4022fe8fb19SBen Gras 
4032fe8fb19SBen Gras 	return (0);
4042fe8fb19SBen Gras 
4052fe8fb19SBen Gras parsefail:
4062fe8fb19SBen Gras 	free(ei->recommend[0]);
4072fe8fb19SBen Gras 	free(ei->recommend[1]);
4082fe8fb19SBen Gras 	free(ei->recommend[2]);
4092fe8fb19SBen Gras 	free(ei->recommend[3]);
4102fe8fb19SBen Gras 
4112fe8fb19SBen Gras 	return (EFTYPE);
4122fe8fb19SBen Gras }
4132fe8fb19SBen Gras 
4142fe8fb19SBen Gras static __inline void
4152fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_init_state(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict s)4162fe8fb19SBen Gras _citrus_ISO2022_init_state(_ISO2022EncodingInfo * __restrict ei,
4172fe8fb19SBen Gras 			   _ISO2022State * __restrict s)
4182fe8fb19SBen Gras {
4192fe8fb19SBen Gras 	int i;
4202fe8fb19SBen Gras 
4212fe8fb19SBen Gras 	memset(s, 0, sizeof(*s));
4222fe8fb19SBen Gras 	s->gl = 0;
4232fe8fb19SBen Gras 	s->gr = (ei->flags & F_8BIT) ? 1 : -1;
4242fe8fb19SBen Gras 
4252fe8fb19SBen Gras 	for (i = 0; i < 4; i++) {
4262fe8fb19SBen Gras 		if (ei->initg[i].final) {
4272fe8fb19SBen Gras 			s->g[i].type = ei->initg[i].type;
4282fe8fb19SBen Gras 			s->g[i].final = ei->initg[i].final;
4292fe8fb19SBen Gras 			s->g[i].interm = ei->initg[i].interm;
4302fe8fb19SBen Gras 		}
4312fe8fb19SBen Gras 	}
4322fe8fb19SBen Gras 	s->singlegl = s->singlegr = -1;
4332fe8fb19SBen Gras 	s->flags |= _ISO2022STATE_FLAG_INITIALIZED;
4342fe8fb19SBen Gras }
4352fe8fb19SBen Gras 
4362fe8fb19SBen Gras static __inline void
4372fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_pack_state(_ISO2022EncodingInfo * __restrict ei,void * __restrict pspriv,const _ISO2022State * __restrict s)4382fe8fb19SBen Gras _citrus_ISO2022_pack_state(_ISO2022EncodingInfo * __restrict ei,
4392fe8fb19SBen Gras 			   void * __restrict pspriv,
4402fe8fb19SBen Gras 			   const _ISO2022State * __restrict s)
4412fe8fb19SBen Gras {
4422fe8fb19SBen Gras 	memcpy(pspriv, (const void *)s, sizeof(*s));
4432fe8fb19SBen Gras }
4442fe8fb19SBen Gras 
4452fe8fb19SBen Gras static __inline void
4462fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_unpack_state(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict s,const void * __restrict pspriv)4472fe8fb19SBen Gras _citrus_ISO2022_unpack_state(_ISO2022EncodingInfo * __restrict ei,
4482fe8fb19SBen Gras 			     _ISO2022State * __restrict s,
4492fe8fb19SBen Gras 			     const void * __restrict pspriv)
4502fe8fb19SBen Gras {
4512fe8fb19SBen Gras 	memcpy((void *)s, pspriv, sizeof(*s));
4522fe8fb19SBen Gras }
4532fe8fb19SBen Gras 
4542fe8fb19SBen Gras static int
4552fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)4562fe8fb19SBen Gras _citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * __restrict ei,
4572fe8fb19SBen Gras 				     const void * __restrict var,
4582fe8fb19SBen Gras 				     size_t lenvar)
4592fe8fb19SBen Gras {
4602fe8fb19SBen Gras 
4612fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
4622fe8fb19SBen Gras 
4632fe8fb19SBen Gras 	return _citrus_ISO2022_parse_variable(ei, var, lenvar);
4642fe8fb19SBen Gras }
4652fe8fb19SBen Gras 
4662fe8fb19SBen Gras static void
4672fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo * ei)4682fe8fb19SBen Gras _citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo *ei)
4692fe8fb19SBen Gras {
4702fe8fb19SBen Gras }
4712fe8fb19SBen Gras 
4722fe8fb19SBen Gras #define	ESC	'\033'
4732fe8fb19SBen Gras #define	ECMA	-1
4742fe8fb19SBen Gras #define	INTERM	-2
4752fe8fb19SBen Gras #define	OECMA	-3
4762fe8fb19SBen Gras static const struct seqtable {
4772fe8fb19SBen Gras 	int type;
4782fe8fb19SBen Gras 	int csoff;
4792fe8fb19SBen Gras 	int finaloff;
4802fe8fb19SBen Gras 	int intermoff;
4812fe8fb19SBen Gras 	int versoff;
4822fe8fb19SBen Gras 	int len;
4832fe8fb19SBen Gras 	int chars[10];
4842fe8fb19SBen Gras } seqtable[] = {
4852fe8fb19SBen Gras 	/* G0 94MULTI special */
4862fe8fb19SBen Gras 	{ CS94MULTI, -1, 2, -1, -1,	3, { ESC, '$', OECMA }, },
4872fe8fb19SBen Gras 	/* G0 94MULTI special with version identification */
4882fe8fb19SBen Gras 	{ CS94MULTI, -1, 5, -1, 2,	6, { ESC, '&', ECMA, ESC, '$', OECMA }, },
4892fe8fb19SBen Gras 	/* G? 94 */
4902fe8fb19SBen Gras 	{ CS94, 1, 2, -1, -1,		3, { ESC, CS94, ECMA, }, },
4912fe8fb19SBen Gras 	/* G? 94 with 2nd intermediate char */
4922fe8fb19SBen Gras 	{ CS94, 1, 3, 2, -1,		4, { ESC, CS94, INTERM, ECMA, }, },
4932fe8fb19SBen Gras 	/* G? 96 */
4942fe8fb19SBen Gras 	{ CS96, 1, 2, -1, -1,		3, { ESC, CS96, ECMA, }, },
4952fe8fb19SBen Gras 	/* G? 96 with 2nd intermediate char */
4962fe8fb19SBen Gras 	{ CS96, 1, 3, 2, -1,		4, { ESC, CS96, INTERM, ECMA, }, },
4972fe8fb19SBen Gras 	/* G? 94MULTI */
4982fe8fb19SBen Gras 	{ CS94MULTI, 2, 3, -1, -1,	4, { ESC, '$', CS94, ECMA, }, },
4992fe8fb19SBen Gras 	/* G? 96MULTI */
5002fe8fb19SBen Gras 	{ CS96MULTI, 2, 3, -1, -1,	4, { ESC, '$', CS96, ECMA, }, },
5012fe8fb19SBen Gras 	/* G? 94MULTI with version specification */
5022fe8fb19SBen Gras 	{ CS94MULTI, 5, 6, -1, 2,	7, { ESC, '&', ECMA, ESC, '$', CS94, ECMA, }, },
5032fe8fb19SBen Gras 	/* LS2/3 */
5042fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, 'n', }, },
5052fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, 'o', }, },
5062fe8fb19SBen Gras 	/* LS1/2/3R */
5072fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, '~', }, },
5082fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, /*{*/ '}', }, },
5092fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, '|', }, },
5102fe8fb19SBen Gras 	/* SS2/3 */
5112fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, 'N', }, },
5122fe8fb19SBen Gras 	{ -1, -1, -1, -1, -1,		2, { ESC, 'O', }, },
5132fe8fb19SBen Gras 	/* end of records */
5142fe8fb19SBen Gras 	{ 0, }
5152fe8fb19SBen Gras };
5162fe8fb19SBen Gras 
5172fe8fb19SBen Gras static int
seqmatch(const char * __restrict s,size_t n,const struct seqtable * __restrict sp)5182fe8fb19SBen Gras seqmatch(const char * __restrict s, size_t n,
5192fe8fb19SBen Gras 	 const struct seqtable * __restrict sp)
5202fe8fb19SBen Gras {
5212fe8fb19SBen Gras 	const int *p;
5222fe8fb19SBen Gras 
5232fe8fb19SBen Gras 	_DIAGASSERT(s != NULL);
5242fe8fb19SBen Gras 	_DIAGASSERT(sp != NULL);
5252fe8fb19SBen Gras 
5262fe8fb19SBen Gras 	p = sp->chars;
5272fe8fb19SBen Gras 	while (p - sp->chars < n && p - sp->chars < sp->len) {
5282fe8fb19SBen Gras 		switch (*p) {
5292fe8fb19SBen Gras 		case ECMA:
5302fe8fb19SBen Gras 			if (!isecma(*s))
5312fe8fb19SBen Gras 				goto terminate;
5322fe8fb19SBen Gras 			break;
5332fe8fb19SBen Gras 		case OECMA:
5342fe8fb19SBen Gras 			if (*s && strchr("@AB", *s))
5352fe8fb19SBen Gras 				break;
5362fe8fb19SBen Gras 			else
5372fe8fb19SBen Gras 				goto terminate;
5382fe8fb19SBen Gras 		case INTERM:
5392fe8fb19SBen Gras 			if (!isinterm(*s))
5402fe8fb19SBen Gras 				goto terminate;
5412fe8fb19SBen Gras 			break;
5422fe8fb19SBen Gras 		case CS94:
5432fe8fb19SBen Gras 			if (*s && strchr("()*+", *s))
5442fe8fb19SBen Gras 				break;
5452fe8fb19SBen Gras 			else
5462fe8fb19SBen Gras 				goto terminate;
5472fe8fb19SBen Gras 		case CS96:
5482fe8fb19SBen Gras 			if (*s && strchr(",-./", *s))
5492fe8fb19SBen Gras 				break;
5502fe8fb19SBen Gras 			else
5512fe8fb19SBen Gras 				goto terminate;
5522fe8fb19SBen Gras 		default:
5532fe8fb19SBen Gras 			if (*s != *p)
5542fe8fb19SBen Gras 				goto terminate;
5552fe8fb19SBen Gras 			break;
5562fe8fb19SBen Gras 		}
5572fe8fb19SBen Gras 
5582fe8fb19SBen Gras 		p++;
5592fe8fb19SBen Gras 		s++;
5602fe8fb19SBen Gras 	}
5612fe8fb19SBen Gras 
5622fe8fb19SBen Gras terminate:
5632fe8fb19SBen Gras 	return p - sp->chars;
5642fe8fb19SBen Gras }
5652fe8fb19SBen Gras 
5662fe8fb19SBen Gras static wchar_t
_ISO2022_sgetwchar(_ISO2022EncodingInfo * __restrict ei,const char * __restrict string,size_t n,const char ** __restrict result,_ISO2022State * __restrict psenc)5672fe8fb19SBen Gras _ISO2022_sgetwchar(_ISO2022EncodingInfo * __restrict ei,
5682fe8fb19SBen Gras 		const char * __restrict string, size_t n,
5692fe8fb19SBen Gras 		const char ** __restrict result,
5702fe8fb19SBen Gras 		_ISO2022State * __restrict psenc)
5712fe8fb19SBen Gras {
5722fe8fb19SBen Gras 	wchar_t wchar = 0;
5732fe8fb19SBen Gras 	int cur;
5742fe8fb19SBen Gras 	const struct seqtable *sp;
5752fe8fb19SBen Gras 	int nmatch;
5762fe8fb19SBen Gras 	int i;
5772fe8fb19SBen Gras 
5782fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
5792fe8fb19SBen Gras 	_DIAGASSERT(psenc != NULL);
5802fe8fb19SBen Gras 	_DIAGASSERT(string != NULL);
5812fe8fb19SBen Gras 	/* result may be NULL */
5822fe8fb19SBen Gras 
5832fe8fb19SBen Gras 	while (1) {
5842fe8fb19SBen Gras 		/* SI/SO */
5852fe8fb19SBen Gras 		if (1 <= n && string[0] == '\017') {
5862fe8fb19SBen Gras 			psenc->gl = 0;
5872fe8fb19SBen Gras 			string++;
5882fe8fb19SBen Gras 			n--;
5892fe8fb19SBen Gras 			continue;
5902fe8fb19SBen Gras 		}
5912fe8fb19SBen Gras 		if (1 <= n && string[0] == '\016') {
5922fe8fb19SBen Gras 			psenc->gl = 1;
5932fe8fb19SBen Gras 			string++;
5942fe8fb19SBen Gras 			n--;
5952fe8fb19SBen Gras 			continue;
5962fe8fb19SBen Gras 		}
5972fe8fb19SBen Gras 
5982fe8fb19SBen Gras 		/* SS2/3R */
5992fe8fb19SBen Gras 		if (1 <= n && string[0] && strchr("\217\216", string[0])) {
6002fe8fb19SBen Gras 			psenc->singlegl = psenc->singlegr =
6012fe8fb19SBen Gras 			    (string[0] - '\216') + 2;
6022fe8fb19SBen Gras 			string++;
6032fe8fb19SBen Gras 			n--;
6042fe8fb19SBen Gras 			continue;
6052fe8fb19SBen Gras 		}
6062fe8fb19SBen Gras 
6072fe8fb19SBen Gras 		/* eat the letter if this is not ESC */
6082fe8fb19SBen Gras 		if (1 <= n && string[0] != '\033')
6092fe8fb19SBen Gras 			break;
6102fe8fb19SBen Gras 
6112fe8fb19SBen Gras 		/* look for a perfect match from escape sequences */
6122fe8fb19SBen Gras 		for (sp = &seqtable[0]; sp->len; sp++) {
6132fe8fb19SBen Gras 			nmatch = seqmatch(string, n, sp);
6142fe8fb19SBen Gras 			if (sp->len == nmatch && n >= sp->len)
6152fe8fb19SBen Gras 				break;
6162fe8fb19SBen Gras 		}
6172fe8fb19SBen Gras 
6182fe8fb19SBen Gras 		if (!sp->len)
6192fe8fb19SBen Gras 			goto notseq;
6202fe8fb19SBen Gras 
6212fe8fb19SBen Gras 		if (sp->type != -1) {
6222fe8fb19SBen Gras 			if (sp->csoff == -1)
6232fe8fb19SBen Gras 				i = 0;
6242fe8fb19SBen Gras 			else {
6252fe8fb19SBen Gras 				switch (sp->type) {
6262fe8fb19SBen Gras 				case CS94:
6272fe8fb19SBen Gras 				case CS94MULTI:
6282fe8fb19SBen Gras 					i = string[sp->csoff] - '(';
6292fe8fb19SBen Gras 					break;
6302fe8fb19SBen Gras 				case CS96:
6312fe8fb19SBen Gras 				case CS96MULTI:
6322fe8fb19SBen Gras 					i = string[sp->csoff] - ',';
6332fe8fb19SBen Gras 					break;
6342fe8fb19SBen Gras 				default:
6352fe8fb19SBen Gras 					return (_ISO2022INVALID);
6362fe8fb19SBen Gras 				}
6372fe8fb19SBen Gras 			}
6382fe8fb19SBen Gras 			psenc->g[i].type = sp->type;
6392fe8fb19SBen Gras 			psenc->g[i].final = '\0';
6402fe8fb19SBen Gras 			psenc->g[i].interm = '\0';
6412fe8fb19SBen Gras 			psenc->g[i].vers = '\0';
6422fe8fb19SBen Gras 			/* sp->finaloff must not be -1 */
6432fe8fb19SBen Gras 			if (sp->finaloff != -1)
6442fe8fb19SBen Gras 				psenc->g[i].final = string[sp->finaloff];
6452fe8fb19SBen Gras 			if (sp->intermoff != -1)
6462fe8fb19SBen Gras 				psenc->g[i].interm = string[sp->intermoff];
6472fe8fb19SBen Gras 			if (sp->versoff != -1)
6482fe8fb19SBen Gras 				psenc->g[i].vers = string[sp->versoff];
6492fe8fb19SBen Gras 
6502fe8fb19SBen Gras 			string += sp->len;
6512fe8fb19SBen Gras 			n -= sp->len;
6522fe8fb19SBen Gras 			continue;
6532fe8fb19SBen Gras 		}
6542fe8fb19SBen Gras 
6552fe8fb19SBen Gras 		/* LS2/3 */
6562fe8fb19SBen Gras 		if (2 <= n && string[0] == '\033'
6572fe8fb19SBen Gras 		 && string[1] && strchr("no", string[1])) {
6582fe8fb19SBen Gras 			psenc->gl = string[1] - 'n' + 2;
6592fe8fb19SBen Gras 			string += 2;
6602fe8fb19SBen Gras 			n -= 2;
6612fe8fb19SBen Gras 			continue;
6622fe8fb19SBen Gras 		}
6632fe8fb19SBen Gras 
6642fe8fb19SBen Gras 		/* LS1/2/3R */
6652fe8fb19SBen Gras 			/* XXX: { for vi showmatch */
6662fe8fb19SBen Gras 		if (2 <= n && string[0] == '\033'
6672fe8fb19SBen Gras 		 && string[1] && strchr("~}|", string[1])) {
6682fe8fb19SBen Gras 			psenc->gr = 3 - (string[1] - '|');
6692fe8fb19SBen Gras 			string += 2;
6702fe8fb19SBen Gras 			n -= 2;
6712fe8fb19SBen Gras 			continue;
6722fe8fb19SBen Gras 		}
6732fe8fb19SBen Gras 
6742fe8fb19SBen Gras 		/* SS2/3 */
6752fe8fb19SBen Gras 		if (2 <= n && string[0] == '\033'
6762fe8fb19SBen Gras 		 && string[1] && strchr("NO", string[1])) {
6772fe8fb19SBen Gras 			psenc->singlegl = (string[1] - 'N') + 2;
6782fe8fb19SBen Gras 			string += 2;
6792fe8fb19SBen Gras 			n -= 2;
6802fe8fb19SBen Gras 			continue;
6812fe8fb19SBen Gras 		}
6822fe8fb19SBen Gras 
6832fe8fb19SBen Gras 	notseq:
6842fe8fb19SBen Gras 		/*
6852fe8fb19SBen Gras 		 * if we've got an unknown escape sequence, eat the ESC at the
6862fe8fb19SBen Gras 		 * head.  otherwise, wait till full escape sequence comes.
6872fe8fb19SBen Gras 		 */
6882fe8fb19SBen Gras 		for (sp = &seqtable[0]; sp->len; sp++) {
6892fe8fb19SBen Gras 			nmatch = seqmatch(string, n, sp);
6902fe8fb19SBen Gras 			if (!nmatch)
6912fe8fb19SBen Gras 				continue;
6922fe8fb19SBen Gras 
6932fe8fb19SBen Gras 			/*
6942fe8fb19SBen Gras 			 * if we are in the middle of escape sequence,
6952fe8fb19SBen Gras 			 * we still need to wait for more characters to come
6962fe8fb19SBen Gras 			 */
6972fe8fb19SBen Gras 			if (n < sp->len) {
6982fe8fb19SBen Gras 				if (nmatch == n) {
6992fe8fb19SBen Gras 					if (result)
7002fe8fb19SBen Gras 						*result = string;
7012fe8fb19SBen Gras 					return (_ISO2022INVALID);
7022fe8fb19SBen Gras 				}
7032fe8fb19SBen Gras 			} else {
7042fe8fb19SBen Gras 				if (nmatch == sp->len) {
7052fe8fb19SBen Gras 					/* this case should not happen */
7062fe8fb19SBen Gras 					goto eat;
7072fe8fb19SBen Gras 				}
7082fe8fb19SBen Gras 			}
7092fe8fb19SBen Gras 		}
7102fe8fb19SBen Gras 
7112fe8fb19SBen Gras 		break;
7122fe8fb19SBen Gras 	}
7132fe8fb19SBen Gras 
7142fe8fb19SBen Gras eat:
7152fe8fb19SBen Gras 	/* no letter to eat */
7162fe8fb19SBen Gras 	if (n < 1) {
7172fe8fb19SBen Gras 		if (result)
7182fe8fb19SBen Gras 			*result = string;
7192fe8fb19SBen Gras 		return (_ISO2022INVALID);
7202fe8fb19SBen Gras 	}
7212fe8fb19SBen Gras 
7222fe8fb19SBen Gras 	/* normal chars.  always eat C0/C1 as is. */
7232fe8fb19SBen Gras 	if (iscntl(*string & 0xff))
7242fe8fb19SBen Gras 		cur = -1;
7252fe8fb19SBen Gras 	else if (*string & 0x80) {
7262fe8fb19SBen Gras 		cur = (psenc->singlegr == -1)
7272fe8fb19SBen Gras 			? psenc->gr : psenc->singlegr;
7282fe8fb19SBen Gras 	} else {
7292fe8fb19SBen Gras 		cur = (psenc->singlegl == -1)
7302fe8fb19SBen Gras 			? psenc->gl : psenc->singlegl;
7312fe8fb19SBen Gras 	}
7322fe8fb19SBen Gras 
7332fe8fb19SBen Gras 	if (cur == -1) {
7342fe8fb19SBen Gras asis:
7352fe8fb19SBen Gras 		wchar = *string++ & 0xff;
7362fe8fb19SBen Gras 		if (result)
7372fe8fb19SBen Gras 			*result = string;
7382fe8fb19SBen Gras 		/* reset single shift state */
7392fe8fb19SBen Gras 		psenc->singlegr = psenc->singlegl = -1;
7402fe8fb19SBen Gras 		return wchar;
7412fe8fb19SBen Gras 	}
7422fe8fb19SBen Gras 
7432fe8fb19SBen Gras 	/* length error check */
7442fe8fb19SBen Gras 	switch (psenc->g[cur].type) {
7452fe8fb19SBen Gras 	case CS94MULTI:
7462fe8fb19SBen Gras 	case CS96MULTI:
7472fe8fb19SBen Gras 		if (!isthree(psenc->g[cur].final)) {
7482fe8fb19SBen Gras 			if (2 <= n
7492fe8fb19SBen Gras 			 && (string[0] & 0x80) == (string[1] & 0x80))
7502fe8fb19SBen Gras 				break;
7512fe8fb19SBen Gras 		} else {
7522fe8fb19SBen Gras 			if (3 <= n
7532fe8fb19SBen Gras 			 && (string[0] & 0x80) == (string[1] & 0x80)
7542fe8fb19SBen Gras 			 && (string[0] & 0x80) == (string[2] & 0x80))
7552fe8fb19SBen Gras 				break;
7562fe8fb19SBen Gras 		}
7572fe8fb19SBen Gras 
7582fe8fb19SBen Gras 		/* we still need to wait for more characters to come */
7592fe8fb19SBen Gras 		if (result)
7602fe8fb19SBen Gras 			*result = string;
7612fe8fb19SBen Gras 		return (_ISO2022INVALID);
7622fe8fb19SBen Gras 
7632fe8fb19SBen Gras 	case CS94:
7642fe8fb19SBen Gras 	case CS96:
7652fe8fb19SBen Gras 		if (1 <= n)
7662fe8fb19SBen Gras 			break;
7672fe8fb19SBen Gras 
7682fe8fb19SBen Gras 		/* we still need to wait for more characters to come */
7692fe8fb19SBen Gras 		if (result)
7702fe8fb19SBen Gras 			*result = string;
7712fe8fb19SBen Gras 		return (_ISO2022INVALID);
7722fe8fb19SBen Gras 	}
7732fe8fb19SBen Gras 
7742fe8fb19SBen Gras 	/* range check */
7752fe8fb19SBen Gras 	switch (psenc->g[cur].type) {
7762fe8fb19SBen Gras 	case CS94:
7772fe8fb19SBen Gras 		if (!(is94(string[0] & 0x7f)))
7782fe8fb19SBen Gras 			goto asis;
7792fe8fb19SBen Gras 	case CS96:
7802fe8fb19SBen Gras 		if (!(is96(string[0] & 0x7f)))
7812fe8fb19SBen Gras 			goto asis;
7822fe8fb19SBen Gras 		break;
7832fe8fb19SBen Gras 	case CS94MULTI:
7842fe8fb19SBen Gras 		if (!(is94(string[0] & 0x7f) && is94(string[1] & 0x7f)))
7852fe8fb19SBen Gras 			goto asis;
7862fe8fb19SBen Gras 		break;
7872fe8fb19SBen Gras 	case CS96MULTI:
7882fe8fb19SBen Gras 		if (!(is96(string[0] & 0x7f) && is96(string[1] & 0x7f)))
7892fe8fb19SBen Gras 			goto asis;
7902fe8fb19SBen Gras 		break;
7912fe8fb19SBen Gras 	}
7922fe8fb19SBen Gras 
7932fe8fb19SBen Gras 	/* extract the character. */
7942fe8fb19SBen Gras 	switch (psenc->g[cur].type) {
7952fe8fb19SBen Gras 	case CS94:
7962fe8fb19SBen Gras 		/* special case for ASCII. */
7972fe8fb19SBen Gras 		if (psenc->g[cur].final == 'B' && !psenc->g[cur].interm) {
7982fe8fb19SBen Gras 			wchar = *string++;
7992fe8fb19SBen Gras 			wchar &= 0x7f;
8002fe8fb19SBen Gras 			break;
8012fe8fb19SBen Gras 		}
8022fe8fb19SBen Gras 		wchar = psenc->g[cur].final;
8032fe8fb19SBen Gras 		wchar = (wchar << 8);
8042fe8fb19SBen Gras 		wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
8052fe8fb19SBen Gras 		wchar = (wchar << 8);
8062fe8fb19SBen Gras 		wchar = (wchar << 8) | (*string++ & 0x7f);
8072fe8fb19SBen Gras 		break;
8082fe8fb19SBen Gras 	case CS96:
8092fe8fb19SBen Gras 		/* special case for ISO-8859-1. */
8102fe8fb19SBen Gras 		if (psenc->g[cur].final == 'A' && !psenc->g[cur].interm) {
8112fe8fb19SBen Gras 			wchar = *string++;
8122fe8fb19SBen Gras 			wchar &= 0x7f;
8132fe8fb19SBen Gras 			wchar |= 0x80;
8142fe8fb19SBen Gras 			break;
8152fe8fb19SBen Gras 		}
8162fe8fb19SBen Gras 		wchar = psenc->g[cur].final;
8172fe8fb19SBen Gras 		wchar = (wchar << 8);
8182fe8fb19SBen Gras 		wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
8192fe8fb19SBen Gras 		wchar = (wchar << 8);
8202fe8fb19SBen Gras 		wchar = (wchar << 8) | (*string++ & 0x7f);
8212fe8fb19SBen Gras 		wchar |= 0x80;
8222fe8fb19SBen Gras 		break;
8232fe8fb19SBen Gras 	case CS94MULTI:
8242fe8fb19SBen Gras 	case CS96MULTI:
8252fe8fb19SBen Gras 		wchar = psenc->g[cur].final;
8262fe8fb19SBen Gras 		wchar = (wchar << 8);
8272fe8fb19SBen Gras 		if (isthree(psenc->g[cur].final))
8282fe8fb19SBen Gras 			wchar |= (*string++ & 0x7f);
8292fe8fb19SBen Gras 		wchar = (wchar << 8) | (*string++ & 0x7f);
8302fe8fb19SBen Gras 		wchar = (wchar << 8) | (*string++ & 0x7f);
8312fe8fb19SBen Gras 		if (psenc->g[cur].type == CS96MULTI)
8322fe8fb19SBen Gras 			wchar |= 0x80;
8332fe8fb19SBen Gras 		break;
8342fe8fb19SBen Gras 	}
8352fe8fb19SBen Gras 
8362fe8fb19SBen Gras 	if (result)
8372fe8fb19SBen Gras 		*result = string;
8382fe8fb19SBen Gras 	/* reset single shift state */
8392fe8fb19SBen Gras 	psenc->singlegr = psenc->singlegl = -1;
8402fe8fb19SBen Gras 	return wchar;
8412fe8fb19SBen Gras }
8422fe8fb19SBen Gras 
8432fe8fb19SBen Gras 
8442fe8fb19SBen Gras 
8452fe8fb19SBen Gras static int
_citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * __restrict ei,wchar_t * __restrict pwc,const char ** __restrict s,size_t n,_ISO2022State * __restrict psenc,size_t * __restrict nresult)8462fe8fb19SBen Gras _citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * __restrict ei,
8472fe8fb19SBen Gras 			     wchar_t * __restrict pwc,
8482fe8fb19SBen Gras 			     const char ** __restrict s,
8492fe8fb19SBen Gras 			     size_t n, _ISO2022State * __restrict psenc,
8502fe8fb19SBen Gras 			     size_t * __restrict nresult)
8512fe8fb19SBen Gras {
8522fe8fb19SBen Gras 	wchar_t wchar;
8532fe8fb19SBen Gras 	const char *s0, *p, *result;
8542fe8fb19SBen Gras 	int c;
8552fe8fb19SBen Gras 	int chlenbak;
8562fe8fb19SBen Gras 
8572fe8fb19SBen Gras 	_DIAGASSERT(nresult != 0);
8582fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
8592fe8fb19SBen Gras 	_DIAGASSERT(psenc != NULL);
8602fe8fb19SBen Gras 	_DIAGASSERT(s != NULL);
8612fe8fb19SBen Gras 
8622fe8fb19SBen Gras 	if (*s == NULL) {
8632fe8fb19SBen Gras 		_citrus_ISO2022_init_state(ei, psenc);
8642fe8fb19SBen Gras 		*nresult = _ENCODING_IS_STATE_DEPENDENT;
8652fe8fb19SBen Gras 		return 0;
8662fe8fb19SBen Gras 	}
8672fe8fb19SBen Gras 	s0 = *s;
8682fe8fb19SBen Gras 	c = 0;
8692fe8fb19SBen Gras 	chlenbak = psenc->chlen;
8702fe8fb19SBen Gras 
8712fe8fb19SBen Gras 	/*
8722fe8fb19SBen Gras 	 * if we have something in buffer, use that.
8732fe8fb19SBen Gras 	 * otherwise, skip here
8742fe8fb19SBen Gras 	 */
8752fe8fb19SBen Gras 	if (psenc->chlen < 0 || psenc->chlen > sizeof(psenc->ch)) {
8762fe8fb19SBen Gras 		/* illgeal state */
8772fe8fb19SBen Gras 		_citrus_ISO2022_init_state(ei, psenc);
8782fe8fb19SBen Gras 		goto encoding_error;
8792fe8fb19SBen Gras 	}
8802fe8fb19SBen Gras 	if (psenc->chlen == 0)
8812fe8fb19SBen Gras 		goto emptybuf;
8822fe8fb19SBen Gras 
8832fe8fb19SBen Gras 	/* buffer is not empty */
8842fe8fb19SBen Gras 	p = psenc->ch;
8852fe8fb19SBen Gras 	while (psenc->chlen < sizeof(psenc->ch)) {
8862fe8fb19SBen Gras 		if (n > 0) {
8872fe8fb19SBen Gras 			psenc->ch[psenc->chlen++] = *s0++;
8882fe8fb19SBen Gras 			n--;
8892fe8fb19SBen Gras 		}
8902fe8fb19SBen Gras 
8912fe8fb19SBen Gras 		wchar = _ISO2022_sgetwchar(ei, p, psenc->chlen - (p-psenc->ch),
8922fe8fb19SBen Gras 					   &result, psenc);
8932fe8fb19SBen Gras 		c += result - p;
8942fe8fb19SBen Gras 		if (wchar != _ISO2022INVALID) {
8952fe8fb19SBen Gras 			if (psenc->chlen > c)
8962fe8fb19SBen Gras 				memmove(psenc->ch, result, psenc->chlen - c);
8972fe8fb19SBen Gras 			if (psenc->chlen < c)
8982fe8fb19SBen Gras 				psenc->chlen = 0;
8992fe8fb19SBen Gras 			else
9002fe8fb19SBen Gras 				psenc->chlen -= c;
9012fe8fb19SBen Gras 			goto output;
9022fe8fb19SBen Gras 		}
9032fe8fb19SBen Gras 
9042fe8fb19SBen Gras 		if (n == 0) {
9052fe8fb19SBen Gras 			if ((result - p) == psenc->chlen)
9062fe8fb19SBen Gras 				/* complete shift sequence. */
9072fe8fb19SBen Gras 				psenc->chlen = 0;
9082fe8fb19SBen Gras 			goto restart;
9092fe8fb19SBen Gras 		}
9102fe8fb19SBen Gras 
9112fe8fb19SBen Gras 		p = result;
9122fe8fb19SBen Gras 	}
9132fe8fb19SBen Gras 
9142fe8fb19SBen Gras 	/* escape sequence too long? */
9152fe8fb19SBen Gras 	goto encoding_error;
9162fe8fb19SBen Gras 
9172fe8fb19SBen Gras emptybuf:
9182fe8fb19SBen Gras 	wchar = _ISO2022_sgetwchar(ei, s0, n, &result, psenc);
9192fe8fb19SBen Gras 	if (wchar != _ISO2022INVALID) {
9202fe8fb19SBen Gras 		c += result - s0;
9212fe8fb19SBen Gras 		psenc->chlen = 0;
9222fe8fb19SBen Gras 		s0 = result;
9232fe8fb19SBen Gras 		goto output;
9242fe8fb19SBen Gras 	}
9252fe8fb19SBen Gras 	if (result > s0) {
9262fe8fb19SBen Gras 		c += (result - s0);
9272fe8fb19SBen Gras 		n -= (result - s0);
9282fe8fb19SBen Gras 		s0 = result;
9292fe8fb19SBen Gras 		if (n>0)
9302fe8fb19SBen Gras 			goto emptybuf;
9312fe8fb19SBen Gras 		/* complete shift sequence. */
9322fe8fb19SBen Gras 		goto restart;
9332fe8fb19SBen Gras 	}
9342fe8fb19SBen Gras 	n += c;
9352fe8fb19SBen Gras 	if (n < sizeof(psenc->ch)) {
9362fe8fb19SBen Gras 		memcpy(psenc->ch, s0 - c, n);
9372fe8fb19SBen Gras 		psenc->chlen = n;
9382fe8fb19SBen Gras 		s0 = result;
9392fe8fb19SBen Gras 		goto restart;
9402fe8fb19SBen Gras 	}
9412fe8fb19SBen Gras 
9422fe8fb19SBen Gras 	/* escape sequence too long? */
9432fe8fb19SBen Gras 
9442fe8fb19SBen Gras encoding_error:
9452fe8fb19SBen Gras 	psenc->chlen = 0;
9462fe8fb19SBen Gras 	*nresult = (size_t)-1;
9472fe8fb19SBen Gras 	return (EILSEQ);
9482fe8fb19SBen Gras 
9492fe8fb19SBen Gras output:
9502fe8fb19SBen Gras 	*s = s0;
9512fe8fb19SBen Gras 	if (pwc)
9522fe8fb19SBen Gras 		*pwc = wchar;
9532fe8fb19SBen Gras 
9542fe8fb19SBen Gras 	if (!wchar)
9552fe8fb19SBen Gras 		*nresult = 0;
9562fe8fb19SBen Gras 	else
9572fe8fb19SBen Gras 		*nresult = c - chlenbak;
9582fe8fb19SBen Gras 
9592fe8fb19SBen Gras 	return (0);
9602fe8fb19SBen Gras 
9612fe8fb19SBen Gras restart:
9622fe8fb19SBen Gras 	*s = s0;
9632fe8fb19SBen Gras 	*nresult = (size_t)-2;
9642fe8fb19SBen Gras 
9652fe8fb19SBen Gras 	return (0);
9662fe8fb19SBen Gras }
9672fe8fb19SBen Gras 
9682fe8fb19SBen Gras static int
recommendation(_ISO2022EncodingInfo * __restrict ei,_ISO2022Charset * __restrict cs)9692fe8fb19SBen Gras recommendation(_ISO2022EncodingInfo * __restrict ei,
9702fe8fb19SBen Gras 	       _ISO2022Charset * __restrict cs)
9712fe8fb19SBen Gras {
9722fe8fb19SBen Gras 	int i, j;
9732fe8fb19SBen Gras 	_ISO2022Charset *recommend;
9742fe8fb19SBen Gras 
9752fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
9762fe8fb19SBen Gras 	_DIAGASSERT(cs != NULL);
9772fe8fb19SBen Gras 
9782fe8fb19SBen Gras 	/* first, try a exact match. */
9792fe8fb19SBen Gras 	for (i = 0; i < 4; i++) {
9802fe8fb19SBen Gras 		recommend = ei->recommend[i];
9812fe8fb19SBen Gras 		for (j = 0; j < ei->recommendsize[i]; j++) {
9822fe8fb19SBen Gras 			if (cs->type != recommend[j].type)
9832fe8fb19SBen Gras 				continue;
9842fe8fb19SBen Gras 			if (cs->final != recommend[j].final)
9852fe8fb19SBen Gras 				continue;
9862fe8fb19SBen Gras 			if (cs->interm != recommend[j].interm)
9872fe8fb19SBen Gras 				continue;
9882fe8fb19SBen Gras 
9892fe8fb19SBen Gras 			return i;
9902fe8fb19SBen Gras 		}
9912fe8fb19SBen Gras 	}
9922fe8fb19SBen Gras 
9932fe8fb19SBen Gras 	/* then, try a wildcard match over final char. */
9942fe8fb19SBen Gras 	for (i = 0; i < 4; i++) {
9952fe8fb19SBen Gras 		recommend = ei->recommend[i];
9962fe8fb19SBen Gras 		for (j = 0; j < ei->recommendsize[i]; j++) {
9972fe8fb19SBen Gras 			if (cs->type != recommend[j].type)
9982fe8fb19SBen Gras 				continue;
9992fe8fb19SBen Gras 			if (cs->final && (cs->final != recommend[j].final))
10002fe8fb19SBen Gras 				continue;
10012fe8fb19SBen Gras 			if (cs->interm && (cs->interm != recommend[j].interm))
10022fe8fb19SBen Gras 				continue;
10032fe8fb19SBen Gras 
10042fe8fb19SBen Gras 			return i;
10052fe8fb19SBen Gras 		}
10062fe8fb19SBen Gras 	}
10072fe8fb19SBen Gras 
10082fe8fb19SBen Gras 	/* there's no recommendation. make a guess. */
10092fe8fb19SBen Gras 	if (ei->maxcharset == 0) {
10102fe8fb19SBen Gras 		return 0;
10112fe8fb19SBen Gras 	} else {
10122fe8fb19SBen Gras 		switch (cs->type) {
10132fe8fb19SBen Gras 		case CS94:
10142fe8fb19SBen Gras 		case CS94MULTI:
10152fe8fb19SBen Gras 			return 0;
10162fe8fb19SBen Gras 		case CS96:
10172fe8fb19SBen Gras 		case CS96MULTI:
10182fe8fb19SBen Gras 			return 1;
10192fe8fb19SBen Gras 		}
10202fe8fb19SBen Gras 	}
10212fe8fb19SBen Gras 	return 0;
10222fe8fb19SBen Gras }
10232fe8fb19SBen Gras 
10242fe8fb19SBen Gras static int
_ISO2022_sputwchar(_ISO2022EncodingInfo * __restrict ei,wchar_t wc,char * __restrict string,size_t n,char ** __restrict result,_ISO2022State * __restrict psenc,size_t * __restrict nresult)10252fe8fb19SBen Gras _ISO2022_sputwchar(_ISO2022EncodingInfo * __restrict ei, wchar_t wc,
10262fe8fb19SBen Gras 		   char * __restrict string, size_t n,
10272fe8fb19SBen Gras 		   char ** __restrict result,
10282fe8fb19SBen Gras 		   _ISO2022State * __restrict psenc,
10292fe8fb19SBen Gras 		   size_t * __restrict nresult)
10302fe8fb19SBen Gras {
10312fe8fb19SBen Gras 	int i = 0;
10322fe8fb19SBen Gras 	size_t len;
10332fe8fb19SBen Gras 	_ISO2022Charset cs;
10342fe8fb19SBen Gras 	char *p;
10352fe8fb19SBen Gras 	char tmp[MB_LEN_MAX];
10362fe8fb19SBen Gras 	int target;
10372fe8fb19SBen Gras 	u_char mask;
10382fe8fb19SBen Gras 	int bit8;
10392fe8fb19SBen Gras 
10402fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
10412fe8fb19SBen Gras 	_DIAGASSERT(string != NULL);
10422fe8fb19SBen Gras 	/* result may be NULL */
10432fe8fb19SBen Gras 	_DIAGASSERT(psenc != NULL);
10442fe8fb19SBen Gras 	_DIAGASSERT(nresult != NULL);
10452fe8fb19SBen Gras 
10462fe8fb19SBen Gras 	if (isc0(wc & 0xff)) {
10472fe8fb19SBen Gras 		/* go back to INIT0 or ASCII on control chars */
10482fe8fb19SBen Gras 		cs = ei->initg[0].final ? ei->initg[0] : ascii;
10492fe8fb19SBen Gras 	} else if (isc1(wc & 0xff)) {
10502fe8fb19SBen Gras 		/* go back to INIT1 or ISO-8859-1 on control chars */
10512fe8fb19SBen Gras 		cs = ei->initg[1].final ? ei->initg[1] : iso88591;
10522fe8fb19SBen Gras 	} else if (!(wc & ~0xff)) {
10532fe8fb19SBen Gras 		if (wc & 0x80) {
10542fe8fb19SBen Gras 			/* special treatment for ISO-8859-1 */
10552fe8fb19SBen Gras 			cs = iso88591;
10562fe8fb19SBen Gras 		} else {
10572fe8fb19SBen Gras 			/* special treatment for ASCII */
10582fe8fb19SBen Gras 			cs = ascii;
10592fe8fb19SBen Gras 		}
10602fe8fb19SBen Gras 	} else {
10612fe8fb19SBen Gras 		cs.final = (wc >> 24) & 0x7f;
10622fe8fb19SBen Gras 		if ((wc >> 16) & 0x80)
10632fe8fb19SBen Gras 			cs.interm = (wc >> 16) & 0x7f;
10642fe8fb19SBen Gras 		else
10652fe8fb19SBen Gras 			cs.interm = '\0';
10662fe8fb19SBen Gras 		if (wc & 0x80)
10672fe8fb19SBen Gras 			cs.type = (wc & 0x00007f00) ? CS96MULTI : CS96;
10682fe8fb19SBen Gras 		else
10692fe8fb19SBen Gras 			cs.type = (wc & 0x00007f00) ? CS94MULTI : CS94;
10702fe8fb19SBen Gras 	}
10712fe8fb19SBen Gras 	target = recommendation(ei, &cs);
10722fe8fb19SBen Gras 	p = tmp;
10732fe8fb19SBen Gras 	bit8 = ei->flags & F_8BIT;
10742fe8fb19SBen Gras 
10752fe8fb19SBen Gras 	/* designate the charset onto the target plane(G0/1/2/3). */
10762fe8fb19SBen Gras 	if (psenc->g[target].type == cs.type
10772fe8fb19SBen Gras 	 && psenc->g[target].final == cs.final
10782fe8fb19SBen Gras 	 && psenc->g[target].interm == cs.interm)
10792fe8fb19SBen Gras 		goto planeok;
10802fe8fb19SBen Gras 
10812fe8fb19SBen Gras 	*p++ = '\033';
10822fe8fb19SBen Gras 	if (cs.type == CS94MULTI || cs.type == CS96MULTI)
10832fe8fb19SBen Gras 		*p++ = '$';
10842fe8fb19SBen Gras 	if (target == 0 && cs.type == CS94MULTI && strchr("@AB", cs.final)
10852fe8fb19SBen Gras 	 && !cs.interm && !(ei->flags & F_NOOLD))
10862fe8fb19SBen Gras 		;
10872fe8fb19SBen Gras 	else if (cs.type == CS94 || cs.type == CS94MULTI)
10882fe8fb19SBen Gras 		*p++ = "()*+"[target];
10892fe8fb19SBen Gras 	else
10902fe8fb19SBen Gras 		*p++ = ",-./"[target];
10912fe8fb19SBen Gras 	if (cs.interm)
10922fe8fb19SBen Gras 		*p++ = cs.interm;
10932fe8fb19SBen Gras 	*p++ = cs.final;
10942fe8fb19SBen Gras 
10952fe8fb19SBen Gras 	psenc->g[target].type = cs.type;
10962fe8fb19SBen Gras 	psenc->g[target].final = cs.final;
10972fe8fb19SBen Gras 	psenc->g[target].interm = cs.interm;
10982fe8fb19SBen Gras 
10992fe8fb19SBen Gras planeok:
11002fe8fb19SBen Gras 	/* invoke the plane onto GL or GR. */
11012fe8fb19SBen Gras 	if (psenc->gl == target)
11022fe8fb19SBen Gras 		goto sideok;
11032fe8fb19SBen Gras 	if (bit8 && psenc->gr == target)
11042fe8fb19SBen Gras 		goto sideok;
11052fe8fb19SBen Gras 
11062fe8fb19SBen Gras 	if (target == 0 && (ei->flags & F_LS0)) {
11072fe8fb19SBen Gras 		*p++ = '\017';
11082fe8fb19SBen Gras 		psenc->gl = 0;
11092fe8fb19SBen Gras 	} else if (target == 1 && (ei->flags & F_LS1)) {
11102fe8fb19SBen Gras 		*p++ = '\016';
11112fe8fb19SBen Gras 		psenc->gl = 1;
11122fe8fb19SBen Gras 	} else if (target == 2 && (ei->flags & F_LS2)) {
11132fe8fb19SBen Gras 		*p++ = '\033';
11142fe8fb19SBen Gras 		*p++ = 'n';
11152fe8fb19SBen Gras 		psenc->gl = 2;
11162fe8fb19SBen Gras 	} else if (target == 3 && (ei->flags & F_LS3)) {
11172fe8fb19SBen Gras 		*p++ = '\033';
11182fe8fb19SBen Gras 		*p++ = 'o';
11192fe8fb19SBen Gras 		psenc->gl = 3;
11202fe8fb19SBen Gras 	} else if (bit8 && target == 1 && (ei->flags & F_LS1R)) {
11212fe8fb19SBen Gras 		*p++ = '\033';
11222fe8fb19SBen Gras 		*p++ = '~';
11232fe8fb19SBen Gras 		psenc->gr = 1;
11242fe8fb19SBen Gras 	} else if (bit8 && target == 2 && (ei->flags & F_LS2R)) {
11252fe8fb19SBen Gras 		*p++ = '\033';
11262fe8fb19SBen Gras 		/*{*/
11272fe8fb19SBen Gras 		*p++ = '}';
11282fe8fb19SBen Gras 		psenc->gr = 2;
11292fe8fb19SBen Gras 	} else if (bit8 && target == 3 && (ei->flags & F_LS3R)) {
11302fe8fb19SBen Gras 		*p++ = '\033';
11312fe8fb19SBen Gras 		*p++ = '|';
11322fe8fb19SBen Gras 		psenc->gr = 3;
11332fe8fb19SBen Gras 	} else if (target == 2 && (ei->flags & F_SS2)) {
11342fe8fb19SBen Gras 		*p++ = '\033';
11352fe8fb19SBen Gras 		*p++ = 'N';
11362fe8fb19SBen Gras 		psenc->singlegl = 2;
11372fe8fb19SBen Gras 	} else if (target == 3 && (ei->flags & F_SS3)) {
11382fe8fb19SBen Gras 		*p++ = '\033';
11392fe8fb19SBen Gras 		*p++ = 'O';
11402fe8fb19SBen Gras 		psenc->singlegl = 3;
11412fe8fb19SBen Gras 	} else if (bit8 && target == 2 && (ei->flags & F_SS2R)) {
11422fe8fb19SBen Gras 		*p++ = '\216';
11432fe8fb19SBen Gras 		*p++ = 'N';
11442fe8fb19SBen Gras 		psenc->singlegl = psenc->singlegr = 2;
11452fe8fb19SBen Gras 	} else if (bit8 && target == 3 && (ei->flags & F_SS3R)) {
11462fe8fb19SBen Gras 		*p++ = '\217';
11472fe8fb19SBen Gras 		*p++ = 'O';
11482fe8fb19SBen Gras 		psenc->singlegl = psenc->singlegr = 3;
11492fe8fb19SBen Gras 	} else
11502fe8fb19SBen Gras 		goto ilseq;
11512fe8fb19SBen Gras 
11522fe8fb19SBen Gras sideok:
11532fe8fb19SBen Gras 	if (psenc->singlegl == target)
11542fe8fb19SBen Gras 		mask = 0x00;
11552fe8fb19SBen Gras 	else if (psenc->singlegr == target)
11562fe8fb19SBen Gras 		mask = 0x80;
11572fe8fb19SBen Gras 	else if (psenc->gl == target)
11582fe8fb19SBen Gras 		mask = 0x00;
11592fe8fb19SBen Gras 	else if ((ei->flags & F_8BIT) && psenc->gr == target)
11602fe8fb19SBen Gras 		mask = 0x80;
11612fe8fb19SBen Gras 	else
11622fe8fb19SBen Gras 		goto ilseq;
11632fe8fb19SBen Gras 
11642fe8fb19SBen Gras 	switch (cs.type) {
11652fe8fb19SBen Gras 	case CS94:
11662fe8fb19SBen Gras 	case CS96:
11672fe8fb19SBen Gras 		i = 1;
11682fe8fb19SBen Gras 		break;
11692fe8fb19SBen Gras 	case CS94MULTI:
11702fe8fb19SBen Gras 	case CS96MULTI:
11712fe8fb19SBen Gras 		i = !iscntl(wc & 0xff) ?
11722fe8fb19SBen Gras 		    (isthree(cs.final) ? 3 : 2) : 1;
11732fe8fb19SBen Gras 		break;
11742fe8fb19SBen Gras 	}
11752fe8fb19SBen Gras 	while (i-- > 0)
11762fe8fb19SBen Gras 		*p++ = ((wc >> (i << 3)) & 0x7f) | mask;
11772fe8fb19SBen Gras 
11782fe8fb19SBen Gras 	/* reset single shift state */
11792fe8fb19SBen Gras 	psenc->singlegl = psenc->singlegr = -1;
11802fe8fb19SBen Gras 
11812fe8fb19SBen Gras 	len = (size_t)(p - tmp);
11822fe8fb19SBen Gras 	if (n < len) {
11832fe8fb19SBen Gras 		if (result)
11842fe8fb19SBen Gras 			*result = (char *)0;
11852fe8fb19SBen Gras 		*nresult = (size_t)-1;
11862fe8fb19SBen Gras 		return E2BIG;
11872fe8fb19SBen Gras 	}
11882fe8fb19SBen Gras 	if (result)
11892fe8fb19SBen Gras 		*result = string + len;
11902fe8fb19SBen Gras 	memcpy(string, tmp, len);
11912fe8fb19SBen Gras 	*nresult = len;
11922fe8fb19SBen Gras 
11932fe8fb19SBen Gras 	return 0;
11942fe8fb19SBen Gras 
11952fe8fb19SBen Gras ilseq:
11962fe8fb19SBen Gras 	*nresult = (size_t)-1;
11972fe8fb19SBen Gras 	return EILSEQ;
11982fe8fb19SBen Gras }
11992fe8fb19SBen Gras 
12002fe8fb19SBen Gras static int
_citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * __restrict ei,char * __restrict s,size_t n,_ISO2022State * __restrict psenc,size_t * __restrict nresult)12012fe8fb19SBen Gras _citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * __restrict ei,
12022fe8fb19SBen Gras 				char * __restrict s, size_t n,
12032fe8fb19SBen Gras 				_ISO2022State * __restrict psenc,
12042fe8fb19SBen Gras 				size_t * __restrict nresult)
12052fe8fb19SBen Gras {
12062fe8fb19SBen Gras 	char buf[MB_LEN_MAX];
12072fe8fb19SBen Gras 	char *result;
12082fe8fb19SBen Gras 	int ret;
12092fe8fb19SBen Gras 	size_t len;
12102fe8fb19SBen Gras 
12112fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
12122fe8fb19SBen Gras 	_DIAGASSERT(nresult != 0);
12132fe8fb19SBen Gras 	_DIAGASSERT(s != NULL);
12142fe8fb19SBen Gras 
12152fe8fb19SBen Gras 	/* XXX state will be modified after this operation... */
12162fe8fb19SBen Gras 	ret = _ISO2022_sputwchar(ei, L'\0', buf, sizeof(buf), &result, psenc,
12172fe8fb19SBen Gras 	    &len);
12182fe8fb19SBen Gras 	if (ret) {
12192fe8fb19SBen Gras 		*nresult = len;
12202fe8fb19SBen Gras 		return ret;
12212fe8fb19SBen Gras 	}
12222fe8fb19SBen Gras 
12232fe8fb19SBen Gras 	if (sizeof(buf) < len || n < len-1) {
12242fe8fb19SBen Gras 		/* XXX should recover state? */
12252fe8fb19SBen Gras 		*nresult = (size_t)-1;
12262fe8fb19SBen Gras 		return E2BIG;
12272fe8fb19SBen Gras 	}
12282fe8fb19SBen Gras 
12292fe8fb19SBen Gras 	memcpy(s, buf, len-1);
12302fe8fb19SBen Gras 	*nresult = len-1;
12312fe8fb19SBen Gras 	return (0);
12322fe8fb19SBen Gras }
12332fe8fb19SBen Gras 
12342fe8fb19SBen Gras static int
_citrus_ISO2022_wcrtomb_priv(_ISO2022EncodingInfo * __restrict ei,char * __restrict s,size_t n,wchar_t wc,_ISO2022State * __restrict psenc,size_t * __restrict nresult)12352fe8fb19SBen Gras _citrus_ISO2022_wcrtomb_priv(_ISO2022EncodingInfo * __restrict ei,
12362fe8fb19SBen Gras 			     char * __restrict s, size_t n, wchar_t wc,
12372fe8fb19SBen Gras 			     _ISO2022State * __restrict psenc,
12382fe8fb19SBen Gras 			     size_t * __restrict nresult)
12392fe8fb19SBen Gras {
12402fe8fb19SBen Gras 	char buf[MB_LEN_MAX];
12412fe8fb19SBen Gras 	char *result;
12422fe8fb19SBen Gras 	int ret;
12432fe8fb19SBen Gras 	size_t len;
12442fe8fb19SBen Gras 
12452fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL);
12462fe8fb19SBen Gras 	_DIAGASSERT(s != NULL);
12472fe8fb19SBen Gras 	_DIAGASSERT(psenc != NULL);
12482fe8fb19SBen Gras 	_DIAGASSERT(nresult != 0);
12492fe8fb19SBen Gras 
12502fe8fb19SBen Gras 	/* XXX state will be modified after this operation... */
12512fe8fb19SBen Gras 	ret = _ISO2022_sputwchar(ei, wc, buf, sizeof(buf), &result, psenc,
12522fe8fb19SBen Gras 	    &len);
12532fe8fb19SBen Gras 	if (ret) {
12542fe8fb19SBen Gras 		*nresult = len;
12552fe8fb19SBen Gras 		return ret;
12562fe8fb19SBen Gras 	}
12572fe8fb19SBen Gras 
12582fe8fb19SBen Gras 	if (sizeof(buf) < len || n < len) {
12592fe8fb19SBen Gras 		/* XXX should recover state? */
12602fe8fb19SBen Gras 		*nresult = (size_t)-1;
12612fe8fb19SBen Gras 		return E2BIG;
12622fe8fb19SBen Gras 	}
12632fe8fb19SBen Gras 
12642fe8fb19SBen Gras 	memcpy(s, buf, len);
12652fe8fb19SBen Gras 	*nresult = len;
12662fe8fb19SBen Gras 	return (0);
12672fe8fb19SBen Gras }
12682fe8fb19SBen Gras 
12692fe8fb19SBen Gras static __inline int
12702fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * __restrict ei,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)12712fe8fb19SBen Gras _citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * __restrict ei,
12722fe8fb19SBen Gras 			      _csid_t * __restrict csid,
12732fe8fb19SBen Gras 			      _index_t * __restrict idx, wchar_t wc)
12742fe8fb19SBen Gras {
12752fe8fb19SBen Gras 	wchar_t m, nm;
12762fe8fb19SBen Gras 
12772fe8fb19SBen Gras 	_DIAGASSERT(csid != NULL && idx != NULL);
12782fe8fb19SBen Gras 
12792fe8fb19SBen Gras 	m = wc & 0x7FFF8080;
12802fe8fb19SBen Gras 	nm = wc & 0x007F7F7F;
12812fe8fb19SBen Gras 	if (m & 0x00800000) {
12822fe8fb19SBen Gras 		nm &= 0x00007F7F;
12832fe8fb19SBen Gras 	} else {
12842fe8fb19SBen Gras 		m &= 0x7F008080;
12852fe8fb19SBen Gras 	}
12862fe8fb19SBen Gras 	if (nm & 0x007F0000) {
12872fe8fb19SBen Gras 		/* ^3 mark */
12882fe8fb19SBen Gras 		m |= 0x007F0000;
12892fe8fb19SBen Gras 	} else if (nm & 0x00007F00) {
12902fe8fb19SBen Gras 		/* ^2 mark */
12912fe8fb19SBen Gras 		m |= 0x00007F00;
12922fe8fb19SBen Gras 	}
12932fe8fb19SBen Gras 	*csid = (_csid_t)m;
12942fe8fb19SBen Gras 	*idx  = (_index_t)nm;
12952fe8fb19SBen Gras 
12962fe8fb19SBen Gras 	return (0);
12972fe8fb19SBen Gras }
12982fe8fb19SBen Gras 
12992fe8fb19SBen Gras static __inline int
13002fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * __restrict ei,wchar_t * __restrict wc,_csid_t csid,_index_t idx)13012fe8fb19SBen Gras _citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * __restrict ei,
13022fe8fb19SBen Gras 			      wchar_t * __restrict wc,
13032fe8fb19SBen Gras 			      _csid_t csid, _index_t idx)
13042fe8fb19SBen Gras {
13052fe8fb19SBen Gras 
13062fe8fb19SBen Gras 	_DIAGASSERT(ei != NULL && wc != NULL);
13072fe8fb19SBen Gras 
13082fe8fb19SBen Gras 	*wc = (wchar_t)(csid & 0x7F808080) | (wchar_t)idx;
13092fe8fb19SBen Gras 
13102fe8fb19SBen Gras 	return (0);
13112fe8fb19SBen Gras }
13122fe8fb19SBen Gras 
13132fe8fb19SBen Gras static __inline int
13142fe8fb19SBen Gras /*ARGSUSED*/
_citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict psenc,int * __restrict rstate)13152fe8fb19SBen Gras _citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * __restrict ei,
13162fe8fb19SBen Gras 					      _ISO2022State * __restrict psenc,
13172fe8fb19SBen Gras 					      int * __restrict rstate)
13182fe8fb19SBen Gras {
13192fe8fb19SBen Gras 
13202fe8fb19SBen Gras 	if (psenc->chlen == 0) {
13212fe8fb19SBen Gras 		/* XXX: it should distinguish initial and stable. */
13222fe8fb19SBen Gras 		*rstate = _STDENC_SDGEN_STABLE;
13232fe8fb19SBen Gras 	} else {
13242fe8fb19SBen Gras 		if (psenc->ch[0] == '\033')
13252fe8fb19SBen Gras 			*rstate = _STDENC_SDGEN_INCOMPLETE_SHIFT;
13262fe8fb19SBen Gras 		else
13272fe8fb19SBen Gras 			*rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
13282fe8fb19SBen Gras 	}
13292fe8fb19SBen Gras 
13302fe8fb19SBen Gras 	return 0;
13312fe8fb19SBen Gras }
13322fe8fb19SBen Gras 
13332fe8fb19SBen Gras /* ----------------------------------------------------------------------
13342fe8fb19SBen Gras  * public interface for ctype
13352fe8fb19SBen Gras  */
13362fe8fb19SBen Gras 
13372fe8fb19SBen Gras _CITRUS_CTYPE_DECLS(ISO2022);
13382fe8fb19SBen Gras _CITRUS_CTYPE_DEF_OPS(ISO2022);
13392fe8fb19SBen Gras 
13402fe8fb19SBen Gras #include "citrus_ctype_template.h"
13412fe8fb19SBen Gras 
13422fe8fb19SBen Gras /* ----------------------------------------------------------------------
13432fe8fb19SBen Gras  * public interface for stdenc
13442fe8fb19SBen Gras  */
13452fe8fb19SBen Gras 
13462fe8fb19SBen Gras _CITRUS_STDENC_DECLS(ISO2022);
13472fe8fb19SBen Gras _CITRUS_STDENC_DEF_OPS(ISO2022);
13482fe8fb19SBen Gras 
13492fe8fb19SBen Gras #include "citrus_stdenc_template.h"
1350