Updated README with better build info
[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 ** 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.
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
32 static HANDLE sConsoleHandle = INVALID_HANDLE_VALUE;
33 static int sIsConsoleValid = FALSE;
34
35 typedef enum ConsoleState_e
36 {
37     SDCONSOLE_STATE_IDLE = 0,
38     SDCONSOLE_STATE_GOT_ESCAPE,
39     SDCONSOLE_STATE_GOT_BRACKET
40
41 } ConsoleState;
42
43 static int sConsoleState = SDCONSOLE_STATE_IDLE;
44 static int sParam1 = 0;
45 static CONSOLE_SCREEN_BUFFER_INFO sScreenInfo;
46
47 /******************************************************************/
48 static 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 /******************************************************************/
66 static 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 /******************************************************************/
83 static 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 /******************************************************************/
99 static 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 /******************************************************************/
112 static 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  */
131 int  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. */
190 int  sdTerminalEcho( char c )
191 {
192     sdConsoleEmit((char)(c));
193     return 0;
194 }
195
196 int  sdTerminalIn( void )
197 {
198     return _getch();
199 }
200
201 int  sdQueryTerminal( void )
202 {
203     return _kbhit();
204 }
205
206 int  sdTerminalFlush( void )
207 {
208 #ifdef PF_NO_FILEIO
209     return -1;
210 #else
211     return fflush(PF_STDOUT);
212 #endif
213 }
214
215 void 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
231 void sdTerminalTerm( void )
232 {
233 }
234 #endif