relicense to 0BSD
[pforth] / csrc / win32_console / pf_io_win32_console.c
/* $Id$ */
/***************************************************************
** I/O subsystem for PForth for WIN32 systems.
**
** Use Windows Console so we can add the ANSI console commands needed to support HISTORY
**
** Author: Phil Burk
** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
**
** Permission to use, copy, modify, and/or distribute this
** software for any purpose with or without fee is hereby granted.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**
***************************************************************/
#include "../pf_all.h"
#if defined(WIN32) || defined(__NT__)
#include <windows.h>
#define ASCII_ESCAPE (0x1B)
static HANDLE sConsoleHandle = INVALID_HANDLE_VALUE;
static int sIsConsoleValid = FALSE;
typedef enum ConsoleState_e
{
SDCONSOLE_STATE_IDLE = 0,
SDCONSOLE_STATE_GOT_ESCAPE,
SDCONSOLE_STATE_GOT_BRACKET
} ConsoleState;
static int sConsoleState = SDCONSOLE_STATE_IDLE;
static int sParam1 = 0;
static CONSOLE_SCREEN_BUFFER_INFO sScreenInfo;
/******************************************************************/
static void sdConsoleEmit( char c )
{
/* Write a WCHAR in case we have compiled with Unicode support.
* Otherwise we will see '?' printed.*/
WCHAR wc = (WCHAR) c;
DWORD count;
if( sIsConsoleValid )
{
WriteConsoleW(sConsoleHandle, &wc, 1, &count, NULL );
}
else
{
/* This will get called if we are redirecting to a file.*/
WriteFile(sConsoleHandle, &c, 1, &count, NULL );
}
}
/******************************************************************/
static void sdClearScreen( void )
{
if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
{
COORD XY;
int numNeeded;
DWORD count;
XY.X = 0;
XY.Y = sScreenInfo.srWindow.Top;
numNeeded = sScreenInfo.dwSize.X * (sScreenInfo.srWindow.Bottom - sScreenInfo.srWindow.Top + 1);
FillConsoleOutputCharacter(
sConsoleHandle, ' ', numNeeded, XY, &count );
SetConsoleCursorPosition( sConsoleHandle, XY );
}
}
/******************************************************************/
static void sdEraseEOL( void )
{
if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
{
COORD savedXY;
int numNeeded;
DWORD count;
savedXY.X = sScreenInfo.dwCursorPosition.X;
savedXY.Y = sScreenInfo.dwCursorPosition.Y;
numNeeded = sScreenInfo.dwSize.X - savedXY.X;
FillConsoleOutputCharacter(
sConsoleHandle, ' ', numNeeded, savedXY, &count );
}
}
/******************************************************************/
static void sdCursorBack( int dx )
{
if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
{
COORD XY;
XY.X = sScreenInfo.dwCursorPosition.X;
XY.Y = sScreenInfo.dwCursorPosition.Y;
XY.X -= dx;
if( XY.X < 0 ) XY.X = 0;
SetConsoleCursorPosition( sConsoleHandle, XY );
}
}
/******************************************************************/
static void sdCursorForward( int dx )
{
if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
{
COORD XY;
int width = sScreenInfo.dwSize.X;
XY.X = sScreenInfo.dwCursorPosition.X;
XY.Y = sScreenInfo.dwCursorPosition.Y;
XY.X += dx;
if( XY.X > width ) XY.X = width;
SetConsoleCursorPosition( sConsoleHandle, XY );
}
}
/******************************************************************/
/* Use console mode I/O so that KEY and ?TERMINAL will work.
* Parse ANSI escape sequences and call the appropriate cursor
* control functions.
*/
int sdTerminalOut( char c )
{
switch( sConsoleState )
{
case SDCONSOLE_STATE_IDLE:
switch( c )
{
case ASCII_ESCAPE:
sConsoleState = SDCONSOLE_STATE_GOT_ESCAPE;
break;
default:
sdConsoleEmit( c );
}
break;
case SDCONSOLE_STATE_GOT_ESCAPE:
switch( c )
{
case '[':
sConsoleState = SDCONSOLE_STATE_GOT_BRACKET;
sParam1 = 0;
break;
default:
sConsoleState = SDCONSOLE_STATE_IDLE;
sdConsoleEmit( c );
}
break;
case SDCONSOLE_STATE_GOT_BRACKET:
if( (c >= '0') && (c <= '9') )
{
sParam1 = (sParam1 * 10) + (c - '0');
}
else
{
sConsoleState = SDCONSOLE_STATE_IDLE;
if( c == 'K')
{
sdEraseEOL();
}
else if( c == 'D' )
{
sdCursorBack( sParam1 );
}
else if( c == 'C' )
{
sdCursorForward( sParam1 );
}
else if( (c == 'J') && (sParam1 == 2) )
{
sdClearScreen();
}
}
break;
}
return 0;
}
/* Needed cuz _getch() does not echo. */
int sdTerminalEcho( char c )
{
sdConsoleEmit((char)(c));
return 0;
}
int sdTerminalIn( void )
{
return _getch();
}
int sdQueryTerminal( void )
{
return _kbhit();
}
int sdTerminalFlush( void )
{
#ifdef PF_NO_FILEIO
return -1;
#else
return fflush(PF_STDOUT);
#endif
}
void sdTerminalInit( void )
{
DWORD mode = 0;
sConsoleHandle = GetStdHandle( STD_OUTPUT_HANDLE );
if( GetConsoleMode( sConsoleHandle, &mode ) )
{
/*printf("GetConsoleMode() mode is 0x%08X\n", mode );*/
sIsConsoleValid = TRUE;
}
else
{
/*printf("GetConsoleMode() failed\n", mode );*/
sIsConsoleValid = FALSE;
}
}
void sdTerminalTerm( void )
{
}
#endif