1 /********************************************************************/
2 /*                                                                  */
3 /*  con_win.c     Driver for windows console access.                */
4 /*  Copyright (C) 1989 - 2005  Thomas Mertes                        */
5 /*                                                                  */
6 /*  This file is part of the Seed7 Runtime Library.                 */
7 /*                                                                  */
8 /*  The Seed7 Runtime Library is free software; you can             */
9 /*  redistribute it and/or modify it under the terms of the GNU     */
10 /*  Lesser General Public License as published by the Free Software */
11 /*  Foundation; either version 2.1 of the License, or (at your      */
12 /*  option) any later version.                                      */
13 /*                                                                  */
14 /*  The Seed7 Runtime Library is distributed in the hope that it    */
15 /*  will be useful, but WITHOUT ANY WARRANTY; without even the      */
16 /*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /*  PURPOSE.  See the GNU Lesser General Public License for more    */
18 /*  details.                                                        */
19 /*                                                                  */
20 /*  You should have received a copy of the GNU Lesser General       */
21 /*  Public License along with this program; if not, write to the    */
22 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
23 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
24 /*                                                                  */
25 /*  Module: Seed7 Runtime Library                                   */
26 /*  File: seed7/src/con_win.c                                       */
27 /*  Changes: 2005  Thomas Mertes                                    */
28 /*  Content: Driver for windows console access.                     */
29 /*                                                                  */
30 /********************************************************************/
31 
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34 
35 #include "version.h"
36 
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "windows.h"
41 #include "wchar.h"
42 
43 #include "common.h"
44 #include "heaputl.h"
45 #include "striutl.h"
46 #include "fil_rtl.h"
47 #include "ut8_rtl.h"
48 #include "rtl_err.h"
49 #include "con_drv.h"
50 #include "kbd_drv.h"
51 
52 
53 #define SCRHEIGHT 25
54 #define SCRWIDTH 80
55 #define WRITE_STRI_BLOCK_SIZE 256
56 
57 static boolType keybd_initialized = FALSE;
58 static DWORD savedKeybdMode;
59 static HANDLE hKeyboard = INVALID_HANDLE_VALUE;
60 
61 static char currentattribute;
62 static boolType console_initialized = FALSE;
63 
64 static const charType map_1252_to_unicode[] = {
65 /* 128 */ 0x20AC,    '?', 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
66 /* 136 */ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152,    '?', 0x017D,    '?',
67 /* 144 */    '?', 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
68 /* 152 */ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153,    '?', 0x017E, 0x0178};
69 
70 
71 
kbdShut(void)72 void kbdShut (void)
73 
74   { /* kbdShut */
75     if (keybd_initialized) {
76       if (hKeyboard != INVALID_HANDLE_VALUE) {
77         SetConsoleMode(hKeyboard, savedKeybdMode);
78       } /* if */
79     } /* if */
80   } /* kbdShut */
81 
82 
83 
kbd_init(void)84 static void kbd_init (void)
85 
86   { /* kbd_init */
87     logFunction(printf("kbd_init\n"););
88     hKeyboard = GetStdHandle(STD_INPUT_HANDLE);
89     if (hKeyboard != INVALID_HANDLE_VALUE) {
90       if (unlikely(GetConsoleMode(hKeyboard, &savedKeybdMode) == 0)) {
91         logError(printf("kbd_init: GetConsoleMode(hKeyboard, *) failed:\n"
92                         "Error=" FMT_U32 "\n", (uint32Type) GetLastError());
93                  fflush(stdout););
94       } else {
95 #ifdef OUT_OF_ORDER
96         if (savedKeybdMode & ENABLE_ECHO_INPUT) { printf("ECHO_INPUT\n"); }
97         if (savedKeybdMode & ENABLE_EXTENDED_FLAGS) { printf("EXTENDED_FLAGS\n"); }
98         if (savedKeybdMode & ENABLE_INSERT_MODE) { printf("INSERT_MODE\n"); }
99         if (savedKeybdMode & ENABLE_LINE_INPUT) { printf("LINE_INPUT\n"); }
100         if (savedKeybdMode & ENABLE_MOUSE_INPUT) { printf("MOUSE_INPUT\n"); }
101         if (savedKeybdMode & ENABLE_PROCESSED_INPUT) { printf("PROCESSED_INPUT\n"); }
102         if (savedKeybdMode & ENABLE_QUICK_EDIT_MODE) { printf("QUICK_EDIT_MODE\n"); }
103         if (savedKeybdMode & ENABLE_WINDOW_INPUT) { printf("WINDOW_INPUT\n"); }
104         /* if (savedKeybdMode & ENABLE_VIRTUAL_TERMINAL_INPUT) { printf("VIRTUAL_TERMINAL_INPUT\n"); } */
105 #endif
106         /* ENABLE_LINE_INPUT enables CTRL-S processing. */
107         /* ENABLE_PROCESSED_INPUT enables CTRL-C processing. */
108         SetConsoleMode(hKeyboard, savedKeybdMode &
109                        (DWORD) ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT));
110         keybd_initialized = TRUE;
111         atexit(kbdShut);
112       } /* if */
113     } /* if */
114     logFunction(printf("kbd_init -->\n"););
115   } /* kbd_init */
116 
117 
118 
kbdKeyPressed(void)119 boolType kbdKeyPressed (void)
120 
121   {
122     INPUT_RECORD event;
123     DWORD count = 0;
124     boolType ignoreEvent;
125     boolType result;
126 
127   /* kbdKeyPressed */
128     logFunction(printf("kbdKeyPressed\n"););
129     if (!keybd_initialized) {
130       kbd_init();
131     } /* if */
132     do {
133       ignoreEvent = FALSE;
134       result = PeekConsoleInputW(hKeyboard, &event, 1, &count) != 0 &&
135                count != 0;
136       if (result) {
137         if (event.EventType == KEY_EVENT) {
138           if (event.Event.KeyEvent.bKeyDown) {
139             switch (event.Event.KeyEvent.wVirtualKeyCode){
140               case VK_SHIFT:
141               case VK_CONTROL:
142               case VK_MENU:
143               case VK_CAPITAL:
144               case VK_NUMLOCK:
145               case VK_SCROLL:
146                 ignoreEvent = TRUE;
147                 break;
148             } /* switch */
149           } else {
150             ignoreEvent = TRUE;
151           } /* if */
152         } else if (event.EventType == FOCUS_EVENT ||
153                    event.EventType == MENU_EVENT ||
154                    event.EventType == MOUSE_EVENT) {
155           /* Ignore focus and menu events.                  */
156           /* They are used internally by windows.           */
157           /* Ignore mouse movement and button press events. */
158           ignoreEvent = TRUE;
159         } else {
160           printf("kbdKeyPressed: EventType = %d\n", event.EventType);
161         } /* if */
162         if (ignoreEvent) {
163           /* Skip the event to be ignored. */
164           ignoreEvent = ReadConsoleInputW(hKeyboard, &event, 1, &count) != 0;
165           /* If reading the event, that already has been */
166           /* peeked, fails the loop is terminated. */
167         } /* if */
168       } /* if */
169     } while (ignoreEvent);
170     logFunction(printf("kbdKeyPressed --> %d\n", result););
171     return result;
172   } /* kbdKeyPressed */
173 
174 
175 
kbdGetc(void)176 charType kbdGetc (void)
177 
178   {
179     INPUT_RECORD event;
180     DWORD count;
181     charType result = K_NONE;
182 
183   /* kbdGetc */
184     logFunction(printf("kbdGetc\n"););
185     if (!keybd_initialized) {
186       kbd_init();
187     } /* if */
188     while (result == K_NONE &&
189         ReadConsoleInputW(hKeyboard, &event, 1, &count) != 0) {
190       if (event.EventType == KEY_EVENT) {
191         if (event.Event.KeyEvent.bKeyDown) {
192           if (event.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
193             switch (event.Event.KeyEvent.wVirtualKeyCode){
194               case VK_LBUTTON:  result = K_MOUSE1;     break;
195               case VK_MBUTTON:  result = K_MOUSE2;     break;
196               case VK_RBUTTON:  result = K_MOUSE3;     break;
197               case VK_RETURN:   result = K_NL;         break;
198               case VK_F1:       result = K_SFT_F1;     break;
199               case VK_F2:       result = K_SFT_F2;     break;
200               case VK_F3:       result = K_SFT_F3;     break;
201               case VK_F4:       result = K_SFT_F4;     break;
202               case VK_F5:       result = K_SFT_F5;     break;
203               case VK_F6:       result = K_SFT_F6;     break;
204               case VK_F7:       result = K_SFT_F7;     break;
205               case VK_F8:       result = K_SFT_F8;     break;
206               case VK_F9:       result = K_SFT_F9;     break;
207               case VK_F10:      result = K_SFT_F10;    break;
208               case VK_F11:      result = K_SFT_F11;    break;
209               case VK_F12:      result = K_SFT_F12;    break;
210               case VK_LEFT:     result = K_LEFT;       break;
211               case VK_RIGHT:    result = K_RIGHT;      break;
212               case VK_UP:       result = K_UP;         break;
213               case VK_DOWN:     result = K_DOWN;       break;
214               case VK_HOME:     result = K_HOME;       break;
215               case VK_END:      result = K_END;        break;
216               case VK_PRIOR:    result = K_PGUP;       break;
217               case VK_NEXT:     result = K_PGDN;       break;
218               case VK_INSERT:   result = K_INS;        break;
219               case VK_DELETE:   result = K_DEL;        break;
220               case VK_CLEAR:    result = K_PAD_CENTER; break;
221               case VK_APPS:     result = K_UNDEF;      break;
222               case VK_TAB:      result = K_BACKTAB;    break;
223               case VK_SHIFT:
224               case VK_CONTROL:
225               case VK_MENU:
226               case VK_CAPITAL:
227               case VK_NUMLOCK:
228               case VK_SCROLL:   result = K_NONE;       break;
229               default:          result = K_UNDEF;      break;
230             } /* switch */
231           } else if (event.Event.KeyEvent.dwControlKeyState &
232                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
233             switch (event.Event.KeyEvent.wVirtualKeyCode){
234               case VK_LBUTTON:  result = K_MOUSE1;     break;
235               case VK_MBUTTON:  result = K_MOUSE2;     break;
236               case VK_RBUTTON:  result = K_MOUSE3;     break;
237               case VK_RETURN:   result = K_NL;         break;
238               case VK_F1:       result = K_ALT_F1;     break;
239               case VK_F2:       result = K_ALT_F2;     break;
240               case VK_F3:       result = K_ALT_F3;     break;
241               case VK_F4:       result = K_ALT_F4;     break;
242               case VK_F5:       result = K_ALT_F5;     break;
243               case VK_F6:       result = K_ALT_F6;     break;
244               case VK_F7:       result = K_ALT_F7;     break;
245               case VK_F8:       result = K_ALT_F8;     break;
246               case VK_F9:       result = K_ALT_F9;     break;
247               case VK_F10:      result = K_ALT_F10;    break;
248               case VK_F11:      result = K_ALT_F11;    break;
249               case VK_F12:      result = K_ALT_F12;    break;
250               case VK_LEFT:     result = K_LEFT;       break;
251               case VK_RIGHT:    result = K_RIGHT;      break;
252               case VK_UP:       result = K_UP;         break;
253               case VK_DOWN:     result = K_DOWN;       break;
254               case VK_HOME:     result = K_HOME;       break;
255               case VK_END:      result = K_END;        break;
256               case VK_PRIOR:    result = K_PGUP;       break;
257               case VK_NEXT:     result = K_PGDN;       break;
258               case VK_INSERT:   result = K_INS;        break;
259               case VK_DELETE:   result = K_DEL;        break;
260               case VK_CLEAR:    result = K_PAD_CENTER; break;
261               case VK_APPS:     result = K_UNDEF;      break;
262               case VK_SHIFT:
263               case VK_CONTROL:
264               case VK_MENU:
265               case VK_CAPITAL:
266               case VK_NUMLOCK:
267               case VK_SCROLL:   result = K_NONE;       break;
268               default:          result = K_UNDEF;      break;
269             } /* switch */
270           } else if (event.Event.KeyEvent.dwControlKeyState &
271                      (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
272             switch (event.Event.KeyEvent.wVirtualKeyCode){
273               case VK_LBUTTON:  result = K_MOUSE1;     break;
274               case VK_MBUTTON:  result = K_MOUSE2;     break;
275               case VK_RBUTTON:  result = K_MOUSE3;     break;
276               case VK_RETURN:   result = K_NL;         break;
277               case VK_F1:       result = K_CTL_F1;     break;
278               case VK_F2:       result = K_CTL_F2;     break;
279               case VK_F3:       result = K_CTL_F3;     break;
280               case VK_F4:       result = K_CTL_F4;     break;
281               case VK_F5:       result = K_CTL_F5;     break;
282               case VK_F6:       result = K_CTL_F6;     break;
283               case VK_F7:       result = K_CTL_F7;     break;
284               case VK_F8:       result = K_CTL_F8;     break;
285               case VK_F9:       result = K_CTL_F9;     break;
286               case VK_F10:      result = K_CTL_F10;    break;
287               case VK_F11:      result = K_CTL_F11;    break;
288               case VK_F12:      result = K_CTL_F12;    break;
289               case VK_LEFT:     result = K_CTL_LEFT;   break;
290               case VK_RIGHT:    result = K_CTL_RIGHT;  break;
291               case VK_UP:       result = K_CTL_UP;     break;
292               case VK_DOWN:     result = K_CTL_DOWN;   break;
293               case VK_HOME:     result = K_CTL_HOME;   break;
294               case VK_END:      result = K_CTL_END;    break;
295               case VK_PRIOR:    result = K_CTL_PGUP;   break;
296               case VK_NEXT:     result = K_CTL_PGDN;   break;
297               case VK_INSERT:   result = K_CTL_INS;    break;
298               case VK_DELETE:   result = K_CTL_DEL;    break;
299               case VK_CLEAR:    result = K_PAD_CENTER; break;
300               case VK_APPS:     result = K_UNDEF;      break;
301               case VK_SHIFT:
302               case VK_CONTROL:
303               case VK_MENU:
304               case VK_CAPITAL:
305               case VK_NUMLOCK:
306               case VK_SCROLL:   result = K_NONE;       break;
307               default:          result = K_UNDEF;      break;
308             } /* switch */
309           } else {
310             switch (event.Event.KeyEvent.wVirtualKeyCode){
311               case VK_LBUTTON:  result = K_MOUSE1;     break;
312               case VK_MBUTTON:  result = K_MOUSE2;     break;
313               case VK_RBUTTON:  result = K_MOUSE3;     break;
314               case VK_RETURN:   result = K_NL;         break;
315               case VK_F1:       result = K_F1;         break;
316               case VK_F2:       result = K_F2;         break;
317               case VK_F3:       result = K_F3;         break;
318               case VK_F4:       result = K_F4;         break;
319               case VK_F5:       result = K_F5;         break;
320               case VK_F6:       result = K_F6;         break;
321               case VK_F7:       result = K_F7;         break;
322               case VK_F8:       result = K_F8;         break;
323               case VK_F9:       result = K_F9;         break;
324               case VK_F10:      result = K_F10;        break;
325               case VK_F11:      result = K_F11;        break;
326               case VK_F12:      result = K_F12;        break;
327               case VK_LEFT:     result = K_LEFT;       break;
328               case VK_RIGHT:    result = K_RIGHT;      break;
329               case VK_UP:       result = K_UP;         break;
330               case VK_DOWN:     result = K_DOWN;       break;
331               case VK_HOME:     result = K_HOME;       break;
332               case VK_END:      result = K_END;        break;
333               case VK_PRIOR:    result = K_PGUP;       break;
334               case VK_NEXT:     result = K_PGDN;       break;
335               case VK_INSERT:   result = K_INS;        break;
336               case VK_DELETE:   result = K_DEL;        break;
337               case VK_CLEAR:    result = K_PAD_CENTER; break;
338               case VK_APPS:     result = K_UNDEF;      break;
339               case VK_SHIFT:
340               case VK_CONTROL:
341               case VK_MENU:
342               case VK_CAPITAL:
343               case VK_NUMLOCK:
344               case VK_SCROLL:   result = K_NONE;       break;
345               default:          result = K_UNDEF;      break;
346             } /* switch */
347           } /* if */
348           if (result == K_UNDEF) {
349             if (event.Event.KeyEvent.uChar.UnicodeChar != 0) {
350               if (event.Event.KeyEvent.dwControlKeyState &
351                   (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
352                 switch (event.Event.KeyEvent.uChar.UnicodeChar) {
353                   case 'A': case 'a': result = K_ALT_A; break;
354                   case 'B': case 'b': result = K_ALT_B; break;
355                   case 'C': case 'c': result = K_ALT_C; break;
356                   case 'D': case 'd': result = K_ALT_D; break;
357                   case 'E': case 'e': result = K_ALT_E; break;
358                   case 'F': case 'f': result = K_ALT_F; break;
359                   case 'G': case 'g': result = K_ALT_G; break;
360                   case 'H': case 'h': result = K_ALT_H; break;
361                   case 'I': case 'i': result = K_ALT_I; break;
362                   case 'J': case 'j': result = K_ALT_J; break;
363                   case 'K': case 'k': result = K_ALT_K; break;
364                   case 'L': case 'l': result = K_ALT_L; break;
365                   case 'M': case 'm': result = K_ALT_M; break;
366                   case 'N': case 'n': result = K_ALT_N; break;
367                   case 'O': case 'o': result = K_ALT_O; break;
368                   case 'P': case 'p': result = K_ALT_P; break;
369                   case 'Q': case 'q': result = K_ALT_Q; break;
370                   case 'R': case 'r': result = K_ALT_R; break;
371                   case 'S': case 's': result = K_ALT_S; break;
372                   case 'T': case 't': result = K_ALT_T; break;
373                   case 'U': case 'u': result = K_ALT_U; break;
374                   case 'V': case 'v': result = K_ALT_V; break;
375                   case 'W': case 'w': result = K_ALT_W; break;
376                   case 'X': case 'x': result = K_ALT_X; break;
377                   case 'Y': case 'y': result = K_ALT_Y; break;
378                   case 'Z': case 'z': result = K_ALT_Z; break;
379                   case '0':           result = K_ALT_0; break;
380                   case '1':           result = K_ALT_1; break;
381                   case '2':           result = K_ALT_2; break;
382                   case '3':           result = K_ALT_3; break;
383                   case '4':           result = K_ALT_4; break;
384                   case '5':           result = K_ALT_5; break;
385                   case '6':           result = K_ALT_6; break;
386                   case '7':           result = K_ALT_7; break;
387                   case '8':           result = K_ALT_8; break;
388                   case '9':           result = K_ALT_9; break;
389                 } /* switch */
390               } /* if */
391               if (result == K_UNDEF) {
392                 result = event.Event.KeyEvent.uChar.UnicodeChar;
393                 if (result >= 128 && result <= 159) {
394                   result = map_1252_to_unicode[result - 128];
395                 } /* if */
396               } /* if */
397             } else {
398               /*
399               printf("VK: %lu\n",
400                      (unsigned long) event.Event.KeyEvent.wVirtualKeyCode);
401               printf("Char: %lu\n",
402                      (unsigned long) event.Event.KeyEvent.uChar.UnicodeChar);
403               printf("CKey: %lx\n",
404                      (unsigned long) event.Event.KeyEvent.dwControlKeyState);
405               */
406             } /* if */
407           } /* if */
408         } /* if */
409       } else if (event.EventType == FOCUS_EVENT ||
410                  event.EventType == MENU_EVENT ||
411                  event.EventType == MOUSE_EVENT) {
412         /* Ignore focus and menu events.                  */
413         /* They are used internally by windows.           */
414         /* Ignore mouse movement and button press events. */
415       } else {
416         printf("kbdGetc: EventType = %d\n", event.EventType);
417       } /* if */
418     } /* while */
419     logFunction(printf("kbdGetc --> %d\n", result););
420     return result;
421   } /* kbdGetc */
422 
423 
424 
kbdRawGetc(void)425 charType kbdRawGetc (void)
426 
427   { /* kbdRawGetc */
428     return kbdGetc();
429   } /* kbdRawGetc */
430 
431 
432 
con_setcolor(intType foreground,intType background)433 static void con_setcolor (intType foreground, intType background)
434 
435   { /* con_setcolor */
436     currentattribute = (char) (foreground + 16 * (background % 8));
437   } /* con_setcolor */
438 
439 
440 
con_standardcolour(void)441 static void con_standardcolour (void)
442 
443   { /* con_standardcolour */
444     con_setcolor(lightgray, black);
445   } /* con_standardcolour */
446 
447 
448 
con_normalcolour(void)449 static void con_normalcolour (void)
450 
451   { /* con_normalcolour */
452     con_setcolor(lightgray, black);
453   } /* con_normalcolour */
454 
455 
456 
textheight(void)457 intType textheight (void)
458 
459   { /* textheight */
460     return 1;
461   } /* textheight */
462 
463 
464 
textwidth(striType stri,intType startcol,intType stopcol)465 intType textwidth (striType stri,
466     intType startcol, intType stopcol)
467 
468   { /* textwidth */
469     return stopcol + 1 - startcol;
470   } /* textwidth */
471 
472 
473 
textcolumns(striType stri,intType striwidth,intType * cols,intType * rest)474 void textcolumns (striType stri, intType striwidth,
475     intType *cols, intType *rest)
476 
477   { /* textcolumns */
478     *cols = striwidth;
479     *rest = 0;
480   } /* textcolumns */
481 
482 
483 
conHeight(void)484 int conHeight (void)
485 
486   {
487     HANDLE hConsole;
488     CONSOLE_SCREEN_BUFFER_INFO con_info;
489 
490   /* conHeight */
491     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
492     if (hConsole != INVALID_HANDLE_VALUE) {
493       if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
494         return con_info.dwSize.Y;
495       } else {
496         /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
497             hConsole, (uint32Type) GetLastError()); */
498         return SCRHEIGHT;
499       } /* if */
500     } else {
501       /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
502           hConsole, (uint32Type) GetLastError()); */
503       return SCRHEIGHT;
504     } /* if */
505   } /* conHeight */
506 
507 
508 
conWidth(void)509 int conWidth (void)
510 
511   {
512     HANDLE hConsole;
513     CONSOLE_SCREEN_BUFFER_INFO con_info;
514 
515   /* conWidth */
516     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
517     if (hConsole != INVALID_HANDLE_VALUE) {
518       if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
519         return con_info.dwSize.X;
520       } else {
521         /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
522             hConsole, (uint32Type) GetLastError()); */
523         return SCRWIDTH;
524       } /* if */
525     } else {
526       /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
527           hConsole, (uint32Type) GetLastError()); */
528       return SCRWIDTH;
529     } /* if */
530   } /* conWidth */
531 
532 
533 
conFlush(void)534 void conFlush (void)
535 
536   { /* conFlush */
537   } /* conFlush */
538 
539 
540 
conCursor(boolType on)541 void conCursor (boolType on)
542 
543   {
544     HANDLE hConsole;
545     CONSOLE_CURSOR_INFO info;
546 
547   /* conCursor */
548     if (console_initialized) {
549       hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
550       if (hConsole != INVALID_HANDLE_VALUE) {
551         if (likely(GetConsoleCursorInfo(hConsole, &info) != 0)) {
552           info.bVisible = on;
553           if (unlikely(SetConsoleCursorInfo(hConsole, &info) == 0)) {
554             /* printf("SetConsoleCursorInfo(%d, (visible=%d)) --> Error " FMT_U32 "\n",
555                 hConsole, on, (uint32Type) GetLastError()); */
556           } /* if */
557         } else {
558           /* printf("GetConsoleCursorInfo(%d, *) --> Error " FMT_U32 "\n",
559               hConsole, (uint32Type) GetLastError()); */
560         } /* if */
561       } else {
562         /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
563             hConsole, (uint32Type) GetLastError()); */
564       } /* if */
565     } /* if */
566   } /* conCursor */
567 
568 
569 
570 /**
571  *  Moves the system cursor to the given place of the console.
572  *  If no system cursor exists this procedure can be replaced by
573  *  a dummy procedure.
574  */
conSetCursor(intType line,intType column)575 void conSetCursor (intType line, intType column)
576 
577   {
578     HANDLE hConsole;
579     COORD position;
580 
581   /* conSetCursor */
582     if (unlikely(line <= 0 || column <= 0)) {
583       raise_error(RANGE_ERROR);
584     } else if (line <= INT16TYPE_MAX && column <= INT16TYPE_MAX) {
585       if (console_initialized) {
586         hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
587         if (hConsole != INVALID_HANDLE_VALUE) {
588           position.X = (int16Type) (column - 1);
589           position.Y = (int16Type) (line - 1);
590           if (SetConsoleCursorPosition(hConsole, position) == 0) {
591             /* printf("SetConsoleCursorPosition(%d, (%d, %d)) --> Error " FMT_U32 "\n",
592                 hConsole, column - 1, line - 1, (uint32Type) GetLastError()); */
593           } /* if */
594         } else {
595           /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
596               hConsole, (uint32Type) GetLastError()); */
597         } /* if */
598       } /* if */
599     } /* if */
600   } /* conSetCursor */
601 
602 
603 
conColumn(void)604 intType conColumn (void)
605 
606   {
607     HANDLE hConsole;
608     CONSOLE_SCREEN_BUFFER_INFO con_info;
609 
610   /* conColumn */
611     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
612     if (hConsole != INVALID_HANDLE_VALUE) {
613       if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
614         return (intType) con_info.dwCursorPosition.X + 1;
615       } else {
616         /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
617             hConsole, (uint32Type) GetLastError()); */
618         return 1;
619       } /* if */
620     } else {
621       /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
622           hConsole, (uint32Type) GetLastError()); */
623       return 1;
624     } /* if */
625   } /* conColumn */
626 
627 
628 
conLine(void)629 intType conLine (void)
630 
631   {
632     HANDLE hConsole;
633     CONSOLE_SCREEN_BUFFER_INFO con_info;
634 
635   /* conLine */
636     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
637     if (hConsole != INVALID_HANDLE_VALUE) {
638       if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
639         return (intType) con_info.dwCursorPosition.Y + 1;
640       } else {
641         /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
642             hConsole, (uint32Type) GetLastError()); */
643         return 1;
644       } /* if */
645     } else {
646       /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
647           hConsole, (uint32Type) GetLastError()); */
648       return 1;
649     } /* if */
650   } /* conLine */
651 
652 
653 
doWriteConsole(HANDLE hConsole,const const_striType stri)654 static void doWriteConsole (HANDLE hConsole, const const_striType stri)
655 
656   {
657     wcharType wstri_buffer[WRITE_STRI_BLOCK_SIZE * SURROGATE_PAIR_FACTOR];
658     wstriType wstri;
659     wstriType wstri_part;
660     memSizeType wstri_size;
661     errInfoType err_info = OKAY_NO_ERROR;
662     DWORD numchars;
663 
664   /* doWriteConsole */
665     /* fprintf(stderr, "doWriteConsole(%lx, ...)", (unsigned long) hConsole); */
666     if (stri->size <= WRITE_STRI_BLOCK_SIZE) {
667       wstri_size = stri_to_utf16(wstri_buffer, stri->mem, stri->size, &err_info);
668       if (unlikely(err_info != OKAY_NO_ERROR)) {
669         raise_error(err_info);
670       } else {
671         WriteConsoleW(hConsole, wstri_buffer, (DWORD) wstri_size, &numchars, NULL);
672       } /* if */
673     } else {
674       /* ALLOC_WSTRI adds space for a NULL termination, which is not needed here. */
675       if (unlikely(stri->size >
676                    (MAX_WSTRI_LEN + NULL_TERMINATION_LEN) / SURROGATE_PAIR_FACTOR ||
677                    !ALLOC_WSTRI(wstri, stri->size * SURROGATE_PAIR_FACTOR -
678                    NULL_TERMINATION_LEN))) {
679         raise_error(MEMORY_ERROR);
680       } else {
681         wstri_size = stri_to_utf16(wstri, stri->mem, stri->size, &err_info);
682         if (unlikely(err_info != OKAY_NO_ERROR)) {
683           raise_error(err_info);
684         } else {
685           wstri_part = wstri;
686           /* Writing may fail for lengths above 26000 to 32000 */
687           while (wstri_size > 25000) {
688             WriteConsoleW(hConsole, wstri_part, 25000, &numchars, NULL);
689             wstri_part = &wstri_part[25000];
690             wstri_size -= 25000;
691           } /* while */
692           WriteConsoleW(hConsole, wstri_part, (DWORD) wstri_size, &numchars, NULL);
693         } /* if */
694         UNALLOC_WSTRI(wstri, stri->size * SURROGATE_PAIR_FACTOR - NULL_TERMINATION_LEN);
695       } /* if */
696     } /* if */
697   } /* doWriteConsole */
698 
699 
700 
701 /**
702  *  Write a string to the current position of the console.
703  *  Unicode characters are written with the encoding of the
704  *  operating system. The cursor position is changed, if
705  *  one of the characters '\n', '\r' and '\b' is written.
706  *  If the standard output file of the operating system has
707  *  been redirected UTF-8 encoded characters are written to
708  *  the redirected file.
709  */
conWrite(const const_striType stri)710 void conWrite (const const_striType stri)
711 
712   {
713     HANDLE hConsole;
714     DWORD mode;
715 
716   /* conWrite */
717     logFunction(printf("conWrite(\"%s\")\n", striAsUnquotedCStri(stri)););
718     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
719     if (hConsole != INVALID_HANDLE_VALUE &&
720         GetFileType(hConsole) == FILE_TYPE_CHAR &&
721         GetConsoleMode(hConsole, &mode) != 0) {
722       /* hConsole refers to a real console */
723       doWriteConsole(hConsole, stri);
724     } else {
725       /* The output has been redirected */
726       ut8Write(&stdoutFileRecord, stri);
727     } /* if */
728     logFunction(printf("conWrite -->\n"););
729   } /* conWrite */
730 
731 
732 
733 /**
734  *  Clears the area described by startlin, stoplin, startcol and stopcol.
735  */
conClear(intType startlin,intType startcol,intType stoplin,intType stopcol)736 void conClear (intType startlin, intType startcol,
737     intType stoplin, intType stopcol)
738 
739   {
740     HANDLE hConsole;
741     COORD position;
742     DWORD numchars;
743 
744   /* conClear */
745     if (unlikely(startlin <= 0 || startcol <= 0 ||
746                  stoplin < startlin || stopcol < startcol)) {
747       raise_error(RANGE_ERROR);
748     } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
749       if (stoplin > INT16TYPE_MAX) {
750         stoplin = INT16TYPE_MAX;
751       } /* if */
752       if (stopcol > INT16TYPE_MAX) {
753         stopcol = INT16TYPE_MAX;
754       } /* if */
755       hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
756       if (hConsole != INVALID_HANDLE_VALUE) {
757         position.X = (int16Type) (startcol - 1);
758         position.Y = (int16Type) (startlin - 1);
759         while (position.Y < (int16Type) stoplin) {
760           FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
761               (unsigned int) (stopcol - startcol + 1), position, &numchars);
762           position.Y++;
763         } /* while */
764       } /* if */
765     } /* if */
766   } /* conClear */
767 
768 
769 
770 /**
771  *  Scrolls the area inside startlin, startcol, stoplin and
772  *  stopcol upward by count lines. The upper count lines of the
773  *  area are overwritten. At the lower end of the area blank lines
774  *  are inserted. Nothing is changed outside the area.
775  *  The calling function assures that count is greater or equal 1.
776  */
conUpScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)777 void conUpScroll (intType startlin, intType startcol,
778     intType stoplin, intType stopcol, intType count)
779 
780   {
781     HANDLE hConsole;
782     SMALL_RECT scrollRect;
783     COORD destOrigin;
784     CHAR_INFO fillChar;
785 
786   /* conUpScroll */
787     if (unlikely(startlin <= 0 || startcol <= 0 ||
788                  stoplin < startlin || stopcol < startcol)) {
789       raise_error(RANGE_ERROR);
790     } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
791       if (count > stoplin - startlin + 1) {
792         conClear(startlin, startcol, stoplin, stopcol);
793       } else {
794         if (stoplin > INT16TYPE_MAX) {
795           stoplin = INT16TYPE_MAX;
796         } /* if */
797         if (stopcol > INT16TYPE_MAX) {
798           stopcol = INT16TYPE_MAX;
799         } /* if */
800         hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
801         if (hConsole != INVALID_HANDLE_VALUE) {
802           scrollRect.Left   = (int16Type) (startcol - 1);
803           scrollRect.Top    = (int16Type) (startlin + count - 1);
804           scrollRect.Right  = (int16Type) (stopcol - 1);
805           scrollRect.Bottom = (int16Type) (stoplin - 1);
806           destOrigin.X = (int16Type) (startcol - 1);
807           destOrigin.Y = (int16Type) (startlin - 1);
808           memset(&fillChar, 0, sizeof(CHAR_INFO));
809           fillChar.Char.AsciiChar = ' ';
810           ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
811         } else {
812           /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
813               hConsole, (uint32Type) GetLastError()); */
814         } /* if */
815       } /* if */
816     } /* if */
817   } /* conUpScroll */
818 
819 
820 
821 /**
822  *  Scrolls the area inside startlin, startcol, stoplin and
823  *  stopcol downward by count lines. The lower count lines of the
824  *  area are overwritten. At the upper end of the area blank lines
825  *  are inserted. Nothing is changed outside the area.
826  *  The calling function assures that count is greater or equal 1.
827  */
conDownScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)828 void conDownScroll (intType startlin, intType startcol,
829     intType stoplin, intType stopcol, intType count)
830 
831   {
832     HANDLE hConsole;
833     SMALL_RECT scrollRect;
834     COORD destOrigin;
835     CHAR_INFO fillChar;
836 
837   /* conDownScroll */
838     if (unlikely(startlin <= 0 || startcol <= 0 ||
839                  stoplin < startlin || stopcol < startcol)) {
840       raise_error(RANGE_ERROR);
841     } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
842       if (count > stoplin - startlin + 1) {
843         conClear(startlin, startcol, stoplin, stopcol);
844       } else {
845         if (stoplin > INT16TYPE_MAX) {
846           stoplin = INT16TYPE_MAX;
847         } /* if */
848         if (stopcol > INT16TYPE_MAX) {
849           stopcol = INT16TYPE_MAX;
850         } /* if */
851         hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
852         if (hConsole != INVALID_HANDLE_VALUE) {
853           scrollRect.Left   = (int16Type) (startcol - 1);
854           scrollRect.Top    = (int16Type) (startlin - 1);
855           scrollRect.Right  = (int16Type) (stopcol - 1);
856           scrollRect.Bottom = (int16Type) (stoplin - count - 1);
857           destOrigin.X = (int16Type) (startcol - 1);
858           destOrigin.Y = (int16Type) (startlin + count - 1);
859           memset(&fillChar, 0, sizeof(CHAR_INFO));
860           fillChar.Char.AsciiChar = ' ';
861           ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
862         } else {
863           /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
864               hConsole, (uint32Type) GetLastError()); */
865         } /* if */
866       } /* if */
867     } /* if */
868   } /* conDownScroll */
869 
870 
871 
872 /**
873  *  Scrolls the area inside startlin, startcol, stoplin and
874  *  stopcol leftward by count columns. The left count columns of the
875  *  area are overwritten. At the right end of the area blank columns
876  *  are inserted. Nothing is changed outside the area.
877  *  The calling function assures that count is greater or equal 1.
878  */
conLeftScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)879 void conLeftScroll (intType startlin, intType startcol,
880     intType stoplin, intType stopcol, intType count)
881 
882   {
883     HANDLE hConsole;
884     SMALL_RECT scrollRect;
885     COORD destOrigin;
886     CHAR_INFO fillChar;
887 
888   /* conLeftScroll */
889     if (unlikely(startlin <= 0 || startcol <= 0 ||
890                  stoplin < startlin || stopcol < startcol)) {
891       raise_error(RANGE_ERROR);
892     } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
893       if (count > stopcol - startcol + 1) {
894         conClear(startlin, startcol, stoplin, stopcol);
895       } else {
896         if (stoplin > INT16TYPE_MAX) {
897           stoplin = INT16TYPE_MAX;
898         } /* if */
899         if (stopcol > INT16TYPE_MAX) {
900           stopcol = INT16TYPE_MAX;
901         } /* if */
902         hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
903         if (hConsole != INVALID_HANDLE_VALUE) {
904           scrollRect.Left   = (int16Type) (startcol + count - 1);
905           scrollRect.Top    = (int16Type) (startlin - 1);
906           scrollRect.Right  = (int16Type) (stopcol - 1);
907           scrollRect.Bottom = (int16Type) (stoplin - 1);
908           destOrigin.X = (int16Type) (startcol - 1);
909           destOrigin.Y = (int16Type) (startlin - 1);
910           memset(&fillChar, 0, sizeof(CHAR_INFO));
911           fillChar.Char.AsciiChar = ' ';
912           ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
913         } else {
914           /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
915               hConsole, (uint32Type) GetLastError()); */
916         } /* if */
917       } /* if */
918     } /* if */
919   } /* conLeftScroll */
920 
921 
922 
923 /**
924  *  Scrolls the area inside startlin, startcol, stoplin and
925  *  stopcol rightward by count columns. The right count columns of the
926  *  area are overwritten. At the left end of the area blank columns
927  *  are inserted. Nothing is changed outside the area.
928  *  The calling function assures that count is greater or equal 1.
929  */
conRightScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)930 void conRightScroll (intType startlin, intType startcol,
931     intType stoplin, intType stopcol, intType count)
932 
933   {
934     HANDLE hConsole;
935     SMALL_RECT scrollRect;
936     COORD destOrigin;
937     CHAR_INFO fillChar;
938 
939   /* conRightScroll */
940     if (unlikely(startlin <= 0 || startcol <= 0 ||
941                  stoplin < startlin || stopcol < startcol)) {
942       raise_error(RANGE_ERROR);
943     } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
944       if (count > stopcol - startcol + 1) {
945         conClear(startlin, startcol, stoplin, stopcol);
946       } else {
947         if (stoplin > INT16TYPE_MAX) {
948           stoplin = INT16TYPE_MAX;
949         } /* if */
950         if (stopcol > INT16TYPE_MAX) {
951           stopcol = INT16TYPE_MAX;
952         } /* if */
953         hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
954         if (hConsole != INVALID_HANDLE_VALUE) {
955           scrollRect.Left   = (int16Type) (startcol - 1);
956           scrollRect.Top    = (int16Type) (startlin - 1);
957           scrollRect.Right  = (int16Type) (stopcol - count - 1);
958           scrollRect.Bottom = (int16Type) (stoplin - 1);
959           destOrigin.X = (int16Type) (startcol + count - 1);
960           destOrigin.Y = (int16Type) (startlin - 1);
961           memset(&fillChar, 0, sizeof(CHAR_INFO));
962           fillChar.Char.AsciiChar = ' ';
963           ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
964         } else {
965           /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
966               hConsole, (uint32Type) GetLastError()); */
967         } /* if */
968       } /* if */
969     } /* if */
970   } /* conRightScroll */
971 
972 
973 
conShut(void)974 void conShut (void)
975 
976   { /* conShut */
977     logFunction(printf("conShut\n"););
978     if (console_initialized) {
979       con_standardcolour();
980       conCursor(TRUE);
981       conClear(1, 1, conHeight(), conWidth());
982       conSetCursor(1, 24);
983       console_initialized = FALSE;
984     } /* if */
985     logFunction(printf("conShut -->\n"););
986   } /* conShut */
987 
988 
989 
990 /**
991  *  Initializes and clears the console.
992  */
conOpen(void)993 int conOpen (void)
994 
995   { /* conOpen */
996     logFunction(printf("conOpen\n"););
997     con_normalcolour();
998     conClear(1, 1, conHeight(), conWidth());
999     console_initialized = TRUE;
1000     conCursor(FALSE);
1001     conSetCursor(1, 1);
1002     atexit(conShut);
1003     logFunction(printf("conOpen -->\n"););
1004     return 1;
1005   } /* conOpen */
1006