]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_console.cc
* cygwin.din (dup3): Export.
[newlib-cygwin.git] / winsup / cygwin / fhandler_console.cc
1 /* fhandler_console.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2008, 2009, 2010 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <wchar.h>
17 #include <wingdi.h>
18 #include <winuser.h>
19 #include <winnls.h>
20 #include <ctype.h>
21 #include <sys/cygwin.h>
22 #include <cygwin/kd.h>
23 #include "cygerrno.h"
24 #include "security.h"
25 #include "path.h"
26 #include "fhandler.h"
27 #include "dtable.h"
28 #include "cygheap.h"
29 #include "sigproc.h"
30 #include "pinfo.h"
31 #include "shared_info.h"
32 #include "cygtls.h"
33 #include "tls_pbuf.h"
34 #include "registry.h"
35
36 /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer
37 is allocated using tmp_pathbuf!!! */
38 #define CONVERT_LIMIT NT_MAX_PATH
39
40 /*
41 * Scroll the screen context.
42 * x1, y1 - ul corner
43 * x2, y2 - dr corner
44 * xn, yn - new ul corner
45 * Negative values represents current screen dimensions
46 */
47
48 #define srTop (dev_state->info.winTop + dev_state->scroll_region.Top)
49 #define srBottom ((dev_state->scroll_region.Bottom < 0) ? dev_state->info.winBottom : dev_state->info.winTop + dev_state->scroll_region.Bottom)
50
51 #define use_tty ISSTATE (myself, PID_USETTY)
52
53 const char *get_nonascii_key (INPUT_RECORD&, char *);
54
55 const unsigned fhandler_console::MAX_WRITE_CHARS = 16384;
56
57 static console_state NO_COPY *shared_console_info;
58
59 dev_console NO_COPY *fhandler_console::dev_state;
60
61 static void
62 beep ()
63 {
64 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS, "AppEvents", "Schemes", "Apps",
65 ".Default", ".Default", ".Current", NULL);
66 if (r.created ())
67 {
68 char *buf = NULL;
69 UINT len = GetWindowsDirectory (buf, 0);
70 buf = (char *) alloca (len += sizeof ("\\media\\ding.wav"));
71 UINT res = GetWindowsDirectory (buf, len);
72 if (res && res <= len)
73 r.set_string ("", strcat (buf, "\\media\\ding.wav"));
74 }
75 MessageBeep (MB_OK);
76 }
77
78 /* Allocate and initialize the shared record for the current console.
79 Returns a pointer to shared_console_info. */
80 tty_min *
81 fhandler_console::get_tty_stuff (int flags = 0)
82 {
83 if (dev_state)
84 return &shared_console_info->tty_min_state;
85
86 shared_locations sh_shared_console = SH_SHARED_CONSOLE;
87 shared_console_info =
88 (console_state *) open_shared (NULL, 0, cygheap->console_h,
89 sizeof (*shared_console_info),
90 sh_shared_console);
91 dev_state = &shared_console_info->dev_state;
92
93 ProtectHandleINH (cygheap->console_h);
94 if (!shared_console_info->tty_min_state.ntty)
95 {
96 shared_console_info->tty_min_state.setntty (TTY_CONSOLE);
97 shared_console_info->tty_min_state.setsid (myself->sid);
98 myself->set_ctty (&shared_console_info->tty_min_state, flags, NULL);
99
100 dev_state->scroll_region.Bottom = -1;
101 dev_state->dwLastCursorPosition.X = -1;
102 dev_state->dwLastCursorPosition.Y = -1;
103 dev_state->dwLastMousePosition.X = -1;
104 dev_state->dwLastMousePosition.Y = -1;
105 dev_state->dwLastButtonState = 0; /* none pressed */
106 dev_state->last_button_code = 3; /* released */
107 dev_state->underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
108 dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
109 dev_state->meta_mask = LEFT_ALT_PRESSED;
110 /* Set the mask that determines if an input keystroke is modified by
111 META. We set this based on the keyboard layout language loaded
112 for the current thread. The left <ALT> key always generates
113 META, but the right <ALT> key only generates META if we are using
114 an English keyboard because many "international" keyboards
115 replace common shell symbols ('[', '{', etc.) with accented
116 language-specific characters (umlaut, accent grave, etc.). On
117 these keyboards right <ALT> (called AltGr) is used to produce the
118 shell symbols and should not be interpreted as META. */
119 if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH)
120 dev_state->meta_mask |= RIGHT_ALT_PRESSED;
121 dev_state->set_default_attr ();
122 shared_console_info->tty_min_state.sethwnd ((HWND) INVALID_HANDLE_VALUE);
123 }
124
125 return &shared_console_info->tty_min_state;
126 }
127
128 void
129 set_console_ctty ()
130 {
131 fhandler_console::get_tty_stuff ();
132 }
133
134 /* Return the tty structure associated with a given tty number. If the
135 tty number is < 0, just return a dummy record. */
136 tty_min *
137 tty_list::get_tty (int n)
138 {
139 static tty_min nada;
140 if (n == TTY_CONSOLE)
141 return fhandler_console::get_tty_stuff ();
142 else if (n >= 0)
143 return &cygwin_shared->tty.ttys[n];
144 else
145 return &nada;
146 }
147
148 inline DWORD
149 dev_console::con_to_str (char *d, int dlen, WCHAR w)
150 {
151 return sys_cp_wcstombs (cygheap->locale.wctomb, cygheap->locale.charset,
152 d, dlen, &w, 1);
153 }
154
155 inline UINT
156 dev_console::get_console_cp ()
157 {
158 /* The alternate charset is always 437, just as in the Linux console. */
159 return alternate_charset_active ? 437 : 0;
160 }
161
162 inline DWORD
163 dev_console::str_to_con (mbtowc_p f_mbtowc, const char *charset,
164 PWCHAR d, const char *s, DWORD sz)
165 {
166 return sys_cp_mbstowcs (f_mbtowc, charset, d, CONVERT_LIMIT, s, sz);
167 }
168
169 bool
170 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode)
171 {
172 bool old_mode = dev_state->raw_win32_keyboard_mode;
173 dev_state->raw_win32_keyboard_mode = new_mode;
174 syscall_printf ("raw keyboard mode %sabled", dev_state->raw_win32_keyboard_mode ? "en" : "dis");
175 return old_mode;
176 };
177
178 void
179 fhandler_console::set_cursor_maybe ()
180 {
181 CONSOLE_SCREEN_BUFFER_INFO now;
182
183 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
184 return;
185
186 if (dev_state->dwLastCursorPosition.X != now.dwCursorPosition.X ||
187 dev_state->dwLastCursorPosition.Y != now.dwCursorPosition.Y)
188 {
189 SetConsoleCursorPosition (get_output_handle (), now.dwCursorPosition);
190 dev_state->dwLastCursorPosition = now.dwCursorPosition;
191 }
192 }
193
194 void
195 fhandler_console::send_winch_maybe ()
196 {
197 SHORT y = dev_state->info.dwWinSize.Y;
198 SHORT x = dev_state->info.dwWinSize.X;
199 dev_state->fillin_info (get_output_handle ());
200
201 if (y != dev_state->info.dwWinSize.Y || x != dev_state->info.dwWinSize.X)
202 {
203 extern fhandler_tty_master *tty_master;
204 dev_state->scroll_region.Top = 0;
205 dev_state->scroll_region.Bottom = -1;
206 if (tty_master)
207 tty_master->set_winsize (true);
208 else
209 tc->kill_pgrp (SIGWINCH);
210 }
211 }
212
213 /* Check whether a mouse event is to be reported as an escape sequence */
214 bool
215 fhandler_console::mouse_aware (MOUSE_EVENT_RECORD& mouse_event)
216 {
217 if (! dev_state->use_mouse)
218 return 0;
219
220 /* Adjust mouse position by window scroll buffer offset
221 and remember adjusted position in state for use by read() */
222 CONSOLE_SCREEN_BUFFER_INFO now;
223 if (GetConsoleScreenBufferInfo (get_output_handle (), &now))
224 {
225 dev_state->dwMousePosition.X = mouse_event.dwMousePosition.X - now.srWindow.Left;
226 dev_state->dwMousePosition.Y = mouse_event.dwMousePosition.Y - now.srWindow.Top;
227 }
228 else
229 {
230 /* Cannot adjust position by window scroll buffer offset */
231 return 0;
232 }
233
234 /* Check whether adjusted mouse position can be reported */
235 if (dev_state->dwMousePosition.X > 0xFF - ' ' - 1
236 || dev_state->dwMousePosition.Y > 0xFF - ' ' - 1)
237 {
238 /* Mouse position out of reporting range */
239 return 0;
240 }
241
242 return ((mouse_event.dwEventFlags == 0 || mouse_event.dwEventFlags == DOUBLE_CLICK)
243 && mouse_event.dwButtonState != dev_state->dwLastButtonState)
244 || mouse_event.dwEventFlags == MOUSE_WHEELED
245 || (mouse_event.dwEventFlags == MOUSE_MOVED
246 && (dev_state->dwMousePosition.X != dev_state->dwLastMousePosition.X
247 || dev_state->dwMousePosition.Y != dev_state->dwLastMousePosition.Y)
248 && ((dev_state->use_mouse >= 2 && mouse_event.dwButtonState)
249 || dev_state->use_mouse >= 3));
250 }
251
252 void __stdcall
253 fhandler_console::read (void *pv, size_t& buflen)
254 {
255 HANDLE h = get_io_handle ();
256
257 #define buf ((char *) pv)
258
259 int ch;
260 set_input_state ();
261
262 int copied_chars = get_readahead_into_buffer (buf, buflen);
263
264 if (copied_chars)
265 {
266 buflen = copied_chars;
267 return;
268 }
269
270 HANDLE w4[2];
271 DWORD nwait;
272 char tmp[60];
273
274 w4[0] = h;
275 if (&_my_tls != _main_tls)
276 nwait = 1;
277 else
278 {
279 w4[1] = signal_arrived;
280 nwait = 2;
281 }
282
283 termios ti = tc->ti;
284 for (;;)
285 {
286 int bgres;
287 if ((bgres = bg_check (SIGTTIN)) <= bg_eof)
288 {
289 buflen = bgres;
290 return;
291 }
292
293 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
294 switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE))
295 {
296 case WAIT_OBJECT_0:
297 break;
298 case WAIT_OBJECT_0 + 1:
299 goto sig_exit;
300 default:
301 goto err;
302 }
303
304 DWORD nread;
305 INPUT_RECORD input_rec;
306 const char *toadd = NULL;
307
308 if (!ReadConsoleInputW (h, &input_rec, 1, &nread))
309 {
310 syscall_printf ("ReadConsoleInput failed, %E");
311 goto err; /* seems to be failure */
312 }
313
314 /* check the event that occurred */
315 switch (input_rec.EventType)
316 {
317 case KEY_EVENT:
318 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
319 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
320
321 dev_state->nModifiers = 0;
322
323 #ifdef DEBUGGING
324 /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
325 if (input_rec.Event.KeyEvent.bKeyDown &&
326 virtual_key_code == VK_SCROLL &&
327 ((control_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) == (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED))
328 )
329 {
330 set_raw_win32_keyboard_mode (!dev_state->raw_win32_keyboard_mode);
331 continue;
332 }
333 #endif
334
335 if (dev_state->raw_win32_keyboard_mode)
336 {
337 __small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK",
338 input_rec.Event.KeyEvent.bKeyDown,
339 input_rec.Event.KeyEvent.wRepeatCount,
340 input_rec.Event.KeyEvent.wVirtualKeyCode,
341 input_rec.Event.KeyEvent.wVirtualScanCode,
342 input_rec.Event.KeyEvent.uChar.UnicodeChar,
343 input_rec.Event.KeyEvent.dwControlKeyState);
344 toadd = tmp;
345 nread = strlen (toadd);
346 break;
347 }
348
349 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
350 #define wch (input_rec.Event.KeyEvent.uChar.UnicodeChar)
351 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
352 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
353
354 /* Ignore key up events, except for left alt events with non-zero character
355 */
356 if (!input_rec.Event.KeyEvent.bKeyDown &&
357 /*
358 Event for left alt, with a non-zero character, comes from
359 "alt + numerics" key sequence.
360 e.g. <left-alt> 0233 => &eacute;
361 */
362 !(wch != 0
363 // ?? experimentally determined on an XP system
364 && virtual_key_code == VK_MENU
365 // left alt -- see http://www.microsoft.com/hwdev/tech/input/Scancode.asp
366 && input_rec.Event.KeyEvent.wVirtualScanCode == 0x38))
367 continue;
368
369 if (control_key_state & SHIFT_PRESSED)
370 dev_state->nModifiers |= 1;
371 if (control_key_state & RIGHT_ALT_PRESSED)
372 dev_state->nModifiers |= 2;
373 if (control_key_state & CTRL_PRESSED)
374 dev_state->nModifiers |= 4;
375 if (control_key_state & LEFT_ALT_PRESSED)
376 dev_state->nModifiers |= 8;
377
378 /* Send the VERASE character from the terminal settings as backspace keycode. */
379 if (input_rec.Event.KeyEvent.wVirtualScanCode == 14)
380 {
381 char c = ti.c_cc[VERASE];
382 nread = 0;
383 if (control_key_state & ALT_PRESSED) {
384 if (dev_state->metabit)
385 c |= 0x80;
386 else
387 tmp[nread++] = '\e';
388 }
389 tmp[nread++] = c;
390 tmp[nread] = 0;
391 toadd = tmp;
392 }
393 /* Allow Ctrl-Space to emit ^@ */
394 else if (input_rec.Event.KeyEvent.wVirtualKeyCode == VK_SPACE
395 && (control_key_state & CTRL_PRESSED))
396 toadd = "";
397 else if (wch == 0
398 /* arrow/function keys */
399 || (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
400 {
401 toadd = get_nonascii_key (input_rec, tmp);
402 if (!toadd)
403 {
404 dev_state->nModifiers = 0;
405 continue;
406 }
407 nread = strlen (toadd);
408 }
409 else
410 {
411 nread = dev_state->con_to_str (tmp + 1, 59, wch);
412 /* Determine if the keystroke is modified by META. The tricky
413 part is to distinguish whether the right Alt key should be
414 recognized as Alt, or as AltGr. */
415 bool meta =
416 /* Alt but not AltGr (= left ctrl + right alt)? */
417 (control_key_state & ALT_PRESSED) != 0
418 && ((control_key_state & CTRL_PRESSED) == 0
419 /* but also allow Alt-AltGr: */
420 || (control_key_state & ALT_PRESSED) == ALT_PRESSED
421 || (wch <= 0x1f || wch == 0x7f));
422 if (!meta)
423 {
424 /* Determine if the character is in the current multibyte
425 charset. The test is easy. If the multibyte sequence
426 is > 1 and the first byte is ASCII CAN, the character
427 has been translated into the ASCII CAN + UTF-8 replacement
428 sequence. If so, just ignore the keypress.
429 FIXME: Is there a better solution? */
430 if (nread > 1 && tmp[1] == 0x18)
431 beep ();
432 else
433 toadd = tmp + 1;
434 }
435 else if (dev_state->metabit)
436 {
437 tmp[1] |= 0x80;
438 toadd = tmp + 1;
439 }
440 else
441 {
442 tmp[0] = '\033';
443 tmp[1] = cyg_tolower (tmp[1]);
444 toadd = tmp;
445 nread++;
446 dev_state->nModifiers &= ~4;
447 }
448 }
449 #undef ich
450 #undef wch
451 #undef ALT_PRESSED
452 #undef CTRL_PRESSED
453 break;
454
455 case MOUSE_EVENT:
456 send_winch_maybe ();
457 {
458 MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
459 /* As a unique guard for mouse report generation,
460 call mouse_aware() which is common with select(), so the result
461 of select() and the actual read() will be consistent on the
462 issue of whether input (i.e. a mouse escape sequence) will
463 be available or not */
464 if (mouse_aware (mouse_event))
465 {
466 /* Note: Reported mouse position was already retrieved by
467 mouse_aware() and adjusted by window scroll buffer offset */
468
469 /* Treat the double-click event like a regular button press */
470 if (mouse_event.dwEventFlags == DOUBLE_CLICK)
471 {
472 syscall_printf ("mouse: double-click -> click");
473 mouse_event.dwEventFlags = 0;
474 }
475
476 /* This code assumes Windows never reports multiple button
477 events at the same time. */
478 int b = 0;
479 char sz[32];
480
481 if (mouse_event.dwEventFlags == MOUSE_WHEELED)
482 {
483 if (mouse_event.dwButtonState & 0xFF800000)
484 {
485 b = 0x41;
486 strcpy (sz, "wheel down");
487 }
488 else
489 {
490 b = 0x40;
491 strcpy (sz, "wheel up");
492 }
493 }
494 else
495 {
496 /* Ignore unimportant mouse buttons */
497 mouse_event.dwButtonState &= 0x7;
498
499 if (mouse_event.dwEventFlags == MOUSE_MOVED)
500 {
501 b = dev_state->last_button_code;
502 }
503 else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
504 {
505 b = 3;
506 strcpy (sz, "btn up");
507 }
508 else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1))
509 {
510 b = 0;
511 strcpy (sz, "btn1 down");
512 }
513 else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2))
514 {
515 b = 2;
516 strcpy (sz, "btn2 down");
517 }
518 else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4))
519 {
520 b = 1;
521 strcpy (sz, "btn3 down");
522 }
523
524 dev_state->last_button_code = b;
525
526 if (mouse_event.dwEventFlags == MOUSE_MOVED)
527 {
528 b += 32;
529 strcpy (sz, "move");
530 }
531 else
532 {
533 /* Remember the modified button state */
534 dev_state->dwLastButtonState = mouse_event.dwButtonState;
535 }
536 }
537
538 /* Remember mouse position */
539 dev_state->dwLastMousePosition.X = dev_state->dwMousePosition.X;
540 dev_state->dwLastMousePosition.Y = dev_state->dwMousePosition.Y;
541
542 /* Remember the modifiers */
543 dev_state->nModifiers = 0;
544 if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
545 dev_state->nModifiers |= 0x4;
546 if (mouse_event.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
547 dev_state->nModifiers |= 0x8;
548 if (mouse_event.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
549 dev_state->nModifiers |= 0x10;
550
551 /* Indicate the modifiers */
552 b |= dev_state->nModifiers;
553
554 /* We can now create the code. */
555 sprintf (tmp, "\033[M%c%c%c", b + ' ', dev_state->dwMousePosition.X + ' ' + 1, dev_state->dwMousePosition.Y + ' ' + 1);
556 syscall_printf ("mouse: %s at (%d,%d)", sz, dev_state->dwMousePosition.X, dev_state->dwMousePosition.Y);
557
558 toadd = tmp;
559 nread = 6;
560 }
561 }
562 break;
563
564 case FOCUS_EVENT:
565 if (dev_state->use_focus) {
566 if (input_rec.Event.FocusEvent.bSetFocus)
567 sprintf (tmp, "\033[I");
568 else
569 sprintf (tmp, "\033[O");
570
571 toadd = tmp;
572 nread = 3;
573 }
574 break;
575
576 case WINDOW_BUFFER_SIZE_EVENT:
577 send_winch_maybe ();
578 /* fall through */
579 default:
580 continue;
581 }
582
583 if (toadd)
584 {
585 line_edit_status res = line_edit (toadd, nread, ti);
586 if (res == line_edit_signalled)
587 goto sig_exit;
588 else if (res == line_edit_input_done)
589 break;
590 }
591 }
592
593 while (buflen)
594 if ((ch = get_readahead ()) < 0)
595 break;
596 else
597 {
598 buf[copied_chars++] = (unsigned char)(ch & 0xff);
599 buflen--;
600 }
601 #undef buf
602
603 buflen = copied_chars;
604 return;
605
606 err:
607 __seterrno ();
608 buflen = (size_t) -1;
609 return;
610
611 sig_exit:
612 set_sig_errno (EINTR);
613 buflen = (size_t) -1;
614 }
615
616 void
617 fhandler_console::set_input_state ()
618 {
619 if (tc->rstcons ())
620 input_tcsetattr (0, &tc->ti);
621 }
622
623 bool
624 dev_console::fillin_info (HANDLE h)
625 {
626 bool ret;
627 CONSOLE_SCREEN_BUFFER_INFO linfo;
628
629 if ((ret = GetConsoleScreenBufferInfo (h, &linfo)))
630 {
631 info.winTop = linfo.srWindow.Top;
632 info.winBottom = linfo.srWindow.Bottom;
633 info.dwWinSize.Y = 1 + linfo.srWindow.Bottom - linfo.srWindow.Top;
634 info.dwWinSize.X = 1 + linfo.srWindow.Right - linfo.srWindow.Left;
635 info.dwBufferSize = linfo.dwSize;
636 info.dwCursorPosition = linfo.dwCursorPosition;
637 info.wAttributes = linfo.wAttributes;
638 }
639 else
640 {
641 memset (&info, 0, sizeof info);
642 info.dwWinSize.Y = 25;
643 info.dwWinSize.X = 80;
644 info.winBottom = 24;
645 }
646
647 return ret;
648 }
649
650 void
651 fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
652 {
653 SMALL_RECT sr1, sr2;
654 CHAR_INFO fill;
655 COORD dest;
656
657 dev_state->fillin_info (get_output_handle ());
658 sr1.Left = x1 >= 0 ? x1 : dev_state->info.dwWinSize.X - 1;
659 if (y1 == 0)
660 sr1.Top = dev_state->info.winTop;
661 else
662 sr1.Top = y1 > 0 ? y1 : dev_state->info.winBottom;
663 sr1.Right = x2 >= 0 ? x2 : dev_state->info.dwWinSize.X - 1;
664 if (y2 == 0)
665 sr1.Bottom = dev_state->info.winTop;
666 else
667 sr1.Bottom = y2 > 0 ? y2 : dev_state->info.winBottom;
668 sr2.Top = srTop;
669 sr2.Left = 0;
670 sr2.Bottom = srBottom;
671 sr2.Right = dev_state->info.dwWinSize.X - 1;
672 if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom)
673 sr1.Bottom = sr2.Bottom;
674 dest.X = xn >= 0 ? xn : dev_state->info.dwWinSize.X - 1;
675 if (yn == 0)
676 dest.Y = dev_state->info.winTop;
677 else
678 dest.Y = yn > 0 ? yn : dev_state->info.winBottom;
679 fill.Char.AsciiChar = ' ';
680 fill.Attributes = dev_state->current_win32_attr;
681 ScrollConsoleScreenBuffer (get_output_handle (), &sr1, &sr2, dest, &fill);
682
683 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
684 * is more than half of screen, filling doesn't work as expected */
685
686 if (sr1.Top == sr1.Bottom)
687 /* nothing to do */;
688 else if (dest.Y <= sr1.Top) /* forward scroll */
689 clear_screen (0, 1 + dest.Y + sr1.Bottom - sr1.Top, sr2.Right, sr2.Bottom);
690 else /* reverse scroll */
691 clear_screen (0, sr1.Top, sr2.Right, dest.Y - 1);
692 }
693
694 int
695 fhandler_console::open (int flags, mode_t)
696 {
697 HANDLE h;
698
699 tcinit (get_tty_stuff (flags));
700
701 set_io_handle (NULL);
702 set_output_handle (NULL);
703
704 set_flags ((flags & ~O_TEXT) | O_BINARY);
705
706 /* Open the input handle as handle_ */
707 h = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
708 FILE_SHARE_READ | FILE_SHARE_WRITE, sec_none_cloexec (flags),
709 OPEN_EXISTING, 0, 0);
710
711 if (h == INVALID_HANDLE_VALUE)
712 {
713 __seterrno ();
714 return 0;
715 }
716 set_io_handle (h);
717 uninterruptible_io (true); // Handled explicitly in read code
718
719 h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
720 FILE_SHARE_READ | FILE_SHARE_WRITE, sec_none_cloexec (flags),
721 OPEN_EXISTING, 0, 0);
722
723 if (h == INVALID_HANDLE_VALUE)
724 {
725 __seterrno ();
726 return 0;
727 }
728 set_output_handle (h);
729
730 if (dev_state->fillin_info (get_output_handle ()))
731 {
732 dev_state->current_win32_attr = dev_state->info.wAttributes;
733 if (!dev_state->default_color)
734 dev_state->default_color = dev_state->info.wAttributes;
735 dev_state->set_default_attr ();
736 }
737
738 tc->rstcons (false);
739 set_open_status ();
740 cygheap->manage_console_count ("fhandler_console::open", 1);
741
742 DWORD cflags;
743 if (GetConsoleMode (get_io_handle (), &cflags))
744 SetConsoleMode (get_io_handle (),
745 ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | cflags);
746
747 debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (),
748 get_output_handle ());
749
750 return 1;
751 }
752
753 int
754 fhandler_console::close ()
755 {
756 CloseHandle (get_io_handle ());
757 CloseHandle (get_output_handle ());
758 if (!hExeced)
759 cygheap->manage_console_count ("fhandler_console::close", -1);
760 return 0;
761 }
762
763 /* Special console dup to duplicate input and output handles. */
764
765 int
766 fhandler_console::dup (fhandler_base *child)
767 {
768 fhandler_console *fhc = (fhandler_console *) child;
769
770 if (!fhc->open (get_flags () & ~O_NOCTTY, 0))
771 system_printf ("error opening console, %E");
772
773 return 0;
774 }
775
776 int
777 fhandler_console::ioctl (unsigned int cmd, void *buf)
778 {
779 switch (cmd)
780 {
781 case TIOCGWINSZ:
782 int st;
783
784 st = dev_state->fillin_info (get_output_handle ());
785 if (st)
786 {
787 /* *not* the buffer size, the actual screen size... */
788 /* based on Left Top Right Bottom of srWindow */
789 ((struct winsize *) buf)->ws_row = dev_state->info.dwWinSize.Y;
790 ((struct winsize *) buf)->ws_col = dev_state->info.dwWinSize.X;
791 syscall_printf ("WINSZ: (row=%d,col=%d)",
792 ((struct winsize *) buf)->ws_row,
793 ((struct winsize *) buf)->ws_col);
794 return 0;
795 }
796 else
797 {
798 syscall_printf ("WINSZ failed");
799 __seterrno ();
800 return -1;
801 }
802 return 0;
803 case TIOCSWINSZ:
804 bg_check (SIGTTOU);
805 return 0;
806 case KDGKBMETA:
807 *(int *) buf = (dev_state->metabit) ? K_METABIT : K_ESCPREFIX;
808 return 0;
809 case KDSKBMETA:
810 if ((int) buf == K_METABIT)
811 dev_state->metabit = TRUE;
812 else if ((int) buf == K_ESCPREFIX)
813 dev_state->metabit = FALSE;
814 else
815 {
816 set_errno (EINVAL);
817 return -1;
818 }
819 return 0;
820 case TIOCLINUX:
821 if (*(unsigned char *) buf == 6)
822 {
823 *(unsigned char *) buf = (unsigned char) dev_state->nModifiers;
824 return 0;
825 }
826 else
827 {
828 set_errno (EINVAL);
829 return -1;
830 }
831 }
832
833 return fhandler_base::ioctl (cmd, buf);
834 }
835
836 int
837 fhandler_console::tcflush (int queue)
838 {
839 int res = 0;
840 if (queue == TCIFLUSH
841 || queue == TCIOFLUSH)
842 {
843 if (!FlushConsoleInputBuffer (get_io_handle ()))
844 {
845 __seterrno ();
846 res = -1;
847 }
848 }
849 return res;
850 }
851
852 int
853 fhandler_console::output_tcsetattr (int, struct termios const *t)
854 {
855 /* All the output bits we can ignore */
856
857 DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
858
859 int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
860 syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)",
861 res, t, flags, t->c_lflag, t->c_oflag);
862 return res;
863 }
864
865 int
866 fhandler_console::input_tcsetattr (int, struct termios const *t)
867 {
868 /* Ignore the optional_actions stuff, since all output is emitted
869 instantly */
870
871 DWORD oflags;
872
873 if (!GetConsoleMode (get_io_handle (), &oflags))
874 oflags = 0;
875 DWORD flags = 0;
876
877 #if 0
878 /* Enable/disable LF -> CRLF conversions */
879 rbinary ((t->c_iflag & INLCR) ? false : true);
880 #endif
881
882 /* There's some disparity between what we need and what's
883 available. We've got ECHO and ICANON, they've
884 got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
885
886 tc->ti = *t;
887
888 if (t->c_lflag & ECHO)
889 {
890 flags |= ENABLE_ECHO_INPUT;
891 }
892 if (t->c_lflag & ICANON)
893 {
894 flags |= ENABLE_LINE_INPUT;
895 }
896
897 if (flags & ENABLE_ECHO_INPUT
898 && !(flags & ENABLE_LINE_INPUT))
899 {
900 /* This is illegal, so turn off the echo here, and fake it
901 when we read the characters */
902
903 flags &= ~ENABLE_ECHO_INPUT;
904 }
905
906 if (t->c_lflag & ISIG)
907 {
908 flags |= ENABLE_PROCESSED_INPUT;
909 }
910
911 if (use_tty)
912 {
913 flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
914 tc->ti.c_iflag = 0;
915 tc->ti.c_lflag = 0;
916 }
917
918 flags |= ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
919
920 int res;
921 if (flags == oflags)
922 res = 0;
923 else
924 {
925 res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1;
926 if (res < 0)
927 __seterrno ();
928 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
929 res, t, flags, t->c_lflag, t->c_iflag);
930 }
931
932 tc->rstcons (false);
933 return res;
934 }
935
936 int
937 fhandler_console::tcsetattr (int a, struct termios const *t)
938 {
939 int res = output_tcsetattr (a, t);
940 if (res != 0)
941 return res;
942 return input_tcsetattr (a, t);
943 }
944
945 int
946 fhandler_console::tcgetattr (struct termios *t)
947 {
948 int res;
949 *t = tc->ti;
950
951 t->c_cflag |= CS8;
952
953 DWORD flags;
954
955 if (!GetConsoleMode (get_io_handle (), &flags))
956 {
957 __seterrno ();
958 res = -1;
959 }
960 else
961 {
962 if (flags & ENABLE_ECHO_INPUT)
963 t->c_lflag |= ECHO;
964
965 if (flags & ENABLE_LINE_INPUT)
966 t->c_lflag |= ICANON;
967
968 if (flags & ENABLE_PROCESSED_INPUT)
969 t->c_lflag |= ISIG;
970
971 /* What about ENABLE_WINDOW_INPUT
972 and ENABLE_MOUSE_INPUT ? */
973
974 /* All the output bits we can ignore */
975 res = 0;
976 }
977 syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p",
978 res, t, flags, t->c_lflag, t->c_iflag);
979 return res;
980 }
981
982 fhandler_console::fhandler_console () :
983 fhandler_termios ()
984 {
985 trunc_buf.len = 0;
986 }
987
988 void
989 dev_console::set_color (HANDLE h)
990 {
991 WORD win_fg = fg;
992 WORD win_bg = bg;
993 if (reverse)
994 {
995 WORD save_fg = win_fg;
996 win_fg = (win_bg & BACKGROUND_RED ? FOREGROUND_RED : 0) |
997 (win_bg & BACKGROUND_GREEN ? FOREGROUND_GREEN : 0) |
998 (win_bg & BACKGROUND_BLUE ? FOREGROUND_BLUE : 0) |
999 (win_bg & BACKGROUND_INTENSITY ? FOREGROUND_INTENSITY : 0);
1000 win_bg = (save_fg & FOREGROUND_RED ? BACKGROUND_RED : 0) |
1001 (save_fg & FOREGROUND_GREEN ? BACKGROUND_GREEN : 0) |
1002 (save_fg & FOREGROUND_BLUE ? BACKGROUND_BLUE : 0) |
1003 (save_fg & FOREGROUND_INTENSITY ? BACKGROUND_INTENSITY : 0);
1004 }
1005
1006 /* apply attributes */
1007 if (underline)
1008 win_fg = underline_color;
1009 /* emulate blink with bright background */
1010 if (blink)
1011 win_bg |= BACKGROUND_INTENSITY;
1012 if (intensity == INTENSITY_INVISIBLE)
1013 win_fg = win_bg;
1014 else if (intensity != INTENSITY_BOLD)
1015 /* nothing to do */;
1016 /* apply foreground intensity only in non-reverse mode! */
1017 else if (reverse)
1018 win_bg |= BACKGROUND_INTENSITY;
1019 else
1020 win_fg |= FOREGROUND_INTENSITY;
1021
1022 current_win32_attr = win_fg | win_bg;
1023 if (h)
1024 SetConsoleTextAttribute (h, current_win32_attr);
1025 }
1026
1027 #define FOREGROUND_ATTR_MASK (FOREGROUND_RED | FOREGROUND_GREEN | \
1028 FOREGROUND_BLUE | FOREGROUND_INTENSITY)
1029 #define BACKGROUND_ATTR_MASK (BACKGROUND_RED | BACKGROUND_GREEN | \
1030 BACKGROUND_BLUE | BACKGROUND_INTENSITY)
1031 void
1032 dev_console::set_default_attr ()
1033 {
1034 blink = underline = reverse = false;
1035 intensity = INTENSITY_NORMAL;
1036 fg = default_color & FOREGROUND_ATTR_MASK;
1037 bg = default_color & BACKGROUND_ATTR_MASK;
1038 set_color (NULL);
1039 }
1040
1041 /*
1042 * Clear the screen context from x1/y1 to x2/y2 cell.
1043 * Negative values represents current screen dimensions
1044 */
1045 void
1046 fhandler_console::clear_screen (int x1, int y1, int x2, int y2)
1047 {
1048 COORD tlc;
1049 DWORD done;
1050 int num;
1051
1052 dev_state->fillin_info (get_output_handle ());
1053
1054 if (x1 < 0)
1055 x1 = dev_state->info.dwWinSize.X - 1;
1056 if (y1 < 0)
1057 y1 = dev_state->info.winBottom;
1058 if (x2 < 0)
1059 x2 = dev_state->info.dwWinSize.X - 1;
1060 if (y2 < 0)
1061 y2 = dev_state->info.winBottom;
1062
1063 num = abs (y1 - y2) * dev_state->info.dwBufferSize.X + abs (x1 - x2) + 1;
1064
1065 if ((y2 * dev_state->info.dwBufferSize.X + x2) > (y1 * dev_state->info.dwBufferSize.X + x1))
1066 {
1067 tlc.X = x1;
1068 tlc.Y = y1;
1069 }
1070 else
1071 {
1072 tlc.X = x2;
1073 tlc.Y = y2;
1074 }
1075 FillConsoleOutputCharacterA (get_output_handle (), ' ',
1076 num,
1077 tlc,
1078 &done);
1079 FillConsoleOutputAttribute (get_output_handle (),
1080 dev_state->current_win32_attr,
1081 num,
1082 tlc,
1083 &done);
1084 }
1085
1086 void
1087 fhandler_console::cursor_set (bool rel_to_top, int x, int y)
1088 {
1089 COORD pos;
1090
1091 dev_state->fillin_info (get_output_handle ());
1092 if (y > dev_state->info.winBottom)
1093 y = dev_state->info.winBottom;
1094 else if (y < 0)
1095 y = 0;
1096 else if (rel_to_top)
1097 y += dev_state->info.winTop;
1098
1099 if (x > dev_state->info.dwWinSize.X)
1100 x = dev_state->info.dwWinSize.X - 1;
1101 else if (x < 0)
1102 x = 0;
1103
1104 pos.X = x;
1105 pos.Y = y;
1106 SetConsoleCursorPosition (get_output_handle (), pos);
1107 }
1108
1109 void
1110 fhandler_console::cursor_rel (int x, int y)
1111 {
1112 dev_state->fillin_info (get_output_handle ());
1113 x += dev_state->info.dwCursorPosition.X;
1114 y += dev_state->info.dwCursorPosition.Y;
1115 cursor_set (false, x, y);
1116 }
1117
1118 void
1119 fhandler_console::cursor_get (int *x, int *y)
1120 {
1121 dev_state->fillin_info (get_output_handle ());
1122 *y = dev_state->info.dwCursorPosition.Y;
1123 *x = dev_state->info.dwCursorPosition.X;
1124 }
1125
1126 /* VT100 line drawing graphics mode maps `abcdefghijklmnopqrstuvwxyz{|}~ to
1127 graphical characters */
1128 static wchar_t __vt100_conv [31] = {
1129 0x25C6, /* Black Diamond */
1130 0x2592, /* Medium Shade */
1131 0x2409, /* Symbol for Horizontal Tabulation */
1132 0x240C, /* Symbol for Form Feed */
1133 0x240D, /* Symbol for Carriage Return */
1134 0x240A, /* Symbol for Line Feed */
1135 0x00B0, /* Degree Sign */
1136 0x00B1, /* Plus-Minus Sign */
1137 0x2424, /* Symbol for Newline */
1138 0x240B, /* Symbol for Vertical Tabulation */
1139 0x2518, /* Box Drawings Light Up And Left */
1140 0x2510, /* Box Drawings Light Down And Left */
1141 0x250C, /* Box Drawings Light Down And Right */
1142 0x2514, /* Box Drawings Light Up And Right */
1143 0x253C, /* Box Drawings Light Vertical And Horizontal */
1144 0x23BA, /* Horizontal Scan Line-1 */
1145 0x23BB, /* Horizontal Scan Line-3 */
1146 0x2500, /* Box Drawings Light Horizontal */
1147 0x23BC, /* Horizontal Scan Line-7 */
1148 0x23BD, /* Horizontal Scan Line-9 */
1149 0x251C, /* Box Drawings Light Vertical And Right */
1150 0x2524, /* Box Drawings Light Vertical And Left */
1151 0x2534, /* Box Drawings Light Up And Horizontal */
1152 0x252C, /* Box Drawings Light Down And Horizontal */
1153 0x2502, /* Box Drawings Light Vertical */
1154 0x2264, /* Less-Than Or Equal To */
1155 0x2265, /* Greater-Than Or Equal To */
1156 0x03C0, /* Greek Small Letter Pi */
1157 0x2260, /* Not Equal To */
1158 0x00A3, /* Pound Sign */
1159 0x00B7, /* Middle Dot */
1160 };
1161
1162 inline
1163 bool fhandler_console::write_console (PWCHAR buf, DWORD len, DWORD& done)
1164 {
1165 if (dev_state->vt100_graphics_mode_active)
1166 for (DWORD i = 0; i < len; i ++)
1167 if (buf[i] >= (unsigned char) '`' && buf[i] <= (unsigned char) '~')
1168 buf[i] = __vt100_conv[buf[i] - (unsigned char) '`'];
1169
1170 while (len > 0)
1171 {
1172 DWORD nbytes = len > MAX_WRITE_CHARS ? MAX_WRITE_CHARS : len;
1173 if (!WriteConsoleW (get_output_handle (), buf, nbytes, &done, 0))
1174 {
1175 __seterrno ();
1176 return false;
1177 }
1178 len -= done;
1179 buf += done;
1180 }
1181 return true;
1182 }
1183
1184 #define BAK 1
1185 #define ESC 2
1186 #define NOR 0
1187 #define IGN 4
1188 #if 1
1189 #define ERR 5
1190 #else
1191 #define ERR NOR
1192 #endif
1193 #define DWN 6
1194 #define BEL 7
1195 #define TAB 8 /* We should't let the console deal with these */
1196 #define CR 13
1197 #define LF 10
1198 #define SO 14
1199 #define SI 15
1200
1201 static const char base_chars[256] =
1202 {
1203 /*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL,
1204 /*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, SO, SI,
1205 /*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR,
1206 /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
1207 /* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1208 /*( ) * + , - . / */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1209 /*0 1 2 3 4 5 6 7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1210 /*8 9 : ; < = > ? */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1211 /*@ A B C D E F G */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1212 /*H I J K L M N O */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1213 /*P Q R S T U V W */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1214 /*X Y Z [ \ ] ^ _ */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1215 /*` a b c d e f g */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1216 /*h i j k l m n o */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1217 /*p q r s t u v w */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1218 /*x y z { | } ~ 7F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1219 /*80 81 82 83 84 85 86 87 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1220 /*88 89 8A 8B 8C 8D 8E 8F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1221 /*90 91 92 93 94 95 96 97 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1222 /*98 99 9A 9B 9C 9D 9E 9F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1223 /*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1224 /*A8 A9 AA AB AC AD AE AF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1225 /*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1226 /*B8 B9 BA BB BC BD BE BF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1227 /*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1228 /*C8 C9 CA CB CC CD CE CF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1229 /*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1230 /*D8 D9 DA DB DC DD DE DF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1231 /*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1232 /*E8 E9 EA EB EC ED EE EF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1233 /*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1234 /*F8 F9 FA FB FC FD FE FF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR };
1235
1236 void
1237 fhandler_console::char_command (char c)
1238 {
1239 int x, y;
1240 char buf[40];
1241
1242 switch (c)
1243 {
1244 case 'm': /* Set Graphics Rendition */
1245 for (int i = 0; i <= dev_state->nargs_; i++)
1246 switch (dev_state->args_[i])
1247 {
1248 case 0: /* normal color */
1249 dev_state->set_default_attr ();
1250 break;
1251 case 1: /* bold */
1252 dev_state->intensity = INTENSITY_BOLD;
1253 break;
1254 case 2: /* dim */
1255 dev_state->intensity = INTENSITY_DIM;
1256 break;
1257 case 4: /* underlined */
1258 dev_state->underline = 1;
1259 break;
1260 case 5: /* blink mode */
1261 dev_state->blink = true;
1262 break;
1263 case 7: /* reverse */
1264 dev_state->reverse = true;
1265 break;
1266 case 8: /* invisible */
1267 dev_state->intensity = INTENSITY_INVISIBLE;
1268 break;
1269 case 10: /* end alternate charset */
1270 dev_state->alternate_charset_active = false;
1271 break;
1272 case 11: /* start alternate charset */
1273 dev_state->alternate_charset_active = true;
1274 break;
1275 case 22:
1276 case 28:
1277 dev_state->intensity = INTENSITY_NORMAL;
1278 break;
1279 case 24:
1280 dev_state->underline = false;
1281 break;
1282 case 25:
1283 dev_state->blink = false;
1284 break;
1285 case 27:
1286 dev_state->reverse = false;
1287 break;
1288 case 30: /* BLACK foreground */
1289 dev_state->fg = 0;
1290 break;
1291 case 31: /* RED foreground */
1292 dev_state->fg = FOREGROUND_RED;
1293 break;
1294 case 32: /* GREEN foreground */
1295 dev_state->fg = FOREGROUND_GREEN;
1296 break;
1297 case 33: /* YELLOW foreground */
1298 dev_state->fg = FOREGROUND_RED | FOREGROUND_GREEN;
1299 break;
1300 case 34: /* BLUE foreground */
1301 dev_state->fg = FOREGROUND_BLUE;
1302 break;
1303 case 35: /* MAGENTA foreground */
1304 dev_state->fg = FOREGROUND_RED | FOREGROUND_BLUE;
1305 break;
1306 case 36: /* CYAN foreground */
1307 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
1308 break;
1309 case 37: /* WHITE foreg */
1310 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
1311 break;
1312 case 39:
1313 dev_state->fg = dev_state->default_color & FOREGROUND_ATTR_MASK;
1314 break;
1315 case 40: /* BLACK background */
1316 dev_state->bg = 0;
1317 break;
1318 case 41: /* RED background */
1319 dev_state->bg = BACKGROUND_RED;
1320 break;
1321 case 42: /* GREEN background */
1322 dev_state->bg = BACKGROUND_GREEN;
1323 break;
1324 case 43: /* YELLOW background */
1325 dev_state->bg = BACKGROUND_RED | BACKGROUND_GREEN;
1326 break;
1327 case 44: /* BLUE background */
1328 dev_state->bg = BACKGROUND_BLUE;
1329 break;
1330 case 45: /* MAGENTA background */
1331 dev_state->bg = BACKGROUND_RED | BACKGROUND_BLUE;
1332 break;
1333 case 46: /* CYAN background */
1334 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
1335 break;
1336 case 47: /* WHITE background */
1337 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
1338 break;
1339 case 49:
1340 dev_state->bg = dev_state->default_color & BACKGROUND_ATTR_MASK;
1341 break;
1342 }
1343 dev_state->set_color (get_output_handle ());
1344 break;
1345 case 'h':
1346 case 'l':
1347 if (!dev_state->saw_question_mark)
1348 {
1349 switch (dev_state->args_[0])
1350 {
1351 case 4: /* Insert mode */
1352 dev_state->insert_mode = (c == 'h') ? true : false;
1353 syscall_printf ("insert mode %sabled", dev_state->insert_mode ? "en" : "dis");
1354 break;
1355 }
1356 break;
1357 }
1358 switch (dev_state->args_[0])
1359 {
1360 case 47: /* Save/Restore screen */
1361 if (c == 'h') /* save */
1362 {
1363 CONSOLE_SCREEN_BUFFER_INFO now;
1364 COORD cob = { 0, 0 };
1365
1366 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1367 break;
1368
1369 dev_state->savebufsiz.X = now.srWindow.Right - now.srWindow.Left + 1;
1370 dev_state->savebufsiz.Y = now.srWindow.Bottom - now.srWindow.Top + 1;
1371
1372 if (dev_state->savebuf)
1373 cfree (dev_state->savebuf);
1374 dev_state->savebuf = (PCHAR_INFO) cmalloc_abort (HEAP_1_BUF, sizeof (CHAR_INFO) *
1375 dev_state->savebufsiz.X * dev_state->savebufsiz.Y);
1376
1377 ReadConsoleOutputW (get_output_handle (), dev_state->savebuf,
1378 dev_state->savebufsiz, cob, &now.srWindow);
1379 }
1380 else /* restore */
1381 {
1382 CONSOLE_SCREEN_BUFFER_INFO now;
1383 COORD cob = { 0, 0 };
1384
1385 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1386 break;
1387
1388 if (!dev_state->savebuf)
1389 break;
1390
1391 WriteConsoleOutputW (get_output_handle (), dev_state->savebuf,
1392 dev_state->savebufsiz, cob, &now.srWindow);
1393
1394 cfree (dev_state->savebuf);
1395 dev_state->savebuf = NULL;
1396 dev_state->savebufsiz.X = dev_state->savebufsiz.Y = 0;
1397 }
1398 break;
1399
1400 case 1000: /* Mouse tracking */
1401 dev_state->use_mouse = (c == 'h') ? 1 : 0;
1402 syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
1403 break;
1404
1405 case 1002: /* Mouse button event tracking */
1406 dev_state->use_mouse = (c == 'h') ? 2 : 0;
1407 syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
1408 break;
1409
1410 case 1003: /* Mouse any event tracking */
1411 dev_state->use_mouse = (c == 'h') ? 3 : 0;
1412 syscall_printf ("mouse support set to mode %d", dev_state->use_mouse);
1413 break;
1414
1415 case 1004: /* Focus in/out event reporting */
1416 dev_state->use_focus = (c == 'h') ? true : false;
1417 syscall_printf ("focus reporting set to %d", dev_state->use_focus);
1418 break;
1419
1420 case 2000: /* Raw keyboard mode */
1421 set_raw_win32_keyboard_mode ((c == 'h') ? true : false);
1422 break;
1423
1424 default: /* Ignore */
1425 syscall_printf ("unknown h/l command: %d", dev_state->args_[0]);
1426 break;
1427 }
1428 break;
1429 case 'J':
1430 switch (dev_state->args_[0])
1431 {
1432 case 0: /* Clear to end of screen */
1433 cursor_get (&x, &y);
1434 clear_screen (x, y, -1, -1);
1435 break;
1436 case 1: /* Clear from beginning of screen to cursor */
1437 cursor_get (&x, &y);
1438 clear_screen (0, 0, x, y);
1439 break;
1440 case 2: /* Clear screen */
1441 clear_screen (0, 0, -1, -1);
1442 cursor_set (true, 0,0);
1443 break;
1444 default:
1445 goto bad_escape;
1446 }
1447 break;
1448
1449 case 'A':
1450 cursor_rel (0, -(dev_state->args_[0] ? dev_state->args_[0] : 1));
1451 break;
1452 case 'B':
1453 cursor_rel (0, dev_state->args_[0] ? dev_state->args_[0] : 1);
1454 break;
1455 case 'C':
1456 cursor_rel (dev_state->args_[0] ? dev_state->args_[0] : 1, 0);
1457 break;
1458 case 'D':
1459 cursor_rel (-(dev_state->args_[0] ? dev_state->args_[0] : 1),0);
1460 break;
1461 case 'K':
1462 switch (dev_state->args_[0])
1463 {
1464 case 0: /* Clear to end of line */
1465 cursor_get (&x, &y);
1466 clear_screen (x, y, -1, y);
1467 break;
1468 case 2: /* Clear line */
1469 cursor_get (&x, &y);
1470 clear_screen (0, y, -1, y);
1471 break;
1472 case 1: /* Clear from bol to cursor */
1473 cursor_get (&x, &y);
1474 clear_screen (0, y, x, y);
1475 break;
1476 default:
1477 goto bad_escape;
1478 }
1479 break;
1480 case 'H':
1481 case 'f':
1482 cursor_set (true, (dev_state->args_[1] ? dev_state->args_[1] : 1) - 1,
1483 (dev_state->args_[0] ? dev_state->args_[0] : 1) - 1);
1484 break;
1485 case 'G': /* hpa - position cursor at column n - 1 */
1486 cursor_get (&x, &y);
1487 cursor_set (false, (dev_state->args_[0] ? dev_state->args_[0] - 1 : 0), y);
1488 break;
1489 case 'd': /* vpa - position cursor at line n */
1490 cursor_get (&x, &y);
1491 cursor_set (true, x, (dev_state->args_[0] ? dev_state->args_[0] - 1 : 0));
1492 break;
1493 case 's': /* Save cursor position */
1494 cursor_get (&dev_state->savex, &dev_state->savey);
1495 dev_state->savey -= dev_state->info.winTop;
1496 break;
1497 case 'u': /* Restore cursor position */
1498 cursor_set (true, dev_state->savex, dev_state->savey);
1499 break;
1500 case 'I': /* TAB */
1501 cursor_get (&x, &y);
1502 cursor_set (false, 8 * (x / 8 + 1), y);
1503 break;
1504 case 'L': /* AL - insert blank lines */
1505 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1506 cursor_get (&x, &y);
1507 scroll_screen (0, y, -1, -1, 0, y + dev_state->args_[0]);
1508 break;
1509 case 'M': /* DL - delete lines */
1510 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1511 cursor_get (&x, &y);
1512 scroll_screen (0, y + dev_state->args_[0], -1, -1, 0, y);
1513 break;
1514 case '@': /* IC - insert chars */
1515 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1516 cursor_get (&x, &y);
1517 scroll_screen (x, y, -1, y, x + dev_state->args_[0], y);
1518 break;
1519 case 'P': /* DC - delete chars */
1520 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1521 cursor_get (&x, &y);
1522 scroll_screen (x + dev_state->args_[0], y, -1, y, x, y);
1523 break;
1524 case 'S': /* SF - Scroll forward */
1525 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1526 scroll_screen (0, dev_state->args_[0], -1, -1, 0, 0);
1527 break;
1528 case 'T': /* SR - Scroll down */
1529 dev_state->fillin_info (get_output_handle ());
1530 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1531 scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + dev_state->args_[0]);
1532 break;
1533 case 'X': /* ec - erase chars */
1534 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1535 cursor_get (&x, &y);
1536 scroll_screen (x + dev_state->args_[0], y, -1, y, x, y);
1537 scroll_screen (x, y, -1, y, x + dev_state->args_[0], y);
1538 break;
1539 case 'Z': /* Back tab */
1540 cursor_get (&x, &y);
1541 cursor_set (false, ((8 * (x / 8 + 1)) - 8), y);
1542 break;
1543 case 'b': /* Repeat char #1 #2 times */
1544 if (dev_state->insert_mode)
1545 {
1546 cursor_get (&x, &y);
1547 scroll_screen (x, y, -1, y, x + dev_state->args_[1], y);
1548 }
1549 while (dev_state->args_[1]--)
1550 WriteFile (get_output_handle (), &dev_state->args_[0], 1, (DWORD *) &x, 0);
1551 break;
1552 case 'c': /* u9 - Terminal enquire string */
1553 if (dev_state->saw_greater_than_sign)
1554 /* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
1555 to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
1556 and cygwin version for terminal version. */
1557 __small_sprintf (buf, "\033[>67;%d%02d;0c", CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
1558 else
1559 strcpy (buf, "\033[?6c");
1560 /* The generated report needs to be injected for read-ahead into the
1561 fhandler_console object associated with standard input.
1562 The current call does not work. */
1563 puts_readahead (buf);
1564 break;
1565 case 'n':
1566 switch (dev_state->args_[0])
1567 {
1568 case 6: /* u7 - Cursor position request */
1569 cursor_get (&x, &y);
1570 y -= dev_state->info.winTop;
1571 /* x -= dev_state->info.winLeft; // not available yet */
1572 __small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
1573 puts_readahead (buf);
1574 break;
1575 default:
1576 goto bad_escape;
1577 }
1578 break;
1579 case 'r': /* Set Scroll region */
1580 dev_state->scroll_region.Top = dev_state->args_[0] ? dev_state->args_[0] - 1 : 0;
1581 dev_state->scroll_region.Bottom = dev_state->args_[1] ? dev_state->args_[1] - 1 : -1;
1582 cursor_set (true, 0, 0);
1583 break;
1584 case 'g': /* TAB set/clear */
1585 break;
1586 default:
1587 bad_escape:
1588 break;
1589 }
1590 }
1591
1592 /* This gets called when we found an invalid input character. We just
1593 print a half filled square (UTF 0x2592). We have no chance to figure
1594 out the "meaning" of the input char anyway. */
1595 inline void
1596 fhandler_console::write_replacement_char ()
1597 {
1598 static const wchar_t replacement_char = 0x2592; /* Half filled square */
1599 DWORD done;
1600 WriteConsoleW (get_output_handle (), &replacement_char, 1, &done, 0);
1601 }
1602
1603 const unsigned char *
1604 fhandler_console::write_normal (const unsigned char *src,
1605 const unsigned char *end)
1606 {
1607 /* Scan forward to see what a char which needs special treatment */
1608 DWORD done;
1609 DWORD buf_len;
1610 const unsigned char *found = src;
1611 size_t ret;
1612 mbstate_t ps;
1613 UINT cp = dev_state->get_console_cp ();
1614 const char *charset;
1615 mbtowc_p f_mbtowc;
1616
1617 if (cp)
1618 {
1619 /* The alternate charset is always 437, just as in the Linux console. */
1620 f_mbtowc = __cp_mbtowc;
1621 charset = "CP437";
1622 }
1623 else
1624 {
1625 f_mbtowc = cygheap->locale.mbtowc;
1626 charset = cygheap->locale.charset;
1627 }
1628
1629 /* First check if we have cached lead bytes of a former try to write
1630 a truncated multibyte sequence. If so, process it. */
1631 if (trunc_buf.len)
1632 {
1633 const unsigned char *nfound;
1634 int cp_len = min (end - src, 4 - trunc_buf.len);
1635 memcpy (trunc_buf.buf + trunc_buf.len, src, cp_len);
1636 memset (&ps, 0, sizeof ps);
1637 switch (ret = f_mbtowc (_REENT, NULL, (const char *) trunc_buf.buf,
1638 trunc_buf.len + cp_len, charset, &ps))
1639 {
1640 case -2:
1641 /* Still truncated multibyte sequence? Keep in trunc_buf. */
1642 trunc_buf.len += cp_len;
1643 return end;
1644 case -1:
1645 /* Give up, print replacement chars for trunc_buf... */
1646 for (int i = 0; i < trunc_buf.len; ++i)
1647 write_replacement_char ();
1648 /* ... mark trunc_buf as unused... */
1649 trunc_buf.len = 0;
1650 /* ... and proceed. */
1651 nfound = NULL;
1652 break;
1653 case 0:
1654 nfound = trunc_buf.buf + 1;
1655 break;
1656 default:
1657 nfound = trunc_buf.buf + ret;
1658 break;
1659 }
1660 /* Valid multibyte sequence? Process. */
1661 if (nfound)
1662 {
1663 buf_len = dev_state->str_to_con (f_mbtowc, charset, write_buf,
1664 (const char *) trunc_buf.buf,
1665 nfound - trunc_buf.buf);
1666 if (!write_console (write_buf, buf_len, done))
1667 {
1668 debug_printf ("multibyte sequence write failed, handle %p", get_output_handle ());
1669 return 0;
1670 }
1671 found = src + (nfound - trunc_buf.buf - trunc_buf.len);
1672 trunc_buf.len = 0;
1673 return found;
1674 }
1675 }
1676
1677 memset (&ps, 0, sizeof ps);
1678 while (found < end
1679 && found - src < CONVERT_LIMIT
1680 && base_chars[*found] == NOR)
1681 {
1682 switch (ret = f_mbtowc (_REENT, NULL, (const char *) found,
1683 end - found, charset, &ps))
1684 {
1685 case -2:
1686 /* Truncated multibyte sequence. Stick to it until the next write. */
1687 trunc_buf.len = end - found;
1688 memcpy (trunc_buf.buf, found, trunc_buf.len);
1689 return end;
1690 case -1:
1691 break;
1692 case 0:
1693 found++;
1694 break;
1695 default:
1696 found += ret;
1697 break;
1698 }
1699 if (ret == (size_t) -1) /* Invalid multibyte sequence. */
1700 break;
1701 }
1702
1703 /* Print all the base ones out */
1704 if (found != src)
1705 {
1706 DWORD len = found - src;
1707 buf_len = dev_state->str_to_con (f_mbtowc, charset, write_buf,
1708 (const char *) src, len);
1709 if (!buf_len)
1710 {
1711 debug_printf ("conversion error, handle %p",
1712 get_output_handle ());
1713 __seterrno ();
1714 return 0;
1715 }
1716
1717 if (dev_state->insert_mode)
1718 {
1719 int x, y;
1720 cursor_get (&x, &y);
1721 scroll_screen (x, y, -1, y, x + buf_len, y);
1722 }
1723
1724 if (!write_console (write_buf, buf_len, done))
1725 {
1726 debug_printf ("write failed, handle %p", get_output_handle ());
1727 return 0;
1728 }
1729 if (len >= CONVERT_LIMIT)
1730 return found;
1731 }
1732
1733 if (found < end)
1734 {
1735 int x, y;
1736 switch (base_chars[*found])
1737 {
1738 case SO:
1739 dev_state->vt100_graphics_mode_active = true;
1740 break;
1741 case SI:
1742 dev_state->vt100_graphics_mode_active = false;
1743 break;
1744 case BEL:
1745 beep ();
1746 break;
1747 case ESC:
1748 dev_state->state_ = gotesc;
1749 break;
1750 case DWN:
1751 cursor_get (&x, &y);
1752 if (y >= srBottom)
1753 {
1754 if (y >= dev_state->info.winBottom && !dev_state->scroll_region.Top)
1755 WriteConsoleW (get_output_handle (), L"\n", 1, &done, 0);
1756 else
1757 {
1758 scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
1759 y--;
1760 }
1761 }
1762 cursor_set (false, ((tc->ti.c_oflag & ONLCR) ? 0 : x), y + 1);
1763 break;
1764 case BAK:
1765 cursor_rel (-1, 0);
1766 break;
1767 case IGN:
1768 cursor_rel (1, 0);
1769 break;
1770 case CR:
1771 cursor_get (&x, &y);
1772 cursor_set (false, 0, y);
1773 break;
1774 case ERR:
1775 /* Don't print chars marked as ERR chars, except for a ASCII CAN
1776 sequence which is printed as singlebyte chars from the UTF
1777 Basic Latin and Latin 1 Supplement plains. */
1778 if (*found == 0x18)
1779 {
1780 write_replacement_char ();
1781 if (found + 1 < end)
1782 {
1783 ret = __utf8_mbtowc (_REENT, NULL, (const char *) found + 1,
1784 end - found - 1, NULL, &ps);
1785 if (ret != (size_t) -1)
1786 while (ret-- > 0)
1787 {
1788 WCHAR w = *(found + 1);
1789 WriteConsoleW (get_output_handle (), &w, 1, &done, 0);
1790 found++;
1791 }
1792 }
1793 }
1794 break;
1795 case TAB:
1796 cursor_get (&x, &y);
1797 cursor_set (false, 8 * (x / 8 + 1), y);
1798 break;
1799 case NOR:
1800 write_replacement_char ();
1801 break;
1802 }
1803 found++;
1804 }
1805 return found;
1806 }
1807
1808 ssize_t __stdcall
1809 fhandler_console::write (const void *vsrc, size_t len)
1810 {
1811 /* Run and check for ansi sequences */
1812 unsigned const char *src = (unsigned char *) vsrc;
1813 unsigned const char *end = src + len;
1814 /* This might look a bit far fetched, but using the TLS path buffer allows
1815 to allocate a big buffer without using the stack too much. Doing it here
1816 in write instead of in write_normal should be faster, too. */
1817 tmp_pathbuf tp;
1818 write_buf = tp.w_get ();
1819
1820 debug_printf ("%x, %d", vsrc, len);
1821
1822 while (src < end)
1823 {
1824 debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ',
1825 dev_state->state_);
1826 switch (dev_state->state_)
1827 {
1828 case normal:
1829 src = write_normal (src, end);
1830 if (!src) /* write_normal failed */
1831 return -1;
1832 break;
1833 case gotesc:
1834 if (*src == '[') /* CSI Control Sequence Introducer */
1835 {
1836 dev_state->state_ = gotsquare;
1837 dev_state->saw_question_mark = false;
1838 dev_state->saw_greater_than_sign = false;
1839 for (dev_state->nargs_ = 0; dev_state->nargs_ < MAXARGS; dev_state->nargs_++)
1840 dev_state->args_[dev_state->nargs_] = 0;
1841 dev_state->nargs_ = 0;
1842 }
1843 else if (*src == ']') /* OSC Operating System Command */
1844 {
1845 dev_state->rarg = 0;
1846 dev_state->my_title_buf[0] = '\0';
1847 dev_state->state_ = gotrsquare;
1848 }
1849 else if (*src == '(') /* Designate G0 character set */
1850 {
1851 dev_state->state_ = gotparen;
1852 }
1853 else if (*src == ')') /* Designate G1 character set */
1854 {
1855 dev_state->state_ = gotrparen;
1856 }
1857 else if (*src == 'M') /* Reverse Index (scroll down) */
1858 {
1859 dev_state->fillin_info (get_output_handle ());
1860 scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + 1);
1861 dev_state->state_ = normal;
1862 }
1863 else if (*src == 'c') /* RIS Full Reset */
1864 {
1865 dev_state->set_default_attr ();
1866 clear_screen (0, 0, -1, -1);
1867 cursor_set (true, 0, 0);
1868 dev_state->state_ = normal;
1869 }
1870 else if (*src == '8') /* DECRC Restore cursor position */
1871 {
1872 cursor_set (true, dev_state->savex, dev_state->savey);
1873 dev_state->state_ = normal;
1874 }
1875 else if (*src == '7') /* DECSC Save cursor position */
1876 {
1877 cursor_get (&dev_state->savex, &dev_state->savey);
1878 dev_state->savey -= dev_state->info.winTop;
1879 dev_state->state_ = normal;
1880 }
1881 else if (*src == 'R') /* ? */
1882 dev_state->state_ = normal;
1883 else
1884 {
1885 dev_state->state_ = normal;
1886 }
1887 src++;
1888 break;
1889 case gotarg1:
1890 if (isdigit (*src))
1891 {
1892 dev_state->args_[dev_state->nargs_] = dev_state->args_[dev_state->nargs_] * 10 + *src - '0';
1893 src++;
1894 }
1895 else if (*src == ';')
1896 {
1897 src++;
1898 dev_state->nargs_++;
1899 if (dev_state->nargs_ >= MAXARGS)
1900 dev_state->nargs_--;
1901 }
1902 else
1903 {
1904 dev_state->state_ = gotcommand;
1905 }
1906 break;
1907 case gotcommand:
1908 char_command (*src++);
1909 dev_state->state_ = normal;
1910 break;
1911 case gotrsquare:
1912 if (isdigit (*src))
1913 dev_state->rarg = dev_state->rarg * 10 + (*src - '0');
1914 else if (*src == ';' && (dev_state->rarg == 2 || dev_state->rarg == 0))
1915 dev_state->state_ = gettitle;
1916 else
1917 dev_state->state_ = eattitle;
1918 src++;
1919 break;
1920 case eattitle:
1921 case gettitle:
1922 {
1923 int n = strlen (dev_state->my_title_buf);
1924 if (*src < ' ')
1925 {
1926 if (*src == '\007' && dev_state->state_ == gettitle)
1927 {
1928 if (old_title)
1929 strcpy (old_title, dev_state->my_title_buf);
1930 set_console_title (dev_state->my_title_buf);
1931 }
1932 dev_state->state_ = normal;
1933 }
1934 else if (n < TITLESIZE)
1935 {
1936 dev_state->my_title_buf[n++] = *src;
1937 dev_state->my_title_buf[n] = '\0';
1938 }
1939 src++;
1940 break;
1941 }
1942 case gotsquare:
1943 if (*src == ';')
1944 {
1945 dev_state->state_ = gotarg1;
1946 dev_state->nargs_++;
1947 src++;
1948 }
1949 else if (isalpha (*src))
1950 dev_state->state_ = gotcommand;
1951 else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
1952 {
1953 if (*src == '?')
1954 dev_state->saw_question_mark = true;
1955 else if (*src == '>')
1956 dev_state->saw_greater_than_sign = true;
1957 /* ignore any extra chars between [ and first arg or command */
1958 src++;
1959 }
1960 else
1961 dev_state->state_ = gotarg1;
1962 break;
1963 case gotparen:
1964 if (*src == '0')
1965 dev_state->vt100_graphics_mode_active = true;
1966 else
1967 dev_state->vt100_graphics_mode_active = false;
1968 dev_state->state_ = normal;
1969 src++;
1970 break;
1971 case gotrparen:
1972 /* This is not strictly needed, ^N/^O can just always be enabled */
1973 if (*src == '0')
1974 /*dev_state->vt100_graphics_mode_SOSI_enabled = true*/;
1975 else
1976 /*dev_state->vt100_graphics_mode_SOSI_enabled = false*/;
1977 dev_state->state_ = normal;
1978 src++;
1979 break;
1980 }
1981 }
1982
1983 syscall_printf ("%d = fhandler_console::write (,..%d)", len, len);
1984
1985 return len;
1986 }
1987
1988 static struct {
1989 int vk;
1990 const char *val[4];
1991 } keytable[] NO_COPY = {
1992 /* NORMAL */ /* SHIFT */ /* CTRL */ /* CTRL-SHIFT */
1993 /* Unmodified and Alt-modified keypad keys comply with linux console
1994 SHIFT, CTRL, CTRL-SHIFT modifiers comply with xterm modifier usage */
1995 {VK_NUMPAD5, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
1996 {VK_CLEAR, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
1997 {VK_LEFT, {"\033[D", "\033[1;2D", "\033[1;5D", "\033[1;6D"}},
1998 {VK_RIGHT, {"\033[C", "\033[1;2C", "\033[1;5C", "\033[1;6C"}},
1999 {VK_UP, {"\033[A", "\033[1;2A", "\033[1;5A", "\033[1;6A"}},
2000 {VK_DOWN, {"\033[B", "\033[1;2B", "\033[1;5B", "\033[1;6B"}},
2001 {VK_PRIOR, {"\033[5~", "\033[5;2~", "\033[5;5~", "\033[5;6~"}},
2002 {VK_NEXT, {"\033[6~", "\033[6;2~", "\033[6;5~", "\033[6;6~"}},
2003 {VK_HOME, {"\033[1~", "\033[1;2~", "\033[1;5~", "\033[1;6~"}},
2004 {VK_END, {"\033[4~", "\033[4;2~", "\033[4;5~", "\033[4;6~"}},
2005 {VK_INSERT, {"\033[2~", "\033[2;2~", "\033[2;5~", "\033[2;6~"}},
2006 {VK_DELETE, {"\033[3~", "\033[3;2~", "\033[3;5~", "\033[3;6~"}},
2007 /* F1...F12, SHIFT-F1...SHIFT-F10 comply with linux console
2008 F6...F12, and all modified F-keys comply with rxvt (compatible extension) */
2009 {VK_F1, {"\033[[A", "\033[23~", "\033[11^", "\033[23^"}},
2010 {VK_F2, {"\033[[B", "\033[24~", "\033[12^", "\033[24^"}},
2011 {VK_F3, {"\033[[C", "\033[25~", "\033[13^", "\033[25^"}},
2012 {VK_F4, {"\033[[D", "\033[26~", "\033[14^", "\033[26^"}},
2013 {VK_F5, {"\033[[E", "\033[28~", "\033[15^", "\033[28^"}},
2014 {VK_F6, {"\033[17~", "\033[29~", "\033[17^", "\033[29^"}},
2015 {VK_F7, {"\033[18~", "\033[31~", "\033[18^", "\033[31^"}},
2016 {VK_F8, {"\033[19~", "\033[32~", "\033[19^", "\033[32^"}},
2017 {VK_F9, {"\033[20~", "\033[33~", "\033[20^", "\033[33^"}},
2018 {VK_F10, {"\033[21~", "\033[34~", "\033[21^", "\033[34^"}},
2019 {VK_F11, {"\033[23~", "\033[23$", "\033[23^", "\033[23@"}},
2020 {VK_F12, {"\033[24~", "\033[24$", "\033[24^", "\033[24@"}},
2021 /* CTRL-6 complies with Windows cmd console but should be fixed */
2022 {'6', {NULL, NULL, "\036", NULL}},
2023 /* Table end marker */
2024 {0}
2025 };
2026
2027 const char *
2028 get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
2029 {
2030 #define NORMAL 0
2031 #define SHIFT 1
2032 #define CONTROL 2
2033 /*#define CONTROLSHIFT 3*/
2034
2035 int modifier_index = NORMAL;
2036 if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
2037 modifier_index = SHIFT;
2038 if (input_rec.Event.KeyEvent.dwControlKeyState &
2039 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
2040 modifier_index += CONTROL;
2041
2042 for (int i = 0; keytable[i].vk; i++)
2043 if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
2044 {
2045 if ((input_rec.Event.KeyEvent.dwControlKeyState &
2046 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
2047 && keytable[i].val[modifier_index] != NULL)
2048 { /* Generic ESC prefixing if Alt is pressed */
2049 tmp[0] = '\033';
2050 strcpy (tmp + 1, keytable[i].val[modifier_index]);
2051 return tmp;
2052 }
2053 else
2054 return keytable[i].val[modifier_index];
2055 }
2056
2057 if (input_rec.Event.KeyEvent.uChar.AsciiChar)
2058 {
2059 tmp[0] = input_rec.Event.KeyEvent.uChar.AsciiChar;
2060 tmp[1] = '\0';
2061 return tmp;
2062 }
2063 return NULL;
2064 }
2065
2066 int
2067 fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
2068 {
2069 // this->fhandler_termios::init (f, mode, bin);
2070 /* Ensure both input and output console handles are open */
2071 int flags = 0;
2072
2073 a &= GENERIC_READ | GENERIC_WRITE;
2074 if (a == GENERIC_READ)
2075 flags = O_RDONLY;
2076 if (a == GENERIC_WRITE)
2077 flags = O_WRONLY;
2078 if (a == (GENERIC_READ | GENERIC_WRITE))
2079 flags = O_RDWR;
2080 open (flags | O_BINARY);
2081 if (f != INVALID_HANDLE_VALUE)
2082 CloseHandle (f); /* Reopened by open */
2083
2084 return !tcsetattr (0, &tc->ti);
2085 }
2086
2087 int
2088 fhandler_console::igncr_enabled ()
2089 {
2090 return tc->ti.c_iflag & IGNCR;
2091 }
2092
2093 void
2094 fhandler_console::set_close_on_exec (bool val)
2095 {
2096 fhandler_base::set_close_on_exec (val);
2097 set_no_inheritance (output_handle, val);
2098 }
2099
2100 void __stdcall
2101 set_console_title (char *title)
2102 {
2103 wchar_t buf[TITLESIZE + 1];
2104 sys_mbstowcs (buf, TITLESIZE + 1, title);
2105 lock_ttys here (15000);
2106 SetConsoleTitleW (buf);
2107 debug_printf ("title '%W'", buf);
2108 }
2109
2110 void
2111 fhandler_console::fixup_after_fork_exec (bool execing)
2112 {
2113 HANDLE h = get_handle ();
2114 HANDLE oh = get_output_handle ();
2115
2116 if ((execing && close_on_exec ()) || open (O_NOCTTY | get_flags (), 0))
2117 cygheap->manage_console_count ("fhandler_console::fixup_after_fork_exec", -1);
2118 else
2119 {
2120 bool sawerr = false;
2121 if (!get_io_handle ())
2122 {
2123 system_printf ("error opening input console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
2124 sawerr = true;
2125 }
2126 if (!get_output_handle ())
2127 {
2128 system_printf ("error opening output console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
2129 sawerr = true;
2130 }
2131
2132 if (!sawerr)
2133 system_printf ("error opening console after fork/exec, errno %d, %E", get_errno ());
2134 }
2135
2136 if (!close_on_exec ())
2137 {
2138 CloseHandle (h);
2139 CloseHandle (oh);
2140 }
2141 }
2142
2143 bool NO_COPY fhandler_console::invisible_console;
2144
2145 // #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
2146 #define WINSTA_ACCESS WINSTA_ALL_ACCESS
2147
2148 /* Create a console in an invisible window station. This should work
2149 in all versions of Windows NT except Windows 7 (so far). */
2150 bool
2151 fhandler_console::create_invisible_console (HWINSTA horig)
2152 {
2153 HWINSTA h = CreateWindowStationW (NULL, 0, WINSTA_ACCESS, NULL);
2154 termios_printf ("%p = CreateWindowStation(NULL), %E", h);
2155 BOOL b;
2156 if (h)
2157 {
2158 b = SetProcessWindowStation (h);
2159 termios_printf ("SetProcessWindowStation %d, %E", b);
2160 }
2161 b = AllocConsole (); /* will cause flashing if CreateWindowStation
2162 failed */
2163 if (!h)
2164 SetParent (GetConsoleWindow (), HWND_MESSAGE);
2165 if (horig && h && h != horig && SetProcessWindowStation (horig))
2166 CloseWindowStation (h);
2167 termios_printf ("%d = AllocConsole (), %E", b);
2168 invisible_console = true;
2169 return b;
2170 }
2171
2172 /* Ugly workaround for Windows 7.
2173
2174 First try to just attach to any console which may have started this
2175 app. If that works use this as our "invisible console".
2176
2177 This will fail if not started from the command prompt. In that case, start
2178 a dummy console application in a hidden state so that we can use its console
2179 as our invisible console. This probably works everywhere but process
2180 creation is slow and to be avoided if possible so the window station method
2181 is vastly preferred.
2182
2183 FIXME: This is not completely thread-safe since it creates two inheritable
2184 handles which are known only to this function. If another thread starts
2185 a process the new process will inherit these handles. However, since this
2186 function is currently only called at startup and during exec, it shouldn't
2187 be a big deal. */
2188 bool
2189 fhandler_console::create_invisible_console_workaround ()
2190 {
2191 if (!AttachConsole (-1))
2192 {
2193 bool taskbar;
2194 DWORD err = GetLastError ();
2195 path_conv helper ("/bin/cygwin-console-helper.exe");
2196 HANDLE hello = NULL;
2197 HANDLE goodbye = NULL;
2198 /* If err == ERROR_PROC_FOUND then this method won't work. But that's
2199 ok. The window station method should work ok when AttachConsole doesn't
2200 work.
2201
2202 If the helper doesn't exist or we can't create event handles then we
2203 can't use this method. */
2204 if (err == ERROR_PROC_NOT_FOUND || !helper.exists ()
2205 || !(hello = CreateEvent (&sec_none, true, false, NULL))
2206 || !(goodbye = CreateEvent (&sec_none, true, false, NULL)))
2207 {
2208 AllocConsole (); /* This is just sanity check code. We should
2209 never actually hit here unless we're running
2210 in an environment which lacks the helper
2211 app. */
2212 taskbar = true;
2213 }
2214 else
2215 {
2216 STARTUPINFOW si = {};
2217 PROCESS_INFORMATION pi;
2218 size_t len = helper.get_wide_win32_path_len ();
2219 WCHAR cmd[len + (2 * strlen (" 0xffffffff")) + 1];
2220 WCHAR title[] = L"invisible cygwin console";
2221
2222 helper.get_wide_win32_path (cmd);
2223 __small_swprintf (cmd + len, L" %p %p", hello, goodbye);
2224
2225 si.cb = sizeof (si);
2226 si.dwFlags = STARTF_USESHOWWINDOW;
2227 si.wShowWindow = SW_HIDE;
2228 si.lpTitle = title;
2229
2230 /* Create a new hidden process. Use the two event handles as
2231 argv[1] and argv[2]. */
2232 BOOL x = CreateProcessW (NULL, cmd, &sec_none_nih, &sec_none_nih, true,
2233 CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2234 if (x)
2235 {
2236 CloseHandle (pi.hProcess); /* Don't need */
2237 CloseHandle (pi.hThread); /* these. */
2238 }
2239 taskbar = false;
2240 /* Wait for subprocess to indicate that it is live. This may not
2241 actually be needed but it's hard to say since it is possible that
2242 there will be no console for a brief time after the process
2243 returns and there is no easy way to determine if/when this happens
2244 in Windows. So play it safe. */
2245 if (!x || (WaitForSingleObject (hello, 10000) != WAIT_OBJECT_0)
2246 || !AttachConsole (pi.dwProcessId))
2247 AllocConsole (); /* Oh well. Watch the flash. */
2248 }
2249
2250 if (!taskbar)
2251 /* Setting the owner of the console window to HWND_MESSAGE seems to
2252 hide it from the taskbar. Don't know if this method is faster than
2253 calling ShowWindowAsync but it should guarantee no taskbar presence
2254 for the hidden console. */
2255 SetParent (GetConsoleWindow (), HWND_MESSAGE);
2256 if (hello)
2257 CloseHandle (hello);
2258 if (goodbye)
2259 {
2260 SetEvent (goodbye); /* Tell helper process it's ok to exit. */
2261 CloseHandle (goodbye);
2262 }
2263 }
2264 return invisible_console = true;
2265 }
2266
2267 bool
2268 fhandler_console::need_invisible ()
2269 {
2270 BOOL b = false;
2271 if (GetConsoleCP ())
2272 invisible_console = false;
2273 else
2274 {
2275 HWINSTA h;
2276 /* The intent here is to allocate an "invisible" console if we have no
2277 controlling tty or to reuse the existing console if we already have
2278 a tty. So, first get the old window station. If there is no controlling
2279 terminal, create a new window station and then set it as the current
2280 window station. The subsequent AllocConsole will then be allocated
2281 invisibly. But, after doing that we have to restore any existing windows
2282 station or, strangely, characters will not be displayed in any windows
2283 drawn on the current screen. We only do this if we have changed to
2284 a new window station and if we had an existing windows station previously.
2285 We also close the previously opened window station even though AllocConsole
2286 is now "using" it. This doesn't seem to cause any problems.
2287
2288 Things to watch out for if you make changes in this code:
2289
2290 - Flashing, black consoles showing up when you start, e.g., ssh in
2291 an xterm.
2292 - Non-displaying of characters in rxvt or xemacs if you start a
2293 process using setsid: bash -lc "setsid rxvt". */
2294
2295 h = GetProcessWindowStation ();
2296
2297 USEROBJECTFLAGS oi;
2298 DWORD len;
2299 if (!h
2300 || !GetUserObjectInformationW (h, UOI_FLAGS, &oi, sizeof (oi), &len)
2301 || !(oi.dwFlags & WSF_VISIBLE))
2302 {
2303 b = true;
2304 debug_printf ("window station is not visible");
2305 AllocConsole ();
2306 invisible_console = true;
2307 }
2308 else if (wincap.has_broken_alloc_console ())
2309 b = create_invisible_console_workaround ();
2310 else
2311 b = create_invisible_console (h);
2312 }
2313
2314 debug_printf ("invisible_console %d", invisible_console);
2315 return b;
2316 }
This page took 0.143877 seconds and 5 git commands to generate.