/*
 * Copyright (c) 1999 Sun Microsystems, Inc.
 * Copyright (c) 1999 Nihon Sun Microsystems K.K.
 * All rights reserved.
 */

/*
 * "$Id: euc_ct.c,v 1.1.1.1 2000/10/29 16:44:42 himi Exp $"
 */

#pragma ident	"@(#)euc_ct.c 1.8	99/05/20 SMI"


#include "config.h"

#if defined(CSC_WCS_CTEX)
#  define CSC_WCS_CT	1
#endif /* CSC_WCS_CTEX */

#if defined(CSC_WCS_CT)
#  define CSC_EUC_CT	1
#endif /* CSC_WCS_CT */

#if defined(CSC_PCKW_CT)
#  define CSC_WCS_CT	1
#endif /* CSC_PCKW_CT */

#if defined(CSC_CNS_CT)
#  define CSC_EUC_CT	1
#endif /* CSC_CNS_CT */

#if defined(CSC_CNSW_CT)
#  define CSC_EUC_CT	1
#  define CSC_WCS_CT	1
#endif /* CSC_CNSW_CT */

#if defined(CSC_BIG5_CT)
#  define CSC_EUC_CT	1
#endif /* CSC_BIG5_CT */

#if defined(CSC_BIG5W_CT)
#  define CSC_EUC_CT	1
#  define CSC_WCS_CT	1
#endif /* CSC_BIG5W_CT */

#if defined(CSC_EUC_CT)
#if defined(CSC_MBS_CTEX) || defined(CSC_PCK_CT)
error {error} error
#endif /* CSC_MBS_CTEX || CSC_PCK_CT */
#else /* !CSC_EUC_CT */
#if defined(CSC_MBS_CTEX) && defined(CSC_PCK_CT)
error {error} error
#endif /* CSC_MBS_CTEX && CSC_PCK_CT */
#endif /* !CSC_EUC_CT */

#if defined(CSC_EUCW_CT)
#if defined(CSC_WCS_CTEX) || defined(CSC_PCKW_CT)
error {error} error
#endif /* CSC_WCS_CTEX || CSC_PCKW_CT */
#else /* !CSC_EUCW_CT */
#if defined(CSC_WCS_CTEX) && defined(CSC_PCKW_CT)
error {error} error
#endif /* CSC_WCS_CTEX && CSC_PCKW_CT */
#endif /* !CSC_EUCW_CT */


#if defined(CSC_PCK_CT) || defined(CSC_PCKW_CT)
#define CSC_USE_ICONV		1
#define CSC_EUC_CT		1
#endif /* CSC_PCK_CT || CSC_PCKW_CT */

#if defined(CSC_PCKW_CT)
#define CSC_EUCW_CT		1
#endif

#if defined(CSC_PCKW_CT)
#define CSC_EUCW_CT		1
#endif

#if defined(CSC_BIG5_CT) || defined(CSC_BIG5W_CT)
#define CSC_USE_ICONV		1
#define CSC_EUC_CT		1
#endif /* CSC_BIG5_CT || CSC_BIG5W_CT */

#if defined(CSC_WCS_CT) || (CSC_USE_ICONV)
#define CSC_SET_LOCALE		1
#else /* !(CSC_WCS_CT || CSC_USE_ICONV) */
#undef CSC_SET_LOCALE
#endif /* !(CSC_WCS_CT || CSC_USE_ICONV) */

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#if defined(CSC_SET_LOCALE)
#include <locale.h>
#include <wchar.h>
#endif /* CSC_SET_LOCALE */
#include <errno.h>
#include <sys/types.h>
#if defined(CSC_USE_ICONV)
#include <sys/param.h>
#endif /* CSC_USE_ICONV */

#include "csconv.h"
#include "ct_map.h"
#include "euc_ct_set.h"

#if defined(CSC_USE_ICONV)
#include <iconv.h>
#include "csc_norm.h"
#endif /* CSC_USE_ICONV */


#if defined(CSC_EUC_CT)
#define EUC_CS0		(0)
#define EUC_CS1		(1)
#define EUC_CS2		(2)
#define EUC_CS3		(3)

#define SS2		(0x8E)
#define SS3		(0x8F)
#endif /* CSC_EUC_CT */

#if defined(CSC_PCK_CT)
#define PCK_CS0		(0)
#define PCK_CS1		(1)
#define PCK_CS2		(2)
#define PCK_CS3		(3)
#endif /* CSC_PCK_CT */

#if defined(CSC_MBS_CTEX)
#define MBS_CS0		(0)
#define MBS_CS1		(1)
#define MBS_CS2		(2)
#define MBS_CS3		(3)
#endif /* CSC_MBS_CTEX */

#define	MAXVAL_14BIT		((16 * 1024) - 1)
#define	ERROR_BREAK(err)	ret_errno = (err);	\
				ret_val = (size_t)(-1);	\
				break


#if defined(CSC_USE_ICONV)
#  define EUC_BUF_LEN	(32)
#endif /* CSC_USE_ICONV */

#if defined(CSC_WCS_CT)
#  define MB_BUF_LEN	(32)
#if defined(CSC_WCS_CTEX)
#  define euc_ct_open	wcs_ctex_open
#  define euc_ct_close	wcs_ctex_close
#  define euc_ct_conv	wcs_ctex_conv
#else /* !CSC_WCS_CTEX */
#if defined(CSC_PCKW_CT)
#  define euc_ct_open	pckw_ct_open
#  define euc_ct_close	pckw_ct_close
#  define euc_ct_conv	pckw_ct_conv
#else /* !CSC_PCKW_CT */
#  define euc_ct_open	eucw_ct_open
#  define euc_ct_close	eucw_ct_close
#  define euc_ct_conv	eucw_ct_conv
#endif /* !CSC_PCKW_CT */
#endif /* !CSC_WCS_CTEX */
#else /* !CSC_WCS_CT */
#if defined(CSC_MBS_CTEX)
#  define euc_ct_open	mbs_ctex_open
#  define euc_ct_close	mbs_ctex_close
#  define euc_ct_conv	mbs_ctex_conv
#else /* !CSC_MBS_CTEX */
#if defined(CSC_PCK_CT)
#  define euc_ct_open	pck_ct_open
#  define euc_ct_close	pck_ct_close
#  define euc_ct_conv	pck_ct_conv
#else /* !CSC_PCK_CT */
#endif /* !CSC_PCK_CT */
#endif /* !CSC_MBS_CTEX */
#endif /* !CSC_WCS_CT */

#if defined(CSC_CNS_CT)
#  undef euc_ct_open
#  undef euc_ct_close
#  undef euc_ct_conv
#  define euc_ct_open	cns_ct_open
#  define euc_ct_close	cns_ct_close
#  define euc_ct_conv	cns_ct_conv
#else /* !CSC_CNS_CT */
#if defined(CSC_CNSW_CT)
#  undef euc_ct_open
#  undef euc_ct_close
#  undef euc_ct_conv
#  define euc_ct_open	cnsw_ct_open
#  define euc_ct_close	cnsw_ct_close
#  define euc_ct_conv	cnsw_ct_conv
#else /* !CSC_CNSW_CT */
#endif /* !CSC_CNSW_CT */
#endif /* !CSC_CNS_CT */

#if defined(CSC_BIG5_CT)
#  undef euc_ct_open
#  undef euc_ct_close
#  undef euc_ct_conv
#  define euc_ct_open	big5_ct_open
#  define euc_ct_close	big5_ct_close
#  define euc_ct_conv	big5_ct_conv
#else /* !CSC_BIG5_CT */
#if defined(CSC_BIG5W_CT)
#  undef euc_ct_open
#  undef euc_ct_close
#  undef euc_ct_conv
#  define euc_ct_open	big5w_ct_open
#  define euc_ct_close	big5w_ct_close
#  define euc_ct_conv	big5w_ct_conv
#else /* !CSC_BIG5W_CT */
#endif /* !CSC_BIG5W_CT */
#endif /* !CSC_BIG5_CT */

#if !defined(INTERIM_ENCODING)
#define INTERIM_ENCODING	"UTF-8"
#endif /* !INTERIM_ENCODING */
#if !defined(INTERIM_ENCODING_DELIM)
#define INTERIM_ENCODING_DELIM '%'
#endif /* !INTERIM_ENCODING_DELIM */


typedef struct _csc_state {
	const csc_euc_ct_set_t *	euc_ct_set;
#if defined(CSC_USE_ICONV)
	iconv_t				iconv_cd;
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	char *				locale;
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
	unsigned char *			mb_buf;
#endif /* CSC_WCS_CT */
} csc_state_t;


extern const csc_euc_ct_set_t	euc_ct_set[];


csc_state_t *
euc_ct_open(
	const char *	locale,
	const char *	tocode,
	const char *	fromcode)
{
	csc_state_t *			csc_state;
	const csc_euc_ct_set_t *	ecs;
	int				i;
	int				ret_errno;
#if defined(CSC_USE_ICONV)
	iconv_t				iconv_cd;
	csc_norm_encoding_t *		norm_encoding;
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	char *				locale_dup;
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
	unsigned char *			mb_buf;
#endif /* CSC_WCS_CT */
#if defined(CSC_USE_ICONV)
	char				interim_encoding_buf[MAXPATHLEN];
	char *				interim_encoding;
	char *				p;
	int				n;
	int				len;
#endif /* 0 */

	csc_state = NULL;
	ecs = NULL;
#if defined(CSC_USE_ICONV)
	iconv_cd = (iconv_t)(-1);
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	locale_dup = NULL;
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
	mb_buf = NULL;
#endif /* CSC_WCS_CT */

#if defined(CSC_USE_ICONV)
	p = strchr(tocode, INTERIM_ENCODING_DELIM);
	if (NULL == p) {
		interim_encoding = INTERIM_ENCODING;
	} else {
		len = strlen(tocode);
		n = (p - tocode);

		if (((sizeof (interim_encoding_buf)) <= n) ||
		    (n <= 0) ||
		    (strlen(tocode) <= (n + 1))) {
			errno = EINVAL;
			return NULL;
		}

		interim_encoding = interim_encoding_buf;
		memcpy(interim_encoding_buf, tocode, n);
		interim_encoding_buf[n] = '\0';
		tocode = tocode + n + 1;
	}

	norm_encoding = NULL;

#endif /* CSC_USE_ICONV */

	do {
		for (i = 0; NULL != euc_ct_set[i].name; i++) {
			if (0 == strcmp(tocode, euc_ct_set[i].name)) {
				ecs = (euc_ct_set + i);
				break;
			}
		}
		if (NULL == ecs) {
			ret_errno = EINVAL;
			continue;
		}

		csc_state = malloc(sizeof (*csc_state));
		if (NULL == csc_state) {
			ret_errno = ENOMEM;
			continue;
		}

#if defined(CSC_USE_ICONV)
		norm_encoding = csc_norm_encoding(CSC_SYSTEM_NAME,
						  locale,
						  interim_encoding,
						  fromcode);
		if (NULL == norm_encoding) {
			iconv_cd = iconv_open(interim_encoding, fromcode);
		} else {
			iconv_cd = iconv_open(norm_encoding->encoding2,
					      norm_encoding->encoding1);
		}

		if ((iconv_t)(-1) == iconv_cd) {
			ret_errno = EINVAL;
			continue;
		}

		csc_norm_free(norm_encoding);
		norm_encoding = NULL;
#endif /* CSC_USE_ICONV */

#if defined(CSC_SET_LOCALE)
		locale_dup = strdup(locale);
		if (NULL == locale_dup) {
			ret_errno = ENOMEM;
			continue;
		}
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
		if (MB_BUF_LEN < MB_CUR_MAX) {
			mb_buf = malloc(MB_CUR_MAX);
			if (NULL == mb_buf) {
				ret_errno = ENOMEM;
				continue;
			}
		} else {
			mb_buf = NULL;
		}
#endif /* CSC_WCS_CT */

		csc_state->euc_ct_set = ecs;
#if defined(CSC_USE_ICONV)
		csc_state->iconv_cd = iconv_cd;
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
		csc_state->locale = locale_dup;
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
		csc_state->mb_buf = mb_buf;
#endif /* CSC_WCS_CT */

		return csc_state;

	} while(0);

	free(csc_state);
#if defined(CSC_USE_ICONV)
	csc_norm_free(norm_encoding);
	if ((iconv_t)(-1) != iconv_cd) {
		iconv_close(iconv_cd);
	}
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	free(locale_dup);
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
	free(mb_buf);
#endif /* CSC_WCS_CT */
	errno = ret_errno;

	return NULL;
}

void
euc_ct_close(csc_state_t * csc_state)
{
	if (NULL == csc_state) {
		return;
	}

#if defined(CSC_USE_ICONV)
	if ((iconv_t)(-1) != csc_state->iconv_cd) {
		iconv_close(csc_state->iconv_cd);
	}
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	free(csc_state->locale);
#endif /* CSC_SET_LOCALE */
#if defined(CSC_WCS_CT)
	free(csc_state->mb_buf);
#endif /* !CSC_WCS_CT */
	free(csc_state);
	return;
}

size_t
euc_ct_conv(
	csc_state_t *	csc_state,
	const char **	inbuf,
	size_t *	inbytesleft,
	char **		outbuf,
	size_t *	outbytesleft)
{
	size_t				ret_val;
	int				ret_errno;
	const csc_euc_ct_set_t *	ecs;
	const csc_euc_ct_t *		ec;
	const csc_euc_ct_t *		ec_current;
	const unsigned char * 		ip;
	size_t				ileft;
#if defined(CSC_WCS_CT)
	const unsigned char * 		iwp;
	size_t				iwleft;
#endif /* CSC_WCS_CT */
	unsigned char *			op;
	size_t				oleft;
	const char *			p;
	int				i;
#if defined(CSC_EUC_CT)
	int				ileft_pending;
#endif /* CSC_EUC_CT */
	int				req;
#if defined(CSC_WCS_CT)
	unsigned char			mb_buf[MB_BUF_LEN];
	unsigned char *			mb;
	size_t				mb_len;
#endif /* CSC_WCS_CT */
#if defined(CSC_USE_ICONV)
	unsigned char			euc_buf[EUC_BUF_LEN];
	unsigned char *			euc;
	size_t				euc_len;
	unsigned char *			oip;
	size_t				oileft;
	unsigned char			interim_buf[1024];
	unsigned char *			interim;
	size_t				interim_len;
	int				interim_error;
	unsigned char *			ptr;
	int				n;
#endif /* CSC_USE_ICONV */
#if defined(CSC_SET_LOCALE)
	char *				locale;
	const unsigned char *		ip0;
	size_t				ileft0;
	unsigned char *			op0;
	size_t				oleft0;
#endif /* CSC_SET_LOCALE */
	unsigned char *			extended_segment_ml;
	int				extended_segment_len;

#if defined(CSC_WCS_CT)
#  define ip_wcmb	ip
#  define il_wcmb	ileft
#  define op_wcmb	mb
#  define ol_wcmb	mb_len
#
#  if defined(CSC_USE_ICONV)
#    define ip_iconv	mb
#    define il_iconv	ileft0
#    define op_iconv	euc
#    define ol_iconv	euc_len
#    define ip_ct	euc
#    define il_ct	ileft0
#  else /* !CSC_USE_ICONV */
#    define ip_ct	mb
#    define il_ct	ileft0
#  endif /* !CSC_USE_ICONV */
#
#else /* !CSC_WCS_CT */
#  if defined(CSC_USE_ICONV)
#    define ip_iconv	ip
#    define il_iconv	ileft
#    define op_iconv	euc
#    define ol_iconv	euc_len
#    define ip_ct	euc
#    define il_ct	euc_len
#  else /* !CSC_USE_ICONV */
#    define ip_ct	ip
#    define il_ct	ileft
#  endif /* !CSC_USE_ICONV */
#endif /* !CSC_WCS_CT */

#if defined(CSC_USE_ICONV)
	interim = 0;
	interim_error = 0;
#endif /* CSC_USE_ICONV */

	ret_val = 0;

	if ((NULL == inbuf) || (NULL == *inbuf)) {
		return ret_val;
	}

	ecs = csc_state->euc_ct_set;
	ec_current = NULL;

	extended_segment_ml = NULL;
	extended_segment_len = 0;

#if defined(CSC_SET_LOCALE)
	p = setlocale(LC_CTYPE, NULL);
	if (0 == strcmp(p, csc_state->locale)) {
		locale = NULL;
	} else {
		locale = strdup(p);
		if (NULL == locale) {
			errno = ENOMEM;
			return (size_t)(-1);
		}
		if (NULL == setlocale(LC_CTYPE, csc_state->locale)) {
			free(locale);
			errno = EBADF;
			return (size_t)(-1);
		}
	}
#endif /* CSC_SET_LOCALE */

#if 0
#if defined(CSC_USE_ICONV)
	interim_len = *inbytesleft;

	if ((sizeof interim_buf) < interim_len) {
		interim = malloc(interim_len);
		if (NULL == interim) {
			if (NULL != locale) {
				setlocale(LC_CTYPE, locale);
				free(locale);
			}
			errno = ENOMEM;
			return (size_t)(-1);
		}
	} else {
		interim = interim_buf;
	}

	ip = (unsigned char *)(*inbuf);
	ileft = *inbytesleft;
	op = interim;
	oleft = interim_len;

	ret_val = iconv(csc_state->iconv_cd,
			(const char **)(&ip), &ileft, (char **)(&op), &oleft);

	if ((size_t)(-1) == ret_val) {
		interim_error = errno;
	} else {
		interim_error = 0;
	}

	interim_len -= oleft;
	ret_val = 0;
#endif /* CSC_USE_ICONV */
#endif /* 0 */

#if 0
#if defined(CSC_WCS_CT)
#  if defined(CSC_USE_ICONV)
	iwp = interim;
	iwleft = interim_len;
#  else /* !CSC_USE_ICONV */
	iwp = (unsigned char *)(*inbuf);
	iwleft = *inbytesleft;
#  endif /* !CSC_USE_ICONV */
#else /* !CSC_WCS_CT */
#  if defined(CSC_USE_ICONV)
	ip = (unsigned char *)(*inbuf);
	ileft = *inbytesleft;
#if 0
	ip = interim;
	ileft = interim_len;
#endif /* 0 */
#  else /* !CSC_USE_ICONV */
	ip = (unsigned char *)(*inbuf);
	ileft = *inbytesleft;
#  endif /* !CSC_USE_ICONV */
#endif /* !CSC_WCS_CT */
	op = (unsigned char *)(*outbuf);
	oleft = *outbytesleft;

#if defined(CSC_WCS_CT)
	if (NULL == csc_state->mb_buf) {
		mb = mb_buf;
	} else {
		mb = csc_state->mb_buf;
	}
#endif /* CSC_WCS_CT */
#endif /* 0 */

	ip = (const unsigned char *)(*inbuf);
	ileft = *inbytesleft;
	op = (unsigned char *)(*outbuf);
	oleft = *outbytesleft;

#if defined(CSC_WCS_CT)
	mb = mb_buf;
	mb_len = (sizeof (mb_buf));
#endif /* CSC_WCS_CT */
#if defined(CSC_USE_ICONV)
	euc = euc_buf;
	euc_len = (sizeof (euc_buf));
#endif /* CSC_USE_ICONV */

	while (0 <
	       ileft
#if 0
#if defined(CSC_WCS_CT)
	       iwleft
#else /* !CSC_WCS_CT */
	       ileft
#endif /* !CSC_WCS_CT */
#endif /* 0 */
		) {

#if defined(CSC_USE_ICONV)
		euc = euc_buf;
		euc_len = (sizeof (euc_buf));
#endif /* CSC_USE_ICONV */
#if defined(CSC_WCS_CT)
		if (il_wcmb < (sizeof (wchar_t))) {
			ERROR_BREAK(EINVAL);
		}
		mb = mb_buf;
		ileft0 = wctomb((char *)mb, *((wchar_t *)(ip_wcmb)));
		ip_wcmb += (sizeof (wchar_t));
		il_wcmb -= (sizeof (wchar_t));
		if (-1 == ileft0) {
			continue;
		}
#endif /* CSC_WCS_CT */
#if defined(CSC_USE_ICONV)
		ip0 = ip_iconv;
		ileft0 = mblen((const char *)ip_iconv, il_iconv);
		op0 = op_iconv;
		oleft0 = ol_iconv;
		n = ileft0;
		ret_val = iconv(csc_state->iconv_cd,
				(const char **)(&ip0), &ileft0,
				(char **)(&op0), &oleft0);
		if ((-1) == ret_val) {
			ip_iconv += 1;
			il_iconv -= 1;
			continue;
		}
		ip_iconv += n;
		il_iconv -= n;
		ileft0 = (ol_iconv - oleft0);
#endif /* CSC_USE_ICONV */

#if defined(CSC_EUC_CT)
		if ((0 != ecs->cs[EUC_CS3].length) && (SS3 == *ip_ct)) {
			ec = (ecs->cs + EUC_CS3);
			ileft_pending = 1;

		} else if ((0 != ecs->cs[EUC_CS2].length) && (SS2 == *ip_ct)) {
#if defined(CSC_CNS_CT) || defined(CSC_CNSW_CT)
			if (2 <= il_ct) {
				switch (*(ip_ct + 1)) {
				case 0xa2:
					ec = (ecs->cs + EUC_CS2);
					break;
				case 0xae:
					ec = (ecs->cs + EUC_CS3);
					break;
				default:
					ec = (ecs->cs + EUC_CS2);
					break;
#if 0
					ec = NULL;
					break;
#endif /* 0 */
				}
#if 0
				if (NULL == ec) {
					ERROR_BREAK(EINVAL);
				}
#endif /* 0 */
				ileft_pending = 2;
			} else {
				ERROR_BREAK(EINVAL);
			}
#else /* !(CSC_CNS_CT || CSC_CNSW_CT) */
			ec = (ecs->cs + EUC_CS2);
			ileft_pending = 1;
#endif /* !(CSC_CNS_CT || CSC_CNSW_CT) */

		} else if ((0 != ecs->cs[EUC_CS1].length) && (0x80 & *ip_ct)) {
			ec = (ecs->cs + EUC_CS1);
			ileft_pending = 0;

		} else {
			ec = (ecs->cs + EUC_CS0);
			ileft_pending = 0;
		}
#endif /* CSC_EUC_CT */
#if defined(CSC_MBS_CTEX)
		if (0 == (0x80 & (*ip_ct))) {
			ec = (ecs->cs + MBS_CS0);
		} else {
			ec = (ecs->cs + MBS_CS1);
		}
#endif /* CSC_MBS_CTEX */
#if 0
#if defined(CSC_PCK_CT)
		if ((*ip_ct) < 0x80) {
			ec = (ecs->cs + PCK_CS0);
		} else if ((0xa0 <= (*ip_ct)) && ((*ip_ct) <= 0xdf)) {
			ec = (ecs->cs + PCK_CS2);
		} else {
			ec = (ecs->cs + PCK_CS1);
		}
#endif /* CSC_PCK_CT */
#endif /* 0 */

		if (ec == ec_current) {
			req = ec->length;
		} else {
			req = (ec->desig_len + ec->length);
		}
		if (oleft < req) {
			ERROR_BREAK(E2BIG);
		}

		oleft -= req;

#if defined(CSC_EUC_CT)
		il_ct -= ileft_pending;
		ip_ct += ileft_pending;
#endif /* CSC_EUC_CT */

		if ((ec != ec_current) ||
		    ((NULL != extended_segment_ml) &&
		     (MAXVAL_14BIT <= extended_segment_len))) {
			i = ec->desig_len;
			p = (const char *)(ec->desig);

			if (NULL != extended_segment_ml) {
				unsigned int	h7;
				unsigned int	l7;

				h7 = (0x0080 |
				      ((0x3f80 & extended_segment_len) >> 7));
				l7 = (0x0080 | (0x007f & extended_segment_len));
				

				*(extended_segment_ml + 0) = h7;
				*(extended_segment_ml + 1) = l7;

				extended_segment_ml = NULL;
				extended_segment_len = 0;
			}

			if (1 == ec->extended_segment) {
				extended_segment_ml = (op + 4);
				extended_segment_len = (i - 6);
			}

			while (0 <= (--i)) {
				*(op++) = *(p++);
			}
			ec_current = ec;
		}

		i = ec->length;
		il_ct -= i;
		switch (ec->gl_gr) {
		case ENC_GL:
			while (0 <= (--i)) {
				*(op++) = (0x7f & (*(ip_ct++)));
			}
			break;
		case ENC_GR:
			while (0 <= (--i)) {
				*(op++) = (0x80 | (*(ip_ct++)));
			}
			break;
		case ENC_GLGR:
			while (0 <= (--i)) {
				*(op++) = *(ip_ct++);
			}
			break;
		default:
			while (0 <= (--i)) {
				*(op++) = *(ip_ct++);
			}
			break;
		}

#if defined(CSC_WCS_CT)
		if (0 != il_ct) {
			ERROR_BREAK(EBADF);
		}
#endif /* CSC_WCS_CT */
	}

	if (NULL != extended_segment_ml) {
		unsigned int	h7;
		unsigned int	l7;
		
		h7 = (0x0080 | ((0x3f00 & extended_segment_len) >> 7));
		l7 = (0x0080 | (0x007f & extended_segment_len));

		*(extended_segment_ml + 0) = h7;
		*(extended_segment_ml + 1) = l7;

		extended_segment_ml = NULL;
		extended_segment_len = 0;
	}

#if 0
#if defined(CSC_WCS_CT)
#  if defined(CSC_USE_ICONV)
	if ((0 != ret_val) || (0 != interim_error)) {
		ptr = interim;
		for (i = (interim_len - iwleft), n = 0; 0 < i; --i) {
			if ((*ptr <= 0x7f) ||
			    ((0xa0 <= *ptr) && (*ptr <= 0xdf))) {
				ptr += 1;
				n += 1;
			} else {
				ptr += 2;
				n += 2;
			}
		}
		*inbuf += n;
		*inbytesleft -= n;
	} else {
		*inbuf = (const char *)iwp;
		*inbytesleft = iwleft;
	}
#  else /* !CSC_USE_ICONV */
	*inbuf = (const char *)iwp;
	*inbytesleft = iwleft;
#  endif /* !CSC_USE_ICONV */
#else /* !CSC_WCS_CT */
#  if defined(CSC_USE_ICONV)
	*inbuf = (const char *)ip_ct;
	*inbytesleft = il_ct;
#  else /* !CSC_USE_ICONV */
	*inbuf = (const char *)ip_ct;
	*inbytesleft = il_ct;
#  endif /* !CSC_USE_ICONV */
#endif /* !CSC_WCS_CT */
#endif /* 0 */

	*inbuf = (const char *)ip;
	*outbytesleft = ileft;
	*outbuf = (char *)op;
	*outbytesleft = oleft;

#if defined(CSC_USE_ICONV)
	if (interim_buf != interim) {
		free(interim);
	}
#endif /* CSC_USE_ICONV */

#if defined(CSC_SET_LOCALE)
	if (NULL != locale) {
		setlocale(LC_CTYPE, locale);
		free(locale);
	}
#endif /* CSC_SET_LOCALE */

#if defined(CSC_USE_ICONV)
	if (0 == interim_error) {
		if ((size_t)(-1) == ret_val) {
			errno = ret_errno;
		}
	} else {
		ret_val = (size_t)(-1);
		errno = interim_error;
	}
#else /* !CSC_USE_ICONV */
	if ((size_t)(-1) == ret_val) {
		errno = ret_errno;
	}
#endif /* !CSC_USE_ICONV */

	return ret_val;
}
