/* vi: set sw=4 ts=4: */
/*
 * KON2 - Kanji ON Console -
 * Copyright (C) 1992-1996 Takashi MANABE (manabe@papilio.tutics.tut.ac.jp)
 *
 * CCE - Console Chinese Environment -
 * Copyright (C) 1998-2003 Rui He (rhe@3eti.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 */

/* Console driver handling, may have a look at CCE 0.11's console.c
   and Linux kernel source code: /usr/src/linux/drivers/char/console.c

   The below code doesn't handle all of the ANSI required ESC stuff
 */
#include	<stdio.h>
#include	<unistd.h>
#include	<string.h>
#include	<sys/types.h>

#include	<getcap.h>
#include	<defs.h>
#include	<term.h>
#include	<font.h>
#include	<vtcon.h>
#include 	<hzinput.h>
#include	<errors.h>
#include	<vc.h>

#define	CHAR_NUL	'\x00'
#define	CHAR_BEL	'\x07'
#define	CHAR_BS		'\x08'
#define	CHAR_HT		'\x09'
#define	CHAR_LF		'\x0A'
#define	CHAR_VT		'\x0B'
#define	CHAR_FF		'\x0C'
#define	CHAR_CR		'\x0D'
#define	CHAR_SO		'\x0E'
#define	CHAR_SI		'\x0F'
#define	CHAR_XON	'\x11'
#define	CHAR_XOFF	'\x12'
#define	CHAR_CAN	'\x18'
#define	CHAR_SUB	'\x1A'
#define	CHAR_ESC	'\x1B'
#define	CHAR_DEL	'\x7F'
#define	CHAR_CSI	'\x9B'
#define	CHAR_SS2	'\x8E'

#define	LEN_REPORT	9

static int scroll;
LangInfo lInfo;
int OverrideSysCoding;  /* override the configuration file settings */

static void SaveAttr(ConInfo *con)
{
    struct attrStack *tmp;

    tmp = (struct attrStack *)malloc(sizeof(struct attrStack));
    if (con->saveAttr) tmp->prev = con->saveAttr;
    else tmp->prev = NULL;
    con->saveAttr = tmp;
    con->saveAttr->x = con->x;
    con->saveAttr->y = con->y;
    con->saveAttr->attr = con->attr;
	con->saveAttr->charfont = con->charfont;
    con->saveAttr->fcol = con->fcol;
    con->saveAttr->bcol = con->bcol;
}

static void RestoreAttr(ConInfo *con)
{
    struct attrStack *tmp;

    if (con->saveAttr) 
    {
	con->x = con->saveAttr->x;
	con->y = con->saveAttr->y;
	con->attr = con->saveAttr->attr;
	con->fcol = con->saveAttr->fcol;
	con->bcol = con->saveAttr->bcol;
	con->charfont = con->saveAttr->charfont;
	tmp = con->saveAttr;
	con->saveAttr = tmp->prev;
	free(tmp);
    }
}

static void UpdateAttr(ConInfo *con)
{
	u_char swp;
	
    if (con->attr & ATTR_ULINE)
        con->fcol = 0xf;  /* ulcolor */ /* bold white */
    else if (con->attr & ATTR_LOW)
		con->fcol = 0x8; /* halfcolor */ /* grey */

	if (con->attr & ATTR_REVERSE)
	{
		swp = con->fcol;
		con->fcol = (con->fcol & 8) | (con->bcol & 7);
		con->bcol = (con->bcol & 8) | (swp & 7);
	}

	if (con->attr & ATTR_BLINK)
		con->bcol |= 0x8; /* ^= 0x8; */

	if (con->attr & ATTR_HIGH)
		con->fcol |= 0x8; /* ^= 0x8; */
}

static void	EscSetAttr(ConInfo *con,int col)
{
    static u_char color_table[] = 
		{ 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 };

    u_char	swp;
    
    switch(col) 
    {
    case 0:	/* off all attributes */
		con->bcol = DEF_BGCOLOR;
		con->fcol = DEF_FGCOLOR;
		con->charfont = 0;
		con->attr = 0;
		break;
    case 1:  /* highlight, fcolor   intensity = 2   Turns on bold mode */
		con->attr = (con->attr & ~ATTR_LOW) | ATTR_HIGH;
		break;
	case 2:    /* intensity = 0  halfcolor 0x08 grey  Set foreground color? CSI 2;M;N m */
		con->attr = (con->attr & ~ATTR_HIGH) | ATTR_LOW;
		break;
	case 3:    /* italic/blink mode SCO-ish?  enable italic mode */
	case 23:   /* disable italic mode  */
		break;
    case 4:	/* underline, bcolor linux kernel using ulcolor(0x0f) bold white for underline  */
		con->attr |= ATTR_ULINE;
		break;
	case 5: /* blink=1   enable blinking */
	case 26:
		con->attr |= ATTR_BLINK;
		break;
	case 6: /* blink=0   disable blinking */
	case 25:
		con->attr &= ~ATTR_BLINK;
		break;
	case 7:  /* reverse  reverse=1 */
		con->attr |= ATTR_REVERSE;

		break;

    case 21:  /* clear highlight    21-disable bold mode */
	case 22:  /* 21,22 intensity=1 */
		con->attr &= ~(ATTR_HIGH | ATTR_LOW);
		con->fcol &= ~8;
		break;
    case 24:   /* clear underline  underline=0 */
		con->attr &= ~ATTR_ULINE;
		con->fcol &= ~8; 
		break;
    case 27:  /* clear reverse reverse=0 */
		if (con->attr & ATTR_REVERSE) 
        {
	    	con->attr &= ~ATTR_REVERSE;
			
			swp = con->fcol;
			con->fcol = (con->fcol & 8) | (con->bcol & 7);
			con->bcol = (con->bcol & 8) | (swp & 7);
	
		}
		break;

    case 10: /* ANSI X3.64-1979 (SCO-ish?)
                  * Select primary font, don't display
                  * control chars if defined, don't set
                  * bit 8 on output.
                  */
		con->charfont = 0;
        break;
    case 11: /* ANSI X3.64-1979 (SCO-ish?)
              * Select first alternate font, lets
              * chars < 32 be displayed as ROM chars.
              */
		con->charfont = 1;
        break;
	
    case 12: /* ANSI X3.64-1979 (SCO-ish?)
              * Select second alternate font, toggle
              * high bit before displaying as ROM char.
              */
		con->charfont = 2;
        break;

	case 38: /* ANSI X3.64-1979 (SCO-ish?)
                  * Enables underscore, white foreground
                  * with white underscore (Linux - use
                  ** default foreground). */
		con->fcol = DEF_FGCOLOR;
		con->attr |= ATTR_ULINE;
        break;
    case 39: /* ANSI X3.64-1979 (SCO-ish?)
          * Disable underline option.
          * Reset colour to default? It did this before... */
		con->fcol = DEF_FGCOLOR;
		con->attr &= ~ATTR_ULINE;
        break;
    case 49: /* background use default, foregroud use old values */
		con->bcol = DEF_BGCOLOR;
        break;

    default:
		if (col >= 30 && col <= 37)  /* assign foreground color */
        {
			con->fcol = color_table[col-30];

		} 
        else if (col >= 40 && col <= 47)  /* assign background color */
        {
			con->bcol = color_table[col-40];

		}
		break;
    }
}

static void	VtSetMode(ConInfo *con,u_char mode, bool sw)
{
    switch(mode) 
    {
	case 3:  /* Monitor (display ctrls) */
		break;
    case 4: /* Insert Mode on/off */
		con->ins = sw;
		break;
	case 7: /* autowrap on/off  */
		break;
	case 20: /* Lf, Enter = CrLf/Lf  */
		break;
    case 25: /* cursor on/off */
		cursorInfo.sw = sw;
		break;
    }
}

static void EscReport(ConInfo *con,u_char mode, u_short arg)
{
    static char report[LEN_REPORT];
    
    switch(mode) 
    {
    case 'n':
		if (arg == 6)   /* cursor report */
        {
	    	int x = (con->x < con->xmax) ? con->x : con->xmax;
	    	int y = (con->y < con->ymax) ? con->y : con->ymax;
	    	snprintf(report, LEN_REPORT, "\x1B[%d;%dR", y + 1, x + 1);
		} 
        else if (arg == 5)     /* status report */
	    	strcpy(report, "\x1B[0n\0"); /* ok */
		break;
    case 'c':
		if (arg == 0) strcpy(report, "\x1B[?6c\0"); /* ok */
		else return;
		break;
    }
    write(con->masterPty, report, strlen(report));
}

#define	MAX_NARG	8

static void EscBracketEqual(ConInfo *con, u_char ch)
{
    u_char	n;
    static u_short varg[MAX_NARG+1], narg;

    if (ch >= '0' && ch <= '9') 
    {
		varg[narg] = (varg[narg] * 10) + (ch - '0');
    }
    else if (ch == ';') 
    {
		if (narg < MAX_NARG) narg++;
		else con->esc = NULL;
    } 
    else 
    {
		con->esc = NULL;
   
		switch(ch)   
        {

		case 'c':
			cursorInfo.sw = (varg[0] != 0);  
			break;		
		}

    	if (con->esc == NULL) 
    	{
    	    narg = 0;
            for ( n = 0; n < MAX_NARG; n++ )
                varg[n] = 0;
        }
    }
}

static void EscBracket(ConInfo *con,u_char ch)
{
    u_char	n;
    static u_short varg[MAX_NARG+1], narg, question;

    if (ch >= '0' && ch <= '9') 
    {
		varg[narg] = (varg[narg] * 10) + (ch - '0');
    }
    else if (ch == ';') 
    {
		if (narg < MAX_NARG) narg++;
		else con->esc = NULL;
    } 
    else 
    {
		con->esc = NULL;
        
    	switch(ch) 
        {

		case '=':  /* Feb 12, 2004 added for FreeBSD's vim, SCO-specific */
    	    question = narg = 0;
            for ( n = 0; n < MAX_NARG; n++ ) varg[n] = 0;
			con->esc = EscBracketEqual;
			break;

       	case 'K':  /* bash use this all the time  ESC(0x1B) [(0x5B) K(0x4B) ^M(0x0D) */
       	    TextClearEol(con,varg[0]);  /* 0x0 */
       	    break;
       	case 'J':   /* linux kernel csi_J() */
       	    TextClearEos(con,varg[0]);
       	    break;
        case 'X':   /* Erase n characters in line */
            TextClearChars(con, varg[0]);
            break;

       	case 'S':   /* Scroll up n lines */
			scroll += varg[0] ? varg[0] : 1;
       	    break;
		case 'T':   /* Scroll down n lines */
			scroll -= varg[0] ? varg[0] : 1;
       	    break;
 
    	case 'F':  /* UP, CR */
    		con->x = 0;
       	case 'A':  /* UP  ESC(0x1B) [(0x5B) A(0x41) */
       	    con->y -= varg[0] ? varg[0]: 1;
       	    if (con->y < con->ymin) 
            {
       			scroll -= con->y - con->ymin;
       			con->y = con->ymin;
       	    }
       	    break;
    	case 'E': /*  DOWN, CR */
    		con->x = 0;
       	case 'B':  /* DOWN */
    	case 'e':
       	    con->y += varg[0] ? varg[0]: 1;
       	    if (con->y > con->ymax) 
            {
       			scroll += con->y - con->ymin;
       			con->y = con->ymax;
       	    }
       	    break;
       	case 'C':  /* RIGHT */
    	case 'a': 
       	    con->x += varg[0] ? varg[0]: 1;
       	    con->wrap = FALSE;
       	    break;
       	case 'D':  /* LEFT */
       	    con->x -= varg[0] ? varg[0]: 1;
       	    con->wrap = FALSE;
       	    break;
       	case 'G':   /* cursor horizontal movement */
    	case '`':
       	    con->x = varg[0] ? varg[0] - 1: 0;
       	    con->wrap = FALSE;
       	    break;
       	case 'P':   /* Delete n chars */
       	    TextDeleteChar(con,varg[0] ? varg[0]: 1);
       	    break;
       	case '@':   /* Insert n chars */
       	    TextInsertChar(con,varg[0] ? varg[0]: 1);
       	    break;
       	case 'L':   /* Insert n lines */
       	    TextMoveDown(con, con->y, con->ymax, varg[0] ? varg[0] : 1);
       	    break;
       	case 'M':   /* Delete n lines */
       	    TextMoveUp(con, con->y, con->ymax, varg[0] ? varg[0] : 1);
       	    break;

       	case 'H':
       	case 'f':  /* move cursor to (m,n) */
       	    if (varg[1]) con->x = varg[1] - 1;
       	    else con->x = 0;
       	    con->wrap = FALSE;  /* Attention: no break! */
       	case 'd':  /* move cursor to (n) */
       	    con->y = varg[0] ? varg[0] - 1: 0;
       	    break;
       	case 'm': 

			if (question != TRUE)
			{
       	    	for (n = 0; n <= narg; n ++)
       				EscSetAttr(con,varg[n]);
    			UpdateAttr(con);
			}
       	    break;
       	case 'r':  /* set scroll range */
       	    con->ymin = varg[0]? (varg[0] - 1): 0;
       	    con->ymax = varg[1]? (varg[1] - 1): (dispInfo.tymax - 1); /* Fixed by Holly Lee - Sep 26, 1999 */
       	    con->x = 0;
       	    con->y = con->ymin;
       	    con->wrap = FALSE;
       	    if (con->ymin || con->ymax != dispInfo.tymax)
       			con->soft = TRUE;
       	    else
       			con->soft = FALSE;
       	    break;
       	case 'l':
       	    for (n = 0; n <= narg; n ++)
       			VtSetMode(con,varg[n], FALSE);
       	    break;
       	case 'h':
       	    for (n = 0; n <= narg; n ++)
       			VtSetMode(con,varg[n], TRUE);
       	    break;
       	case '?':
       	    question = TRUE;
       	    con->esc = EscBracket;
       	    break;
       	case 's':
       	    SaveAttr(con);
       	    break;
       	case 'u':
       	    RestoreAttr(con);
       	    break;
       	case 'n':

       	    if (question != TRUE)
       			EscReport(con,ch, varg[0]);
       	    break;
       	case 'c':

#if defined(__SCOUnixWare__)  /* ESC [ 0-2 c for show/hide cursor */
			if (question != TRUE) cursorInfo.sw = (varg[0] != 2);
#else  /* Linux-specific?  */
			if (question != TRUE) EscReport(con, ch, varg[0]);
#endif
			break;			
       	case 'R':
       	    break;
    	}
            
    	if (con->esc == NULL) 
    	{
    	    question = narg = 0;  /* reset question mark */
            for ( n = 0; n < MAX_NARG; n++ )
                varg[n] = 0;
        }
    }
}

static void EscSetDCodeG0(ConInfo *con,u_char ch)
{
    int i;

    switch(ch) 
    {
    case '(': /* EscSetDCodeG0 */
    case ')': /* EscSetDCodeG1 */
		return;
    case '@':
		ch = 'B';  /* For Japanese, @->B */
    default:
		i = 0;
		while (fDRegs[i].sign0) 
        {
	    	if (fDRegs[i].sign0 == ch) 
            {
				con->db = (u_char)i|LATCH_1;
				break;
	    	}
	    	i++;
		}
		con->trans = CS_DBCS;
		break;
    }
    con->esc = NULL;
}

static void EscSetSCodeG0(ConInfo *con,u_char ch)
{
    int i=0;

    switch(ch) 
	{
    case 'U':
		con->g[0] = CS_GRAPH;
		break;
    default:
		while (fSRegs[i].sign0) 
        {
	    	if (fSRegs[i].sign0 == ch) 
            {
				con->sb = (u_char)i;
				con->g[0] = CS_LEFT;
				break;
	    	} 
            else if (fSRegs[i].sign1 == ch) 
            {
				con->sb = (u_char)i;
				con->g[0] = CS_RIGHT;
				break;
	    	}
	    	i++;
		}
    }
    con->trans = con->g[0];
    con->esc = NULL;
}

static void EscSetSCodeG1(ConInfo *con,u_char ch)
{
    switch(ch) 
    {
    case 'U':
		con->g[1] = CS_LEFT;
		break;
    case '0':
		con->g[1] = CS_GRAPH;
		break;
    case 'A':
    case 'J': /* <ESC>(J  from ISO-2022-JP JIS back to ASCII */
    case 'B': /* <ESC>$B  from ASCII to ISO-2022-JP JIS */
	case 'C': /* <ESC>$)C ISO-2022-KR  (0x0E/0x0F shift-in/out) */
		break;
    }
    con->trans = con->g[1];
    con->esc = NULL;
}

static void EscStart(ConInfo *con,u_char ch)
{
	con->esc = NULL;
    switch(ch) 
   	{
    case '[':
		con->esc = EscBracket;
		break;
    case '$':/* Set Double Byte Code */
		con->esc = EscSetDCodeG0;
		break;
    case '(':/* Set 94 to G0 */
		con->esc = EscSetSCodeG0;  
		break;
    case ')':/* Set G1 */
		con->esc = EscSetSCodeG1;
		break;

    case 'E': /* supposed to be cr() lf() */
		con->x = 0;
		con->wrap = FALSE;
    case 'D':
		if (con->y == con->ymax) scroll++;
		else con->y++;
		break;
	case 'I': /* beginning of previous line, scroll up */
		con->x = 0;
		con->wrap = FALSE;
    case 'M': /* cursor reverse index, scroll up */
		if (con->y == con->ymin) scroll--;
		else con->y--;
		break;	
    case 'c':  /* reset terminal  & clear screen?  */
		con->fcol = DEF_FGCOLOR;
		con->attr = DEF_BGCOLOR;
		con->charfont = 0;
		con->knj1 = con->bcol = 0;
		con->wrap = FALSE;
		con->trans = CS_LEFT;
		con->sb = lInfo.sb;
		con->db = lInfo.db|LATCH_1;
    case '*':
		con->x = con->y = 0;
		con->wrap = FALSE;
		TextClearAll(con);
		break;
    case '7':   /* Save cursor position & other attributes(as in Linux) */
		SaveAttr(con);
		break;
    case '8':   /* Restore cursor position */
		RestoreAttr(con);
		con->wrap = FALSE;
		break;
	case ']':
		break;
    }
}

int isPrevW1(ConInfo *con)
{
  u_int addr;
  if (con->x <= 0) return 0;
  addr = TextAddress(con,con->x-1, con->y);
  return(*(con->flagBuff + addr) & LATCH_1);
}

void	VtWrite(ConInfo *con, const u_char *buff, int nchars)
{
	u_char	ch;

	while (nchars-- > 0) 
	{
		ch = *buff++;
		if (! ch) continue;

		if (con->esc) 
	    	con->esc(con,ch);   /* in escape mode, parse the parameters */
		else switch (ch) 
        {

		case CHAR_BEL:  /* 0x07 ^G */
	    	Beep();
	    	break;
		case CHAR_DEL:  /* 0x7F */
	    	break;
		case CHAR_BS:   /* 0x08 ^H BackSpace */
	    	if (con->x) con->x--;
	    	con->wrap = FALSE;
	    	break;
		case CHAR_HT:  /*0x09 ^I Horizontal Tab */
	    	con->x += con->tab - (con->x % con->tab);
	    	con->wrap = FALSE;
	    	if (con->x > con->xmax) con->x -= con->xmax + 1;
	    	else break;
		case CHAR_FF:  /* 0x0C ^L Form Feed  (clear screen and move cursor to topleft) */

			con->x = con->y = 0;
			con->wrap = FALSE;
			TextClearAll(con);
			break;	

		case CHAR_VT:  /* 0x0B ^K Vertial Tab  (same x location, but next line) */
		case CHAR_LF:   /* 0x0A ^J Line Feed */
	    	con->wrap = FALSE;
	    	if (con->y == con->ymax) scroll++;
	    	else con->y++;
	    	break;
		case CHAR_CR:  /* 0x0D ^M Carriage Return */
	    	con->x = 0;
	    	con->wrap = FALSE;
	    	break;
		case CHAR_ESC:  /* 0x1B */
	    	con->esc = EscStart;
	    	continue;
#if defined(__SCO__)
		case CHAR_CSI: /* case 128+27:  0x9B  Esc->SQUARE */
			con->esc = EscBracket;
			break;
#endif
		case CHAR_SO:  /* 0x0E  ^N Shift Out  using G1 charset (charset=1) */
	    	con->trans = con->g[1] | G1_SET;
	    	continue;
		case CHAR_SI:  /* 0x0F  ^O Shift In using G0 charset  */
	    	con->trans = con->g[0];
	    	continue;

		default:
#if defined(__SCO__)   /* Rui He Jan 18, 2004 added for SCO's table line stuff */
			if (con->charfont == 2)   /* toggle_meta, turn on bit 7 before display  */
			{
#if defined(__SCOUnixWare__)

				static unsigned char ISO8859ToCP437Map[] =
				{ 217, 191, 218, 192, 197, 32, 32, 196, 32, 32, 195, 180, 193, 194, 179};

				ch |= 0x80;
				if (ch >= 139 && ch <= 153) ch = ISO8859ToCP437Map[ch - 139];
#else  /* otherwise __SCOOpenServer__ */
				ch |= 0x80;				
#endif		   
			}
#endif

	    	if (con->x == con->xmax + 1) 
        	{
				con->wrap = TRUE;
				con->x --;
	    	}

	    	if (con->wrap) 
        	{
				con->x -= con->xmax;
				if (con->y == con->ymax) scroll ++;
				else con->y ++;
				con->wrap = FALSE;
				buff --;
				nchars ++;
				break;
	    	}

	    	if (con->knj1)  /* First Part of Hanzi in memory ? */
        	{

				if (con->knj1 & 0x80) 
            	{
            		switch(lInfo.sysCoding) 
                	{
		  			case CODE_EUC: /* CHAR_SS2 followed by a kata-kana(0xA0-DF) */
		    			if (con->knj1 == (u_char)CHAR_SS2)  /* CHAR_SS2    '\x8E' */
                    	{

							if (con->ins) TextInsertChar(con,1);
							TextSput(con,ch);
							con->x ++;
							con->knj1 = 0;
							continue;
		    			}
		    			break;
					case CODE_SJIS:
		    			sjistojis(con->knj1, ch);  /* always store JIS */
		    			break;
		  			}  /* case */
				}

            	if (con->ins) TextInsertChar(con,2);
            	TextWput(con,con->knj1, ch);
            	con->x += 2;
            	con->knj1 = 0;
            	continue;
        	} /* if knj1 */

        	else if ((con->charfont== 0) && (con->trans == CS_DBCS || 
					(iskanji_byte1(lInfo.sysCoding, ch) && con->trans == CS_LEFT)))
			{

				if (nchars > 0 && iskanji_byte2(lInfo.sysCoding, *buff))  /* added by Rui He Jul 3 2003, test the 2nd byte */
        		{
                	if (con->x == con->xmax) con->wrap = TRUE;  /* xmax is something like 79 */
                	con->knj1 = ch;
                	continue;
				}
				else  /* next one is not kanji ? */
				{
					if ( (nchars > 2) && (buff[0] == 0x0D) && (buff[1] == 0x0A) && 
							iskanji_byte2(lInfo.sysCoding, buff[2]))
						con->knj1 = ch;
					else
					{
						if (isPrevW1(con) && iskanji_byte2(lInfo.sysCoding, ch))  /* previous one is Kanji byte1, this one should be byte2? */
						{
							if (con->ins) TextInsertChar(con,1);
							TextWput2(con, ch);
						}
						else  /* output as the first char  */
						{	
							if (con->ins) TextInsertChar(con,1);
							TextWput1(con, ch);  /* Rui He Jul 9 2003, should we output LATCH_1 ?  */
						}
                		con->x++;
                		continue;
					}
				}
            } 
            else 
            {
                if (con->ins) TextInsertChar(con,1);
                TextSput(con,con->trans == CS_RIGHT ? ch | 0x80: ch);
                con->x++;
                continue;
            }

        }  /* switch  */

		if (scroll > 0) 
	    	ScrollUp(con, scroll);
		else if (scroll < 0)
	    	ScrollDown(con, - scroll);
		scroll = 0;

	}  /* while */
}

extern int CodingByRegistry(char *reg);
static int	ConfigCoding(const char *confstr)
{
    char reg[3][MAX_COLS];
    int n, i;

    *reg[0] = *reg[1] = *reg[2] = '\0';
    sscanf(confstr, "%255s %255s %255s", reg[0], reg[1], reg[2]);
    for (i = 0; i < 2 && *reg[i]; i ++) 
    {
		n = (int)CodingByRegistry(reg[i]);
		if (n < 0)   /* Rui He Jul 11, 2003 */
			fatal("Unrecognized coding registry %s\r\n", reg[i]); 
		else if (n & CHR_DBC)
	    	lInfo.db = n & ~CHR_DFLD;
		else
	    	lInfo.sb = n & ~CHR_SFLD;
    }

	if (OverrideSysCoding == -1)  /* read default settings from cce.cfg */
	{
		lInfo.sysCoding = CODE_GB;  /* default one */
		if (*reg[2]) /* Coding Exists */
		{
    		if (!strcasecmp(reg[i], "EUC"))
				lInfo.sysCoding = CODE_EUC;
    		else if (!strcasecmp(reg[i], "SJIS"))
				lInfo.sysCoding = CODE_SJIS;
    		else if (!strcasecmp(reg[i], "BIG5"))
				lInfo.sysCoding = CODE_BIG5;
        	else if (!strcasecmp(reg[i], "GB"))
            	lInfo.sysCoding = CODE_GB;
        	else if (!strcasecmp(reg[i], "GBK"))
            	lInfo.sysCoding = CODE_GBK;
   	    	else if (!strcasecmp(reg[i], "KSC"))
	  	    	lInfo.sysCoding = CODE_KSC;
		}
	}
	else lInfo.sysCoding = OverrideSysCoding;

	switch(lInfo.sysCoding)
	{
	case CODE_GB:
		DefineCap("InputMethodGB", ConfigInputMethod, NULL);
		break;
	case CODE_BIG5:
		DefineCap("InputMethodBig5", ConfigInputMethod, NULL);
		break;
	case CODE_GBK:
		DefineCap("InputMethodGBK", ConfigInputMethod, NULL);
		break;
	case CODE_EUC:
	case CODE_SJIS:
		DefineCap("InputMethodJIS", ConfigInputMethod, NULL);
		break;
	case CODE_KSC:
		DefineCap("InputMethodKSC", ConfigInputMethod, NULL);
		break;
	}

    return SUCCESS;
}

void	VtInit(void)
{

    DefineCap("Coding", ConfigCoding,
              "ISO8859-1 GB2312.1980-0 GB");
}

void	VtStart(ConInfo *con)
{

    con->x = con->y = 0;
    con->xmax = dispInfo.txmax-1;
    con->ymax = dispInfo.tymax-1;
    con->ymin = 0;   
    con->tab = 8;
	con->charfont = 0;

    con->fcol = DEF_FGCOLOR;
    con->bcol = DEF_BGCOLOR;
    con->attr = 0;
    con->esc = NULL;
    con->g[0] = con->g[1] = CS_LEFT;
    con->trans = con->soft = con->ins = con->wrap = FALSE;
    con->sb = lInfo.sb;
    con->db = lInfo.db|LATCH_1;
	
    con->knj1 = 0;
    cursorInfo.sw = TRUE;

    con->textBuff = (u_char *)calloc(dispInfo.txmax, dispInfo.tymax);
    con->attrBuff = (u_char *)calloc(dispInfo.txmax, dispInfo.tymax);
    con->flagBuff = (u_char *)calloc(dispInfo.txmax, dispInfo.tymax); 
	if (!con->textBuff || !con->attrBuff || !con->flagBuff)
		fatal("Failed to allocate new window buffer, textBuff=%p, attrBuff=%p, flagBuff=%p\n",
			con->textBuff, con->attrBuff, con->flagBuff);

    con->textSize = (dispInfo.txmax) * (dispInfo.tymax);

    con->currentScroll = con->scrollLine = 0;
    con->textHead = 0;

    con->textClear = FALSE;
    con->terminate = 0;
}

void VtCleanup(ConInfo *con)
{
    if (con == NULL) return;
    con->scrollLine = con->textHead = con->currentScroll = 0;
    
}
