|
|
#define WIN32_ONLY
#include <posix/sys/types.h>
#include <posix/termios.h>
#include "psxses.h"
#include "ansiio.h"
#include <io.h>
#include <stdio.h>
#include <ctype.h>
extern DWORD OutputModeFlags; /* Console Output Mode */ extern DWORD InputModeFlags; extern unsigned char AnsiNewMode; extern struct termios SavedTermios;
/* DFC: New globals (from trans.h) */ WORD ansi_attr; /* attribute of TTY */ WORD ansi_attr1; /* MSKK : leave space for 3 attr */ WORD ansi_attr2; /* MSKK : leave space for 3 attr */ SHORT ScreenColNum; /* col number */ SHORT ScreenRowNum; /* row number */ BYTE CarriageReturn;
COORD TrackedCoord, CurrentCoord;
DWORD TTYConBeep(void);
static BYTE ColorTable[8] = { 0, /* Black */ 4, /* Red */ 2, /* Green */ 6, /* Yellow */ 1, /* Blue */ 5, /* Magenta */ 3, /* Cyan */ 7}; /* White */
DWORD TermioInit(void) { CONSOLE_SCREEN_BUFFER_INFO ScreenInfo1; BOOL Success;
ansi_state = NOCMD; /* state of machine */ ignore_next_char = 0; #if 0
ansi_base = ansi_attr = 0x07; /* white on black */ #endif
ansi_reverse = 0;
InputModeFlags = (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT; AnsiNewMode = FALSE;
if (!SetConsoleMode(hConsoleInput, InputModeFlags)) { KdPrint(("posix - can't set console mode: 0x%x\n", GetLastError())); }
/* Set default termio parameters */ SavedTermios.c_iflag = BRKINT|ICRNL; SavedTermios.c_oflag = OPOST|ONLCR; SavedTermios.c_cflag = CREAD|CS8; SavedTermios.c_lflag = ICANON|ECHO|ECHOE|ECHOK|ISIG;
SavedTermios.c_cc[VEOF] = CTRL('Z'); SavedTermios.c_cc[VEOL] = 0; // _POSIX_VDISABLE
SavedTermios.c_cc[VERASE] = CTRL('H'); SavedTermios.c_cc[VINTR] = CTRL('C'); SavedTermios.c_cc[VKILL] = CTRL('X'); SavedTermios.c_cc[VQUIT] = CTRL('\\'); SavedTermios.c_cc[VSUSP] = CTRL('Y'); SavedTermios.c_cc[VSTOP] = CTRL('S'); SavedTermios.c_cc[VSTART] = CTRL('Q');
SavedTermios.c_ospeed = B9600; SavedTermios.c_ispeed = B9600;
Success = GetConsoleScreenBufferInfo(hConsoleOutput, &ScreenInfo1); if (!Success) { return Success; }
ansi_base = ansi_attr = ScreenInfo1.wAttributes; ansi_attr1 = ansi_attr2 = 0;
ScreenRowNum = ScreenInfo1.dwSize.Y; ScreenColNum = ScreenInfo1.dwSize.X;
CurrentCoord.Y = TrackedCoord.Y = ScreenInfo1.dwCursorPosition.Y + 1; CurrentCoord.X = TrackedCoord.X = ScreenInfo1.dwCursorPosition.X + 1;
return (DWORD) 0; }
/*
** TermOutput(SourStr, cnt) - pass characters to the finite state machine ** SourStr points to the array of characters ** cnt indicates how many characters are being passed. */
DWORD TermOutput( IN HANDLE cs, IN LPSTR SourStr, IN DWORD cnt) { register CHAR c; USHORT NewCoord, ToFlash; DWORD Rc = 0, orig_cnt = cnt; BOOL SetModeOn, OldWrap, NewWrap; CONSOLE_SCREEN_BUFFER_INFO ScreenInfo1;
//
// Kludge because we don't know how many carriage returns we received
// as input, thereby impeding TermOutput()'s ability to track the
// cursor coordinate accurately
//
GetConsoleScreenBufferInfo(cs, &ScreenInfo1); CurrentCoord.Y = TrackedCoord.Y = ScreenInfo1.dwCursorPosition.Y + 1; CurrentCoord.X = TrackedCoord.X = ScreenInfo1.dwCursorPosition.X + 1;
NewCoord = 0; CarriageReturn = 0; TTYOldCtrlCharInStr = TRUE; TTYCtrlCharInStr = FALSE; TTYcs = cs; TTYTextPtr = SourStr; TTYNumBytes = 0;
//
// Stop output, if VSTOP has been encountered
//
if (bStop) { RtlEnterCriticalSection(&StopMutex); if (bStop) { RtlLeaveCriticalSection(&StopMutex); WaitForSingleObject(hStopEvent, INFINITE); } else { RtlLeaveCriticalSection(&StopMutex); } }
SetModeOn = FALSE; while (cnt--) { c = *SourStr++;
switch (ansi_state) { case NOCMD: if (c == ANSI_ESC) { //
// Make sure buffer is flushed and cursor position is
// up-to-date before processing next esc-seq
//
if ( (Rc = TTYFlushStr(&NewCoord, "1")) != 0 ) { KdPrint(("PSXSES(trans-TTY): failed on " "TTYFlushStr #1\n")); return (DWORD) -1; } ansi_state = ESCED; break; } else { if (isprint(c)) { /* Printable char found */
TTYNumBytes++; TrackedCoord.X++;
} else { /* Non-printable char found */
ToFlash = TRUE; switch ( c ) { case '\n': new_line: if (SavedTermios.c_oflag & OPOST) { if (c == '\n' && (SavedTermios.c_oflag & ONLCR)) { TrackedCoord.Y++; goto carriage_return; } if (SavedTermios.c_oflag & ONLRET) { #if 0
TrackedCoord.X = 1; #endif
CarriageReturn = 1; } } TrackedCoord.Y++; NewCoord = 1; break;
case '\r': carriage_return: if ( SavedTermios.c_oflag & OPOST ) { if ( c == '\r' && (SavedTermios.c_oflag & OCRNL) ) { goto new_line; } else if ( ! (SavedTermios.c_oflag & ONOCR) || TrackedCoord.X != 1 ) { #if 0
TrackedCoord.X = 1; #endif
NewCoord = 1; CarriageReturn = 1; } } else { if ( TrackedCoord.X > 1 ) { TrackedCoord.X = 1; NewCoord = 1; CarriageReturn = 1; } } break;
case '\b': if ( TrackedCoord.X > 1 ) { TrackedCoord.X--; NewCoord = 1; } break;
case '\t': TrackedCoord.X += (8 - ((TrackedCoord.X - 1) % 8));
// Handle wrap after tab
if (TrackedCoord.X > ScreenColNum) { if (OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) { TrackedCoord.Y += ((TrackedCoord.X) / ScreenColNum); TrackedCoord.X = (TrackedCoord.X % ScreenColNum); } else { TrackedCoord.X = ScreenColNum; } } NewCoord = 1; break;
case '\a': if ( (Rc = TTYConBeep()) != 0 ) { KdPrint(("PSXSES(trans-TTY): failed on " "BEEP\n")); return (DWORD) -1; } break;
default: TTYCtrlCharInStr = TRUE; ToFlash = FALSE; #if 0
TTYNumBytes++; TrackedCoord.X++; #endif
break; } /* switch */
if ( ToFlash ) { /* Flush */ //
// Flush carriage control chars to update cursor
// position
//
if ((Rc = TTYFlushStr(&NewCoord, "2")) != 0) { return (DWORD)-1; }
TTYTextPtr = SourStr; } } /* isprint */ } /* ANSI_ESC */ break;
case ESCED: switch ( c ) { case '[': ansi_state = PARAMS; SetModeOn = TRUE; clrparam(); break;
default: ansi_state = NOCMD; TTYTextPtr = SourStr - 1; cnt++ ; SourStr--; break; } break;
case PARAMS: if ( isdigit(c) ) { ansi_param[ansi_pnum] *= 10; ansi_param[ansi_pnum] += (c - '0'); SetModeOn = FALSE; } else if ( c == ';' ) { if ( ansi_pnum < (NPARMS - 1) ) ++ansi_pnum; else { ansi_state = NOCMD; TTYTextPtr = SourStr; } } else if ( (c == '=') && SetModeOn ) { /* maybe set/reset mode */ ansi_state = MODCMD; } else { ansi_state = NOCMD; if ( (Rc = ansicmd(cs, c)) != 0 ) { return (DWORD) -1; } TTYTextPtr = SourStr; NewCoord = 1; if ( (Rc = TTYFlushStr(&NewCoord, "3")) != 0 ) { #if 0
return (DWORD) -1; #endif
} } break;
case MODCMD: if ( ansi_pnum == 1 ) {
if ( c == 'h' || c == 'l' ) {
if ( ansi_param[0] == 7 ) {
OldWrap = ((OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) != 0); NewWrap = (c == 'h');
if ( OldWrap != NewWrap ) {
if ( (Rc = !SetConsoleMode(cs, OutputModeFlags^ENABLE_WRAP_AT_EOL_OUTPUT)) != 0 ) { return (DWORD) -1; }
OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT; #if 0
} else { OutputModeFlags ~= ENABLE_WRAP_AT_EOL_OUTPUT; #endif
} }
TTYTextPtr = SourStr;
} else { TTYTextPtr = SourStr - 5; TTYNumBytes = 5; }
} else if ( c >= '0' && c <= '7' ) { ansi_param[0] = (USHORT) (c - '0'); ansi_pnum = 1; break; } else { TTYTextPtr = SourStr - 4; TTYNumBytes = 4; } ansi_state = NOCMD; break;
case MODDBCS: TTYNumBytes++; TrackedCoord.X++; ansi_state = NOCMD; break;
} /* switch ansi_state */
} /* while cnt */
/* Flush */ if ( (Rc = TTYFlushStr(&NewCoord, "4")) != 0 ) { return (DWORD) -1; }
return(orig_cnt); }
/*
** clrparam(lp) - clear the parameters for a screen ** lp points to the screen's crt struct */
VOID clrparam(void) { register int i;
for ( i = 0; i < NPARMS; i += 1 ) ansi_param[i] = 0; ansi_pnum = 0; }
//
// lscroll - scroll the sceen
//
void lscroll( HANDLE h, // handle on the console buffer to scroll
int lines // number of lines to scroll (negative means
// scroll text down)
) { COORD coordDest; SMALL_RECT ScrollRect; CHAR_INFO ScrollChar; BOOLEAN Success;
if (0 == lines) { // already done
return; }
if (lines < 0) { // scroll text down
ScrollRect.Top = 0; ScrollRect.Bottom = ScreenRowNum + lines; coordDest.X = 0; coordDest.Y = 0 - lines; } else { // scroll text up
ScrollRect.Top = (SHORT)lines; ScrollRect.Bottom = ScreenRowNum; coordDest.X = 0; coordDest.Y = 0; }
ScrollRect.Left = 0; ScrollRect.Right = ScreenColNum;
ScrollChar.Attributes = (ansi_attr); ScrollChar.Char.AsciiChar = ' ';
Success = ScrollConsoleScreenBufferA(h, &ScrollRect, NULL, coordDest, &ScrollChar) ? TRUE : FALSE; if (!Success) { KdPrint(("POSIX: ScrollConsole: 0x%x\n", GetLastError())); } return; }
//
// ansicmd - perform some ANSI 3.64 function, using the parameters
// we've just gathered.
//
// c is the character that indicates the function to be performed
//
DWORD ansicmd( IN HANDLE cs, IN CHAR c ) { DWORD NumFilled, Rc = 0; USHORT j; COORD Coord;
switch (c) { case ANSI_CUB: /* cursor backward */ TrackedCoord.X -= (short) range(ansi_param[0], 1, 1, TrackedCoord.X - 1); break;
case ANSI_CUF: /* cursor forward */ TrackedCoord.X += (short) range(ansi_param[0], 1, 1, ScreenColNum - TrackedCoord.X ); break;
case ANSI_CUU: /* cursor up */ TrackedCoord.Y -= (short) range(ansi_param[0], 1, 1, TrackedCoord.Y - 1); break;
case ANSI_CUD: /* cursor down */ TrackedCoord.Y += (short) range(ansi_param[0], 1, 1, ScreenRowNum - TrackedCoord.Y); break;
case ANSI_CUP: /* cursor position */ case ANSI_CUP1: TrackedCoord.Y = (USHORT) range(ansi_param[0], 1, 1, ScreenRowNum); TrackedCoord.X = (USHORT) range(ansi_param[1], 1, 1, ScreenColNum); break;
case ANSI_ED: /* erase display */ switch ( ansi_param[0] ) { case 2: TrackedCoord.Y = TrackedCoord.X = 1; Coord.X = (SHORT) (TrackedCoord.X - 1); Coord.Y = (SHORT) (TrackedCoord.Y - 1); if ( (Rc = (!FillConsoleOutputCharacterA(cs, ' ', (DWORD) ScreenRowNum * ScreenColNum, Coord, &NumFilled))) != 0 ) { return (Rc); }
if ( (Rc = (!FillConsoleOutputAttribute(cs, (ansi_attr), NumFilled, Coord, &NumFilled))) != 0 ) {
return (Rc); } break;
default: break; } break;
case ANSI_EL: Coord.X = (SHORT)(TrackedCoord.X - 1); Coord.Y = (SHORT)(TrackedCoord.Y - 1);
switch ( ansi_param[0] ) { case 0: /* up to end */ if ( (Rc = (!FillConsoleOutputCharacterA(cs, ' ', (DWORD) (ScreenColNum - Coord.X), Coord, &NumFilled))) != 0 ) { return (Rc); }
if ( (Rc = (!FillConsoleOutputAttribute(cs, (ansi_attr), NumFilled, Coord, &NumFilled))) != 0 ) {
return (Rc); } break;
default: break; } break;
case ANSI_SGR: // SGR = Select Graphic Rendition
for ( j = 0; (SHORT) j <= (SHORT) ansi_pnum; j++ ) { SetTTYAttr(cs, ansi_param[j]); } break;
#if 0
case ANSI_SCP: ansi_scp = TrackedCoord; break;
case ANSI_RCP: TrackedCoord = ansi_scp; break; case ANSI_CPL: /* cursor to previous line */ TrackedCoord.Y -= range(ansi_param[0], 1, 1, ScreenRowNum); TrackedCoord.X = 1; break;
case ANSI_CNL: /* cursor to next line */ TrackedCoord.Y += range(ansi_param[0], 1, 1, ScreenRowNum); TrackedCoord.X = 1; break;
case ANSI_CBT: /* tab backwards */ col = TrackedCoord.X - 1; i = range(ansi_param[0], 1, 1, (col + 7) >> 3); if ( col & 7 ) { TrackedCoord.X = (col & ~7) + 1; --i; } TrackedCoord.X -= (i << 3); break;
case ANSI_DCH: /* delete character */ ansi_param[0] = range(ansi_param[0], 1, 1, (ScreenColNum - TrackedCoord.X) + 1); if ( TrackedCoord.X + ansi_param[0] <= ScreenColNum ) { lcopy(cs, lp, TrackedCoord.X+ansi_param[0]-1, TrackedCoord.Y-1, TrackedCoord.X-1, TrackedCoord.Y-1, ScreenColNum-(TrackedCoord.X+ansi_param[0]-1)); } lclear(cs, lp, ScreenColNum-ansi_param[0], TrackedCoord.Y-1, ansi_param[0], SA_BONW); break;
case ANSI_DL: /* delete line */ ansi_param[0] = range(ansi_param[0], 1, 1, (ScreenRowNum - TrackedCoord.Y) + 1); /* copy lines up */ if ( TrackedCoord.Y + ansi_param[0] <= ScreenRowNum ) { lcopy(cs, lp, 0, TrackedCoord.Y+ansi_param[0]-1, 0, TrackedCoord.Y-1, ScreenColNum*(ScreenRowNum-(TrackedCoord.Y+ansi_param[0]-1))); } /* clear new stuff */ lclear(cs, lp, 0, ScreenRowNum-ansi_param[0], ScreenColNum*ansi_param[0], SA_BONW); break;
case ANSI_ECH: /* erase character */ ansi_param[0] = range( ansi_param[0], 1, 1, (ScreenColNum - TrackedCoord.X) + 1); lclear(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1, ansi_param[0], SA_BONW); break;
case ANSI_ICH: /* insert character */ ansi_param[0] = range( ansi_param[0], 1, 1, (ScreenColNum - TrackedCoord.X) + 1); if ( TrackedCoord.X + ansi_param[0] <= ScreenColNum ) { lcopy(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1, TrackedCoord.X+ansi_param[0]-1, TrackedCoord.Y-1, ScreenColNum-(TrackedCoord.X+ansi_param[0]-1)); } lclear(cs, lp, TrackedCoord.X-1, TrackedCoord.Y-1, ansi_param[0], SA_BONW); break;
case ANSI_IL: /* insert line */ ansi_param[0] = range(ansi_param[0], 1, 1, (ScreenRowNum - TrackedCoord.Y) + 1); /* copy lines down */ if ( TrackedCoord.Y + ansi_param[0] <= ScreenRowNum ) { lcopy(cs, lp, 0, TrackedCoord.Y-1, 0, TrackedCoord.Y+ansi_param[0]-1, ScreenColNum*(ScreenRowNum-(TrackedCoord.Y+ansi_param[0]-1))); } /* clear new stuff */ lclear(cs, lp, 0, TrackedCoord.Y-1, ScreenColNum * ansi_param[0], SA_BONW); break; #endif
case ANSI_SU: /* scroll up */ ansi_param[0] = (short) range(ansi_param[0], 1, 1, ScreenRowNum); lscroll(cs, ansi_param[0]); break;
case ANSI_SD: /* scroll down */ { int i = -range(ansi_param[0], 1, 1, ScreenRowNum); lscroll(cs, i); } break;
default: return (DWORD) 0; } return (Rc); }
/*
** range(val, default, min, max) - restrict a value to a range, or supply a ** default ** val is the value to be restricted. ** default is the value to be returned if val is zero ** min is the minimum value ** max is the maximum value */
int range(int val, int def, int min, int max) { if ( val == 0 ) return def; if ( val < min ) return min; if ( val > max ) return max; return val; }
DWORD SetTTYAttr(IN HANDLE cs, IN USHORT AnsiParm) { WORD NewAttr, LastAttr = ansi_attr; /* attribute of TTY */ BOOL Rc;
if ( AnsiParm == 0 ) { // BUGBUG ? or the default is according to Win
ansi_base = 0x07; /* white on black */ ansi_reverse = 0x00; } else if ( AnsiParm == 7 ) { ansi_reverse = 1; } else if ( ((AnsiParm >= 30) && (AnsiParm <= 37)) || ((AnsiParm >= 40) && (AnsiParm <= 47)) ) { if ( AnsiParm >= 40 ) ansi_base = (BYTE) ((ansi_base & 0x0F) | ( 4 << ColorTable[AnsiParm%10])); else ansi_base = (BYTE) ((ansi_base & 0xF0) | ColorTable[AnsiParm%10]); } else if ( AnsiParm == 8 ) { #if 0
ansi_cancel = 1; #endif
} else if ( AnsiParm == 1 ) { #if 0
ansi_intensity = 1; #endif
} else if ( AnsiParm == 4 ) { #if 0
ansi_bold = 1; #endif
} else if ( AnsiParm == 5 ) { #if 0
ansi_underscore = 1; #endif
}
if ( ansi_reverse ) NewAttr = (BYTE) (((ansi_base & 0x0F) << 4 ) | ((ansi_base & 0xF0) >> 4 )); else NewAttr = ansi_base;
if ( LastAttr != NewAttr ) { /* new attribute */ if ( (Rc = !SetConsoleTextAttribute(cs, (NewAttr))) != 0 ) { return (Rc); } else { ansi_attr = NewAttr; } } return (NO_ERROR); }
DWORD TTYConBeep(void) { DWORD NumWritten, Rc; CHAR BeepChar = '\a';
Rc = !WriteConsoleA(TTYcs, &BeepChar, 1, &NumWritten, NULL);
return(Rc); }
DWORD TTYFlushStr(USHORT *newcoord, const char *call) { DWORD NumWritten; BOOL Success; COORD coordDest, coord; SMALL_RECT ScrollRect; CHAR_INFO ScrollChar;
if (TTYNumBytes) { if (TrackedCoord.X > ScreenColNum) {
// Handle cursor tracking of text wrap-around
if (OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) { #if 0
TrackedCoord.Y += ((CurrentCoord.X + TrackedCoord.X) / ScreenColNum); #else
TrackedCoord.Y += ((TrackedCoord.X) / ScreenColNum); #endif
TrackedCoord.X = (TrackedCoord.X % ScreenColNum); } else { TrackedCoord.X = ScreenColNum; } *newcoord = 1; } else if (TrackedCoord.X < 1) { TrackedCoord.X = 1; #if 0
*newcoord = 1; #endif
} }
//
// Handle scrolling when printing beyond bottom of screen
//
if (TrackedCoord.Y > ScreenRowNum) { #if 0
ScrollRect.Top = TrackedCoord.Y - ScreenRowNum; ScrollRect.Bottom = (SHORT)ScreenRowNum; ScrollRect.Left = 0; ScrollRect.Right = (SHORT)ScreenColNum; coordDest.X = 0; coordDest.Y = 0; ScrollChar.Attributes = (ansi_attr); ScrollChar.Char.AsciiChar = ' ';
Success = ScrollConsoleScreenBufferA(TTYcs, &ScrollRect, NULL, coordDest, &ScrollChar); if (!Success) { KdPrint(("POSIX: ScrollConsole: 0x%x\n", GetLastError())); return Success; } #else
lscroll(TTYcs, TrackedCoord.Y - ScreenRowNum); #endif
if (TTYNumBytes) { coord.X = CurrentCoord.X - 1; coord.Y = ScreenRowNum - (TrackedCoord.Y - ScreenRowNum) - 1;
Success = WriteConsoleOutputCharacterA(TTYcs, (LPSTR)TTYTextPtr, TTYNumBytes, coord, &NumWritten); if (!Success) { KdPrint(("POSIX: WriteConsoleOutputChar: 0x%x\n", GetLastError())); return Success; }
TTYNumBytes = 0; } TrackedCoord.Y = ScreenRowNum; #if 0
*newcoord = 1; #endif
} else if (TTYNumBytes) {
// Not printing beyond bottom of screen.
Success = WriteConsoleA(TTYcs, (LPSTR) TTYTextPtr, TTYNumBytes, &NumWritten, NULL); if (!Success) { return Success; } TTYNumBytes = 0; }
if (*newcoord) { if (CarriageReturn) { CarriageReturn = 0; TrackedCoord.X = 1; }
coord.X = TrackedCoord.X - 1; coord.Y = TrackedCoord.Y - 1;
Success = SetConsoleCursorPosition(TTYcs, coord); if (!Success) { return Success; } *newcoord = 0; }
CurrentCoord = TrackedCoord;
return (DWORD)0; }
|