/*
 * $Id: xutoj.c,v 1.21.2.3 1999/04/01 05:18:17 nakanisi Exp $
 */

/*
 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
 * This file is part of FreeWnn.
 * 
 * Copyright Kyoto University Research Institute for Mathematical Sciences
 *                 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
 *
 * Author: OMRON SOFTWARE Co., Ltd. <freewnn@rd.kyoto.omronsoft.co.jp>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Emacs; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Commentary:
 *
 * Change log:
 *	'99/03/20	片山＠ＰＦＵ <kate@pfu.co.jp>
 *		英数字指示のエスケープシーケンスを ESC ( B（ASCII）にする。
 *
 * Last modified date: 20,Mar.1999
 *
 * Code:
 *
 */
/*	Version 4.0
 */
#define	NEED_CR

#include "commonhd.h"
#include "config.h"
#include "wnn_os.h"

#define ECNS_IS_UCNS 1	/* The trust CNS is CNS11643 based on ISO2022,
			   but the CNS is binded on EUC */

#define NON_LIMIT	0x7FFFFFFF

#define G0	0
#define G1	1
#define G2	2
#define G3	3
#define SS	4
#define GL	1
#define GR	2
#define LS0	0x0f
#define LS1	0x0e
#define LS1R	0x7e
#define LS2	0x6e
#define LS2R	0x7d
#define LS3	0x6f
#define LS3R	0x7c
#define SS2	0x8e
#define SS3	0x8f


#define CS_MASK		0x8080
#define CS0_MASK	0x0000
#define CS1_MASK	0x8080
#define CS2_MASK	0x0080
#define CS3_MASK	0x8000

#define CS1	0
#define CS2	1
#define CS3	2

#define UJIS_CSWIDTH	"2,1,2"
#define UGB_CSWIDTH	"2,1,2"
#define UKSC_CSWIDTH	"2,1,2"

typedef struct _CSWidthTable {
    int cs1, cs2, cs3;
} CSWidthTable;

typedef struct _cswidth_name_struct {
    char *lang;
    char *name;
    char *def_name;
} cswidth_name_struct;

typedef struct _DesignateTable {
    unsigned char *code;
    unsigned int mask;
} DesignateTable;

static int _etc_cs[3] = { 2, 1, 2};
static int _etc_cs_len[3] = { 2, 1, 2};
static int cs_mask[3] = { 0x8080, 0x0080, 0x8000};

static int default_glr_mode[3] = {0, G0, G1};
static int save_glr_mode[2];
static int default_gn_len[4] = {1, 1, 1, 2};
static unsigned int default_gn_mask[4] = {0x00, 0x80, 0x80, 0x8000};
static DesignateTable default_designate[4] = {
    { (unsigned char *)"(B", 0x0 },
    { (unsigned char *)NULL, 0x0 }
};

static int *glr_mode = default_glr_mode;
static int *gn_len = default_gn_len;
static unsigned int *gn_mask = default_gn_mask;

static unsigned char save_seq[6]= {'\0'};
static int save_seq_len = 0;
static int pending_esc = 0;
static unsigned char pending = '\0';
static w_char pending_mask = (w_char)0;

static DesignateTable *designate = default_designate;

#ifdef	JAPANESE
static DesignateTable JIS_designate[] = {
    { (unsigned char *)"(B", 0x0 },
    { (unsigned char *)"(J", 0x0 },
    { (unsigned char *)"(I", 0x80 },
    { (unsigned char *)"$B",  0x8080 },
    { (unsigned char *)"$(B", 0x8080 },
    { (unsigned char *)")I", 0x80 },
    { (unsigned char *)"$)B", 0x8080 },
    { (unsigned char *)"$)D", 0x8000 },
    { (unsigned char *)"$(D", 0x8000 },
    { (unsigned char *)NULL, 0x0 }
};
#endif	/* JAPANESE */

#ifdef	CHINESE
#ifndef ECNS_IS_UCNS
static DesignateTable CNS_designate[] = {
    { (unsigned char *)"(B", 0x0 },
    { (unsigned char *)"$)0",  0x8080 },
    { (unsigned char *)"$*1", 0x8000 },
    { NULL, 0x0 }
};
#endif	/* ECNS_IS_UCNS */
#endif	/* CHINESE */

#ifdef	KOREAN
static DesignateTable KSC_designate[] = {
    { (unsigned char *)"(B", 0x0 },
    { (unsigned char *)"$(C", 0x8080 },
    { (unsigned char *)"$)C", 0x8080 },
    { (unsigned char *)NULL, 0x0 }
};
#endif	/* KOREAN */

#if defined(JAPANESE) || defined(CHINESE) || defined(KOREAN)
static w_char tmp_w_buf[1000];
#endif

static void
set_gn(dg)
DesignateTable *dg;
{
    register char *p = (char *)dg->code;
    register int len = 1, gn = 0;

    if (!strcmp(p, "$B")) {	/* JIS */
	gn_len[0] = 2;
	gn_mask[0] = dg->mask;
	return;
    }	
    if (*p == '$') {
	len = 2;
	p++;
    }
    if (*p >= '(' && *p <= '+') gn = *p - '(';
    else if (*p >= '-' && *p <= '/') gn = *p - '+';
    else return;
    gn_len[gn] = len;
    gn_mask[gn] = dg->mask;
}

static int
check_designate(ec, eend, ret_buf)
unsigned char *ec, *eend, **ret_buf;
{
    register unsigned char *c = ec;
    register int i, j, ok = 0;

    *ret_buf = NULL;
    for (i = save_seq_len; c < eend; c++) {
	ok = 0;
	save_seq[i++] = *c;
	save_seq[i] = '\0';
	for (j = 0; designate[j].code; j++) {
	    if (!strncmp((char *)save_seq, (char *)designate[j].code, i)) {
		if (i == strlen((char *)designate[j].code)) {
		    set_gn(&designate[j]);
		    save_seq_len = 0;
		    return(c - ec);
		}
		ok = 1;
		break;
	    }
	}
	if (ok == 0) {
	    *ret_buf = save_seq;
	    save_seq_len = 0;
	    return(c - ec);
	}
    }
    save_seq_len = i;
    return(c - ec - 1);
}

int flush_designate(buf)
w_char *buf;
{
    register w_char *c = buf;
    register int i;

    if (pending_esc) {
	*c++ = ESC;
	pending_esc = 0;
	return(1);
    }
    if (save_seq_len == 0) return(0);
    *c++ = ESC;
    for (i = 0; i < save_seq_len; i++) {
	*c++ = save_seq[i];
    }
    save_seq_len = 0;
    return((char *)c - (char *)buf);
}

int
extc_to_intc(intc,extc,esiz)
w_char *intc;
unsigned char *extc;
int esiz;
{
    unsigned char *eend = extc + esiz;
    register unsigned char *ec = extc;
    register w_char *ic = intc;
    register int LorR = 0, i;
    w_char tmp;
    int ret, len;
    unsigned char *ret_buf;
    register unsigned char *p;

    for (;ec < eend; ec++) {
	if (pending_esc) {
	    pending_esc = 0;
	    goto ESC_SWITCH;
	}
	if (pending) {
	    *ic++ = ((pending << 8 | *ec) & 0x7f7f) | pending_mask;
	    pending = '\0';
	    continue;
	}
	switch(*ec) {
#ifdef JIS7
	 case LS0:
	    glr_mode[GL] = G0;
	    break;
	 case LS1:
	    glr_mode[GL] = G1;
	    break;
#endif /* JIS7 */
	 case SS2:
	    save_glr_mode[GL] = glr_mode[GL];
	    glr_mode[GL] = (G2 | SS);
	    break;
	 case SS3:
	    save_glr_mode[GL] = glr_mode[GL];
	    glr_mode[GL] = (G3 | SS);
	    break;
	 case ESC:
	    if (++ec == eend) {
		pending_esc = 1;
		break;
	    }
ESC_SWITCH:
	    switch(*ec) {
	     case LS1R:
		glr_mode[GR] = G1;
		break;
	     case LS2:
		glr_mode[GL] = G2;
		break;
	     case LS2R:
		glr_mode[GR] = G2;
		break;
	     case LS3:
		glr_mode[GL] = G3;
		break;
	     case LS3R:
		glr_mode[GR] = G3;
		break;
	     default:
		ret = check_designate(ec, eend, &ret_buf);
		ec += ret;
		if (ret_buf) {
		    *ic++ = ESC;
		    for (p = ret_buf; *p; p++) *ic++ = *p;
		}
		break;
	    }
	    break;
	 default:
	    LorR = 0;
	    if (*ec >= 0x20 && *ec <= 0x7f) { /* GL */
		LorR = GL;
	    } else if (*ec >= 0xa0 && *ec <= 0xff) { /* GR */
		LorR = GR;
	    }
	    if (LorR) {
		len = gn_len[(glr_mode[LorR] & 0x3)];
		if ((ec + len) > eend) {
		    pending = *ec;
		    pending_mask = gn_mask[(glr_mode[LorR] & 0x3)];
		} else {
		    for (tmp = (w_char)0, i = 0; i < len; i++) {
			tmp = ((tmp << 8 | *ec++) & 0x7f7f) |
			        gn_mask[(glr_mode[LorR] & 0x3)];
		    }
		    if (len) ec -= 1;
		    *ic++ = tmp;
		    if (glr_mode[LorR] & SS)
		      glr_mode[LorR] = save_glr_mode[LorR];
		}
	    } else {
		*ic++ = *ec;
	    }
	}
    }
    return((char *)ic - (char *)intc);
}

int
through(x, y, z)
char *x, *y;
int z;
{
    bcopy(y, x, z);
    return z;
}

int
ibit8_to_ebit8(ebit8, ibit8, ibsiz)
unsigned char *ebit8;
w_char *ibit8;
int ibsiz;
{
    register unsigned char *eb = ebit8;
    register w_char *ib = ibit8;

    for (; ibsiz>0;ibsiz-=sizeof(w_char)) {
	*eb++ = *ib++ & 0xff;
    }
    return((char *)eb - (char *)ebit8);
}

/** cswidth functions **/
unsigned int
create_cswidth(s)
char *s;
{
    char tmp[2];
    int cs = 0, css = 0, i;

    if (!s || !*s) return(0);
    
    tmp[0] = tmp[1] = '\0';
    for (i = 2; i >= 0 ; i--) {
	tmp[0] = *s;
	cs = atoi(tmp);
	if (cs > 0 && cs < 3) css = (cs << (i * 8 + 4)) | css;
	if (!*++s) {
	    if (cs > 0 && cs < 3) css = (cs << (i * 8)) | css;
	    break;
	}
	if (*s == ':') {
	    if (!*++s) {
		if (cs > 0 && cs < 3) css = (cs << (i * 8)) | css;
		break;
	    }
	    tmp[0] = *s;
	    cs = atoi(tmp);
	    s++;
	}
	if (cs > 0 && cs < 3) css = (cs << (i * 8)) | css;
	if (!*s || *s != ',' || !*++s) break;
    }
    return(css);
}

void
set_cswidth(id)
register unsigned int id;
{
    _etc_cs[CS1] = (id >> 20) & 0xf;
    _etc_cs[CS2] = (id >> 12) & 0xf;
    _etc_cs[CS3] = (id >> 4) & 0xf;
    _etc_cs_len[CS1] = (id >> 16) & 0xf;
    _etc_cs_len[CS2] = (id >> 8) & 0xf;
    _etc_cs_len[CS3] = id & 0xf;
    return;
}

static cswidth_name_struct cs_width_name[] = {
    {WNN_J_LANG, "JCSWIDTH", "2,1,2" },
    {WNN_C_LANG, "CCSWIDTH", "2,1,2" },
    {WNN_K_LANG, "KCSWIDTH", "2" },
    {WNN_T_LANG, "TCSWIDTH", "2,1,2" },
    {NULL, NULL}
};

char *
get_cswidth_name(lang)
register char *lang;
{
    register cswidth_name_struct *p;
    register char *name;
    extern char *getenv();

    if (!lang || !*lang) {
	return(getenv("CSWIDTH"));
    }

    for (p = cs_width_name; p->lang; p++) {
	if (!strncmp(lang, p->lang, strlen(lang))) {
	    if ((name = getenv(p->name)) != NULL) {
		return(name);
	    } else if ((name = getenv("CSWIDTH")) != NULL) {
		return(name);
	    } else {
		return(p->def_name);
	    }
	}
    }
    return(NULL);
}

int get_cswidth(cs)
int cs;
{
    return(_etc_cs[cs]);
}

int get_cswidth_by_char(c)
register unsigned char c;
{
    if (c < SS2 || (c < 0xa0 && c > SS3)) return(1);
    if (c == SS2) return(_etc_cs[CS2]+1);
    if (c == SS3) return(_etc_cs[CS3]+1);
    return(_etc_cs[CS1]);
}

int get_cs_mask(cs)
int cs;
{
    return(cs_mask[cs]);
}

int columnlen(eeuc)
unsigned char *eeuc;
{
    register int n = 0;
    register unsigned char *c, x;
    register int cs_id;

    for (c = eeuc; *c;) {
	x = *c;
	if (x & 0x80) {
	    cs_id = ((x == SS2)? CS2 : ((x == SS3)? CS3: CS1));
	    if (cs_id == CS2 || cs_id == CS3) c++;
	    n += _etc_cs_len[cs_id];
	    c += _etc_cs[cs_id];
	} else {
	    n++;
	    c++;
	}
    }
    return(n);
}

int columnlen_w(ieuc)
w_char *ieuc;
{
    register int n = 0;
    register w_char *c, x;
    register int cs_id, mask;

    for(c = ieuc; *c; c++){
	x = *c;
	mask = x & CS_MASK;
	if (mask == CS0_MASK) {
	    n++;
	} else {
	    cs_id = (mask == cs_mask[CS3])? CS3:
		     ((mask == cs_mask[CS2])? CS2: CS1);
	    n += _etc_cs_len[cs_id];
	}
    }
    return(n);
}

int
ieuc_to_eeuc(eeuc,ieuc,iesiz)
unsigned char *eeuc;
w_char *ieuc;
int iesiz;
{
    register int x;
    register w_char *ie;
    register unsigned char *ee;
    register int cs_id, mask, non_limit = 0;
    ie=ieuc;ee=eeuc;

    if (iesiz == -1) non_limit = 1;
    for(;(non_limit?(*ie):(iesiz>0)) ;iesiz-=sizeof(w_char)){
	x = *ie++;
	mask = x & CS_MASK;
	if (mask == CS0_MASK || x == 0xffff) {
	    *ee++ = x;
	} else {
	    cs_id = (mask == cs_mask[CS3])? CS3:
		     ((mask == cs_mask[CS2])? CS2: CS1);
	    if (_etc_cs[cs_id] <= 0) continue;
	    if (cs_id == CS2) *ee++ = SS2;
	    else if (cs_id == CS3) *ee++ = SS3;
	    if (_etc_cs[cs_id] > 1) *ee++ = (x >> 8) | 0x80;
	    if (_etc_cs[cs_id] > 0) *ee++ = (x & 0xff) | 0x80;
	}
    }
    return((char *)ee - (char *)eeuc);
}


int
eeuc_to_ieuc(ieuc,eeuc,eesiz)
w_char *ieuc;
unsigned char *eeuc;
register int eesiz;
{
    register unsigned char x;
    register w_char *ie;
    register unsigned char *ee;
    register int cs_id, non_limit = 0;
    ie=ieuc;ee=eeuc;

    if (eesiz == -1) non_limit = 1;
    for(;(non_limit?(*ee):(eesiz>0));){
	x = *ee++;
	if(x > 0x9f || x == SS2 || x == SS3){
	    cs_id = ((x == SS2)? CS2 : ((x == SS3)? CS3: CS1));
	    if (cs_id == CS2 || cs_id == CS3) x = *ee++;
	    if (_etc_cs[cs_id] <= 0) continue;
	    if (_etc_cs[cs_id] > 1) {
		*ie = (w_char)(x & 0x7f) << 8;
		x = *ee++;
	    } else {
		*ie = (w_char)0;
	    }
	    *ie |= (x & 0x7f);
	    *ie++ |= cs_mask[cs_id];
	    eesiz -= _etc_cs[cs_id] + 1;
	}else{
	    *ie++ = x;
	    eesiz--;
	}
    }
    return((char *)ie - (char *)ieuc);
}

#ifdef nodef
void
wnn_delete_ss2(s, n)
register unsigned int *s;
register int n;
{
    register unsigned int x;

    for(; n != 0 && (x = *s); n--, s++){
	if ((x & 0xff00) == 0x8e00) *s &= ~0xff00;
	if (x == 0xffffffff) break;
    }
}
#endif

void
wnn_delete_w_ss2(s, n)
register w_char *s;
register int n;
{
    register w_char x;

    for(; n != 0 && (x = *s); n--, s++){
	if ((x & 0xff00) == 0x8e00) *s &= ~0xff00;
    }
}

#ifdef nodef
int
wnn_byte_count(in)
register int in;
{
    return(((in < 0xa0 && in != 0x00 && in != 0x8e) || in == 0xff) ? 1 : 2);
}
#endif

#define	ASCII		0

#ifdef	JAPANESE
#define	HANKAKU_JIS_IN	'\016'
#define	HANKAKU_JIS_OUT	'\017'

#define	HANKAKU_JIS	2
#define	ZENKAKU_JIS	1
#define	ZENKAKU_JIS_HOJYO	3

static	unsigned char	*j;
static	w_char		*iu;
static	unsigned char	*eu;
static	unsigned char	*sj;
static unsigned char tmp_buf[2000];

static void
putj(x)
int x;
{
	*j++=x;
}

static void
puteu(x)
int x;
{
	*eu++=x;
}

static void
putsj(x)
int x;
{
	*sj++ = x;
}

static void
putsjw(x)
int x;
{
	*sj++ = x>>8;
	*sj++ = x;
}

static int oj_mode = ASCII;	/* 出力時のｊｉｓコードのモード */
static int jtosj();
extern int eujis_to_iujis();

/* convert JIS code to shift-JIS code */
static int
jtosj(high,low)
unsigned high, low;
{
	if(high & 1)
		low += 0x1f;
	else
		low += 0x7d;
	if(low >= 0x7f) low++;
	high = ((high - 0x21) >> 1) + 0x81;
	if(high > 0x9f)
		high += 0x40;
	return((high << 8) | low);
}

/* convert shift-JIS to JIS code */ 
static int
sjtoj(high, low)
register unsigned high, low;
{
	high -= (high <= 0x9f) ? 0x71 : 0xb1;
	high = high * 2;
	if (low > 0x7f)
		low--;
	if (low >=0x9e) {
		high += 2;
		low -= 0x7d;
	}else{
		high++;
		low -= 0x1f;
	}
	return((high << 8) | low);
}

static void
jis_change_mode(mode,new_mode)
int *mode;
int new_mode;
{
 if(*mode==new_mode)return;
 switch(*mode){
	case ZENKAKU_JIS :
	case ZENKAKU_JIS_HOJYO :
		/* designate ISO-8859-1 rather than JIS X 0201 */
		/* putj('\033'); putj('('); putj('J');break; */
		putj('\033'); putj('('); putj('B');break;
#ifdef	JIS7
	case HANKAKU_JIS :
		putj(HANKAKU_JIS_OUT);break;
#endif	/* JIS7 */
	default: ;
 }
 *mode=new_mode;
 switch(new_mode){
	case ZENKAKU_JIS :
		putj('\033'); putj('$'); putj('B');break;
	case ZENKAKU_JIS_HOJYO :
		putj('\033'); putj('$'); putj('('); putj('D');break;
#ifdef	JIS7
	case HANKAKU_JIS :
		putj(HANKAKU_JIS_IN);break;
#endif	/* JIS7 */
	default: ;
 }
}

#ifdef	JIS7
/*	内部 U-jis を 7bit jis コードに変換します
	文字列の長さを返します			*/
extern int
iujis_to_jis(jis,iujis,iusiz)
unsigned char	*jis;	/*	jisコードになったものをおくbuf	*/
w_char	*iujis;	/*	iujisコードのものをおいてくるbuf*/
int	iusiz;	/*	iujis の大きさ			*/
{
 int x;
 j=jis;
 iu=iujis;
 for(;iusiz>0;iusiz-=sizeof(w_char)){
	x = *iu++;
	if(((x & 0xFF00)==0x8E00) || ((x & 0xFF80)==0x80){
		jis_change_mode(&oj_mode,HANKAKU_JIS);
		putj(x & 0x7f);
	}else if((x & 0x8080) == 0x8080){
		jis_change_mode(&oj_mode,ZENKAKU_JIS);
		putj((x >>8) & 0x7f);putj(x & 0x7f);
	}else if(x & 0x8000){
		jis_change_mode(&oj_mode,ZENKAKU_JIS_HOJYO);
		putj((x >>8) & 0x7f);putj(x & 0x7f);
	}else{
		jis_change_mode(&oj_mode,ASCII);
		putj(x);
	}
 }
 jis_change_mode(&oj_mode,ASCII);
 return (j - jis);
}
#endif	/* JIS7 */

/*	内部 U-jis を 8bit jis コードに変換します
	文字列の長さを返します			*/
extern int
iujis_to_jis8(jis,iujis,iusiz)
unsigned char	*jis;	/*	jisコードになったものをおくbuf	*/
w_char	*iujis;	/*	iujisコードのものをおいてくるbuf*/
int	iusiz;	/*	iujis の大きさ			*/
{
 int x;
 j=jis;iu=iujis;
 for( ;iusiz>0;iusiz-=sizeof(w_char)){
	x = *iu++;
	if(((x & 0xFF00)==0x8E00) || ((x & 0xFF80) == 0x80)){
		jis_change_mode(&oj_mode,ASCII);
		putj(x & 0xff);
	}else if((x & 0x8080) == 0x8080){
		jis_change_mode(&oj_mode,ZENKAKU_JIS);
		putj((x >> 8) & 0x7f);putj(x & 0x7f);
	}else if(x & 0x8000){
		jis_change_mode(&oj_mode,ZENKAKU_JIS_HOJYO);
		putj((x >> 8) & 0x7f);putj(x & 0x7f);
	}else{
		jis_change_mode(&oj_mode,ASCII);
		putj(x);
	}
 }
 jis_change_mode(&oj_mode,ASCII);
 return (j - jis);
}


#ifdef	JIS7
/*	外部 U-jis を 7bit jis コードに変換します	*/
extern int
eujis_to_jis(jis,eujis,eusiz)
unsigned char *jis,*eujis;
int eusiz;
{
    static int kanji1 = 0;
    static char kanji1_code = 0;
    /* 0: normal
       1: get SS2
       2: get kanji 1 byte */
    /*
    int oj_mode;
    */
    int x;
    j=jis;
    eu=eujis;
    /* ADD KURI */
    if (kanji1 != 0) {
	if (kanji1 == 2) {
	    putj(kanji1_code & 0x7f);
	}
	putj(*eu & 0x7f);
	eusiz -= sizeof(char);
	kanji1 = 0;
    }
    /* ADD KURI end */
    /*
    for(oj_mode=ASCII;eusiz>0;eusiz-=sizeof(char)){
    */
    for( ;eusiz>0;eusiz-=sizeof(char)){
	x = *eu++;
	if((x & 0xFF)==0x8E){
	    jis_change_mode(&oj_mode,HANKAKU_JIS);
	    if (eusiz > 1) {
		putj(*eu++ & 0x7f);
		eusiz -= sizeof(char);
	    } else {
		kanji1 = 1;
	    }
	}else if(x & 0x80){
	    jis_change_mode(&oj_mode,ZENKAKU_JIS);
	    if (eusiz > 1) {
		putj(x & 0x7f);putj(*eu++ & 0x7f);
		eusiz -= sizeof(char);
	    } else {
		kanji1 = 2;
		kanji1_code = x & 0x7f;
	    }
	}else{
	    jis_change_mode(&oj_mode,ASCII);
	    putj(x);
	}
    }
    if (kanji1 == 0)
	jis_change_mode(&oj_mode,ASCII);
    return(j - jis);
}
#endif	/* JIS7 */

/*	外部 U-jis を 8bit jis コードに変換します	*/
extern int
eujis_to_jis8(jis,eujis,eusiz)
unsigned char *jis,*eujis;
int eusiz;
{
    static int kanji1 = 0;
    static unsigned char kanji1_code = 0;
    /* 0: normal
       1: get SS2
       2: get kanji 1 byte */
    /*
    int oj_mode;
    */
    int x;
    j=jis;
    eu=eujis;
    /* ADD KURI */
    if (kanji1 != 0) {
	if (kanji1 == 2) {
	    putj(kanji1_code & 0x7f);
	    putj(*eu & 0x7f);
	} else {
	    putj(*eu);
	}
	eusiz -= sizeof(char);
	kanji1 = 0;
	eu++;
    }
    /* ADD KURI end */
    /*
    for(oj_mode=ASCII;eusiz>0;eusiz-=sizeof(char)){
    */
    for( ;eusiz>0;eusiz-=sizeof(char)){
	x = *eu++;
	if((x & 0xFF)==0x8E){
	    jis_change_mode(&oj_mode,ASCII);
	    if (eusiz > 1) {
		putj(*eu++);
		eusiz -= sizeof(char);
	    } else {
		kanji1 = 1;
	    }
	}else if(x & 0x80){
	    jis_change_mode(&oj_mode,ZENKAKU_JIS);
	    if (eusiz > 1) {
		putj(x & 0x7f);putj(*eu++ & 0x7f);
		eusiz -= sizeof(char);
	    } else {
		kanji1 = 2;
		kanji1_code = x;
	    }
	}else{
	    jis_change_mode(&oj_mode,ASCII);
	    putj(x);
	}
    }
    if (kanji1 == 0)
	jis_change_mode(&oj_mode,ASCII);
    return(j - jis);
}

/*	内部 U-jis を 外部 U-jis コードに変換します	*/
extern int
iujis_to_eujis(eujis,iujis,iusiz)
unsigned char *eujis;
w_char *iujis;
int iusiz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UJIS_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(ieuc_to_eeuc(eujis, iujis, iusiz));
}

int
jis_to_eujis(eujis, jis, jsiz)
unsigned char *eujis, *jis;
int jsiz;
{
    int len;

    designate = JIS_designate;
    len = extc_to_intc(tmp_w_buf, jis, jsiz);
    return(iujis_to_eujis(eujis, tmp_w_buf, len));
}	

/*
 *	Shifted JIS
 */

/*	外部 U-jis を S-jis コードに変換します
	文字列の長さを返します			*/
extern int
eujis_to_sjis(sjis,eujis,eusiz)
unsigned char	*sjis;	/*	sjisコードになったものをおくbuf	*/
unsigned char	*eujis;	/*	eujisコードのものをおいてくるbuf*/
int	eusiz;	/*	eujis の大きさ			*/
{register int x;
 int save = 0;
 sj=sjis;eu=eujis;
 if (save && eusiz > 0) {
	if(save == 0x8e){
		putsj(*eu++ | 0x80);
	}else{
		putsjw(jtosj(save & 0x7F, *eu++ & 0x7F)) ;
	}
	eusiz--;
 }
 for(;eusiz>0;){
	x = *eu++;
	eusiz--;
	if(x & 0x80){
		if (eusiz <= 0) {
			save = x;
			break;
		}
		if(x == 0x8e){
			putsj(*eu++ | 0x80);
		}else{
			putsjw(jtosj(x & 0x7F, *eu++ & 0x7F)) ;
		}
		eusiz--;
	}else{
		putsj(x);
	}
 }
 return(sj - sjis);
}

/*	内部 U-jis を S-jis コードに変換します
	文字列の長さを返します			*/
extern int
iujis_to_sjis(sjis,iujis,iusiz)
unsigned char	*sjis;	/*	sjisコードになったものをおくbuf	*/
w_char	*iujis;	/*	iujisコードのものをおいてくるbuf*/
int	iusiz;	/*	iujis の大きさ			*/
{
    register int x;
    sj=sjis;
    iu=iujis;
    for(;iusiz>0;iusiz-=sizeof(w_char)){
	if((x = *iu++) & 0xff00){
		if ((x & 0xff00) == 0x8e00){
			putsj((x & 0xff) | 0x80);
		} else {
			putsjw(jtosj((x>>8) & 0x7f, x & 0x7f)) ;
		}
	}else{
		putsj(x);
	}
    }
    return(sj - sjis);
}

int
sjis_to_iujis(iujis,sjis,ssiz)
w_char	*iujis;		/* iujisコードになったものをおくbuf */
unsigned char	*sjis;	/* sjisコードのものをおいてくるbuf */
int	ssiz;		/* sjis の大き */
{register int x;
 int save = 0;
 sj=sjis;iu=iujis;
 if (save && ssiz > 0) {
	*iu++ = (sjtoj(save,*sj++) | 0x8080);
	ssiz--;
	save = 0;
 }
 for(;ssiz>0;){
	x = *sj++;
	ssiz--;
	if(x & 0x80){
		if (ssiz <= 0) {
		    save = x;
		    break;
		}
		*iu++ = ((sjtoj(x,*sj++)) | 0x8080);
		ssiz--;
	}else{
		*iu++ = (x);
	}
 }
 return((char *)iu - (char *)iujis);
}

int
sjis_to_eujis(eujis,sjis,ssiz)
unsigned char	*eujis;	/*	eujisコードになったものをおくbuf	*/
unsigned char	*sjis;	/*	sjisコードのものをおいてくるbuf*/
int	ssiz;	/*	sjis の大きさ			*/
{register int x;unsigned char *sj;
 int save = 0;
 sj=sjis;eu=eujis;
 if (save && ssiz > 0) {
	x = (sjtoj(save,*sj++) | 0x8080);
	puteu(x>>8);
	puteu(x);
	ssiz--;
	save = 0;
 }
 for(;ssiz>0;){
	x = *sj++;
	ssiz--;
	if(x & 0x80){
		if (ssiz <= 0) {
		    save = x;
		    break;
		}
		x = (sjtoj(x,*sj++) | 0x8080);		/* 変えました KUWA */
		puteu(x>>8);
		puteu(x);
		ssiz--;
	}else{
		puteu(x);
	}
 }
 return(eu - eujis);
}

#ifdef	JIS7
int
sjis_to_jis(jis,sjis,siz)
unsigned char *jis,*sjis;
int siz;
{int len;
 len= sjis_to_eujis(tmp_buf,sjis,siz);
 return(eujis_to_jis(jis,tmp_buf,len));
}
#endif	/* JIS7 */

int
sjis_to_jis8(jis,sjis,siz)
unsigned char *jis,*sjis;
int siz;
{int len;
 len= sjis_to_eujis(tmp_buf,sjis,siz);
 return(eujis_to_jis8(jis,tmp_buf,len));
}

int
jis_to_iujis(iujis, jis, jsiz)
w_char *iujis;
unsigned char *jis;
int jsiz;
{
    designate = JIS_designate;
    return(extc_to_intc(iujis, jis, jsiz));
}

int
jis_to_sjis(sjis,jis,siz)
unsigned char *sjis,*jis;
int siz;
{int len;
 len= jis_to_iujis(tmp_w_buf,jis,siz);
 return(iujis_to_sjis(sjis,tmp_w_buf,len));
}

int
eujis_to_iujis(iujis, eujis, eusiz)
w_char *iujis;
unsigned char *eujis;
int eusiz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UJIS_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(eeuc_to_ieuc(iujis, eujis, eusiz));
}

#endif	/* JAPANESE */

#ifdef	CHINESE

#define CNS11643_1	2
#define CNS11643_2	1

/* The following facts are helpful for understanding:
	* _W,		means Wei in Pinyin
	* _Q,		means Wei in Pinyin. 
	* 0x5e = 94,	num of wchar in one _Q at 1xxxxxxx 1xxxxxxx hand
	* 0x3f = 63,	Num of Wchar in one _Q at 1xxxxxxx 0xxxxxxx hand 
	* Almost all the numbers in HEX are given for showing the _Q or _W
*/

#define CNS_NUM_Q		0x5e	/* num of wchar in one _Q at hand */
#define BIG5_NUM_11_Q		0x5e	/* num of wchar in one _Q at 1xxxxxxx 1xxxxxxx hand */
#define BIG5_NUM_10_Q		0x3f	/* num of wchar in one _Q at 1xxxxxxx 0xxxxxxx hand */

#define CNS_HANZI_11_START_Q	0x24 	/* At 1xxxxxxx 1xxxxxxx hand */
#define CNS_HANZI_11_START_W	0x01 	/* At 1xxxxxxx 1xxxxxxx hand */
#define CNS_HANZI_11_END_Q	0x5D	/* At 1xxxxxxx 1xxxxxxx hand */
#define CNS_HANZI_11_END_W	0x2B	/* At 1xxxxxxx 1xxxxxxx hand */
#define CNS_HANZI_11_START_QM	0x01 	/* At 1xxxxxxx 1xxxxxxx hand */
#define CNS_HANZI_11_END_QM	0x05	/* At 1xxxxxxx 1xxxxxxx hand */

#define CNS_HANZI_10_START_Q	0x01	/* At 1xxxxxxx 0xxxxxxx hand */
#define CNS_HANZI_10_START_W	0x01	/* At 1xxxxxxx 0xxxxxxx hand */
#define CNS_HANZI_10_END_Q	0x52	/* At 1xxxxxxx 0xxxxxxx hand */
#define CNS_HANZI_10_END_W	0x24	/* At 1xxxxxxx 0xxxxxxx hand */

#define BIG5_HANZI_11_START_Q 	0x04 	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_START_W 	0x01 	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_END_Q	0x25	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_END_W	0x5e	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_START_QM 	0x01 	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_END_QM	0x03	/* At 1xxxxxxx 1xxxxxxx hand */

#define BIG5_HANZI_10_START_Q 	0x04 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_START_W 	0x20 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_END_Q	0x26 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_END_W	0x5e 	/* At 1xxxxxxx 0xxxxxxx hand */

#define BIG5_HANZI_11_START_Q2	0x29 	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_START_W2	0x01 	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_END_Q2	0x59	/* At 1xxxxxxx 1xxxxxxx hand */
#define BIG5_HANZI_11_END_W2	0x35	/* At 1xxxxxxx 1xxxxxxx hand */

#define BIG5_HANZI_10_START_Q2	0x29 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_START_W2	0x20 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_END_Q2	0x59 	/* At 1xxxxxxx 0xxxxxxx hand */
#define BIG5_HANZI_10_END_W2   	0x5e    /* At 1xxxxxxx 0xxxxxxx hand */

#define CNS_SYMBOL_11_START	0
#define CNS_SYMBOL_11_END	0
#define BIG5_SYMBOL_10_START 	0
#define BIG5_SYMBOL_10_END	0
#define BIG5_SYMBOL_11_START	0
#define BIG5_SYMBOL_11_END	0

#define BIG5_TO_CNS	0x0000	/* Flag for convert from BIG5 to CNS */
#define CNS_TO_BIG5	0x0001	/* Flag for convert from CNS to BIG5 */

#define BIG5_1NUMS	((BIG5_NUM_10_Q*0x23)+(BIG5_NUM_11_Q*0x22))
				/* Numbers of level 1 */
#define BIG5_1TO2_SKIP	(0x25*(BIG5_NUM_10_Q+BIG5_NUM_11_Q))
				/*Location of starting level 2 */

#define CNS_SPACE	0x256D	/* for unconvert character code */

/* not sequential character code on CNS level 2 */
#define CNS_XK		0xa121	/* XK on Tsang Jye */
#define CNS_ONLN	0xa14c	/* ONLN on Tsang Jye */
#define CNS_MSOK	0xa24d	/* MSOK on Tsang Jye */
#define CNS_TNKM	0xbf6a	/* TNKM on Tsang Jye */
#define CNS_CYIB	0xd54b	/* CYIB on Tsang Jye */
#define CNS_YIHXO	0xda28	/* YIHXO on Tsang Jye */
#define CNS_MDMR	0xdd74	/* MDMR on Tsang Jye */
#define CNS_COLH	0xe42f	/* COLH on Tsang Jye */
#define CNS_ODC		0xe761	/* ODC on Tsang Jye */
#define CNS_OKHAE	0xe934	/* OKHAE on Tsang Jye */
#define CNS_HBBM	0xe64d	/* HBBM on Tsang Jye */
#define CNS_CJTC	0xea4b	/* CJTC on Tsang Jye */
#define CNS_LNNXU	0xf166	/* LNNXU on Tsang Jye */
#define CNS_YPYBP	0xf244	/* YPYBP on Tsang Jye */
#define CNS_FDDH	0xf240	/* FDDH on Tsang Jye */
#define CNS_HOOMA	0xd722	/* HOOMA on Tsang Jye */
		
/* not sequential character code on BIG5 level 2 */
#define BIG5_XK		0xc940	/* XK on Tsang Jye */
#define BIG5_ONLN	0xc9be	/* ONLN on Tsang Jye */
#define BIG5_MSOK      	0xcaf7	/* MSOK on Tsang Jye */
#define BIG5_TNKM	0xd77a	/* TNKM on Tsang Jye */
#define BIG5_CYIB	0xebf1	/* CYIB on Tsang Jye */
#define BIG5_YIHXO	0xf0cb	/* YIHXO on Tsang Jye */
#define BIG5_MDMR	0xf056	/* MDMR on Tsang Jye */
#define BIG5_COLH	0xeeeb	/* COLH on Tsang Jye */
#define BIG5_ODC	0xf16b	/* ODC on Tsang Jye */
#define BIG5_OKHAE	0xf268	/* OKHAE on Tsang Jye */
#define BIG5_HBBM	0xf4b5	/* HBBM on Tsang Jye */
#define BIG5_CJTC	0xf663	/* CJTC on Tsang Jye */
#define BIG5_LNNXU	0xf9c4	/* LNNXU on Tsang Jye */
#define BIG5_YPYBP	0xf9d5	/* YPYBP on Tsang Jye */
#define BIG5_FDDH	0xf9c6	/* FDDH on Tsang Jye */
#define BIG5_HOOMA	0xecde	/* HOOMA on Tsang Jye */
#define BIG5_MU		0xc94a	/* MU on Tsang Jye */
#define BIG5_GRHNE	0xddfc	/* GRHNE on Tsang Jye */

/* This function checks if the given code is really a Hanzi in the original 
code definition determined by "which".  If so, it returns 1. And otherwise
it returns 0)
*/
static int
_is_hanzi(code, which)
w_char code;
int	which;
{
    register unsigned char high, low;

    if (which == CNS_TO_BIG5){
	if ((code & 0x8080) == 0x8080){ 	/* 1xxxxxxx 1xxxxxxx Case */
	    high = (code >> 8) - 0xa0;
	    low = (code & 0xff) - 0xa0;
	    if (((high >= CNS_HANZI_11_START_Q && high < CNS_HANZI_11_END_Q) &&
		 (low >= CNS_HANZI_11_START_W && low <= CNS_NUM_Q)) ||
		((high == CNS_HANZI_11_END_Q) &&
		 (low >= CNS_HANZI_11_START_W && low <= CNS_HANZI_11_END_W)) ||
		((high >= CNS_HANZI_11_START_QM && high < CNS_HANZI_11_END_QM)&&
		 (low >= CNS_HANZI_11_START_W && low <= CNS_NUM_Q))) {
		return(1);
	    } else {
		return(0);
	    }
	} else if ((code & 0x8080) == 0x8000){	/* 1xxxxxxx 0xxxxxxx Case */
	    high = (code >> 8) - 0xa0;
	    low = (code & 0xff) - 0x20;
	    if (((high >= CNS_HANZI_10_START_Q && high < CNS_HANZI_10_END_Q) &&
		 (low >= CNS_HANZI_10_START_W && low <= CNS_NUM_Q)) ||
		((high == CNS_HANZI_10_END_Q) &&
		 (low >= CNS_HANZI_10_START_W && low <= CNS_HANZI_10_END_W))) {
		return(1);
	    } else {
		return(0);
	    }
	} else {
	    return(0);
	}
    } else if (which == BIG5_TO_CNS ) {
	if ((code & 0x8080) == 0x8080){ 	/* 1xxxxxxx 1xxxxxxx Case */
	    high = (code >> 8) - 0xa0;
	    low = (code & 0xff) - 0xa0;
	    if (((high >= BIG5_HANZI_11_START_Q && high <= BIG5_HANZI_11_END_Q) &&
		 (low >= BIG5_HANZI_11_START_W && low <= BIG5_HANZI_11_END_W))||
		((high >= BIG5_HANZI_11_START_QM && high <= BIG5_HANZI_11_END_QM) &&
		 (low >= BIG5_HANZI_11_START_W && low <= BIG5_HANZI_11_END_W))){
		return(1);
	    } else if (((high >= BIG5_HANZI_11_START_Q2 && high < BIG5_HANZI_11_END_Q2) &&
			(low >= BIG5_HANZI_11_START_W2 && low <= BIG5_HANZI_11_END_W)) ||
		       ((high == BIG5_HANZI_11_END_Q2) &&
			(low >= BIG5_HANZI_11_START_W2 && low <= BIG5_HANZI_11_END_W2))) {
		return(1);
	    } else {
		return(0);
	    }
	} else if ((code & 0x8080) == 0x8000){	/* 1xxxxxxx 0xxxxxxx Case */
	    high = (code >> 8) - 0xa0;
	    low = (code & 0xff) - 0x20;
	    if ((high >= BIG5_HANZI_10_START_Q && high <= BIG5_HANZI_10_END_Q) &&
		(low >= BIG5_HANZI_10_START_W && low <= BIG5_HANZI_10_END_W)) { 
		return(1);
	    } else if ((high >= BIG5_HANZI_10_START_Q2 && high <= BIG5_HANZI_10_END_Q2) &&
		       (low >= BIG5_HANZI_10_START_W2 && low <= BIG5_HANZI_10_END_W2)) {
		return(1);
	    } else {
		return(0);
	    }
	} else {
	    return(0);
	}
    } 
    return(0);
}

/* convert one Hanzi from BIG5 (or CNS) to CNS (or BIG5) depend on the 
   parameter "which".  This function works under the asumpsion that the 
   give code is really a Hanzi under the original code definition.  Given 
   code value can be checked by function "_is_hanzi()" in the same file.
   The result Hanzi code is always returned.
*/
static unsigned int
_convert(code, which)
register w_char code;
int	which;
{
    unsigned int qu, wei;		/* counting from   1 ------	*/
    register unsigned int location;	/* counting from   0 ----	*/
    unsigned int loc_wei;		/* counting from   0 ----       */
    int plant;

    if (which ==CNS_TO_BIG5) {
	if ((code & 0x8080) == 0x8080) { 	/* 1xxxxxxx 1xxxxxxx Case */
	    if (code <= 0xa5fe && code >= 0xa1a1) {
		wei = (code & 0x7f);
		switch(((code & 0xff00) >> 8) - 0xa0) {
		 case (1):
		    if (wei > 0x5f) {
			return(0xa1a1 + (wei - 0x60));
		    } else {
			return(0xa140 + (wei - 0x21));
		    }
		 case (2):
		    if (wei > 0x5f) {
			return(0xa2a1 + (wei - 0x60));
		    } else {
			return(0xa240 + (wei - 0x21));
		    }
		 case (3):
		    if (wei > 0x40) {
			return(0xa2a1 + (wei - 0x41));
		    } else {
			return(0xa25f + (wei - 0x21));
		    }
		 case (4):
		    if (wei > 0x70) {
			return(0xa340 + (wei - 0x71));
		    } else {
			return(0xa2af + (wei - 0x21));
		    }
		 case (5):
		    if (wei > 0x51) {
			return(0xa3a1 + (wei - 0x52));
		    } else {
			return(0xa34e + (wei - 0x21));
		    }
		}
	    }
	    location = ((code >> 8) - 0xa0 - CNS_HANZI_11_START_Q) * CNS_NUM_Q + 
		       (code & 0xff) - 0xa0 - 1;
	    if ((code > 0xebd0 && code <= 0xefdb) ||
		(code >  0xf5c5 && code <= 0xf7c6) ||
		(code > 0xf8ad && code <= 0xf9e1))
		location--;
	    else if (code == 0xebd0) return(0xbe52);
	    else if (code == 0xf5b5) return(0xc2cb);
	    else if (code == 0xf8ad) return(0xc456);
	} else {				/* 1xxxxxxx 0xxxxxxx Case */
	    location = ((code >> 8) - 0xa0 - CNS_HANZI_10_START_Q) * CNS_NUM_Q + 
		        (code & 0xff) - 0x20 - 1;
	    location += BIG5_1TO2_SKIP;        
	    if (code > CNS_YIHXO && code <= 0xdb3e)
		location--;
	    else if ((code >= 0xa12b && code < CNS_ONLN) ||
		     (code >= 0xa17d && code < CNS_MSOK) ||
		     (code >= 0xa439 && code <= 0xb87d) ||
		     (code > CNS_TNKM && code <= 0xc423) ||
		     (code > CNS_CYIB && code < CNS_HOOMA) ||
		     (code >= 0xdc6a && code < CNS_MDMR) ||		    
		     (code >= 0xe039 && code <= 0xe242) ||
		     (code > CNS_OKHAE && code <= 0xe961) ||
		     (code > CNS_CJTC && code <= 0xec51) ||
		     (code > CNS_LNNXU && code <= 0xf233))
		location++;
	    else if ((code >= 0xb87e && code < CNS_TNKM) ||
		     (code >= 0xc424 && code < CNS_CYIB) ||
		     (code >= 0xe243 && code <= 0xe336) ||
		     (code > CNS_COLH && code <= 0xe437) ||
		     (code > CNS_ODC && code < CNS_OKHAE) ||
		     (code >= 0xe962 && code < CNS_CJTC) ||
		     (code >= 0xec52 && code < CNS_LNNXU) ||
		     (code == 0xf234) ||
		     (code > CNS_FDDH && code <= CNS_YPYBP))
		location += 2;
	    else if ((code >= 0xe337 && code < CNS_COLH) ||
		     (code >= 0xe438 && code <= 0xe572) ||
		     (code > CNS_HBBM && code < CNS_ODC) ||
		     (code >= 0xf235 && code < CNS_FDDH))
		location += 3;
	    else if (code >= 0xe573 && code < CNS_HBBM)
		location += 4;
	    else if (code == CNS_ONLN) return (BIG5_ONLN);
	    else if (code == CNS_MSOK) return (BIG5_MSOK);
	    else if (code == CNS_TNKM) return (BIG5_TNKM);
	    else if (code == CNS_CYIB) return (BIG5_CYIB);
	    else if (code == CNS_YIHXO) return (BIG5_YIHXO);
	    else if (code == CNS_MDMR) return (BIG5_MDMR);
	    else if (code == CNS_COLH) return (BIG5_COLH);
	    else if (code == CNS_ODC) return (BIG5_ODC);
	    else if (code == CNS_OKHAE) return (BIG5_OKHAE);
	    else if (code == CNS_HBBM) return (BIG5_HBBM);
	    else if (code == CNS_CJTC) return (BIG5_CJTC);
	    else if (code == CNS_LNNXU) return (BIG5_LNNXU);
	    else if (code == CNS_YPYBP) return (BIG5_YPYBP);
	    else if (code == CNS_HOOMA) return (BIG5_HOOMA);
	    else if (code == CNS_FDDH) return (BIG5_FDDH);
	}
	qu  = location / (BIG5_NUM_10_Q + BIG5_NUM_11_Q) + BIG5_HANZI_11_START_Q;
	loc_wei = location % (BIG5_NUM_10_Q + BIG5_NUM_11_Q);
	
	if (loc_wei < BIG5_NUM_10_Q){			/* 1xxxxxxx 0xxxxxxx Case */
	    plant = 0xa020;
	    wei = loc_wei + BIG5_HANZI_10_START_W;
	} else  {
	    plant = 0xa0a0;
	    wei  = loc_wei - BIG5_NUM_10_Q + 1;	/* 1xxxxxxx 1xxxxxxx Case */
	}
	return ((qu << 8) + wei + plant);
    } else if (which == BIG5_TO_CNS) {
	if (code >= 0xa3cd && code <= 0xa140) {
	    if (code <= 0xa1bf) {
		if (code & 0x80) {
		    return(0xa1e0 + (code - 0xa1a1));
		} else {
		    return(0xa1a1 + (code - 0xa140));
		}
	    } else if (code <= 0xa25e) {
		if (code & 0x80) {
		    return(0xa2a1 + (code - 0xa1c0));
		} else {
		    return(0xa2e0 + (code - 0xa240));
		}
	    } else if (code <= 0xa2ae) {
		if (code & 0x80) {
		    return(0xa3c1 + (code - 0xa2a1));
		} else {
		    return(0xa3a1 + (code - 0xa25f));
		}
	    } else if (code <= 0xa34e) {
		if (code & 0x80) {
		    return(0xa4a1 + (code - 0xa2af));
		} else {
		    return(0xa4f1 + (code - 0xa340));
		}
	    } else {
		if (code & 0x80) {
		    return(0xa5d2 + (code - 0xa3a1));
		} else {
		    return(0xa5a1 + (code - 0xa34e));
		}
	    }
	}
	if ( (code & 0x8080) == 0x8080) { 	/* 1xxxxxxx 1xxxxxxx Case */
	    location = (((code >> 8)- 0xa0 - BIG5_HANZI_11_START_Q) *
			(BIG5_NUM_10_Q + BIG5_NUM_11_Q) +
			(code & 0xff) - 0xa0 + BIG5_NUM_10_Q - 1); 
	    
	} else {					/* 1xxxxxxx 0xxxxxxx Case */
	    location = (((code >> 8) - 0xa0 - BIG5_HANZI_10_START_Q) *
			(BIG5_NUM_10_Q + BIG5_NUM_11_Q) +
			(code & 0xff) - 0x20 - BIG5_HANZI_10_START_W);
	}
	if (location < BIG5_1NUMS){  			/* 1xxxxxxx 0xxxxxxx  Case*/
	    plant = 0xa0a0;
	    qu  = location / BIG5_NUM_11_Q + CNS_HANZI_11_START_Q;
	    wei = location % BIG5_NUM_11_Q + CNS_HANZI_11_START_W;
	    if ((code >= 0xbbc8 && code < 0xbe52) ||
		(code >=  0xc1ab && code < 0xc2cb) ||
		(code >= 0xc361 && code < 0xc456))
		location++;
	    else if (code == 0xbe52) return(0xebd0);
	    else if (code == 0xc2cb) return(0xf5b5);
	    else if (code == 0xc456) return(0xf8ad);
	} else {					/* 1xxxxxxx 1xxxxxxx Case */
	    location -=  BIG5_1TO2_SKIP;	/* For level two */ 
	    if (code >= 0xeb5b && code < BIG5_CYIB) 
		location++;
	    else if ((code > BIG5_MU && code <= 0xc96b) ||
		     (code > BIG5_ONLN && code <= 0xc9ec) ||
		     (code > BIG5_MSOK && code < BIG5_TNKM) ||
		     (code >= 0xdba7 && code < BIG5_GRHNE) ||
		     (code >= 0xe8a3 && code <= 0xe975) ||
		     (code > BIG5_HOOMA && code <= 0xeda9) ||
		     (code > BIG5_COLH && code < BIG5_MDMR) ||
		     (code >= 0xf466 && code < BIG5_HBBM) ||
		     (code >= 0xf4fd && code < BIG5_CJTC) ||
		     (code >= 0xf977 && code < BIG5_LNNXU))
		location--;
	    else if ((code > BIG5_TNKM && code <= 0xdba6) ||
		     (code > BIG5_GRHNE && code <= 0xe8a2) ||
		     (code > BIG5_MDMR && code < BIG5_YIHXO) ||
		     (code >= 0xf163 && code < BIG5_ODC) ||
		     (code >= 0xf375 && code <= 0xf465) ||
		     (code > BIG5_HBBM && code <= 0xf4fc) ||
		     (code > BIG5_CJTC && code <= 0xf976) ||
		     (code == 0xf9c5) ||
		     (code >= 0xf9d2 && code <= BIG5_YPYBP))
		location -= 2;
	    else if ((code > BIG5_YIHXO && code <= 0xf162) ||
		     (code > BIG5_ODC && code < BIG5_OKHAE) ||
		     (code >= 0xf2c3 && code <= 0xf374) ||
		     (code > BIG5_FDDH && code <= 0xf9d1))
		location -= 3;
	    else if (code > BIG5_OKHAE && code <= 0xf2c2)
		location -= 4;
	    else if (code == BIG5_ONLN) return (CNS_ONLN);
	    else if (code == BIG5_MSOK) return (CNS_MSOK);
	    else if (code == BIG5_TNKM) return (CNS_TNKM);
	    else if (code == BIG5_CYIB) return (CNS_CYIB);
	    else if (code == BIG5_YIHXO) return (CNS_YIHXO);
	    else if (code == BIG5_MDMR) return (CNS_MDMR);
	    else if (code == BIG5_COLH) return (CNS_COLH);
	    else if (code == BIG5_ODC) return (CNS_ODC);
	    else if (code == BIG5_OKHAE) return (CNS_OKHAE);
	    else if (code == BIG5_HBBM) return (CNS_HBBM);
	    else if (code == BIG5_CJTC) return (CNS_CJTC);
	    else if (code == BIG5_LNNXU) return (CNS_LNNXU);
	    else if (code == BIG5_FDDH) return (CNS_FDDH);
	    else if (code == BIG5_YPYBP) return (CNS_YPYBP);
	    else if (code == BIG5_HOOMA) return (CNS_HOOMA);
	    else if (code == BIG5_MU) return (CNS_SPACE);
	    else if (code == BIG5_GRHNE) return (CNS_SPACE);

	    plant = 0xa020;
	    qu  = location / BIG5_NUM_11_Q + CNS_HANZI_10_START_Q;
	    wei = location % BIG5_NUM_11_Q + CNS_HANZI_10_START_W;
	}
	return((qu << 8) + wei + plant);
    }
    return(0);
}

#ifdef	ECNS_IS_UCNS
int ecns_to_icns(icns, ucns, siz)
w_char *icns;
unsigned char *ucns;
int siz;
{
    register w_char *i = icns;
    register unsigned char *u = ucns, *uend = ucns + siz, x;
    static w_char local_pending = (w_char)0;
    static unsigned char shift_mode = '\0';

    if (siz <= 0) return(0);
    if (local_pending) {
	*i = local_pending | (*u++ & 0x7f);
	if (shift_mode == SS3) {
	    *i++ |= 0x8000;
	    shift_mode = '\0';
	} else {
	    *i++ |= 0x8080;
	}
	local_pending = (w_char)0;
    }
    if (shift_mode == SS2) {
	*i++ = *u++;
	shift_mode = '\0';
    }
    for (; u < uend;) {
	x = *u++;
	if (x == SS2) {
	    if (u == uend) {
		shift_mode = SS2;
		break;
	    }
	    *i++ = *u++;
	    break;
	} else if (x == SS3) {
	    if (u == uend) {
		shift_mode = SS3;
		break;
	    }
	    *i = ((*u++ & 0x7f) << 8);
	    if (u == uend) {
		local_pending = *i;
		break;
	    }
	    *i |= (*u++ & 0x7f);
	    *i++ |= 0x8000;
	} else if (x > 0x7f) {
	    *i = ((x & 0x7f) << 8);
	    if (u == uend) {
		local_pending = *i;
		break;
	    }
	    *i |= (*u++ & 0x7f);
	    *i++ |= 0x8080;
	} else {
	    *i++ = x;
	}
    }
    return((char *)i - (char *)icns);
}

int icns_to_ecns(ucns, icns, siz)
unsigned char *ucns;
w_char *icns;
int siz;
{
    register unsigned char *u = ucns;
    register w_char *i = icns, w;

    for (;siz > 0; siz -= sizeof(w_char)) {
	w = *i++;
	if (!(w & 0xff80)) { /* CS0 */
	    *u++ = (unsigned char)w;
	} else if (!(w & 0xff00)) { /* CS2 */
	    *u++ = SS2;
	    *u++ = (unsigned char)w;
	} else if (w & 0x80) { /* CS1 */
	    *u++ = (unsigned char)((w & 0xff00) >> 8);
	    *u++ = (unsigned char)(w & 0xff);
	} else { /* CS3 */
	    *u++ = SS3;
	    *u++ = (unsigned char)((w & 0xff00) >> 8);
	    *u++ = (unsigned char)((w & 0xff) | 0x80);
	}
    }
    return(u - ucns);
}
#else	/* ECNS_IS_UCNS */

static int oc_mode = ASCII;
static unsigned char *cns;

static void
putcns(x)
unsigned char x;
{
    *cns++ = x;
}

static void
cns_change_mode(mode, new_mode)
int *mode;
int new_mode;
{
    if (*mode == new_mode) return;
    switch(*mode = new_mode) {
     case CNS11643_1:
	putcns('\033'); putcns('$'); putcns(')'); putcns('0'); break;
     case CNS11643_2:
	putcns('\033'); putcns('$'); putcns('*'); putcns('1'); break;
     case ASCII:
	/* designate ISO-8859-1 rather than JIS X 0201 */
	/* putcns('\033'); putcns('('); putcns('J'); break; */
	putcns('\033'); putcns('('); putcns('B'); break;
    }
}

int
ecns_to_icns(icns,ecns,siz)
w_char *icns;
unsigned char *ecns;
int siz;
{
    designate = CNS_designate;
    return(extc_to_intc(icns, ecns, siz));
}

int icns_to_ecns(ecns, icns, siz)
unsigned char *ecns;
w_char *icns;
int siz;
{
    register int i = siz;
    register w_char *ic, x;
    cns = ecns;

    for (;i > 0; i -= sizeof(w_char)) {
	x = *ic++;
	if ((x & 0x8080) == 0x8080) {
	    cns_change_mode(&oc_mode, CNS11643_1);
	    putcns((x >> 8) & 0xff); putcns(x & 0xff);
	} else if ((x & 0x8000) == 0x8000) {
	    cns_change_mode(&oc_mode, CNS11643_2);
	    putcns(((x >> 8) & 0x7f) | 0x80); putcns((x & 0x7f) | 0x80);
	} else {
	    cns_change_mode(&oc_mode, ASCII);
	    putcns(x & 0x7f);
	}
    }
    cns_change_mode(&oc_mode, ASCII);
    return(cns - ecns);
}
#endif	/* ECNS_IS_UCNS */

int icns_to_big5(big5, icns, siz)
unsigned char *big5;
w_char *icns;
int siz;
{
    register unsigned char *d = big5;
    register w_char *s = icns;
    register i = siz;
    short code_out;	/* Buffering one two-byte code	*/

    if (d == NULL || s == NULL) return(-1);

    for (; i > 0; i -= sizeof(w_char)) {
	if (!(*s & 0xff00)){			/* Ascii */
	    if (!(*s & 0x80)) {
		*d++ = (unsigned char)(*s++ & 0x7f);
	    }else {		/* Single Shift */
		*d++ = SS2;
		*d++ = (unsigned char)(*s++ & 0xff);
	    }
	} else if (_is_hanzi(*s, CNS_TO_BIG5)){
	    code_out = _convert(*s++, CNS_TO_BIG5);
	    *d++ = (code_out >> 8);
	    *d++ = code_out & 0x00ff;
	} else {			/* Strainge codes */
	    *d++ = (unsigned char)((*s & 0xff00) >> 8);
	    *d++ = (unsigned char)(*s++ & 0xff);
	}
    }
    *d = '\0';
    return(d - big5);
}

int ecns_to_big5(big5,ecns,siz)
unsigned char *big5, *ecns;
int siz;
{
    int len;
    len = ecns_to_icns(tmp_w_buf, ecns, siz);
    return(icns_to_big5(big5, tmp_w_buf, len));
}

int big5_to_icns(icns, big5, siz)
w_char *icns;
unsigned char *big5;
int siz;
{
    register w_char *d = icns;
    register unsigned char *s = big5;
    unsigned char *send = s + siz;
    unsigned short code_in;	/* Buffering one two-byte code	*/

    if (d == NULL || s == NULL ) return(-1);

    for (;s < send; s++) {
	if (!(*s & 0x80)){			/* Ascii */
	    *d++ = (w_char)*s;
	}else if (*s == 0x8e){		/* Single Shift */
	    *d++ = (w_char)*(++s);
	} else {
	    code_in = ((*s++) << 8);
	    code_in |= *s;
	    if (_is_hanzi(code_in, BIG5_TO_CNS)){
		*d++ = _convert(code_in, BIG5_TO_CNS);
	    } else {			/* Strainge codes */
		*d++ = code_in;
	    }
	}
    }
    *d = (w_char)0;
    return((char *)d - (char *)icns);
}

int big5_to_ecns(ecns, big5, siz)
unsigned char *ecns, *big5;
int siz;
{
    int len;
    len = big5_to_icns(tmp_w_buf, big5, siz);
    return(icns_to_ecns(ecns, tmp_w_buf, len));
}

int iugb_to_eugb(eugb, iugb, siz)
unsigned char *eugb;
w_char *iugb;
int siz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UGB_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(ieuc_to_eeuc(eugb, iugb, siz));
}

int eugb_to_iugb(iugb, eugb, siz)
w_char *iugb;
unsigned char *eugb;
int siz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UGB_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(eeuc_to_ieuc(iugb, eugb, siz));
}
#endif	/* CHINESE */


#ifdef	KOREAN

#define	ZENKAKU_KSC	1

static	unsigned char	*ks;
static	w_char		*iuk;
static	unsigned char	*euk;

static void
putks(x)
int x;
{
	*ks++=x;
}

static int oks_mode = ASCII;	/* 出力時のKSCコードのモード */
extern int euksc_to_iuksc();

static void
ksc_change_mode(mode,new_mode)
int *mode;
int new_mode;
{
 if(*mode==new_mode)return;
 switch(*mode){
	case ZENKAKU_KSC :
		putks('\033'); putks('('); putks('B');break;
	default: ;
 }
 *mode=new_mode;
 switch(new_mode){
	case ZENKAKU_KSC :
		putks('\033'); putks('$'); putks('('); putks('C');break;
	default: ;
 }
}

/*	内部 U-ksc を ksc コードに変換します
	文字列の長さを返します			*/
extern int
iuksc_to_ksc(ksc,iuksc,iusiz)
unsigned char	*ksc;	/*	kscコードになったものをおくbuf	*/
w_char	*iuksc;	/*	iukscコードのものをおいてくるbuf*/
int	iusiz;	/*	iuksc の大きさ			*/
{
 int x;
 ks=ksc;
 iuk=iuksc;
 for(;iusiz>0;iusiz-=sizeof(w_char)){
	x = *iuk++;
	if((x & 0x8080) == 0x8080){
		ksc_change_mode(&oks_mode,ZENKAKU_KSC);
		putks((x >>8) & 0x7f);putks(x & 0x7f);
	}else{
		ksc_change_mode(&oks_mode,ASCII);
		putks(x);
	}
 }
 ksc_change_mode(&oks_mode,ASCII);
 return (ks - ksc);
}


/*	外部 U-ksc を ksc コードに変換します	*/
extern int
euksc_to_ksc(ksc,euksc,eusiz)
unsigned char *ksc,*euksc;
int eusiz;
{
    static int kanji1 = 0;
    static unsigned char kanji1_code = 0;
    /* 0: normal
       1: get SS2
       2: get kanji 1 byte */
    int x;
    ks=ksc;
    euk=euksc;
    if (kanji1 != 0) {
	if (kanji1 == 2) {
	    putks(kanji1_code & 0x7f);
	    putks(*euk & 0x7f);
	} else {
	    putks(*euk);
	}
	eusiz -= sizeof(char);
	kanji1 = 0;
	euk++;
    }
    for( ;eusiz>0;eusiz-=sizeof(char)){
	x = *euk++;
	if(x & 0x80){
	    ksc_change_mode(&oks_mode,ZENKAKU_KSC);
	    if (eusiz > 1) {
		putks(x & 0x7f);putks(*euk++ & 0x7f);
		eusiz -= sizeof(char);
	    } else {
		kanji1 = 2;
		kanji1_code = x;
	    }
	}else{
	    ksc_change_mode(&oks_mode,ASCII);
	    putks(x);
	}
    }
    if (kanji1 == 0)
	ksc_change_mode(&oks_mode,ASCII);
    return(ks - ksc);
}

/*	内部 U-ksc を 外部 U-ksc コードに変換します	*/
extern int
iuksc_to_euksc(euksc,iuksc,iusiz)
unsigned char *euksc;
w_char *iuksc;
int iusiz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UKSC_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(ieuc_to_eeuc(euksc, iuksc, iusiz));
}

int
ksc_to_euksc(euksc, ksc, jsiz)
unsigned char *euksc, *ksc;
int jsiz;
{
    int len;

    designate = KSC_designate;
    len = extc_to_intc(tmp_w_buf, ksc, jsiz);
    return(iuksc_to_euksc(euksc, tmp_w_buf, len));
}	

int
ksc_to_iuksc(iuksc, ksc, jsiz)
w_char *iuksc;
unsigned char *ksc;
int jsiz;
{
    designate = KSC_designate;
    return(extc_to_intc(iuksc, ksc, jsiz));
}

int
euksc_to_iuksc(iuksc, euksc, eusiz)
w_char *iuksc;
unsigned char *euksc;
int eusiz;
{
    static int first = 0;
    static unsigned int cswidth_id;

    if (first == 0) {
	cswidth_id = create_cswidth(UKSC_CSWIDTH);
	first++;
    }
    set_cswidth(cswidth_id);
    return(eeuc_to_ieuc(iuksc, euksc, eusiz));
}

#endif	/* KOREAN */
