/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by Olaf 'Olsen' Barthel & MXM
 *
 *	Name .....: ParseRoutines.c
 *	Created ..: Monday 21-Jan-91 20:12
 *	Revision .: 0
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	21-Jan-91       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#include "TermGlobal.h"


	/* Flag indicating whether the cursor has already been
	 * erased or not.
	 */

STATIC BYTE CursorEnabled = FALSE;

	/* Global string buffer and backup style. */

STATIC UBYTE GlobalBuffer[20],StyleType = FS_NORMAL;

	/* ClearCursor():
	 *
	 *	Clear the cursor image.
	 */

VOID
ClearCursor()
{
	if(CursorEnabled)
	{
		if(Config . FontScale == SCALE_HALF)
			ClipBlit(RPort,0,0,RPort,CursorX << 2,CursorY << 3,4,8,0x50);
		else
			ClipBlit(RPort,0,0,RPort,CursorX << 3,CursorY << 3,8,8,0x50);

		CursorEnabled = FALSE;
	}
}

	/* DrawCursor():
	 *
	 *	Explicitely (re-)draw the cursor image.
	 */

VOID
DrawCursor()
{
	if(Config . FontScale == SCALE_HALF)
		ClipBlit(RPort,0,0,RPort,CursorX << 2,CursorY << 3,4,8,0x50);
	else
		ClipBlit(RPort,0,0,RPort,CursorX << 3,CursorY << 3,8,8,0x50);

	CursorEnabled = TRUE;
}

	/* ColourValue(UWORD Colour):
	 *
	 *	Calculate the value of a given colour (brightness).
	 */

STATIC SHORT
ColourValue(UWORD Colour)
{
	BYTE	Red,Green,Blue;
	SHORT	Sum;

	Red	= (Colour >> 8) & 0xF;
	Green	= (Colour >> 4) & 0xF;
	Blue	= (Colour     ) & 0xF;

	Sum = (Red + Green + Blue) / 3;

	return(Sum);
}

	/* SetCursor():
	 *
	 *	Move the cursor to a given location.
	 */

VOID
SetCursor()
{
	USHORT X,Y,Hit;

	Hit = UseRegion ? Bottom : LastLine;

	if(CursorY > Hit)
		CursorY = Hit;

	X = CursorX * 8;
	Y = CursorY * 8 + 6;

	Move(RPort,X,Y);

	if(!CursorEnabled)
	{
		if(Config . FontScale == SCALE_HALF)
			ClipBlit(RPort,0,0,RPort,CursorX << 2,CursorY << 3,4,8,0x50);
		else
			ClipBlit(RPort,0,0,RPort,CursorX << 3,CursorY << 3,8,8,0x50);
	}

	CursorEnabled = TRUE;
}

	/* BackupRender():
	 *
	 *	Save current draw modes, pen and position or restore
	 *	the data.
	 */

VOID
BackupRender()
{
	STATIC BYTE	Called = FALSE;
	STATIC UBYTE	DrMd,FgPen,BgPen;
	STATIC UWORD	CpX,CpY;
	STATIC UBYTE	Style;

	if(!Called)
	{
		DrMd	= RPort -> DrawMode;
		FgPen	= RPort -> FgPen;
		BgPen	= RPort -> BgPen;

		CpX	= RPort -> cp_x;
		CpY	= RPort -> cp_y;

		Style	= StyleType;

		Called	= TRUE;
	}
	else
	{
		if(RPort -> DrawMode != DrMd)
			SetDrMd(RPort,DrMd);

		if(RPort -> FgPen != FgPen)
			SetAPen(RPort,FgPen);

		if(RPort -> BgPen != BgPen)
			SetBPen(RPort,BgPen);

		if(RPort -> cp_x != CpX || RPort -> cp_y != CpY)
			Move(RPort,CpX,CpY);

		if(Style != StyleType)
		{
			SetSoftStyle(RPort,Style,0xFF);

			StyleType = Style;
		}

		Called	= FALSE;
	}
}

	/* ShiftChar():
	 *
	 *	Simulate character insertion at the current cursor
	 *	position by shifting the whole line eight pixels
	 *	to the right.
	 */

VOID
ShiftChar()
{
	BackupRender();

	SetBPen(RPort,0);

	ClearCursor();

	ScrollRaster(RPort,-8,0,CursorX * 8,CursorY * 8,(LastColumn + 1) * 8 - 1,(CursorY + 1) * 8 - 1);

	DrawCursor();

	BackupRender();
}

	/* ScrollRegion(BYTE Direction):
	 *
	 *	Scroll the current scroll region up or down.
	 */

VOID
ScrollRegion(BYTE Direction)
{
	RasterScrollRegion(Direction);

	BackupRender();

	SetBPen(RPort,0);

	ClearCursor();

	if(Config . JumpScroll)
	{
		if(UseRegion)
			ScrollRaster(RPort,0,Direction,0,Top * 8,Window -> Width - 1,(Bottom + 1) * 8 - 1);
		else
			ScrollRaster(RPort,0,Direction,0,0,Window -> Width - 1,(LastLine + 1) * 8 - 1);
	}
	else
	{
		BYTE i,Diff = Direction / 4;

		if(UseRegion)
		{
			for(i = 0 ; i < 4 ; i++)
			{
				WaitTOF();

				ScrollRaster(RPort,0,Diff,0,Top * 8,Window -> Width - 1,(Bottom + 1) * 8 - 1);
			}
		}
		else
		{
			for(i = 0 ; i < 4 ; i++)
			{
				WaitTOF();

				ScrollRaster(RPort,0,Diff,0,0,Window -> Width - 1,(LastLine + 1) * 8 - 1);
			}
		}
	}

	DrawCursor();

	BackupRender();
}

	/* LastChar(UBYTE *Buffer):
	 *
	 *	Return the last character in a string.
	 */

STATIC UBYTE
LastChar(UBYTE *Buffer)
{
	SHORT Offset = 0;

	while(Buffer[Offset])
		Offset++;

	return(Buffer[Offset - 1]);
}

	/* ReadValue(UBYTE *Buffer,BYTE *Value):
	 *
	 *	Parse a buffer for numbers and return a pointer
	 *	to the next buffer element to contain additional
	 *	information.
	 */

STATIC UBYTE *
ReadValue(UBYTE *Buffer,SHORT *Value)
{
	while((*Buffer < '0' || *Buffer > '9') && *Buffer)
		Buffer++;

	if(*Buffer)
	{
		*Value = 0;

		while(*Buffer >= '0' && *Buffer <= '9')
			*Value = (*Value * 10) + (*Buffer++ - '0');
	}
	else
		*Value = -1;

	if(*Buffer == ';' || *Buffer == ' ')
		return(&Buffer[1]);
	else
		return(NULL);
}

	/* Ignore():
	 *
	 *	Do nothing, return immediately.
	 */

UBYTE *
Ignore()
{
	return(NULL);
}

	/* CursorScrollDown():
	 *
	 *	Move cursor down and scroll region if necessary.
	 */

UBYTE *
CursorScrollDown()
{
	ClearCursor();

	if(UseRegion)
	{
		if(CursorY == Bottom)
			ScrollRegion(8);
		else
		{
			CursorY++;

			SetCursor();
		}
	}
	else
	{
		if(CursorY == LastLine)
			ScrollRegion(8);
		else
		{
			CursorY++;

			SetCursor();
		}
	}

	return(NULL);
}

	/* CursorScrollUp():
	 *
	 *	Move cursor up and scroll region if necessary.
	 */

UBYTE *
CursorScrollUp()
{
	ClearCursor();

	if(UseRegion)
	{
		if(CursorY == Top)
			ScrollRegion(-8);
		else
		{
			CursorY--;

			SetCursor();
		}
	}
	else
	{
		if(CursorY == 0)
			ScrollRegion(-8);
		else
		{
			CursorY--;

			SetCursor();
		}
	}

	return(NULL);
}

	/* NextLine():
	 *
	 *	Do something like CR+LF.
	 */

UBYTE *
NextLine()
{
	ClearCursor();

	CursorX = 0;

	if(UseRegion)
	{
		if(CursorY == Bottom)
			ScrollRegion(8);
		else
		{
			CursorY++;

			SetCursor();
		}
	}
	else
	{
		if(CursorY == LastLine)
			ScrollRegion(8);
		else
		{
			CursorY++;

			SetCursor();
		}
	}

	return(NULL);
}

	/* SaveCursor():
	 *
	 *	Save cursor position and rendering attributes.
	 */

UBYTE *
SaveCursor()
{
	CursorBackup . Charset		= Charset;
	CursorBackup . Attributes	= Attributes;
	CursorBackup . UseRegion	= UseRegion;
	CursorBackup . Top		= Top;
	CursorBackup . Bottom		= Bottom;
	CursorBackup . CursorX		= CursorX;
	CursorBackup . CursorY		= CursorY;

	return(NULL);
}

	/* FontStuff(UBYTE *Buffer):
	 *
	 *	Set the drawing font (standard characters/line).
	 */

UBYTE *
FontStuff(UBYTE *Buffer)
{
	switch(LastChar(Buffer))
	{
		case 'A':
		case 'B':	if(Config . Font == FONT_TOPAZ)
					SetFont(RPort,Topaz);
				else
				{
					if(IBM)
						SetFont(RPort,IBM);
				}

				break;

		case '0':	if(GFX)
					SetFont(RPort,GFX);

				break;

		default:	break;
	}

	return(NULL);
}

	/* LoadCursor():
	 *
	 *	Load cursor position and rendering attributes.
	 */

UBYTE *
LoadCursor()
{
	LONG TextFlags = FS_NORMAL;

	ClearCursor();

	if(CursorBackup . Attributes & ATTR_UNDERLINE)
		TextFlags |= FSF_UNDERLINED;

	if((CursorBackup . Attributes & ATTR_HIGHLIGHT) && Config . ColourMode != COLOUR_SIXTEEN)
		TextFlags |= FSF_BOLD;

	if(CursorBackup . Attributes & ATTR_BLINK)
	{
		if(Config . Emulation == EMULATION_ANSIVT100)
		{
			switch(Config . ColourMode)
			{
				case COLOUR_AMIGA:	if(CursorBackup . Attributes & ATTR_INVERSE)
								BgPen = 3;
							else
								FgPen = 3;

							break;

				case COLOUR_EIGHT:	if(CursorBackup . Attributes & ATTR_INVERSE)
								BgPen |= 8;
							else
								FgPen |= 8;

							break;

				case COLOUR_SIXTEEN:	break;
			}
		}
	}

	if(StyleType != TextFlags)
	{
		SetSoftStyle(RPort,TextFlags,0xFF);

		StyleType = TextFlags;
	}

	if(RPort -> FgPen != FgPen)
		SetAPen(RPort,FgPen);

	if(RPort -> BgPen != BgPen)
		SetBPen(RPort,BgPen);

	Attributes	= CursorBackup . Attributes;
	UseRegion	= CursorBackup . UseRegion;
	Top		= CursorBackup . Top;
	Bottom		= CursorBackup . Bottom;
	CursorX		= CursorBackup . CursorX;
	CursorY		= CursorBackup . CursorY;

	SetCursor();

	return(NULL);
}

UBYTE *
ScaleFont(UBYTE *Buffer)
{
	ClearCursor();

	switch(LastChar(Buffer))
	{
		case '3':	if(Config . FontScale == SCALE_HALF)
				{
					CursorX >>= 1;
					SetCursor();

					if(Config . EightyColumns)
						LastColumn = 79;
					else
						LastColumn = (Window -> Width >> 3) - 1;
				}

				Config . FontScale = SCALE_TOP2X;

				break;

		case '4':	if(Config . FontScale == SCALE_HALF)
				{
					CursorX >>= 1;
					SetCursor();

					if(Config . EightyColumns)
						LastColumn = 79;
					else
						LastColumn = (Window -> Width >> 3) - 1;
				}

				Config . FontScale = SCALE_BOT2X;

				break;

		case '6':	if(Config . FontScale == SCALE_HALF)
				{
					CursorX >>= 1;
					SetCursor();

					if(Config . EightyColumns)
						LastColumn = 79;
					else
						LastColumn = (Window -> Width >> 3) - 1;
				}

				Config . FontScale = SCALE_2X;

				break;

		default:	if(Config . FontScale == SCALE_HALF)
				{
					CursorX >>= 1;
					SetCursor();

					if(Config . EightyColumns)
						LastColumn = 79;
					else
						LastColumn = (Window -> Width >> 3) - 1;
				}

				Config . FontScale = SCALE_NORMAL;

				break;
	}

	return(NULL);
}

	/* SetTab():
	 *
	 *	Set a tabulator stop at the current position.
	 */

UBYTE *
SetTab()
{
	if(CursorX < 1024)
		TabStops[CursorX] = TRUE;

	return(NULL);
}

	/* RequestTerminal(UBYTE *Buffer):
	 *
	 *	Return the current terminal position.
	 */

UBYTE *
RequestTerminal(UBYTE *Buffer)
{
	switch(Buffer[0])
	{
				/* Make ourselves known as a VT200
				 * terminal.
				 */

		case '[':	if(Buffer[1] != '>')
					return("\033[?62;1;2;6;7;8;9c");
				else
					return("\033[>1;10;0c");

				/* This is an old status request type,
				 * we will return the standard `I am a
				 * VT101' sequence.
				 */

		case 'Z':	return("\033[?1;0c");

		default:	return(NULL);
	}
}

	/* Reset():
	 *
	 *	Reset terminal to initial state.
	 */

UBYTE *
Reset()
{
	SHORT i;

	ClearCursor();

	memset(&TabStops[0],FALSE,1024);

	for(i = 9 ; i < 1024 ; i += 8)
		TabStops[i] = TRUE;

	SetRast(RPort,0);

	RasterEraseScreen(2);

	switch(Config . ColourMode)
	{
		case COLOUR_EIGHT:	FgPen = 7;
					break;

		case COLOUR_SIXTEEN:	FgPen = 15;
					break;

		case COLOUR_AMIGA:
		default:		FgPen = 1;
					break;
	}

	BgPen = 0;

	if(RPort -> FgPen != FgPen)
		SetAPen(RPort,FgPen);

	if(RPort -> BgPen != BgPen)
		SetBPen(RPort,BgPen);

	if(StyleType != FS_NORMAL)
	{
		SetSoftStyle(RPort,FS_NORMAL,0xFF);

		StyleType = FS_NORMAL;
	}

	if(Config . Font == FONT_TOPAZ)
		SetFont(RPort,Topaz);
	else
	{
		if(IBM)
			SetFont(RPort,IBM);
	}

	if(Config . EightyColumns)
		LastColumn = 79;
	else
		LastColumn = (Window -> Width >> 3) - 1;

	UseRegion		= FALSE;
	Config . AutoWrap	= TRUE;
	Config . NewLine	= FALSE;
	Config . InsertChar	= FALSE;
	Config . CursorApp	= FALSE;
	Config . NumApp		= FALSE;
	Config . FontScale	= SCALE_NORMAL;
	Config . JumpScroll	= TRUE;

	Attributes	= 0;
	Top		= 0;
	Bottom		= LastLine;
	CursorX		= 0;
	CursorY		= 0;

	CursorBackup . Charset		= Charset;
	CursorBackup . Attributes	= Attributes;
	CursorBackup . UseRegion	= UseRegion;
	CursorBackup . Top		= Top;
	CursorBackup . Bottom		= Bottom;
	CursorBackup . CursorX		= CursorX;
	CursorBackup . CursorY		= CursorY;

	SetCursor();

	return(NULL);
}

	/* RequestInformation(UBYTE *Buffer):
	 *
	 *	Request miscellaneous information (state & cursor position).
	 */

UBYTE *
RequestInformation(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	switch(Value)
	{
				/* Terminal status report, return code
				 * for `no malfunction'.
				 */

		case 5:		return("\033[0n");

				/* The origin is placed at 0/0 and the first
				 * cursor position is 1/1. We'll have to add
				 * 1 to our internal positions since our
				 * universe has been shifted one field to the
				 * left top corner.
				 */

		case 6:		SPrintf(GlobalBuffer,"\033[%ld;%ldR",CursorY + 1,CursorX + 1);
				return(GlobalBuffer);

				/* A VT200 command: request printer status.
				 * We will return `no printer connected'.
				 */

		case 15:	return("\033[?13n");

				/* VT200 command: request user defined
				 * key status. We will return `user
				 * defined keys are locked'.
				 */

		case 25:	return("\033[?21n");

				/* Another VT200 command: request
				 * keyboard language. We will return
				 * `keyboard language unknown' - does
				 * anybody know when locale.library will
				 * be released?
				 */

		case 26:	return("\033[?27;0n");

		default:	return(NULL);
	}
}

	/* SetSomething(UBYTE *Buffer):
	 *
	 *	Set a terminal option.
	 */

UBYTE *
SetSomething(UBYTE *Buffer)
{
	if(Buffer[1] == '?')
	{
		switch(Buffer[2])
		{
			case '1':	if(Buffer[3] == 'h')
						Config . CursorApp = TRUE;
					else
						Config . CursorApp = FALSE;

					return(NULL);

			case '3':	if(Buffer[3] == 'h')
					{
						Config . FontScale = SCALE_HALF;

						if(Config . EightyColumns)
							LastColumn = 131;
						else
							LastColumn = (Window -> Width >> 2) - 1;
					}
					else
					{
						if(Config . FontScale == SCALE_HALF)
						{
							ClearCursor();

							CursorX >>= 1;

							SetCursor();

							if(Config . EightyColumns)
								LastColumn = 79;
							else
								LastColumn = (Window -> Width >> 3) - 1;

							DrawCursor();
						}

						Config . FontScale = SCALE_NORMAL;
					}

					break;

			case '4':	if(Buffer[3] == 'h')
						Config . JumpScroll = FALSE;
					else
						Config . JumpScroll = TRUE;

					break;

			case '6':	if(Buffer[3] == 'h')
						UseRegion = TRUE;
					else
						UseRegion = FALSE;

					return(NULL);

			case '7':	if(Buffer[3] == 'h')
						Config . AutoWrap = TRUE;
					else
						Config . AutoWrap = FALSE;

					return(NULL);

			case '9':	if(Buffer[3] == 'h')
					{
						if(!(Config . DisplayMode & LACE))
						{
							CopyMem(&Config,&PrivateConfig,sizeof(struct Configuration));

							Config . DisplayMode |= LACE;

							ResetDisplay = TRUE;
						}
					}
					else
					{
						if(Config . DisplayMode & LACE)
						{
							CopyMem(&Config,&PrivateConfig,sizeof(struct Configuration));

							Config . DisplayMode &= ~LACE;

							ResetDisplay = TRUE;
						}
					}

					return(NULL);

			default:	return(NULL);
		}
	}
	else
	{
		if(Buffer[1] == '2' && Buffer[2] == '0')
		{
			if(Buffer[3] == 'h')
				Config . NewLine = TRUE;
			else
				Config . NewLine = FALSE;
		}
		else
		{
			if(Buffer[1] == '4')
			{
				if(Buffer[2] == 'h')
					Config . InsertChar = TRUE;
				else
					Config . InsertChar = FALSE;
			}
		}
	}

	return(NULL);
}

	/* NumericAppMode(UBYTE *Buffer):
	 *
	 *	Set the numeric pad applications mode.
	 */

UBYTE *
NumericAppMode(UBYTE *Buffer)
{
	if(*Buffer == '=')
		Config . NumApp = TRUE;
	else
	{
		if(*Buffer == '>')
			Config . NumApp = FALSE;
	}

	return(NULL);
}

	/* MoveCursor(UBYTE *Buffer):
	 *
	 *	Move the cursor in some direction and stop at
	 *	top/bottom/margin if necessary.
	 */

UBYTE *
MoveCursor(UBYTE *Buffer)
{
	SHORT Value;

	switch(LastChar(Buffer))
	{
		case 'A':	ReadValue(Buffer,&Value);

				if(Value == -1)
					Value = 1;

				ClearCursor();

				if(UseRegion)
				{
					if(CursorY - Value > Top)
						CursorY -= Value;
					else
						CursorY = Top;
				}
				else
				{
					if(CursorY - Value > 0)
						CursorY -= Value;
					else
					{
						if(Config . CursorWrap)
						{
							SHORT i;

							Value -= CursorY;

							for(i = 0 ; i < Value ; i++)
								ScrollRegion(-8);
						}

						CursorY = 0;
					}
				}

				break;

		case 'B':	ReadValue(Buffer,&Value);

				if(Value == -1)
					Value = 1;

				ClearCursor();

				if(UseRegion)
				{
					if(CursorY + Value < Bottom)
						CursorY += Value;
					else
						CursorY = Bottom;
				}
				else
				{
					if(CursorY + Value < LastLine)
						CursorY += Value;
					else
					{
						if(Config . CursorWrap)
						{
							SHORT i;

							Value = CursorY + Value - LastLine;

							for(i = 0 ; i < Value ; i++)
								ScrollRegion(8);
						}

						CursorY = LastLine;
					}
				}

				break;

		case 'C':	ReadValue(Buffer,&Value);

				if(Value == -1)
					Value = 1;

				ClearCursor();

				if(CursorX + Value < LastColumn)
					CursorX += Value;
				else
				{
					SHORT i;

					Value = (CursorX + Value) - LastColumn;

					CursorX = LastColumn;

					if(Config . CursorWrap)
					{
						if(UseRegion)
						{
							for(i = 0 ; i < Value ; i++)
							{
								if(CursorX == LastColumn)
								{
									if(CursorY == Bottom)
										ScrollRegion(8);
									else
										CursorY++;

									CursorX = 0;
								}
								else
									CursorX++;
							}
						}
						else
						{
							for(i = 0 ; i < Value ; i++)
							{
								if(CursorX == LastColumn)
								{
									if(CursorY == LastLine)
										ScrollRegion(8);
									else
										CursorY++;

									CursorX = 0;
								}
								else
									CursorX++;
							}
						}
					}
				}

				break;

		case 'D':	ReadValue(Buffer,&Value);

				if(Value == -1)
					Value = 1;

				ClearCursor();

				if(CursorX - Value > 0)
					CursorX -= Value;
				else
				{
					Value -= CursorX;

					CursorX = 0;

					if(Config . CursorWrap)
					{
						SHORT i;

						if(UseRegion)
						{
							for(i = 0 ; i < Value ; i++)
							{
								if(CursorX == 0)
								{
									if(CursorY == Top)
										ScrollRegion(-8);
									else
										CursorY--;

									CursorX = LastColumn;
								}
								else
									CursorX--;
							}
						}
						else
						{
							for(i = 0 ; i < Value ; i++)
							{
								if(CursorX == 0)
								{
									if(CursorY == 0)
										ScrollRegion(-8);
									else
										CursorY--;

									CursorX = LastColumn;
								}
								else
									CursorX--;
							}
						}
					}
				}

				break;

		default:	break;
	}

	SetCursor();

	return(NULL);
}

	/* EraseLine(UBYTE *Buffer):
	 *
	 *	Erase a line on the display.
	 */

UBYTE *
EraseLine(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	BackupRender();

	SetAPen(RPort,0);

	RasterEraseLine(Value);

	ClearCursor();

	switch(Value)
	{
		case 1:	RectFill(RPort,0,CursorY * 8,(CursorX + 1) * 8 - 1,(CursorY + 1) * 8 - 1);
			break;

		case 2:	RectFill(RPort,0,CursorY * 8,Window -> Width - 1,(CursorY + 1) * 8 - 1);
			break;

		default:RectFill(RPort,CursorX * 8,CursorY * 8,Window -> Width - 1,(CursorY + 1) * 8 - 1);
			break;
	}

	DrawCursor();

	BackupRender();

	return(NULL);
}

	/* EraseScreen(UBYTE *Buffer):
	 *
	 *	Erase parts of the screen.
	 */

UBYTE *
EraseScreen(UBYTE *Buffer)
{
	SHORT Value;

	ClearCursor();

	ReadValue(Buffer,&Value);

	BackupRender();

	SetAPen(RPort,0);

	RasterEraseScreen(Value);

	switch(Value)
	{
		case 1:	RectFill(RPort,0,0,Window -> Width - 1,(CursorY + 1) * 8 - 1);
			break;

		case 2:	RectFill(RPort,0,0,Window -> Width - 1,(LastLine + 1) * 8 - 1);
			break;

		default:RectFill(RPort,0,CursorY * 8,Window -> Width - 1,(LastLine + 1) * 8 - 1);
			break;
	}

	DrawCursor();

	BackupRender();

	return(NULL);
}

	/* EraseCharacters(UBYTE *Buffer):
	 *
	 *	Erase a number of characters.
	 */

UBYTE *
EraseCharacters(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	BackupRender();

	SetBPen(RPort,0);

	if(Value == -1)
		Value = 1;

	if(Value > 0)
	{
		RasterEraseCharacters(Value);

		ClearCursor();

		ScrollRaster(RPort,8 * Value,0,CursorX * 8,CursorY * 8,Window -> Width - 1,(LastLine + 1) * 8 - 1);

		DrawCursor();
	}

	BackupRender();

	return(NULL);
}

	/* InsertLine(UBYTE *Buffer):
	 *
	 *	Insert a number of lines and scroll the rest of the
	 *	display down.
	 */

UBYTE *
InsertLine(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	BackupRender();

	SetAPen(RPort,0);

	if(Value == -1)
		Value = 1;

	if(Value > 0)
	{
		RasterInsertLine(Value);

		ClearCursor();

		ScrollRaster(RPort,0,-8 * Value,0,CursorY * 8,Window -> Width - 1,(LastLine + 1) * 8 - 1);

		DrawCursor();
	}

	BackupRender();

	return(NULL);
}

	/* ClearLine(UBYTE *Buffer):
	 *
	 *	Clear a number of lines.
	 */

UBYTE *
ClearLine(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	BackupRender();

	SetAPen(RPort,0);

	if(Value == -1)
		Value = 1;

	if(Value > 0)
	{
		RasterClearLine(Value);

		ClearCursor();

		RectFill(RPort,0,CursorY * 8,Window -> Width - 1,(CursorY + Value + 1) * 8 - 1);

		DrawCursor();
	}

	BackupRender();

	return(NULL);
}

	/* SetTabs(UBYTE *Buffer):
	 *
	 *	Set the current tab stops.
	 */

UBYTE *
SetTabs(UBYTE *Buffer)
{
	SHORT Value;

	ReadValue(Buffer,&Value);

	if(Value == -1)
		Value = 0;

	switch(Value)
	{
		case 0:	if(CursorX < 1024)
				TabStops[CursorX] = FALSE;

			break;

		case 3:	memset(&TabStops[0],FALSE,1024);

			break;

		default:break;
	}

	return(NULL);
}

	/* SetPosition(UBYTE *Buffer):
	 *
	 *	Move the cursor to a given location on the display.
	 */

UBYTE *
SetPosition(UBYTE *Buffer)
{
	SHORT Value;

	Buffer = ReadValue(Buffer,&Value);

	ClearCursor();

	if(Value == -1)
	{
		CursorX = 0;

		if(UseRegion)
			CursorY = Top;
		else
			CursorY = 0;
	}
	else
	{
		/* Our raster origin is 0/0 instead of 1/1. */

		if(UseRegion)
			CursorY = Top + Value - 1;
		else
			CursorY = Value - 1;

		if(Buffer)
		{
			ReadValue(Buffer,&Value);

			if(Value != -1)
				CursorX = Value - 1;
			else
				CursorX = 0;
		}
		else
			CursorX = 0;
	}

	SetCursor();

	return(NULL);
}

	/* SetAttributes(UBYTE *Buffer):
	 *
	 *	Set the current display rendering attributes.
	 */

UBYTE *
SetAttributes(UBYTE *Buffer)
{
	LONG TextFlags = FS_NORMAL;
	SHORT Value;

	do
	{
		Buffer = ReadValue(Buffer,&Value);

		if(Value == -1)
			Value = 0;

		switch(Value)
		{
			case 0:	
				if((Attributes & ATTR_HIGHLIGHT) && Config . ColourMode == COLOUR_SIXTEEN)
				{
					if(Attributes & ATTR_INVERSE)
						BgPen &= ~8;
					else
						FgPen &= ~8;
				}

				if(Attributes & ATTR_BLINK)
				{
					switch(Config . ColourMode)
					{
						case COLOUR_AMIGA:
						case COLOUR_MONO:	if(Attributes & ATTR_INVERSE)
										BgPen = 1;
									else
										FgPen = 1;

									break;

						case COLOUR_EIGHT:	if(Attributes & ATTR_INVERSE)
										BgPen &= ~8;
									else
										FgPen &= ~8;

									break;

						default:		break;
					}
				}

				if(Attributes & ATTR_INVERSE)
				{
					BYTE Help;

					Help	= FgPen;
					FgPen	= BgPen;
					BgPen	= Help;
				}
/*
				switch(Config . ColourMode)
				{
					case COLOUR_EIGHT:	FgPen = 7;
								break;

					case COLOUR_SIXTEEN:	FgPen = 15;
								break;

					case COLOUR_AMIGA:
					default:		FgPen = 1;
								break;
				}

				BgPen = 0;*/

				if(RPort -> FgPen != FgPen)
					SetAPen(RPort,FgPen);

				if(RPort -> BgPen != BgPen)
					SetBPen(RPort,BgPen);

				Attributes = 0;

				break;

			case 1:	Attributes |= ATTR_HIGHLIGHT;

				break;

			case 4:	Attributes |= ATTR_UNDERLINE;

				break;

			case 5:	Attributes |= ATTR_BLINK;

				break;

			case 7:	if(!(Attributes & ATTR_INVERSE))
				{
					BYTE Help;

					Help	= FgPen;
					FgPen	= BgPen;
					BgPen	= Help;
				}

				Attributes |= ATTR_INVERSE;

				break;

			default:if(Value >= 30)
				{
					if(Value <= 37)
					{
						if(Attributes & ATTR_INVERSE)
							BgPen = Value - 30;
						else
							FgPen = Value - 30;
					}
					else
					{
						if(Value >= 40 && Value <= 47)
						{
							if(Attributes & ATTR_INVERSE)
								FgPen = Value - 40;
							else
								BgPen = Value - 40;
						}
					}
				}

				break;
		}
	}
	while(Buffer);

	if(Attributes & ATTR_UNDERLINE)
		TextFlags |= FSF_UNDERLINED;

	if(Attributes & ATTR_HIGHLIGHT)
	{
		if(Config . ColourMode == COLOUR_SIXTEEN)
		{
			if(Attributes & ATTR_INVERSE)
				BgPen |= 8;
			else
				FgPen |= 8;
		}
		else
			TextFlags |= FSF_BOLD;
	}

	if(Attributes & ATTR_BLINK)
	{
		if(Config . Emulation == EMULATION_ANSIVT100)
		{
			switch(Config . ColourMode)
			{
				case COLOUR_AMIGA:	if(Attributes & ATTR_INVERSE)
								BgPen = 3;
							else
								FgPen = 3;
							break;

				case COLOUR_EIGHT:	if(Attributes & ATTR_INVERSE)
								BgPen |= 8;
							else
								FgPen |= 8;
							break;

				case COLOUR_SIXTEEN:	break;

				case COLOUR_MONO:	if(Attributes & ATTR_INVERSE)
								BgPen = 1;
							else
								FgPen = 1;
							break;
			}
		}
	}

	if(TextFlags != StyleType)
	{
		SetSoftStyle(RPort,TextFlags,0xFF);

		StyleType = TextFlags;
	}

	if(Config . ColourMode == COLOUR_MONO)
	{
		if(ColourValue(FgPen) < ColourValue(BgPen))
		{
			FgPen = 0;
			BgPen = 1;
		}
		else
		{
			FgPen = 1;
			BgPen = 0;
		}
	}

	if(FgPen != RPort -> FgPen)
		SetAPen(RPort,FgPen);

	if(BgPen != RPort -> BgPen)
		SetBPen(RPort,BgPen);

	return(NULL);
}

	/* SetRegion(UBYTE *Buffer):
	 *
	 *	Set the current scroll region top and bottom.
	 */

UBYTE *
SetRegion(UBYTE *Buffer)
{
	SHORT Value;

	Buffer = ReadValue(Buffer,&Value);

	if(Value != -1)
	{
		Top = Value - 1;

		if(Buffer)
		{
			ReadValue(Buffer,&Value);

			if(Value != -1)
				Bottom = Value - 1;
		}

		UseRegion = TRUE;
	}

	return(NULL);
}
