#include    <stdlib.h>
#include    <ctype.h>
#include    "defs.h"

#define DMYKAN  0xFE
#define CRCHR   0x1F
#define TABCHR  0x09

extern void colset(UCHAR *vp,int cl,int cnt);
extern void PutChr();
extern void memcpy();
extern void memset();
extern void Dsp_vram();

       UCHAR   *cvram=NULL;
       int     MAX_SCR=MAX_Y;
       int     TrmCol=7;
       int     DspCnt=0;
static int     KanMod=TRUE;
static int     BakCh1=0,KanCod=0;
static int     ExtFlg=FALSE;
static void    (*ExtAdr)();
static int     EscCnt=0,Bak_X=0,Bak_Y=0;
static char    EscPrm[8];

void	Col_cnv()
{
    int   c;

    c = TrmCol & 0x07;
    if ( (TrmCol & 0x18) != 0 )
	c |= 0x10;
    if ( (TrmCol & 0x20) != 0 )
	c |= 0x08;
    TrmCol = c;
}
BOOL	Con_init()
{
    if ( cvram == NULL ) {
	if ( (cvram = (UCHAR *)malloc(MAX_X*MAX_Y*2)) == NULL )
	    return ERR;
        colset(cvram,TrmCol,MAX_X*MAX_Y*2);
        Cur_X = Cur_Y = 0;
    } else {
	Cur_X = Bak_X; Cur_Y = Bak_Y;
    }
    Dsp_vram(cvram);
    MAX_SCR = MAX_Y2;
    return FALSE;
}
void	Con_end()
{
    Bak_X = Cur_X; Bak_Y = Cur_Y;
    MAX_SCR = MAX_Y;
}
static void    NextChr(sub)
void     (*sub)();
{
    ExtFlg = TRUE;
    ExtAdr = sub;
}
static void    Scrool()
{
    memcpy(cvram,cvram + (MAX_X * 2),(MAX_X * 2) * (MAX_Y2 - 1));
    colset(cvram + (MAX_X * 2) * (MAX_Y2 - 1),TrmCol,(MAX_X * 2));
/**************
    Disp_Scrool(cvram,TrmCol);
**************/
}
static void    PutBS()
{
    if ( --Cur_X < 0 ) {
        Cur_X = MAX_X - 1;
        if ( --Cur_Y < 0 )
            Cur_Y = 0;
    }
}
static void    PutTAB()
{
    int     i;
    extern void    PutChr();

    i = ((Cur_X + TAB) / TAB) * TAB - Cur_X;

    if ( DspCnt > 1 && i-- > 0 )
	PutChr(0x20|(TrmCol-2),TABCHR);
    while ( i-- > 0 )
	PutChr(TrmCol,' ');
}
static void    PutLF()
{
    if ( ++Cur_Y >= MAX_Y2 ) {
	Cur_Y = (MAX_Y2 - 1);
	Scrool();
    }
}
static void    PutHOME()
{
    Cur_X = Cur_Y = 0;
}
static void    PutCLS()
{
    colset(cvram,TrmCol,(MAX_X * 2) * MAX_Y2);
    Cur_X = Cur_Y = 0;
}
static void    PutCR()
{
    extern void     PutChr();

    if ( DspCnt > 1 )
	PutChr(0x20|(TrmCol-2),CRCHR);
    Cur_X = 0;
}
static void    CurRit()
{
    if ( ++Cur_X >= MAX_X )
        Cur_X = 0;
}
static void    CurLft()
{
    if ( --Cur_X < 0 )
        Cur_X = MAX_X - 1;
}
static void    CurUp()
{
    if ( --Cur_Y < 0 )
        Cur_Y = MAX_Y2 - 1;
}
static void    CurDwn()
{
    if ( ++Cur_Y >= MAX_Y2 )
        Cur_Y = 0;
}
void    SVidAt(ch)
int     ch;
{
    TrmCol = ch & 0x3F;
    Col_cnv();
}
void    SetDC2_s(ch)
int     ch;
{
    Cur_X = BakCh1;
    Cur_Y = ch;
    if ( Cur_X < 0 ) Cur_X = 0;
    if ( Cur_X >= MAX_X ) Cur_X = MAX_X - 1;
    if ( Cur_Y < 0 ) Cur_Y = 0;
    if ( Cur_Y >= MAX_Y2 ) Cur_Y = MAX_Y2 - 1;
}
void    SetDC2(ch)
int     ch;
{
    extern void    SetDC2_s();

    BakCh1 = ch;
    NextChr(SetDC2_s);
}
void    SetDC3_s(ch)
int     ch;
{
    extern void    PutChr();

    while ( BakCh1-- > 0 )
        PutChr(0x20|TrmCol,ch);
}
void    SetDC3(ch)
int     ch;
{
    extern void    SetDC3_s();

    BakCh1 = ch;
    NextChr(SetDC3_s);
}
static void    EraLin()
{
    colset(cvram + (Cur_X * 2) + (MAX_X * 2) * Cur_Y,TrmCol,(MAX_X - Cur_X) * 2);
}
static void    EraScr()
{
    colset(cvram + (Cur_X * 2) + (MAX_X * 2) * Cur_Y,TrmCol,
	    (MAX_X * 2) * MAX_Y2 - ((Cur_X * 2) + (MAX_X * 2) * Cur_Y));
}
static void    InsLin()
{
    int     i;
    UCHAR   *p;

    p = cvram + (MAX_X * 2) * (MAX_Y2 - 1);
    for ( i = MAX_Y2 - 1 ; i > Cur_Y ; i-- ) {
        memcpy(p,p-(MAX_X * 2),(MAX_X * 2));
        p -= (MAX_X * 2);
    }
    colset(cvram + (MAX_X * 2) * Cur_Y,TrmCol,MAX_X * 2);
}
static void    DelLin()
{
    int     i;
    UCHAR   *p;

    p = cvram + (MAX_X * 2) * Cur_Y;
    for ( i = Cur_Y ; i < (MAX_Y2 - 1) ; i ++ ) {
        memcpy(p,p+(MAX_X * 2),(MAX_X * 2));
        p += (MAX_X * 2);
    }
    colset(cvram + (MAX_X * 2) * (MAX_Y2 - 1),TrmCol,MAX_X * 2);
}
void    SCurPs_s(ch)
int     ch;
{
    Cur_Y = BakCh1 - ' ';
    Cur_X = ch - ' ';
    if ( Cur_X < 0 ) Cur_X = 0;
    if ( Cur_X >= MAX_X ) Cur_X = MAX_X - 1;
    if ( Cur_Y < 0 ) Cur_Y = 0;
    if ( Cur_Y >= MAX_Y2 ) Cur_Y = MAX_Y2 - 1;
}
void    SCurPs(ch)
int     ch;
{
    extern void    SCurPs_s();

    BakCh1 = ch;
    NextChr(SCurPs_s);
}
void	CurAtt_s()
{
}
void	CurAtt(ch)
int	ch;
{
    extern void    CurAtt_s();

    NextChr(CurAtt_s);
}
static void    AnsiH()
{
    if ( EscPrm[0] > 0 ) EscPrm[0]--;
    if ( EscPrm[1] > 0 ) EscPrm[1]--;
    Cur_Y = EscPrm[0];
    Cur_X = EscPrm[1];
    if ( Cur_X < 0 ) Cur_X = 0;
    if ( Cur_X >= MAX_X ) Cur_X = MAX_X - 1;
    if ( Cur_Y < 0 ) Cur_Y = 0;
    if ( Cur_Y >= MAX_Y2 ) Cur_Y = MAX_Y2 - 1;
}
static void    AnsiA()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    if ( (Cur_Y -= EscPrm[0]) < 0 )
        Cur_Y = 0;
}
static void    AnsiB()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    if ( (Cur_Y += EscPrm[0]) >= MAX_Y2 )
        Cur_Y = MAX_Y2 - 1;
}
static void    AnsiC()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    if ( (Cur_X += EscPrm[0]) >= MAX_X )
        Cur_X = MAX_X - 1;
}
static void    AnsiD()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    if ( (Cur_X -= EscPrm[0]) < 0 )
        Cur_X = 0;
}
static void    Ansis()
{
    Bak_X = Cur_X;
    Bak_Y = Cur_Y;
}
static void    Ansiu()
{
    Cur_X = Bak_X;
    Cur_Y = Bak_Y;
}
static void    AnsiJ()
{
    switch(EscPrm[0]) {
        case 0: EraScr(); break;
        case 1: colset(cvram,TrmCol,(Cur_X * 2) + (MAX_X * 2) * Cur_Y); break;
        case 2: PutCLS(); break;
    }
}
static void    AnsiK()
{
    switch(EscPrm[0]) {
        case 0: EraLin(); break;
        case 1:
            if ( Cur_X > 0 )
		colset(cvram + (MAX_X * 2) * Cur_Y,TrmCol,Cur_X * 2);
            break;
        case 2: colset(cvram + (MAX_X * 2) * Cur_Y,TrmCol,MAX_X * 2); break;
    }
}
static void    AnsiM()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    while ( EscPrm[0]-- > 0 )
        DelLin();
    Cur_X = 0;
}
static void    AnsiL()
{
    if ( EscPrm[0] == 0 ) EscPrm[0] = 1;
    while ( EscPrm[0]-- > 0 )
        InsLin();
    Cur_X = 0;
}
static void    Ansim()
{
    int     c=7;
    int     i,n;
    static char ansiatt[]={ 0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x08,0x00 };
    static char ansicol[]={ 0,2,4,6,1,3,5,7 };
 
    for ( n = 0 ; n < EscCnt ; n++ ) {
        if ( (i = EscPrm[n]) >= 1 && i <= 7 ) {
            c |= ansiatt[i];
	} else if ( i == 0 ) {
	    c = 7;
        } else if ( i >= 30 && i <= 38 ) {
            c &= 0xF8;
            c |= ansicol[i-30];
        } else if ( i >= 40 && i <= 47 ) {
            c &= 0xF8;
            c |= ansicol[i-40];
            c |= 0x10;
        }
    }
    TrmCol = c;
}
void    AnsiCom(ch)
int     ch;
{
    if ( ch == ';' && EscCnt < 8 )
        EscCnt++;
    else if ( ch >= '0' && ch <= '9' )
        EscPrm[EscCnt] = EscPrm[EscCnt] * 10 + (ch - '0');
    else if ( ch != ' ' ) {
        EscCnt++;
        switch(ch) {
            case 'H': AnsiH(); break;
            case 'f': AnsiH(); break;
            case 'A': AnsiA(); break;
            case 'B': AnsiB(); break;
            case 'C': AnsiC(); break;
            case 'D': AnsiD(); break;
            case 's': Ansis(); break;
            case 'u': Ansiu(); break;
            case 'J': AnsiJ(); break;
            case 'K': AnsiK(); break;
            case 'm': Ansim(); break;
            case 'M': AnsiM(); break;
            case 'L': AnsiL(); break;
        }
        return;
    }
    NextChr(AnsiCom);
}
static void    AnsiESC()
{
    extern void    AnsiCom();

    memset(EscPrm,0,8);
    EscCnt = 0;
    NextChr(AnsiCom);
}
static	void	ShtKan(int ch)
{
}
static	void	UnShtKan(int ch)
{
}
void    EscCom(ch)
int     ch;
{
    extern void    SCurPs(),SVidAt(),CurAtt();

    switch(ch) {
        case '*': PutCLS(); break;
        case 'T': EraLin(); break;
        case 'Y': EraScr(); break;
        case 'E': InsLin(); break;
        case 'R': DelLin(); break;
        case '=': NextChr(SCurPs); break;
        case 'G': NextChr(SVidAt); break;
        case 'K': KanMod = TRUE; break;
        case 'C': KanMod = FALSE; break;
	case '.': NextChr(CurAtt); break;
        case '[': AnsiESC(); break;
	case '$': NextChr(ShtKan); break;
	case '(': NextChr(UnShtKan); break;
        default: PutChr(TrmCol|0x20,ch); break;
    }
}
static void    PutCnt(ch)
int     ch;
{
    extern void    SetDC2(),SetDC3(),EscCom();

    if ( DspCnt != 0 ) {
	switch(ch) {
	    case 0x08: PutBS(); break;
            case 0x09: PutTAB(); break;
	    case 0x0A: PutLF(); break;
	    case 0x0D: PutCR(); break;
	    default: 
		if ( DspCnt > 1 )
		    PutChr(TrmCol|0x20,ch);
		break;
	}
	return;
    }
    switch(ch) {
        case 0x08: PutBS(); break;
        case 0x09: PutTAB(); break;
	case 0x0A: PutLF(); break;
        case 0x0B: PutHOME(); break;
	case 0x0C: PutCLS(); break;
        case 0x0D: PutCR(); break;

	case 0x12: NextChr(SetDC2); break;
        case 0x13: NextChr(SetDC3); break;
        case 0x15: PutCLS(); break;
	case 0x16: PutCLS(); break;

	case 0x1B: NextChr(EscCom); break;

	case 0x1C: CurRit(); break;
        case 0x1D: CurLft(); break;
        case 0x1E: CurUp(); break;
        case 0x1F: CurDwn(); break;

        default:
	    if ( DspCnt > 1 )
		PutChr(TrmCol|0x20,ch);
	    break;
    }
}
void    PutChr(att,ch)
int     att,ch;
{
    UCHAR   *p;

    if ( (att & 0x20) == 0 ) {
	if ( ch < ' ' || ch == 0x7f ) {
	    PutCnt(ch);
	    return;
	}
    }

    if ( ch == '\0' )
	return;

    p = cvram + Cur_X * 2 + (MAX_X * 2) * Cur_Y;
    *(p++) = (att & 0xDF); *p = ch;

    if ( ++Cur_X >= MAX_X ) {
        Cur_X = 0;
	if ( ++Cur_Y >= MAX_Y2 ) {
            Cur_Y = MAX_Y2 - 1;
            Scrool();
        }
    }
}
void    BakPut(ch)
int     ch;
{
    ch &= 0xff;

    if ( ExtFlg != FALSE ) {
	ExtFlg = FALSE;
	(*ExtAdr)(ch);
        return;
    }

    if ( KanMod != FALSE ) {
        if ( KanCod != '\0' ) {
            if ( iskanji2(ch) != FALSE ) {
		if ( Cur_X == (MAX_X - 1) ) {
                    PutChr(TrmCol,DMYKAN);
                    PutChr(TrmCol,DMYKAN);
		} else {
#ifdef	TOWNS
		    PutChr(0x40|TrmCol,KanCod);
                    PutChr(0x80|TrmCol,ch);
#else
		    ch = sjistojis((KanCod << 8) | ch);
		    PutChr(0x40|TrmCol,ch >> 8);
                    PutChr(0x80|TrmCol,ch & 0xff);
#endif
                }
            } else {
		PutChr(TrmCol,KanCod);
		PutChr(TrmCol,ch);
	    }
            KanCod = '\0';
	    return;
        } else if ( iskanji(ch) != FALSE ) {
	    KanCod = ch;
            return;
        }
    }
    PutChr(TrmCol,ch);
}
void    BakStr(str)
char    *str;
{
    while ( *str != '\0' )
	BakPut(*(str++));
}
