Merge pull request #71 from frankpolte/master
[pforth] / csrc / win32_console / pf_io_win32_console.c
CommitLineData
8e9db35f
PB
1/* $Id$ */
2/***************************************************************
3** I/O subsystem for PForth for WIN32 systems.
4**
5** Use Windows Console so we can add the ANSI console commands needed to support HISTORY
6**
7** Author: Phil Burk
8** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
9**
10** The pForth software code is dedicated to the public domain,
11** and any third party may reproduce, distribute and modify
12** the pForth software code or any derivative works thereof
13** without any compensation or license. The pForth software
14** code is provided on an "as is" basis without any warranty
15** of any kind, including, without limitation, the implied
16** warranties of merchantability and fitness for a particular
17** purpose and their equivalents under the laws of any jurisdiction.
18**
19***************************************************************/
20
21#include "../pf_all.h"
22
23#if defined(WIN32) || defined(__NT__)
24
25#include <windows.h>
26
27#define ASCII_ESCAPE (0x1B)
28
29static HANDLE sConsoleHandle = INVALID_HANDLE_VALUE;
30static int sIsConsoleValid = FALSE;
31
32typedef enum ConsoleState_e
33{
34 SDCONSOLE_STATE_IDLE = 0,
35 SDCONSOLE_STATE_GOT_ESCAPE,
36 SDCONSOLE_STATE_GOT_BRACKET
37
38} ConsoleState;
39
40static int sConsoleState = SDCONSOLE_STATE_IDLE;
41static int sParam1 = 0;
42static CONSOLE_SCREEN_BUFFER_INFO sScreenInfo;
43
44/******************************************************************/
45static void sdConsoleEmit( char c )
46{
47 /* Write a WCHAR in case we have compiled with Unicode support.
48 * Otherwise we will see '?' printed.*/
49 WCHAR wc = (WCHAR) c;
50 DWORD count;
51 if( sIsConsoleValid )
52 {
53 WriteConsoleW(sConsoleHandle, &wc, 1, &count, NULL );
54 }
55 else
56 {
57 /* This will get called if we are redirecting to a file.*/
58 WriteFile(sConsoleHandle, &c, 1, &count, NULL );
59 }
60}
61
62/******************************************************************/
63static void sdClearScreen( void )
64{
65 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
66 {
67 COORD XY;
68 int numNeeded;
69 DWORD count;
70 XY.X = 0;
71 XY.Y = sScreenInfo.srWindow.Top;
72 numNeeded = sScreenInfo.dwSize.X * (sScreenInfo.srWindow.Bottom - sScreenInfo.srWindow.Top + 1);
73 FillConsoleOutputCharacter(
74 sConsoleHandle, ' ', numNeeded, XY, &count );
75 SetConsoleCursorPosition( sConsoleHandle, XY );
76 }
77}
78
79/******************************************************************/
80static void sdEraseEOL( void )
81{
82 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
83 {
84 COORD savedXY;
85 int numNeeded;
86 DWORD count;
87 savedXY.X = sScreenInfo.dwCursorPosition.X;
88 savedXY.Y = sScreenInfo.dwCursorPosition.Y;
89 numNeeded = sScreenInfo.dwSize.X - savedXY.X;
90 FillConsoleOutputCharacter(
91 sConsoleHandle, ' ', numNeeded, savedXY, &count );
92 }
93}
94
95/******************************************************************/
96static void sdCursorBack( int dx )
97{
98 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
99 {
100 COORD XY;
101 XY.X = sScreenInfo.dwCursorPosition.X;
102 XY.Y = sScreenInfo.dwCursorPosition.Y;
103 XY.X -= dx;
104 if( XY.X < 0 ) XY.X = 0;
105 SetConsoleCursorPosition( sConsoleHandle, XY );
106 }
107}
108/******************************************************************/
109static void sdCursorForward( int dx )
110{
111 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
112 {
113 COORD XY;
114 int width = sScreenInfo.dwSize.X;
115 XY.X = sScreenInfo.dwCursorPosition.X;
116 XY.Y = sScreenInfo.dwCursorPosition.Y;
117 XY.X += dx;
118 if( XY.X > width ) XY.X = width;
119 SetConsoleCursorPosition( sConsoleHandle, XY );
120 }
121}
122
123/******************************************************************/
124/* Use console mode I/O so that KEY and ?TERMINAL will work.
125 * Parse ANSI escape sequences and call the appropriate cursor
126 * control functions.
127 */
128int sdTerminalOut( char c )
129{
130 switch( sConsoleState )
131 {
132 case SDCONSOLE_STATE_IDLE:
133 switch( c )
134 {
135 case ASCII_ESCAPE:
136 sConsoleState = SDCONSOLE_STATE_GOT_ESCAPE;
137 break;
138 default:
139 sdConsoleEmit( c );
140 }
141 break;
142
143 case SDCONSOLE_STATE_GOT_ESCAPE:
144 switch( c )
145 {
146 case '[':
147 sConsoleState = SDCONSOLE_STATE_GOT_BRACKET;
148 sParam1 = 0;
149 break;
150 default:
151 sConsoleState = SDCONSOLE_STATE_IDLE;
152 sdConsoleEmit( c );
153 }
154 break;
155
156 case SDCONSOLE_STATE_GOT_BRACKET:
157 if( (c >= '0') && (c <= '9') )
158 {
159 sParam1 = (sParam1 * 10) + (c - '0');
160 }
161 else
162 {
163 sConsoleState = SDCONSOLE_STATE_IDLE;
164 if( c == 'K')
165 {
166 sdEraseEOL();
167 }
168 else if( c == 'D' )
169 {
170 sdCursorBack( sParam1 );
171 }
172 else if( c == 'C' )
173 {
174 sdCursorForward( sParam1 );
175 }
176 else if( (c == 'J') && (sParam1 == 2) )
177 {
178 sdClearScreen();
179 }
180 }
181 break;
182 }
183 return 0;
184}
185
186/* Needed cuz _getch() does not echo. */
187int sdTerminalEcho( char c )
188{
189 sdConsoleEmit((char)(c));
190 return 0;
191}
192
193int sdTerminalIn( void )
194{
195 return _getch();
196}
197
198int sdQueryTerminal( void )
199{
200 return _kbhit();
201}
202
203int sdTerminalFlush( void )
204{
205#ifdef PF_NO_FILEIO
206 return -1;
207#else
208 return fflush(PF_STDOUT);
209#endif
210}
211
212void sdTerminalInit( void )
213{
214 DWORD mode = 0;
215 sConsoleHandle = GetStdHandle( STD_OUTPUT_HANDLE );
216 if( GetConsoleMode( sConsoleHandle, &mode ) )
217 {
218 /*printf("GetConsoleMode() mode is 0x%08X\n", mode );*/
219 sIsConsoleValid = TRUE;
220 }
221 else
222 {
223 /*printf("GetConsoleMode() failed\n", mode );*/
224 sIsConsoleValid = FALSE;
225 }
226}
227
228void sdTerminalTerm( void )
229{
230}
231#endif