/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
// ansiterm.c
// two-letter descriptor: at
// ****************************************************************************
// Copyright (C) B. Cameron Lesiuk, 1999. All rights reserved.
// Permission to use/copy this code is granted for non-commercial use only.
// B. Cameron Lesiuk
// Victoria, BC, Canada
// wi961@freenet.victoria.bc.ca
// ****************************************************************************
//
// This module provides an ANSI colour terminal

/* ECMA-48 Implementation Notes
 * - Modes: EMCA-48 depreciates the use of modes. Consequently, the use of
 *   modes are not implemented. All modes are assumed to have their default value.
 * - It is unspecified what should happen when a LF is given at the bottom of
 *   the screen (or I'm missing something). Anyways, I coded it so that it scrolls
 *   the screen; I think everyone and their dog expects this anyways.
 * - FF is technically unimplemented; it does the same thing as an LF.
 * - Only align-left tabs are implemented. Affected operations: HT TAC TALE TATE TCC
 *   (and probably a few others)
 * - SIMD is implemented, but I'm not sure if I did it completely or correctly.
 *   Setting SIMD to 1 affects *ONLY* BS, CR, NEL, and the printing of characters.
 *   With SIMD=1, characters will be printed in a right-to-left progression, complete
 *   with wrap up and line-feeds when the cursor gets to the top of the screen.
 *   I am unsure if this is what ECMA-48 intended. Furthermore, I am unsure what
 *   other operations, if any, should be affected by SIMD.
 * - I'm not sure if CNL is supposed to generate linefeeds. Currently, it does.
 *   Same goes for CPL.
 * - I didn't have a *clue* what to do with F1-F12, INS, DEL, Home, End, PgUp,
 *   PgDn, or the cursor keys. So I guessed:
 *      INS  = ESC [ 2 ~         F1 = ESC [ [ A        F11= ESC [ 23 ~
 *      DEL  = DEL (0x7F)        F2 = ESC [ [ B        F12= ESC [ 24 ~
 *      Home = ESC [ H           F3 = ESC [ [ C
 *      End  = ESC [ 4 ~         F4 = ESC [ [ D
 *      PgUp = ESC [ 5 ~         F5 = ESC [ [ E
 *      PgDn = ESC [ 6 ~         F6 = ESC [ 17 ~
 *      Up   = ESC [ A           F7 = ESC [ 18 ~
 *      Down = ESC [ B           F8 = ESC [ 19 ~
 *      Right= ESC [ C           F9 = ESC [ 20 ~
 *      Left = ESC [ D           F10= ESC [ 21 ~
 *
 */


#include<windows.h>
#include<commdlg.h>
#include<windowsx.h>
#include<ctl3d.h>
#include"ctl3dl.h"
#include<stdio.h>
#include"molerc.h"
#include"termbuf.h"
#include"ansiterm.h"
#include"ansitbl.h"
#include"ascii_co.h"
#include"enviromt.h"
#include"mem.h"
#include"dialog.h"
#include"debug.h"

#define AT_ATOMSTR_HI "AnsiTermLong Hi"
#define AT_ATOMSTR_LO "AnsiTermLong Lo"
/* Globals */
UINT g_atCommDlgHelp;
ATOM g_atLongHi,g_atLongLo;

/* Macros (i hate them, I know, but...) for manipulating the input buffer */
#define ATIB_PREVCHAR(x,y)  ((y==x->aInputBuf)?(x->aInputBuf+x->aInputBufSize-1):(y-1))   /* x==ATTERM, y=cur pointer */
#define ATIB_NEXTCHAR(x,y)  ((y>=(x->aInputBuf+x->aInputBufSize-1))?(x->aInputBuf):(y+1)) /* x==ATTERM, y=cur pointer */
#define ATIB_ADDCHAR(x,y,z) ((y+z>=(x->aInputBuf+x->aInputBufSize-1))?(y+z-x->aInputBufSize):(y+z)) /* x==ATTERM, y=cur pointer, z=offset */
#define ATIB_SUBCHAR(x,y,z) ((y-z<x->aInputBuf)?(y-z+x->aInputBufSize):(y-z)) /* x==ATTERM, y=cur pointer, z=offset */

/* defines */
#define ATIB_FCOLOUR  7
#define ATIB_BCOLOUR  0

#define ATIB_MINX 20 /* minimum X window size (in characters) */
#define ATIB_MINY 1  /* minimum Y window size (in characters) */

/* The TermBuf doesn't work with a scrollback of 0, so this helps it along some */
#define ATIB_TERMBUF_EXTRALINES 5    /* this is not necessary if termbuf handled scrollback=0 */


BOOL atInitAnsiTermApplication(HINSTANCE p_hInst) {
	WNDCLASS l_wc;

	l_wc.style = CS_HREDRAW|CS_VREDRAW;
	l_wc.lpfnWndProc = atAnsiTermProc;
	l_wc.cbClsExtra = 0;
	l_wc.cbWndExtra = 4;
	l_wc.hInstance = p_hInst;
	l_wc.hIcon = LoadIcon(p_hInst, MAKEINTRESOURCE(ICON_ANSITERM));
	l_wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
	l_wc.hbrBackground = GetStockObject(BLACK_BRUSH);
	l_wc.lpszMenuName =MAKEINTRESOURCE(MENU_ANSITERM);
	l_wc.lpszClassName = AT_WIND_CLASS_NAME;

	return (RegisterClass(&l_wc));
}

BOOL atInitAnsiTerm() {
	g_atLongHi=GlobalAddAtom(AT_ATOMSTR_HI);
	g_atLongLo=GlobalAddAtom(AT_ATOMSTR_LO);
	g_atCommDlgHelp=RegisterWindowMessage(HELPMSGSTRING);
	return TRUE;
}

void atShutdownAnsiTerm() {
	GlobalDeleteAtom(g_atLongHi);
	GlobalDeleteAtom(g_atLongLo);
	return;
}

ATTERM *atAllocTerm(HINSTANCE p_hInst, HWND p_hParent,long p_BufX,
	long p_BufY,long p_ScrX,long p_ScrY, char *p_EnvSection, char *p_Title) {
	ATTERM *l_Term;
	HGLOBAL l_memory;
	long l_i;

	/* first, let's try to alloc our structure */
	l_memory=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(ATTERM));
	if (l_memory) {
		l_Term=(ATTERM*)GlobalLock(l_memory);
		if (l_Term) {
			/* set up our values and defaults */
			l_Term->aMemory=l_memory;
			l_Term->aInst=p_hInst;
			l_Term->aEmulation=AT_EMU_VT100;
			l_Term->aSeparateInputLine=FALSE;
			l_Term->aShowX=l_Term->aShowY=0;
			l_Term->aState=g_atGroundTable;
			strncpy(l_Term->aEnvSection,p_EnvSection,TBSTR_ENVSECTION);
			l_Term->aEnvSection[TBSTR_ENVSECTION-1]=0; /* enforce terminator */
			l_Term->aFont=NULL;
			l_Term->aFontUnderline=NULL;
			l_Term->aLogFontValid=FALSE;
			atChangeFont(l_Term,NULL,NULL);
			l_Term->aInputBorderDY=3;
			l_Term->aInputFColour=ATIB_FCOLOUR;
			l_Term->aInputBColour=ATIB_BCOLOUR;
			strncpy(l_Term->aTitle,p_Title,TBSTR_TITLE_LEN);
			l_Term->aTitle[TBSTR_TITLE_LEN-1]=0; /* enforce terminator */
			l_Term->aLocalEcho=FALSE;
			l_Term->aLFwithNLMode=TRUE;
			l_Term->aBackSpaceChar=ASCII_BS;
			l_Term->aDeleteChar=ASCII_DEL;
			l_Term->aNotify=NULL;
			l_Term->aAuxMsgHandler=NULL;
			l_Term->aLE_BSCount=0L;
			l_Term->aBell=TRUE;
			l_Term->aScroll=0L;
			l_Term->aCharacterSet[0]='B';  /* ASCII_G		*/
			l_Term->aCharacterSet[1]='B';
			l_Term->aCharacterSet[2]='B';  /* DEC supplemental.	*/
			l_Term->aCharacterSet[3]='B';
			l_Term->aCurCharacterSet=0;

			/* ECMA-48 Codes and default Modes */
			l_Term->aSIMD=0;
			l_Term->aSLH=0;

			/* clear function key macros */
			for (l_i=0;l_i<12;l_i++)
				l_Term->aFnKeyMacro[l_i][0]=0;

			/* now we need a termbuf */
			l_Term->aTermBuf=tbAllocTermBuf((unsigned long)(l_Term),p_BufX,
				p_BufY+ATIB_TERMBUF_EXTRALINES,p_ScrX,p_ScrY);
			if (l_Term->aTermBuf) {
				/* and set up our termbuf */
				((void*)(l_Term->aTermBuf->tNotifyFn))=((void*)(atNotifyFn));

				/* now we need an output buffer */
				l_Term->aOutBufMemory=GlobalAlloc(GHND|GMEM_NOCOMPACT,8192);
				if (l_Term->aOutBufMemory) {
					l_Term->aOutBuf=(unsigned char*)GlobalLock(l_Term->aOutBufMemory);
					if (l_Term->aOutBuf) {
						l_Term->aOutBufSize=(unsigned long)GlobalSize(l_Term->aOutBufMemory);
						l_Term->aOutBufSockTail=l_Term->aOutBufHead=l_Term->aOutBuf;

						/* and we need a separate input line buffer */
						l_Term->aInputBufMemory=GlobalAlloc(GHND|GMEM_NOCOMPACT,8192);
						if (l_Term->aInputBufMemory) {
							l_Term->aInputBuf=GlobalLock(l_Term->aInputBufMemory);
							if (l_Term->aInputBuf) {
								l_Term->aInputBufSize=(unsigned long)GlobalSize(l_Term->aInputBufMemory);
								atResetSeparateInputLine(l_Term);

								/* now we need a window */
								l_Term->aWnd = CreateWindow(
									 AT_WIND_CLASS_NAME,
									 p_Title,
									 WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_VSCROLL,
									 CW_USEDEFAULT,
                   CW_USEDEFAULT,
									 CW_USEDEFAULT,
									 CW_USEDEFAULT,
									 p_hParent,
									 NULL,
									 p_hInst,
									 NULL
									 );
                if (l_Term->aWnd) {
                  /* set up our extra window memory */
#ifdef WIN32
                  SetWindowLong(l_Term->aWnd,ATWND_ATTERMSEG,(LONG)l_Term);
#else
									SetWindowLong(l_Term->aWnd,ATWND_ATTERMSEG,(LONG)(SELECTOROF(l_Term)));
									SetWindowLong(l_Term->aWnd,ATWND_ATTERMOFF,(LONG)(OFFSETOF(l_Term)));
#endif
                  SetWindowPlacement(l_Term->aWnd,enRestoreWindowPlacement(l_Term->aEnvSection,
                    GetSystemMetrics(SM_CXSCREEN)*1/10,GetSystemMetrics(SM_CYSCREEN)*1/10,
										GetSystemMetrics(SM_CXSCREEN)*7/10,GetSystemMetrics(SM_CYSCREEN)*6/10));
									atAdjustTerm(l_Term,-1); /* shows/hides scrollbars, edit, etc. */
									tbClearScreen(l_Term->aTermBuf);
									l_Term->aSLL=TB_GETYMAX(l_Term->aTermBuf);
									/* we're done and happy! */
									atResetTerm(l_Term);
									return l_Term;
								}
								GlobalUnlock(l_Term->aInputBufMemory);
							}
							GlobalFree(l_Term->aInputBufMemory);
						}
						GlobalUnlock(l_Term->aOutBufMemory);
					}
					GlobalFree(l_Term->aOutBufMemory);
				}
				tbFreeTermBuf(l_Term->aTermBuf);
			}
			GlobalUnlock(l_memory);
		}
		GlobalFree(l_memory);
	}
	return NULL;
}

void atFreeTerm(ATTERM *p_Term) {
	HGLOBAL l_memory;
	if (p_Term) {
		/* first, close the window */
		DestroyWindow(p_Term->aWnd);
		/* next, turf our termbuf */
		tbFreeTermBuf(p_Term->aTermBuf);
		/* lastly, get rid of our structures */
    l_memory=p_Term->aInputBufMemory;
		GlobalUnlock(l_memory);
		GlobalFree(l_memory);
    l_memory=p_Term->aOutBufMemory;
		GlobalUnlock(l_memory);
		GlobalFree(l_memory);
		l_memory=p_Term->aMemory;
		GlobalUnlock(l_memory);
		GlobalFree(l_memory);
		/* and we're done! */
	}
}

void atChangeFont(ATTERM *p_Term, HFONT p_font, LOGFONT *p_logfont) {
	HDC l_hDC;
	TEXTMETRIC l_tm;
	RECT l_rect;
	HFONT l_newfont;

	if (p_Term) {
		if (p_Term->aFont) {
			DeleteObject(p_Term->aFont);
		}
		if (p_Term->aFontUnderline) {
			DeleteObject(p_Term->aFontUnderline);
		}
		if (p_logfont) {
			l_newfont=CreateFontIndirect(p_logfont);
			if (l_newfont) {
				p_Term->aFont=l_newfont;
				meMemCpy(&(p_Term->aLogFont),p_logfont,sizeof(LOGFONT));
				p_Term->aLogFontValid=TRUE;
				if (p_logfont->lfUnderline) {
					p_Term->aFontUnderline=NULL;
				} else {
					p_logfont->lfUnderline=TRUE;
					l_newfont=CreateFontIndirect(p_logfont);
					p_Term->aFontUnderline=l_newfont;
				}
			} else {
				p_Term->aFont=GetStockObject(SYSTEM_FIXED_FONT);
				p_Term->aLogFontValid=FALSE;
				p_Term->aFontUnderline=NULL;
			}
		} else if (p_font) {
			/* This method is undesired because it leaves us with no aLogFont to save
			 * the font to disk for retrieval next time */
			/* IE: if you set the terminal with only p_font specified, you can't
			 * save the font settings. End of story. */
			/* Also, we then have to way to get underlined fonts, etc. */
			p_Term->aFont=p_font;
			p_Term->aLogFontValid=FALSE;
			p_Term->aFontUnderline=NULL;
		} else {
			p_Term->aFont=GetStockObject(SYSTEM_FIXED_FONT);
			p_Term->aLogFontValid=FALSE;
			p_Term->aFontUnderline=NULL;
		}
		if (p_Term->aFont) {
			l_hDC=GetDC(p_Term->aWnd);
			if (l_hDC) {
				SelectObject(l_hDC,p_Term->aFont);
				GetTextMetrics(l_hDC,&l_tm);
				ReleaseDC(p_Term->aWnd,l_hDC);
				p_Term->aFontX=l_tm.tmAveCharWidth;
				p_Term->aFontY=l_tm.tmHeight; //+l_tm.tmExternalLeading;
			}
		} else {
			p_Term->aFontX=p_Term->aFontY=1;
		}
		/* change the font in our input window too, and redefine its height */
		p_Term->aInputWndDY=p_Term->aFontY;
		/* now give the window a nudge to activate our resizing acgorithms etc. */
		GetWindowRect(p_Term->aWnd,&l_rect);
		MoveWindow(p_Term->aWnd,l_rect.left,l_rect.top,
			l_rect.right-l_rect.left+1,l_rect.bottom-l_rect.top+1,TRUE);
		InvalidateRect(p_Term->aWnd,NULL,TRUE);
		if (!p_Term->aFontX)
			p_Term->aFontX=2;
		if (!p_Term->aFontY)
			p_Term->aFontY=2;
		/* resize caret */
		DestroyCaret();
		CreateCaret(p_Term->aWnd, NULL, (p_Term->aFontX)>>1, p_Term->aFontY);
		atUpdateCaret(p_Term);
		/* resize underline pen */
		tbCreateUnderscorePen(p_Term->aTermBuf,p_Term->aFontY);
	}
}

/* This procedure changes all the internal ansiterm states to reflect the
 * current window dimentions */
void atAdjustTerm(ATTERM *p_Term,long p_Scrollback){
	RECT l_rect;
	int l_ScrX,l_ScrY;
	long l_BufY;

	if (p_Term) {
		GetClientRect(p_Term->aWnd,&l_rect);
		/* ok! This is how much space we have, minus our scroll bars. */
		if (p_Term->aSeparateInputLine) {
			l_ScrX=(l_rect.right-l_rect.left)/p_Term->aFontX;
			l_ScrY=(l_rect.bottom-l_rect.top-p_Term->aInputWndDY-p_Term->aInputBorderDY)/
				p_Term->aFontY;
		} else {
			l_ScrX=(l_rect.right-l_rect.left)/p_Term->aFontX;
			l_ScrY=(l_rect.bottom-l_rect.top)/p_Term->aFontY;
		}
		if (l_ScrX<ATIB_MINX)
			l_ScrX=ATIB_MINX;
		if (l_ScrY<ATIB_MINY)
			l_ScrY=ATIB_MINY;
		if (p_Scrollback>=0)
			l_BufY=l_ScrY+p_Scrollback;
		else
			l_BufY=l_ScrY+(p_Term->aTermBuf->tBufY-ATIB_TERMBUF_EXTRALINES-p_Term->aTermBuf->tScrY);
		p_Term->aTermBuf=tbReAllocTermBuf(p_Term->aTermBuf,l_ScrX,
			l_BufY+ATIB_TERMBUF_EXTRALINES,l_ScrX,l_ScrY);
		p_Term->aSizeX=p_Term->aTermBuf->tScrX;
		p_Term->aSizeY=p_Term->aTermBuf->tScrY;

		/* our scrolling? let's just reset it. */
		p_Term->aShowX=p_Term->aShowY=0;

		/* reposition scrollbars accordingly. */
		atAdjustScrollbar(p_Term);

		/* Redraw the entire box */
		InvalidateRect(p_Term->aWnd,NULL,TRUE);

		atUpdateTermTitle(p_Term,NULL);

		/* and notify our owner of any changes */
		if (p_Term->aNotify)
			(*(p_Term->aNotify))(p_Term,ATNOTIFY_WINDOWSIZE);
	}
}

void atUpdateTermTitle(ATTERM *p_Term,char *p_NewTitle) {
	char l_buf[TBSTR_TITLE_LEN+50];

	if (p_Term) {
		if (p_NewTitle)
			strcpy(p_Term->aTitle,p_NewTitle);

		/* set our title up appropriately */
		sprintf(l_buf,"%s (%ix%i)",p_Term->aTitle,p_Term->aSizeX,p_Term->aSizeY);
		SetWindowText(p_Term->aWnd,l_buf);
	}
}

void atAdjustScrollbar(ATTERM *p_Term) {
	/* this proc just repositions the scrollbars to where they
	 * should be according to the present terminal settings */
	if (p_Term) {
//    SetScrollRange(p_Term->aWnd,SB_HORZ,TB_GETXMIN(p_Term->aTermBuf),
//      TB_GETXMAX(p_Term->aTermBuf)-p_Term->aSizeX, FALSE);
//    SetScrollPos(p_Term->aWnd,SB_HORZ,p_Term->aSizeX,TRUE);
//    SetScrollRange(p_Term->aWnd,SB_VERT,TB_GETYMIN(p_Term->aTermBuf),
//      TB_GETYMAX(p_Term->aTermBuf)-p_Term->aSizeY,FALSE);
		SetScrollRange(p_Term->aWnd,SB_VERT,
			p_Term->aSizeY-p_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES,0,FALSE);
		SetScrollPos(p_Term->aWnd,SB_VERT,p_Term->aShowY,TRUE);
	}
}

void atShowTerm(ATTERM *p_Term) {
	if (p_Term)
		ShowWindow(p_Term->aWnd,SW_SHOWNORMAL);
}

void atHideTerm(ATTERM *p_Term) {
	if (p_Term)
		ShowWindow(p_Term->aWnd,SW_HIDE);
}

BOOL atIsTermVisible(ATTERM *p_Term) {
	if (p_Term)
		return IsWindowVisible(p_Term->aWnd);
	return FALSE;
}

int atSendTerm(void *p_TermA, unsigned char *p_Buf, int p_BufLen) {
	int l_byte,l_i,l_j;
	int l_result;
	long l_x,l_y;
#ifndef DB_DEBUG_NODEBUG
	char l_tBuf[80];
#endif
	unsigned long l_p1,l_p2,l_p3;
//	long l_bit;
	ATTERM *p_Term=(ATTERM*)p_TermA;

	if (!p_Term)
		return 0;

//	for (l_byte=0;l_byte<p_BufLen;l_byte++) {
//		sprintf(l_tBuf,"AT Rx: 0x%02X",p_Buf[l_byte]);
//		dbPrint(l_tBuf);
//	}
//

	if (p_Term->aEmulation==AT_EMU_NONE) {
		for (l_byte=0;l_byte<p_BufLen;l_byte++) {
			if ((p_Buf[l_byte]<0x20)||(p_Buf[l_byte]>=0x80)) {
				switch (p_Buf[l_byte]) {
					case 0x0A: // linefeed
						tbLineFeed(p_Term->aTermBuf);
						break;
//					case 0x0D: // carridge return
//						tbCarridgeReturn(p_Term->aTermBuf);
//						break;
					default:
						break;
				}
			} else {
				tbPutChar(p_Term->aTermBuf,p_Buf[l_byte]);
			}
		}
	} else if (p_Term->aEmulation==AT_EMU_VT100) {
		for (l_byte=0;l_byte<p_BufLen;l_byte++) {
			if (p_Buf[l_byte]==0x03) {
				dbPrint("Ctrl-C encountered!");
				continue;
			}
			l_result=(p_Term->aState)[p_Buf[l_byte]];
#ifndef DB_DEBUG_NODEBUG
//			if (l_result!=ATSTATE_PRINT) {
				sprintf(l_tBuf,"AT: (%02X) %s -> %s %s",(unsigned int)(p_Buf[l_byte]),
					p_Term->aState==g_atGroundTable?"Ground Table":
					p_Term->aState==g_atCSITable?"g_atCSITable":
					p_Term->aState==g_atEIGTable?"g_atEIGTable":
					p_Term->aState==g_atESCTable?"g_atESCTable":
					p_Term->aState==g_atIESTable?"g_atIESTable":
					p_Term->aState==g_atIGNTable?"g_atIGNTable":
					p_Term->aState==g_atSCRTable?"g_atSCRTable":
					p_Term->aState==g_atSCSTable?"g_atSCSTable":
					p_Term->aState==g_atCSI_SIBTable?"g_atCSI_SIBTable": "??WHAT??",
					g_atStateTable[l_result],
					((p_Term->aState!=g_atGroundTable)&&(l_result==ATSTATE_GROUND_STATE))?
						"(ignored)":"");
				dbPrint(l_tBuf);
//			}
#endif
			switch(l_result) {
				case ATSTATE_GROUND_STATE:
					/* exit ignore mode */
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_IGNORE_STATE:
					/* IES: ignore anything else */
					p_Term->aState=g_atIGNTable;
					break;
				case ATSTATE_IGNORE_ESC:
					/* IGN: escape */
					p_Term->aState=g_atIESTable;
					break;
				case ATSTATE_IGNORE:
					/* ignore character */
					break;
				case ATSTATE_PRINT:
					/* print character */
					/* we should be using l_Term->aCharacterSet[l_Term->aCurCharacterSet] */
					if (p_Term->aSIMD)
						tbPutCharReverse(p_Term->aTermBuf,p_Buf[l_byte]);
					else
						tbPutChar(p_Term->aTermBuf,p_Buf[l_byte]);
					break;
				case ATSTATE_BELL:
					if (p_Term->aBell) {
						MessageBeep(MB_OK);
					}
					break;
				case ATSTATE_BS:
					if (p_Term->aSIMD)
						tbCurRight(p_Term->aTermBuf);
					else
						tbCurLeft(p_Term->aTermBuf);
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DEL:
					/* this functionality has been removed from the standard. However,
					 * it's inclusion may be usefull in some situations. For any
					 * qualified shell, it should handle the echo and thus the
					 * delete key properly. However, for things like MUDs that
					 * use the delete key, and which DON'T echo, or for terminals
					 * that (falsely) expect backspace to ERASE the previous character
					 * (ie: not just move the cursor), this can be handy. Basically,
					 * it's a kludge. Furthermore, it doesn't really work properly;
					 * you can delete back past the start of an input prompt. If you are
					 * using a system where this is important, I suggest you use the
           * separate input line operation. 
					 */
					tbDelete(p_Term->aTermBuf);
          break;
				case ATSTATE_DCH:
					/* delete character */
					l_i=p_Term->aStateVal[0];
					if (l_i<1)
						l_i=1;
					for (;l_i;l_i--) {
						tbDelete(p_Term->aTermBuf);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CR:
					if (p_Term->aSIMD)
						tbSetCursor(p_Term->aTermBuf,p_Term->aSLL,p_Term->aTermBuf->tCurY);
					else
						tbSetCursor(p_Term->aTermBuf,p_Term->aSLH,p_Term->aTermBuf->tCurY);
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_NEL:
					if (p_Term->aSIMD) {
						tbSetCursor(p_Term->aTermBuf,p_Term->aSLL,p_Term->aTermBuf->tCurY);
						tbLineFeedUp(p_Term->aTermBuf); /* will update our cursor for us */
					}	else {
						tbSetCursor(p_Term->aTermBuf,p_Term->aSLH,p_Term->aTermBuf->tCurY);
						tbLineFeed(p_Term->aTermBuf); /* will update our cursor for us */
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_ESC:
					p_Term->aState=g_atESCTable;
					break;
				case ATSTATE_VT: /**/
					/* line feed, form feed, vertical tab */
					tbLineFeed(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_HT:
					/* horizontal tab */
					tbHTab(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_HTS:
					/* horizontal tab set */
					tbTabSet(p_Term->aTermBuf,TBTAB_LEFTALIGN,-1);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_TBC:
					/* horizontal tab clear */
					switch(p_Term->aStateVal[0]) {
						default:
						case 0: /* Character tab at current cursor position is cleared */
							tbTabSet(p_Term->aTermBuf,TBTAB_NONE,-1);
							break;
						case 1: /* Line tabulation at current line is cleared -- unimplemented */
						case 2: /* all character tabs in active line are cleared */
						case 3: /* all character tabs are cleared */
						case 4: /* all line tabs are cleared */
						case 5: /* all tabs are cleared (both character and line) */
							tbTabClearAll(p_Term->aTermBuf);
							break;
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_TSR:
					/* Tabulation Stop Remove */
					if (p_Term->aStateVal[0]!=AT_STATEVAL_DEFAULT) {
						tbTabSet(p_Term->aTermBuf,TBTAB_NONE,p_Term->aStateVal[0]-1);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CBT:
					/* Cursor Backward Tabulation */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for(;l_j;l_j--)
						tbHTabReverse(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CHA:
					/* Cursor Character Absolute */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					tbSetCursor(p_Term->aTermBuf,l_j-1,p_Term->aTermBuf->tCurY);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_VPA:
					/* Line Position Absolute */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					tbSetCursor(p_Term->aTermBuf,p_Term->aTermBuf->tCurX,l_j-1);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CHT:
					/* Cursor Forward Tabulation */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for(;l_j;l_j--)
						tbHTab(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CNL:
					/* Cursor Next Line */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for(;l_j;l_j--)
						tbLineFeed(p_Term->aTermBuf); /* will update our cursor for us */
					tbSetCursor(p_Term->aTermBuf,0,p_Term->aTermBuf->tCurY);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CPL:
					/* Cursor Previous Line */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for(;l_j;l_j--)
						tbLineFeedUp(p_Term->aTermBuf); /* will update our cursor for us */
					tbSetCursor(p_Term->aTermBuf,0,p_Term->aTermBuf->tCurY);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CTC:
					/* Cursor Tabulation Control */
					/* horizontal tab clear */
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT)
						p_Term->aStateVal[0]=0;
					for (l_i=0;p_Term->aStateVal[l_i]!=AT_STATEVAL_DEFAULT;l_i++) {
						switch(p_Term->aStateVal[l_i]) {
							default:
							case 0: /* Character tab at current cursor position is set */
								tbTabSet(p_Term->aTermBuf,TBTAB_LEFTALIGN,-1);
								break;
							case 1: /* Line tabulation at current line is set -- unimplemented */
								break;
							case 2: /* Character tab at current position is cleared */
								tbTabSet(p_Term->aTermBuf,TBTAB_NONE,-1);
								break;
							case 3: /* current line tabs is cleared */
								break;
							case 4: /* all character tabs in current line are cleared */
							case 5: /* all character tabs are cleared */
								tbTabClearAll(p_Term->aTermBuf);
								break;
							case 6: /* all line tabulation stops are cleared */
								break;
						}
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SD:
					/* Scroll data down n lines */
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT)
						p_Term->aStateVal[0]=1;
					for (l_i=0;l_i<p_Term->aStateVal[0];l_i++) {
						tbScrollDown(p_Term->aTermBuf);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SU:
					/* Scroll data up n lines */
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT)
						p_Term->aStateVal[0]=1;
					for (l_i=0;l_i<p_Term->aStateVal[0];l_i++) {
						tbScrollUp(p_Term->aTermBuf);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SR:
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT)
						p_Term->aStateVal[0]=1;
					for (l_i=0;l_i<p_Term->aStateVal[0];l_i++) {
						tbScrollRight(p_Term->aTermBuf);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SL:
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT)
						p_Term->aStateVal[0]=1;
					for (l_i=0;l_i<p_Term->aStateVal[0];l_i++) {
						tbScrollLeft(p_Term->aTermBuf);
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SI:
					dbPrint("AT: Unhandled _SI");
					break;
				case ATSTATE_SO:
					dbPrint("AT: Unhandled _SO");
					break;
				case ATSTATE_SCR_STATE:
					p_Term->aState=g_atSCRTable;
					break;
				case ATSTATE_SCS0_STATE: /**/
					p_Term->aSCSType=0;
					p_Term->aState=g_atSCSTable;
					break;
				case ATSTATE_SCS1_STATE: /**/
					p_Term->aSCSType=1;
					p_Term->aState=g_atSCSTable;
					break;
				case ATSTATE_SCS2_STATE: /**/
					p_Term->aSCSType=2;
					p_Term->aState=g_atSCSTable;
					break;
				case ATSTATE_SCS3_STATE: /**/
					p_Term->aSCSType=3;
					p_Term->aState=g_atSCSTable;
					break;
				case ATSTATE_ESC_IGNORE:
					/* unknown ESC code */
					p_Term->aState=g_atEIGTable;
					break;
				case ATSTATE_ESC_DIGIT:
					l_j=p_Term->aStateVal[p_Term->aStateValPos];
					if (l_j==AT_STATEVAL_DEFAULT) {
						p_Term->aStateVal[p_Term->aStateValPos]=(p_Buf[l_byte]-'0');
					} else {
						p_Term->aStateVal[p_Term->aStateValPos]=l_j*10+(p_Buf[l_byte]-'0');
					}
					break;
				case ATSTATE_ESC_SEMI:
					p_Term->aStateValPos++;
					break;
				case ATSTATE_ICH:
					/* insert characters */
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					tbInsertChar(p_Term->aTermBuf,l_j);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_RI:
					if (p_Term->aTermBuf->tCurY) {
						tbCurUp(p_Term->aTermBuf);
					} else {
						tbScrollDown(p_Term->aTermBuf);
					}
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CUU:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for (;l_j;l_j--) {
						tbCurUp(p_Term->aTermBuf);
					}
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CUD:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for (;l_j;l_j--) {
						tbCurDown(p_Term->aTermBuf);
					}
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CUF:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for (;l_j;l_j--) {
						tbCurRight(p_Term->aTermBuf);
					}
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CUB:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					for (;l_j;l_j--) {
						tbCurLeft(p_Term->aTermBuf);
					}
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CUP:
					/* cursor position */
					l_y=p_Term->aStateVal[0];
					l_x=p_Term->aStateVal[1];
					if (l_y<1)
						l_y=1;
					if (l_x<1)
						l_x=1;
					tbSetCursor(p_Term->aTermBuf,l_x-1,l_y-1);
					atUpdateCaret(p_Term);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_ECH:
					/* Erase Character */
					l_i=p_Term->aStateVal[0];
					if (l_i<1)
						l_i=1;
					l_i--;
					tbClearLineX(p_Term->aTermBuf,p_Term->aTermBuf->tCurX,p_Term->aTermBuf->tCurX+l_i);
					p_Term->aState=g_atGroundTable;
          break;
				case ATSTATE_ED:
					/* Erase in Page */
					switch(p_Term->aStateVal[0]) {
						default:
						case 0:
							/* clear below */
							tbClearBelow(p_Term->aTermBuf);
							break;
						case 1:
							/* clear above */
							tbClearAbove(p_Term->aTermBuf);
							break;
						case 2:
							/* clear screen */
							tbClearScreen(p_Term->aTermBuf);
							break;
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_EL:
					switch(p_Term->aStateVal[0]) {
						default:
						case 0:
							/* clear to right */
							tbClearRight(p_Term->aTermBuf);
							break;
						case 1:
							/* clear to left */
							tbClearLeft(p_Term->aTermBuf);
							break;
						case 2:
							/* clear line */
							tbClearLine(p_Term->aTermBuf);
							break;
					}
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SGR:
					if (p_Term->aStateVal[0]==AT_STATEVAL_DEFAULT) {
						/* no parameters - set defaults */
						l_p1=0x07;
						l_p2=0x00;
						l_p3=0x00;
					} else {
						l_p1=TB_EXTFCOLOUR(p_Term->aTermBuf->tCurrentAttribute);
						l_p2=TB_EXTBCOLOUR(p_Term->aTermBuf->tCurrentAttribute);
						l_p3=TB_EXTEFFECT(p_Term->aTermBuf->tCurrentAttribute);
					}
					for (l_j=0;p_Term->aStateVal[l_j]!=AT_STATEVAL_DEFAULT;l_j++) {
						switch(p_Term->aStateVal[l_j]) {
							case 0:	/* default */
								/* reset - lgray on black - all attributes off */
								l_p1=0x07;
								l_p2=0x00;
								l_p3=0x00;
								break;
							case 1: /* bold on */
								l_p3|=AT_FONTEFFECT_BOLD;
								break;
//							case 2:  /* faint on */
//							case 3:  /* italicized on */
							case 4:  /* singly underline on */
								/* Underscores on */
								l_p3|=AT_FONTEFFECT_UNDERLINE;
								break;
							case 5:  /* slowly blinking on (less than 150 per minute) */
							case 6:  /* rapidly blinking on (more than 150 per minute) */
								/* Blink on */
//								l_p2=l_p2|0x08;  /* this should be taken out sometime */
								l_p3|=AT_FONTEFFECT_BLINK;
								break;
							case 7:  /* negative image (reverse video) on */
								/* reverse video on */
								l_p3|=AT_FONTEFFECT_REVERSE;
								/* the following color-adjustment stuff should be taken out sometime */
//								if ((l_p1==0x0F)||(l_p1==0x08))
//									l_p1=0x00;
//								else
//								l_p1^=0x07;
//								l_p2^=0x07;
								break;
//							case 8:  /* concealed characters on */
//							case 9:  /* crossed-out (strike-out) */
							case 10: /* Primary (default) font */
							case 11: /* first alternate font */
							case 12: /* second alternate font */
							case 13: /* third alternate font */
							case 14: /* fourth alternate font */
							case 15: /* fifth alternate font */
							case 16: /* sixth alternate font */
							case 17: /* seventh alternate font */
							case 18: /* eighth alternate font */
							case 19: /* ninth alternate font */
							case 20: /* Fraktur (Gothic) */
								break;
//							case 21: /* double underline on */
							case 21: /* **>> This breaks ECMA-48 (bold off ?!?!?!) */ 
							case 22: /* normal color/intensity (neither bold nor faint) */
								/* Bold off */
//								l_p1=l_p1|0x08;
//								l_p1=l_p1^0x08;
								l_p3|=AT_FONTEFFECT_BOLD;
								l_p3^=AT_FONTEFFECT_BOLD;
								break;
//							case 23: /* not italicized, not fraktur */
							case 24: /* not underlined (not singly nor double) */
								/* Underscores off */
								l_p3|=AT_FONTEFFECT_UNDERLINE;
								l_p3^=AT_FONTEFFECT_UNDERLINE;
								break;
							case 25: /* steady (blink off) */
								/* Blink off */
//								l_p2=l_p2|0x08;
//								l_p2=l_p2^0x08;
								l_p3|=AT_FONTEFFECT_BLINK;
								l_p3^=AT_FONTEFFECT_BLINK;
								break;
//							case 26: /* (reserved for proportional spacing) */
							case 27: /* positive image (negative off) */
								/* reverse video off */
								l_p3|=AT_FONTEFFECT_REVERSE;
								l_p3^=AT_FONTEFFECT_REVERSE;
//								if ((l_p1==0x0F)||(l_p1==0x08))
//									l_p1=0x00;
//								else
//									l_p1^=0x07;
//								l_p2^=0x07;
								break;
//							case 28: /* revealed characters (conceal off) */
//							case 29: /* not crossed out (crossed-out off) */
							case 30: /* black display (char) */
							case 31: /* red display (char) */
							case 32: /* green display (char) */
							case 33: /* yellow display (char) */
							case 34: /* blue display (char) */
							case 35: /* magenta display (char) */
							case 36: /* cyan display (char) */
							case 37: /* white display (char) */
								/* Foreground colour */
								l_p1=(((l_p1|0x07)^0x07)|(p_Term->aStateVal[l_j]-30));
								break;
//							case 38: /* (reserved) */
							case 39: /* default display (char) colour */
								/* turn off foreground color */
								l_p1=0x07;
								break;
							case 40: /* black background */
							case 41: /* red background */
							case 42: /* green background */
							case 43: /* yellow background */
							case 44: /* blue background */
							case 45: /* magenta background */
							case 46: /* cyan background */
							case 47: /* white background */
								/* Background colour */
								l_p2=(((l_p2|0x07)^0x07)|(p_Term->aStateVal[l_j]-40));
								break;
//							case 48: /* (reserved) */
							case 49: /* default background colour */
								/* turn off background color */
								l_p2=0x00;
								break;
//							case 50: /* (reserved - cancels effect of 26) */
//							case 51: /* framed */
//							case 52: /* encircled */
//							case 53: /* overline */
//							case 54: /* not framed, not encircled */
//							case 55: /* not overlined */
//							case 56: /* (reserved) */
//							case 57: /* (reserved) */
//							case 58: /* (reserved) */
//							case 59: /* (reserved) */
//							case 60: /* ideogram underline or right side line */
//							case 61: /* ideogram double underline or double right side line */
//							case 62: /* ideogram overline or left side line */
//							case 63: /* ideogram double overline or double left side line */
//							case 64: /* ideogram stress marking */
//							case 65: /* cancels effect from 60-64 */
							default:
#ifndef DB_DEBUG_NODEBUG
								sprintf(l_tBuf,"VT100: ESC [ %i m sequence ignored",p_Term->aStateVal[l_j]);
								dbPrint(l_tBuf);
#endif
								break;
						}
					}
					tbSetFColour(p_Term->aTermBuf,l_p1);
					tbSetBColour(p_Term->aTermBuf,l_p2);
					tbSetEffect(p_Term->aTermBuf,l_p3);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CSI_STATE:
					/* reset parameters */
					for (l_i=0;l_i<AT_ESC_PARAM_MAX;l_i++)
						p_Term->aStateVal[l_i]=AT_STATEVAL_DEFAULT;
					p_Term->aStateValPos=0;
					p_Term->aState=g_atCSITable;
					break;
				case ATSTATE_IL:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					tbInsertLine(p_Term->aTermBuf,l_j);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DL:
					l_j=p_Term->aStateVal[0];
					if (l_j<1)
						l_j=1;
					tbDeleteLine(p_Term->aTermBuf,l_j);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DECSC:
					tbCursorSave(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DECRC:
					tbCursorRestore(p_Term->aTermBuf);
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DECSET:
				case ATSTATE_DECRST:
					/* process DEC private modes set, reset */
					if (l_result==ATSTATE_DECSET) {
//						l_bit=0x00;  /* set bit */
					} else {
//						l_bit=~0x00; /* reset (clr) bits */
					}
					l_i=0;
					while(p_Term->aStateVal[l_i]!=AT_STATEVAL_DEFAULT) {
						switch (p_Term->aStateVal[l_i]) {
							case 1: /* DECCKM */
							case 2: /* ANSI/VT52 mode */
							case 3: /* DECCOLM */
							case 4: /* DECSCLM (slow scroll) */
							case 5: /* DECSCNM */
							case 6: /* DECOM */
							case 7: /* DECAWM */
							case 8: /* DECARM */
							case 9: /* MIT bogus sequence */
							case 38: /* DECTEK */
							case 40: /* 132 column mode */
							case 41: /* curses hack */
							case 44: /* margin bell */
							case 45: /* reverse wraparound */
							case 46: /* logging */
							case 47: /* alternate buffer */
							case 1000: /* xterm bogus sequence */
							case 1001: /* xterm sequence w/ hilite tracking */
#ifndef DB_DEBUG_NODEBUG
								if (l_result==ATSTATE_DECSET)
									sprintf(l_tBuf,"AT: unhandled DECSET: %i",p_Term->aStateVal[l_i]);
								else
									sprintf(l_tBuf,"AT: unhandled DECRST: %i",p_Term->aStateVal[l_i]);
								dbPrint(l_tBuf);
#endif
								break;
						}
						l_i++;
					}
					break;
				case ATSTATE_SIMD:
					if (p_Term->aStateVal[0]==1)
						p_Term->aSIMD=1;
					else
						p_Term->aSIMD=0; /* default */
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_CSI_SIB: /* CSI Single Intermediate Byte mode */
					p_Term->aState=g_atCSI_SIBTable;
					break;
				case ATSTATE_SLH:
					if (p_Term->aStateVal[0]<1)
						p_Term->aSLH=0;
					else
						p_Term->aSLH=p_Term->aStateVal[0]-1;
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_SLL:
					if (p_Term->aStateVal[0]<1)
						p_Term->aSLL=0;
					else
						p_Term->aSLL=p_Term->aStateVal[0]-1;
					p_Term->aState=g_atGroundTable;
					break;
				case ATSTATE_DA1:
				case ATSTATE_TRACK_MOUSE:
				case ATSTATE_SET:
				case ATSTATE_RST:
				case ATSTATE_CPR:
				case ATSTATE_DECSTBM:
				case ATSTATE_DECREQTPARM:
				case ATSTATE_DECALN:
				case ATSTATE_GSETS:
				case ATSTATE_DECKPAM:
				case ATSTATE_DECKPNM:
				case ATSTATE_IND:
				case ATSTATE_SS2:
				case ATSTATE_SS3:
				case ATSTATE_OSC:
				case ATSTATE_RIS:
				case ATSTATE_LS2:
				case ATSTATE_LS3:
				case ATSTATE_LS3R:
				case ATSTATE_LS2R:
				case ATSTATE_LS1R:
				case ATSTATE_XTERM_SAVE:
				case ATSTATE_XTERM_RESTORE:
				case ATSTATE_XTERM_TITLE:
				case ATSTATE_DECID:
#ifndef DB_DEBUG_NODEBUG
					dbPrint("Unimplemented ANSITerm state");
					sprintf(l_tBuf,"AT: %s -> %s",
						p_Term->aState==g_atGroundTable?"Ground Table":
						p_Term->aState==g_atCSITable?"g_atCSITable":
						p_Term->aState==g_atEIGTable?"g_atEIGTable":
						p_Term->aState==g_atESCTable?"g_atESCTable":
						p_Term->aState==g_atIESTable?"g_atIESTable":
						p_Term->aState==g_atIGNTable?"g_atIGNTable":
						p_Term->aState==g_atSCRTable?"g_atSCRTable":
						p_Term->aState==g_atSCSTable?"g_atSCSTable":
						p_Term->aState==g_atCSI_SIBTable?"g_atCSI_SIBTable": "??WHAT??",
						g_atStateTable[l_result]);
					dbPrint(l_tBuf);
#endif
					p_Term->aState=g_atGroundTable;
					break;
				default:
#ifndef DB_DEBUG_NODEBUG
					dbPrint("Invalid ANSITerm state");
					sprintf(l_tBuf,"AT: %s -> %s",
						p_Term->aState==g_atGroundTable?"Ground Table":
						p_Term->aState==g_atCSITable?"g_atCSITable":
						p_Term->aState==g_atEIGTable?"g_atEIGTable":
						p_Term->aState==g_atESCTable?"g_atESCTable":
						p_Term->aState==g_atIESTable?"g_atIESTable":
						p_Term->aState==g_atIGNTable?"g_atIGNTable":
						p_Term->aState==g_atSCRTable?"g_atSCRTable":
						p_Term->aState==g_atSCSTable?"g_atSCSTable": "??WHAT??",
						g_atStateTable[l_result]);
					dbPrint(l_tBuf);
#endif
					p_Term->aState=g_atGroundTable;
					break;
			} /* master switch */
		} /* for() -- loop through buffer */
	} /* VT100 emulation */
	return(p_BufLen);
}

void atClearTerm(ATTERM *p_Term) {
	if (p_Term)
		tbClearScreen(p_Term->aTermBuf);
}

#pragma argsused
void atNotifyFn(unsigned long p_ID, unsigned int p_Operation, long p_P0,
	long p_P1, long p_P2, long p_P3) {
	ATTERM *l_Term;
	long l_sy,l_dy;
	RECT l_rect;

	if (!p_ID)
		return;
	l_Term=(ATTERM*)(p_ID);
	switch (p_Operation) {
		case TBNOTIFY_SCROLL:
//      if (l_Term->aShowY==0)
			l_Term->aScroll+=-p_P0*l_Term->aFontY;
			PostMessage(l_Term->aWnd,WM_PAINT,0,0L); /* note there may not be an update region! He he he */
//      else  /* NOTE THIS SHOULD CHANGE, IF UNCOMMENTED, TO */
//            /* CHECK FOR aSeparateInputLine */   <<<CAUSE AN ERROR>>>
//        ScrollWindow(l_Term->aWnd,0,-p_P0*l_Term->aFontY,NULL,NULL);
//      UpdateWindow(l_Term->aWnd);
			break;
		case TBNOTIFY_NEWCHAR:
			l_sy=TB_MAX(p_P1,l_Term->aShowY);
			l_dy=TB_MIN(p_P3,l_Term->aShowY+l_Term->aSizeY);
			if (l_dy>=l_sy) {
				l_rect.top=(l_sy-l_Term->aShowY)*l_Term->aFontY;
				l_rect.bottom=(l_sy-l_Term->aShowY+(l_dy-l_sy)+1)*l_Term->aFontY;
				if (l_sy==l_dy) {
					l_rect.left=(p_P0-l_Term->aShowX)*l_Term->aFontX;
					l_rect.right=(p_P0-l_Term->aShowX+(p_P2-p_P0)+1)*l_Term->aFontX;
				} else {
					l_rect.left=0;
					l_rect.right=l_Term->aSizeX*l_Term->aFontX;
				}
				InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
			}
			break;
		case TBNOTIFY_MOVECUR:
			if (p_P2)
				atUpdateCaret(l_Term);
			break;
		case TBNOTIFY_RESIZE:
//      atAdjustTerm(l_Term,-1);
		default:
			dbPrint("ANSITERM: Unhandled NotifyFn operation");
			break;
	}
//  atUpdateCaret(l_Term);
	return;
}

/* This proc updates the caret position & visibility information based
 * on the current state of the terminal */
void atUpdateCaret(ATTERM *p_Term) {
	if (p_Term) {
		if (GetFocus()==p_Term->aWnd) {
			if (p_Term->aSeparateInputLine) {
				/* TAG TAG TAG THIS has to move the caret over in the X direction
				 * according to whatever text is currently displayed */
				SetCaretPos(p_Term->aFontX*(p_Term->aInputCurPos-p_Term->aInputDispCurPos),
					p_Term->aTermBuf->tScrY*p_Term->aFontY+p_Term->aInputBorderDY);
				ShowCaret(p_Term->aWnd);
			} else if (p_Term->aTermBuf) {
				if ((p_Term->aTermBuf->tCurX>=p_Term->aShowX)&&
						(p_Term->aTermBuf->tCurX<p_Term->aShowX+p_Term->aSizeX) &&
						(p_Term->aTermBuf->tCurY>=p_Term->aShowY)&&
						(p_Term->aTermBuf->tCurY<p_Term->aShowY+p_Term->aSizeY)) {
					SetCaretPos((p_Term->aTermBuf->tCurX-p_Term->aShowX)*p_Term->aFontX,
						(p_Term->aTermBuf->tCurY-p_Term->aShowY)*p_Term->aFontY);
					ShowCaret(p_Term->aWnd);
				} else {
					HideCaret(p_Term->aWnd);
				}
			}
		}
	}
}

/* Does screen scrolling & invalidation etc to cause the screen to
 * be repainted at a new specified location */
void atScrollTermTo(ATTERM *p_Term,BOOL p_Rel,long p_Val) {
	long l_newShowY;
//	char l_buf[100];

//	sprintf(l_buf,"SCROLL: %s %i",p_Rel?"Relative":"Absolute",p_Val);
//	dbPrint(l_buf);

	/* first, let's check our input */
	if (!p_Term)
		return;

	if (p_Rel) {
		/* relative offset */
		l_newShowY=p_Term->aShowY+p_Val;
	} else {
		l_newShowY=p_Val;
	}

	if (l_newShowY>0)
		l_newShowY=0;
	if (l_newShowY<(p_Term->aTermBuf->tScrY-p_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES))
		l_newShowY=(p_Term->aTermBuf->tScrY-p_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES);

	/* ok, we know where we are scrolling to. Now, let's check if we can
	 * scroll part of our window. If we can, do so. */
	if (p_Term->aShowY==l_newShowY) {
		return;
	} else if (p_Term->aShowY<l_newShowY) {
		/* scroll down */
		if ((l_newShowY-p_Term->aShowY)<p_Term->aSizeY) {
//      p_Term->aScroll+=-(l_newShowY-p_Term->aShowY)*p_Term->aFontY;
			if (p_Term->aSeparateInputLine)
				ScrollWindow(p_Term->aWnd,0,-(l_newShowY-p_Term->aShowY)*p_Term->aFontY,
					&(p_Term->aScrollRect),&(p_Term->aScrollRect));
			else
				ScrollWindow(p_Term->aWnd,0,-(l_newShowY-p_Term->aShowY)*p_Term->aFontY,NULL,NULL);
		} else {
			if (p_Term->aSeparateInputLine)
				InvalidateRect(p_Term->aWnd,&(p_Term->aScrollRect),FALSE);
			else
				InvalidateRect(p_Term->aWnd,NULL,FALSE);
		}
	} else {
		/* scroll up */
		if ((p_Term->aShowY-l_newShowY)<p_Term->aSizeY) {
//      p_Term->aScroll+=(p_Term->aShowY-l_newShowY)*p_Term->aFontY;
			if (p_Term->aSeparateInputLine)
				ScrollWindow(p_Term->aWnd,0,(p_Term->aShowY-l_newShowY)*p_Term->aFontY,
					&(p_Term->aScrollRect),&(p_Term->aScrollRect));
			else
				ScrollWindow(p_Term->aWnd,0,(p_Term->aShowY-l_newShowY)*p_Term->aFontY,NULL,NULL);
		} else {
			if (p_Term->aSeparateInputLine)
				InvalidateRect(p_Term->aWnd,&(p_Term->aScrollRect),FALSE);
			else
				InvalidateRect(p_Term->aWnd,NULL,FALSE);
		}
	}
	p_Term->aShowY=l_newShowY;
	return;
}

#define ATANSITERMPROCBUFSIZE 1024
#pragma argsused
LRESULT CALLBACK _export atAnsiTermProc(HWND p_hWnd, UINT p_message,
											WPARAM p_wParam, LPARAM p_lParam) {
	static RECT l_rect;
	static PAINTSTRUCT l_ps; // paint structure
	static HDC l_hDC; // device context
	static HFONT l_oldFont;
	static HPEN l_oldPen;
	static int l_i,l_j,l_x,l_y,l_count;
	static int l_startX,l_endX; /* start & end lines */
	static int l_startY,l_endY; /* start & end lines */
//  static HBRUSH l_hBrush;
//  static DSSTRUCT *l_area,*l_thing;
	static unsigned char l_buf[ATANSITERMPROCBUFSIZE];
//  static POINT l_ptCurrent; /* for quick-menu */
//  static HMENU l_hmenu;     /* for quick-menu */
//  static UINT l_flags;      /* for quick-menu */
//  static UINT l_flagsInactive; /* for quick-menu */
//  static UINT l_flagsSeparator; /* for quick-menu */
	static ATTERM *l_Term;
	static long l_attrib;
	static unsigned long l_rawChar,*l_rawCharP;
	static unsigned char *l_p,*l_q;
	static HMENU l_menu;
	static POINT l_point;

#ifdef WIN32
	l_Term=(ATTERM *)GetWindowLong(p_hWnd,ATWND_ATTERMSEG);
#else
	l_Term=(ATTERM *)MAKELP(GetWindowLong(p_hWnd,ATWND_ATTERMSEG),
		GetWindowLong(p_hWnd,ATWND_ATTERMOFF));
#endif

	if (p_message==g_atCommDlgHelp) {
		(*(l_Term->aNotify))(l_Term,TBNOTIFY_FONTHELP);
		return 0L;
	}

	switch (p_message)
		{
		case WM_VSCROLL:
			DestroyCaret();
			switch(GET_WM_VSCROLL_CODE(p_wParam,p_lParam)) {
				case SB_BOTTOM:
					atScrollTermTo(l_Term,0,0);
					break;
				case SB_LINEDOWN:
					atScrollTermTo(l_Term,1,1);
					break;
				case SB_LINEUP:
					atScrollTermTo(l_Term,1,-1);
					break;
				case SB_PAGEDOWN:
					atScrollTermTo(l_Term,1,l_Term->aTermBuf->tScrY-1);
					break;
				case SB_PAGEUP:
					atScrollTermTo(l_Term,1,-(l_Term->aTermBuf->tScrY-1));
					break;
				case SB_THUMBPOSITION:
				case SB_THUMBTRACK:
					atScrollTermTo(l_Term,0,(long)((short)(GET_WM_HSCROLL_POS(p_wParam,p_lParam))));
					UpdateWindow(p_hWnd);
					break;
				case SB_TOP:
					atScrollTermTo(l_Term,0,0);
					break;
				case SB_ENDSCROLL:
//          PostMessage(p_hWnd,WM_USER_AREALIST_SCROLL,0,0L);
//          break;
					SendMessage(p_hWnd,WM_SETFOCUS,0,0L);
					break;
			}
			SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
			return 0L;
		case WM_COMMAND:
			switch(GET_WM_COMMAND_ID(p_wParam,p_lParam)) {
				case CM_ANSIEDITCOPY:
					l_i=tbHilightSize(l_Term->aTermBuf);
					if (!l_i)
            break; /* nothing to copy */
					if (OpenClipboard(l_Term->aWnd)) {
						if (EmptyClipboard()) {
							HGLOBAL l_hGlobal;
							/* first thing we need to do is calculate how large of a buffer
							 * we need */
							/* next, alloc our buffer */
							l_hGlobal=GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,l_i+10); /* + 10 just to be sure we don't overrun */
							if (l_hGlobal) {
								l_p=(unsigned char*)GlobalLock(l_hGlobal);
								if (l_p) {
									/* now copy our data into the buffer */
									tbCopyHilight(l_Term->aTermBuf,l_p);
									GlobalUnlock(l_hGlobal);
									SetClipboardData(CF_TEXT,(HANDLE)l_hGlobal);
								} else {
									GlobalFree(l_hGlobal);
								}
							}
						}
						CloseClipboard();
					}
					break;
				case CM_ANSIEDITPASTE:
					if (IsClipboardFormatAvailable(CF_TEXT)) {
						if (OpenClipboard(l_Term->aWnd)) {
							HGLOBAL l_hGlobal;
							l_hGlobal=GetClipboardData(CF_TEXT);
							if (l_hGlobal) {
								unsigned char *l_pp;
								l_pp=(unsigned char*)GlobalLock(l_hGlobal);
								if (l_pp) {
									/* insert text */
									atSendTermInput(l_Term,l_pp,strlen((char*)l_pp));
									/* phew, that wasn't so hard. */
									GlobalUnlock(l_hGlobal);
								}
							}
							CloseClipboard();
						}
					}
					break;
				case CM_ANSIOPTIONSTERMSET:
					if (DialogBoxParam(l_Term->aInst,MAKEINTRESOURCE(DIALOG_ATOPT),
						l_Term->aWnd,atAnsiTermOptionsProc,(LPARAM)l_Term)==IDOK)
						(*(l_Term->aNotify))(l_Term,TBNOTIFY_OPTIONS);
					return 0L;
				case CM_ANSIOPTIONSFNKEYS:
					{
					int l_i;
					unsigned char l_Macro[48][TBMACRO_MAXLEN];

					for (l_i=0;l_i<48;l_i++)
						strcpy((char*)l_Macro[l_i],(char*)l_Term->aFnKeyMacro[l_i]);
					if (DialogBoxParam(l_Term->aInst,MAKEINTRESOURCE(DIALOG_ATFNKEY),
						l_Term->aWnd,atATFnKeyProc,(LPARAM)l_Term)==IDOK) {
						(*(l_Term->aNotify))(l_Term,TBNOTIFY_MACROS);
					} else {
						/* restore macros */
						for (l_i=0;l_i<48;l_i++)
							strcpy((char*)l_Term->aFnKeyMacro[l_i],(char*)l_Macro[l_i]);
					}
					}
					return 0L;
				case CM_ANSIOPTIONSFONT:
					{
					CHOOSEFONT l_font;
					LOGFONT l_logfont;

					l_font.lStructSize=sizeof(CHOOSEFONT);
					l_font.hwndOwner=l_Term->aWnd;
					l_font.hDC=NULL;
					l_font.lpLogFont=&l_logfont;
					if (l_Term->aLogFontValid) {
						meMemCpy(&l_logfont,&(l_Term->aLogFont),sizeof(LOGFONT));
						l_font.Flags=CF_ANSIONLY|CF_FIXEDPITCHONLY|CF_INITTOLOGFONTSTRUCT|
							CF_SCREENFONTS|CF_SHOWHELP|CF_ENABLEHOOK;
					} else {
						l_font.Flags=CF_ANSIONLY|CF_FIXEDPITCHONLY|
							CF_SCREENFONTS|CF_SHOWHELP|CF_ENABLEHOOK;
					}
// N/A          l_font.rgbColours
// N/A          l_font.lCustData=0;
					((void*)(l_font.lpfnHook))=((void*)(dl3DSubClassProc));
					l_font.lpTemplateName=NULL;
					l_font.hInstance=NULL;
					l_font.lpszStyle=NULL;
					l_font.nFontType=0;
					l_font.nSizeMin=0;
					l_font.nSizeMax=0;
					if (ChooseFont(&l_font)) {
						/* we have a selection! */
						atChangeFont(l_Term,NULL,&l_logfont);
						(*(l_Term->aNotify))(l_Term,TBNOTIFY_FONT);
					}
					}
				default:
					break;
			}
			break;
		case WM_LBUTTONDBLCLK:
			break;
		case WM_RBUTTONDOWN:
			/* bring up our pop-up menu */
			l_menu=CreatePopupMenu();
			if (l_menu) {        // CM_ANSIEDITCOPY CM_ANSIEDITPASTE
				AppendMenu(l_menu,MF_ENABLED|MF_STRING,CM_ANSIEDITCOPY,"&Copy\tCtrl+Ins");
				if (IsClipboardFormatAvailable(CF_TEXT))
					AppendMenu(l_menu,MF_ENABLED|MF_STRING,CM_ANSIEDITPASTE,"&Paste\tShift+Ins");
				else
					AppendMenu(l_menu,MF_DISABLED|MF_GRAYED,CM_ANSIEDITPASTE,"&Paste\tShift+Ins");
				if (GetCursorPos(&l_point)) {
					TrackPopupMenu(l_menu,TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
					l_point.x,l_point.y,0,p_hWnd,NULL);
				}
				DestroyMenu(l_menu);
			}
			break;
		case WM_LBUTTONDOWN:
			/* start hilighting */
			if (!GetCursorPos(&l_point))
				break;
			ScreenToClient(l_Term->aWnd,&l_point);
			/* let's see if we're in our input line */
			if (l_Term->aSeparateInputLine) {
				if (l_point.y>l_Term->aScrollRect.bottom) {
					break;
				}
			}
			/* first thing we have to do is erase any pre-existing hilight area */
			tbClearHilight(l_Term->aTermBuf);
			InvalidateRect(l_Term->aWnd,NULL,FALSE);
			/* capture our mouse */
			SetCapture(p_hWnd);
			l_Term->aMouseHiliteCapture=TRUE;
			l_Term->aCaptureLastX=l_point.x;
			l_Term->aCaptureLastY=l_point.y;
			tbStartHilight(l_Term->aTermBuf,
				(l_point.x/l_Term->aFontX)+l_Term->aShowX,
				(l_point.y/l_Term->aFontY)+l_Term->aShowY);
			/* generate a timer to check on scrolling */
			SetTimer(l_Term->aWnd,1,100,NULL);
			dbPrint("WM_LBUTTONDOWN");
			break;
		case WM_LBUTTONUP:
			if (l_Term->aMouseHiliteCapture) {
				/* release our mouse */
				l_Term->aMouseHiliteCapture=FALSE;
				ReleaseCapture();
				KillTimer(l_Term->aWnd,1);
			}
			dbPrint("WM_LBUTTONUP");
			break;
		case WM_TIMER:
			if (l_Term->aMouseHiliteCapture) {
				l_i=0;
				if (l_Term->aCaptureLastY<0) {
					l_i=l_Term->aCaptureLastY;
					if (l_i<-25) {
						l_i+=15;
						l_i/=5;
					}	else {
						l_i=-1;
					}
					l_rect.left  =0;
					l_rect.right =l_Term->aFontX*l_Term->aSizeX;
					l_rect.top   =0;
					l_rect.bottom=((-l_i)+1)*l_Term->aFontY;
				} else if (l_Term->aCaptureLastY>l_Term->aFontY*l_Term->aSizeY) {
					l_i=(l_Term->aCaptureLastY-l_Term->aFontY*l_Term->aSizeY);
					if (l_i>25) {
						l_i-=15;
						l_i/=5;
					}	else {
						l_i=1;
					}
					l_rect.left  =0;
					l_rect.right =l_Term->aFontX*l_Term->aSizeX;
					l_rect.top   =l_Term->aFontY*((l_Term->aSizeY-l_i-1));
					l_rect.bottom=l_Term->aFontY*l_Term->aSizeY;
				}
				if (l_i) {
					atScrollTermTo(l_Term,1,l_i);
					l_j=((l_Term->aCaptureLastY/l_Term->aFontY)+l_Term->aShowY);
					if (l_j<l_Term->aSizeY-l_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES)
						l_j=l_Term->aSizeY-l_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES;
					tbUpdateHilight(l_Term->aTermBuf,
						(l_Term->aCaptureLastX/l_Term->aFontX)+l_Term->aShowX,
						l_j);
					InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
					SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
					atUpdateCaret(l_Term);
				}
			} else {
				KillTimer(l_Term->aWnd,p_wParam);
			}
			break;
		case WM_MOUSEMOVE:
			if (l_Term->aMouseHiliteCapture) {
				if (GetCursorPos(&l_point)) {
					/* capture our mouse */
					ScreenToClient(l_Term->aWnd,&l_point);
					l_i=(l_point.x/l_Term->aFontX)+l_Term->aShowX;
					l_j=(l_point.y/l_Term->aFontY)+l_Term->aShowY;
					if (l_j<l_Term->aSizeY-l_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES) { /* this is not necessary if termbuf handled scrollback=0 */
						l_j=l_Term->aSizeY-l_Term->aTermBuf->tBufY+ATIB_TERMBUF_EXTRALINES;     /* this is not necessary if termbuf handled scrollback=0 */
						l_i=0;                                                                  /* this is not necessary if termbuf handled scrollback=0 */
					}                                                                         /* this is not necessary if termbuf handled scrollback=0 */
					tbUpdateHilight(l_Term->aTermBuf,l_i,l_j);
					if (l_Term->aCaptureLastY>l_point.y) {
						l_rect.top=(l_point.y/l_Term->aFontY)*l_Term->aFontY;
						l_rect.bottom=(l_Term->aCaptureLastY/l_Term->aFontY+1)*l_Term->aFontY;
					} else {
						l_rect.top=(l_Term->aCaptureLastY/l_Term->aFontY)*l_Term->aFontY;
						l_rect.bottom=(l_point.y/l_Term->aFontY+1)*l_Term->aFontY;
					}
					l_rect.left=0;
					l_rect.right=l_Term->aSizeX*l_Term->aFontX;
					InvalidateRect(p_hWnd,&l_rect,FALSE);
					l_Term->aCaptureLastX=l_point.x;
					l_Term->aCaptureLastY=l_point.y;
				}
			}
			break;
		case WM_KEYDOWN:
			/* let's see if this is a function key macro */
			/* VIRTUAL KEY VALUES:
			 * ------------------
			 * PgUp   : 0x21
			 * PgDn   : 0x22
			 * End    : 0x23
			 * Home   : 0x24
			 * Ins    : 0x2D
			 * Del    : 0x2E
			 * F1-F12 : 0x70-0x7B
			 * CsrLft : 0x25
			 * CsrUp  : 0x26
			 * CsrRgt : 0x27
			 * CsrDn  : 0x28
			 * ------------------
			 */
			l_i=LOWORD(p_wParam);
			if ((l_i>=0x70)&&(l_i<=0x7B)) {
				l_i-=0x70;
				if (GetKeyState(VK_SHIFT)&0x00008000)
					l_i+=12;
				if (GetKeyState(VK_CONTROL)&0x00008000)
					l_i+=24;
				if (l_Term->aFnKeyMacro[l_i][0]) {
					/* we have a macro! */
					/* First, let's process this sucker into a proper string */
					l_j=0;
					for (l_j=0;(l_j<TBMACRO_MAXLEN)&&(l_Term->aFnKeyMacro[l_i][l_j]);l_j++) {
						if (l_Term->aFnKeyMacro[l_i][l_j]=='\\') {
							l_j++;
							if ((l_j<TBMACRO_MAXLEN)&&(l_Term->aFnKeyMacro[l_i][l_j])) {
								if ((l_Term->aFnKeyMacro[l_i][l_j]=='a')||
										(l_Term->aFnKeyMacro[l_i][l_j]=='A')) {
									l_buf[0]=0x07;
									atSendTermInput(l_Term,l_buf,1);
								} else if ((l_Term->aFnKeyMacro[l_i][l_j]=='b')||
										(l_Term->aFnKeyMacro[l_i][l_j]=='B')) {
									l_buf[0]=0x08;
									atSendTermInput(l_Term,l_buf,1);
								} else if ((l_Term->aFnKeyMacro[l_i][l_j]=='t')||
										(l_Term->aFnKeyMacro[l_i][l_j]=='T')) {
									l_buf[0]=0x09;
									atSendTermInput(l_Term,l_buf,1);
								} else if ((l_Term->aFnKeyMacro[l_i][l_j]=='n')||
										(l_Term->aFnKeyMacro[l_i][l_j]=='N')) {
									l_buf[0]=0x0D; /* should be 0x0A, but people will want it to be 0x0D */
									atSendTermInput(l_Term,l_buf,1);
								} else if ((l_Term->aFnKeyMacro[l_i][l_j]=='r')||
										(l_Term->aFnKeyMacro[l_i][l_j]=='R')) {
									l_buf[0]=0x0D;
									atSendTermInput(l_Term,l_buf,1);
								} else if (l_Term->aFnKeyMacro[l_i][l_j]=='\\'){
									l_buf[0]='\\';
									atSendTermInput(l_Term,l_buf,1);
								} /* else ignore it */
							} else {
								break;
							}
						} else {
							atSendTermInput(l_Term,&(l_Term->aFnKeyMacro[l_i][l_j]),1);
						}
					}
					return 0L;
				} else {
					if (l_Term->aSeparateInputLine) {
						return 0L;
					}
					/* send function key sequence */
					if ((l_i>=0)&&(l_i<=4)) {
						l_buf[0]=(unsigned char)ASCII_ESC;
						l_buf[1]=(unsigned char)'[';
						l_buf[2]=(unsigned char)'[';
						l_buf[3]=(unsigned char)('A'+l_i);
						atSendTermInput(l_Term,l_buf,4);
					} else if ((l_i>=5)&&(l_i<=11)) {
						if (l_i>=10) l_i++;
						sprintf((char*)l_buf," [%02i~",l_i+12);
						l_buf[0]=(unsigned char)ASCII_ESC;
						atSendTermInput(l_Term,l_buf,5);
					} /* else don't know what to do with it */
				}
			} else if (l_i==0x21) { /* Page UP */
				if (l_Term->aSeparateInputLine) {
					atScrollTermTo(l_Term,1,-(l_Term->aTermBuf->tScrY-1));
					SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
				} else if (GetKeyState(VK_SHIFT)&0x00008000) {
					atScrollTermTo(l_Term,1,-(l_Term->aTermBuf->tScrY-1));
					SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
          atUpdateCaret(l_Term);
				} else {
					/* send PGUP */
					l_buf[0]=(unsigned char)ASCII_ESC;
					l_buf[1]=(unsigned char)'[';
					l_buf[2]=(unsigned char)'5';
					l_buf[3]=(unsigned char)'~';
					atSendTermInput(l_Term,l_buf,4);
				}
			} else if (l_i==0x22) { /* Page DOWN */
				if (l_Term->aSeparateInputLine) {
					atScrollTermTo(l_Term,1,l_Term->aTermBuf->tScrY-1);
					SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
				} else if (GetKeyState(VK_SHIFT)&0x00008000) {
					atScrollTermTo(l_Term,1,l_Term->aTermBuf->tScrY-1);
					SetScrollPos(p_hWnd,SB_VERT,l_Term->aShowY,TRUE);
					atUpdateCaret(l_Term);
				} else {
					/* send PGDN */
					l_buf[0]=(unsigned char)ASCII_ESC;
					l_buf[1]=(unsigned char)'[';
					l_buf[2]=(unsigned char)'6';
					l_buf[3]=(unsigned char)'~';
					atSendTermInput(l_Term,l_buf,4);
				}
			} else if (l_i==0x23) { /* END */
				if (l_Term->aSeparateInputLine) {
					if (*l_Term->aInputCurPos) {
						while(*(l_Term->aInputCurPos)) {
							/* increment the sucker */
							l_Term->aInputCurPos=ATIB_NEXTCHAR(l_Term,l_Term->aInputCurPos);
							if (l_Term->aInputCurPos==ATIB_ADDCHAR(l_Term,
								l_Term->aInputDispCurPos,l_Term->aTermBuf->tScrX)) {
								/* also scroll input line forward one */
								l_Term->aInputDispCurPos=ATIB_NEXTCHAR(l_Term,l_Term->aInputDispCurPos);
							}
						}
						GetClientRect(l_Term->aWnd,&l_rect);
						l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
						InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
						atUpdateCaret(l_Term);
					}
					return 0L;
				}
				/* send END */
				l_buf[0]=(unsigned char)ASCII_ESC;
				l_buf[1]=(unsigned char)'[';
				l_buf[2]=(unsigned char)'4';
				l_buf[3]=(unsigned char)'~';
				atSendTermInput(l_Term,l_buf,4);
			} else if (l_i==0x24) { /* HOME */
				if (l_Term->aSeparateInputLine) {
					if (l_Term->aInputCurPos!=l_Term->aInputCurLine) {
						l_Term->aInputCurPos=l_Term->aInputCurLine;
						l_Term->aInputDispCurPos=l_Term->aInputCurLine;
						GetClientRect(l_Term->aWnd,&l_rect);
						l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
						InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
						atUpdateCaret(l_Term);
					}
					return 0L;
				}
				/* send Home */
				l_buf[0]=(unsigned char)ASCII_ESC;
				l_buf[1]=(unsigned char)'[';
				l_buf[2]=(unsigned char)'H';
				atSendTermInput(l_Term,l_buf,3);
//				/* send HOME */
//				l_buf[0]=(unsigned char)ASCII_ESC;
//				l_buf[1]=(unsigned char)'[';
//				l_buf[2]=(unsigned char)'1';
//				l_buf[2]=(unsigned char)'~';
//				atSendTermInput(l_Term,l_buf,4);
			} else if (l_i==0x25) { /* Cursor LEFT */
				if (l_Term->aSeparateInputLine) {
					if (l_Term->aInputCurPos!=l_Term->aInputCurLine) {
						if (l_Term->aInputCurPos==l_Term->aInputDispCurPos) {
							/* also scroll input line back one */
							l_Term->aInputDispCurPos=ATIB_PREVCHAR(l_Term,l_Term->aInputDispCurPos);
							GetClientRect(l_Term->aWnd,&l_rect);
							l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
							InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
						}
						l_Term->aInputCurPos=ATIB_PREVCHAR(l_Term,l_Term->aInputCurPos);
						atUpdateCaret(l_Term);
					}
					return 0L;
				}
				/* send ASCII Crsr Left */
				l_buf[0]=(unsigned char)ASCII_ESC;
				l_buf[1]=(unsigned char)'[';
				l_buf[2]=(unsigned char)'D';
				atSendTermInput(l_Term,l_buf,3);
			} else if (l_i==0x27) { /* Cursor RIGHT */
				if (l_Term->aSeparateInputLine) {
					if (*(l_Term->aInputCurPos)) {
						l_Term->aInputCurPos=ATIB_NEXTCHAR(l_Term,l_Term->aInputCurPos);
						if (l_Term->aInputCurPos==ATIB_ADDCHAR(l_Term,
							l_Term->aInputDispCurPos,l_Term->aTermBuf->tScrX)) {
							/* also scroll input line forward one */
							l_Term->aInputDispCurPos=ATIB_NEXTCHAR(l_Term,l_Term->aInputDispCurPos);
							GetClientRect(l_Term->aWnd,&l_rect);
							l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
							InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
						}
						atUpdateCaret(l_Term);
					}
					return 0L;
				}
				/* send ASCII Crsr Right */
				l_buf[0]=(unsigned char)ASCII_ESC;
				l_buf[1]=(unsigned char)'[';
				l_buf[2]=(unsigned char)'C';
				atSendTermInput(l_Term,l_buf,3);
			} else if (l_i==0x26) { /* Cursor UP */
				/* send ASCII Crsr Up */
				if (l_Term->aSeparateInputLine) {
					/* advance one command back and copy this to our current buffer */
					if (l_Term->aInputScrollBackPos!=l_Term->aInputCurLineEnd) {
						/* first, find our previous command in the history */
						l_p=ATIB_PREVCHAR(l_Term,l_Term->aInputScrollBackPos);
						l_p=ATIB_PREVCHAR(l_Term,l_p);
						/* find the start of this command & count characters */
						l_i=0;
						while(*l_p) {
							l_p=ATIB_PREVCHAR(l_Term,l_p);
							l_i++;
						}
						/* we are one past the start of our command... */
						l_p=ATIB_NEXTCHAR(l_Term,l_p);
						/* we don't need to adjust l_i kuz we started 1 lower than we should have */
						if (l_p!=l_Term->aInputCurLine) {
							/* this is a valid command. Let's count the size of our current
							 * input line and ensure there's enuf space to copy this command over */
							l_q=l_Term->aInputCurLine;
							while((l_i) && (l_q!=l_p)) {
								l_q=ATIB_NEXTCHAR(l_Term,l_q);
								l_i--;
							}
							if (l_q!=l_p) {
								/* there's enough space -- let's copy this sucker over and update
								 * our scroll back position */
								l_Term->aInputScrollBackPos=l_p;
								/* clear current input line */
								for (l_q=l_Term->aInputCurLine;
										 l_q!=l_Term->aInputCurLineEnd;
										 l_q=ATIB_NEXTCHAR(l_Term,l_q))
									*l_q=0x00;
								l_Term->aInputCurPos=l_Term->aInputDispCurPos=l_Term->aInputCurLine;
								/* copy history cmd into our current input buffer */
								for (l_q=l_p;*l_q;l_q=ATIB_NEXTCHAR(l_Term,l_q))
									atSendTermInput(l_Term,l_q,1);
								/* now refresh line */
								GetClientRect(l_Term->aWnd,&l_rect);
								l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
								InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
							} /* else our buffer isn't big enuf for previous cmd -- ignore */
						}
					} /* else there is no previous cmd */
				} else {
					l_buf[0]=(unsigned char)ASCII_ESC;
					l_buf[1]=(unsigned char)'[';
					l_buf[2]=(unsigned char)'A';
					atSendTermInput(l_Term,l_buf,3);
				}
			} else if (l_i==0x28) { /* Cursor DOWN */
				/* send ASCII Crsr Down */
				if (l_Term->aSeparateInputLine) {
					/* advance one command forward and copy this to our current buffer */
					if (l_Term->aInputScrollBackPos!=l_Term->aInputCurPos) {
						/* first, find our next command in the history */
						l_p=l_Term->aInputScrollBackPos;
						while (*l_p) {
							l_p=ATIB_NEXTCHAR(l_Term,l_p);
						}
						l_p=ATIB_NEXTCHAR(l_Term,l_p); /* get past ending 0x00 */
						l_Term->aInputScrollBackPos=l_p;
						if (l_Term->aInputScrollBackPos!=l_Term->aInputCurPos) {
							/* clear current input line */
							for (l_q=l_Term->aInputCurLine;
								 l_q!=l_Term->aInputCurLineEnd;
								 l_q=ATIB_NEXTCHAR(l_Term,l_q))
								*l_q=0x00;
							l_Term->aInputCurPos=l_Term->aInputDispCurPos=l_Term->aInputCurLine;
							/* copy history cmd into our current input buffer */
							for (l_q=l_p;*l_q;l_q=ATIB_NEXTCHAR(l_Term,l_q))
								atSendTermInput(l_Term,l_q,1);
							/* now refresh line */
							GetClientRect(l_Term->aWnd,&l_rect);
							l_rect.top=l_rect.bottom-l_Term->aInputWndDY;
							InvalidateRect(l_Term->aWnd,&l_rect,FALSE);
						}
					}
				} else {
					l_buf[0]=(unsigned char)ASCII_ESC;
					l_buf[1]=(unsigned char)'[';
					l_buf[2]=(unsigned char)'B';
					atSendTermInput(l_Term,l_buf,3);
				}
			} else if (l_i==0x2D) { /* INS */
				if (GetKeyState(VK_SHIFT)&0x00008000) {
					/* paste */
					FORWARD_WM_COMMAND(p_hWnd,CM_ANSIEDITPASTE,NULL,0,PostMessage);
				}	else if (GetKeyState(VK_CONTROL)&0x00008000) {
					/* copy */
					FORWARD_WM_COMMAND(p_hWnd,CM_ANSIEDITCOPY,NULL,0,PostMessage);
				} else {
				/* send INS */
				l_buf[0]=(unsigned char)ASCII_ESC;
				l_buf[1]=(unsigned char)'[';
				l_buf[2]=(unsigned char)'2';
				l_buf[3]=(unsigned char)'~';
				atSendTermInput(l_Term,l_buf,4);
				}
			} else if (l_i==0x2E) { /* DEL */
				/* pass on DEL keystroke */
				l_buf[0]=(unsigned char)ASCII_DEL;
				atSendTermInput(l_Term,l_buf,1);
				return 0L;
//				/* send DEL */
//				l_buf[0]=(unsigned char)ASCII_ESC;
//				l_buf[1]=(unsigned char)'[';
//				l_buf[2]=(unsigned char)'3';
//				l_buf[2]=(unsigned char)'~';
//				atSendTermInput(l_Term,l_buf,4);
			}
			break;
//      sprintf(l_buf,"WM_KEYDOWN: %04X repeat %i, scan code %02X, %s, %s %s %s",
//        p_wParam,p_lParam&(0x0000FFFF),(p_lParam&0x00FF0000)>>16,
//        (p_lParam&0x01000000)?"extended":"not extended",
//        (p_lParam&(1<<29))?" ALT ":"",l_i&0x8000?"SHIFT":"",l_j&0x8000?"CONTROL":"");
//      dbPrint(l_buf);

		case WM_CHAR:
			l_buf[0]=(unsigned char)p_wParam;
			atSendTermInput(l_Term,l_buf,1);
			/* return moves scroll back to normal position */
			if (((unsigned char)p_wParam)==ASCII_CR)
				atScrollTermTo(l_Term,0,0);
//      if (!(p_lParam&0x01000000)) {
//        /* regular key stroke */
//        l_buf[0]=(unsigned char)p_wParam;
//        atSendTermInput(l_Term,l_buf,1);
//      }
			return 0L;
//      sprintf((char*)l_buf,"WM_CHAR: %04X repeat %i, scan code %02X, %s, %s ",
//        p_wParam,p_lParam&(0x0000FFFF),(p_lParam&0x00FF0000)>>16,
//        (p_lParam&0x01000000)?"extended":"not extended",
//        (p_lParam&(1<<29))?" ALT ":"");
//      dbPrint((char*)l_buf);
		case WM_PAINT:
//			if (IsIconic(p_hWnd))
//				break;
			/* first, check for scrolling */
			if (l_Term->aScroll) {
				if (l_Term->aSeparateInputLine)
					ScrollWindow(l_Term->aWnd,0,l_Term->aScroll,
						&(l_Term->aScrollRect),&(l_Term->aScrollRect));
				else
					ScrollWindow(l_Term->aWnd,0,l_Term->aScroll,NULL,NULL);
				l_Term->aScroll=0;
			}
			/* Paint window */
			if (GetUpdateRect(p_hWnd,&l_rect,TRUE)) { /* get new update region */
				l_hDC=BeginPaint(p_hWnd,&l_ps);
				l_oldFont=SelectObject(l_hDC,l_Term->aFont);
				/* first, determine our line numbers to update */
				if (l_Term->aSeparateInputLine) {
					if (l_rect.top < l_Term->aScrollRect.bottom) {
						l_startY=(l_rect.top/l_Term->aFontY)+l_Term->aShowY;
					} else {
						l_startY=-1;
					}
					if (l_rect.bottom < l_Term->aScrollRect.bottom) {
						l_endY=((l_rect.bottom+l_Term->aFontY-1)/l_Term->aFontY)+l_Term->aShowY;
					} else {
						l_endY=((l_Term->aScrollRect.bottom-1)/l_Term->aFontY)+l_Term->aShowY;

						/* paint input line */
						l_startX=(l_rect.left/l_Term->aFontX);
						l_endX=((l_rect.right+l_Term->aFontX-1)/l_Term->aFontX);

						SetBkColor(l_hDC,l_Term->aTermBuf->tColourBank[l_Term->aInputBColour]);
						SetTextColor(l_hDC,l_Term->aTermBuf->tColourBank[l_Term->aInputFColour]);

						l_p=l_Term->aInputDispCurPos;
						for (l_x=0;l_x<l_startX;l_x++) {
							if (*l_p)
								l_p++;
						}
						l_count=0;
						for (l_x=l_startX;l_x<l_endX;l_x++) {
							if (*l_p) {
								l_buf[l_count]=*l_p;
								l_p=ATIB_NEXTCHAR(l_Term,l_p);
							} else {
								l_buf[l_count]=' ';
							}
							l_count++;
						}
						TextOut(l_hDC,l_startX*l_Term->aFontX,
							(l_Term->aScrollRect.bottom+l_Term->aInputBorderDY),
							(LPCSTR)l_buf,l_count);

						/* and don't forget to paint the separation line accross the screen */
						l_oldPen=SelectObject(l_hDC,GetStockObject(WHITE_PEN));
						MoveToEx(l_hDC,l_rect.left,l_Term->aScrollRect.bottom+1,NULL);
						LineTo(l_hDC,l_rect.right,l_Term->aScrollRect.bottom+1);
						SelectObject(l_hDC,l_oldPen);
					}
				} else {
					l_startY=(l_rect.top/l_Term->aFontY)+l_Term->aShowY;
					l_endY=((l_rect.bottom-1)/l_Term->aFontY)+l_Term->aShowY;
				}
				l_startX=(l_rect.left/l_Term->aFontX)+l_Term->aShowX;
				l_endX=((l_rect.right-1)/l_Term->aFontX)+l_Term->aShowX;
				if (l_startX>TB_GETXMAX(l_Term->aTermBuf))
					l_startX=TB_GETXMAX(l_Term->aTermBuf);
				if (l_endX>TB_GETXMAX(l_Term->aTermBuf))
					l_endX=TB_GETXMAX(l_Term->aTermBuf);
				if (l_startY>TB_GETYMAX(l_Term->aTermBuf))
					l_startY=TB_GETYMAX(l_Term->aTermBuf);
				if (l_endY>TB_GETYMAX(l_Term->aTermBuf))
					l_endY=TB_GETYMAX(l_Term->aTermBuf);
				/* paint rest of screen, if required */
				/* first, let's make sure we're using the correct colour -- we do this by
				 * ensuring we have the WRONG attrib */
				l_rawCharP=TB_GETCHARADDR(l_Term->aTermBuf,l_startX,l_startY);
				if (IsBadReadPtr(l_rawCharP,1)) {
#ifndef DB_DEBUG_NODEBUG
					sprintf((char*)l_buf,"SNAG!!! =========================== x=%i y=%i bx=%i by=%i",
						l_startX,l_startY,l_Term->aTermBuf->tScrX,l_Term->aTermBuf->tScrY);
					dbPrint((char*)l_buf);
#endif
				} else {
					l_rawChar=*l_rawCharP;
					l_attrib=l_rawChar&(TB_EFFECTMASK|TB_BCOLOURMASK|TB_FCOLOURMASK);
					l_attrib^=0xFFFFFFFFL;
					l_count=0; /* l_count counts how many characters we have in our buffer so far */
					for (l_y=l_startY;l_y<=l_endY;l_y++) {
						for (l_x=l_startX;l_x<=l_endX;l_x++) {
							/* print this character */
							l_rawCharP=TB_GETCHARADDR(l_Term->aTermBuf,l_x,l_y);
							if (!IsBadReadPtr(l_rawCharP,1)) {
								l_rawChar=*l_rawCharP;
							} else {
								dbPrint("SNAG TOO!!!!! ////////////////////////////////////");
								l_rawChar=TB_MAKEEFFECT(0)|TB_MAKEBCOLOUR(0)|TB_MAKEFCOLOUR(7)|TB_MAKECHAR(0x20);
							}
							if (tbIsHilight(l_Term->aTermBuf,l_x,l_y)) {
								l_rawChar^=(TB_BCOLOURMASK|TB_FCOLOURMASK);
							}
							if ((l_attrib!=(l_rawChar&(TB_EFFECTMASK|TB_BCOLOURMASK|TB_FCOLOURMASK)))||
								(l_count>=(ATANSITERMPROCBUFSIZE-1))) {
								if (l_count) {
									if (l_Term->aFontUnderline) {
										/* check for underline */
										if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
											SelectObject(l_hDC,l_Term->aFontUnderline);
											TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
												(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
											SelectObject(l_hDC,l_Term->aFont);
										} else {
											TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
											(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
										}
									} else {
										TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
											(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
										/* check for underline */
										if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
											l_oldPen=SelectObject(l_hDC,
												l_Term->aTermBuf->tColourPen[l_i]);
											MoveToEx(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
												(l_y-l_Term->aShowY+1)*l_Term->aFontY-1,NULL);
											LineTo(l_hDC,(l_x-l_Term->aShowX+1)*l_Term->aFontX,
												(l_y-l_Term->aShowY+1)*l_Term->aFontY-1);
											l_oldPen=SelectObject(l_hDC,l_oldPen);
										}
									}
									l_count=0;
								}


//								if ((l_attrib&TB_BCOLOURMASK)!=(l_rawChar&TB_BCOLOURMASK)) {
//									SetBkColor(l_hDC,l_Term->aTermBuf->tColourBank[TB_EXTBCOLOUR(l_rawChar)]);
//								}
//								if ((l_attrib&TB_FCOLOURMASK)!=(l_rawChar&TB_FCOLOURMASK)) {
//									SetTextColor(l_hDC,l_Term->aTermBuf->tColourBank[TB_EXTFCOLOUR(l_rawChar)]);
//								}
//								if ((l_attrib&TB_EFFECTMASK)!=(l_rawChar&TB_EFFECTMASK)) {
								l_i=TB_EXTFCOLOUR(l_rawChar);
								l_j=TB_EXTBCOLOUR(l_rawChar);
								if (TB_EXTEFFECT(l_rawChar)&AT_FONTEFFECT_BOLD) {
									l_i|=0x08;
								}
//									if (TB_EXTEFFECT(l_rawChar)&AT_FONTEFFECT_UNDERLINE) {
//									} else {
//									}
								if (TB_EXTEFFECT(l_rawChar)&AT_FONTEFFECT_BLINK) {
									l_j|=0x08;
								}
								if (TB_EXTEFFECT(l_rawChar)&AT_FONTEFFECT_REVERSE) {
									/* this is a bit complicated */
									if (l_i==0x08)
										l_i=0x00;
									else
										l_i^=0x07;
									if (l_j==0x08)
										l_j=0x00;
									else
										l_j^=0x07;
								}
								SetTextColor(l_hDC,l_Term->aTermBuf->tColourBank[l_i]);
								SetBkColor(l_hDC,l_Term->aTermBuf->tColourBank[l_j]);
//								}
								l_attrib=(l_rawChar&(TB_EFFECTMASK|TB_BCOLOURMASK|TB_FCOLOURMASK));
							}
							l_buf[l_count]=(char)TB_EXTCHAR(l_rawChar);
							l_count++;
							/* Note: The following commented-out code used to draw the
							 * screen one character at a time. This was deathly slow.
							 * Therefore, I copied this to two places: above, and below. */
//							if (l_Term->aFontUnderline) {
//								/* check for underline */
//								if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
//									SelectObject(l_hDC,l_Term->aFontUnderline);
//									TextOut(l_hDC,(l_x-l_Term->aShowX)*l_Term->aFontX,
//										(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,1);
// 									SelectObject(l_hDC,l_Term->aFont);
//								} else {
//									TextOut(l_hDC,(l_x-l_Term->aShowX)*l_Term->aFontX,
// 										(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,1);
//								}
//							} else {
//								TextOut(l_hDC,(l_x-l_Term->aShowX)*l_Term->aFontX,
//									(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,1);
//								/* check for underline */
//								/* actually, I should swap in a new font... but one is,
// 								 * for whatever reason, unavailable. So I fake it. */
//								if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
//									l_oldPen=SelectObject(l_hDC,
// 										l_Term->aTermBuf->tColourPen[l_i]);
//									MoveToEx(l_hDC,(l_x-l_Term->aShowX)*l_Term->aFontX,
//										(l_y-l_Term->aShowY+1)*l_Term->aFontY-1,NULL);
//									LineTo(l_hDC,(l_x-l_Term->aShowX+1)*l_Term->aFontX,
//										(l_y-l_Term->aShowY+1)*l_Term->aFontY-1);
//									l_oldPen=SelectObject(l_hDC,l_oldPen);
//								}
//							}
						}
						if (l_count) {
							if (l_Term->aFontUnderline) {
								/* check for underline */
								if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
									SelectObject(l_hDC,l_Term->aFontUnderline);
									TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
										(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
									SelectObject(l_hDC,l_Term->aFont);
								} else {
									TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
										(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
								}
							} else {
								TextOut(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
									(l_y-l_Term->aShowY)*l_Term->aFontY,(LPCSTR)l_buf,l_count);
								/* check for underline */
								if (l_attrib&TB_MAKEEFFECT(AT_FONTEFFECT_UNDERLINE)) {
									l_oldPen=SelectObject(l_hDC,
										l_Term->aTermBuf->tColourPen[l_i]);
									MoveToEx(l_hDC,(l_x-l_count-l_Term->aShowX)*l_Term->aFontX,
										(l_y-l_Term->aShowY+1)*l_Term->aFontY-1,NULL);
									LineTo(l_hDC,(l_x-l_Term->aShowX+1)*l_Term->aFontX,
										(l_y-l_Term->aShowY+1)*l_Term->aFontY-1);
									l_oldPen=SelectObject(l_hDC,l_oldPen);
								}
							}
							l_count=0;
						}
					}
				}
				SelectObject(l_hDC,l_oldFont);
				EndPaint(p_hWnd,&l_ps);
			}
			atUpdateCaret(l_Term);
			return 0L;
		case WM_SETFOCUS:
			CreateCaret(p_hWnd, NULL, (l_Term->aFontX)>>1, l_Term->aFontY);
			atUpdateCaret(l_Term);
			return 0L;
		case WM_KILLFOCUS:
			DestroyCaret();
			return 0L;
		case WM_DESTROY:
			enSaveWindowPlacement(l_Term->aEnvSection,l_Term->aWnd);
			return 0L;
		case WM_WINDOWPOSCHANGING:
			/* let's adjust our cx and cy so that our window is perfectly
			 * aligned with our row/column borders and we don't have any
			 * columns/rows half-displayed. */
			if (((WINDOWPOS*)(p_lParam))->flags&SWP_NOSIZE)
				break;
			if (IsIconic(p_hWnd))
				break;

			l_i=(((WINDOWPOS*)(p_lParam))->cx)-2*GetSystemMetrics(SM_CXFRAME)-
				GetSystemMetrics(SM_CXVSCROLL)+GetSystemMetrics(SM_CXBORDER);
			l_j=(((WINDOWPOS*)(p_lParam))->cy)-2*GetSystemMetrics(SM_CYFRAME)-
				GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENU);

			/* make our adjustment for our input line */
  		if (l_Term->aSeparateInputLine) {
        l_j-=(l_Term->aInputWndDY+l_Term->aInputBorderDY);
        if (l_j<0)
          l_j=0;
      }

			/* calculate our closest dimentions */
			l_x=(l_i+(l_Term->aFontX/2))/l_Term->aFontX;
			l_y=(l_j+(l_Term->aFontY/2))/l_Term->aFontY;
			if (l_x<ATIB_MINX)
				l_x=ATIB_MINX;
			if (l_y<ATIB_MINY)
        l_y=ATIB_MINY;

			/* while here, update our recorded scroll region */
			l_Term->aScrollRect.left=0;
			l_Term->aScrollRect.top=0;
			l_Term->aScrollRect.right=l_x*l_Term->aFontX;
			l_Term->aScrollRect.bottom=l_y*l_Term->aFontY;

			/* now get column and row "remainders */
			l_i-=(l_x*l_Term->aFontX);
			l_j-=(l_y*l_Term->aFontY);

			/* and make changes to the WINDOWPOS struct */
			((WINDOWPOS*)(p_lParam))->cx-=l_i;
			((WINDOWPOS*)(p_lParam))->cy-=l_j;

			/* and then let the window handler continue it's job */
			break;
		case WM_SIZE:
			if (IsIconic(p_hWnd))
				break;
			atAdjustTerm(l_Term,-1);
			atUpdateCaret(l_Term);
			break;
		default:
			break;
		}
	if (l_Term)
		if (l_Term->aAuxMsgHandler)
			return (*(l_Term->aAuxMsgHandler))(l_Term,p_hWnd,p_message,p_wParam,p_lParam);
	return (DefWindowProc(p_hWnd, p_message, p_wParam, p_lParam));
	}

/* This proc allows a higher module to fetch data from the user input buffer,
 * presumably to send it to a socket */
long atReadTermInput(ATTERM *p_Term, unsigned char *p_Buf, unsigned long p_BufLen) {
	unsigned long l_i;

	if (!p_Term)
		return 0L;
	l_i=0;
	while ((p_Term->aOutBufSockTail!=p_Term->aOutBufHead)&&(l_i<p_BufLen)) {
		p_Buf[l_i]=*(p_Term->aOutBufSockTail);
		l_i++;
		p_Term->aOutBufSockTail++;
		if ((p_Term->aOutBufSockTail-p_Term->aOutBuf)>=p_Term->aOutBufSize)
			p_Term->aOutBufSockTail=p_Term->aOutBuf;
	}
	return l_i;
}

long atUnReadTermInput(ATTERM *p_Term, unsigned char *p_Buf, unsigned long p_BufLen) {
	unsigned long l_i;

	if (!p_Term)
		return 0L;
	l_i=0;
	while ((p_Term->aOutBufSockTail!=p_Term->aOutBufHead)&&(l_i<p_BufLen)) {
		p_Term->aOutBufSockTail--;
		if (p_Term->aOutBufSockTail<p_Term->aOutBuf)
			p_Term->aOutBufSockTail+=p_Term->aOutBufSize;
		*(p_Term->aOutBufSockTail)=p_Buf[l_i];
		l_i++;
	}
	return l_i;
}

/* This proc inserts a string into the output buffer for the terminal. */
long atWriteTermInput(ATTERM *p_Term, unsigned char *p_Buf, unsigned long p_BufLen) {
	unsigned long l_i;

	l_i=0;
	if (p_Term) {
		while (l_i<p_BufLen) {
			*(p_Term->aOutBufHead)=p_Buf[l_i];
			l_i++;
			(p_Term->aOutBufHead)++;
			if ((p_Term->aOutBufHead-p_Term->aOutBuf)>=p_Term->aOutBufSize)
				p_Term->aOutBufHead=p_Term->aOutBuf;
			if (p_Term->aOutBufHead==p_Term->aOutBufSockTail) {
				p_Term->aOutBufHead--;
				if (p_Term->aOutBufHead<p_Term->aOutBuf)
					p_Term->aOutBufHead=p_Term->aOutBuf+p_Term->aOutBufSize-1;
				l_i--;
				break;
			}
		}
	}
	return l_i;
}

/* This proc processes a string as though the user typed it. */
void atSendTermInput(ATTERM *p_Term, unsigned char *p_Buf, unsigned long p_BufLen) {
	int l_i;
	unsigned char l_outStr[256];
  unsigned char *l_p,*l_q;
  RECT l_rect;

	if (p_Term) {
    if (p_Term->aSeparateInputLine) {
      for (l_i=0;l_i<p_BufLen;l_i++) {
        if (p_Buf[l_i]==p_Term->aDeleteChar) {
          /* delete next character after cursor (if there is one) */
          l_p=p_Term->aInputCurPos;
          while(*l_p) {
            l_q=ATIB_NEXTCHAR(p_Term,l_p);
            *l_p=*l_q;
            l_p=l_q;
					}
          /* now refresh line -- from cursor on */
          GetClientRect(p_Term->aWnd,&l_rect);
          l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
          l_rect.left=p_Term->aFontX*(p_Term->aInputCurPos-p_Term->aInputDispCurPos);
					InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
				} else if (p_Buf[l_i]==p_Term->aBackSpaceChar) {
					/* delete previous character from cursor (if there is one) */
					if (p_Term->aInputCurPos!=p_Term->aInputCurLine) {
						l_p=ATIB_PREVCHAR(p_Term,p_Term->aInputCurPos);
						p_Term->aInputCurPos=l_p;
						while(*l_p) {
							l_q=ATIB_NEXTCHAR(p_Term,l_p);
							*l_p=*l_q;
							l_p=l_q;
						}
						/* now refresh line -- from cursor on */
						GetClientRect(p_Term->aWnd,&l_rect);
						l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
						l_rect.left=p_Term->aFontX*(p_Term->aInputCurPos-p_Term->aInputDispCurPos);
						InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
					}
				} else if (p_Buf[l_i]==ASCII_CR) {
					l_q=l_outStr;
					for (l_p=p_Term->aInputCurLine;(*l_p);l_p=ATIB_NEXTCHAR(p_Term,l_p)) {
						*l_q=*l_p;
						l_q++;
						if (l_q-l_outStr>250) {
							/* send this chunk and then continue */
							*l_q=0;
							atWriteTermInput(p_Term,(unsigned char*)l_outStr,l_q-l_outStr);
							if (p_Term->aVLocalEcho) {
								atSendTerm(p_Term,l_outStr,l_q-l_outStr);
							}
							l_q=l_outStr;
						}
          }
          if (l_q!=l_outStr) {
            atWriteTermInput(p_Term,(unsigned char*)l_outStr,l_q-l_outStr);
            if (p_Term->aVLocalEcho) {
              atSendTerm(p_Term,l_outStr,l_q-l_outStr);
            }
          }
          /* now send return */
          l_q=l_outStr;
          *l_q=ASCII_CR;
          l_q++;
          if (p_Term->aLFwithNLMode) {
            *l_q=ASCII_LF;
            l_q++;
          }
          atWriteTermInput(p_Term,(unsigned char*)l_outStr,l_q-l_outStr);
          if (p_Term->aVLocalEcho) {
            atSendTerm(p_Term,l_outStr,l_q-l_outStr);
          }
          (*(p_Term->aNotify))(p_Term,TBNOTIFY_USERINPUT);
					/* now advance our input line */
					for (l_p=p_Term->aInputCurLine;*l_p;l_p=ATIB_NEXTCHAR(p_Term,l_p));
					/* note: l_p should be pointing to our 0x00 terminator for this line */
					if (l_p!=p_Term->aInputCurLine) /* check for null line - don't want'em in our history */
	          l_p=ATIB_NEXTCHAR(p_Term,l_p);
          /* l_p now points to the first character of our new line */
          *l_p=0x00;
          p_Term->aInputCurLine=l_p;
          p_Term->aInputCurPos=l_p;
          p_Term->aInputDispCurPos=l_p;
          while(!(*l_p)) {
            l_p=ATIB_NEXTCHAR(p_Term,l_p);
          }
					p_Term->aInputCurLineEnd=l_p;
					p_Term->aInputScrollBackPos=p_Term->aInputCurLine;
          /* and finally, redraw input line */
          GetClientRect(p_Term->aWnd,&l_rect);
          l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
					InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
          atUpdateCaret(p_Term);
				} else {
          /* insert character into line */
          l_p=p_Term->aInputCurPos;
          if (*l_p==0x00) {
            *(p_Term->aInputCurPos)=p_Buf[l_i];
            /* invalidate that region of the screen */
            GetClientRect(p_Term->aWnd,&l_rect);
            l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
            l_rect.left=p_Term->aFontX*(p_Term->aInputCurPos-p_Term->aInputDispCurPos);
            l_rect.right=l_rect.left+p_Term->aFontX;
            InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
            atUpdateCaret(p_Term);
						l_p=ATIB_NEXTCHAR(p_Term,p_Term->aInputCurPos);
            p_Term->aInputCurPos=l_p;
          } else {
            /* we have to first move the existing line over one, from the cursor on */
            l_p=ATIB_PREVCHAR(p_Term,p_Term->aInputCurLineEnd);
            while(l_p!=p_Term->aInputCurPos) {
              l_q=ATIB_PREVCHAR(p_Term,l_p);
              *l_p=*l_q;
              l_p=l_q;
            }
            *(p_Term->aInputCurPos)=p_Buf[l_i];
            /* invalidate that region of the screen - from that char to end of line */
            GetClientRect(p_Term->aWnd,&l_rect);
            l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
            l_rect.left=p_Term->aFontX*(p_Term->aInputCurPos-p_Term->aInputDispCurPos);
            InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
            atUpdateCaret(p_Term);
            l_p=ATIB_NEXTCHAR(p_Term,p_Term->aInputCurPos);
            p_Term->aInputCurPos=l_p;
            /* we now need to find the end of our line */
            while((*l_p)&&(l_p!=p_Term->aInputCurLineEnd))
              l_p=ATIB_NEXTCHAR(p_Term,l_p);
          }
          /* check end of line -- l_p should point to end of our character line for this to work */
          if (l_p==p_Term->aInputCurLineEnd) {
						/* uh oh, we have to delete a history command */
            do {
              *l_p=0x00;
              l_p=ATIB_NEXTCHAR(p_Term,l_p);
            } while ((*l_p)&&(l_p!=p_Term->aInputCurLine));
            if (l_p==p_Term->aInputCurLine) {
              dbPrint("ACK EEEEK OOOOOOOO input line overrun!!!\n");
              l_p=ATIB_PREVCHAR(p_Term,l_p);
            }
            p_Term->aInputCurLineEnd=l_p;
          }
          /* check if we have to reposition our line */
          if (p_Term->aInputCurPos==ATIB_ADDCHAR(p_Term,
              p_Term->aInputDispCurPos,p_Term->aTermBuf->tScrX)) {
            p_Term->aInputDispCurPos=ATIB_NEXTCHAR(p_Term,p_Term->aInputDispCurPos);
            GetClientRect(p_Term->aWnd,&l_rect);
						l_rect.top=l_rect.bottom-p_Term->aInputWndDY;
						InvalidateRect(p_Term->aWnd,&l_rect,FALSE);
            atUpdateCaret(p_Term);
          }
        }
      }
    } else {
      /* send data immediately */
      for (l_i=0;l_i<p_BufLen;l_i++) {
				/* do keyboard translation NOW */
				if (p_Buf[l_i]==0x7F)
					*l_outStr=p_Term->aDeleteChar;
        else if (p_Buf[l_i]==0x08)
          *l_outStr=p_Term->aBackSpaceChar;
        else
          *l_outStr=p_Buf[l_i];

        /* insert into our output buffer */
        atWriteTermInput(p_Term,(unsigned char*)l_outStr,1L);
        /* check echo to the screen */
        if (p_Term->aVLocalEcho) {
          if ((*l_outStr>=0x20)&&(*l_outStr<0x7F)) {
            atSendTerm(p_Term,l_outStr, 1);
            (p_Term->aLE_BSCount)++;
          } else {
            if ((*l_outStr==ASCII_CR)&&(p_Term->aLFwithNLMode)) {
              l_outStr[1]=ASCII_LF;
              atSendTerm(p_Term,(unsigned char *)l_outStr, 2);
              p_Term->aLE_BSCount=0;
            } else if (*l_outStr==ASCII_BS) {
              if (p_Term->aLE_BSCount) {
                atSendTerm(p_Term,(unsigned char *)l_outStr, 1);
                p_Term->aLE_BSCount--;
              } /* else don't echo */
						} else {
              atSendTerm(p_Term,(unsigned char *)l_outStr, 1);
              p_Term->aLE_BSCount++;
						}
          }
        }
      }
      (*(p_Term->aNotify))(p_Term,TBNOTIFY_USERINPUT);
    }
	}
}

/* clears and resets the input line */
void atResetSeparateInputLine(ATTERM *p_Term) {
  unsigned long l_i;
  if (p_Term) {
		/* let's reset this sucker */
		p_Term->aInputCurLine=p_Term->aInputBuf;
		p_Term->aInputCurLineEnd=p_Term->aInputBuf;
		p_Term->aInputCurPos=p_Term->aInputBuf;
		p_Term->aInputDispCurPos=p_Term->aInputBuf;
		p_Term->aInputScrollBackPos=p_Term->aInputCurLine;
    for(l_i=0;l_i<p_Term->aInputBufSize;l_i++)
      (p_Term->aInputBuf)[l_i]=0x00;
  }
}

BOOL CALLBACK _export atAnsiTermOptionsProc(HWND p_hWnd, UINT p_message,
											WPARAM p_wParam, LPARAM p_lParam) {
	ATTERM *l_Term;
	BOOL l_bool;
	RECT l_rect;
	long l_i;

	switch (p_message)
		{
		case WM_INITDIALOG:
			Ctl3dSubclassDlgEx(p_hWnd,CTL3D_ALL);
			dlCentreDialogBox(p_hWnd);
			l_Term=(ATTERM *)p_lParam;
			if (!l_Term)
				EndDialog(p_hWnd,IDCANCEL);
#ifdef WIN32
			SetProp(p_hWnd,(LPCSTR)g_atLongHi,(HANDLE)(p_lParam));
#else
			SetProp(p_hWnd,(LPCSTR)g_atLongHi,HIWORD(p_lParam));
			SetProp(p_hWnd,(LPCSTR)g_atLongLo,LOWORD(p_lParam));
#endif
			/* Ok, let's setup our window to look nice & pretty for the user */
			/* Emulation */
			switch (l_Term->aEmulation) {
				case AT_EMU_VT100:
					CheckRadioButton(p_hWnd,IDC_ATOPTEMUNONE,IDC_ATOPTEMUVT100,IDC_ATOPTEMUVT100);
					break;
				case AT_EMU_NONE:
				default:
					CheckRadioButton(p_hWnd,IDC_ATOPTEMUNONE,IDC_ATOPTEMUVT100,IDC_ATOPTEMUNONE);
					break;
			}
			/*  Separate Input Line */
			if (l_Term->aSeparateInputLine)
				CheckDlgButton(p_hWnd,IDC_ATOPTINPUTLINE,TRUE);
			else
				CheckDlgButton(p_hWnd,IDC_ATOPTINPUTLINE,FALSE);
			/* local echo */
			if (l_Term->aLocalEcho)
				CheckDlgButton(p_hWnd,IDC_ATOPTLOCALECHO,TRUE);
			else
				CheckDlgButton(p_hWnd,IDC_ATOPTLOCALECHO,FALSE);
			/* Bell */
			if (l_Term->aBell)
				CheckDlgButton(p_hWnd,IDC_ATOPTBELL,TRUE);
			else
				CheckDlgButton(p_hWnd,IDC_ATOPTBELL,FALSE);
			/* Backspace Character */
			if (l_Term->aBackSpaceChar==ASCII_BS)
				CheckRadioButton(p_hWnd,IDC_ATOPTBSBS,IDC_ATOPTBSDEL,IDC_ATOPTBSBS);
			else
				CheckRadioButton(p_hWnd,IDC_ATOPTBSBS,IDC_ATOPTBSDEL,IDC_ATOPTBSDEL);
			/* Delete Character */
			if (l_Term->aDeleteChar==ASCII_BS)
				CheckRadioButton(p_hWnd,IDC_ATOPTDELBS,IDC_ATOPTDELDEL,IDC_ATOPTDELBS);
			else
				CheckRadioButton(p_hWnd,IDC_ATOPTDELBS,IDC_ATOPTDELDEL,IDC_ATOPTDELDEL);
			/* Scrollback Buffer */
			SetDlgItemInt(p_hWnd,IDC_ATOPTSCROLLBUF,
				l_Term->aTermBuf->tBufY-l_Term->aTermBuf->tScrY-ATIB_TERMBUF_EXTRALINES,FALSE);
			return TRUE;
		case WM_SYSCOMMAND:
			switch(p_wParam) /* Process Control Box / Max-Min function */
				{
				case SC_CLOSE:
					EndDialog(p_hWnd,IDCANCEL);
					return TRUE;
				default:
					break;
				}
			break;
		case WM_COMMAND:
			switch (GET_WM_COMMAND_ID(p_wParam,p_lParam))
				{
				case IDOK:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
#ifdef WIN32
					l_Term=(ATTERM *)GetProp(p_hWnd,(LPCSTR)g_atLongHi);
#else
					l_Term=(ATTERM *)MAKELP(GetProp(p_hWnd,(LPCSTR)g_atLongHi),
						GetProp(p_hWnd,(LPCSTR)g_atLongLo));
#endif
					/* make our adjustments */
					/* Emulation */
					if (IsDlgButtonChecked(p_hWnd,IDC_ATOPTEMUVT100)) {
						l_Term->aEmulation=AT_EMU_VT100;
					} else {
						l_Term->aEmulation=AT_EMU_NONE;
					}
					/*  Separate Input Line */
					l_bool=IsDlgButtonChecked(p_hWnd,IDC_ATOPTINPUTLINE);
					if (l_bool!=l_Term->aSeparateInputLine) {
						l_Term->aSeparateInputLine=l_bool;
						/* we have to reset our terminal here, or something */
						/* Let's do that by "bumping" our window -- it'll cause a recalculation
						 * of the window size, the scroll window, etc etc etc */
						GetWindowRect(l_Term->aWnd,&l_rect);
						MoveWindow(l_Term->aWnd,l_rect.left,l_rect.top,
							l_rect.right-l_rect.left+1,l_rect.bottom-l_rect.top+1,TRUE);
						/* and if we have a separate input line, make sure it's reset */
						if (l_bool)
							atResetSeparateInputLine(l_Term);
					}
					/* local echo */
					l_Term->aLocalEcho=IsDlgButtonChecked(p_hWnd,IDC_ATOPTLOCALECHO);
					l_Term->aVLocalEcho=l_Term->aLocalEcho;
					/* Bell */
					l_Term->aBell=IsDlgButtonChecked(p_hWnd,IDC_ATOPTBELL);
					/* Backspace Character */
					if (IsDlgButtonChecked(p_hWnd,IDC_ATOPTBSBS)) {
						l_Term->aBackSpaceChar=ASCII_BS;
					} else {
						l_Term->aBackSpaceChar=ASCII_DEL;
					}
					/* Delete Character */
					if (IsDlgButtonChecked(p_hWnd,IDC_ATOPTDELBS)) {
						l_Term->aDeleteChar=ASCII_BS;
					} else {
						l_Term->aDeleteChar=ASCII_DEL;
					}
					/* Scrollback buffer */
					l_i=GetDlgItemInt(p_hWnd,IDC_ATOPTSCROLLBUF,&l_bool,FALSE);
					if (l_bool) {
						atAdjustTerm(l_Term,l_i);
					}
					EndDialog(p_hWnd,IDOK);
					return TRUE;
				case IDHELP:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
#ifdef WIN32
					l_Term=(ATTERM *)GetProp(p_hWnd,(LPCSTR)g_atLongHi);
#else
					l_Term=(ATTERM *)MAKELP(GetProp(p_hWnd,(LPCSTR)g_atLongHi),
						GetProp(p_hWnd,(LPCSTR)g_atLongLo));
#endif
					(*(l_Term->aNotify))(l_Term,TBNOTIFY_OPTIONSHELP);
					return TRUE;
				case IDCANCEL:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
					EndDialog(p_hWnd,IDCANCEL);
					return TRUE;
				default:
					break;
				}
			break;
		case WM_DESTROY:
			RemoveProp(p_hWnd,(LPCSTR)g_atLongHi);
#ifndef WIN32
			RemoveProp(p_hWnd,(LPCSTR)g_atLongLo);
#endif
			break;
		default:
			break;
		}
	return d3DlgMessageCheck(p_hWnd,p_message,p_wParam,p_lParam);
}


BOOL CALLBACK _export atATFnKeyProc(HWND p_hWnd, UINT p_message,
											WPARAM p_wParam, LPARAM p_lParam) {
	int l_i,l_j,l_k;
	ATTERM *l_Term;

	switch (p_message)
		{
		case WM_INITDIALOG:
			Ctl3dSubclassDlgEx(p_hWnd,CTL3D_ALL);
			dlCentreDialogBox(p_hWnd);
			l_Term=(ATTERM *)p_lParam;
			if (!l_Term)
				EndDialog(p_hWnd,IDCANCEL);
#ifdef WIN32
			SetProp(p_hWnd,(LPCSTR)g_atLongHi,(HANDLE)(p_lParam));
#else
			SetProp(p_hWnd,(LPCSTR)g_atLongHi,HIWORD(p_lParam));
			SetProp(p_hWnd,(LPCSTR)g_atLongLo,LOWORD(p_lParam));
#endif
			/* Ok, let's setup our window to look nice & pretty for the user */
			CheckRadioButton(p_hWnd,IDC_ATFNKEYBANKNONE,IDC_ATFNKEYBANKSHCT,IDC_ATFNKEYBANKNONE);
			for (l_i=0;l_i<12;l_i++) {
				SetDlgItemText(p_hWnd,IDC_ATFNKEYFN1+l_i,(char*)l_Term->aFnKeyMacro[l_i]);
			}
			SetProp(p_hWnd,"FnPage",(HANDLE)0);
			return TRUE;
		case WM_SYSCOMMAND:
			switch(p_wParam) /* Process Control Box / Max-Min function */
				{
				case SC_CLOSE:
					EndDialog(p_hWnd,IDCANCEL);
					return TRUE;
				default:
					break;
				}
			break;
		case WM_COMMAND:
			switch (GET_WM_COMMAND_ID(p_wParam,p_lParam))
				{
				case IDOK:
				case IDC_ATFNKEYBANKNONE:
				case IDC_ATFNKEYBANKSHIFT:
				case IDC_ATFNKEYBANKCTRL:
				case IDC_ATFNKEYBANKSHCT:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
#ifdef WIN32
					l_Term=(ATTERM *)GetProp(p_hWnd,(LPCSTR)g_atLongHi);
#else
					l_Term=(ATTERM *)MAKELP(GetProp(p_hWnd,(LPCSTR)g_atLongHi),
						GetProp(p_hWnd,(LPCSTR)g_atLongLo));
#endif
					l_j=((int)(GetProp(p_hWnd,"FnPage")))*12;
					dbPrint("Macro page change");
					if(IsDlgButtonChecked(p_hWnd,IDC_ATFNKEYBANKNONE)) {
						dbPrint("None");
						l_k=0;
						SetProp(p_hWnd,"FnPage",(HANDLE)0);
					} else if(IsDlgButtonChecked(p_hWnd,IDC_ATFNKEYBANKSHIFT)) {
						dbPrint("Shift");
						l_k=12;
						SetProp(p_hWnd,"FnPage",(HANDLE)1);
					} else if(IsDlgButtonChecked(p_hWnd,IDC_ATFNKEYBANKCTRL)) {
						dbPrint("Ctrl");
						l_k=24l;
						SetProp(p_hWnd,"FnPage",(HANDLE)2);
					} else {
						dbPrint("Shift+Ctrl");
						l_k=36;
						SetProp(p_hWnd,"FnPage",(HANDLE)3);
					}
					for (l_i=0;l_i<12;l_i++) {
						/* first save our old setting */
						GetDlgItemText(p_hWnd,IDC_ATFNKEYFN1+l_i,
							(char*)l_Term->aFnKeyMacro[l_i+l_j],TBMACRO_MAXLEN);
						/* force a terminating 0x00 - I don't trust microshit */
						l_Term->aFnKeyMacro[l_i+l_j][TBMACRO_MAXLEN-1]=0x00;
						/* now set our new setting */
						SetDlgItemText(p_hWnd,IDC_ATFNKEYFN1+l_i,
							(char*)l_Term->aFnKeyMacro[l_i+l_k]);
					}
					if (GET_WM_COMMAND_ID(p_wParam,p_lParam)==IDOK) {
						/* update our options */
						l_Term->aBell=l_Term->aBell;
						EndDialog(p_hWnd,IDOK);
					}
					return TRUE;
				case IDHELP:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
#ifdef WIN32
					l_Term=(ATTERM *)GetProp(p_hWnd,(LPCSTR)g_atLongHi);
#else
					l_Term=(ATTERM *)MAKELP(GetProp(p_hWnd,(LPCSTR)g_atLongHi),
						GetProp(p_hWnd,(LPCSTR)g_atLongLo));
#endif
					(*(l_Term->aNotify))(l_Term,TBNOTIFY_MACROSHELP);
					return TRUE;
				case IDCANCEL:
					if (GET_WM_COMMAND_CMD(p_wParam,p_lParam)!=BN_CLICKED)
						break;
					EndDialog(p_hWnd,IDCANCEL);
					return TRUE;
				default:
					break;
				}
			break;
		case WM_DESTROY:
			RemoveProp(p_hWnd,"FnPage");
			RemoveProp(p_hWnd,(LPCSTR)g_atLongHi);
#ifndef WIN32
			RemoveProp(p_hWnd,(LPCSTR)g_atLongLo);
#endif
			break;
		default:
			break;
		}
	return d3DlgMessageCheck(p_hWnd,p_message,p_wParam,p_lParam);
}

void atSaveTermSettings(ATTERM *p_Term, int p_Settings, char *p_Section) {
	char l_Buf[20];
	char *l_Sect;
	int l_i;

	if (!p_Term)
		return;

	if (p_Section)
		l_Sect=p_Section;
	else
		l_Sect=p_Term->aEnvSection;

	switch (p_Settings) {
		case TBNOTIFY_OPTIONS:
			enSaveLong(l_Sect,"Emulation",p_Term->aEmulation);
			enSaveInt(l_Sect,"SeparateInputLine",(unsigned int)p_Term->aSeparateInputLine);
			enSaveInt(l_Sect,"InputLineFColour",(unsigned int)p_Term->aInputFColour);
			enSaveInt(l_Sect,"InputLineBColour",(unsigned int)p_Term->aInputBColour);
			enSaveInt(l_Sect,"LocalEcho",(unsigned int)p_Term->aLocalEcho);
			enSaveInt(l_Sect,"Bell",(unsigned int)p_Term->aBell);
			enSaveInt(l_Sect,"BackSpaceChar",(unsigned int)p_Term->aBackSpaceChar);
			enSaveInt(l_Sect,"DeleteChar",(unsigned int)p_Term->aDeleteChar);
			enSaveInt(l_Sect,"Scrollback",
				(unsigned long)(p_Term->aTermBuf->tBufY-p_Term->aTermBuf->tScrY-ATIB_TERMBUF_EXTRALINES));
			break;
		case TBNOTIFY_FONT:
			if (p_Term->aLogFontValid) {
				enSaveInt(l_Sect,"LogFontValid",1);
				enSaveLogFont(l_Sect,&(p_Term->aLogFont));
			} else {
				enSaveInt(l_Sect,"LogFontValid",0);
			}
			break;
		case TBNOTIFY_MACROS:
			for (l_i=0;l_i<48;l_i++) {
				sprintf(l_Buf,"Macro%i",l_i+1);
				enSaveString(l_Sect,l_Buf,p_Term->aFnKeyMacro[l_i]);
			}
			break;
		default:
			break;
	}
}

void atLoadTermSettings(ATTERM *p_Term, int p_Settings, char *p_Section) {
	char *l_Sect;
	LOGFONT l_LogFont;
	int l_i;
	char l_Buf[20];
	unsigned long l_u;

	if (!p_Term)
		return;

	if (p_Section)
		l_Sect=p_Section;
	else
		l_Sect=p_Term->aEnvSection;

	switch (p_Settings) {
		case TBNOTIFY_OPTIONS:
			p_Term->aEmulation=enRestoreLong(l_Sect,"Emulation",p_Term->aEmulation);
			p_Term->aSeparateInputLine=(BOOL)enRestoreInt(l_Sect,"SeparateInputLine",0);
			p_Term->aInputFColour=(unsigned int)enRestoreInt(l_Sect,"InputLineFColour",ATIB_FCOLOUR);
			p_Term->aInputBColour=(unsigned int)enRestoreInt(l_Sect,"InputLineBColour",ATIB_BCOLOUR);
			p_Term->aLocalEcho=(BOOL)enRestoreInt(l_Sect,"LocalEcho",1);
      p_Term->aVLocalEcho=p_Term->aLocalEcho;
			p_Term->aBell=(BOOL)enRestoreInt(l_Sect,"Bell",1);
			p_Term->aBackSpaceChar=(unsigned char)enRestoreInt(l_Sect,"BackSpaceChar",ASCII_BS);
			p_Term->aDeleteChar=(unsigned char)enRestoreInt(l_Sect,"DeleteChar",ASCII_DEL);
			l_u=(unsigned int)enRestoreInt(l_Sect,"Scrollback",50);
			atAdjustTerm(p_Term,l_u);
			enSaveInt(l_Sect,"Scrollback",
				(unsigned long)(p_Term->aTermBuf->tBufY-p_Term->aTermBuf->tScrY-ATIB_TERMBUF_EXTRALINES));
			break;
		case TBNOTIFY_FONT:
			if (enRestoreInt(l_Sect,"LogFontValid",0)) {
				enRestoreLogFont(l_Sect,&(l_LogFont));
				atChangeFont(p_Term,NULL, &l_LogFont);
			} else {
				atChangeFont(p_Term,GetStockObject(SYSTEM_FIXED_FONT),NULL);
			}
			break;
		case TBNOTIFY_MACROS:
			for (l_i=0;l_i<48;l_i++) {
				sprintf(l_Buf,"Macro%i",l_i+1);
				enRestoreString(l_Sect,l_Buf,"",p_Term->aFnKeyMacro[l_i],TBMACRO_MAXLEN);
			}
			break;
		default:
			break;
	}
}

void atResetTerm(ATTERM *p_Term) {
	int l_i;
	p_Term->aVLocalEcho=FALSE;
	for (l_i=0;l_i<4;l_i++)
		p_Term->aLED[l_i]=FALSE;
	p_Term->aLFwithNLMode=TRUE;
	p_Term->aCursorKeyAppMode=FALSE;
	p_Term->aANSIMode=TRUE;

	p_Term->aColumnMode=TRUE;
	p_Term->aScrollingMode=TRUE;
	p_Term->aScreenMode=TRUE;
	p_Term->aWraparoundMode=TRUE;
	p_Term->aAutoRepeatMode=TRUE;
	p_Term->aInterlaceMode=TRUE;
	p_Term->aGraphicProcMode=TRUE;
	p_Term->aKeypadMode=TRUE;

}