ced47a85e0257c30efd2ad5b903a196e19497af4
[debian/pforth] / csrc / win32_console / pf_io_win32_console.c
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
29 static HANDLE sConsoleHandle = INVALID_HANDLE_VALUE;
30 static int sIsConsoleValid = FALSE;
31
32 typedef enum ConsoleState_e
33 {
34     SDCONSOLE_STATE_IDLE = 0,
35     SDCONSOLE_STATE_GOT_ESCAPE,
36     SDCONSOLE_STATE_GOT_BRACKET
37
38 } ConsoleState;
39
40 static int sConsoleState = SDCONSOLE_STATE_IDLE;
41 static int sParam1 = 0;
42 static CONSOLE_SCREEN_BUFFER_INFO sScreenInfo;
43
44 /******************************************************************/
45 static 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 /******************************************************************/
63 static 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 /******************************************************************/
80 static 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 /******************************************************************/
96 static 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 /******************************************************************/
109 static 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  */
128 int  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. */
187 int  sdTerminalEcho( char c )
188 {
189     sdConsoleEmit((char)(c));
190     return 0;
191 }
192
193 int  sdTerminalIn( void )
194 {
195     return _getch();
196 }
197
198 int  sdQueryTerminal( void )
199 {
200     return _kbhit();
201 }
202
203 int  sdTerminalFlush( void )
204 {
205 #ifdef PF_NO_FILEIO
206     return -1;
207 #else
208     return fflush(PF_STDOUT);
209 #endif
210 }
211
212 void 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
228 void sdTerminalTerm( void )
229 {
230 }
231 #endif