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