OSDN Git Service

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