/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
viotty.c
Abstract:
This module contains the VIO-TTY utilities procedures
Author:
Michael Jarus (mjarus) 12-Apr-1992
Environment:
User Mode Only
Revision History:
--*/
#define WIN32_ONLY
#include "os2ses.h"
#include "event.h"
#include "trans.h"
#include "vio.h"
#include "os2win.h"
#include <io.h>
#include <stdio.h>
#include <limits.h>
/*
* - character definitions for ANSI 3.64
*/
#define ANSI_ESC 0x1b /* ESC - escape */
#define ANSI_CUU 0x41 /* ESC[<n>A - cursor up */
#define ANSI_CUD 0x42 /* ESC[<n>B - cursor down */
#define ANSI_CUF 0x43 /* ESC[<n>C - cursor forward */
#define ANSI_CUB 0x44 /* ESC[<n>D - cursor back */
#define ANSI_CUP 0x48 /* ESC[<row>;<col>H - cursor position */
#define ANSI_ED 0x4a /* ESC[2J - erase display */
#define ANSI_EL 0x4b /* ESC[K - erase line */
#define ANSI_CUP1 0x66 /* ESC[<row>;<col>f - cursor position */
#define ANSI_SMOD 0x68 /* ESC[=<s>h - set mode */
#define ANSI_RMOD 0x6c /* ESC[=<s>l - reset mode */
#define ANSI_SGR 0x6d /* ESC[<g1>;...;<gn>m - select graphic rendition */
#define ANSI_SCP 0x73 /* ESC[s - save cursor position */
#define ANSI_RCP 0x75 /* ESC[u - restore cursor position */
//#define ANSI_ICH 0x40 /* ESC[@ insert character */
//#define ANSI_CNL 0x45 /* ESC[E cursor to next line */
//#define ANSI_CPL 0x46 /* ESC[F cursor to previous line */
//#define ANSI_IL 0x4c /* ESC[L insert line */
//#define ANSI_DL 0x4d /* ESC[M delete line */
//#define ANSI_DCH 0x50 /* ESC[P delete character */
//#define ANSI_SU 0x53 /* ESC[S scroll up */
//#define ANSI_SD 0x54 /* ESC[T scroll down */
//#define ANSI_ECH 0x58 /* ESC[X erase character */
//#define ANSI_CBT 0x5a /* ESC[Z backward tabulation */
/* states of the finite state machine */
#define NOCMD 1 /* type of crt state - most chars will go onto screen */
#define ESCED 2 /* we've seen an ESC, waiting for rest of CSI */
#define EQCMD 3 /* if '=' goto MODPARAMS else PARAMS */
#define PARAMS 4 /* we're building the parameter list for ansicmd */
#define MODPARAMS 5 /* we're building the parameter list for MODCMD */
#define MODCMD 6 /* we've seen "ESC[=Num" waiting for #h or #l (# in {0..7}) */
#define MODDBCS 7 /* we've seen DBCS lead-in char */
#define NPARMS 4 /* max # of params */
#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
#define OS2_BACKGROUND_MASK (OS2_BACKGROUND_BLUE | OS2_BACKGROUND_GREEN | OS2_BACKGROUND_RED)
#define OS2_FOREGROUND_MASK (OS2_FOREGROUND_BLUE | OS2_FOREGROUND_GREEN | OS2_FOREGROUND_RED)
#define OS2_BACKGROUND_WHITE (OS2_BACKGROUND_BLUE | OS2_BACKGROUND_GREEN | OS2_BACKGROUND_RED)
#define OS2_FOREGROUND_WHITE (OS2_FOREGROUND_BLUE | OS2_FOREGROUND_GREEN | OS2_FOREGROUND_RED)
#define OS2_BACKGROUND_BLACK 0
#define OS2_FOREGROUND_BLACK 0
#define OS2_DEFAULT (OS2_FOREGROUND_WHITE | OS2_BACKGROUND_BLACK)
#define TTY_LAST_PARMS_MAX ((USHRT_MAX - 10) / 10)
#define TTY_DEST_BUFFER ((PCHAR)Ow2VioDataAddress)
extern CONSOLE_SCREEN_BUFFER_INFO StartUpScreenInfo;
extern HANDLE Od2VioWriteSemHandle;
DWORD
Od2AcquireMutant(
IN HANDLE handle
);
DWORD
Od2ReleaseMutant(
IN HANDLE handle
);
DWORD
Ow2VioUpdateCurPos(
IN COORD CurPos
);
COORD Ow2TtySavedCursorPosition; /* CurPos for saving */
USHORT Ow2TtyParmList[NPARMS]; /* parameter list */
ULONG Ow2TtyParmNum; /* index of parameter we're building */
USHORT Ow2TtyAnsiState; /* state of machine */
USHORT Ow2TtyIgnoreNextChar;
COORD Ow2TtyCoord;
DWORD Ow2TtyNumBytes;
DWORD
Ow2TtyScreen(
IN LPSTR SourStr,
IN DWORD cnt
);
VOID
Ow2TtyClrParam();
DWORD
Ow2TtyAnsiCmd(
IN CHAR c,
OUT BOOL *NewCoord
);
USHORT
Ow2TtyRange(
USHORT val,
USHORT def,
USHORT min,
USHORT max
);
DWORD
Ow2TtyFlushStr();
DWORD
Ow2TtySetAttr();
static BYTE ColorTable[8] = { 0, /* Black */
4, /* Red */
2, /* Green */
6, /* Yellow */
1, /* Blue */
5, /* Magenta */
3, /* Cyan */
7}; /* White */
#if DBG
BYTE Ow2TtyScreenStr[] = "Ow2TtyScreen";
BYTE Ow2TtyAnsiCmdStr[] = "Ow2TtyAnsiCmd";
BYTE Ow2TtySetAttrStr[] = "Ow2TtySetAttr";
BYTE Ow2TtyFlushStrStr[] = "Ow2TtyFlushStr";
#endif
DWORD
AnsiInitForSession()
{
SesGrp->AnsiMode = ANSI_ON;
SesGrp->WinAttr = (USHORT)StartUpScreenInfo.wAttributes;
#ifdef DBCS
// MSKK Feb.2.1993 V-AkihiS
MapWin2Os2Attr(SesGrp->WinAttr, &(SesGrp->AnsiCellAttr[0]));
#else
SesGrp->AnsiCellAttr[0] = MapWin2Os2Attr(SesGrp->WinAttr);
SesGrp->AnsiCellAttr[1] = SesGrp->AnsiCellAttr[2] = 0;
#endif
SesGrp->ansi_background = SesGrp->AnsiCellAttr[0] & OS2_BACKGROUND_MASK;
SesGrp->ansi_foreground = SesGrp->AnsiCellAttr[0] & OS2_FOREGROUND_MASK;
SesGrp->ansi_bold = (SesGrp->AnsiCellAttr[0] & OS2_FOREGROUND_INTENSITY) ? 1 : 0;
SesGrp->ansi_blink = (SesGrp->AnsiCellAttr[0] & OS2_BACKGROUND_BLINKING) ? 1 : 0;
return(AnsiInit());
}
DWORD
AnsiInit()
{
Ow2TtySavedCursorPosition = /*ansi_coord*/SesGrp->WinCoord;
Ow2TtyAnsiState = NOCMD; /* state of machine */
Ow2TtyIgnoreNextChar = 0;
return(0L);
}
DWORD
Ow2VioWriteTTYStr(
IN PUCHAR SourStr,
IN ULONG Length,
IN ULONG ExtRequestType
)
{
DWORD Rc;
VIOREQUESTNUMBER RequestType = (VIOREQUESTNUMBER) ExtRequestType;
USHORT Row, Col;
if (RequestType == VIOWrtStdOut)
{
if (!hStdOutConsoleType)
{
return (ERROR_INVALID_HANDLE);
}
} else if (RequestType == VIOWrtStdErr)
{
if (!hStdErrConsoleType)
{
return (ERROR_INVALID_HANDLE);
}
}
Od2AcquireMutant(Od2VioWriteSemHandle);
if (Rc = Ow2VioGetCurPos(&Row, &Col))
{
#if DBG
ASSERT1("OS2SES(VioTTY)-Ow2VioGetCurPos failed\n", FALSE);
#endif
Od2ReleaseMutant(Od2VioWriteSemHandle);
return(Rc);
}
#if DBG
IF_OD2_DEBUG( VIO )
{
UCHAR Buffer[256], *Ptr = SourStr, *Ptr1;
ULONG Count = Length, CurCount, i;
for ( ; Count ; Count -= CurCount, Ptr += CurCount )
{
CurCount = ( Count > 10 ) ? 10 : Count;
sprintf(Buffer, "%s %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
(Count == Length) ? "OS2SES(VioTTY):" : " " ,
Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[4],
Ptr[5], Ptr[6], Ptr[7], Ptr[8], Ptr[9]
);
Ptr1 = &Buffer[48];
for ( i = 0 ; i < 10 ; i++ )
{
if ( i >= CurCount )
{
Buffer[15 + i * 3] = Buffer[16 + i * 3] = Buffer[17 + i * 3] = ' ';
} else if (Ptr[i] < 0x20)
{
if (Ptr[i] == ANSI_ESC)
{
*Ptr1++ = '<';
*Ptr1++ = 'E';
*Ptr1++ = 'S';
*Ptr1++ = 'C';
*Ptr1++ = '>';
} else if (Ptr[i] == '\n')
{
*Ptr1++ = '<';
*Ptr1++ = 'N';
*Ptr1++ = 'L';
*Ptr1++ = '>';
} else if (Ptr[i] == '\r')
{
*Ptr1++ = '<';
*Ptr1++ = 'C';
*Ptr1++ = 'R';
*Ptr1++ = '>';
} else if (Ptr[i] == '\b')
{
*Ptr1++ = '<';
*Ptr1++ = 'B';
*Ptr1++ = 'S';
*Ptr1++ = '>';
} else if (Ptr[i] == '\t')
{
*Ptr1++ = '<';
*Ptr1++ = 'T';
*Ptr1++ = 'A';
*Ptr1++ = 'B';
*Ptr1++ = '>';
} else if (Ptr[i] == '\07')
{
*Ptr1++ = '<';
*Ptr1++ = 'B';
*Ptr1++ = 'E';
*Ptr1++ = 'L';
*Ptr1++ = 'L';
*Ptr1++ = '>';
} else
{
*Ptr1++ = '<';
*Ptr1++ = '0';
*Ptr1++ = 'x';
*Ptr1++ = ((Ptr[i] & 0xF0) >> 4) + '0';
*Ptr1++ = (Ptr[i] & 0x0F) + '0';
*Ptr1++ = '>';
}
} else
{
*Ptr1++ = Ptr[i];
}
}
*Ptr1++ = '\n';
*Ptr1 = '\0';
KdPrint((Buffer));
}
}
#endif
Rc = Ow2TtyScreen(
SourStr,
Length
);
Od2ReleaseMutant(Od2VioWriteSemHandle);
if (Rc == 1)
{
Rc = GetLastError();
}
if (Rc)
{
#if DBG
KdPrint(("OS2SES(VioTTY-VioWriteTTYStr): Rc %lu\n"));
ASSERT( FALSE );
#endif
}
return (Rc);
}
/*
** Basic concepts:
** The screen consists of rows and columns
** columns are numbered from the left, starting with one.
** rows on the screen are numbered from the top, starting with one.
** Thus, the home position in the upper left corner is row one, column one.
**
** Associated with each screen is the 'current active position'.
** It corresponds roughly to the cursor; in fact, after each call to screen
** the cursor will indicate the active position. Thus,
** the cursor movements really change the active position, and
** the cursor follows the change.
**
** This code implements a finite state machine that reads a stream of
** characters, and emits commands that alter the screen. All of these
** commands are issued via calls through the 'crtsw' array. Each element
** of this array consists of an aggregate of functions which are
** responsible for making the appropriate changes to the actual screen.
**
** The functions in the aggregate and their responsibities are:
**
** v_scroll(i)
** scroll the text on the screen i lines.
** This will move some lines off the screen, and some blank lines
** onto the screen. i may be negative, indicating that the text
** moves downward, and blank lines appear at the top.
** v_copy(sr, sc, dr, dc, cnt)
** sr and sc specify a source row and column.
** dr and dc specify a destination row and column.
** Count characters are copied from the source to the dest,
** with the copy proceeding from left to right, and top to bottom.
** If the source and destination overlap, the copy is done
** correctly.
** v_clear(r, c, cnt)
** Characters starting at row r and column are cleared to the
** space character.
** v_pchar(r, c, ch)
** The character ch is placed on the screen at row r, column c,
** using the current graphic rendition.
** return value is number of character positions to adjust active
** position by - zero means the character has no graphic
** representation.
** v_scurs(r, c)
** The cursor is moved to row r, column c.
** v_init()
** The screen and all data structures are initialized.
** v_sgr(i)
** The current graphic rendition (e. g. font, color) is set to
** that specified by i. See ANSI x3.64 for encoding.
*/
DWORD
Ow2TtyScreen(
IN LPSTR SourStr,
IN DWORD cnt
)
/*++
Routine Description:
This routine handles the TTY string and pass characters to the finite
state machine
Arguments:
SourStr - points to the array of characters
cnt - indicates how many characters are being passed.
Return Value:
Note:
--*/
{
register CHAR c;
BOOL NewCoord = FALSE; // for GET_LVB_PTR
BOOL OldWrap, NewWrap, NewParms, ignoreBSFlag;
PCHAR LVBPtr;
SHORT LFchar = FALSE;
DWORD Rc;
Ow2TtyCoord = SesGrp->WinCoord;
Ow2TtyNumBytes = 0;
LVBPtr = Ow2LvbGetPtr(Ow2TtyCoord);
while ( cnt-- )
{
c = *SourStr++;
// if (Ow2TtyIgnoreNextChar)
// {
// Ow2TtyIgnoreNextChar = 0;
// continue;
// }
switch ( Ow2TtyAnsiState )
{
case NOCMD:
if (( c == ANSI_ESC ) && SesGrp->AnsiMode)
{
/*
* Found ESC when ASNI_ON
* wait for remaining string
*/
Ow2TtyAnsiState = ESCED;
break;
} else
{
#ifdef DBCS
// MSKK Nov.17.1992 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(c, SesGrp->VioCP)) {
TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
Ow2TtyCoord.X++;
LVBUpdateTTYCharWithAttrAndCurPosDBCS(c, &LVBPtr, Ow2TtyAnsiState);
Ow2TtyAnsiState = MODDBCS;
}
else
#endif
if( c >= ' ' )
{
TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
Ow2TtyCoord.X++;
LVBUpdateTTYCharWithAttrAndCurPos(c, &LVBPtr);
}else
{
ignoreBSFlag = FALSE;
switch(c)
{
/*
* For each char:
* - check if to handle (BS at first column, etc.)
* - update cursor position (different according to the char)
* - update LVB pointer
* - put charcater in output buffer
*/
case '\n':
Ow2TtyCoord.Y++;
NewCoord = 1;
LFchar = Ow2TtyCoord.X;
Ow2TtyCoord.X = 0;
break;
case '\r':
if (Ow2TtyCoord.X > 0)
{
Ow2TtyCoord.X = 0;
NewCoord = 1;
}
break;
case '\b':
if ( Ow2TtyCoord.X > 0 )
{
Ow2TtyCoord.X--;
NewCoord = 1;
} else
{
// wincon move to previous line so don't
// pass this char.
ignoreBSFlag = TRUE;
}
break;
case '\t':
Ow2TtyCoord.X += (8 - (Ow2TtyCoord.X % 8));
NewCoord = 1;
break;
case '\07':
break;
default:
Ow2TtyCoord.X++;
LVBUpdateTTYCharWithAttrAndCurPos(c, &LVBPtr);
break;
} /* end switch */
if (!ignoreBSFlag)
{
TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
}
}
}
break;
case ESCED:
switch(c)
{
case '[':
Ow2TtyAnsiState = EQCMD;
Ow2TtyClrParam();
break;
default:
Ow2TtyAnsiState = NOCMD;
/*
* invalid string -
* put back last char and handle it in NOCMD mode
*/
cnt++ ;
SourStr--;
break;
}
break;
case EQCMD:
if (c == '=')
{
Ow2TtyAnsiState = MODPARAMS;
break;
}
Ow2TtyAnsiState = PARAMS;
NewParms = FALSE;
/* fall down into PARAMS mode */
case PARAMS:
if ( c >= '0' && c <= '9' )
{
if (Ow2TtyParmList[Ow2TtyParmNum] < TTY_LAST_PARMS_MAX)
{
Ow2TtyParmList[Ow2TtyParmNum] *= 10;
Ow2TtyParmList[Ow2TtyParmNum] += (c - '0');
NewParms = TRUE;
}
} else if (c == ';')
{
if ( Ow2TtyParmNum < (NPARMS - 1) )
{
NewParms = FALSE;
Ow2TtyParmNum++;
//NewParms = TRUE;
} else
{ Ow2TtyAnsiState = NOCMD;
/*
* invalid string -
* put back last char and handle it in NOCMD mode
*/
cnt++ ;
SourStr--;
}
} else
{
Ow2TtyAnsiState = NOCMD;
if (NewParms || (Ow2TtyParmNum == 0))
{
Ow2TtyParmNum++;
}
if ((Rc = Ow2TtyAnsiCmd(
c,
&NewCoord)) == 1)
{
#if DBG
KdPrint(("OS2SES(VIOTTY): failed on Ow2TtyAnsiCmd\n"));
#endif
return(1);
} else if ( Rc == 2 )
{
/*
* invalid string -
* put back last char and handle it in NOCMD mode
*/
cnt++ ;
SourStr--;
}
}
break;
case MODPARAMS:
if ( c >= '0' && c <= '9' )
{
if (Ow2TtyParmList[Ow2TtyParmNum] < TTY_LAST_PARMS_MAX)
{
Ow2TtyParmList[0] *= 10;
Ow2TtyParmList[0] += (c - '0');
break;
}
}
/* fall down into MODCMD mode */
case MODCMD:
Ow2TtyAnsiState = NOCMD;
if ( c == 'h' || c == 'l' )
{
if (Ow2TtyParmList[0] == 7)
{
OldWrap = ((SesGrp->OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) != 0);
NewWrap = (c == 'h');
if (OldWrap != NewWrap)
{
if(Ow2TtyFlushStr())
{
#if DBG
KdPrint(("OS2SES(TTY): failed on FlushStr1\n"));
#endif
return(1);
}
if (!Or2WinSetConsoleMode(
#if DBG
Ow2TtyScreenStr,
#endif
hConOut,
SesGrp->OutputModeFlags^ENABLE_WRAP_AT_EOL_OUTPUT))
{
#if DBG
ASSERT1("OS2SES(TTY): failed on SetConsoleMode\n", FALSE);
#endif
return (1);
}
SesGrp->OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT;
}
break;
} else if (Ow2TtyParmList[0] < 7)
{
if(Ow2TtyFlushStr())
{
#if DBG
KdPrint(("OS2SES(TTY): failed on FlushStr2\n"));
#endif
return(1);
}
/* According to the spec
=====================
0 => 40x25 black and white
1 => 40x25 color
2 => 80x25 black and white
3 => 80x25 color
4 => 320x200 color
5 => 320x200 black and white
6 => 640x200 black and white
0,1,4,5 => 40 col (2,3,6 => 80 col)
1,3,4, => color (0,2,5,6 =>b&w)
According to OS/2 1.21 (for WIN COM)
====================================
0,1 => 80x50 (2-6 => 80x25)
*/
VioSetScreenSize(
(SHORT)((Ow2TtyParmList[0] <= 1) ? 50 : 25),
(SHORT)80,
hConOut);
Ow2TtyCoord.X = Ow2TtyCoord.Y = 0;
NewCoord = TRUE;
break;
} else
{
// illegal parameter
break;
}
} // else - illegal character
/*
* invalid string -
* put back last char and handle it in NOCMD mode
*/
cnt++ ;
SourStr--;
break;
case MODDBCS:
#ifdef DBCS
// MSKK Feb.06.1992 V-AkihiS
TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
Ow2TtyCoord.X++;
LVBUpdateTTYCharWithAttrAndCurPosDBCS(c, &LVBPtr, Ow2TtyAnsiState);
Ow2TtyAnsiState = NOCMD;
#else
TTY_DEST_BUFFER[Ow2TtyNumBytes++] = ' ';
Ow2TtyCoord.X++;
LVBPtr += SesGrp->BytesPerCell;
Ow2TtyAnsiState = NOCMD;
#endif
break;
}
/*
* if past right hand edge
* move left and down
*/
if ( Ow2TtyCoord.X >= SesGrp->ScreenColNum )
{
if (SesGrp->OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT)
{
//Ow2TtyCoord.Y += (Ow2TtyCoord.X / SesGrp->ScreenColNum);
//Ow2TtyCoord.X = (Ow2TtyCoord.X % SesGrp->ScreenColNum);
//if (Ow2TtyCoord.X == 0)
//{
// Ow2TtyCoord.Y++;
//}
/*
* It happends only with '\n', so only one line at a time
*/
Ow2TtyCoord.Y++;
Ow2TtyCoord.X -= SesGrp->ScreenColNum;
} else
{
Ow2TtyCoord.X = SesGrp->ScreenColNum - 1;
NewCoord = TRUE;
}
} else if ( Ow2TtyCoord.X < 0 )
{
ASSERT(FALSE);
Ow2TtyCoord.X = 0;
}
/* if off screen, scroll */
if ( Ow2TtyCoord.Y >= SesGrp->ScreenRowNum )
{
//VioLVBScrollBuff((DWORD)(Ow2TtyCoord.Y - SesGrp->ScreenRowNum + 1));
/*
* It happends only with '\n', so only one line at a time
*/
//ASSERT(Ow2TtyCoord.Y == SesGrp->ScreenRowNum);
VioLVBScrollBuff(1);
Ow2TtyCoord.Y = SesGrp->ScreenRowNum - 1;
NewCoord = TRUE;
}
if (LFchar)
{
/*
* The console doesn't support LF but treats it as CR-LF.
* We send LF (does the scroll if necessary) and than move
* to the desire column
*/
if(Ow2TtyFlushStr())
{
#if DBG
KdPrint(("OS2SES(TTY): failed on FlushStr3\n"));
#endif
return(1);
}
if(Ow2VioSetCurPos((ULONG)Ow2TtyCoord.Y, (ULONG)LFchar))
{
ASSERT1( "OS2SES(VIOTTY): LF error on Ow2VioSetCurPos", FALSE );
}
Ow2TtyCoord = SesGrp->WinCoord;
LFchar = 0;
}
if ( NewCoord )
{
LVBPtr = Ow2LvbGetPtr(Ow2TtyCoord);
NewCoord = FALSE;
}
}
/* Flush */
if(Ow2TtyFlushStr())
{
#if DBG
KdPrint(("OS2SES(TTY): failed on FlushStr4\n"));
#endif
return(1);
}
#if DBG
IF_OD2_DEBUG( VIO )
{
ASSERT( Ow2TtyCoord.X == SesGrp->WinCoord.X );
ASSERT( Ow2TtyCoord.Y == SesGrp->WinCoord.Y );
}
#endif
return(0L);
}
/*
** Ow2TtyClrParam(lp) - clear the parameters for a screen
*/
VOID
Ow2TtyClrParam()
{
register USHORT i;
for ( i = 0; i < NPARMS; i += 1)
Ow2TtyParmList[i] = 0;
Ow2TtyParmNum = 0;
}
DWORD
Ow2TtyAnsiCmd(
IN CHAR c,
OUT BOOL *NewCoord
)
/*++
Routine Description:
This routine performs some ANSI 3.64 function, using the parameters
we've just gathered.
Arguments:
c - the character that indicates the function to be performed
NewCoord = where to flag if new coordinates were set
Return Value:
Should return 0.
1 - for any error (after ASSERT), RetCode from GetLastError().
Note:
Ow2TtyParmNum - length of parameter list
Ow2TtyParmList - list of Set Graphics Rendition values
Ow2TtyCoord - pointer to current screen coordinates
Ow2TtyCoord is updated if new coordinates were set and it also calls
Ow2TtyFlushStr to flush the TTY output buffer to the console.
hConOut is used for console handle.
If data/attr is written to the screen (erase line/display), the
LVB is updated.
--*/
{
DWORD NumFilled;
COORD Coord = Ow2TtyCoord;
BYTE Cell[4];
BOOL ValidCmd = TRUE;
//if (((Ow2TtyParmNum >= 3) && (c != ANSI_SGR)) ||
// ((Ow2TtyParmNum == 2) && (c != ANSI_CUP) && (c != ANSI_CUP1)) ||
// ((Ow2TtyParmNum == 1) && ((c == ANSI_SCP) || (c == ANSI_RCP))))
//{
// ValidCmd = FALSE;
//} else
switch ( c )
{
case ANSI_CUB: /* cursor backward */
Coord.X -= Ow2TtyRange(Ow2TtyParmList[0], 1, 0, Coord.X);
break;
case ANSI_CUF: /* cursor forward */
Coord.X += (SHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 0, (USHORT)(SesGrp->ScreenColNum - Coord.X - 1));
break;
case ANSI_CUU: /* cursor up */
Coord.Y -= Ow2TtyRange(Ow2TtyParmList[0], 1, 0, Coord.Y);
break;
case ANSI_CUD: /* cursor down */
Coord.Y += (SHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 0, (USHORT)(SesGrp->ScreenRowNum - Coord.Y - 1));
break;
case ANSI_CUP: /* cursor position */
case ANSI_CUP1: /* cursor position */
Coord.Y = (USHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum) - 1;
Coord.X = (USHORT)Ow2TtyRange(Ow2TtyParmList[1], 1, 1, SesGrp->ScreenColNum) - 1;
break;
case ANSI_ED: /* erase display */
#if 0
switch(Ow2TtyParmList[0])
{
case 2:
#endif
Coord.X = Coord.Y = 0;
if(Ow2TtyFlushStr())
{
return(1);
}
if (!Or2WinFillConsoleOutputCharacterA(
#if DBG
Ow2TtyAnsiCmdStr,
#endif
hConOut,
' ',
SesGrp->ScreenSize,
Coord,
&NumFilled))
{
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): failed on FillConsoleOutputCharacterA\n", FALSE);
#endif
return (1);
}
if (!Or2WinFillConsoleOutputAttribute(
#if DBG
Ow2TtyAnsiCmdStr,
#endif
hConOut,
(WORD)SesGrp->WinAttr,
NumFilled,
Coord,
&NumFilled))
{
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): failed on FillConsoleOutputAttribute\n", FALSE);
#endif
return (1);
}
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): partial data\n", NumFilled == SesGrp->ScreenSize );
#endif
Cell[0] = ' ';
Cell[1] = SesGrp->AnsiCellAttr[0];
Cell[2] = SesGrp->AnsiCellAttr[1];
Cell[3] = SesGrp->AnsiCellAttr[2];
VioLVBFillCell(&Cell[0],
Coord,
NumFilled);
//return(0);
#if 0
break;
case 0:
lclear(hConOut, Coord.X, Coord.Y,
((SesGrp->ScreenRowNum - Coord.X) * SesGrp->ScreenColNum) +
((SesGrp->ScreenColNum - Coord.X) + 1 ), SA_BONW);
break;
case 1:
lclear(hConOut, 0, 0, (Coord.Y)*SesGrp->ScreenColNum+Coord.X, SA_BONW);
break;
default:
#if DBG
IF_OD2_DEBUG( VIO )
{
KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown value(%u) for ED\n",
Ow2TtyParmList[0]));
}
#endif
ValidCmd = FALSE;
break;
}
#endif
break;
case ANSI_EL:
#if 0
switch(Ow2TtyParmList[0])
{
case 0:
#endif
if(Ow2TtyFlushStr())
{
return(1);
}
if (!Or2WinFillConsoleOutputCharacterA(
#if DBG
Ow2TtyAnsiCmdStr,
#endif
hConOut,
' ',
(DWORD)(SesGrp->ScreenColNum - Coord.X),
Coord,
&NumFilled))
{
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): failed on FillConsoleOutputCharacterA\n", FALSE);
#endif
return (1);
}
if (!Or2WinFillConsoleOutputAttribute(
#if DBG
Ow2TtyAnsiCmdStr,
#endif
hConOut,
(WORD)SesGrp->WinAttr,
NumFilled,
Coord,
&NumFilled))
{
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): failed on FillConsoleOutputAttribute\n", FALSE);
#endif
return (1);
}
#if DBG
ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): partial data\n",
NumFilled == (DWORD)(SesGrp->ScreenColNum - Coord.X));
#endif
Cell[0] = ' ';
Cell[1] = SesGrp->AnsiCellAttr[0];
Cell[2] = SesGrp->AnsiCellAttr[1];
Cell[3] = SesGrp->AnsiCellAttr[2];
VioLVBFillCell(&Cell[0],
Coord,
NumFilled);
//return(0);
#if 0
break;
break;
case 1: /* start to ap */
lclear(hConOut, 0, Coord.Y, Coord.X, SA_BONW);
break;
case 2: /* whole line */
lclear(hConOut, 0, Coord.Y, SesGrp->ScreenColNum, SA_BONW);
break;
default:
#if DBG
IF_OD2_DEBUG( VIO )
{
KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown value(%u) for ED\n",
Ow2TtyParmList[0]));
}
#endif
ValidCmd = FALSE;
break;
}
#endif
break;
case ANSI_SGR:
if(Ow2TtySetAttr())
{
return(1);
}
return(0);
case ANSI_SCP:
Ow2TtySavedCursorPosition = Coord;
break;
case ANSI_RCP:
Coord = Ow2TtySavedCursorPosition;
break;
#if 0
case ANSI_CPL: /* cursor to previous line */
Coord.Y -= Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
Coord.X = 1;
break;
case ANSI_CNL: /* cursor to next line */
Coord.Y += Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
Coord.X = 1;
break;
case ANSI_CBT: /* tab backwards */
col = Coord.X;
i = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (col + 7) >> 3);
if (col & 7)
{
Coord.X = (col & ~7) + 1;
--i;
}
Coord.X -= (i << 3);
break;
case ANSI_DCH: /* delete character */
Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
if ( Coord.X + Ow2TtyParmList[0] <= SesGrp->ScreenColNum ) {
lcopy(hConOut, Coord.X+Ow2TtyParmList[0]-1, Coord.Y-1,
Coord.X-1, Coord.Y-1, SesGrp->ScreenColNum-(Coord.X+Ow2TtyParmList[0]-1));
}
lclear(hConOut, SesGrp->ScreenColNum-Ow2TtyParmList[0], Coord.Y-1,
Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_DL: /* delete line */
Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenRowNum - Coord.Y) + 1);
/* copy lines up */
if ( Coord.Y + Ow2TtyParmList[0] <= SesGrp->ScreenRowNum ) {
lcopy(hConOut, 0, Coord.Y+Ow2TtyParmList[0]-1, 0, Coord.Y-1,
SesGrp->ScreenColNum*(SesGrp->ScreenRowNum-(Coord.Y+Ow2TtyParmList[0]-1)));
}
/* clear new stuff */
lclear(hConOut, 0, SesGrp->ScreenRowNum-Ow2TtyParmList[0],
SesGrp->ScreenColNum*Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_ECH: /* erase character */
Ow2TtyParmList[0] = Ow2TtyRange( Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
lclear(hConOut, Coord.X-1, Coord.Y-1, Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_ICH: /* insert character */
Ow2TtyParmList[0] = Ow2TtyRange( Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
if ( Coord.X + Ow2TtyParmList[0] <= SesGrp->ScreenColNum ) {
lcopy(hConOut, Coord.X-1, Coord.Y-1, Coord.X+Ow2TtyParmList[0]-1,
Coord.Y-1, SesGrp->ScreenColNum-(Coord.X+Ow2TtyParmList[0]-1));
}
lclear(hConOut, Coord.X-1, Coord.Y-1, Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_IL: /* insert line */
Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenRowNum - Coord.Y) + 1);
/* copy lines down */
if ( Coord.Y + Ow2TtyParmList[0] <= SesGrp->ScreenRowNum ) {
lcopy(hConOut, 0, Coord.Y-1, 0, Coord.Y+Ow2TtyParmList[0]-1,
SesGrp->ScreenColNum * ( SesGrp->ScreenRowNum-(Coord.Y+Ow2TtyParmList[0]-1)));
}
/* clear new stuff */
lclear(hConOut, 0, Coord.Y-1, SesGrp->ScreenColNum * Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_SU: /* scroll up */
Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
lscroll(hConOut, Ow2TtyParmList[0], SA_BONW);
break;
case ANSI_SD: /* scroll down */
Ow2TtyParmList[0] = -Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
lscroll(hConOut, Ow2TtyParmList[0], SA_BONW);
break;
#endif
default:
#if DBG
IF_OD2_DEBUG( VIO )
{
KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown cmd 0x%x\n", c));
}
#endif
ValidCmd = FALSE;
break;
}
if (!ValidCmd)
{
return(2);
} else if ((Coord.X != Ow2TtyCoord.X) ||
(Coord.Y != Ow2TtyCoord.Y))
{
if(Ow2TtyFlushStr())
{
return(1);
}
if(Ow2VioSetCurPos((ULONG)Coord.Y, (ULONG)Coord.X))
{
ASSERT1( "OS2SES(VIOTTY): AnsiCmd error on Ow2VioSetCurPos", FALSE );
}
Ow2TtyCoord= SesGrp->WinCoord;
*NewCoord = TRUE;
}
return (0);
}
USHORT
Ow2TtyRange(
IN USHORT val,
IN USHORT def,
IN USHORT min,
IN USHORT max
)
/*++
Routine Description:
This routine restrict a value to range or supply a default.
Arguments:
val - the value to be restricted.
default - the value to use if val is zero
min - the minimum value
max - the maximum value
Return Value:
Note:
--*/
{
if ( val == 0 )
val = def;
if ( val >= max )
return max;
if ( val < min )
return min;
return val;
}
DWORD
Ow2TtySetAttr(
)
/*++
Routine Description:
This routine set new attribute ("ESC[g;...;gm").
Arguments:
Return Value:
Should return 0.
1 - for any error (after ASSERT), RetCode from GetLastError().
Note:
Ow2TtyParmNum - length of parameter list
Ow2TtyParmList - list of Set Graphics Rendition values
Ow2TtyCoord - pointer to current screen coordinates
If new attributes is set, it also calls Ow2TtyFlushStr to flush the TTY
output buffer to the console.
hConOut is used for console handle.
Uses and updates: SesGrp->AnsiCellAttr, SesGrp->ansi_bold, SesGrp->ansi_blink,
SesGrp->ansi_background, SesGrp->ansi_foreground, SesGrp->WinAttr
--*/
{
BYTE NewAttr, LastAttr = SesGrp->AnsiCellAttr[0]; /* attribute of TTY */
ULONG i;
USHORT AnsiParm;
WORD WinAttr;
#ifdef DBCS
// MSKK Jun.28.1992 KazuM
BYTE CommonAttr[3];
#endif
for ( i = 0 ; i < Ow2TtyParmNum ; i++ )
{
AnsiParm = Ow2TtyParmList[i];
if (AnsiParm == 0)
{
/* ATTRIBUTE OFF */
/*****************/
// The default is according to Win. This sequence reset
// all the attribute only but doesn't change the color.
// According to VI.exe (set term-ibmans, fail on find-string
// and Jump to next line till end of screen, #2221, 5/2/93)
// and the updated os2tst\viowrt.
SesGrp->ansi_blink = SesGrp->ansi_bold = 0;
SesGrp->ansi_background = OS2_BACKGROUND_BLACK;
SesGrp->ansi_foreground = OS2_FOREGROUND_WHITE;
} else if (AnsiParm <= 8)
{
if (AnsiParm == 1)
{
/* BOLD */
/********/
SesGrp->ansi_bold = 1;
} else if (AnsiParm == 2)
{
/* FAINT */
/**********/
} else if (AnsiParm == 3)
{
/* ITALIC */
/**********/
} else if (AnsiParm == 4)
{
/* ?BLUE? */
/**********/
SesGrp->ansi_foreground = OS2_FOREGROUND_BLUE;
} else if (AnsiParm == 5)
{
/* BLINK */
/*********/
SesGrp->ansi_blink |= 1;
} else if (AnsiParm == 6)
{
/* RAPID-BLINK */
/***************/
} else if (AnsiParm == 7)
{
/* REVERSE VIDEO */
/*****************/
// BLACK over WHITE
SesGrp->ansi_foreground = OS2_FOREGROUND_BLACK;
SesGrp->ansi_background = OS2_BACKGROUND_WHITE;
} else if (AnsiParm == 8)
{
/* CONCEALED */
/*************/
SesGrp->ansi_background = OS2_BACKGROUND_BLACK;
SesGrp->ansi_foreground = OS2_FOREGROUND_BLACK;
}
} else if (((AnsiParm >= 30) &&
(AnsiParm <= 37)) ||
((AnsiParm >= 40) &&
(AnsiParm <= 47)))
{
/* FORE/BACKGROUND COLOR */
/*************************/
if (AnsiParm >= 40 )
{
SesGrp->ansi_background = (BYTE)( ColorTable[AnsiParm%10] << 4);
} else
{
SesGrp->ansi_foreground = (BYTE)ColorTable[AnsiParm%10];
}
}
}
NewAttr = SesGrp->ansi_background | SesGrp->ansi_foreground;
if ( SesGrp->ansi_bold )
{
NewAttr |= OS2_FOREGROUND_INTENSITY;
}
if ( SesGrp->ansi_blink )
{
NewAttr |= OS2_BACKGROUND_BLINKING;
}
if (LastAttr != NewAttr)
{
/* new attribute */
if(Ow2TtyFlushStr())
{
return(1);
}
#ifdef DBCS
// MSKK Jun.28.1992 KazuM
CommonAttr[0] = NewAttr;
CommonAttr[1] = CommonAttr[2] = 0;
if (!Or2WinSetConsoleTextAttribute(
#if DBG
Ow2TtySetAttrStr,
#endif
hConOut,
(WinAttr = MapOs2ToWinAttr(&CommonAttr[0]))))
#else
if (!Or2WinSetConsoleTextAttribute(
#if DBG
Ow2TtySetAttrStr,
#endif
hConOut,
(WinAttr = MapOs2ToWinAttr(NewAttr))))
#endif
{
#if DBG
ASSERT1("OS2SES(trans-TTY): failed on SetTextAttribute\n", FALSE);
#endif
return (1);
} else
{
#if DBG
IF_OD2_DEBUG( VIO )
{
KdPrint(("Ow2TtySetAttr: New attr %x(win %x), Last %x(win %x)\n",
NewAttr, WinAttr, LastAttr, SesGrp->WinAttr));
}
#endif
SesGrp->AnsiCellAttr[0] = NewAttr;
SesGrp->WinAttr = (USHORT)WinAttr;
}
}
return (NO_ERROR);
}
DWORD
Ow2TtyFlushStr(
)
/*++
Routine Description:
This routine flush the TTY output string (from TTY_DEST_BUFFER)
to the console.
Arguments:
Return Value:
Should return 0.
1 - for any error (after ASSERT), RetCode from GetLastError().
Note:
Ow2TtyCoord - pointer to current screen coordinates after the
flush.
According to Ow2TtyNumBytes, which is reset.
hConOut is used for console handle.
--*/
{
DWORD NumWritten;
if ( Ow2TtyNumBytes )
{
if(!Or2WinWriteConsoleA(
#if DBG
Ow2TtyFlushStrStr,
#endif
hConOut,
(LPSTR)TTY_DEST_BUFFER,
Ow2TtyNumBytes,
&NumWritten,
NULL))
{
#if DBG
ASSERT1("OS2SES(VIOTTY): flush string failed on WriteConsoleA", FALSE);
#endif
return (1);
}
#if DBG
if ( Ow2TtyNumBytes != NumWritten )
{
ASSERT1("OS2SES(VIOTTY): flush string partial data WriteConsoleA", FALSE);
//IF_OD2_DEBUG2( VIO, OS2_EXE )
//{
// KdPrint(("OS2SES(VIOTTY): flush string partial data WriteConsoleA from %u to %u\n",
// Ow2TtyNumBytes, NumWritten));
//}
}
#endif
Ow2TtyNumBytes = 0;
Ow2VioUpdateCurPos(Ow2TtyCoord);
}
return (0L);
}