/
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/
// termbuf.c
// two-letter descriptor: tb
// ****************************************************************************
// 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 a terminal buffer functionality

#include<windows.h>
#include<windowsx.h>
#include"debug.h"
#include"termbuf.h"

TBTERMBUF *tbAllocTermBuf(unsigned long p_ID,long p_BufX,long p_BufY,long p_ScrX,long p_ScrY) {
	TBTERMBUF *l_tBuf;
	unsigned long *l_Buf;
	HGLOBAL l_memory,l_bufmemory;
	long x,y;
	unsigned long data;
	int l_i;
//  int i,r,g,b,lvl;

	/* first, alloc some memory for this sucker */
	l_memory=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(TBTERMBUF));
	if (!l_memory)
		return NULL;
	l_tBuf=(TBTERMBUF*)GlobalLock(l_memory);
	if (!l_tBuf) {
		GlobalFree(l_memory);
		return NULL;
	}
	/* I alloc an extra 1K because if there are race-cases in the programming
	 * (which Winfuck is full of) then this may prevent us from spilling out
   * into the netherlands should a pointer go temporarily astray. */
	l_bufmemory=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(long)*p_BufX*(p_BufY+2)+1024);
	if (!l_bufmemory) {
		GlobalLock(l_memory);
		GlobalFree(l_memory);
		return NULL;
	}
	l_Buf=(unsigned long *)GlobalLock(l_bufmemory);
	if (!l_Buf) {
		GlobalLock(l_memory);
		GlobalFree(l_memory);
		GlobalFree(l_bufmemory);
		return NULL;
	}
	l_tBuf->tMemory=l_memory;
	l_tBuf->tBufferMemory=l_bufmemory;
	l_tBuf->tBuffer=l_Buf;
	l_tBuf->tTab=&(l_Buf[p_BufX*p_BufY]); /* tab stops are kept in an "extra" line at the end of the buffer */
	l_tBuf->tID=p_ID;
	l_tBuf->tTopY=0;
	l_tBuf->tBufX=p_BufX;
	l_tBuf->tBufY=p_BufY;
	l_tBuf->tCurX=0; /* set cursor to default at top-left */
	l_tBuf->tCurY=0;
	l_tBuf->tScrX=p_ScrX;
	l_tBuf->tScrY=p_ScrY;
	l_tBuf->tScrollRegionActive=0;
	l_tBuf->tSRX1=0;
	l_tBuf->tSRX2=p_ScrX;
	l_tBuf->tSRY1=0;
	l_tBuf->tSRY2=p_ScrY;
	l_tBuf->tCurrentAttribute=TB_MAKEFCOLOUR(7L)|TB_MAKEBCOLOUR(0L); /* grey on black */
	l_tBuf->tHLStartX=l_tBuf->tHLStartY=0L; /* tHLEnd is ONE MORE than last tHLStart, so this gives us a NULL hilight */
	l_tBuf->tHLEndX=l_tBuf->tHLEndY=0L; /* tHLEnd is ONE MORE than last tHLStart, so this gives us a NULL hilight */
	l_tBuf->tHTab=8;
	l_tBuf->tNotifyFn=NULL;
	l_tBuf->tAutoRightMargin=TRUE;

	/* create default RGB colour map */
	(l_tBuf->tColourBank)[ 0]=RGB(  0,  0,  0);
	(l_tBuf->tColourBank)[ 1]=RGB(128,  0,  0);
	(l_tBuf->tColourBank)[ 2]=RGB(  0,128,  0);
	(l_tBuf->tColourBank)[ 3]=RGB(128,128,  0);
	(l_tBuf->tColourBank)[ 4]=RGB(  0,  0,128);
  (l_tBuf->tColourBank)[ 5]=RGB(128,  0,128);
  (l_tBuf->tColourBank)[ 6]=RGB(  0,128,128);
  (l_tBuf->tColourBank)[ 7]=RGB(192,192,192);
  (l_tBuf->tColourBank)[ 8]=RGB(128,128,128);
  (l_tBuf->tColourBank)[ 9]=RGB(255,  0,  0);
  (l_tBuf->tColourBank)[10]=RGB(  0,255,  0);
  (l_tBuf->tColourBank)[11]=RGB(255,255,  0);
  (l_tBuf->tColourBank)[12]=RGB(  0,  0,255);
	(l_tBuf->tColourBank)[13]=RGB(255,  0,255);
  (l_tBuf->tColourBank)[14]=RGB(  0,255,255);
	(l_tBuf->tColourBank)[15]=RGB(255,255,255);

	for (l_i=0;l_i<(1<<TB_COLOURDEPTH);l_i++) {
		(l_tBuf->tColourPen)[l_i]=NULL;
	}



//  i=0;
//  for (lvl=128;lvl<256;lvl+=127) {
//    for (r=0;r<2;r++) {
//      for (g=0;g<2;g++) {
//        for (b=0;b<2;b++) {
//          (l_tBuf->tColourBank)[i]=RGB(r*lvl,g*lvl,b*lvl);
//          i++;
//        }
//      }
//    }
//  }

	/* clear the buffer of any & all data */
	data=TB_MAKEEFFECT(0)|TB_MAKEBCOLOUR(0)|TB_MAKEFCOLOUR(7)|TB_MAKECHAR(0x20);
	for (y=0;y<p_BufY;y++)
		for (x=0;x<p_BufX;x++)
			*(l_Buf+x+(y*p_BufX))=data;

	/* reset our tabs to the default - every 8 characters */
	for (l_i=0;l_i<p_BufX;l_i++) {
		if (l_i%8)
			(l_tBuf->tTab)[l_i]=TBTAB_NONE;
		else
			(l_tBuf->tTab)[l_i]=TBTAB_LEFTALIGN;
	}

	/* and we're done! */
	return l_tBuf;
}

void tbFreeTermBuf(TBTERMBUF *p_TermBuf) {
	HGLOBAL l_memory;
	int l_i;
	/* delete attached pens */
	if (p_TermBuf) {
		for (l_i=0;l_i<(1<<TB_COLOURDEPTH);l_i++) {
			if ((p_TermBuf->tColourPen)[l_i]) {
				DeleteObject((p_TermBuf->tColourPen)[l_i]);
			}
		}
		l_memory=p_TermBuf->tBufferMemory;
    GlobalUnlock(l_memory);
    GlobalFree(l_memory);
    l_memory=p_TermBuf->tMemory;
    GlobalUnlock(l_memory);
    GlobalFree(l_memory);
  }
}

/* adjusts the width/height of the terminal buffer */
/* If tScrX=tBufX, then this equality is preserved. Otherwise, tScrX is
 * left as-is (unless p_BufX<tScrX, in which case, tScrX is set to p_BufX) */
/**** THIS NEEDS REDOING ****/
//#pragma argsused
//void tbResizeScreen(TBTERMBUF *p_TermBuf, long p_ScrX, long p_ScrY) {
//  if (!p_TermBuf)
//    return;
//  p_TermBuf->tScrX=TB_MIN(p_TermBuf->tBufX,p_ScrX);
//  p_TermBuf->tScrY=TB_MIN(p_TermBuf->tBufY,p_ScrY);
//
//  p_TermBuf->tCurX=TB_MIN(p_TermBuf->tCurX,p_ScrX);
//  p_TermBuf->tCurY=TB_MIN(p_TermBuf->tCurY,p_ScrY);
//  if (p_TermBuf->tNotifyFn) {
//    (*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_RESIZE,p_TermBuf->tScrX,p_TermBuf->tScrY,0L,0L);
//    (*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,0L,0L);
//  }
//}

TBTERMBUF *tbReAllocTermBuf(TBTERMBUF *p_TermBuf,long p_BufX,long p_BufY,long p_ScrX,long p_ScrY) {
	HGLOBAL l_oldmem,l_newmem;
	unsigned long *l_new;
	long l_x,l_y;
	long xmin,xmax,ymin,ymax;
//  char l_buf[200];
	unsigned long l_data;

	if (!p_TermBuf) {
		return NULL;
	}
	if (p_BufX<p_ScrX)
		p_BufX=p_ScrX;
	if (p_BufY<p_ScrY)
		p_BufY=p_ScrY;

//  sprintf(l_buf,"RESIZE ENTER: Buf=(%i,%i) Scr=(%i,%i)    newBuf=(%i,%i) newScr=(%i,%i)",
//    p_TermBuf->tBufX,p_TermBuf->tBufY,
//    p_TermBuf->tScrX,p_TermBuf->tScrY,
//    p_BufX,p_BufY,p_ScrX,p_ScrY);
//  dbPrint(l_buf);

	if ((p_BufX!=p_TermBuf->tBufX)||(p_BufY!=p_TermBuf->tBufY)) {
		l_newmem=GlobalAlloc(GHND|GMEM_NOCOMPACT,sizeof(long)*p_BufX*(p_BufY+2)+1024);
		if (!l_newmem) {
			return p_TermBuf;
		}
		l_new=(unsigned long *)GlobalLock(l_newmem);
		if (!l_new) {
			GlobalFree(l_newmem);
			return p_TermBuf;
		}

		/* first, clear the new buffer */
		l_data=TB_MAKEEFFECT(0)|TB_MAKEBCOLOUR(0)|TB_MAKEFCOLOUR(7)|TB_MAKECHAR(0x20);
		for (l_y=0;l_y<(p_BufY+2);l_y++)
			for (l_x=0;l_x<p_BufX;l_x++)
				*(l_new+l_x+(l_y*p_BufX))=l_data;
		/* clear all tabs */
		for (l_x=0;l_x<p_BufX;l_x++)
			l_new[p_BufX*p_BufY+l_x]=TBTAB_NONE;

		 /* now copy data over from old buffer to new one */
		xmin=0;
		xmax=TB_MIN(p_TermBuf->tBufX,p_BufX);
		ymin=TB_MAX(p_TermBuf->tScrY-p_TermBuf->tBufY,p_ScrY-p_BufY);
		ymax=TB_MIN(p_TermBuf->tScrY,p_ScrY);
		for (l_y=ymin;l_y<ymax;l_y++) {
			for (l_x=xmin;l_x<xmax;l_x++) {
				l_data=TB_GETCHAR(p_TermBuf,l_x,l_y);
//        l_data=TB_MAKEEFFECT(0)|TB_MAKEBCOLOUR(0)|TB_MAKEFCOLOUR(7)|TB_MAKECHAR(0x20);
				if (l_y<0) {
					*(l_new+l_x+((p_BufY+l_y)*p_BufX))=l_data;
				} else {
					*(l_new+l_x+(l_y*p_BufX))=l_data;
				}
			}
		}
		/* reset our tabs to the default - every 8 characters */
		for (l_x=0;l_x<p_BufX;l_x++) {
			if (l_x%8)
				l_new[p_BufX*p_BufY+l_x]=TBTAB_NONE;
//				(l_tBuf->tTab)[l_i]=TBTAB_NONE;
			else
				l_new[p_BufX*p_BufY+l_x]=TBTAB_LEFTALIGN;
//				(l_tBuf->tTab)[l_i]=TBTAB_LEFTALIGN;
		}
		/* copy over tabs from old buffer to new one */
		for (l_x=xmin;l_x<xmax;l_x++) {
			l_new[p_BufX*p_BufY+l_x]=p_TermBuf->tTab[l_x];
		}
		l_oldmem=p_TermBuf->tBufferMemory;
		/* and now let's swap in our new settings */
		p_TermBuf->tBufferMemory=l_newmem;
		p_TermBuf->tBuffer=l_new;
		p_TermBuf->tTab=&(l_new[p_BufX*p_BufY]);
		p_TermBuf->tTopY=0;
		p_TermBuf->tBufX=p_BufX;
		p_TermBuf->tBufY=p_BufY;
		/* ok, let's turf the old memory */
		GlobalUnlock(l_oldmem);
		GlobalFree(l_oldmem);
	}
	/* let's adjust tTopY so that our bottom line stays where it is. */
	p_TermBuf->tTopY+=p_TermBuf->tScrY-p_ScrY;
	if (p_TermBuf->tTopY<0)
		p_TermBuf->tTopY+=p_BufY;
	else if (p_TermBuf->tTopY>=p_BufY)
		p_TermBuf->tTopY-=p_BufY;
	/* and the cursor too; it's top-relative */
	p_TermBuf->tCurY-=p_TermBuf->tScrY-p_ScrY;

	p_TermBuf->tScrX=p_ScrX;
	p_TermBuf->tScrY=p_ScrY;
	if (p_TermBuf->tCurX>=p_ScrX)
		p_TermBuf->tCurX=p_ScrX-1;
	else if (p_TermBuf->tCurX<0)
		p_TermBuf->tCurX=0;
	if (p_TermBuf->tCurY>=p_ScrY)
		p_TermBuf->tCurY=p_ScrY-1;
	else if (p_TermBuf->tCurY<0)
		p_TermBuf->tCurY=0;
	p_TermBuf->tHLStartX=p_TermBuf->tHLStartY=0;
	p_TermBuf->tHLEndX=p_TermBuf->tHLEndY=0;

	if (p_TermBuf->tScrollRegionActive) {
		dbPrint("TB: Scroll Region not supported");
/*		if (p_TermBuf->tSRX1>p_TermBuf->tScrX)
			p_TermBuf->tSCRX1=p_TermBuf->tSCRX);
		if (p_TermBuf->tSRX2>p_TermBuf->tScrX)
			p_TermBuf->tSCRX2=p_TermBuf->tSCRX);
		if (p_TermBuf->tSRY1>p_TermBuf->tScrY)
			p_TermBuf->tSCRY1=p_TermBuf->tSCRY);
		if (p_TermBuf->tSRY2>p_TermBuf->tScrY)
			p_TermBuf->tSCRY2=p_TermBuf->tSCRY); */
	}

//  sprintf(l_buf,"RESIZE EXIT: Buf=(%i,%i) Scr=(%i,%i)    newBuf=(%i,%i) newScr=(%i,%i)",
//    p_TermBuf->tBufX,p_TermBuf->tBufY,
//    p_TermBuf->tScrX,p_TermBuf->tScrY,
//    p_BufX,p_BufY,p_ScrX,p_ScrY);
//  dbPrint(l_buf);


		return p_TermBuf;
}




/* tbPutChar writes the specified ASCII 8-bit character to the
 * terminal as would be expected, and does all attribute-assignment
 * and scrolling as required. */
void tbPutChar(TBTERMBUF *p_TermBuf, unsigned char p_char) {

	if (p_TermBuf) {
		if (p_TermBuf->tCurX>TB_GETXMAX(p_TermBuf)) {
			/* we are off the end of our line. Throw in a wrap-around here first */
			p_TermBuf->tCurX=0;
			/* and do a newline */
			tbLineFeed(p_TermBuf);
		}
		*TB_GETCHARADDR(p_TermBuf,p_TermBuf->tCurX,p_TermBuf->tCurY)=
			p_TermBuf->tCurrentAttribute|TB_MAKECHAR(p_char);
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,p_TermBuf->tCurX,p_TermBuf->tCurY,
				p_TermBuf->tCurX,p_TermBuf->tCurY);
	}
	/* now let's advance the cursor position etc. */
	/* first, check if we're inside the scrolling region */
	if (p_TermBuf->tScrollRegionActive) {
		dbPrint("TB: Scroll Region not supported ");
//	if ((p_TermBuf->tCurX>=p_TermBuf->tSRX1)&&
//			(p_TermBuf->tCurX<=p_TermBuf->tSRX2)&&
//			(p_TermBuf->tCurY>=p_TermBuf->tSRY1)&&
//			(p_TermBuf->tCurY<=p_TermBuf->tSRY2)) {
//		/* we are within the scroll region */
//		if (p_TermBuf->tCurX<p_TermBuf->tSRX2) {
//			/* Cursor moves right one */
//			p_TermBuf->tCurX++;
//	  } else {
//			/* line wrap */
//			p_TermBuf->tCurX=p_TermBuf->tSRX1;
//			/* and do a newline */
//			tbLineFeed(p_TermBuf);
//    }
//		return;
//  }
	}

	/* note what the following does.. it lets a character hitting the end of
	 * a line to actually "poke" through into an invalid area of the screen.
	 * This is to avoid wrapping until we for sure need to with the reception
	 * of the next character */
	p_TermBuf->tCurX++;

	/* fuck this is stupid. I actualy have a linux box where VI *requires* you
	 * to wrap at the end of a line BEFORE the next character. And I have other
	 * boxes which *require* you to *not* wrap until you've actually given a
	 * new character (which must then be wrapped onto next line). FUCK!!!!!!
	 * NO WAY OUT! */
	/* Ok, I've discovered (I think) this is the termcap entry auto_right_margin.
	 * it's a flag in the termcap/terminfo. Let's assume it's ON, but allow it
	 * to be turned OFF (by command line etc.) */
	/* I WOULD JUST LIKE TO SAY THAT programs that *depend* on shit like this
	 * should BE THROWN TO HELL WHERE THEY BELONG. FUCK YOU ALL! You don't know
	 * how to fucking program your way out of a binary fucking tree!!! FUCK!! */
	/* (as you can tell, I really don't think I should have to be doing this) */
	if (p_TermBuf->tAutoRightMargin) {
		if (p_TermBuf->tCurX>TB_GETXMAX(p_TermBuf)) {
			/* we are off the end of our line. Throw in a wrap-around here first */
			p_TermBuf->tCurX=0;
			/* and do a newline */
			tbLineFeed(p_TermBuf);
		}
	}
	if (p_TermBuf->tNotifyFn)
		(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,0L,0L);
}

/* tbPutChar writes the specified ASCII 8-bit character to the
 * terminal as would be expected, and does all attribute-assignment
 * and scrolling as required. */
void tbPutCharReverse(TBTERMBUF *p_TermBuf, unsigned char p_char) {
//  long i;
	if (p_TermBuf) {
		*TB_GETCHARADDR(p_TermBuf,p_TermBuf->tCurX,p_TermBuf->tCurY)=
			p_TermBuf->tCurrentAttribute|TB_MAKECHAR(p_char);
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,p_TermBuf->tCurX,p_TermBuf->tCurY,
				p_TermBuf->tCurX,p_TermBuf->tCurY);
	}
	/* now let's advance the cursor position etc. */
	/* first, check if we're inside the scrolling region */
	if (p_TermBuf->tScrollRegionActive) {
		dbPrint("TB: Scroll Region not supported ");
//	if ((p_TermBuf->tCurX>=p_TermBuf->tSRX1)&&
//			(p_TermBuf->tCurX<=p_TermBuf->tSRX2)&&
//			(p_TermBuf->tCurY>=p_TermBuf->tSRY1)&&
//			(p_TermBuf->tCurY<=p_TermBuf->tSRY2)) {
//		/* we are within the scroll region */
//		if (p_TermBuf->tCurX<p_TermBuf->tSRX2) {
//			/* Cursor moves right one */
//			p_TermBuf->tCurX++;
//	  } else {
//			/* line wrap */
//			p_TermBuf->tCurX=p_TermBuf->tSRX1;
//			/* and do a newline */
//			tbLineFeed(p_TermBuf);
//    }
//		return;
//  }
	}

	if (p_TermBuf->tCurX>0) {
		/* Cursor moves left one */
		p_TermBuf->tCurX--;
	} else {
		/* line wrap */
		p_TermBuf->tCurX=TB_GETXMAX(p_TermBuf);
		/* and do a newline */
		tbLineFeedUp(p_TermBuf);
	}
	if (p_TermBuf->tNotifyFn)
		(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,0L,0L);
}

void tbSetFColour(TBTERMBUF *p_TermBuf, unsigned long p_colour) {
	if (p_TermBuf) {
		p_TermBuf->tCurrentAttribute=TB_SETATTRFCOLOUR(p_TermBuf,p_colour);
	}
}

void tbSetBColour(TBTERMBUF *p_TermBuf, unsigned long p_colour) {
	if (p_TermBuf) {
		p_TermBuf->tCurrentAttribute=TB_SETATTRBCOLOUR(p_TermBuf,p_colour);
	}
}

void tbSetEffect(TBTERMBUF *p_TermBuf, unsigned long p_effect) {
	if (p_TermBuf) {
		p_TermBuf->tCurrentAttribute=TB_SETATTREFFECT(p_TermBuf,p_effect);
	}
}

void tbSetCursor(TBTERMBUF *p_TermBuf, unsigned long p_CurX, unsigned long p_CurY) {
	if (p_TermBuf) {
		p_TermBuf->tCurX=TB_MIN(TB_MAX(p_CurX,0),TB_GETXMAX(p_TermBuf));
		p_TermBuf->tCurY=TB_MIN(TB_MAX(p_CurY,0),TB_GETYMAX(p_TermBuf));
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,1L,0L);
	}
}

void tbClearScreen(TBTERMBUF *p_TermBuf) {
	long l_x,l_y;
	if (p_TermBuf) {
		for (l_y=0;l_y<=TB_GETYMAX(p_TermBuf);l_y++)
			for (l_x=0;l_x<=TB_GETXMAX(p_TermBuf);l_x++)
				*TB_GETCHARADDR(p_TermBuf,l_x,l_y)=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,0L,0L,
				TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf));
		p_TermBuf->tCurX=p_TermBuf->tCurY=0;
	}
}

///* the following may not adhere to VT100 standards */
//void tbCarridgeReturn(TBTERMBUF *p_TermBuf) {
//	if (p_TermBuf) {
//		p_TermBuf->tCurX=0;
//		if (p_TermBuf->tNotifyFn)
//			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,0L,0L);
//	}
//}

void tbLineFeed(TBTERMBUF *p_TermBuf) {
	long l_i;

	if (p_TermBuf) {
		if (p_TermBuf->tScrollRegionActive) {
			dbPrint("TB: Scroll Region not supported ");
//		if ((p_TermBuf->tCurX>=p_TermBuf->tSRX1)&&
//				(p_TermBuf->tCurX<=p_TermBuf->tSRX2)&&
//				(p_TermBuf->tCurY>=p_TermBuf->tSRY1)&&
//				(p_TermBuf->tCurY<=p_TermBuf->tSRY2)) {
//			/* we're inside the scroll region */
//			if (p_TermBuf->tCurY<p_TermBuf->tSRY2) {
//				/* not at bottom yet.. just increment our cursor Y */
//				p_TermBuf->tCurY++;
//			} else {
//				tbScrollUp(p_TermBuf);
//			}
//			if (p_TermBuf->tNotifyFn)
//				(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,0L,0L);
//			}
		}
		if (p_TermBuf->tCurY<TB_GETYMAX(p_TermBuf)) {
			/* not at bottom yet.. just increment our cursor Y */
			p_TermBuf->tCurY++;
			l_i=1L;
		} else {
			tbScrollUp(p_TermBuf);
			l_i=0L;
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,
				p_TermBuf->tCurX,p_TermBuf->tCurY,l_i,0L);
	}
}

void tbLineFeedUp(TBTERMBUF *p_TermBuf) {
	long l_i;
	if (p_TermBuf) {
		if (p_TermBuf->tCurY>0) {
			/* not at top yet.. just increment our cursor Y */
			p_TermBuf->tCurY--;
			l_i=1L;
		} else {
			tbScrollDown(p_TermBuf);
			l_i=0L;
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,
			  p_TermBuf->tCurX,p_TermBuf->tCurY,l_i,0L);
	}
}

/* This does a scroll down operation - all text is moved down 1 line */
/* I could use a tbMoveText for this operation, but this function
 * uses the scrolling region (because it's full-screen) and is thus faster */
void tbScrollDown(TBTERMBUF *p_TermBuf) {
	long l_x,l_y;
	/* this isn't as easy as a ScrollUp because we can't just use
	 * the scrollback buffer; we have to actually move all our data
	 * down 1 line and redraw the screen */
	if (!p_TermBuf)
		return;

	if (p_TermBuf->tScrollRegionActive) {
		dbPrint("TB: Scroll Region not supported ");
/*		if ((p_TermBuf->tCurX>=p_TermBuf->tSRX1)&&
				(p_TermBuf->tCurX<=p_TermBuf->tSRX2)&&
				(p_TermBuf->tCurY>=p_TermBuf->tSRY1)&&
				(p_TermBuf->tCurY<=p_TermBuf->tSRY2)&&
				((p_TermBuf->tSRX1!=0)||
				 (p_TermBuf->tSRX2!=p_TermBuf->tScrX)||
				 (p_TermBuf->tSRY1!=0)||
				 (p_TermBuf->tSRY2!=p_TermBuf->tScrY) )) {

			return;
		}*/
	}

	/* copy all data down one line */
	for (l_y=TB_GETYMAX(p_TermBuf)-1;l_y>=0;l_y--) {
		for (l_x=0;l_x<=TB_GETXMAX(p_TermBuf);l_x++) {
			*TB_GETCHARADDR(p_TermBuf,l_x,(l_y+1))=*TB_GETCHARADDR(p_TermBuf,l_x,l_y);
		}
	}

	/* clear the top line */
	for (l_x=0;l_x<=TB_GETXMAX(p_TermBuf);l_x++) {
		*TB_GETCHARADDR(p_TermBuf,l_x,0)=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
	}
	/* notify */
	if (p_TermBuf->tNotifyFn)
		(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_SCROLL,-1L,0L,0L,0L);
}

void tbScrollUp(TBTERMBUF *p_TermBuf) {
	long i;

	if (!p_TermBuf)
		return;

	/* Leave cursor Y alone and scroll screen 1 */
	if (p_TermBuf->tScrollRegionActive) {
		dbPrint("TB: Scroll Region not supported ");
//	if ((p_TermBuf->tCurX>=p_TermBuf->tSRX1)&&
//			(p_TermBuf->tCurX<=p_TermBuf->tSRX2)&&
//			(p_TermBuf->tCurY>=p_TermBuf->tSRY1)&&
//			(p_TermBuf->tCurY<=p_TermBuf->tSRY2)&&
//			((p_TermBuf->tSRX1!=0)||
//			 (p_TermBuf->tSRX2!=p_TermBuf->tScrX)||
//			 (p_TermBuf->tSRY1!=0)||
//			 (p_TermBuf->tSRY2!=p_TermBuf->tScrY) )) {
//		/* we are within the scroll region, AND our scroll region is NOT the full screen */
//		tbMoveText(TBTERMBUF *p_TermBuf,p_TermBuf->tSRX1,p_TermBuf->tSRY1+1,
//			p_TermBuf->tSRX2,p_TermBuf->tSRY2,p_TermBuf->tSRX1,p_TermBuf->tSRY1);
//		if (p_TermBuf->tNotifyFn)
//			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
//				p_TermBuf->tSRX1,p_TermBuf->tSRY1,p_TermBuf->tSRX2,p_TermBuf->tSRY2);
//		return;
//		}
	}
	if (p_TermBuf->tTopY<(p_TermBuf->tBufY-1)) {
		/* not at end of the buffer yet... just move screen down 1 */
		p_TermBuf->tTopY++;
	} else {
		/* at the end of the buffer... wrap screen */
		p_TermBuf->tTopY=0;
	}
	/* Note, since we've moved our screen, we also have to move our hilight
	 * region (if there is one) */
	p_TermBuf->tHLStartY--;
	p_TermBuf->tHLEndY--;
	if (p_TermBuf->tHLStartY<TB_GETYMIN(p_TermBuf)) {
		p_TermBuf->tHLStartY=TB_GETYMIN(p_TermBuf);
		p_TermBuf->tHLStartX=0;
	}
	if (p_TermBuf->tHLEndY<TB_GETYMIN(p_TermBuf)) {
		p_TermBuf->tHLEndY=TB_GETYMIN(p_TermBuf);
		p_TermBuf->tHLEndX=0;
	}

	for (i=TB_GETXMIN(p_TermBuf);i<=TB_GETXMAX(p_TermBuf);i++) {
		*TB_GETCHARADDR(p_TermBuf,i,p_TermBuf->tCurY)=
			p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
	}
	if (p_TermBuf->tNotifyFn)
		(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_SCROLL,1L,0L,0L,0L);
}

void tbScrollLeft(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf)
		tbMoveText(p_TermBuf,1,0,TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf),0,0);
}

void tbScrollRight(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf)
		tbMoveText(p_TermBuf,0,0,TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf),1,0);
}

/* Clears to End Of Line with current attribute. Note if p_Start<0, the
 * current cursor position to EOL is cleared. If p_Start>=0, the erase
 * starts at p_Start */
void tbClearToEOL(TBTERMBUF *p_TermBuf,long p_Start) {
	long i;
	if (p_TermBuf) {
		if (p_Start<0)
			p_Start=p_TermBuf->tCurX;
		for (i=p_Start;i<=TB_GETXMAX(p_TermBuf);i++) {
			*TB_GETCHARADDR(p_TermBuf,i,p_TermBuf->tCurY)=
				p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
				p_Start,p_TermBuf->tCurY,TB_GETXMAX(p_TermBuf),p_TermBuf->tCurY);
	}
}
void tbClearLineX(TBTERMBUF *p_TermBuf,long p_Start, long p_End) {
	long i;
	if (p_TermBuf) {
		for (i=p_Start;i<=p_End;i++) {
			*TB_GETCHARADDR(p_TermBuf,i,p_TermBuf->tCurY)=
				p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
				p_Start,p_TermBuf->tCurY,p_End,p_TermBuf->tCurY);
	}
}
void tbClearRight(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		tbClearLineX(p_TermBuf,p_TermBuf->tCurX,TB_GETXMAX(p_TermBuf));
	}
}
void tbClearLeft(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		tbClearLineX(p_TermBuf,0,p_TermBuf->tCurX);
	}
}
void tbClearLine(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		tbClearLineX(p_TermBuf,0,TB_GETXMAX(p_TermBuf));
	}
}

/* tbHTab - advance to next horizontal tab position */
/* move to next tab position */
void tbHTab(TBTERMBUF *p_TermBuf) {
	int l_i;

	if (p_TermBuf) {
		l_i=p_TermBuf->tCurX;
		do {
			l_i++;
			if (l_i>TB_GETXMAX(p_TermBuf))
				l_i=0;
			if (p_TermBuf->tTab[l_i])
				break;
		} while(l_i!=p_TermBuf->tCurX);
		if ((l_i<=p_TermBuf->tCurX)&&(p_TermBuf->tTab[l_i])) {
			/* do line down */
			p_TermBuf->tCurX=l_i;
			tbLineFeed(p_TermBuf); /* will perform notify function */
			/* tbLineFeed should reposition the cursor for us */
		} else if (l_i>p_TermBuf->tCurX) {
			p_TermBuf->tCurX=l_i;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,1L,0L);
		} /* else no tabs set -- do nothing */
	}
}

/* tbHTabReverse - advance to previous horizontal tab position */
void tbHTabReverse(TBTERMBUF *p_TermBuf) {
	int l_i;

	if (p_TermBuf) {
		l_i=p_TermBuf->tCurX;
		do {
			l_i--;
			if (l_i<0)
				l_i=TB_GETXMAX(p_TermBuf);
			if (p_TermBuf->tTab[l_i])
				break;
		}	while(l_i!=p_TermBuf->tCurX);
		if ((l_i>=p_TermBuf->tCurX)&&(p_TermBuf->tTab[l_i])) {
			/* do line up */
			p_TermBuf->tCurX=l_i;
			tbLineFeedUp(p_TermBuf); /* will perform notify function */
			/* tbLineFeed should reposition the cursor for us */
		} else if (l_i<p_TermBuf->tCurX) {
			p_TermBuf->tCurX=l_i;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,1L,0L);
		} /* else no tabs set -- do nothing */
	}
}

/* tbBackSpace - go back without deleting or moving any characters */
void tbBackSpace(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		if (p_TermBuf->tCurX==0)
			return;
    p_TermBuf->tCurX-=1;
    if (p_TermBuf->tNotifyFn)
      (*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,p_TermBuf->tCurY,1L,0L);
  }
}

/* tbDelete - delete current character, dragging anything to the right over 1 */
void tbDelete(TBTERMBUF *p_TermBuf) {
	int l_i;

	if (p_TermBuf) {
		for (l_i=p_TermBuf->tCurX+1;l_i<=TB_GETXMAX(p_TermBuf);l_i++) {
			*TB_GETCHARADDR(p_TermBuf,l_i-1,p_TermBuf->tCurY)=
				*TB_GETCHARADDR(p_TermBuf,l_i,p_TermBuf->tCurY);
		}
		*TB_GETCHARADDR(p_TermBuf,TB_GETXMAX(p_TermBuf),p_TermBuf->tCurY)=
				p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		if (p_TermBuf->tNotifyFn) {
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
				p_TermBuf->tCurX,p_TermBuf->tCurY,
				TB_GETXMAX(p_TermBuf),p_TermBuf->tCurY);
		}
	}
}

void tbCurUp(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		if (p_TermBuf->tCurY>0) {
			p_TermBuf->tCurY--;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,
				p_TermBuf->tCurY,1L,0L);
		}
	}
}

void tbCurDown(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		if (p_TermBuf->tCurY<TB_GETYMAX(p_TermBuf)) {
			p_TermBuf->tCurY++;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,
				p_TermBuf->tCurY,1L,0L);
		}
	}
}

void tbCurRight(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		if (p_TermBuf->tCurX<TB_GETXMAX(p_TermBuf)) {
			p_TermBuf->tCurX++;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,
				p_TermBuf->tCurY,1L,0L);
		}
	}
}

void tbCurLeft(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		if (p_TermBuf->tCurX>0) {
			p_TermBuf->tCurX--;
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_MOVECUR,p_TermBuf->tCurX,
				p_TermBuf->tCurY,1L,0L);
		}
	}
}

/* inserts p_Spaces blanks at the cursor's position, no wraparound */
void tbInsertChar(TBTERMBUF *p_TermBuf,int p_Spaces) {
	long i;
	if (p_TermBuf) {
		if (p_Spaces<0)
			p_Spaces=1;
		if (p_Spaces>TB_GETXMAX(p_TermBuf)-p_TermBuf->tCurX) {
			tbClearRight(p_TermBuf);
		} else {
			for (i=TB_GETXMAX(p_TermBuf)-p_Spaces;i>=p_TermBuf->tCurX;i--) {
				*TB_GETCHARADDR(p_TermBuf,i+p_Spaces,p_TermBuf->tCurY)=
				*TB_GETCHARADDR(p_TermBuf,i,p_TermBuf->tCurY);
			}
			for (i=p_TermBuf->tCurX;i<p_TermBuf->tCurX+p_Spaces;i++)
				*TB_GETCHARADDR(p_TermBuf,i,p_TermBuf->tCurY)=
          p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);

			if (p_TermBuf->tNotifyFn)
				(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
					p_TermBuf->tCurX,p_TermBuf->tCurY,TB_GETXMAX(p_TermBuf),p_TermBuf->tCurY);
		}
	}
}

/* clears from cursor position to end of display, inclusive */
void tbClearBelow(TBTERMBUF *p_TermBuf) {
	long l_x,l_y;
	if (p_TermBuf) {
		for (l_y=p_TermBuf->tCurY;l_y<=TB_GETYMAX(p_TermBuf);l_y++) {
			if (l_y==p_TermBuf->tCurY)
				l_x=p_TermBuf->tCurX;
			else
				l_x=0;

			for (;l_x<=TB_GETXMAX(p_TermBuf);l_x++)
				*TB_GETCHARADDR(p_TermBuf,l_x,l_y)=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,0L,p_TermBuf->tCurY,
			TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf));
	}
}

/* clears from cursor position to start of display, inclusive */
void tbClearAbove(TBTERMBUF *p_TermBuf) {
	long l_x,l_y;
	if (p_TermBuf) {
		for (l_y=0;l_y<=p_TermBuf->tCurY;l_y++) {
			if (l_y==p_TermBuf->tCurY)
				l_x=p_TermBuf->tCurX;
			else
				l_x=TB_GETXMAX(p_TermBuf);
			for (;l_x>=0;l_x--)
				*TB_GETCHARADDR(p_TermBuf,l_x,l_y)=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,0L,0L,
				TB_GETXMAX(p_TermBuf),p_TermBuf->tCurY);
	}
}

/* Inserts p_NumLines lines at cursor position. Lines above bottom margin are lost. */
void tbInsertLine(TBTERMBUF *p_TermBuf,long l_NumLines){
	long l_i;
	if (p_TermBuf) {
		for (l_i=0;l_i<l_NumLines;l_i++) {
			tbMoveText(p_TermBuf,
				0,p_TermBuf->tCurY,                     /* start x,y */
				TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf),  /* end x,y */
				0,p_TermBuf->tCurY+1);                  /* destination start x,y */
		}
	}
}

/* Deletes p_NumLines lines at cursor position. Lines added at bottom are blank. */
void tbDeleteLine(TBTERMBUF *p_TermBuf,long l_NumLines){
	long l_i;
	if (p_TermBuf) {
		for (l_i=0;l_i<l_NumLines;l_i++) {
			tbMoveText(p_TermBuf,
				0,p_TermBuf->tCurY+1,                   /* start x,y */
				TB_GETXMAX(p_TermBuf),TB_GETYMAX(p_TermBuf),    /* end x,y */
				0,p_TermBuf->tCurY);                    /* destination start x,y */
		}
	}
}


/* This proc moves text from one place to another on the screen. It blanks the
 * source area with 0x20 (spaces) in the current background color */
/* note this proc DOES NOT pay ANY attention to the current scrolling region */
/* Furthermore, it can handle copying from and to regions outside the current screen */
void tbMoveText(TBTERMBUF *p_TermBuf,long p_startX,long p_startY,
	long p_endX,long p_endY,long p_destX,long p_destY) {
	long l_x,l_y,l_dstx,l_dsty,l_OffsetX,l_OffsetY;
	unsigned long l_Char,*l_pChar;
	long l_startX,l_startY,l_endX,l_endY,l_stepX,l_stepY;

	if (p_TermBuf) {
		/* let's make sure we go from top-left to bottom right */
		if (p_endX<p_startX) {
			l_x=p_startX;
			p_startX=p_endX;
			p_endX=l_x;
		}
		if (p_endY<p_startY) {
			l_y=p_startY;
			p_startY=p_endY;
			p_endX=l_y;
		}

		/* First, let's figure out the order in which we will be copying */
		if (p_startX<p_destX) {
			l_startX=p_endX;
			l_endX=p_startX;
			l_stepX=-1;
		} else {
			l_startX=p_startX;
			l_endX=p_endX;
			l_stepX=1;
		}
		l_OffsetX=p_destX-p_startX;
		if (p_startY<p_destY) {
			l_startY=p_endY;
			l_endY=p_startY;
			l_stepY=-1;
		} else {
			l_startY=p_startY;
			l_endY=p_endY;
			l_stepY=1;
		}
		l_OffsetY=p_destY-p_startY;

		for (l_y=l_startY;l_y!=(l_endY+l_stepY);l_y+=l_stepY) {
			for (l_x=l_startX;l_x!=(l_endX+l_stepX);l_x+=l_stepX) {
				/* first, let's get & clear our source */
				if ((l_y>=0)&&(l_y<=TB_GETYMAX(p_TermBuf))&&
						(l_x>=0)&&(l_x<=TB_GETXMAX(p_TermBuf))) {
					l_pChar=TB_GETCHARADDR(p_TermBuf,l_x,l_y);
					l_Char=*l_pChar;
					*l_pChar=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
				} else {
					l_Char=p_TermBuf->tCurrentAttribute|TB_MAKECHAR(0x20);
				}
				/* next, let's save this char in it's destination spot */
				l_dstx=l_x+l_OffsetX;
				l_dsty=l_y+l_OffsetY;
				if ((l_dsty>=0)&&(l_dsty<=TB_GETYMAX(p_TermBuf))&&
						(l_dstx>=0)&&(l_dstx<=TB_GETXMAX(p_TermBuf))) {
					*TB_GETCHARADDR(p_TermBuf,l_dstx,l_dsty)=l_Char;
				}
			}
		}
		if (p_TermBuf->tNotifyFn)
			(*(p_TermBuf->tNotifyFn))(p_TermBuf->tID,TBNOTIFY_NEWCHAR,
				p_startX<p_destX?p_startX:p_destX,
				p_startY<p_destY?p_startY:p_destY,
				p_startX<p_destX?p_endX+l_OffsetX:p_endX,
        p_startY<p_destY?p_endY+l_OffsetY:p_endY);
	}
}

void tbCreateUnderscorePen(TBTERMBUF *p_TermBuf,int p_FontHeight) {
	int l_i,l_width;

	if (p_TermBuf) {
		l_width=(p_FontHeight+5)/10;
		if (!l_width)
			l_width=1;
		for (l_i=0;l_i<(1<<TB_COLOURDEPTH);l_i++) {
			if ((p_TermBuf->tColourPen)[l_i]) {
				DeleteObject((p_TermBuf->tColourPen)[l_i]);
			}
			(p_TermBuf->tColourPen)[l_i]=CreatePen(PS_SOLID,l_width,p_TermBuf->tColourBank[l_i]);
		}
	}
}

/* save cursor and attributes */
void tbCursorSave(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		p_TermBuf->tSaveCurrentAttribute=p_TermBuf->tCurrentAttribute;
		p_TermBuf->tSaveCurX=p_TermBuf->tCurX;
		p_TermBuf->tSaveCurY=p_TermBuf->tCurY;
	}
}

/* restore cursor and attributes */
void tbCursorRestore(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		p_TermBuf->tCurrentAttribute=p_TermBuf->tSaveCurrentAttribute;
		p_TermBuf->tCurX=p_TermBuf->tSaveCurX;
		p_TermBuf->tCurY=p_TermBuf->tSaveCurY;
	}
}

/* sets tabstop at specified position, or at current cursor position if p_X<1 */
void tbTabSet(TBTERMBUF *p_TermBuf,int p_Type, int p_X) {
	if (p_TermBuf) {
		if ((p_X>=0)&&(p_X<=(TB_GETXMAX(p_TermBuf)))) {
			p_TermBuf->tTab[p_X]=p_Type;
		} else {
			p_TermBuf->tTab[p_TermBuf->tCurX]=p_Type;
		}
	}
}

void tbTabClearAll(TBTERMBUF *p_TermBuf) {
	int l_i;
	if (p_TermBuf) {
		for (l_i=0;l_i<=TB_GETXMAX(p_TermBuf);l_i++) {
			p_TermBuf->tTab[l_i]=TBTAB_NONE;
		}
	}
}

void tbStartHilight(TBTERMBUF *p_TermBuf,int p_X,int p_Y) {
	if (p_TermBuf) {
		if (p_Y>TB_GETYMAX(p_TermBuf)) {
			p_Y=TB_GETYMAX(p_TermBuf);
			p_X=TB_GETXMAX(p_TermBuf);
		} else if (p_Y<TB_GETYMIN(p_TermBuf)) {
			p_Y=TB_GETYMIN(p_TermBuf);
			p_X=TB_GETXMIN(p_TermBuf);
		} else if (p_X>TB_GETXMAX(p_TermBuf)) {
			p_X=TB_GETXMAX(p_TermBuf);
		} else if (p_X<TB_GETXMIN(p_TermBuf)) {
			p_X=TB_GETXMIN(p_TermBuf);
		}
		p_TermBuf->tHLStartX=p_TermBuf->tHLEndX=p_X;
		p_TermBuf->tHLStartY=p_TermBuf->tHLEndY=p_Y;
	}
}

void tbUpdateHilight(TBTERMBUF *p_TermBuf,int p_X,int p_Y) {
	if (p_TermBuf) {
		if (p_Y>TB_GETYMAX(p_TermBuf)) {
			p_Y=TB_GETYMAX(p_TermBuf);
			p_X=TB_GETXMAX(p_TermBuf)+1;
		} else if (p_Y<TB_GETYMIN(p_TermBuf)) {
			p_Y=TB_GETYMIN(p_TermBuf);
			p_X=TB_GETXMIN(p_TermBuf);
		} else if (p_X>TB_GETXMAX(p_TermBuf)+1) {
			p_X=TB_GETXMAX(p_TermBuf)+1;
		} else if (p_X<TB_GETXMIN(p_TermBuf)) {
			p_X=TB_GETXMIN(p_TermBuf);
		}
		p_TermBuf->tHLEndX=p_X;
		p_TermBuf->tHLEndY=p_Y;
	}
}

void tbClearHilight(TBTERMBUF *p_TermBuf) {
	if (p_TermBuf) {
		p_TermBuf->tHLStartX=p_TermBuf->tHLStartY=0L; /* tHLEnd is ONE MORE than last tHLStart, so this gives us a NULL hilight */
		p_TermBuf->tHLEndX=p_TermBuf->tHLEndY=0L;     /* tHLEnd is ONE MORE than last tHLStart, so this gives us a NULL hilight */
	}
}

BOOL tbIsHilight(TBTERMBUF *p_TermBuf,int p_X,int p_Y) {
	if (p_TermBuf) {
		if (p_TermBuf->tHLStartY<p_TermBuf->tHLEndY) {
			/* we go from start, FORWARD to our end */
			if ((p_Y>p_TermBuf->tHLStartY) &&
					(p_Y<p_TermBuf->tHLEndY))
				return TRUE;
			if (p_Y==p_TermBuf->tHLStartY) {
				/* on starting line */
				if (p_X>=p_TermBuf->tHLStartX)
					return TRUE;
			} else if (p_Y==p_TermBuf->tHLEndY) {
				/* on ending line */
				if (p_X<p_TermBuf->tHLEndX)
					return TRUE;
			}
			return FALSE;
		} else if (p_TermBuf->tHLStartY>p_TermBuf->tHLEndY) {
			/* we go from start, BACKWARD to our end */
			if ((p_Y>p_TermBuf->tHLEndY) &&
					(p_Y<p_TermBuf->tHLStartY))
				return TRUE;
			if (p_Y==p_TermBuf->tHLEndY) {
				/* on starting line */
				if (p_X>=p_TermBuf->tHLEndX)
					return TRUE;
			} else if (p_Y==p_TermBuf->tHLStartY) {
				/* on ending line */
				if (p_X<p_TermBuf->tHLStartX)
					return TRUE;
			}
			return FALSE;
		} else if (p_TermBuf->tHLStartX<p_TermBuf->tHLEndX) {
			/* we go from start, FORWARD to our end */
			/* single line! */
			if ((p_Y==p_TermBuf->tHLStartY) &&
					(p_X >= p_TermBuf->tHLStartX) &&
					(p_X < p_TermBuf->tHLEndX) )
				return TRUE;
			return FALSE;
		} else if (p_TermBuf->tHLStartX>p_TermBuf->tHLEndX) {
			/* we go from start, BACKWARD to our end */
			/* single line! */
			if ((p_Y==p_TermBuf->tHLStartY) &&
					(p_X >= p_TermBuf->tHLEndX) &&
					(p_X < p_TermBuf->tHLStartX) )
				return TRUE;
			return FALSE;
		} else {
			/* no hilight */
			return FALSE;
		}
	}
	return FALSE;
}

/* returns the size, in bytes, the hilighted region would be expected to consume */
int tbHilightSize(TBTERMBUF *p_TermBuf) {
	int l_total;

	if (p_TermBuf) {
		if (p_TermBuf->tHLStartY<p_TermBuf->tHLEndY) {
			/* we go from start, FORWARD to our end */
			/* first, add in our full, margin-to-margin lines */
			l_total=(p_TermBuf->tHLEndY-p_TermBuf->tHLStartY-1)*(TB_GETXMAX(p_TermBuf)+1+2);
			/* next, our start line chunk */
			l_total+=(TB_GETXMAX(p_TermBuf)-p_TermBuf->tHLStartX+1);
			/* finally, our end line chunk */
			l_total+=p_TermBuf->tHLEndX;
			/* and allow for a few extra CRLF's */
			l_total+=6;
		} else if (p_TermBuf->tHLStartY>p_TermBuf->tHLEndY) {
			/* we go from start, BACKWARD to our end */
			/* first, add in our full, margin-to-margin lines */
			l_total=(p_TermBuf->tHLStartY-p_TermBuf->tHLEndY-1)*(TB_GETXMAX(p_TermBuf)+1+2);
			/* next, our start line chunk */
			l_total+=(TB_GETXMAX(p_TermBuf)-p_TermBuf->tHLEndX+1);
			/* finally, our end line chunk */
			l_total+=p_TermBuf->tHLStartX;
			/* and allow for a few extra CRLF's */
			l_total+=6;
		} else if (p_TermBuf->tHLStartX<p_TermBuf->tHLEndX) {
			/* we go from start, FORWARD to our end */
			/* single line! */
			l_total=p_TermBuf->tHLEndX-p_TermBuf->tHLStartX;
			/* and allow for a few extra CRLF's */
			l_total+=6;
		} else if (p_TermBuf->tHLStartX>p_TermBuf->tHLEndX) {
			/* we go from start, BACKWARD to our end */
			/* single line! */
			l_total=p_TermBuf->tHLStartX-p_TermBuf->tHLEndX;
			/* and allow for a few extra CRLF's */
			l_total+=6;
		} else {
			/* no hilight */
			l_total=0; /* a single 0x00 */
		}
	}
	return l_total;
}

/* copies hilighted region into buffer, inserting CRLF at the ends of lines */
void tbCopyHilight(TBTERMBUF *p_TermBuf,unsigned char *p_buf) {
	int l_sx,l_sy,l_ex,l_ey,l_x,l_y,l_char,l_CountEndX;
	unsigned char *l_p;

	if ((p_TermBuf)&&(p_buf)) {
		if (p_TermBuf->tHLStartY<p_TermBuf->tHLEndY) {
			/* we go from start, FORWARD to our end */
			l_sx=p_TermBuf->tHLStartX;
			l_sy=p_TermBuf->tHLStartY;
			l_ex=p_TermBuf->tHLEndX;
			l_ey=p_TermBuf->tHLEndY;
		} else if (p_TermBuf->tHLStartY>p_TermBuf->tHLEndY) {
			/* we go from start, BACKWARD to our end */
			l_sx=p_TermBuf->tHLEndX;
			l_sy=p_TermBuf->tHLEndY;
			l_ex=p_TermBuf->tHLStartX;
			l_ey=p_TermBuf->tHLStartY;
		} else if (p_TermBuf->tHLStartX<p_TermBuf->tHLEndX) {
			/* we go from start, FORWARD to our end */
			l_sx=p_TermBuf->tHLStartX;
			l_sy=p_TermBuf->tHLStartY;
			l_ex=p_TermBuf->tHLEndX;
			l_ey=p_TermBuf->tHLEndY;
		} else if (p_TermBuf->tHLStartX>p_TermBuf->tHLEndX) {
			/* we go from start, BACKWARD to our end */
			l_sx=p_TermBuf->tHLEndX;
			l_sy=p_TermBuf->tHLEndY;
			l_ex=p_TermBuf->tHLStartX;
			l_ey=p_TermBuf->tHLStartY;
		} else {
			/* no hilight */
      p_buf[0]=0;
			return;
		}
		l_p=p_buf;
		for (l_y=l_sy;l_y<=l_ey;l_y++) {

			if (l_y==l_sy)
				l_x=l_sx;
			else
				l_x=0;

			if (l_y==l_ey)
				l_CountEndX=l_ex;
			else
				l_CountEndX=TB_GETXMAX(p_TermBuf)+1;

			for (;l_x<l_CountEndX;l_x++) {
				/* copy this character */
				l_char=TB_GETCHAR(p_TermBuf,l_x,l_y);
				*l_p=(unsigned char)TB_EXTCHAR(l_char);
				l_p++;
			}
			/* As a courtesy, let's remove any trailing spaces */
			l_p--;
			while((l_p>=p_buf)&&(*l_p==' ')) {
				l_p--;
			}
      l_p++;
			/* end of line -- add CRLF */
			if (l_x>TB_GETXMAX(p_TermBuf)) {
				*l_p=0x0D;
				l_p++;
				*l_p=0x0A;
				l_p++;
			}
		}
		/* oh, and terminate the sucker. Forgot this the first time ;) */
		*l_p=0;
	}
	return;
}