/*
.index remote.c
 */
/****************************************************
 * vt100 emulator - remote character interpretation
 *
 *           Oct 86 TAW - added tek 4010 emulation and did some
 *                      - minor bug fixes, I use Move/Draw instead of
 *                      - RectFill, added the box to the extened character 
 *			  set
 *           860823 DBW - Integrated and rewrote lots of code
 *      v2.0 860803 DRB - Rewrote the control sequence parser
 *      v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
 *      v1.0 860712 DBW - First version released
 *
 ****************************************************/

#include "vt100.h"

static int    p [10];
static int    numpar;
static char   escseq[40];

void doctrl ();
void doesc ();                           /* force correct denomination */
void doerase ();
void doindex ();
/*
.page.index doremote
 */
/************************************************
*  function to handle remote characters
*************************************************/
void 
doremote (c)
char c;
    {
    if (Tek (c)) 
	return;
    if (inesc >= 0) 
	{ 
	doesc (c); 
	return; 
	}
    if (inctrl >= 0) 
	{ 
	doctrl (c); 
	return; 
	}

    switch (c) 
	{
    case 15:
        alt = 0;
	break;
    case 14:
        alt = 1;
        break;
    case '\t':
	x += 64 - ((x-MINX) % 64);
        break;
    case 10:  /* lf */
    case 11:
    case 12:
        if (nlmode) 
	    doindex ('E');
	else 
	    doindex ('D');
        break;
    case 13:  /* cr */
        if (!nlmode) 
	    x = MINX;
        break;
    case 8:   /* backspace */
        x -= 8;
        if (x < MINX) 
	    x = MINX;
        break;

    case 7:     /* bell */
        DisplayBeep (NULL);
        break;
    case 27:
        inesc = 0;
        break;
    default:
        if (c < ' ' || c > '~') 
	    return;
        if (a[alt] && c > '`')
	    doalt (c);
        else
	    emitbatch (1,&c);
        } /* end of switch */
    }/* end doremote */
/*
.page.index doesc
 */
void 
doesc (c)
char c;
{
    if (inesc < 0) 
	{ 
	inesc = 0; 
	return; 
	}
    if (c == 27 || c == 24) 
	{ inesc = -1; 
	return; 
	}

    if (c < ' ' || c == 127)	/* Ignore control chars */
	return;              

    if (c < '0') 		/* Collect intermediates */
	{
	escseq [inesc++] = c; 
	return; 
	}  

    /* by process of elimination, we have a final character.  Put it in
       the buffer, and dispatch on the first character in the buffer */

    escseq [inesc] = c;
    inesc = -1;                         /* No longer collecting a sequence */
    switch (escseq[0])                  /* Dispatch on the first received */
        {
    case '[':                           /* Control sequence introducer */
        numpar = 0;                     /* No parameters yet */
        private = 0;                    /* Not a private sequence (yet?) */
        badseq = 0;                     /* Good until proven bad */
        p[0] = p[1] = 0;                /* But default the first parameter */
        inctrl = 0;                     /* We are in a control sequence */
        return;                         /* All done for now ... */
    case 'D': case 'E': case 'M':       /* Some kind of index */
        doindex (c);                    /* Do the index */
        return;                         /* Return */
    case '7':                           /* Save cursor position */
        savx = x; savy = y; savmode = curmode; savalt = alt;
        sa[0] = a[0]; sa[1] = a[1];
        return;
    case '8':                         /* Restore cursor position */
        x = savx; y = savy; alt = savalt; curmode = savmode;
        a[0] = sa[0]; a[1] = sa[1];
        return;
    case 'c':                         /* Reset */
        top = MINY; bot = MAXY; savx = MINX; savy = MINY;
        a[0] = 0; a[1] = 0; sa[0] = 0; sa[1] = 0;
        emit(12); 
	inesc = -1;
        return;
    case '(':                         /* Change character set */
        if (c == '0' || c == '2') 
	    a[0] = 1; 
	else 
	    a[0] = 0;
        return;
    case ')':                         /* Change the other character set */
        if (c == '0' || c == '2') 
	    a[1] = 1; 
	else 
	    a[1] = 0;
        return;
    /* If we didn't match anything, we can just return, happy in the
     * knowledge that we've at least eaten the whole sequence */
        }/* end switch */
    return;
}/* end doesc */

/*
.page.index doctrl
 */
void 
doctrl (c)
char c;
{
    int     i;

    if (c == 27 || c == 24) 
	{ 
	inctrl = -1; 
	return; 
	}
    if (c < ' ' || c == 127) 		/* Ignore control chars */
	return;              

    /* First, look for some parameter characters.  If the very first
     * parameter character isn't a digit, then we have a private sequence */

    if (c >= '0' && c < '@')
	{
        /* can't have parameters after intermediates */
        if (inctrl > 0) 
	    {
	    badseq++; 
            return; 
	    }
        switch (c)
            {
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            p[numpar] = p[numpar] * 10 + (c - '0');
            return;

        case ';':
            p[++numpar] = 0;            /* Start a new parameter */
            return;

        case '<': case '=': case '>': case '?': /* Can only mean private */
            if (inctrl = 0) private = c; /* Only allowed BEFORE parameters */
            return;

        /* if we come here, it's a bad sequence */
            }
        badseq++;                       /* Flag the bad sequence */
        }

    if (c < '0')                        /* Intermediate character */
	{
        escseq[inctrl++] = c;           /* Save the intermediate character */
        return;
	}

    /* if we get here, we have the final character.  Put it in the 
       escape sequence buffer, then dispatch the control sequence */
    numpar++;                           /* Reflect the real number of parameters */
    escseq[inctrl++] = c;               /* Store the final character */
    escseq[inctrl] = '\000';            /* Tie off the buffer */
    inctrl = -1;                        /* End of the control sequence scan */

    /* Don't know how to do any private sequences right now, 
     * so just punt them */
    if (private != 0 || badseq != 0) 
	return;

    switch (escseq[0])                  /* Dispatch on first intermediate or final */
        {
    case 'A': 
	if (p[0]<=0) 
	    p[0] = 1;
	y -= 8*p[0]; 
	if (y<top)  
	    y = top;  
	return;
    case 'B': 
	if (p[0]<=0) 
	    p[0] = 1;                
	y += 8*p[0]; 
	if (y>bot)  
	    y = bot;  
	return;
    case 'C': 
	if (p[0]<=0) 
	    p[0] = 1;        
	x += 8*p[0]; 
	if (x>MAXX) 
	    x = MAXX; 
	return;
    case 'D': 
	if (p[0]<=0) 
	    p[0] = 1;  
	x -= 8*p[0]; 
	if (x<MINX) 
	    x = MINX; 
	return;
    case 'H': case 'f':               /* Cursor position */
        if (p[0] <= 0) 
	    p[0] = 1;
        if (p[1] <= 0) 
	    p[1] = 1;
        y = (--p[0]*8)+MINY; 
	x = (--p[1]*8)+MINX;
        if (y > MAXY) 
	    y = MAXY;
        if (x > MAXX) 
	    x = MAXX;
        if (y < MINY) 
	    y = MINY;
        if (x < MINX) 
	    x = MINX;
        return;
    case 'r':                         /* Set scroll region */
        if (p[0] <= 0) 
	    p[0] = 1;
        if (p[1] <= 0) 
	    p[1] = p_lines;
        top = (--p[0]*8)+MINY; 
	bot = (--p[1]*8)+MINY;
        if (top < MINY) 
	    top = MINY;
        if (bot > MAXY) 
            bot = MAXY;
        if (top > bot) 
	    { 
	    top = MINY; 
	    bot = MAXY; 
	    }
        x = MINX; 
	y = MINY;
        return;
    case 'm':                         /* Set graphic rendition */
        for (i=0; i<numpar; i++) 
	    {
            if (p[i] < 0) 
		p[i] = 0;
            switch (p[i]) 
		{
            case 0:
                curmode  = 0;
                break;

            case 1:
            case 5:
                if (p_depth > 1)    
		    curmode |= BOLD;
                else
                    curmode |= REVERSE;
                break;

            case 4:
                curmode |= UNDERLINE;
                break;

            default:
                curmode |= REVERSE;
                break;
                }
            }
        return;

    case 'K':                         /* Erase in line */
        doerase ();
        return;

    case 'J':                         /* Erase in display */
        if (p[0] < 0) 
	    p[0] = 0;
        SetAPen (mywindow->RPort,0L);
        if (p[0] == 0) 
	    {
            if (y < MAXY) 
		RectFill (mywindow->RPort,
                       (long)MINX,(long)(y+2),(long)(MAXX+7),(long)(MAXY+1));
            }
        else if (p[0] == 1) 
	    {
            if (y > MINY) 
		RectFill (mywindow->RPort,
                       (long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(y-7));
            }
        else 
	    RectFill (mywindow->RPort,
                    (long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
        SetAPen (mywindow->RPort,1L);
        doerase (); 
	return;

    case 'h':                         /* Set parameter */
        if (p[0] == 20) 
	    nlmode = 1;
        return;

    case 'l':                         /* Reset parameter */
        if (p[0] == 20) 
	    nlmode = 0;
        return;

    case 'x':
        sendchar (27); 
	sendstring ("[3;1;8;64;64;1;0x"); 
	return;

    case 'n':
        if (p[0] == 6) {
            sendchar (27);
            sprintf (escseq,"[%d;%dR",((y-MINY)/8)+1,((x-MINX)/8)+1);
            sendstring (escseq); 
	    return;
            }
        sendchar (27); 
	sendstring ("[0n"); 
	return;

    case 'c':
        sendchar (27); 
	sendstring ("[?1;0c"); 
	return;
    }

    /* Don't know how to do this one, so punt it */
}/* end doctrl */
/*
.page.index doindex
 */
void 
doindex (c)
char c;
    {
    if (c != 'M') 
	{
        if (c == 'E') 
	     x = MINX;
        if (y > bot) 
	    if (y < MAXY) 
		y += 8;
        if (y == bot)
            ScrollRaster (mywindow->RPort,0L,8L,(long)MINX,(long)(top-6),
                                               (long)(MAXX+7),(long)(bot+1));
        if (y < bot) 
	    y += 8;
        }
    else 
	{
        if (y < top) 
	    if (y > MINY) 
		y -= 8;
        if (y == top)
            ScrollRaster (mywindow->RPort,0L,-8L,(long)MINX,(long)(top-6),
                                               (long)(MAXX+7),(long)(bot+1));
        if (y > top) 
	    y -= 8;
        }
    return;
    }/* end doindex */
/*
.page.index doalt
 */
doalt (c)
char c;
    {
    int oldx, newx;
    inesc = -1;
    oldx = x; emit (' '); 
    newx = x;
    x = oldx;
    SetAPen (mywindow->RPort,1L);
    switch (c) 
	{
    case 'a':
	c = 127;
	emitbatch (1, &c);
	break;
    case 'j':
    case 'm':
    case 'v':   
	doline (4,-8,4,-4);
        if  (c=='j')  
	    doline (0,-4,4,-4);
        else if (c=='m')  
	    doline (4,-4,8,-4);
        else
            doline (0,-4,8,-4);
        break;
    case 'k':
    case 'l':
    case 'w': 
	doline (4,-4,4,0);
        if (c=='k')
	    doline(0,-4,4,-4);
        else if (c=='l')  
	    doline (4,-4,8,-4);
        else              
	    doline (0,-4,8,-4);
        break;
    case 'n':
    case 'q': 
	doline (0,-4,8,-4);
        if (c=='n')  
	    doline (4,-8,4,0);
        break;
    case 't':
    case 'u':
    case 'x':   
	doline (4,-8,4,0);
        if (c=='t')  
	    doline (4,-4,8,-4);
        else if (c=='u')  
	    doline (0,-4,4,-4);
        break;
    }
    x = newx;
    }/* end doalt */
/*
.index doline
 */
doline (x1,y1,x2,y2) 
    {
    Move (mywindow->RPort, x+x1, y+y1);
    Draw (mywindow->RPort, x+x2, y+y2);
    }
/*
.index doerase
 */
void doerase ()
    {
    if (p[0] < 0) 
	p[0] = 0;
    SetAPen (mywindow->RPort,0L);
    if (p[0] == 0) 
	RectFill (mywindow->RPort,(long)x,(long)(y-6),
                                                 (long)(MAXX+7),(long)(y+1));
    else if (p[0] == 1)
	RectFill (mywindow->RPort,
                             (long)MINX,(long)(y-6),(long)(x+7),(long)(y+1));
    else 
	RectFill (mywindow->RPort,
                          (long)MINX,(long)(y-6),(long)(MAXX+7),(long)(y+1));
    SetAPen (mywindow->RPort,1L);
    return;
    }/* end doerase */

