1 /* HCONSOLE.C (c) Copyright "Fish" (David B. Trout), 2005-2009 */
2 /* Hercules console panel support functions */
3
4 //////////////////////////////////////////////////////////////////////////////////////////
5 // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License
6 // (http://www.hercules-390.org/herclic.html) as modifications to Hercules.
7 //////////////////////////////////////////////////////////////////////////////////////////
8
9 #include "hstdinc.h"
10
11 #include "hercules.h"
12 #include "hconsole.h"
13
14 //////////////////////////////////////////////////////////////////////////////////////////
15 //////////////////////////////////////////////////////////////////////////////////////////
16 //////////////////////////////////////////////////////////////////////////////////////////
17
18 #if defined( _MSVC_ )
19
20 //////////////////////////////////////////////////////////////////////////////////////////
21 // 'save_and_set' = 1 --> just what it says; 0 --> restore from saved value.
22
23 static DWORD g_dwConsoleInputMode = 0; // (saved value so we can later restore it)
24 static DWORD g_dwConsoleOutputMode = 0; // (saved value so we can later restore it)
25 static WORD g_wDefaultAttrib = 0; // (saved value so we can later restore it)
26
default_FG_color()27 static WORD default_FG_color() { return g_wDefaultAttrib & 0x0F; }
default_BG_color()28 static WORD default_BG_color() { return (g_wDefaultAttrib >> 4) & 0x0F; }
29
set_or_reset_console_mode(int keybrd_fd,short save_and_set)30 int set_or_reset_console_mode( int keybrd_fd, short save_and_set )
31 {
32 CONSOLE_SCREEN_BUFFER_INFO csbi;
33 HANDLE hStdIn, hStdErr;
34 DWORD dwNewInputMode;
35 DWORD dwNewOutputMode;
36
37 if ( ! _isatty( keybrd_fd ) )
38 {
39 errno = EBADF;
40 return -1;
41 }
42
43 hStdIn = (HANDLE) _get_osfhandle( keybrd_fd );
44 ASSERT( hStdIn && INVALID_HANDLE_VALUE != hStdIn );
45
46 hStdErr = GetStdHandle( STD_ERROR_HANDLE );
47 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
48
49 if ( save_and_set )
50 {
51 VERIFY( GetConsoleMode( hStdIn, &g_dwConsoleInputMode ) );
52 VERIFY( GetConsoleMode( hStdErr, &g_dwConsoleOutputMode ) );
53 VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) );
54 g_wDefaultAttrib = csbi.wAttributes;
55 dwNewInputMode = 0;
56 dwNewOutputMode = 0;
57 }
58 else // (restore/reset)
59 {
60 VERIFY( SetConsoleTextAttribute( hStdErr, g_wDefaultAttrib ) );
61 dwNewInputMode = g_dwConsoleInputMode;
62 dwNewOutputMode = g_dwConsoleOutputMode;
63 }
64
65 VERIFY( SetConsoleMode( hStdIn, dwNewInputMode ) );
66 VERIFY( SetConsoleMode( hStdErr, dwNewOutputMode ) );
67
68 return 0;
69 }
70
71 //////////////////////////////////////////////////////////////////////////////////////////
72 // Translate Herc color to Win32 color...
73
74 #define W32_FOREGROUND_COLOR( w32_color ) ( ( w32_color ) )
75 #define W32_BACKGROUND_COLOR( w32_color ) ( ( w32_color ) << 4 )
76
77 #define W32_COLOR_BLACK ( 0 )
78 #define W32_COLOR_RED ( FOREGROUND_RED )
79 #define W32_COLOR_GREEN ( FOREGROUND_GREEN )
80 #define W32_COLOR_BLUE ( FOREGROUND_BLUE )
81 #define W32_COLOR_CYAN ( FOREGROUND_GREEN | FOREGROUND_BLUE )
82 #define W32_COLOR_MAGENTA ( FOREGROUND_RED | FOREGROUND_BLUE )
83 #define W32_COLOR_YELLOW ( FOREGROUND_RED | FOREGROUND_GREEN )
84 #define W32_COLOR_LIGHT_GREY ( FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE )
85
86 #define W32_COLOR_DARK_GREY ( FOREGROUND_INTENSITY | W32_COLOR_BLACK )
87 #define W32_COLOR_LIGHT_RED ( FOREGROUND_INTENSITY | W32_COLOR_RED )
88 #define W32_COLOR_LIGHT_GREEN ( FOREGROUND_INTENSITY | W32_COLOR_GREEN )
89 #define W32_COLOR_LIGHT_BLUE ( FOREGROUND_INTENSITY | W32_COLOR_BLUE )
90 #define W32_COLOR_LIGHT_CYAN ( FOREGROUND_INTENSITY | W32_COLOR_CYAN )
91 #define W32_COLOR_LIGHT_MAGENTA ( FOREGROUND_INTENSITY | W32_COLOR_MAGENTA )
92 #define W32_COLOR_LIGHT_YELLOW ( FOREGROUND_INTENSITY | W32_COLOR_YELLOW )
93 #define W32_COLOR_WHITE ( FOREGROUND_INTENSITY | W32_COLOR_LIGHT_GREY )
94
W32_COLOR(short herc_color)95 static WORD W32_COLOR( short herc_color )
96 {
97 switch ( herc_color )
98 {
99 case COLOR_BLACK: return W32_COLOR_BLACK;
100 case COLOR_RED: return W32_COLOR_RED;
101 case COLOR_GREEN: return W32_COLOR_GREEN;
102 case COLOR_BLUE: return W32_COLOR_BLUE;
103 case COLOR_CYAN: return W32_COLOR_CYAN;
104 case COLOR_MAGENTA: return W32_COLOR_MAGENTA;
105 case COLOR_YELLOW: return W32_COLOR_YELLOW;
106 case COLOR_DARK_GREY: return W32_COLOR_DARK_GREY;
107
108 case COLOR_LIGHT_GREY: return W32_COLOR_LIGHT_GREY;
109 case COLOR_LIGHT_RED: return W32_COLOR_LIGHT_RED;
110 case COLOR_LIGHT_GREEN: return W32_COLOR_LIGHT_GREEN;
111 case COLOR_LIGHT_BLUE: return W32_COLOR_LIGHT_BLUE;
112 case COLOR_LIGHT_CYAN: return W32_COLOR_LIGHT_CYAN;
113 case COLOR_LIGHT_MAGENTA: return W32_COLOR_LIGHT_MAGENTA;
114 case COLOR_LIGHT_YELLOW: return W32_COLOR_LIGHT_YELLOW;
115 case COLOR_WHITE: return W32_COLOR_WHITE;
116
117 case COLOR_DEFAULT_BG: return default_BG_color();
118 case COLOR_DEFAULT_FG: return default_FG_color();
119 case COLOR_DEFAULT_LIGHT: return default_FG_color() | FOREGROUND_INTENSITY;
120
121 default: return default_FG_color();
122 }
123 }
124
125 //////////////////////////////////////////////////////////////////////////////////////////
126
set_screen_color(FILE * confp,short herc_fore,short herc_back)127 int set_screen_color ( FILE* confp, short herc_fore, short herc_back )
128 {
129 HANDLE hStdErr;
130 WORD wColor;
131 int cons_fd;
132
133 if ( !confp )
134 {
135 errno = EINVAL;
136 return -1;
137 }
138
139 if ( ! _isatty( cons_fd = fileno( confp ) ) )
140 {
141 errno = EBADF;
142 return -1;
143 }
144
145 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
146 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
147
148 wColor =
149 0
150 | W32_FOREGROUND_COLOR( W32_COLOR( herc_fore ) )
151 | W32_BACKGROUND_COLOR( W32_COLOR( herc_back ) )
152 ;
153
154 VERIFY( SetConsoleTextAttribute( hStdErr, wColor ) );
155
156 return 0;
157 }
158
159 //////////////////////////////////////////////////////////////////////////////////////////
160 // screen positions are 1-based; row 1 == top line; col 1 == leftmost column
161
set_screen_pos(FILE * confp,short rowY1,short colX1)162 int set_screen_pos( FILE* confp, short rowY1, short colX1 )
163 {
164 CONSOLE_SCREEN_BUFFER_INFO csbi;
165 HANDLE hStdErr;
166 COORD ptConsole;
167 int cons_fd;
168
169 if ( !confp )
170 {
171 errno = EINVAL;
172 return -1;
173 }
174
175 if ( ! _isatty( cons_fd = fileno( confp ) ) )
176 {
177 errno = EBADF;
178 return -1;
179 }
180
181 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
182 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
183
184 VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) );
185
186 // Note: ANSI escape codes are 1-based, whereas
187 // SetConsoleCursorPosition values are 0-based...
188
189 if (0
190 || colX1 < 1 || colX1 > csbi.dwSize.X
191 || rowY1 < 1 || rowY1 > csbi.dwSize.Y
192 )
193 {
194 errno = EINVAL;
195 return -1;
196 }
197
198 ptConsole.X = colX1 - 1;
199 ptConsole.Y = rowY1 - 1;
200
201 VERIFY( SetConsoleCursorPosition( hStdErr, ptConsole ) );
202
203 return 0;
204 }
205
206 //////////////////////////////////////////////////////////////////////////////////////////
207 // (From KB article 99261)
208
clear_screen(FILE * confp)209 int clear_screen( FILE* confp )
210 {
211 CONSOLE_SCREEN_BUFFER_INFO csbi;
212 HANDLE hStdErr;
213 DWORD dwNumCells, dwCellsWritten;
214 COORD ptConsole = { 0, 0 };
215 int cons_fd;
216
217 if ( !confp )
218 {
219 errno = EINVAL;
220 return -1;
221 }
222
223 if ( ! _isatty( cons_fd = fileno( confp ) ) )
224 {
225 errno = EBADF;
226 return -1;
227 }
228
229 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
230 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
231
232 VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); dwNumCells = csbi.dwSize.X * csbi.dwSize.Y;
233 VERIFY( FillConsoleOutputCharacter( hStdErr, ' ', dwNumCells, ptConsole, &dwCellsWritten ) );
234 VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) );
235 VERIFY( FillConsoleOutputAttribute( hStdErr, csbi.wAttributes, dwNumCells, ptConsole, &dwCellsWritten ) );
236 VERIFY( SetConsoleCursorPosition ( hStdErr, ptConsole ) );
237
238 return 0;
239 }
240
241 //////////////////////////////////////////////////////////////////////////////////////////
242
erase_to_eol(FILE * confp)243 int erase_to_eol( FILE* confp )
244 {
245 CONSOLE_SCREEN_BUFFER_INFO csbi;
246 HANDLE hStdErr;
247 DWORD dwCellsWritten;
248 COORD ptConsole;
249 int cons_fd;
250
251 if ( !confp )
252 {
253 errno = EINVAL;
254 return -1;
255 }
256
257 if ( ! _isatty( cons_fd = fileno( confp ) ) )
258 {
259 errno = EBADF;
260 return -1;
261 }
262
263 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
264 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
265
266 VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); ptConsole = csbi.dwCursorPosition;
267 VERIFY( FillConsoleOutputAttribute( hStdErr, csbi.wAttributes, csbi.dwSize.X - ptConsole.X, ptConsole, &dwCellsWritten ) );
268 VERIFY( FillConsoleOutputCharacter( hStdErr, ' ', csbi.dwSize.X - ptConsole.X, ptConsole, &dwCellsWritten ) );
269
270 return 0;
271 }
272
273 //////////////////////////////////////////////////////////////////////////////////////////
274 // Handles key presses that result in TWO characters being generated...
275
translate_keystroke(char kbbuf[],int * pkblen)276 void translate_keystroke( char kbbuf[], int* pkblen )
277 {
278 BYTE ch = kbbuf[0]; // (move char to work var)
279
280 switch ( ch ) // Check if special key pressed...
281 {
282 case 0x0D: // enter key
283 kbbuf[0] = '\n'; // change to newline character
284 // fall thru to default case
285 default: // no further translation needed
286 break; // accept the keystroke as-is
287
288 // translate special key (escape sequence)...
289
290 case 0x00: // 1st char of special key press
291 case 0xE0: // 1st char of special key press
292 {
293 BYTE orig_ch, ch2;
294
295 if ( !kbhit() ) // if not two chars generated,
296 break; // then not special key press
297
298 orig_ch = ch; // save original keystroke
299 ch = '\x1B'; // change it to an escape char
300 ch2 = getch(); // get second keystroke of pair
301
302 switch ( ch2 ) // generate ANSI escape sequence
303 {
304 case 0x47: strcpy( kbbuf, KBD_HOME ); break;
305 case 0x52: strcpy( kbbuf, KBD_INSERT ); break;
306 case 0x53: strcpy( kbbuf, KBD_DELETE ); break;
307 case 0x4F: strcpy( kbbuf, KBD_END ); break;
308 case 0x49: strcpy( kbbuf, KBD_PAGE_UP ); break;
309 case 0x51: strcpy( kbbuf, KBD_PAGE_DOWN ); break;
310
311 case 0x48: strcpy( kbbuf, KBD_UP_ARROW ); break;
312 case 0x50: strcpy( kbbuf, KBD_DOWN_ARROW ); break;
313 case 0x4D: strcpy( kbbuf, KBD_RIGHT_ARROW ); break;
314 case 0x4B: strcpy( kbbuf, KBD_LEFT_ARROW ); break;
315
316 case 0x77: strcpy( kbbuf, KBD_CTRL_HOME ); break;
317 case 0x75: strcpy( kbbuf, KBD_CTRL_END ); break;
318
319 case 0x8D: strcpy( kbbuf, KBD_CTRL_UP_ARROW ); break;
320 case 0x91: strcpy( kbbuf, KBD_CTRL_DOWN_ARROW ); break;
321
322 case 0x98: strcpy( kbbuf, KBD_ALT_UP_ARROW ); break;
323 case 0xA0: strcpy( kbbuf, KBD_ALT_DOWN_ARROW ); break;
324 case 0x9D: strcpy( kbbuf, KBD_ALT_RIGHT_ARROW ); break;
325 case 0x9B: strcpy( kbbuf, KBD_ALT_LEFT_ARROW ); break;
326
327 default:
328 {
329 #if 0
330 kbbuf[0] = '\x1B';
331 kbbuf[1] = ch2;
332 kbbuf[2] = 0;
333 #else
334 /* EAT IT */
335 kbbuf[0] = 0;
336 kbbuf[1] = 0;
337 kbbuf[2] = 0;
338 #endif
339 break;
340
341 } // end default
342
343 } // end switch( ch2 )
344
345 *pkblen = strlen( kbbuf ); // inform caller #of chars
346 break;
347
348 } // end case: 0x00, 0xE0
349
350 } // end switch( ch )
351 }
352
353 //////////////////////////////////////////////////////////////////////////////////////////
354
console_beep(FILE * confp)355 int console_beep( FILE* confp )
356 {
357 int cons_fd;
358
359 if ( !confp )
360 {
361 errno = EINVAL;
362 return -1;
363 }
364
365 if ( ! _isatty( cons_fd = fileno( confp ) ) )
366 {
367 errno = EBADF;
368 return -1;
369 }
370
371 MessageBeep(-1);
372
373 return 0;
374 }
375
376 //////////////////////////////////////////////////////////////////////////////////////////
377
378 #ifdef OPTION_EXTCURS
get_cursor_pos(int keybrd_fd,FILE * confp,short * row,short * col)379 int get_cursor_pos( int keybrd_fd, FILE* confp, short* row, short* col )
380 {
381 CONSOLE_SCREEN_BUFFER_INFO csbi;
382 HANDLE hStdErr;
383 int cons_fd;
384
385 UNREFERENCED( keybrd_fd );
386
387 if ( !confp || !row || !col )
388 {
389 errno = EINVAL;
390 return -1;
391 }
392
393 if ( ! _isatty( cons_fd = fileno( confp ) ) )
394 {
395 errno = EBADF;
396 return -1;
397 }
398
399 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
400 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
401
402 if ( !GetConsoleScreenBufferInfo( hStdErr, &csbi ) )
403 {
404 errno = EIO;
405 return -1;
406 }
407
408 *row = 1 + csbi.dwCursorPosition.Y;
409 *col = 1 + csbi.dwCursorPosition.X;
410
411 return 0;
412 }
413 #endif // OPTION_EXTCURS
414
415 //////////////////////////////////////////////////////////////////////////////////////////
416
get_console_dim(FILE * confp,int * rows,int * cols)417 int get_console_dim( FILE* confp, int* rows, int* cols )
418 {
419 CONSOLE_SCREEN_BUFFER_INFO csbi;
420 HANDLE hStdErr;
421 int cons_fd;
422
423 if ( !confp || !rows || !cols )
424 {
425 errno = EINVAL;
426 return -1;
427 }
428
429 *rows = *cols = 0;
430
431 if ( ! _isatty( cons_fd = fileno( confp ) ) )
432 {
433 errno = EBADF;
434 return -1;
435 }
436
437 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
438 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
439
440 if ( !GetConsoleScreenBufferInfo( hStdErr, &csbi ) )
441 {
442 errno = EIO;
443 return -1;
444 }
445
446 *rows = 1 + csbi.srWindow.Bottom - csbi.srWindow.Top;
447 *cols = 1 + csbi.srWindow.Right - csbi.srWindow.Left;
448 return 0;
449 }
450
451 //////////////////////////////////////////////////////////////////////////////////////////
452
set_console_cursor_shape(FILE * confp,int ins)453 int set_console_cursor_shape( FILE* confp, int ins )
454 {
455 CONSOLE_CURSOR_INFO ci;
456 HANDLE hStdErr;
457 int cons_fd;
458
459 if ( !confp )
460 {
461 errno = EINVAL;
462 return -1;
463 }
464
465 if ( ! _isatty( cons_fd = fileno( confp ) ) )
466 {
467 errno = EBADF;
468 return -1;
469 }
470
471 hStdErr = (HANDLE) _get_osfhandle( cons_fd );
472 ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr );
473
474 ci.bVisible = TRUE;
475 ci.dwSize = ins ? 20 : 100; // (note: values are percent of cell height)
476
477 if ( !SetConsoleCursorInfo( hStdErr, &ci ) )
478 {
479 errno = EIO;
480 return -1;
481 }
482
483 return 0;
484 }
485
486 //////////////////////////////////////////////////////////////////////////////////////////
487 // From KB article 124103: "How To Obtain a Console Window Handle (HWND)"
488 // http://support.microsoft.com/?kbid=124103
489
490 #define MAX_WINDOW_TITLE_LEN (256) // (purely arbitrary)
491
492 static TCHAR g_szOriginalTitle[ MAX_WINDOW_TITLE_LEN ] = {0};
493
w32_set_console_title(char * pszTitle)494 int w32_set_console_title( char* pszTitle )
495 {
496 TCHAR szNewTitleBuff [ MAX_WINDOW_TITLE_LEN ];
497 LPCTSTR pszNewTitle = NULL;
498
499 if (!g_szOriginalTitle[0])
500 VERIFY(GetConsoleTitle( g_szOriginalTitle, MAX_WINDOW_TITLE_LEN ));
501
502 if (pszTitle)
503 {
504 _sntprintf( szNewTitleBuff, MAX_WINDOW_TITLE_LEN-1, _T("%hs"), pszTitle );
505 szNewTitleBuff[MAX_WINDOW_TITLE_LEN-1]=0;
506 pszNewTitle = szNewTitleBuff;
507 }
508 else
509 pszNewTitle = g_szOriginalTitle;
510
511 if (!SetConsoleTitle( pszNewTitle ))
512 {
513 errno = GetLastError();
514 return -1;
515 }
516 return 0;
517 }
518
519 //////////////////////////////////////////////////////////////////////////////////////////
520 //////////////////////////////////////////////////////////////////////////////////////////
521 //////////////////////////////////////////////////////////////////////////////////////////
522
523 #else // !defined( WIN32 )
524
525 #ifdef HAVE_TERMIOS_H
526 static struct termios saved_kbattr; // (saved value so we can later restore it)
527 #endif
528
529 // 'save_and_set' = 1 --> just what it says; 0 --> restore from saved value.
530
set_or_reset_console_mode(int keybrd_fd,short save_and_set)531 int set_or_reset_console_mode( int keybrd_fd, short save_and_set )
532 {
533 #ifdef HAVE_TERMIOS_H
534 struct termios kbattr;
535
536 if ( save_and_set )
537 {
538 // Put the terminal into cbreak mode
539
540 tcgetattr( keybrd_fd, &saved_kbattr ); // (save for later restore)
541
542 kbattr = saved_kbattr; // (make copy)
543
544 kbattr.c_lflag &= ~(ECHO | ICANON); // (set desired values...)
545 kbattr.c_cc[VMIN] = 0;
546 kbattr.c_cc[VTIME] = 0;
547
548 tcsetattr( keybrd_fd, TCSANOW, &kbattr );
549 }
550 else
551 {
552 // Restore the terminal mode
553
554 tcsetattr( STDIN_FILENO, TCSANOW, &saved_kbattr ); // (restore prev value)
555 }
556
557 #else
558
559 UNREFERENCED( keybrd_fd );
560 UNREFERENCED( save_and_set );
561
562 #endif
563
564 return 0;
565 }
566
567 //////////////////////////////////////////////////////////////////////////////////////////
568 // screen positions are 1-based; row 1 == top line; col 1 == leftmost column
569
set_screen_pos(FILE * confp,short rowY1,short colX1)570 int set_screen_pos( FILE* confp, short rowY1, short colX1 )
571 {
572 #define ANSI_POSITION_CURSOR "\x1B[%d;%dH"
573
574 return ( fprintf( confp, ANSI_POSITION_CURSOR, rowY1, colX1 ) ? 0 : -1 );
575 }
576
577 //////////////////////////////////////////////////////////////////////////////////////////
578
erase_to_eol(FILE * confp)579 int erase_to_eol( FILE* confp )
580 {
581 #define ANSI_ERASE_EOL "\x1B[K"
582
583 return ( fprintf( confp, ANSI_ERASE_EOL ) ? 0 : -1 );
584 }
585
586 //////////////////////////////////////////////////////////////////////////////////////////
587
clear_screen(FILE * confp)588 int clear_screen( FILE* confp )
589 {
590 #define ANSI_ERASE_SCREEN "\x1B[2J"
591
592 return ( fprintf( confp, ANSI_ERASE_SCREEN ) ? 0 : -1 );
593 }
594
595 //////////////////////////////////////////////////////////////////////////////////////////
596 /*
597 From: (http://www.vtt.fi/tte/EuroBridge/Xew/iso6429.html)
598
599 CSI (Control Sequence Introducer) = "\033[" or "\233"
600
601 SGR (Select Graphic Rendition) = CSI Ps1;Ps2;... m
602
603 SGR (Select Graphic Rendition):
604
605 CSI Ps ... 0x6d
606
607 (Note: 0x6d = ASCII 'm')
608
609 SGR is used to establish one or more graphic rendition aspects for
610 subsequent text. The established aspects remain in effect until the
611 next occurrence of SGR in the data stream, depending on the setting
612 of the GRAPHIC RENDITION COMBINATION MODE (GRCM).
613
614 The implementation assumes the GRCM = CUMULATIVE (that is, each aspect
615 will be in effect until explicitly cancelled by another SGR).
616
617 --------------------------------------------------------------------------
618 Ps Description
619 --------------------------------------------------------------------------
620 0 default rendition; cancel all preceding occurrences of SGR;
621 invoke primary font.
622 1 bold or increased intensity
623
624 2 faint <------<<< Fish: non-standard, but apparently anyway
625 (based on other documents I've seen)
626
627 3 italicized
628 4 underlined
629 7 negative image
630 9 crossed out
631 10 primary (default) font
632 11-19 first to ninth alternative fonts (see also fonts)
633 21 doubly underlined
634 22 normal intensity (neither bold nor faint)
635 23 not italicized
636 24 not underlined (neither singly or doubly)
637 27 positive image
638 29 not crossed out
639 30-37 foreground color of the text; 30=black, 31=red, 32=green,
640 33=yellow, 34=blue, 35=magenta, 36=cyan, 37=white.
641 39 default foreground text color (foreground color of the widget)
642 40-47 background color of the text; 40=black, 41=red, 42=green,
643 43=yellow, 44=blue, 45=magenta, 46=cyan, 47=white.
644 49 default background text color (background color of the widget)
645 51 framed (see FrameRendition)
646 53 overlined [not implemented yet]
647 54 not framed, not encircled
648 55 not overlined [not implemented yet]
649 --------------------------------------------------------------------------
650
651
652 "\033[m" Reset
653 "\033[0m" Reset
654 "\033[1m" Bold
655
656 "\033[2m" Faint <------<<< Fish: non-standard, but apparently anyway
657 (based on other documents I've seen)
658
659 "\033[3m" Italic
660 "\033[4m" Underline
661 "\033[7m" Inverse
662 "\033[9m" Crossed out
663 "\033[10m" primary font
664 "\033[11m" 1st alternate font
665 "\033[12m" 2nd alternate font
666 "\033[13m" 3rd alternate font
667 "\033[14m" 4th alternate font
668 "\033[15m" 5th alternate font
669 "\033[16m" 6th alternate font
670 "\033[17m" 7th alternate font
671 "\033[18m" 8th alternate font
672 "\033[19m" 9th alternate font
673 "\033[21m" Double underline
674 "\033[22m" Bold off
675 "\033[23m" Italic off
676 "\033[24m" Underline off (double or single)
677 "\033[27m" Inverse off
678 "\033[29m" Crossed out off
679
680 "\033[30m" Black foreground
681 "\033[31m" Red foreground
682 "\033[32m" Green foreground
683 "\033[33m" Yellow foreground
684 "\033[34m" Blue foreground
685 "\033[35m" Magenta foreground
686 "\033[36m" Cyan foreground
687 "\033[37m" White foreground
688 "\033[39m" Default foreground
689
690 "\033[40m" Black background
691 "\033[41m" Red background
692 "\033[42m" Green background
693 "\033[43m" Yellow background
694 "\033[44m" Blue background
695 "\033[45m" Magenta background
696 "\033[46m" Cyan background
697 "\033[47m" White background
698 "\033[49m" Default background
699
700 "\033[51m" Framed on
701 "\033[54m" Framed off
702 */
703 //////////////////////////////////////////////////////////////////////////////////////////
704 // Translate Herc color to ANSI/ISO-6429 (ECMA-48) color...
705 // High-order byte is attribute (0=normal, 1=bold), low-order byte is color.
706
707 #define ISO_COLOR_BLACK ( 30 )
708 #define ISO_COLOR_RED ( 31 )
709 #define ISO_COLOR_GREEN ( 32 )
710 #define ISO_COLOR_YELLOW ( 33 )
711 #define ISO_COLOR_BLUE ( 34 )
712 #define ISO_COLOR_MAGENTA ( 35 )
713 #define ISO_COLOR_CYAN ( 36 )
714 #define ISO_COLOR_WHITE ( 37 )
715 #define ISO_COLOR_DEFAULT ( 39 )
716
717 #define ISO_NORMAL( iso_color ) ( ( 0x0000 ) | ( (uint16_t)( iso_color ) ) )
718 #define ISO_BRIGHT( iso_color ) ( ( 0x0100 ) | ( (uint16_t)( iso_color ) ) )
719
720 #define ISO_IS_ISO_BRIGHT( iso_color ) ( ( ( iso_color ) >> 8 ) & 0x01 )
721
722 // PROGRAMMING NOTE: the '2' (faint/dim) and '22' (bold-off)
723 // attribute codes are UNRELIABLE. They are apparently rarely
724 // implemented properly on many platforms (Cygwin included).
725 // Thus we prefer to use the more reliable (but programmatically
726 // bothersome) '0' (reset) attribute instead [whenever we wish
727 // to paint a 'dim/faint' (non-bold) color]. As a result however,
728 // we need to be careful to paint the foregoround/background
729 // colors in the proper sequence/order and in the proper manner.
730 // See the below 'set_screen_color' function for details. (Fish)
731
732 //#define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 22
733 //#define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 2
734 #define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 0
735
736 #define ISO_FOREGROUND_COLOR( iso_color ) ( ( ( iso_color ) & 0x00FF ) )
737 #define ISO_BACKGROUND_COLOR( iso_color ) ( ( ( iso_color ) & 0x00FF ) + 10 )
738
ISO_COLOR(short herc_color)739 static uint16_t ISO_COLOR( short herc_color )
740 {
741 switch ( herc_color )
742 {
743 case COLOR_BLACK: return ISO_NORMAL( ISO_COLOR_BLACK );
744 case COLOR_RED: return ISO_NORMAL( ISO_COLOR_RED );
745 case COLOR_GREEN: return ISO_NORMAL( ISO_COLOR_GREEN );
746 case COLOR_BLUE: return ISO_NORMAL( ISO_COLOR_BLUE );
747 case COLOR_CYAN: return ISO_NORMAL( ISO_COLOR_CYAN );
748 case COLOR_MAGENTA: return ISO_NORMAL( ISO_COLOR_MAGENTA );
749 case COLOR_YELLOW: return ISO_NORMAL( ISO_COLOR_YELLOW );
750 case COLOR_DARK_GREY: return ISO_BRIGHT( ISO_COLOR_BLACK );
751
752 case COLOR_LIGHT_GREY: return ISO_NORMAL( ISO_COLOR_WHITE );
753 case COLOR_LIGHT_RED: return ISO_BRIGHT( ISO_COLOR_RED );
754 case COLOR_LIGHT_GREEN: return ISO_BRIGHT( ISO_COLOR_GREEN );
755 case COLOR_LIGHT_BLUE: return ISO_BRIGHT( ISO_COLOR_BLUE );
756 case COLOR_LIGHT_CYAN: return ISO_BRIGHT( ISO_COLOR_CYAN );
757 case COLOR_LIGHT_MAGENTA: return ISO_BRIGHT( ISO_COLOR_MAGENTA );
758 case COLOR_LIGHT_YELLOW: return ISO_BRIGHT( ISO_COLOR_YELLOW );
759 case COLOR_WHITE: return ISO_BRIGHT( ISO_COLOR_WHITE );
760
761 case COLOR_DEFAULT_FG: return ISO_NORMAL( ISO_COLOR_DEFAULT );
762 case COLOR_DEFAULT_BG: return ISO_NORMAL( ISO_COLOR_DEFAULT );
763 case COLOR_DEFAULT_LIGHT: return ISO_BRIGHT( ISO_COLOR_DEFAULT );
764
765 default: return ISO_NORMAL( ISO_COLOR_DEFAULT );
766 }
767 }
768
769 //////////////////////////////////////////////////////////////////////////////////////////
770 // Translate Herc color to ANSI/ISO-6429 (ECMA-48) SGR terminal escape sequence...
771
set_screen_color(FILE * confp,short herc_fore,short herc_back)772 int set_screen_color( FILE* confp, short herc_fore, short herc_back )
773 {
774 uint16_t iso_fore, iso_back;
775 uint16_t iso_bold_color, iso_dim_color;
776 int rc;
777
778 // Translate Herc color to ANSI (ISO) color...
779
780 iso_fore = ISO_COLOR( herc_fore );
781 iso_back = ISO_COLOR( herc_back );
782
783 // PROGRAMMING NOTE: Because the only means we have to RELIABLY
784 // set non-bold (faint/dim) color attributes across ALL platforms
785 // is to use the '0' (reset) escape code (which of course has the
786 // unfortunate(?) side-effect of resetting BOTH the background
787 // AND foreground colors to dim/faint instead of just one or the
788 // other), we need to be careful to always set the dim (NON-bold)
789 // color attribute FIRST (which will of course reset both the fore-
790 // ground AND the backgound colors to non-bold/faint/dim as well),
791 // and then to, AFTERWARDS, set the BOLD color attribute. This is
792 // the ONLY way I've been able to discover (empirically via trial
793 // and error) how to RELIABLY set bold/faint foreground/background
794 // color attributes across all(?) supported platforms. (Fish)
795
796 if ( ISO_IS_ISO_BRIGHT(iso_fore) == ISO_IS_ISO_BRIGHT(iso_back) )
797 {
798 // BOTH the foreground color AND the background colors
799 // are either BOTH bold or BOTH dim/faint (normal)...
800
801 rc = fprintf
802 (
803 confp,
804
805 // Set the bold/dim attribute FIRST and then
806 // BOTH foreground/background colors afterwards...
807
808 "\x1B[%d;%d;%dm"
809
810 ,ISO_NORMAL_OR_BRIGHT( iso_back )
811 ,ISO_BACKGROUND_COLOR( iso_back )
812 ,ISO_FOREGROUND_COLOR( iso_fore )
813 );
814 }
815 else // ( ISO_IS_ISO_BRIGHT(iso_fore) != ISO_IS_ISO_BRIGHT(iso_back) )
816 {
817 // ONE of either the foreground OR background colors
818 // is bold, but the OTHER one is dim/faint (normal)...
819
820 if ( ISO_IS_ISO_BRIGHT(iso_fore) )
821 {
822 // The foregound color is the bright/bold one...
823
824 iso_bold_color = ISO_FOREGROUND_COLOR( iso_fore );
825 iso_dim_color = ISO_BACKGROUND_COLOR( iso_back );
826 }
827 else // ( !ISO_IS_ISO_BRIGHT(iso_fore) )
828 {
829 // The background color is the bright/bold one...
830
831 iso_bold_color = ISO_BACKGROUND_COLOR( iso_back );
832 iso_dim_color = ISO_FOREGROUND_COLOR( iso_fore );
833 }
834
835 // Set whichever is the DIM color attribute FIRST
836 // and then AFTERWARDS whichever one is the BOLD...
837
838 rc = fprintf
839 (
840 confp,
841
842 "\x1B[0;%d;1;%dm" // (reset, dim-color, bold, bold-color)
843
844 ,iso_dim_color
845 ,iso_bold_color
846 );
847 }
848
849 return rc < 0 ? -1 : 0;
850 }
851
852 //////////////////////////////////////////////////////////////////////////////////////////
853
translate_keystroke(char kbbuf[],int * pkblen)854 void translate_keystroke( char kbbuf[], int* pkblen )
855 {
856 UNREFERENCED( kbbuf );
857 UNREFERENCED( pkblen );
858 return;
859 }
860
861 //////////////////////////////////////////////////////////////////////////////////////////
862
console_beep(FILE * confp)863 int console_beep( FILE* confp )
864 {
865 return fprintf( confp, "\a" ) < 0 ? -1 : 0;
866 }
867
868 //////////////////////////////////////////////////////////////////////////////////////////
869
get_console_dim(FILE * confp,int * rows,int * cols)870 int get_console_dim( FILE* confp, int* rows, int* cols )
871 {
872 char* env;
873 #if defined(TIOCGWINSZ)
874 struct winsize winsize;
875 #else
876 UNREFERENCED( confp );
877 #endif
878
879 if ( !rows || !cols )
880 {
881 errno = EINVAL;
882 return -1;
883 }
884
885 #if defined(TIOCGWINSZ)
886 if (ioctl(fileno(confp), TIOCGWINSZ, &winsize) >= 0)
887 {
888 *rows = winsize.ws_row;
889 *cols = winsize.ws_col;
890 }
891 else
892 #endif
893 {
894 if (!(env = getenv( "LINES" ))) *rows = 24;
895 else *rows = atoi(env);
896 if (!(env = getenv( "COLUMNS" ))) *cols = 80;
897 else *cols = atoi(env);
898 }
899
900 if (!*rows || !*cols)
901 {
902 errno = EIO;
903 return -1;
904 }
905
906 return 0;
907 }
908
909 //////////////////////////////////////////////////////////////////////////////////////////
910
911 #ifdef OPTION_EXTCURS
get_cursor_pos(int keybrd_fd,FILE * confp,short * row,short * col)912 int get_cursor_pos( int keybrd_fd, FILE* confp, short* row, short* col )
913 {
914 struct timeval tv; /* Select timeout structure */
915 fd_set readset; /* Select file descriptors */
916 char kbbuf[16]; /* Keyboard i/p buffer */
917 char* semi; /* Index of semicolon */
918 int kblen; /* Number of chars in kbbuf */
919 int maxfd; /* Highest file descriptor */
920 int rc; /* Return code */
921 char c; /* Work for scanf */
922
923 /* Request the CPR (Cursor Position Report) */
924 if ( fprintf( confp, KBD_ASK_CURSOR_POS ) < 0 )
925 return -1;
926
927 /* Read the CPR from the keyboard i/p buffer */
928 while (1)
929 {
930 FD_ZERO (&readset);
931 FD_SET (keybrd_fd, &readset);
932 maxfd = keybrd_fd;
933 tv.tv_sec = 0;
934 tv.tv_usec = 50 * 1000; // (PLENTY long enough!)
935
936 /* Wait for CPR to arrive in our i/p buffer */
937 rc = select (maxfd + 1, &readset, NULL, NULL, &tv);
938
939 if (rc < 0 )
940 {
941 if (errno == EINTR) continue;
942 errno = EIO;
943 break;
944 }
945
946 /* If keyboard input has arrived then process it */
947 if (!FD_ISSET(keybrd_fd, &readset))
948 continue;
949
950 /* Read character(s) from the keyboard */
951 kblen = read (keybrd_fd, kbbuf, sizeof(kbbuf)-1);
952
953 if (kblen < 0)
954 {
955 errno = EIO;
956 break;
957 }
958
959 kbbuf[kblen] = 0;
960
961 // The returned CPR is the string "\x1B[n;mR"
962 // where n = decimal row, m = decimal column.
963
964 // Note: we expect the entire the CPR to have
965 // been read on our first i/o (i.e. for it to
966 // have arrived all at once in one piece) and
967 // not piecemeal requiring several i/o's...
968 if (0
969 || kblen < 6
970 || kbbuf[ 0 ] != '\x1B'
971 || kbbuf[ 1 ] != '['
972 || kbbuf[kblen-1] != 'R'
973 || (semi = memchr( kbbuf, ';', kblen )) == NULL
974 || (semi - kbbuf) < 3
975 || sscanf( &kbbuf[2], "%hu%c", row, &c ) != 2 || c != ';'
976 || sscanf( semi+1, "%hu%c", col, &c ) != 2 || c != 'R'
977 )
978 {
979 errno = EIO;
980 rc = -1;
981 break;
982 }
983
984 /* Success! */
985 rc = 0;
986 break
987 }
988
989 return rc;
990 }
991 #endif // OPTION_EXTCURS
992
993 //////////////////////////////////////////////////////////////////////////////////////////
994 /*
995 From: (http://groups-beta.google.com/group/comp.protocols.kermit.misc/msg/1cc3ec6f0bfc0084)
996
997 VGA-softcursor.txt, from the 2.2 kernel
998
999 Software cursor for VGA by Pavel Machek <p...@atrey.karlin.mff.cuni.cz>
1000 ======================= and Martin Mares <m...@atrey.karlin.mff.cuni.cz>
1001
1002 Linux now has some ability to manipulate cursor appearance. Normally, you
1003 can set the size of hardware cursor (and also work around some ugly bugs in
1004 those miserable Trident cards--see #define TRIDENT_GLITCH in drivers/video/
1005 vgacon.c). You can now play a few new tricks: you can make your cursor look
1006 like a non-blinking red block, make it inverse background of the character it's
1007 over or to highlight that character and still choose whether the original
1008 hardware cursor should remain visible or not. There may be other things I have
1009 never thought of.
1010
1011 The cursor appearance is controlled by a "<ESC>[?1;2;3c" escape sequence
1012 where 1, 2 and 3 are parameters described below. If you omit any of them,
1013 they will default to zeroes.
1014
1015 Parameter 1 specifies cursor size (0=default, 1=invisible, 2=underline, ...,
1016 8=full block) + 16 if you want the software cursor to be applied + 32 if you
1017 want to always change the background color + 64 if you dislike having the
1018 background the same as the foreground. Highlights are ignored for the last two
1019 flags.
1020
1021 The second parameter selects character attribute bits you want to change
1022 (by simply XORing them with the value of this parameter). On standard VGA,
1023 the high four bits specify background and the low four the foreground. In both
1024 groups, low three bits set color (as in normal color codes used by the console)
1025 and the most significant one turns on highlight (or sometimes blinking--it
1026 depends on the configuration of your VGA).
1027
1028 The third parameter consists of character attribute bits you want to set.
1029 Bit setting takes place before bit toggling, so you can simply clear a bit by
1030 including it in both the set mask and the toggle mask.
1031
1032 Examples:
1033 =========
1034
1035 To get normal blinking underline, use: echo -e '\033[?2c'
1036 To get blinking block, use: echo -e '\033[?6c'
1037 To get red non-blinking block, use: echo -e '\033[?17;0;64c'
1038 */
1039
1040 int set_console_cursor_shape( FILE* confp, int ins )
1041 {
1042 #if SET_CONSOLE_CURSOR_SHAPE_METHOD == CURSOR_SHAPE_NOT_SUPPORTED
1043
1044 UNREFERENCED( confp );
1045 UNREFERENCED( ins );
1046 return 0;
1047
1048 #elif SET_CONSOLE_CURSOR_SHAPE_METHOD == CURSOR_SHAPE_VIA_SPECIAL_LINUX_ESCAPE
1049
1050 #define LINUX_UNDER_BLINK_CURSOR "\x1B[?2c"
1051 #define LINUX_BLINK_BLOCK_CURSOR "\x1B[?6c"
1052
1053 return fprintf( confp, ins ? LINUX_UNDER_BLINK_CURSOR : LINUX_BLINK_BLOCK_CURSOR );
1054
1055 #else
1056 #error Invalid #defined SET_CONSOLE_CURSOR_SHAPE_METHOD value
1057 return -1;
1058 #endif
1059 }
1060
1061 //////////////////////////////////////////////////////////////////////////////////////////
1062
1063 #endif // defined( WIN32 )
1064
1065 //////////////////////////////////////////////////////////////////////////////////////////
1066