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