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