Merge pull request #75 from SeekingMeaning/0BSD
[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**
1f99f95d
S
10** Permission to use, copy, modify, and/or distribute this
11** software for any purpose with or without fee is hereby granted.
12**
13** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
15** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
16** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
17** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
18** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
8e9db35f
PB
21**
22***************************************************************/
23
24#include "../pf_all.h"
25
26#if defined(WIN32) || defined(__NT__)
27
28#include <windows.h>
29
30#define ASCII_ESCAPE (0x1B)
31
32static HANDLE sConsoleHandle = INVALID_HANDLE_VALUE;
33static int sIsConsoleValid = FALSE;
34
35typedef enum ConsoleState_e
36{
37 SDCONSOLE_STATE_IDLE = 0,
38 SDCONSOLE_STATE_GOT_ESCAPE,
39 SDCONSOLE_STATE_GOT_BRACKET
40
41} ConsoleState;
42
43static int sConsoleState = SDCONSOLE_STATE_IDLE;
44static int sParam1 = 0;
45static CONSOLE_SCREEN_BUFFER_INFO sScreenInfo;
46
47/******************************************************************/
48static void sdConsoleEmit( char c )
49{
50 /* Write a WCHAR in case we have compiled with Unicode support.
51 * Otherwise we will see '?' printed.*/
52 WCHAR wc = (WCHAR) c;
53 DWORD count;
54 if( sIsConsoleValid )
55 {
56 WriteConsoleW(sConsoleHandle, &wc, 1, &count, NULL );
57 }
58 else
59 {
60 /* This will get called if we are redirecting to a file.*/
61 WriteFile(sConsoleHandle, &c, 1, &count, NULL );
62 }
63}
64
65/******************************************************************/
66static void sdClearScreen( void )
67{
68 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
69 {
70 COORD XY;
71 int numNeeded;
72 DWORD count;
73 XY.X = 0;
74 XY.Y = sScreenInfo.srWindow.Top;
75 numNeeded = sScreenInfo.dwSize.X * (sScreenInfo.srWindow.Bottom - sScreenInfo.srWindow.Top + 1);
76 FillConsoleOutputCharacter(
77 sConsoleHandle, ' ', numNeeded, XY, &count );
78 SetConsoleCursorPosition( sConsoleHandle, XY );
79 }
80}
81
82/******************************************************************/
83static void sdEraseEOL( void )
84{
85 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
86 {
87 COORD savedXY;
88 int numNeeded;
89 DWORD count;
90 savedXY.X = sScreenInfo.dwCursorPosition.X;
91 savedXY.Y = sScreenInfo.dwCursorPosition.Y;
92 numNeeded = sScreenInfo.dwSize.X - savedXY.X;
93 FillConsoleOutputCharacter(
94 sConsoleHandle, ' ', numNeeded, savedXY, &count );
95 }
96}
97
98/******************************************************************/
99static void sdCursorBack( int dx )
100{
101 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
102 {
103 COORD XY;
104 XY.X = sScreenInfo.dwCursorPosition.X;
105 XY.Y = sScreenInfo.dwCursorPosition.Y;
106 XY.X -= dx;
107 if( XY.X < 0 ) XY.X = 0;
108 SetConsoleCursorPosition( sConsoleHandle, XY );
109 }
110}
111/******************************************************************/
112static void sdCursorForward( int dx )
113{
114 if( GetConsoleScreenBufferInfo( sConsoleHandle, &sScreenInfo ) )
115 {
116 COORD XY;
117 int width = sScreenInfo.dwSize.X;
118 XY.X = sScreenInfo.dwCursorPosition.X;
119 XY.Y = sScreenInfo.dwCursorPosition.Y;
120 XY.X += dx;
121 if( XY.X > width ) XY.X = width;
122 SetConsoleCursorPosition( sConsoleHandle, XY );
123 }
124}
125
126/******************************************************************/
127/* Use console mode I/O so that KEY and ?TERMINAL will work.
128 * Parse ANSI escape sequences and call the appropriate cursor
129 * control functions.
130 */
131int sdTerminalOut( char c )
132{
133 switch( sConsoleState )
134 {
135 case SDCONSOLE_STATE_IDLE:
136 switch( c )
137 {
138 case ASCII_ESCAPE:
139 sConsoleState = SDCONSOLE_STATE_GOT_ESCAPE;
140 break;
141 default:
142 sdConsoleEmit( c );
143 }
144 break;
145
146 case SDCONSOLE_STATE_GOT_ESCAPE:
147 switch( c )
148 {
149 case '[':
150 sConsoleState = SDCONSOLE_STATE_GOT_BRACKET;
151 sParam1 = 0;
152 break;
153 default:
154 sConsoleState = SDCONSOLE_STATE_IDLE;
155 sdConsoleEmit( c );
156 }
157 break;
158
159 case SDCONSOLE_STATE_GOT_BRACKET:
160 if( (c >= '0') && (c <= '9') )
161 {
162 sParam1 = (sParam1 * 10) + (c - '0');
163 }
164 else
165 {
166 sConsoleState = SDCONSOLE_STATE_IDLE;
167 if( c == 'K')
168 {
169 sdEraseEOL();
170 }
171 else if( c == 'D' )
172 {
173 sdCursorBack( sParam1 );
174 }
175 else if( c == 'C' )
176 {
177 sdCursorForward( sParam1 );
178 }
179 else if( (c == 'J') && (sParam1 == 2) )
180 {
181 sdClearScreen();
182 }
183 }
184 break;
185 }
186 return 0;
187}
188
189/* Needed cuz _getch() does not echo. */
190int sdTerminalEcho( char c )
191{
192 sdConsoleEmit((char)(c));
193 return 0;
194}
195
196int sdTerminalIn( void )
197{
198 return _getch();
199}
200
201int sdQueryTerminal( void )
202{
203 return _kbhit();
204}
205
206int sdTerminalFlush( void )
207{
208#ifdef PF_NO_FILEIO
209 return -1;
210#else
211 return fflush(PF_STDOUT);
212#endif
213}
214
215void sdTerminalInit( void )
216{
217 DWORD mode = 0;
218 sConsoleHandle = GetStdHandle( STD_OUTPUT_HANDLE );
219 if( GetConsoleMode( sConsoleHandle, &mode ) )
220 {
221 /*printf("GetConsoleMode() mode is 0x%08X\n", mode );*/
222 sIsConsoleValid = TRUE;
223 }
224 else
225 {
226 /*printf("GetConsoleMode() failed\n", mode );*/
227 sIsConsoleValid = FALSE;
228 }
229}
230
231void sdTerminalTerm( void )
232{
233}
234#endif