/* By Frank on June 20 - Add parity to all outbound chars using software */
/*  Also, ignore DEL (0177) characters on input. */
/* By Bill on May 29 - Add Key set translation */
/* By WBC3 on Apr 24 - Add ^^, ^@ and ^_.  Also use Pascal strings for */
/*  output in the terminal emulator */
/* By WBC3 on Apr 23 - Add query terminal and be more fastidious about */
/*  ignoring sequences we don't know about */
/* By WBC3 on Apr 22 - Fix tab stops to conform to the rest of the world! */
/* By Bill on Apr 21 - Fix immediate echo problems. */
/*  do less cursor_erase, cursor_draw stuff */

/*
 * FILE ckmcon.c
 *
 * Module of mackermit: contains code for the terminal simulation
 * routine.
 */

#include "ckmdef.h"
#include "mac/quickdraw.h"		/* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "ckmkkc.h"			/* common key configure defs */

#define MAXLIN	    24
#define MAXCOL	    80
#define LINEHEIGHT  12
#define CHARWIDTH    6
#define TOPMARGIN    3	    		/* Terminal display constants */
#define BOTTOMMARGIN (LINEHEIGHT * MAXLIN + TOPMARGIN)
#define LEFTMARGIN   3
#define RIGHTMARGIN  (CHARWIDTH * MAXCOL + LEFTMARGIN)
#define LINEADJ	     3			/* Amount of char below base line */

/* output character handling */

unsigned char obuf[2] = {1,0};		/* single char output buffer */

/* Tab settings */

#define NUMTABS 9

short tabstops[NUMTABS] = {8,16,24,32,40,48,56,64,72};

int invert=FALSE,			/* Flag for inverted terminal mode */
    insert=FALSE,
    topmargin=TOPMARGIN,		/* Edges of adjustable window */
    bottommargin=BOTTOMMARGIN,
    textstyle=0,
    autowrap=TRUE;			/* Autowrap on by default */

char *querystring="\033[?6c";		/* Answer we are a VT102 */

short scrollrect[] = { TOPMARGIN, LEFTMARGIN, BOTTOMMARGIN, RIGHTMARGIN };

RgnHandle dumptr;	    		/* Dummy ptr to satisfy scrollbits */

/* Screen book keeping variables */

char scr[MAXLIN][MAXCOL+1];		/* Characters on the screen */
short nxtlin[MAXLIN], toplin, botlin;	/* Linked list of lines */
int curlin, curcol, abslin;		/* Cursor position */
int savcol, savlin;			/* Cursor save variables */
int scrtop, scrbot;			/* Absolute scrolling region bounds */

/* Stuff for escape character processing */

#define CF_OUTC 0			/* Just output the char */
#define CF_SESC	1			/* In a single char escape seq */
#define CF_MESC	2			/* In a multi char '[' escape seq */
#define CF_TOSS	3			/* Toss this char */

char prvchr, numone[6], numtwo[6], *numptr;
int num1, num2, charflg=CF_OUTC;

extern CSParam controlparam;

extern unsigned char dopar();

typedef int (*PFI) ();

/* Terminal function declarations. */

int tab(), back_space(), carriage_return(), line_feed(), bell(), escape_seq(),
    text_mode(), clear_line(), erase_display(), cursor_position(), cursor_up(),
    cursor_down(), cursor_right(), cursor_left(), cursor_save(),
    cursor_restore(), set_scroll_region(), reverse_line_feed(), dummy(),
    delete_char(), insert_mode(), end_insert_mode(), insert_line(),
    delete_line(), query_terminal(), multi_char(), toss_char();

/* Terminal control character function command table. */

#define MINSINGCMDS 000
#define MAXSINGCMDS 037

PFI controltable[MAXSINGCMDS-MINSINGCMDS+1] =
{
    dummy,				/*  0 */
    dummy,				/*  1 */
    dummy,				/*  2 */
    dummy,				/*  3 */
    dummy,				/*  4 */
    dummy,				/*  5 */
    dummy,				/*  6 */
    bell,				/*  7 */
    back_space,				/* 10 */
    tab,				/* 11 */
    line_feed,				/* 12 */
    line_feed,				/* 13 (Vertical tab) */
    line_feed,				/* 14 (Form feed) */
    carriage_return,			/* 15 */
    dummy,				/* 16 */
    dummy,				/* 17 */
    dummy,				/* 20 */
    dummy,				/* 21 */
    dummy,				/* 22 */
    dummy,				/* 23 */
    dummy,				/* 24 */
    dummy,				/* 25 */
    dummy,				/* 26 */
    dummy,				/* 27 */
    dummy,				/* 30 */
    dummy,				/* 31 */
    dummy,				/* 32 */
    escape_seq,				/* 33 (Escape) */
    dummy,				/* 34 */
    dummy,				/* 35 */
    dummy,				/* 36 */
    dummy				/* 37 */
};

#define MINSINGESCS 0040
#define MAXSINGESCS 0137

PFI singescapetable[MAXSINGESCS-MINSINGESCS+1] =
{ 
    dummy,				/*  40 */
    dummy,				/*  41 */
    dummy,				/*  42 */
    toss_char,				/*  43 '#' */
    dummy,				/*  44 */
    dummy,				/*  45 */
    dummy,				/*  46 */
    dummy,				/*  47 */
    toss_char,				/*  50 '(' */
    toss_char,				/*  51 ')' */
    dummy,				/*  52 */
    dummy,				/*  53 */
    dummy,				/*  54 */
    dummy,				/*  55 */
    dummy,				/*  56 */
    dummy,				/*  57 */
    dummy,				/*  60 */
    dummy,				/*  61 */
    dummy,				/*  62 */
    dummy,				/*  63 */
    dummy,				/*  64 */
    dummy,				/*  65 */
    dummy,				/*  66 */
    cursor_save,			/*  67 '7' */
    cursor_restore,			/*  70 '8' */
    dummy,				/*  71 */
    dummy,				/*  72 */
    dummy,				/*  73 */
    dummy,				/*  74 '<' */
    dummy,				/*  75 '=' */
    dummy,				/*  76 '>' */
    dummy,				/*  77 */
    dummy,				/* 100 */
    dummy,				/* 101 */
    dummy,				/* 102 */
    dummy,				/* 103 */
    line_feed,				/* 104 'D' */
    dummy,				/* 105 'E' */
    dummy,				/* 106 */
    dummy,				/* 107 */
    dummy,				/* 110 */
    dummy,				/* 111 */
    dummy,				/* 112 */
    dummy,				/* 113 */
    dummy,				/* 114 */
    reverse_line_feed,			/* 115 'M' */
    dummy,				/* 116 */
    dummy,				/* 117 */
    dummy,				/* 120 */
    dummy,				/* 121 */
    dummy,				/* 122 */
    dummy,				/* 123 */
    dummy,				/* 124 */
    dummy,				/* 125 */
    dummy,				/* 126 */
    dummy,				/* 127 */
    dummy,				/* 130 */
    dummy,				/* 131 */
    query_terminal,			/* 132 'Z' */
    multi_char,				/* 133 '[' */
    dummy,				/* 134 */
    dummy,				/* 135 */
    dummy,				/* 136 */
    dummy				/* 137 */
};

/* Terminal escape sequence function command table */

#define MINMULTESCS 0100
#define MAXMULTESCS 0177

PFI escapetable[MAXMULTESCS-MINMULTESCS+1] =
{
    dummy,				/* 100 */
    cursor_up,				/* 101 'A' */
    cursor_down,			/* 102 'B' */
    cursor_right,			/* 103 'C' */
    cursor_left,			/* 104 'D' */
    dummy,				/* 105 */
    dummy,				/* 106 */
    dummy,				/* 107 */
    cursor_position,			/* 110 'H' */
    dummy,				/* 111 */
    erase_display,			/* 112 'J' */
    clear_line,				/* 113 'K' */
    insert_line,			/* 114 'L' */
    delete_line,			/* 115 'M' */
    dummy,				/* 116 */
    dummy,				/* 117 */
    delete_char,			/* 120 'P' */
    dummy,				/* 121 */
    dummy,				/* 122 */
    dummy,				/* 123 */
    dummy,				/* 124 */
    dummy,				/* 125 */
    dummy,				/* 126 */
    dummy,				/* 127 */
    dummy,				/* 130 */
    dummy,				/* 131 */
    dummy,				/* 132 */
    dummy,				/* 133 */
    dummy,				/* 134 */
    dummy,				/* 135 */
    dummy,				/* 136 */
    dummy,				/* 137 */
    dummy,				/* 140 */
    dummy,				/* 141 */
    dummy,				/* 142 */
    query_terminal,			/* 143 'c' */
    dummy,				/* 144 */
    dummy,				/* 145 */
    cursor_position,			/* 146 'f' */
    dummy,				/* 147 */
    insert_mode,			/* 150 'h' */
    dummy,				/* 151 */
    dummy,				/* 152 */
    dummy,				/* 153 */
    end_insert_mode,			/* 154 'l' */
    text_mode,				/* 155 'm' */
    dummy,				/* 156 */
    dummy,				/* 157 */
    dummy,				/* 160 */
    dummy,				/* 161 */
    set_scroll_region,			/* 162 'r'*/
    dummy,				/* 163 */
    dummy,				/* 164 */
    dummy,				/* 165 */
    dummy,				/* 166 */
    dummy,				/* 167 */
    dummy,				/* 170 */
    dummy,				/* 171 */
    dummy,				/* 172 */
    dummy,				/* 173 */
    dummy,				/* 174 */
    dummy,				/* 175 */
    dummy,				/* 176 */
    dummy				/* 177 */
};

/* Connect support routines */

consetup()
{

    dumptr = NewRgn();
    PenMode(patXor);
    flushio(); 				/* Get rid of pending characters */

    init_term();			/* Set up some terminal variables */
    clear_screen();			/* Clear the screen */
    home_cursor();			/* Go to the upper left */
    cursor_save();			/* Save this position */
}

/* Input and process all the characters pending on the tty line */

inpchars()
{
    int rdcnt;

    if ((rdcnt = ttchk()) == 0) return;	/* How many chars there?  Ret if 0 */
    cursor_erase();			/* remove cursor from screen */
    while (rdcnt-- > 0) printit(ttinc(0)); /* Output all those characters */
    flushbuf();				/* Flush any remaining characters */
    cursor_draw();			/* put it back */
}


/* writeps - write a pascal form string to the serial port.
 *
 */

writeps(s)
char *s;
{
  PLONG wcnt, w2;
  int err; char *s2;

  w2 = wcnt = *s++;			/* get count */
  for (s2 = s; w2 > 0; w2--,s2++)   	/* add parity */
    *s2 = dopar(*s2);
  err = FSWrite(outnum,&wcnt,s);	/* write the characters */
  if (err != noErr)
    printerr("Bad FSWrite in writeps: ",err);
  return;
  SYM(WRITEPS);    
}

/* getindstr - given an indirect (or is it indexed) string and integer
 *    	       n, return the pointer to the Nth substring.
 *
 * Indirect strings have the count of substrings in the first byte and
 * each string follows with a length byte and a body.
 *
 * Substrings are referenced by 1..N
 *
 */

char *getindstr(indstr,n)
char *indstr;
{
  register char *ip = indstr;
  int i;

  if (n > *ip++)			/* too large? */
   return("");				/* yes, return empty pascal string */

  for (i=1; i < n; i++)			/* scan until we hit the Nth */
   ip += (*ip)+1;			/* move to next substring */

  return(ip);				/* return ptr to it */
  SYM(GETINDSTR);
}

/* Process a character received from the keyboard */

handle_char(evt)
EventRecord *evt;
{
    int code,mods,cidx;
    register KSET *ks;
    unsigned char c;

    code = (evt->message & keyCodeMask) >> 8;
    mods = (evt->modifiers & MOD_MASK);

    cidx = (mods & shiftKey) ?		/* decide if shifted or */
      	    UC_IDX : LC_IDX;		/*  unshifted map */

    ks = *kshdl;			/* de-reference KSET handle */

    if (mods & ks->ctrlmods)		/* control? */
      c = ks->ctrlmap[cidx][code];	/* yes... use control map */
    else
      if (mods & ks->caplmods)		/* else caps lock? */
      	c = ks->caplmap[cidx][code];	/* yes, use that map */
     else
       c = ks->normmap[cidx][code];	/* otherwise use normal map */

    if (c & FKEYBIT) {			/* is this a function key? */
      c &= ~FKEYBIT;			/* clear function bit */
      switch (c) {			/* handle special functions */
	case SPFLBRK:			/* do long break */
	  sendbreak(70);		/* 70*50MS = 3.5 seconds */
	  break;
	case SPFSBRK:			/* do short break */
	  sendbreak(5);			/* 5*50MS = 0.25 seconds */
	  break;
	default:			/* do user defined function */
	 writeps(getindstr(*(ks->fcnshdl),(int) c+1));
	 break;
      }
      return;				/* all done */
    }

    if (mods & ks->metamods)		/* want to do meta? */
      if (ks->meta8bit)			/* yes, want 8 bit on? */
      	c |= METABIT;			/* so, turn it on */
      else
        writeps(*(ks->metahdl));	/* else send prefix */

    obuf[1] = c;			/* store character */
    writeps(obuf);			/* and write it out */

    if (duplex != 0)
    {
      cursor_erase();			/* remove from screen */
      printit((char) c);		/* Echo the char to the screen */
      flushbuf();			/* flush the character */
      cursor_draw();			/* put it back */
    }
    return;
    SYM(HANDLE_CHAR);
}

char outbuf[MAXCOL+1];
int outcnt=0, outcol;

flushbuf()
{
    Rect r;

    if (outcnt == 0) return;		/* Nothing to flush */

/* Erase a hole large enough for outcnt chars */

    makerect(&r,abslin,outcol,1,outcnt);

    if (invert) FillRect(&r,&QD->black);
	else EraseRect(&r);

    outbuf[outcnt] = '\0';		/* Terminate the string */
    DrawString(outbuf);			/* Output the string */
    outcnt = 0;				/* Say no more chars to output */
}

buf_char(c)
char c;
{
    if (outcnt == 0) outcol = curcol;	/* No chars in buffer, init column */
    outbuf[outcnt++] = c;		/* Put in the buffer to output later */
}

/*
 *  Printit:
 *	Draws character and updates buffer
 */
	
printit(c)
char c;
{
    PFI funp, lookup();

    c &= 0177;

    switch (charflg)
    {
	case CF_OUTC:			/* Just output the char */
	    MDrawChar(c);
	    break;

	case CF_SESC:			/* In a single char escape seq */
	    charflg = CF_OUTC;		/* Reset flag to simple outputting */
	    if(funp=lookup(c,singescapetable,MINSINGESCS,MAXSINGESCS))
	    	(*funp)();		/* Do escape sequence function */
	    break;

	case CF_MESC:			/* Multichar escape sequence */
	    if (c >= 0x20 && c < 0x40)  /* Deal with the modifiers */
	    {
		if (c >= '<' && c <= '?') prvchr = c;   /* Handle priv char */
		else if ((c >= '0' && c <= '9') || c == '-' || c == '+')
		{
		    *numptr++ = c;	/* Add the chat to the num */
		    *numptr = '\0';	/* Terminate the string */
		}
		else if (c == ';') numptr = numtwo;	/* Go to next number */
	    }
	    else			/* End of sequence */
	    {
		if (funp=lookup(c,escapetable,MINMULTESCS,MAXMULTESCS))
		{
		    StringToNum(numone,&num1); /* Translate the numbers */
		    StringToNum(numtwo,&num2);
		    (*funp)();		/* Do the escape sequence function */
		}
		charflg = CF_OUTC;	/* Back to simple outputting */
	    }
	    break;

	case CF_TOSS:			/* Ignore this char */
	    charflg = CF_OUTC;		/* Reset flag */
	    break;
    }
}

/*
 * Routine makerect
 *
 * Make a rectangle in r starting on line lin and column col extending
 * numlin lines and numcol characters.
 *
 */

makerect(r,lin,col,numlin,numcol)
Rect *r;
int lin, col, numlin, numcol;
{
    r->top = lin * LINEHEIGHT + TOPMARGIN;
    r->left = col * CHARWIDTH + LEFTMARGIN;
    r->bottom = r->top + numlin * LINEHEIGHT;
    r->right = r->left + numcol * CHARWIDTH;
}

/*
 *   Lookup:
 *	Lookup a given character in the apropriate character table, and
 *	return a pointer to the appropriate function, if it exists.
 */

PFI
lookup(index,table,min,max)
char index;
PFI table[];
int min, max;
{
    if (index > max || index < min)
    	return((PFI) NULL);    		/* Don't index out of range */
    return(table[index-min]);
}


/*
 *   Flushio:
 *	Initialize some communications constants, and clear screen and
 *	character buffers.
 */

flushio()
{
    int err;

    err = KillIO(-6);
    if (err) printerr("Bad input clear",err);
    err = KillIO(-7);
    if (err) printerr("Bad ouput clear",err);
}	

   
/* sendbreak - sends a break across the communictions line.
 *
 * The argument is in units of approximately 0.05 seconds (or 50
 * milliseconds).  To send a break of duration 250 milliseconds the
 * argument would be 5; a break of duration 3.5 seconds would be (umm,
 * lets see now) 70.
 *
 */

sendbreak(msunit)
{ 
    int finalticks;

/* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
    
    msunit = msunit*3;		

    Control(outnum,12,&controlparam);	/* Start marking */
/*    SerSetBrk(outnum);		/* start breaking */
    Delay(msunit,&finalticks);		/* delay */
/*    SerClrBrk(outnum);		/* stop breaking */
    Control(outnum,11,&controlparam);	/* Stop marking */

}
     
MDrawChar(chr)
char chr;
{
    PFI funp;

/* If it's a control char, do the apropriate function. */	

    if (chr < ' ')			/* Is it a control character */
    { 
	flushbuf();
	if (funp=lookup(chr,controltable,MINSINGCMDS,MAXSINGCMDS)) (*funp)();
    }
    else if (chr < 0177)  	    	/* Handle graphic characters */
    {
	if (curcol >= MAXCOL)		/* Are we about to wrap around? */
	{
	    if (autowrap)		/* If autowrap indicated wrap */
	    {
		flushbuf();
		carriage_return();
		line_feed();
	    }
	    else
	    {
		back_space();		/* Otherwise just overwrite */
		outcnt--;		/* Overwrite buffered chars too */
	    }
	}
	if (insert)			/* Insert mode? */
	{
	    insert_char();		/* Open hole for char if requested */
	    erase_char();		/* Erase the old char */
	    DrawChar(chr);
	}
	else buf_char(chr);		/* Otherwise just buffer the char */
	scr[curlin][curcol++] = chr;
    }
}	


/*
 *	Control character functions:
 *		Each of the following allow the mac to simulate
 *		the behavior of a terminal when given the proper
 *		control character.
 */

back_space()
{
    if (curcol > 0) relmove(-1,0);
}

erase_char()
{
    Rect r;

    scr[curlin][curcol] = ' ';		/* Erase char for update */
    makerect(&r,abslin,curcol,1,1);	/* One char by one line */

    if (invert) FillRect(&r,&QD->black);
	else EraseRect(&r);
}

tab()
{
    int i;

    for (i=0; i<NUMTABS; i++)
    {
    	if (tabstops[i] > curcol)
	{
	    absmove(tabstops[i],abslin);
	    return;
	}
    }
}

line_feed()
{
    int tbot, ttop, tlout;

    if (curlin == scrbot)
    {
	ScrollRect((Rect *) scrollrect,0,-LINEHEIGHT,dumptr);
	zeroline(scrtop);
	tbot = scrbot;
	ttop = scrtop;
	tlout = nxtlin[scrbot];
	nxtlin[scrbot] = scrtop;
	scrbot = scrtop;
	scrtop = nxtlin[scrtop];
	if (ttop == toplin) toplin = scrtop;
	    else nxtlin[fndprv(ttop)] = scrtop;
	if (tbot == botlin)
	{
	    botlin = scrbot;
	    nxtlin[botlin] = -1;
	}
	else nxtlin[scrbot] = tlout;
	curlin = scrbot;
    }
    else relmove(0,1);
}

reverse_line_feed()
{
    int tbot, ttop, tlout;

    if (curlin == scrtop)
    {
	ScrollRect((Rect *) scrollrect,0,LINEHEIGHT,dumptr);
	zeroline(scrbot);
	tbot = scrbot;
	ttop = scrtop;
	tlout = nxtlin[scrbot];
	nxtlin[scrbot] = scrtop;
	scrtop = scrbot;
	scrbot = fndprv(scrbot);
	if (ttop == toplin) toplin = scrtop;
	    else nxtlin[fndprv(ttop)] = scrtop;
	if (tbot == botlin)
	{
	    botlin = scrbot;
	    nxtlin[botlin] = -1;
	}
	else nxtlin[scrbot] = tlout;
	curlin = scrtop;
    }
    else relmove(0,-1);
}

carriage_return()
{
    absmove(0,abslin);
}

clear_screen()
{
    register int i;
    Rect r;

    makerect(&r,0,0,MAXLIN,MAXCOL);	/* The whole screen */
    EraseRect(&r);

    for (i=0; i<MAXLIN; i++) zeroline(i);   /* Clear up the update records */
}

home_cursor()
{
    absmove(0,0);
}

bell()
{
    SysBeep(3);
}

escape_seq()
{
    charflg = CF_SESC;			/* Say we are in an escape sequence */
}

clear_line()
{
    int i;
    Rect r;

    switch (num1)
    {
	case 0:				/* Clear:  here to the right */
	    makerect(&r,abslin,curcol,1,MAXCOL-curcol);
	    for (i=curcol; i<MAXCOL; i++) scr[curlin][i] = ' ';
	    break;

	case 1:				/* Clear:  left to here */
	    makerect(&r,abslin,0,1,curcol+1);
	    for (i=0; i<=curcol; i++) scr[curlin][i] = ' ';
	    break;

	case 2:				/* Clear:  entire line */
	    makerect(&r,abslin,0,1,MAXCOL);
	    zeroline(curlin);
	    break;
    }
    EraseRect(&r);
}

erase_display()
{
    int i;
    Rect r;

    switch (num1)
    {
	case 0:
	    clear_line();		/* Same num1 causes correct clear */
	    makerect(&r,abslin+1,0,MAXLIN-abslin,MAXCOL);
	    EraseRect(&r);
	    for (i=abslin+1; i<MAXLIN; i++) zeroline(fndrel(i));
	    break;

	case 1:
	    clear_line();		/* Same num1 causes correct clear */
	    makerect(&r,0,0,abslin,MAXCOL);
	    EraseRect(&r);
	    for (i=0; i<abslin; i++) zeroline(fndrel(i));
	    break;

	case 2:
	    clear_screen();
	    break;
    }
}
			
/**** All cursor moves need to check that they don't go beyond the margins */

cursor_right()
{
    if (num1 == 0) num1 = 1;
    relmove(num1,0);
}

cursor_left()
{
    if (num1 == 0) num1 = 1;
    relmove(-num1,0);
}

cursor_up()
{
    if (num1 == 0) num1 = 1;
    relmove(0,-num1);
}

cursor_down()
{
    if (num1 == 0) num1 = 1;
    relmove(0,num1);
}

cursor_position()
{
    if (--num1 < 0) num1 = 0;
    if (--num2 < 0) num2 = 0;

    absmove(num2,num1);
}

cursor_save()
{
    savcol = curcol;			/* Save the current line and column */
    savlin = abslin;
}

cursor_restore()
{
    absmove(savcol,savlin);		/* Move to the old cursor position */
}

cursor_draw()
{
    Line(CHARWIDTH,0);			/* Draw cursor */
}

cursor_erase()
{
    Line(-CHARWIDTH,0);			/* Erase cursor */
}

set_scroll_region()
{
    if (--num1 < 0) num1 = 0;		/* Make top of line (prev line) */
    if (num2 == 0) num2 = 24;		/* Zero means entire screen */

    topmargin = scrollrect[0] = (num1 * LINEHEIGHT) + TOPMARGIN;
    bottommargin = scrollrect[2] = (num2 * LINEHEIGHT) + TOPMARGIN;

    scrtop = fndrel(num1);
    scrbot = fndrel(num2-1);

    home_cursor();			/* We're supposed to home it! */
}


text_mode()				/**** */
{
    switch(num1)
    {
	case 0: 
	    invert=FALSE;
	    textstyle=0;
	    TextFace(0);
	    TextMode(srcOr);
	    break;

	case 1:
	    textstyle +=boldStyle;
	    TextFace(textstyle);
	    break;

	case 4:
	    textstyle+=underlineStyle;
	    TextFace(textstyle);
	    break;

	case 7:
	    invert=TRUE;
	    TextMode(srcBic);
	    break;

	case 22:
	    if (textstyle >= boldStyle)
	    {
		TextFace(textstyle-boldStyle);
		textstyle -= boldStyle;
	    }
	    break;

	case 24:
	    if (textstyle >= underlineStyle)
	    {
		TextFace(textstyle-underlineStyle);
		textstyle -= underlineStyle;
	    }
	    break;

	case 27:
	    invert = FALSE;
	    TextMode(srcOr);
	    break;
    }
}	

/**** NYI */
insert_line()
{
    Rect r;

    if (num1 == 0) num1 = 1;

    makerect(&r,abslin,0,0,MAXCOL);
    r.bottom = bottommargin;		/* Just do this for now */

    if (num1 > fndabs(scrbot) - abslin)
    	num1 = fndabs(scrbot) - abslin;

    ScrollRect(&r,0,num1*LINEHEIGHT,dumptr);
/* Do the book keeping!!! */
}

delete_line()
{
    Rect r;

    if (num1 == 0) num1 = 1;

    makerect(&r,abslin,0,0,MAXCOL);
    r.bottom = bottommargin;		/* Just do this for now */

    if (num1 > fndabs(scrbot) - abslin)
    	num1 = fndabs(scrbot) - abslin;

    ScrollRect(&r,0,-num1*LINEHEIGHT,dumptr);
/* Do the book keeping!!! */
}

delete_char()
{
    int i;
    Rect r;

    if (num1 == 0) num1 = 1;

    makerect(&r,abslin,curcol,1,MAXCOL-curcol);

    if(num1 > MAXCOL - curcol - 1) num1 = MAXCOL - curcol - 1;

    ScrollRect(&r,-CHARWIDTH*num1,0,dumptr);  /* Scroll em out */

/* Shift em down */

    for (i=curcol; i<MAXCOL-num1; i++) scr[abslin][i] = scr[abslin][i+num1];
    while (i < MAXCOL) scr[abslin][i++] = ' ';	/* Fill in holes with spaces */
}

insert_char()
{
    int i;
    Rect r;

    makerect(&r,abslin,curcol,1,MAXCOL-curcol);

    ScrollRect(&r,CHARWIDTH,0,dumptr);

/* Shift em up */

    for (i=MAXCOL-1; i>curcol+1; i--) scr[abslin][i-1] = scr[abslin][i];
    scr[abslin][curcol] = ' ';
}

insert_mode()
{
    if (prvchr == '?') return;		/* Don't deal with these calls */
    if (num1 == 4) insert = TRUE;
}

end_insert_mode()
{
    if (prvchr == '?') return;		/* Don't deal with these calls */
    if (num1 == 4) insert = FALSE;
}

query_terminal()
{
    PLONG wrcnt, w2;
    int err; char *s2;

    w2 = wrcnt = strlen(querystring);	/* How long is the string? */
    for (s2 = querystring; w2 > 0; w2--,s2++) /* add parity */
      *s2 = dopar(*s2);
    err = FSWrite(outnum,&wrcnt,querystring);	/* Respond to the query */
    if (err) printerr("Bad Writeout:",err);
}

dummy()
{
}

multi_char()
{
    numone[0] = numtwo[0] = '0';	/* Initialize the numbers to zero */
    numone[1] = numtwo[1] = '\0';
    numptr = numone;			/* Place to put the next number */
    prvchr = '\0';			/* No priv char yet */
    charflg = CF_MESC;			/* Say we are in a ESC [ swequence */
}

toss_char()
{
    charflg = CF_TOSS;
}

/*
 * Routine zeroline
 *
 * Zero (set to space) all the characters in relative line lin.
 *
 */

zeroline(lin)
int lin;
{
    register int i;

    for (i=0; i<MAXCOL; i++) scr[lin][i] = ' ';
}

/*
 * Move a relative number of lines and chars.  Both can be negative.
 *
 */

relmove(hor,ver)
{
    Move(hor*CHARWIDTH,ver*LINEHEIGHT);
    curcol += hor;
    abslin += ver;
    curlin = fndrel(abslin);
}

/*
 * Move to absolute position hor char and ver line.
 *
 */

absmove(hor,ver)
{
    MoveTo(hor*CHARWIDTH+LEFTMARGIN,(ver+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
    curcol = hor;
    abslin = ver;
    curlin = fndrel(ver);
}

/*
 * Find the relative line number given the absolute one.
 *
 */

fndrel(linum)
int linum;
{
    register int i, lin;

    lin = toplin;
    for (i=0; i<linum; i++) lin = nxtlin[lin];
    return(lin);
}

/*
 * Find the absolute line number given the relative one.
 *
 */

fndabs(linum)
int linum;
{
    int i, lin;

    lin = toplin;
    i = 0;
    while (lin != linum)
    {
	i++;
	lin = nxtlin[lin];
    }
    return(i);
}

/*
 * Find the previous relative line number from relative line linum.
 *
 */

fndprv(linum)
int linum;
{
    int lin;

    lin = toplin;
    while (nxtlin[lin] != linum) lin = nxtlin[lin];
    return(lin);
}

term_redraw()
{
    int i, lin;

    lin = toplin;
    for (i=0; i<MAXLIN; i++)
    {
	MoveTo(LEFTMARGIN,(i+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
	DrawString(scr[lin]);
	lin = nxtlin[lin];
    }
    MoveTo(curcol*CHARWIDTH+LEFTMARGIN,
    	(abslin+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
    cursor_draw();			/* Redraw Cursor */
}

init_term()
{
    int i;

    for (i=0; i<MAXLIN; i++)
    {
	nxtlin[i] = i + 1;		/* Tie together the linked list */
	scr[i][MAXCOL] = '\0';		/* Terminate the lines as strings */
    }
    toplin = 0;				/* Initialize the top and bottom ptr */
    botlin = MAXLIN - 1;
    scrtop = toplin;			/* Scrolling region equals all */
    scrbot = botlin;
    nxtlin[botlin] = -1;		/* Indicate this is the end */
}
