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