xref: /netbsd-src/lib/libc/citrus/modules/citrus_iso2022.c (revision 85a67e61f75c076ff4d0b497160a3065fe39fc5c)
1*85a67e61Sjoerg /*	$NetBSD: citrus_iso2022.c,v 1.23 2013/05/28 16:57:56 joerg Exp $	*/
2dc7d18ffStshiozak 
3dc7d18ffStshiozak /*-
4dc7d18ffStshiozak  * Copyright (c)1999, 2002 Citrus Project,
5dc7d18ffStshiozak  * All rights reserved.
6dc7d18ffStshiozak  *
7dc7d18ffStshiozak  * Redistribution and use in source and binary forms, with or without
8dc7d18ffStshiozak  * modification, are permitted provided that the following conditions
9dc7d18ffStshiozak  * are met:
10dc7d18ffStshiozak  * 1. Redistributions of source code must retain the above copyright
11dc7d18ffStshiozak  *    notice, this list of conditions and the following disclaimer.
12dc7d18ffStshiozak  * 2. Redistributions in binary form must reproduce the above copyright
13dc7d18ffStshiozak  *    notice, this list of conditions and the following disclaimer in the
14dc7d18ffStshiozak  *    documentation and/or other materials provided with the distribution.
15dc7d18ffStshiozak  *
16dc7d18ffStshiozak  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17dc7d18ffStshiozak  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18dc7d18ffStshiozak  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19dc7d18ffStshiozak  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20dc7d18ffStshiozak  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21dc7d18ffStshiozak  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22dc7d18ffStshiozak  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23dc7d18ffStshiozak  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24dc7d18ffStshiozak  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25dc7d18ffStshiozak  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26dc7d18ffStshiozak  * SUCH DAMAGE.
27dc7d18ffStshiozak  *
28dc7d18ffStshiozak  *	$Citrus: xpg4dl/FreeBSD/lib/libc/locale/iso2022.c,v 1.23 2001/06/21 01:51:44 yamt Exp $
29dc7d18ffStshiozak  */
30dc7d18ffStshiozak 
31dc7d18ffStshiozak #include <sys/cdefs.h>
32dc7d18ffStshiozak #if defined(LIBC_SCCS) && !defined(lint)
33*85a67e61Sjoerg __RCSID("$NetBSD: citrus_iso2022.c,v 1.23 2013/05/28 16:57:56 joerg Exp $");
34dc7d18ffStshiozak #endif /* LIBC_SCCS and not lint */
35dc7d18ffStshiozak 
36dc7d18ffStshiozak #include <assert.h>
37dc7d18ffStshiozak #include <errno.h>
38dc7d18ffStshiozak #include <string.h>
39dc7d18ffStshiozak #include <stdio.h>
40dc7d18ffStshiozak #include <stdlib.h>
41dc7d18ffStshiozak #include <stddef.h>
42dc7d18ffStshiozak #include <wchar.h>
43dc7d18ffStshiozak #include <sys/types.h>
44dc7d18ffStshiozak #include <limits.h>
4504e58308Stshiozak 
4604e58308Stshiozak #include "citrus_namespace.h"
4704e58308Stshiozak #include "citrus_types.h"
48dc7d18ffStshiozak #include "citrus_module.h"
49dc7d18ffStshiozak #include "citrus_ctype.h"
5004e58308Stshiozak #include "citrus_stdenc.h"
51dc7d18ffStshiozak #include "citrus_iso2022.h"
52dc7d18ffStshiozak 
53dc7d18ffStshiozak 
54dc7d18ffStshiozak /* ----------------------------------------------------------------------
55dc7d18ffStshiozak  * private stuffs used by templates
56dc7d18ffStshiozak  */
57dc7d18ffStshiozak 
58dc7d18ffStshiozak 
59dc7d18ffStshiozak /*
60dc7d18ffStshiozak  * wchar_t mappings:
61dc7d18ffStshiozak  * ASCII (ESC ( B)		00000000 00000000 00000000 0xxxxxxx
62dc7d18ffStshiozak  * iso-8859-1 (ESC , A)		00000000 00000000 00000000 1xxxxxxx
63dc7d18ffStshiozak  * 94 charset (ESC ( F)		0fffffff 00000000 00000000 0xxxxxxx
64dc7d18ffStshiozak  * 94 charset (ESC ( M F)	0fffffff 1mmmmmmm 00000000 0xxxxxxx
65dc7d18ffStshiozak  * 96 charset (ESC , F)		0fffffff 00000000 00000000 1xxxxxxx
66dc7d18ffStshiozak  * 96 charset (ESC , M F)	0fffffff 1mmmmmmm 00000000 1xxxxxxx
67dc7d18ffStshiozak  * 94x94 charset (ESC $ ( F)	0fffffff 00000000 0xxxxxxx 0xxxxxxx
68dc7d18ffStshiozak  * 96x96 charset (ESC $ , F)	0fffffff 00000000 0xxxxxxx 1xxxxxxx
69dc7d18ffStshiozak  * 94x94 charset (ESC & V ESC $ ( F)
70dc7d18ffStshiozak  *				0fffffff 1vvvvvvv 0xxxxxxx 0xxxxxxx
71dc7d18ffStshiozak  * 94x94x94 charset (ESC $ ( F)	0fffffff 0xxxxxxx 0xxxxxxx 0xxxxxxx
72dc7d18ffStshiozak  * 96x96x96 charset (ESC $ , F)	0fffffff 0xxxxxxx 0xxxxxxx 1xxxxxxx
73855852a0Sitojun  * reserved for UCS4 co-existence (UCS4 is 31bit encoding thanks to mohta bit)
74855852a0Sitojun  *				1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
75dc7d18ffStshiozak  */
76dc7d18ffStshiozak 
77dc7d18ffStshiozak typedef struct {
78dc7d18ffStshiozak 	u_char	type;
79dc7d18ffStshiozak #define	CS94		(0U)
80dc7d18ffStshiozak #define	CS96		(1U)
81dc7d18ffStshiozak #define	CS94MULTI	(2U)
82dc7d18ffStshiozak #define	CS96MULTI	(3U)
83dc7d18ffStshiozak 
84dc7d18ffStshiozak 	u_char	final;
85dc7d18ffStshiozak 	u_char	interm;
86dc7d18ffStshiozak 	u_char	vers;
87dc7d18ffStshiozak } _ISO2022Charset;
88dc7d18ffStshiozak 
89b29e60b3Stnozaki static const _ISO2022Charset ascii    = { CS94, 'B', '\0', '\0' };
90b29e60b3Stnozaki static const _ISO2022Charset iso88591 = { CS96, 'A', '\0', '\0' };
91b29e60b3Stnozaki 
92dc7d18ffStshiozak typedef struct {
93dc7d18ffStshiozak 	_ISO2022Charset	g[4];
94dc7d18ffStshiozak 	/* need 3 bits to hold -1, 0, ..., 3 */
95dc7d18ffStshiozak 	int	gl:3,
96dc7d18ffStshiozak 		gr:3,
97dc7d18ffStshiozak 		singlegl:3,
98dc7d18ffStshiozak 		singlegr:3;
99dc7d18ffStshiozak 	char ch[7];	/* longest escape sequence (ESC & V ESC $ ( F) */
100dc7d18ffStshiozak 	int chlen;
1013daba72aSyamt 	int flags;
1023daba72aSyamt #define _ISO2022STATE_FLAG_INITIALIZED	1
1036854a8c8Syamt } _ISO2022State;
104dc7d18ffStshiozak 
105dc7d18ffStshiozak typedef struct {
106dc7d18ffStshiozak 	_ISO2022Charset	*recommend[4];
107dc7d18ffStshiozak 	size_t	recommendsize[4];
108dc7d18ffStshiozak 	_ISO2022Charset	initg[4];
109dc7d18ffStshiozak 	int	maxcharset;
110dc7d18ffStshiozak 	int	flags;
111dc7d18ffStshiozak #define	F_8BIT	0x0001
112dc7d18ffStshiozak #define	F_NOOLD	0x0002
113dc7d18ffStshiozak #define	F_SI	0x0010	/*0F*/
114dc7d18ffStshiozak #define	F_SO	0x0020	/*0E*/
115dc7d18ffStshiozak #define	F_LS0	0x0010	/*0F*/
116dc7d18ffStshiozak #define	F_LS1	0x0020	/*0E*/
117dc7d18ffStshiozak #define	F_LS2	0x0040	/*ESC n*/
118dc7d18ffStshiozak #define	F_LS3	0x0080	/*ESC o*/
119dc7d18ffStshiozak #define	F_LS1R	0x0100	/*ESC ~*/
120dc7d18ffStshiozak #define	F_LS2R	0x0200	/*ESC }*/
121dc7d18ffStshiozak #define	F_LS3R	0x0400	/*ESC |*/
122dc7d18ffStshiozak #define	F_SS2	0x0800	/*ESC N*/
123dc7d18ffStshiozak #define	F_SS3	0x1000	/*ESC O*/
124dc7d18ffStshiozak #define	F_SS2R	0x2000	/*8E*/
125dc7d18ffStshiozak #define	F_SS3R	0x4000	/*8F*/
126dc7d18ffStshiozak } _ISO2022EncodingInfo;
127dc7d18ffStshiozak typedef struct {
128dc7d18ffStshiozak 	_ISO2022EncodingInfo ei;
129dc7d18ffStshiozak 	struct {
130dc7d18ffStshiozak 		/* for future multi-locale facility */
131dc7d18ffStshiozak 		_ISO2022State	s_mblen;
132dc7d18ffStshiozak 		_ISO2022State	s_mbrlen;
133dc7d18ffStshiozak 		_ISO2022State	s_mbrtowc;
134dc7d18ffStshiozak 		_ISO2022State	s_mbtowc;
135dc7d18ffStshiozak 		_ISO2022State	s_mbsrtowcs;
136*85a67e61Sjoerg 		_ISO2022State	s_mbsnrtowcs;
137dc7d18ffStshiozak 		_ISO2022State	s_wcrtomb;
138dc7d18ffStshiozak 		_ISO2022State	s_wcsrtombs;
139*85a67e61Sjoerg 		_ISO2022State	s_wcsnrtombs;
140dc7d18ffStshiozak 		_ISO2022State	s_wctomb;
141dc7d18ffStshiozak 	} states;
142dc7d18ffStshiozak } _ISO2022CTypeInfo;
143dc7d18ffStshiozak 
144dc7d18ffStshiozak #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
145dc7d18ffStshiozak #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
146dc7d18ffStshiozak 
147dc7d18ffStshiozak #define _FUNCNAME(m)			_citrus_ISO2022_##m
148dc7d18ffStshiozak #define _ENCODING_INFO			_ISO2022EncodingInfo
149dc7d18ffStshiozak #define _CTYPE_INFO			_ISO2022CTypeInfo
150dc7d18ffStshiozak #define _ENCODING_STATE			_ISO2022State
151f0ab6c64Syamt #define _ENCODING_MB_CUR_MAX(_ei_)	MB_LEN_MAX
152dc7d18ffStshiozak #define _ENCODING_IS_STATE_DEPENDENT	1
1533daba72aSyamt #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	\
1543daba72aSyamt     (!((_ps_)->flags & _ISO2022STATE_FLAG_INITIALIZED))
155dc7d18ffStshiozak 
156dc7d18ffStshiozak 
157dc7d18ffStshiozak #define _ISO2022INVALID (wchar_t)-1
158dc7d18ffStshiozak 
isc0(__uint8_t x)159dc7d18ffStshiozak static __inline int isc0(__uint8_t x) { return ((x & 0x1f) == x); }
isc1(__uint8_t x)160dc7d18ffStshiozak static __inline int isc1(__uint8_t x) { return (0x80 <= x && x <= 0x9f); }
iscntl(__uint8_t x)161dc7d18ffStshiozak static __inline int iscntl(__uint8_t x) { return (isc0(x) || isc1(x) || x == 0x7f); }
is94(__uint8_t x)162dc7d18ffStshiozak static __inline int is94(__uint8_t x) { return (0x21 <= x && x <= 0x7e); }
is96(__uint8_t x)163dc7d18ffStshiozak static __inline int is96(__uint8_t x) { return (0x20 <= x && x <= 0x7f); }
isecma(__uint8_t x)164dc7d18ffStshiozak static __inline int isecma(__uint8_t x) { return (0x30 <= x && x <= 0x7f); }
isinterm(__uint8_t x)165dc7d18ffStshiozak static __inline int isinterm(__uint8_t x) { return (0x20 <= x && x <= 0x2f); }
isthree(__uint8_t x)166dc7d18ffStshiozak static __inline int isthree(__uint8_t x) { return (0x60 <= x && x <= 0x6f); }
167dc7d18ffStshiozak 
168dc7d18ffStshiozak static __inline int
getcs(const char * __restrict p,_ISO2022Charset * __restrict cs)169dc7d18ffStshiozak getcs(const char * __restrict p, _ISO2022Charset * __restrict cs)
170dc7d18ffStshiozak {
171dc7d18ffStshiozak 
172dc7d18ffStshiozak 	_DIAGASSERT(p != NULL);
173dc7d18ffStshiozak 	_DIAGASSERT(cs != NULL);
174dc7d18ffStshiozak 
175dc7d18ffStshiozak 	if (!strncmp(p, "94$", 3) && p[3] && !p[4]) {
176dc7d18ffStshiozak 		cs->final = (u_char)(p[3] & 0xff);
177dc7d18ffStshiozak 		cs->interm = '\0';
178dc7d18ffStshiozak 		cs->vers = '\0';
179dc7d18ffStshiozak 		cs->type = CS94MULTI;
180dc7d18ffStshiozak 	} else if (!strncmp(p, "96$", 3) && p[3] && !p[4]) {
181dc7d18ffStshiozak 		cs->final = (u_char)(p[3] & 0xff);
182dc7d18ffStshiozak 		cs->interm = '\0';
183dc7d18ffStshiozak 		cs->vers = '\0';
184dc7d18ffStshiozak 		cs->type = CS96MULTI;
185dc7d18ffStshiozak 	} else if (!strncmp(p, "94", 2) && p[2] && !p[3]) {
186dc7d18ffStshiozak 		cs->final = (u_char)(p[2] & 0xff);
187dc7d18ffStshiozak 		cs->interm = '\0';
188dc7d18ffStshiozak 		cs->vers = '\0';
189dc7d18ffStshiozak 		cs->type = CS94;
190dc7d18ffStshiozak 	} else if (!strncmp(p, "96", 2) && p[2] && !p[3]) {
191dc7d18ffStshiozak 		cs->final = (u_char )(p[2] & 0xff);
192dc7d18ffStshiozak 		cs->interm = '\0';
193dc7d18ffStshiozak 		cs->vers = '\0';
194dc7d18ffStshiozak 		cs->type = CS96;
195dc7d18ffStshiozak 	} else {
196dc7d18ffStshiozak 		return 1;
197dc7d18ffStshiozak 	}
198dc7d18ffStshiozak 
199dc7d18ffStshiozak 	return 0;
200dc7d18ffStshiozak }
201dc7d18ffStshiozak 
202dc7d18ffStshiozak 
203dc7d18ffStshiozak #define _NOTMATCH	0
204dc7d18ffStshiozak #define _MATCH		1
205dc7d18ffStshiozak #define _PARSEFAIL	2
206dc7d18ffStshiozak 
207dc7d18ffStshiozak static __inline int
get_recommend(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)208dc7d18ffStshiozak get_recommend(_ISO2022EncodingInfo * __restrict ei,
209dc7d18ffStshiozak 	      const char * __restrict token)
210dc7d18ffStshiozak {
211dc7d18ffStshiozak 	int i;
2125d489a8aSitojun 	_ISO2022Charset cs, *p;
213dc7d18ffStshiozak 
214dc7d18ffStshiozak 	if (!strchr("0123", token[0]) || token[1] != '=')
215dc7d18ffStshiozak 		return (_NOTMATCH);
216dc7d18ffStshiozak 
217dc7d18ffStshiozak 	if (getcs(&token[2], &cs) == 0)
218dc7d18ffStshiozak 		;
219dc7d18ffStshiozak 	else if (!strcmp(&token[2], "94")) {
220dc7d18ffStshiozak 		cs.final = (u_char)(token[4]);
221dc7d18ffStshiozak 		cs.interm = '\0';
222dc7d18ffStshiozak 		cs.vers = '\0';
223dc7d18ffStshiozak 		cs.type = CS94;
224dc7d18ffStshiozak 	} else if (!strcmp(&token[2], "96")) {
225dc7d18ffStshiozak 		cs.final = (u_char)(token[4]);
226dc7d18ffStshiozak 		cs.interm = '\0';
227dc7d18ffStshiozak 		cs.vers = '\0';
228dc7d18ffStshiozak 		cs.type = CS96;
229dc7d18ffStshiozak 	} else if (!strcmp(&token[2], "94$")) {
230dc7d18ffStshiozak 		cs.final = (u_char)(token[5]);
231dc7d18ffStshiozak 		cs.interm = '\0';
232dc7d18ffStshiozak 		cs.vers = '\0';
233dc7d18ffStshiozak 		cs.type = CS94MULTI;
234dc7d18ffStshiozak 	} else if (!strcmp(&token[2], "96$")) {
235dc7d18ffStshiozak 		cs.final = (u_char)(token[5]);
236dc7d18ffStshiozak 		cs.interm = '\0';
237dc7d18ffStshiozak 		cs.vers = '\0';
238dc7d18ffStshiozak 		cs.type = CS96MULTI;
239dc7d18ffStshiozak 	} else {
240dc7d18ffStshiozak 		return (_PARSEFAIL);
241dc7d18ffStshiozak 	}
242dc7d18ffStshiozak 
243dc7d18ffStshiozak 	i = token[0] - '0';
244dc7d18ffStshiozak 	if (!ei->recommend[i]) {
245dc7d18ffStshiozak 		ei->recommend[i] = malloc(sizeof(_ISO2022Charset));
246dc7d18ffStshiozak 	} else {
2475d489a8aSitojun 		p = realloc(ei->recommend[i],
2485d489a8aSitojun 		    sizeof(_ISO2022Charset) * (ei->recommendsize[i] + 1));
2495d489a8aSitojun 		if (!p)
2505d489a8aSitojun 			return (_PARSEFAIL);
2515d489a8aSitojun 		ei->recommend[i] = p;
252dc7d18ffStshiozak 	}
253dc7d18ffStshiozak 	if (!ei->recommend[i])
254dc7d18ffStshiozak 		return (_PARSEFAIL);
2555d489a8aSitojun 	ei->recommendsize[i]++;
256dc7d18ffStshiozak 
257dc7d18ffStshiozak 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->final = cs.final;
258dc7d18ffStshiozak 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->interm = cs.interm;
259dc7d18ffStshiozak 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->vers = cs.vers;
260dc7d18ffStshiozak 	(ei->recommend[i] + (ei->recommendsize[i] - 1))->type = cs.type;
261dc7d18ffStshiozak 
262dc7d18ffStshiozak 	return (_MATCH);
263dc7d18ffStshiozak }
264dc7d18ffStshiozak 
265dc7d18ffStshiozak static __inline int
get_initg(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)266dc7d18ffStshiozak get_initg(_ISO2022EncodingInfo * __restrict ei,
267dc7d18ffStshiozak 	  const char * __restrict token)
268dc7d18ffStshiozak {
269dc7d18ffStshiozak 	_ISO2022Charset cs;
270dc7d18ffStshiozak 
271dc7d18ffStshiozak 	if (strncmp("INIT", &token[0], 4) ||
272dc7d18ffStshiozak 	    !strchr("0123", token[4]) ||
273dc7d18ffStshiozak 	    token[5] != '=')
274dc7d18ffStshiozak 		return (_NOTMATCH);
275dc7d18ffStshiozak 
276dc7d18ffStshiozak 	if (getcs(&token[6], &cs) != 0)
277dc7d18ffStshiozak 		return (_PARSEFAIL);
278dc7d18ffStshiozak 
279dc7d18ffStshiozak 	ei->initg[token[4] - '0'].type = cs.type;
280dc7d18ffStshiozak 	ei->initg[token[4] - '0'].final = cs.final;
281dc7d18ffStshiozak 	ei->initg[token[4] - '0'].interm = cs.interm;
282dc7d18ffStshiozak 	ei->initg[token[4] - '0'].vers = cs.vers;
283dc7d18ffStshiozak 
284dc7d18ffStshiozak 	return (_MATCH);
285dc7d18ffStshiozak }
286dc7d18ffStshiozak 
287dc7d18ffStshiozak static __inline int
get_max(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)288dc7d18ffStshiozak get_max(_ISO2022EncodingInfo * __restrict ei,
289dc7d18ffStshiozak 	const char * __restrict token)
290dc7d18ffStshiozak {
291dc7d18ffStshiozak 	if (!strcmp(token, "MAX1")) {
292dc7d18ffStshiozak 		ei->maxcharset = 1;
293dc7d18ffStshiozak 	} else if (!strcmp(token, "MAX2")) {
294dc7d18ffStshiozak 		ei->maxcharset = 2;
295dc7d18ffStshiozak 	} else if (!strcmp(token, "MAX3")) {
296dc7d18ffStshiozak 		ei->maxcharset = 3;
297dc7d18ffStshiozak 	} else
298dc7d18ffStshiozak 		return (_NOTMATCH);
299dc7d18ffStshiozak 
300dc7d18ffStshiozak 	return (_MATCH);
301dc7d18ffStshiozak }
302dc7d18ffStshiozak 
303dc7d18ffStshiozak 
304dc7d18ffStshiozak static __inline int
get_flags(_ISO2022EncodingInfo * __restrict ei,const char * __restrict token)305dc7d18ffStshiozak get_flags(_ISO2022EncodingInfo * __restrict ei,
306dc7d18ffStshiozak 	  const char * __restrict token)
307dc7d18ffStshiozak {
308dc7d18ffStshiozak 	int i;
309dc7d18ffStshiozak 	static struct {
310dc7d18ffStshiozak 		const char	*tag;
311dc7d18ffStshiozak 		int		flag;
312dc7d18ffStshiozak 	} const tags[] = {
313dc7d18ffStshiozak 		{ "DUMMY",	0	},
314dc7d18ffStshiozak 		{ "8BIT",	F_8BIT	},
315dc7d18ffStshiozak 		{ "NOOLD",	F_NOOLD	},
316dc7d18ffStshiozak 		{ "SI",		F_SI	},
317dc7d18ffStshiozak 		{ "SO",		F_SO	},
318dc7d18ffStshiozak 		{ "LS0",	F_LS0	},
319dc7d18ffStshiozak 		{ "LS1",	F_LS1	},
320dc7d18ffStshiozak 		{ "LS2",	F_LS2	},
321dc7d18ffStshiozak 		{ "LS3",	F_LS3	},
322dc7d18ffStshiozak 		{ "LS1R",	F_LS1R	},
323dc7d18ffStshiozak 		{ "LS2R",	F_LS2R	},
324dc7d18ffStshiozak 		{ "LS3R",	F_LS3R	},
325dc7d18ffStshiozak 		{ "SS2",	F_SS2	},
326dc7d18ffStshiozak 		{ "SS3",	F_SS3	},
327dc7d18ffStshiozak 		{ "SS2R",	F_SS2R	},
328dc7d18ffStshiozak 		{ "SS3R",	F_SS3R	},
329dc7d18ffStshiozak 		{ NULL,		0 }
330dc7d18ffStshiozak 	};
331dc7d18ffStshiozak 
332dc7d18ffStshiozak 	for (i = 0; tags[i].tag; i++) {
333dc7d18ffStshiozak 		if (!strcmp(token, tags[i].tag)) {
334dc7d18ffStshiozak 			ei->flags |= tags[i].flag;
335dc7d18ffStshiozak 			return (_MATCH);
336dc7d18ffStshiozak 		}
337dc7d18ffStshiozak 	}
338dc7d18ffStshiozak 
339dc7d18ffStshiozak 	return (_NOTMATCH);
340dc7d18ffStshiozak }
341dc7d18ffStshiozak 
342dc7d18ffStshiozak 
343dc7d18ffStshiozak static __inline int
_citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)344dc7d18ffStshiozak _citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * __restrict ei,
345dc7d18ffStshiozak 			       const void * __restrict var, size_t lenvar)
346dc7d18ffStshiozak {
347dc7d18ffStshiozak 	char const *v, *e;
348dc7d18ffStshiozak 	char buf[20];
349dc7d18ffStshiozak 	int i, len, ret;
350dc7d18ffStshiozak 
351dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
352dc7d18ffStshiozak 
353dc7d18ffStshiozak 
354dc7d18ffStshiozak 	/*
355dc7d18ffStshiozak 	 * parse VARIABLE section.
356dc7d18ffStshiozak 	 */
357dc7d18ffStshiozak 
358dc7d18ffStshiozak 	if (!var)
359dc7d18ffStshiozak 		return (EFTYPE);
360dc7d18ffStshiozak 
361dc7d18ffStshiozak 	v = (const char *) var;
362dc7d18ffStshiozak 
363dc7d18ffStshiozak 	/* initialize structure */
364dc7d18ffStshiozak 	ei->maxcharset = 0;
365dc7d18ffStshiozak 	for (i = 0; i < 4; i++) {
366dc7d18ffStshiozak 		ei->recommend[i] = NULL;
367dc7d18ffStshiozak 		ei->recommendsize[i] = 0;
368dc7d18ffStshiozak 	}
369dc7d18ffStshiozak 	ei->flags = 0;
370dc7d18ffStshiozak 
371dc7d18ffStshiozak 	while (*v) {
372dc7d18ffStshiozak 		while (*v == ' ' || *v == '\t')
373dc7d18ffStshiozak 			++v;
374dc7d18ffStshiozak 
375dc7d18ffStshiozak 		/* find the token */
376dc7d18ffStshiozak 		e = v;
377dc7d18ffStshiozak 		while (*e && *e != ' ' && *e != '\t')
378dc7d18ffStshiozak 			++e;
37904e58308Stshiozak 
380dc7d18ffStshiozak 		len = e-v;
38104e58308Stshiozak 		if (len == 0)
38204e58308Stshiozak 			break;
383dc7d18ffStshiozak 		if (len>=sizeof(buf))
384dc7d18ffStshiozak 			goto parsefail;
3852ec4a590Sitojun 		snprintf(buf, sizeof(buf), "%.*s", len, v);
386dc7d18ffStshiozak 
387dc7d18ffStshiozak 		if ((ret = get_recommend(ei, buf)) != _NOTMATCH)
388dc7d18ffStshiozak 			;
389dc7d18ffStshiozak 		else if ((ret = get_initg(ei, buf)) != _NOTMATCH)
390dc7d18ffStshiozak 			;
391dc7d18ffStshiozak 		else if ((ret = get_max(ei, buf)) != _NOTMATCH)
392dc7d18ffStshiozak 			;
393dc7d18ffStshiozak 		else if ((ret = get_flags(ei, buf)) != _NOTMATCH)
394dc7d18ffStshiozak 			;
395dc7d18ffStshiozak 		else
396dc7d18ffStshiozak 			ret = _PARSEFAIL;
397dc7d18ffStshiozak 		if (ret==_PARSEFAIL)
398dc7d18ffStshiozak 			goto parsefail;
399dc7d18ffStshiozak 		v = e;
400dc7d18ffStshiozak 
401dc7d18ffStshiozak 	}
402dc7d18ffStshiozak 
403dc7d18ffStshiozak 	return (0);
404dc7d18ffStshiozak 
405dc7d18ffStshiozak parsefail:
406dc7d18ffStshiozak 	free(ei->recommend[0]);
407dc7d18ffStshiozak 	free(ei->recommend[1]);
408dc7d18ffStshiozak 	free(ei->recommend[2]);
409dc7d18ffStshiozak 	free(ei->recommend[3]);
410dc7d18ffStshiozak 
411dc7d18ffStshiozak 	return (EFTYPE);
412dc7d18ffStshiozak }
413dc7d18ffStshiozak 
414dc7d18ffStshiozak static __inline void
415dc7d18ffStshiozak /*ARGSUSED*/
_citrus_ISO2022_init_state(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict s)416dc7d18ffStshiozak _citrus_ISO2022_init_state(_ISO2022EncodingInfo * __restrict ei,
417dc7d18ffStshiozak 			   _ISO2022State * __restrict s)
418dc7d18ffStshiozak {
419dc7d18ffStshiozak 	int i;
420dc7d18ffStshiozak 
421dc7d18ffStshiozak 	memset(s, 0, sizeof(*s));
422dc7d18ffStshiozak 	s->gl = 0;
423dc7d18ffStshiozak 	s->gr = (ei->flags & F_8BIT) ? 1 : -1;
424dc7d18ffStshiozak 
425dc7d18ffStshiozak 	for (i = 0; i < 4; i++) {
426dc7d18ffStshiozak 		if (ei->initg[i].final) {
427dc7d18ffStshiozak 			s->g[i].type = ei->initg[i].type;
428dc7d18ffStshiozak 			s->g[i].final = ei->initg[i].final;
429dc7d18ffStshiozak 			s->g[i].interm = ei->initg[i].interm;
430dc7d18ffStshiozak 		}
431dc7d18ffStshiozak 	}
432dc7d18ffStshiozak 	s->singlegl = s->singlegr = -1;
4333daba72aSyamt 	s->flags |= _ISO2022STATE_FLAG_INITIALIZED;
434dc7d18ffStshiozak }
435dc7d18ffStshiozak 
436dc7d18ffStshiozak static __inline void
437dc7d18ffStshiozak /*ARGSUSED*/
_citrus_ISO2022_pack_state(_ISO2022EncodingInfo * __restrict ei,void * __restrict pspriv,const _ISO2022State * __restrict s)438dc7d18ffStshiozak _citrus_ISO2022_pack_state(_ISO2022EncodingInfo * __restrict ei,
439dc7d18ffStshiozak 			   void * __restrict pspriv,
440dc7d18ffStshiozak 			   const _ISO2022State * __restrict s)
441dc7d18ffStshiozak {
442dc7d18ffStshiozak 	memcpy(pspriv, (const void *)s, sizeof(*s));
443dc7d18ffStshiozak }
444dc7d18ffStshiozak 
445dc7d18ffStshiozak static __inline void
446dc7d18ffStshiozak /*ARGSUSED*/
_citrus_ISO2022_unpack_state(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict s,const void * __restrict pspriv)447dc7d18ffStshiozak _citrus_ISO2022_unpack_state(_ISO2022EncodingInfo * __restrict ei,
448dc7d18ffStshiozak 			     _ISO2022State * __restrict s,
449dc7d18ffStshiozak 			     const void * __restrict pspriv)
450dc7d18ffStshiozak {
451dc7d18ffStshiozak 	memcpy((void *)s, pspriv, sizeof(*s));
452dc7d18ffStshiozak }
453dc7d18ffStshiozak 
454dc7d18ffStshiozak static int
455dc7d18ffStshiozak /*ARGSUSED*/
_citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)45604e58308Stshiozak _citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * __restrict ei,
45704e58308Stshiozak 				     const void * __restrict var,
45804e58308Stshiozak 				     size_t lenvar)
459dc7d18ffStshiozak {
460dc7d18ffStshiozak 
461dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
462dc7d18ffStshiozak 
463dc7d18ffStshiozak 	return _citrus_ISO2022_parse_variable(ei, var, lenvar);
464dc7d18ffStshiozak }
465dc7d18ffStshiozak 
466dc7d18ffStshiozak static void
467dc7d18ffStshiozak /*ARGSUSED*/
_citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo * ei)46804e58308Stshiozak _citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo *ei)
469dc7d18ffStshiozak {
470dc7d18ffStshiozak }
471dc7d18ffStshiozak 
472dc7d18ffStshiozak #define	ESC	'\033'
473dc7d18ffStshiozak #define	ECMA	-1
474dc7d18ffStshiozak #define	INTERM	-2
475dc7d18ffStshiozak #define	OECMA	-3
4765b3d2342Syamt static const struct seqtable {
477dc7d18ffStshiozak 	int type;
478dc7d18ffStshiozak 	int csoff;
479dc7d18ffStshiozak 	int finaloff;
480dc7d18ffStshiozak 	int intermoff;
481dc7d18ffStshiozak 	int versoff;
482dc7d18ffStshiozak 	int len;
483dc7d18ffStshiozak 	int chars[10];
484dc7d18ffStshiozak } seqtable[] = {
485dc7d18ffStshiozak 	/* G0 94MULTI special */
486dc7d18ffStshiozak 	{ CS94MULTI, -1, 2, -1, -1,	3, { ESC, '$', OECMA }, },
487dc7d18ffStshiozak 	/* G0 94MULTI special with version identification */
488dc7d18ffStshiozak 	{ CS94MULTI, -1, 5, -1, 2,	6, { ESC, '&', ECMA, ESC, '$', OECMA }, },
489dc7d18ffStshiozak 	/* G? 94 */
490dc7d18ffStshiozak 	{ CS94, 1, 2, -1, -1,		3, { ESC, CS94, ECMA, }, },
491dc7d18ffStshiozak 	/* G? 94 with 2nd intermediate char */
492dc7d18ffStshiozak 	{ CS94, 1, 3, 2, -1,		4, { ESC, CS94, INTERM, ECMA, }, },
493dc7d18ffStshiozak 	/* G? 96 */
494dc7d18ffStshiozak 	{ CS96, 1, 2, -1, -1,		3, { ESC, CS96, ECMA, }, },
495dc7d18ffStshiozak 	/* G? 96 with 2nd intermediate char */
496dc7d18ffStshiozak 	{ CS96, 1, 3, 2, -1,		4, { ESC, CS96, INTERM, ECMA, }, },
497dc7d18ffStshiozak 	/* G? 94MULTI */
498dc7d18ffStshiozak 	{ CS94MULTI, 2, 3, -1, -1,	4, { ESC, '$', CS94, ECMA, }, },
499dc7d18ffStshiozak 	/* G? 96MULTI */
500dc7d18ffStshiozak 	{ CS96MULTI, 2, 3, -1, -1,	4, { ESC, '$', CS96, ECMA, }, },
501dc7d18ffStshiozak 	/* G? 94MULTI with version specification */
502dc7d18ffStshiozak 	{ CS94MULTI, 5, 6, -1, 2,	7, { ESC, '&', ECMA, ESC, '$', CS94, ECMA, }, },
503dc7d18ffStshiozak 	/* LS2/3 */
504dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, 'n', }, },
505dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, 'o', }, },
506dc7d18ffStshiozak 	/* LS1/2/3R */
507dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, '~', }, },
508dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, /*{*/ '}', }, },
509dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, '|', }, },
510dc7d18ffStshiozak 	/* SS2/3 */
511dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, 'N', }, },
512dc7d18ffStshiozak 	{ -1, -1, -1, -1, -1,		2, { ESC, 'O', }, },
513dc7d18ffStshiozak 	/* end of records */
514dc7d18ffStshiozak 	{ 0, }
515dc7d18ffStshiozak };
516dc7d18ffStshiozak 
517dc7d18ffStshiozak static int
seqmatch(const char * __restrict s,size_t n,const struct seqtable * __restrict sp)518dc7d18ffStshiozak seqmatch(const char * __restrict s, size_t n,
519dc7d18ffStshiozak 	 const struct seqtable * __restrict sp)
520dc7d18ffStshiozak {
521dc7d18ffStshiozak 	const int *p;
522dc7d18ffStshiozak 
523dc7d18ffStshiozak 	_DIAGASSERT(s != NULL);
524dc7d18ffStshiozak 	_DIAGASSERT(sp != NULL);
525dc7d18ffStshiozak 
526dc7d18ffStshiozak 	p = sp->chars;
527dc7d18ffStshiozak 	while (p - sp->chars < n && p - sp->chars < sp->len) {
528dc7d18ffStshiozak 		switch (*p) {
529dc7d18ffStshiozak 		case ECMA:
530dc7d18ffStshiozak 			if (!isecma(*s))
531dc7d18ffStshiozak 				goto terminate;
532dc7d18ffStshiozak 			break;
533dc7d18ffStshiozak 		case OECMA:
534dc7d18ffStshiozak 			if (*s && strchr("@AB", *s))
535dc7d18ffStshiozak 				break;
536dc7d18ffStshiozak 			else
537dc7d18ffStshiozak 				goto terminate;
538dc7d18ffStshiozak 		case INTERM:
539dc7d18ffStshiozak 			if (!isinterm(*s))
540dc7d18ffStshiozak 				goto terminate;
541dc7d18ffStshiozak 			break;
542dc7d18ffStshiozak 		case CS94:
543dc7d18ffStshiozak 			if (*s && strchr("()*+", *s))
544dc7d18ffStshiozak 				break;
545dc7d18ffStshiozak 			else
546dc7d18ffStshiozak 				goto terminate;
547dc7d18ffStshiozak 		case CS96:
548dc7d18ffStshiozak 			if (*s && strchr(",-./", *s))
549dc7d18ffStshiozak 				break;
550dc7d18ffStshiozak 			else
551dc7d18ffStshiozak 				goto terminate;
552dc7d18ffStshiozak 		default:
553dc7d18ffStshiozak 			if (*s != *p)
554dc7d18ffStshiozak 				goto terminate;
555dc7d18ffStshiozak 			break;
556dc7d18ffStshiozak 		}
557dc7d18ffStshiozak 
558dc7d18ffStshiozak 		p++;
559dc7d18ffStshiozak 		s++;
560dc7d18ffStshiozak 	}
561dc7d18ffStshiozak 
562dc7d18ffStshiozak terminate:
563dc7d18ffStshiozak 	return p - sp->chars;
564dc7d18ffStshiozak }
565dc7d18ffStshiozak 
566dc7d18ffStshiozak static wchar_t
_ISO2022_sgetwchar(_ISO2022EncodingInfo * __restrict ei,const char * __restrict string,size_t n,const char ** __restrict result,_ISO2022State * __restrict psenc)567dc7d18ffStshiozak _ISO2022_sgetwchar(_ISO2022EncodingInfo * __restrict ei,
568dc7d18ffStshiozak 		const char * __restrict string, size_t n,
569dc7d18ffStshiozak 		const char ** __restrict result,
570dc7d18ffStshiozak 		_ISO2022State * __restrict psenc)
571dc7d18ffStshiozak {
572dc7d18ffStshiozak 	wchar_t wchar = 0;
573dc7d18ffStshiozak 	int cur;
5745b3d2342Syamt 	const struct seqtable *sp;
575dc7d18ffStshiozak 	int nmatch;
576dc7d18ffStshiozak 	int i;
577dc7d18ffStshiozak 
578dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
579476f0d92Stnozaki 	_DIAGASSERT(psenc != NULL);
580dc7d18ffStshiozak 	_DIAGASSERT(string != NULL);
581dc7d18ffStshiozak 	/* result may be NULL */
582dc7d18ffStshiozak 
583dc7d18ffStshiozak 	while (1) {
584dc7d18ffStshiozak 		/* SI/SO */
585dc7d18ffStshiozak 		if (1 <= n && string[0] == '\017') {
586dc7d18ffStshiozak 			psenc->gl = 0;
587dc7d18ffStshiozak 			string++;
588dc7d18ffStshiozak 			n--;
589dc7d18ffStshiozak 			continue;
590dc7d18ffStshiozak 		}
591dc7d18ffStshiozak 		if (1 <= n && string[0] == '\016') {
592dc7d18ffStshiozak 			psenc->gl = 1;
593dc7d18ffStshiozak 			string++;
594dc7d18ffStshiozak 			n--;
595dc7d18ffStshiozak 			continue;
596dc7d18ffStshiozak 		}
597dc7d18ffStshiozak 
598dc7d18ffStshiozak 		/* SS2/3R */
599dc7d18ffStshiozak 		if (1 <= n && string[0] && strchr("\217\216", string[0])) {
600dc7d18ffStshiozak 			psenc->singlegl = psenc->singlegr =
601dc7d18ffStshiozak 			    (string[0] - '\216') + 2;
602dc7d18ffStshiozak 			string++;
603dc7d18ffStshiozak 			n--;
604dc7d18ffStshiozak 			continue;
605dc7d18ffStshiozak 		}
606dc7d18ffStshiozak 
607dc7d18ffStshiozak 		/* eat the letter if this is not ESC */
608dc7d18ffStshiozak 		if (1 <= n && string[0] != '\033')
609dc7d18ffStshiozak 			break;
610dc7d18ffStshiozak 
611dc7d18ffStshiozak 		/* look for a perfect match from escape sequences */
612dc7d18ffStshiozak 		for (sp = &seqtable[0]; sp->len; sp++) {
613dc7d18ffStshiozak 			nmatch = seqmatch(string, n, sp);
614dc7d18ffStshiozak 			if (sp->len == nmatch && n >= sp->len)
615dc7d18ffStshiozak 				break;
616dc7d18ffStshiozak 		}
617dc7d18ffStshiozak 
618dc7d18ffStshiozak 		if (!sp->len)
619dc7d18ffStshiozak 			goto notseq;
620dc7d18ffStshiozak 
621dc7d18ffStshiozak 		if (sp->type != -1) {
622dc7d18ffStshiozak 			if (sp->csoff == -1)
623dc7d18ffStshiozak 				i = 0;
624dc7d18ffStshiozak 			else {
625dc7d18ffStshiozak 				switch (sp->type) {
626dc7d18ffStshiozak 				case CS94:
627dc7d18ffStshiozak 				case CS94MULTI:
628dc7d18ffStshiozak 					i = string[sp->csoff] - '(';
629dc7d18ffStshiozak 					break;
630dc7d18ffStshiozak 				case CS96:
631dc7d18ffStshiozak 				case CS96MULTI:
632dc7d18ffStshiozak 					i = string[sp->csoff] - ',';
633dc7d18ffStshiozak 					break;
6345bd7f658Schristos 				default:
6355bd7f658Schristos 					return (_ISO2022INVALID);
636dc7d18ffStshiozak 				}
637dc7d18ffStshiozak 			}
638dc7d18ffStshiozak 			psenc->g[i].type = sp->type;
639dc7d18ffStshiozak 			psenc->g[i].final = '\0';
640dc7d18ffStshiozak 			psenc->g[i].interm = '\0';
641dc7d18ffStshiozak 			psenc->g[i].vers = '\0';
642dc7d18ffStshiozak 			/* sp->finaloff must not be -1 */
643dc7d18ffStshiozak 			if (sp->finaloff != -1)
644dc7d18ffStshiozak 				psenc->g[i].final = string[sp->finaloff];
645dc7d18ffStshiozak 			if (sp->intermoff != -1)
646dc7d18ffStshiozak 				psenc->g[i].interm = string[sp->intermoff];
647dc7d18ffStshiozak 			if (sp->versoff != -1)
648dc7d18ffStshiozak 				psenc->g[i].vers = string[sp->versoff];
649dc7d18ffStshiozak 
650dc7d18ffStshiozak 			string += sp->len;
651dc7d18ffStshiozak 			n -= sp->len;
652dc7d18ffStshiozak 			continue;
653dc7d18ffStshiozak 		}
654dc7d18ffStshiozak 
655dc7d18ffStshiozak 		/* LS2/3 */
656dc7d18ffStshiozak 		if (2 <= n && string[0] == '\033'
657dc7d18ffStshiozak 		 && string[1] && strchr("no", string[1])) {
658dc7d18ffStshiozak 			psenc->gl = string[1] - 'n' + 2;
659dc7d18ffStshiozak 			string += 2;
660dc7d18ffStshiozak 			n -= 2;
661dc7d18ffStshiozak 			continue;
662dc7d18ffStshiozak 		}
663dc7d18ffStshiozak 
664dc7d18ffStshiozak 		/* LS1/2/3R */
665dc7d18ffStshiozak 			/* XXX: { for vi showmatch */
666dc7d18ffStshiozak 		if (2 <= n && string[0] == '\033'
667dc7d18ffStshiozak 		 && string[1] && strchr("~}|", string[1])) {
668dc7d18ffStshiozak 			psenc->gr = 3 - (string[1] - '|');
669dc7d18ffStshiozak 			string += 2;
670dc7d18ffStshiozak 			n -= 2;
671dc7d18ffStshiozak 			continue;
672dc7d18ffStshiozak 		}
673dc7d18ffStshiozak 
674dc7d18ffStshiozak 		/* SS2/3 */
675dc7d18ffStshiozak 		if (2 <= n && string[0] == '\033'
676dc7d18ffStshiozak 		 && string[1] && strchr("NO", string[1])) {
677dc7d18ffStshiozak 			psenc->singlegl = (string[1] - 'N') + 2;
678dc7d18ffStshiozak 			string += 2;
679dc7d18ffStshiozak 			n -= 2;
680dc7d18ffStshiozak 			continue;
681dc7d18ffStshiozak 		}
682dc7d18ffStshiozak 
683dc7d18ffStshiozak 	notseq:
684dc7d18ffStshiozak 		/*
685dc7d18ffStshiozak 		 * if we've got an unknown escape sequence, eat the ESC at the
686dc7d18ffStshiozak 		 * head.  otherwise, wait till full escape sequence comes.
687dc7d18ffStshiozak 		 */
688dc7d18ffStshiozak 		for (sp = &seqtable[0]; sp->len; sp++) {
689dc7d18ffStshiozak 			nmatch = seqmatch(string, n, sp);
690dc7d18ffStshiozak 			if (!nmatch)
691dc7d18ffStshiozak 				continue;
692dc7d18ffStshiozak 
693dc7d18ffStshiozak 			/*
694dc7d18ffStshiozak 			 * if we are in the middle of escape sequence,
695dc7d18ffStshiozak 			 * we still need to wait for more characters to come
696dc7d18ffStshiozak 			 */
697dc7d18ffStshiozak 			if (n < sp->len) {
698dc7d18ffStshiozak 				if (nmatch == n) {
699dc7d18ffStshiozak 					if (result)
7006b58a1b8Stnozaki 						*result = string;
701dc7d18ffStshiozak 					return (_ISO2022INVALID);
702dc7d18ffStshiozak 				}
703dc7d18ffStshiozak 			} else {
704dc7d18ffStshiozak 				if (nmatch == sp->len) {
705dc7d18ffStshiozak 					/* this case should not happen */
706dc7d18ffStshiozak 					goto eat;
707dc7d18ffStshiozak 				}
708dc7d18ffStshiozak 			}
709dc7d18ffStshiozak 		}
710dc7d18ffStshiozak 
711dc7d18ffStshiozak 		break;
712dc7d18ffStshiozak 	}
713dc7d18ffStshiozak 
714dc7d18ffStshiozak eat:
715dc7d18ffStshiozak 	/* no letter to eat */
716dc7d18ffStshiozak 	if (n < 1) {
717dc7d18ffStshiozak 		if (result)
718dc7d18ffStshiozak 			*result = string;
719dc7d18ffStshiozak 		return (_ISO2022INVALID);
720dc7d18ffStshiozak 	}
721dc7d18ffStshiozak 
722dc7d18ffStshiozak 	/* normal chars.  always eat C0/C1 as is. */
723dc7d18ffStshiozak 	if (iscntl(*string & 0xff))
724dc7d18ffStshiozak 		cur = -1;
725dc7d18ffStshiozak 	else if (*string & 0x80) {
726dc7d18ffStshiozak 		cur = (psenc->singlegr == -1)
727dc7d18ffStshiozak 			? psenc->gr : psenc->singlegr;
728dc7d18ffStshiozak 	} else {
729dc7d18ffStshiozak 		cur = (psenc->singlegl == -1)
730dc7d18ffStshiozak 			? psenc->gl : psenc->singlegl;
731dc7d18ffStshiozak 	}
732dc7d18ffStshiozak 
733dc7d18ffStshiozak 	if (cur == -1) {
734dc7d18ffStshiozak asis:
735dc7d18ffStshiozak 		wchar = *string++ & 0xff;
736dc7d18ffStshiozak 		if (result)
737dc7d18ffStshiozak 			*result = string;
738dc7d18ffStshiozak 		/* reset single shift state */
739dc7d18ffStshiozak 		psenc->singlegr = psenc->singlegl = -1;
740dc7d18ffStshiozak 		return wchar;
741dc7d18ffStshiozak 	}
742dc7d18ffStshiozak 
743dc7d18ffStshiozak 	/* length error check */
744dc7d18ffStshiozak 	switch (psenc->g[cur].type) {
745dc7d18ffStshiozak 	case CS94MULTI:
746dc7d18ffStshiozak 	case CS96MULTI:
747dc7d18ffStshiozak 		if (!isthree(psenc->g[cur].final)) {
748dc7d18ffStshiozak 			if (2 <= n
749dc7d18ffStshiozak 			 && (string[0] & 0x80) == (string[1] & 0x80))
750dc7d18ffStshiozak 				break;
751dc7d18ffStshiozak 		} else {
752dc7d18ffStshiozak 			if (3 <= n
753dc7d18ffStshiozak 			 && (string[0] & 0x80) == (string[1] & 0x80)
754dc7d18ffStshiozak 			 && (string[0] & 0x80) == (string[2] & 0x80))
755dc7d18ffStshiozak 				break;
756dc7d18ffStshiozak 		}
757dc7d18ffStshiozak 
758dc7d18ffStshiozak 		/* we still need to wait for more characters to come */
759dc7d18ffStshiozak 		if (result)
7606b58a1b8Stnozaki 			*result = string;
761dc7d18ffStshiozak 		return (_ISO2022INVALID);
762dc7d18ffStshiozak 
763dc7d18ffStshiozak 	case CS94:
764dc7d18ffStshiozak 	case CS96:
765dc7d18ffStshiozak 		if (1 <= n)
766dc7d18ffStshiozak 			break;
767dc7d18ffStshiozak 
768dc7d18ffStshiozak 		/* we still need to wait for more characters to come */
769dc7d18ffStshiozak 		if (result)
7706b58a1b8Stnozaki 			*result = string;
771dc7d18ffStshiozak 		return (_ISO2022INVALID);
772dc7d18ffStshiozak 	}
773dc7d18ffStshiozak 
774dc7d18ffStshiozak 	/* range check */
775dc7d18ffStshiozak 	switch (psenc->g[cur].type) {
776dc7d18ffStshiozak 	case CS94:
777dc7d18ffStshiozak 		if (!(is94(string[0] & 0x7f)))
778dc7d18ffStshiozak 			goto asis;
779dc7d18ffStshiozak 	case CS96:
780dc7d18ffStshiozak 		if (!(is96(string[0] & 0x7f)))
781dc7d18ffStshiozak 			goto asis;
782dc7d18ffStshiozak 		break;
783dc7d18ffStshiozak 	case CS94MULTI:
784dc7d18ffStshiozak 		if (!(is94(string[0] & 0x7f) && is94(string[1] & 0x7f)))
785dc7d18ffStshiozak 			goto asis;
786dc7d18ffStshiozak 		break;
787dc7d18ffStshiozak 	case CS96MULTI:
788dc7d18ffStshiozak 		if (!(is96(string[0] & 0x7f) && is96(string[1] & 0x7f)))
789dc7d18ffStshiozak 			goto asis;
790dc7d18ffStshiozak 		break;
791dc7d18ffStshiozak 	}
792dc7d18ffStshiozak 
793dc7d18ffStshiozak 	/* extract the character. */
794dc7d18ffStshiozak 	switch (psenc->g[cur].type) {
795dc7d18ffStshiozak 	case CS94:
796dc7d18ffStshiozak 		/* special case for ASCII. */
797dc7d18ffStshiozak 		if (psenc->g[cur].final == 'B' && !psenc->g[cur].interm) {
798dc7d18ffStshiozak 			wchar = *string++;
799dc7d18ffStshiozak 			wchar &= 0x7f;
800dc7d18ffStshiozak 			break;
801dc7d18ffStshiozak 		}
802dc7d18ffStshiozak 		wchar = psenc->g[cur].final;
803dc7d18ffStshiozak 		wchar = (wchar << 8);
804dc7d18ffStshiozak 		wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
805dc7d18ffStshiozak 		wchar = (wchar << 8);
806dc7d18ffStshiozak 		wchar = (wchar << 8) | (*string++ & 0x7f);
807dc7d18ffStshiozak 		break;
808dc7d18ffStshiozak 	case CS96:
809dc7d18ffStshiozak 		/* special case for ISO-8859-1. */
810dc7d18ffStshiozak 		if (psenc->g[cur].final == 'A' && !psenc->g[cur].interm) {
811dc7d18ffStshiozak 			wchar = *string++;
812dc7d18ffStshiozak 			wchar &= 0x7f;
813dc7d18ffStshiozak 			wchar |= 0x80;
814dc7d18ffStshiozak 			break;
815dc7d18ffStshiozak 		}
816dc7d18ffStshiozak 		wchar = psenc->g[cur].final;
817dc7d18ffStshiozak 		wchar = (wchar << 8);
818dc7d18ffStshiozak 		wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
819dc7d18ffStshiozak 		wchar = (wchar << 8);
820dc7d18ffStshiozak 		wchar = (wchar << 8) | (*string++ & 0x7f);
821dc7d18ffStshiozak 		wchar |= 0x80;
822dc7d18ffStshiozak 		break;
823dc7d18ffStshiozak 	case CS94MULTI:
824dc7d18ffStshiozak 	case CS96MULTI:
825dc7d18ffStshiozak 		wchar = psenc->g[cur].final;
826dc7d18ffStshiozak 		wchar = (wchar << 8);
827dc7d18ffStshiozak 		if (isthree(psenc->g[cur].final))
828dc7d18ffStshiozak 			wchar |= (*string++ & 0x7f);
829dc7d18ffStshiozak 		wchar = (wchar << 8) | (*string++ & 0x7f);
830dc7d18ffStshiozak 		wchar = (wchar << 8) | (*string++ & 0x7f);
831dc7d18ffStshiozak 		if (psenc->g[cur].type == CS96MULTI)
832dc7d18ffStshiozak 			wchar |= 0x80;
833dc7d18ffStshiozak 		break;
834dc7d18ffStshiozak 	}
835dc7d18ffStshiozak 
836dc7d18ffStshiozak 	if (result)
837dc7d18ffStshiozak 		*result = string;
838dc7d18ffStshiozak 	/* reset single shift state */
839dc7d18ffStshiozak 	psenc->singlegr = psenc->singlegl = -1;
840dc7d18ffStshiozak 	return wchar;
841dc7d18ffStshiozak }
842dc7d18ffStshiozak 
843dc7d18ffStshiozak 
844dc7d18ffStshiozak 
845dc7d18ffStshiozak 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)846dc7d18ffStshiozak _citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * __restrict ei,
847dc7d18ffStshiozak 			     wchar_t * __restrict pwc,
848dc7d18ffStshiozak 			     const char ** __restrict s,
849dc7d18ffStshiozak 			     size_t n, _ISO2022State * __restrict psenc,
850dc7d18ffStshiozak 			     size_t * __restrict nresult)
851dc7d18ffStshiozak {
852dc7d18ffStshiozak 	wchar_t wchar;
853dc7d18ffStshiozak 	const char *s0, *p, *result;
854dc7d18ffStshiozak 	int c;
855dc7d18ffStshiozak 	int chlenbak;
856dc7d18ffStshiozak 
857dc7d18ffStshiozak 	_DIAGASSERT(nresult != 0);
858dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
859dc7d18ffStshiozak 	_DIAGASSERT(psenc != NULL);
860dc7d18ffStshiozak 	_DIAGASSERT(s != NULL);
861dc7d18ffStshiozak 
8620941b12bStnozaki 	if (*s == NULL) {
8630941b12bStnozaki 		_citrus_ISO2022_init_state(ei, psenc);
8640941b12bStnozaki 		*nresult = _ENCODING_IS_STATE_DEPENDENT;
8650941b12bStnozaki 		return 0;
8660941b12bStnozaki 	}
867dc7d18ffStshiozak 	s0 = *s;
868dc7d18ffStshiozak 	c = 0;
869dc7d18ffStshiozak 	chlenbak = psenc->chlen;
870dc7d18ffStshiozak 
871dc7d18ffStshiozak 	/*
872dc7d18ffStshiozak 	 * if we have something in buffer, use that.
873dc7d18ffStshiozak 	 * otherwise, skip here
874dc7d18ffStshiozak 	 */
875dc7d18ffStshiozak 	if (psenc->chlen < 0 || psenc->chlen > sizeof(psenc->ch)) {
876dc7d18ffStshiozak 		/* illgeal state */
877dc7d18ffStshiozak 		_citrus_ISO2022_init_state(ei, psenc);
878dc7d18ffStshiozak 		goto encoding_error;
879dc7d18ffStshiozak 	}
880dc7d18ffStshiozak 	if (psenc->chlen == 0)
881dc7d18ffStshiozak 		goto emptybuf;
882dc7d18ffStshiozak 
883dc7d18ffStshiozak 	/* buffer is not empty */
884dc7d18ffStshiozak 	p = psenc->ch;
885e325eedcSjoerg 	while (psenc->chlen < sizeof(psenc->ch)) {
886dc7d18ffStshiozak 		if (n > 0) {
887dc7d18ffStshiozak 			psenc->ch[psenc->chlen++] = *s0++;
888dc7d18ffStshiozak 			n--;
889dc7d18ffStshiozak 		}
890dc7d18ffStshiozak 
891dc7d18ffStshiozak 		wchar = _ISO2022_sgetwchar(ei, p, psenc->chlen - (p-psenc->ch),
892dc7d18ffStshiozak 					   &result, psenc);
893dc7d18ffStshiozak 		c += result - p;
8941beef8feStshiozak 		if (wchar != _ISO2022INVALID) {
895dc7d18ffStshiozak 			if (psenc->chlen > c)
896dc7d18ffStshiozak 				memmove(psenc->ch, result, psenc->chlen - c);
897dc7d18ffStshiozak 			if (psenc->chlen < c)
898dc7d18ffStshiozak 				psenc->chlen = 0;
899dc7d18ffStshiozak 			else
900dc7d18ffStshiozak 				psenc->chlen -= c;
901dc7d18ffStshiozak 			goto output;
902dc7d18ffStshiozak 		}
903dc7d18ffStshiozak 
9041beef8feStshiozak 		if (n == 0) {
9051beef8feStshiozak 			if ((result - p) == psenc->chlen)
9061beef8feStshiozak 				/* complete shift sequence. */
9071beef8feStshiozak 				psenc->chlen = 0;
908dc7d18ffStshiozak 			goto restart;
909dc7d18ffStshiozak 		}
910dc7d18ffStshiozak 
9111beef8feStshiozak 		p = result;
9121beef8feStshiozak 	}
9131beef8feStshiozak 
914dc7d18ffStshiozak 	/* escape sequence too long? */
915dc7d18ffStshiozak 	goto encoding_error;
916dc7d18ffStshiozak 
917dc7d18ffStshiozak emptybuf:
918dc7d18ffStshiozak 	wchar = _ISO2022_sgetwchar(ei, s0, n, &result, psenc);
919dc7d18ffStshiozak 	if (wchar != _ISO2022INVALID) {
920dc7d18ffStshiozak 		c += result - s0;
921dc7d18ffStshiozak 		psenc->chlen = 0;
922dc7d18ffStshiozak 		s0 = result;
923dc7d18ffStshiozak 		goto output;
924dc7d18ffStshiozak 	}
9251beef8feStshiozak 	if (result > s0) {
926dc7d18ffStshiozak 		c += (result - s0);
927dc7d18ffStshiozak 		n -= (result - s0);
928dc7d18ffStshiozak 		s0 = result;
9291beef8feStshiozak 		if (n>0)
930dc7d18ffStshiozak 			goto emptybuf;
9311beef8feStshiozak 		/* complete shift sequence. */
9321beef8feStshiozak 		goto restart;
933dc7d18ffStshiozak 	}
934dc7d18ffStshiozak 	n += c;
935dc7d18ffStshiozak 	if (n < sizeof(psenc->ch)) {
936dc7d18ffStshiozak 		memcpy(psenc->ch, s0 - c, n);
937dc7d18ffStshiozak 		psenc->chlen = n;
938dc7d18ffStshiozak 		s0 = result;
939dc7d18ffStshiozak 		goto restart;
940dc7d18ffStshiozak 	}
941dc7d18ffStshiozak 
942dc7d18ffStshiozak 	/* escape sequence too long? */
943dc7d18ffStshiozak 
944dc7d18ffStshiozak encoding_error:
945dc7d18ffStshiozak 	psenc->chlen = 0;
946dc7d18ffStshiozak 	*nresult = (size_t)-1;
947dc7d18ffStshiozak 	return (EILSEQ);
948dc7d18ffStshiozak 
949dc7d18ffStshiozak output:
950dc7d18ffStshiozak 	*s = s0;
951dc7d18ffStshiozak 	if (pwc)
952dc7d18ffStshiozak 		*pwc = wchar;
953dc7d18ffStshiozak 
954dc7d18ffStshiozak 	if (!wchar)
955dc7d18ffStshiozak 		*nresult = 0;
956dc7d18ffStshiozak 	else
957dc7d18ffStshiozak 		*nresult = c - chlenbak;
958dc7d18ffStshiozak 
959dc7d18ffStshiozak 	return (0);
960dc7d18ffStshiozak 
961dc7d18ffStshiozak restart:
962dc7d18ffStshiozak 	*s = s0;
963dc7d18ffStshiozak 	*nresult = (size_t)-2;
964dc7d18ffStshiozak 
965dc7d18ffStshiozak 	return (0);
966dc7d18ffStshiozak }
967dc7d18ffStshiozak 
968dc7d18ffStshiozak static int
recommendation(_ISO2022EncodingInfo * __restrict ei,_ISO2022Charset * __restrict cs)969dc7d18ffStshiozak recommendation(_ISO2022EncodingInfo * __restrict ei,
970dc7d18ffStshiozak 	       _ISO2022Charset * __restrict cs)
971dc7d18ffStshiozak {
972dc7d18ffStshiozak 	int i, j;
973dc7d18ffStshiozak 	_ISO2022Charset *recommend;
974dc7d18ffStshiozak 
975dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
976dc7d18ffStshiozak 	_DIAGASSERT(cs != NULL);
977dc7d18ffStshiozak 
978dc7d18ffStshiozak 	/* first, try a exact match. */
979dc7d18ffStshiozak 	for (i = 0; i < 4; i++) {
980dc7d18ffStshiozak 		recommend = ei->recommend[i];
981dc7d18ffStshiozak 		for (j = 0; j < ei->recommendsize[i]; j++) {
982dc7d18ffStshiozak 			if (cs->type != recommend[j].type)
983dc7d18ffStshiozak 				continue;
984dc7d18ffStshiozak 			if (cs->final != recommend[j].final)
985dc7d18ffStshiozak 				continue;
986dc7d18ffStshiozak 			if (cs->interm != recommend[j].interm)
987dc7d18ffStshiozak 				continue;
988dc7d18ffStshiozak 
989dc7d18ffStshiozak 			return i;
990dc7d18ffStshiozak 		}
991dc7d18ffStshiozak 	}
992dc7d18ffStshiozak 
993dc7d18ffStshiozak 	/* then, try a wildcard match over final char. */
994dc7d18ffStshiozak 	for (i = 0; i < 4; i++) {
995dc7d18ffStshiozak 		recommend = ei->recommend[i];
996dc7d18ffStshiozak 		for (j = 0; j < ei->recommendsize[i]; j++) {
997dc7d18ffStshiozak 			if (cs->type != recommend[j].type)
998dc7d18ffStshiozak 				continue;
999dc7d18ffStshiozak 			if (cs->final && (cs->final != recommend[j].final))
1000dc7d18ffStshiozak 				continue;
1001dc7d18ffStshiozak 			if (cs->interm && (cs->interm != recommend[j].interm))
1002dc7d18ffStshiozak 				continue;
1003dc7d18ffStshiozak 
1004dc7d18ffStshiozak 			return i;
1005dc7d18ffStshiozak 		}
1006dc7d18ffStshiozak 	}
1007dc7d18ffStshiozak 
1008dc7d18ffStshiozak 	/* there's no recommendation. make a guess. */
1009dc7d18ffStshiozak 	if (ei->maxcharset == 0) {
1010dc7d18ffStshiozak 		return 0;
1011dc7d18ffStshiozak 	} else {
1012dc7d18ffStshiozak 		switch (cs->type) {
1013dc7d18ffStshiozak 		case CS94:
1014dc7d18ffStshiozak 		case CS94MULTI:
1015dc7d18ffStshiozak 			return 0;
1016dc7d18ffStshiozak 		case CS96:
1017dc7d18ffStshiozak 		case CS96MULTI:
1018dc7d18ffStshiozak 			return 1;
1019dc7d18ffStshiozak 		}
1020dc7d18ffStshiozak 	}
1021dc7d18ffStshiozak 	return 0;
1022dc7d18ffStshiozak }
1023dc7d18ffStshiozak 
1024dc7d18ffStshiozak 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)102504e58308Stshiozak _ISO2022_sputwchar(_ISO2022EncodingInfo * __restrict ei, wchar_t wc,
1026dc7d18ffStshiozak 		   char * __restrict string, size_t n,
1027dc7d18ffStshiozak 		   char ** __restrict result,
1028fca38949Stnozaki 		   _ISO2022State * __restrict psenc,
1029fca38949Stnozaki 		   size_t * __restrict nresult)
1030dc7d18ffStshiozak {
1031fca38949Stnozaki 	int i = 0;
1032fca38949Stnozaki 	size_t len;
1033dc7d18ffStshiozak 	_ISO2022Charset cs;
1034dc7d18ffStshiozak 	char *p;
1035dc7d18ffStshiozak 	char tmp[MB_LEN_MAX];
1036dc7d18ffStshiozak 	int target;
1037dc7d18ffStshiozak 	u_char mask;
1038dc7d18ffStshiozak 	int bit8;
1039dc7d18ffStshiozak 
1040dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
1041dc7d18ffStshiozak 	_DIAGASSERT(string != NULL);
1042dc7d18ffStshiozak 	/* result may be NULL */
1043fca38949Stnozaki 	_DIAGASSERT(psenc != NULL);
1044fca38949Stnozaki 	_DIAGASSERT(nresult != NULL);
1045dc7d18ffStshiozak 
1046fca38949Stnozaki 	if (isc0(wc & 0xff)) {
1047b29e60b3Stnozaki 		/* go back to INIT0 or ASCII on control chars */
1048b29e60b3Stnozaki 		cs = ei->initg[0].final ? ei->initg[0] : ascii;
1049fca38949Stnozaki 	} else if (isc1(wc & 0xff)) {
1050fca38949Stnozaki 		/* go back to INIT1 or ISO-8859-1 on control chars */
1051fca38949Stnozaki 		cs = ei->initg[1].final ? ei->initg[1] : iso88591;
105204e58308Stshiozak 	} else if (!(wc & ~0xff)) {
105304e58308Stshiozak 		if (wc & 0x80) {
1054dc7d18ffStshiozak 			/* special treatment for ISO-8859-1 */
1055b29e60b3Stnozaki 			cs = iso88591;
1056dc7d18ffStshiozak 		} else {
1057dc7d18ffStshiozak 			/* special treatment for ASCII */
1058b29e60b3Stnozaki 			cs = ascii;
1059dc7d18ffStshiozak 		}
1060dc7d18ffStshiozak 	} else {
106104e58308Stshiozak 		cs.final = (wc >> 24) & 0x7f;
106204e58308Stshiozak 		if ((wc >> 16) & 0x80)
106304e58308Stshiozak 			cs.interm = (wc >> 16) & 0x7f;
1064dc7d18ffStshiozak 		else
1065dc7d18ffStshiozak 			cs.interm = '\0';
106604e58308Stshiozak 		if (wc & 0x80)
106704e58308Stshiozak 			cs.type = (wc & 0x00007f00) ? CS96MULTI : CS96;
1068dc7d18ffStshiozak 		else
106904e58308Stshiozak 			cs.type = (wc & 0x00007f00) ? CS94MULTI : CS94;
1070dc7d18ffStshiozak 	}
1071dc7d18ffStshiozak 	target = recommendation(ei, &cs);
1072dc7d18ffStshiozak 	p = tmp;
1073dc7d18ffStshiozak 	bit8 = ei->flags & F_8BIT;
1074dc7d18ffStshiozak 
1075dc7d18ffStshiozak 	/* designate the charset onto the target plane(G0/1/2/3). */
1076dc7d18ffStshiozak 	if (psenc->g[target].type == cs.type
1077dc7d18ffStshiozak 	 && psenc->g[target].final == cs.final
1078dc7d18ffStshiozak 	 && psenc->g[target].interm == cs.interm)
1079dc7d18ffStshiozak 		goto planeok;
1080dc7d18ffStshiozak 
1081dc7d18ffStshiozak 	*p++ = '\033';
1082dc7d18ffStshiozak 	if (cs.type == CS94MULTI || cs.type == CS96MULTI)
1083dc7d18ffStshiozak 		*p++ = '$';
1084dc7d18ffStshiozak 	if (target == 0 && cs.type == CS94MULTI && strchr("@AB", cs.final)
1085dc7d18ffStshiozak 	 && !cs.interm && !(ei->flags & F_NOOLD))
1086dc7d18ffStshiozak 		;
1087dc7d18ffStshiozak 	else if (cs.type == CS94 || cs.type == CS94MULTI)
1088dc7d18ffStshiozak 		*p++ = "()*+"[target];
1089dc7d18ffStshiozak 	else
1090dc7d18ffStshiozak 		*p++ = ",-./"[target];
1091dc7d18ffStshiozak 	if (cs.interm)
1092dc7d18ffStshiozak 		*p++ = cs.interm;
1093dc7d18ffStshiozak 	*p++ = cs.final;
1094dc7d18ffStshiozak 
1095dc7d18ffStshiozak 	psenc->g[target].type = cs.type;
1096dc7d18ffStshiozak 	psenc->g[target].final = cs.final;
1097dc7d18ffStshiozak 	psenc->g[target].interm = cs.interm;
1098dc7d18ffStshiozak 
1099dc7d18ffStshiozak planeok:
1100dc7d18ffStshiozak 	/* invoke the plane onto GL or GR. */
1101dc7d18ffStshiozak 	if (psenc->gl == target)
1102dc7d18ffStshiozak 		goto sideok;
1103dc7d18ffStshiozak 	if (bit8 && psenc->gr == target)
1104dc7d18ffStshiozak 		goto sideok;
1105dc7d18ffStshiozak 
1106dc7d18ffStshiozak 	if (target == 0 && (ei->flags & F_LS0)) {
1107dc7d18ffStshiozak 		*p++ = '\017';
1108dc7d18ffStshiozak 		psenc->gl = 0;
1109dc7d18ffStshiozak 	} else if (target == 1 && (ei->flags & F_LS1)) {
1110dc7d18ffStshiozak 		*p++ = '\016';
1111dc7d18ffStshiozak 		psenc->gl = 1;
1112dc7d18ffStshiozak 	} else if (target == 2 && (ei->flags & F_LS2)) {
1113dc7d18ffStshiozak 		*p++ = '\033';
1114dc7d18ffStshiozak 		*p++ = 'n';
1115dc7d18ffStshiozak 		psenc->gl = 2;
1116dc7d18ffStshiozak 	} else if (target == 3 && (ei->flags & F_LS3)) {
1117dc7d18ffStshiozak 		*p++ = '\033';
1118dc7d18ffStshiozak 		*p++ = 'o';
1119dc7d18ffStshiozak 		psenc->gl = 3;
1120dc7d18ffStshiozak 	} else if (bit8 && target == 1 && (ei->flags & F_LS1R)) {
1121dc7d18ffStshiozak 		*p++ = '\033';
1122dc7d18ffStshiozak 		*p++ = '~';
1123dc7d18ffStshiozak 		psenc->gr = 1;
1124dc7d18ffStshiozak 	} else if (bit8 && target == 2 && (ei->flags & F_LS2R)) {
1125dc7d18ffStshiozak 		*p++ = '\033';
1126dc7d18ffStshiozak 		/*{*/
1127dc7d18ffStshiozak 		*p++ = '}';
1128dc7d18ffStshiozak 		psenc->gr = 2;
1129dc7d18ffStshiozak 	} else if (bit8 && target == 3 && (ei->flags & F_LS3R)) {
1130dc7d18ffStshiozak 		*p++ = '\033';
1131dc7d18ffStshiozak 		*p++ = '|';
1132dc7d18ffStshiozak 		psenc->gr = 3;
1133dc7d18ffStshiozak 	} else if (target == 2 && (ei->flags & F_SS2)) {
1134dc7d18ffStshiozak 		*p++ = '\033';
1135dc7d18ffStshiozak 		*p++ = 'N';
1136dc7d18ffStshiozak 		psenc->singlegl = 2;
1137dc7d18ffStshiozak 	} else if (target == 3 && (ei->flags & F_SS3)) {
1138dc7d18ffStshiozak 		*p++ = '\033';
1139dc7d18ffStshiozak 		*p++ = 'O';
1140dc7d18ffStshiozak 		psenc->singlegl = 3;
1141dc7d18ffStshiozak 	} else if (bit8 && target == 2 && (ei->flags & F_SS2R)) {
1142dc7d18ffStshiozak 		*p++ = '\216';
1143dc7d18ffStshiozak 		*p++ = 'N';
1144dc7d18ffStshiozak 		psenc->singlegl = psenc->singlegr = 2;
1145dc7d18ffStshiozak 	} else if (bit8 && target == 3 && (ei->flags & F_SS3R)) {
1146dc7d18ffStshiozak 		*p++ = '\217';
1147dc7d18ffStshiozak 		*p++ = 'O';
1148dc7d18ffStshiozak 		psenc->singlegl = psenc->singlegr = 3;
1149dc7d18ffStshiozak 	} else
1150fca38949Stnozaki 		goto ilseq;
1151dc7d18ffStshiozak 
1152dc7d18ffStshiozak sideok:
1153dc7d18ffStshiozak 	if (psenc->singlegl == target)
1154dc7d18ffStshiozak 		mask = 0x00;
1155dc7d18ffStshiozak 	else if (psenc->singlegr == target)
1156dc7d18ffStshiozak 		mask = 0x80;
1157dc7d18ffStshiozak 	else if (psenc->gl == target)
1158dc7d18ffStshiozak 		mask = 0x00;
1159dc7d18ffStshiozak 	else if ((ei->flags & F_8BIT) && psenc->gr == target)
1160dc7d18ffStshiozak 		mask = 0x80;
1161dc7d18ffStshiozak 	else
1162fca38949Stnozaki 		goto ilseq;
1163dc7d18ffStshiozak 
1164dc7d18ffStshiozak 	switch (cs.type) {
1165dc7d18ffStshiozak 	case CS94:
1166dc7d18ffStshiozak 	case CS96:
1167dc7d18ffStshiozak 		i = 1;
1168dc7d18ffStshiozak 		break;
1169dc7d18ffStshiozak 	case CS94MULTI:
1170dc7d18ffStshiozak 	case CS96MULTI:
1171b29e60b3Stnozaki 		i = !iscntl(wc & 0xff) ?
1172b29e60b3Stnozaki 		    (isthree(cs.final) ? 3 : 2) : 1;
1173dc7d18ffStshiozak 		break;
1174dc7d18ffStshiozak 	}
1175dc7d18ffStshiozak 	while (i-- > 0)
117604e58308Stshiozak 		*p++ = ((wc >> (i << 3)) & 0x7f) | mask;
1177dc7d18ffStshiozak 
1178dc7d18ffStshiozak 	/* reset single shift state */
1179dc7d18ffStshiozak 	psenc->singlegl = psenc->singlegr = -1;
1180dc7d18ffStshiozak 
1181fca38949Stnozaki 	len = (size_t)(p - tmp);
1182dc7d18ffStshiozak 	if (n < len) {
1183dc7d18ffStshiozak 		if (result)
1184dc7d18ffStshiozak 			*result = (char *)0;
1185fca38949Stnozaki 		*nresult = (size_t)-1;
1186fca38949Stnozaki 		return E2BIG;
1187fca38949Stnozaki 	}
1188dc7d18ffStshiozak 	if (result)
1189dc7d18ffStshiozak 		*result = string + len;
1190dc7d18ffStshiozak 	memcpy(string, tmp, len);
1191fca38949Stnozaki 	*nresult = len;
1192fca38949Stnozaki 
1193fca38949Stnozaki 	return 0;
1194fca38949Stnozaki 
1195fca38949Stnozaki ilseq:
1196fca38949Stnozaki 	*nresult = (size_t)-1;
1197fca38949Stnozaki 	return EILSEQ;
1198dc7d18ffStshiozak }
1199dc7d18ffStshiozak 
1200dc7d18ffStshiozak static int
_citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * __restrict ei,char * __restrict s,size_t n,_ISO2022State * __restrict psenc,size_t * __restrict nresult)1201f3995f1aStshiozak _citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * __restrict ei,
1202f3995f1aStshiozak 				char * __restrict s, size_t n,
1203f3995f1aStshiozak 				_ISO2022State * __restrict psenc,
1204f3995f1aStshiozak 				size_t * __restrict nresult)
1205f3995f1aStshiozak {
1206f3995f1aStshiozak 	char buf[MB_LEN_MAX];
1207f3995f1aStshiozak 	char *result;
1208fca38949Stnozaki 	int ret;
1209fca38949Stnozaki 	size_t len;
1210f3995f1aStshiozak 
1211f3995f1aStshiozak 	_DIAGASSERT(ei != NULL);
1212f3995f1aStshiozak 	_DIAGASSERT(nresult != 0);
1213f3995f1aStshiozak 	_DIAGASSERT(s != NULL);
1214f3995f1aStshiozak 
1215f3995f1aStshiozak 	/* XXX state will be modified after this operation... */
1216fca38949Stnozaki 	ret = _ISO2022_sputwchar(ei, L'\0', buf, sizeof(buf), &result, psenc,
1217fca38949Stnozaki 	    &len);
1218fca38949Stnozaki 	if (ret) {
1219fca38949Stnozaki 		*nresult = len;
1220fca38949Stnozaki 		return ret;
1221f3995f1aStshiozak 	}
1222fca38949Stnozaki 
1223f3995f1aStshiozak 	if (sizeof(buf) < len || n < len-1) {
1224f3995f1aStshiozak 		/* XXX should recover state? */
1225fca38949Stnozaki 		*nresult = (size_t)-1;
1226fca38949Stnozaki 		return E2BIG;
1227f3995f1aStshiozak 	}
1228f3995f1aStshiozak 
1229f3995f1aStshiozak 	memcpy(s, buf, len-1);
1230fca38949Stnozaki 	*nresult = len-1;
1231f3995f1aStshiozak 	return (0);
1232f3995f1aStshiozak }
1233f3995f1aStshiozak 
1234f3995f1aStshiozak 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)1235dc7d18ffStshiozak _citrus_ISO2022_wcrtomb_priv(_ISO2022EncodingInfo * __restrict ei,
1236dc7d18ffStshiozak 			     char * __restrict s, size_t n, wchar_t wc,
1237dc7d18ffStshiozak 			     _ISO2022State * __restrict psenc,
1238dc7d18ffStshiozak 			     size_t * __restrict nresult)
1239dc7d18ffStshiozak {
1240dc7d18ffStshiozak 	char buf[MB_LEN_MAX];
1241dc7d18ffStshiozak 	char *result;
1242fca38949Stnozaki 	int ret;
1243fca38949Stnozaki 	size_t len;
1244dc7d18ffStshiozak 
1245dc7d18ffStshiozak 	_DIAGASSERT(ei != NULL);
1246dc7d18ffStshiozak 	_DIAGASSERT(s != NULL);
1247fca38949Stnozaki 	_DIAGASSERT(psenc != NULL);
1248fca38949Stnozaki 	_DIAGASSERT(nresult != 0);
1249dc7d18ffStshiozak 
1250dc7d18ffStshiozak 	/* XXX state will be modified after this operation... */
1251fca38949Stnozaki 	ret = _ISO2022_sputwchar(ei, wc, buf, sizeof(buf), &result, psenc,
1252fca38949Stnozaki 	    &len);
1253fca38949Stnozaki 	if (ret) {
1254fca38949Stnozaki 		*nresult = len;
1255fca38949Stnozaki 		return ret;
1256fca38949Stnozaki 	}
1257fca38949Stnozaki 
1258dc7d18ffStshiozak 	if (sizeof(buf) < len || n < len) {
1259dc7d18ffStshiozak 		/* XXX should recover state? */
1260fca38949Stnozaki 		*nresult = (size_t)-1;
1261fca38949Stnozaki 		return E2BIG;
1262dc7d18ffStshiozak 	}
1263dc7d18ffStshiozak 
1264dc7d18ffStshiozak 	memcpy(s, buf, len);
1265fca38949Stnozaki 	*nresult = len;
1266dc7d18ffStshiozak 	return (0);
126704e58308Stshiozak }
126804e58308Stshiozak 
126904e58308Stshiozak static __inline int
127004e58308Stshiozak /*ARGSUSED*/
_citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * __restrict ei,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)127104e58308Stshiozak _citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * __restrict ei,
127204e58308Stshiozak 			      _csid_t * __restrict csid,
127304e58308Stshiozak 			      _index_t * __restrict idx, wchar_t wc)
127404e58308Stshiozak {
127504e58308Stshiozak 	wchar_t m, nm;
127604e58308Stshiozak 
127704e58308Stshiozak 	_DIAGASSERT(csid != NULL && idx != NULL);
127804e58308Stshiozak 
127904e58308Stshiozak 	m = wc & 0x7FFF8080;
128004e58308Stshiozak 	nm = wc & 0x007F7F7F;
128104e58308Stshiozak 	if (m & 0x00800000) {
128204e58308Stshiozak 		nm &= 0x00007F7F;
128304e58308Stshiozak 	} else {
128404e58308Stshiozak 		m &= 0x7F008080;
128504e58308Stshiozak 	}
128604e58308Stshiozak 	if (nm & 0x007F0000) {
128704e58308Stshiozak 		/* ^3 mark */
128804e58308Stshiozak 		m |= 0x007F0000;
128904e58308Stshiozak 	} else if (nm & 0x00007F00) {
129004e58308Stshiozak 		/* ^2 mark */
129104e58308Stshiozak 		m |= 0x00007F00;
129204e58308Stshiozak 	}
129304e58308Stshiozak 	*csid = (_csid_t)m;
129404e58308Stshiozak 	*idx  = (_index_t)nm;
129504e58308Stshiozak 
129604e58308Stshiozak 	return (0);
129704e58308Stshiozak }
129804e58308Stshiozak 
129904e58308Stshiozak static __inline int
130004e58308Stshiozak /*ARGSUSED*/
_citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * __restrict ei,wchar_t * __restrict wc,_csid_t csid,_index_t idx)130104e58308Stshiozak _citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * __restrict ei,
130204e58308Stshiozak 			      wchar_t * __restrict wc,
130304e58308Stshiozak 			      _csid_t csid, _index_t idx)
130404e58308Stshiozak {
130504e58308Stshiozak 
130604e58308Stshiozak 	_DIAGASSERT(ei != NULL && wc != NULL);
130704e58308Stshiozak 
130804e58308Stshiozak 	*wc = (wchar_t)(csid & 0x7F808080) | (wchar_t)idx;
130904e58308Stshiozak 
131004e58308Stshiozak 	return (0);
1311dc7d18ffStshiozak }
1312dc7d18ffStshiozak 
13131beef8feStshiozak static __inline int
13141beef8feStshiozak /*ARGSUSED*/
_citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * __restrict ei,_ISO2022State * __restrict psenc,int * __restrict rstate)13151beef8feStshiozak _citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * __restrict ei,
13161beef8feStshiozak 					      _ISO2022State * __restrict psenc,
13171beef8feStshiozak 					      int * __restrict rstate)
13181beef8feStshiozak {
13191beef8feStshiozak 
13201beef8feStshiozak 	if (psenc->chlen == 0) {
13211beef8feStshiozak 		/* XXX: it should distinguish initial and stable. */
13221beef8feStshiozak 		*rstate = _STDENC_SDGEN_STABLE;
13231beef8feStshiozak 	} else {
13241beef8feStshiozak 		if (psenc->ch[0] == '\033')
13251beef8feStshiozak 			*rstate = _STDENC_SDGEN_INCOMPLETE_SHIFT;
13261beef8feStshiozak 		else
13271beef8feStshiozak 			*rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
13281beef8feStshiozak 	}
13291beef8feStshiozak 
13301beef8feStshiozak 	return 0;
13311beef8feStshiozak }
13321beef8feStshiozak 
1333dc7d18ffStshiozak /* ----------------------------------------------------------------------
1334dc7d18ffStshiozak  * public interface for ctype
1335dc7d18ffStshiozak  */
1336dc7d18ffStshiozak 
1337dc7d18ffStshiozak _CITRUS_CTYPE_DECLS(ISO2022);
1338dc7d18ffStshiozak _CITRUS_CTYPE_DEF_OPS(ISO2022);
1339dc7d18ffStshiozak 
1340dc7d18ffStshiozak #include "citrus_ctype_template.h"
134104e58308Stshiozak 
134204e58308Stshiozak /* ----------------------------------------------------------------------
134304e58308Stshiozak  * public interface for stdenc
134404e58308Stshiozak  */
134504e58308Stshiozak 
134604e58308Stshiozak _CITRUS_STDENC_DECLS(ISO2022);
134704e58308Stshiozak _CITRUS_STDENC_DEF_OPS(ISO2022);
134804e58308Stshiozak 
134904e58308Stshiozak #include "citrus_stdenc_template.h"
1350