OSDN Git Service

* fhandler.cc (fhandler_base::get_readahead_into_buffer): New function.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fhandler_console.cc
1 /* fhandler_console.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 /* FIXMES:
12    Should the constructor call tcinit() explicitly rather than having
13    it sprinkled throughout here? */
14
15 #include <sys/termios.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include "winsup.h"
22 #include <ctype.h>
23
24 /*
25  * Scroll the screen context.
26  * x1, y1 - ul corner
27  * x2, y2 - dr corner
28  * xn, yn - new ul corner
29  * Negative values represents current screen dimensions
30  */
31 static struct
32     {
33       short Top, Bottom;
34     } scroll_region = {0, -1};
35
36 #define srTop (info.winTop + scroll_region.Top)
37 #define srBottom ((scroll_region.Bottom < 0) ? info.winBottom : info.winTop + scroll_region.Bottom)
38
39 #define use_tty ISSTATE (myself, PID_USETTY)
40
41 const char * get_nonascii_key (INPUT_RECORD& input_rec);
42
43 HANDLE console_shared_h;
44
45 static tty_min NO_COPY *shared_console_info = NULL;
46
47 /* Allocate and initialize the shared record for the current console.
48    Returns a pointer to shared_console_info. */
49 static __inline tty_min *
50 get_tty_stuff (int force = 0)
51 {
52   if (shared_console_info && !force)
53     return shared_console_info;
54
55   shared_console_info = (tty_min *) open_shared (NULL, console_shared_h,
56                                                  sizeof (*shared_console_info),
57                                                  NULL);
58   ProtectHandle (console_shared_h);
59   shared_console_info->setntty (TTY_CONSOLE);
60   shared_console_info->setsid (myself->sid);
61   return shared_console_info;
62 }
63
64 /* Return the tty structure associated with a given tty number.  If the
65    tty number is < 0, just return a dummy record. */
66 tty_min *
67 tty_list::get_tty (int n)
68 {
69   static tty_min nada;
70   if (n == TTY_CONSOLE)
71     return get_tty_stuff ();
72   else if (n >= 0)
73     return &cygwin_shared->tty.ttys[n];
74   else
75     return &nada;
76 }
77
78
79 /* Determine if a console is associated with this process prior to a spawn.
80    If it is, then we'll return 1.  If the console has been initialized, then
81    set it into a more friendly state for non-cygwin apps. */
82 int __stdcall
83 set_console_state_for_spawn ()
84 {
85   HANDLE h = CreateFileA ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
86                           &sec_none_nih, OPEN_EXISTING,
87                           FILE_ATTRIBUTE_NORMAL, NULL);
88
89   if (h == INVALID_HANDLE_VALUE || h == NULL)
90     return 0;
91
92   if (shared_console_info != NULL)
93     {
94 #     define tc shared_console_info     /* ACK.  Temporarily define for use in TTYSETF macro */
95       SetConsoleMode (h, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
96       TTYSETF (RSTCONS);
97 #if 0
98       char ch;
99       DWORD n;
100       /* NOTE -- This ReadFile is apparently necessary for correct functioning on
101          Windows NT 4.0.  Without this, the next ReadFile returns garbage.  */
102       (void) ReadFile (h, &ch, 0, &n, NULL);
103 #endif
104 #     undef tc
105     }
106
107   CloseHandle (h);
108   return 1;
109 }
110
111 int
112 fhandler_console::read (void *pv, size_t buflen)
113 {
114   if (!buflen)
115     return 0;
116
117   HANDLE h = get_io_handle ();
118
119 #define buf ((char *) pv)
120
121   int ch;
122   set_input_state ();
123
124   int copied_chars = get_readahead_into_buffer (buf, buflen);
125
126   if (copied_chars)
127     return copied_chars;
128
129   HANDLE w4[2];
130   DWORD nwait;
131
132   w4[0] = h;
133   if (iscygthread ())
134     nwait = 1;
135   else
136     {
137       w4[1] = signal_arrived;
138       nwait = 2;
139     }
140
141   for (;;)
142     {
143       int bgres;
144       if ((bgres = bg_check (SIGTTIN)) <= 0)
145         return bgres;
146
147       switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE))
148         {
149         case WAIT_OBJECT_0:
150           break;
151         case WAIT_OBJECT_0 + 1:
152           set_sig_errno (EINTR);
153           return -1;
154         default:
155           __seterrno ();
156           return -1;
157         }
158       DWORD nread;
159       INPUT_RECORD input_rec;
160       const char *toadd;
161
162       if (!ReadConsoleInput (h, &input_rec, 1, &nread))
163         {
164           syscall_printf ("ReadConsoleInput failed, %E");
165           __seterrno ();
166           return -1;            /* seems to be failure */
167         }
168
169 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
170
171       /* check if we're just disposing of this one */
172
173       if (input_rec.EventType == WINDOW_BUFFER_SIZE_EVENT)
174         {
175           kill_pgrp (tc->getpgid (), SIGWINCH);
176           continue;
177         }
178       if (input_rec.EventType != KEY_EVENT ||
179           !input_rec.Event.KeyEvent.bKeyDown)
180         continue;
181
182       if (ich == 0)  /* arrow/function keys */
183         {
184           toadd = get_nonascii_key (input_rec);
185           if (!toadd)
186             continue;
187           nread = strlen (toadd);
188         }
189       else if (!(input_rec.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED))
190         toadd = &ich;
191       else
192         {
193           static char tmp[2];
194           tmp[0] = '\033';
195           tmp[1] = tolower (ich);
196           toadd = tmp;
197           nread = 2;
198         }
199
200       if (line_edit (toadd, nread))
201         break;
202 #undef ich
203     }
204
205   while (buflen)
206     if ((ch = get_readahead ()) < 0)
207       break;
208     else
209       {
210         buf[copied_chars++] = (unsigned char)(ch & 0xff);
211         buflen--;
212       }
213 #undef buf
214
215   return copied_chars;
216 }
217
218 static struct
219   {
220     SHORT winTop;
221     SHORT winBottom;
222     COORD dwWinSize;
223     COORD dwCursorPosition;
224     WORD wAttributes;
225   } info;
226
227 BOOL
228 fhandler_console::fillin_info (void)
229 {
230   BOOL ret;
231   CONSOLE_SCREEN_BUFFER_INFO linfo;
232
233   if ((ret = GetConsoleScreenBufferInfo (get_output_handle(), &linfo)))
234     {
235       info.winTop = linfo.srWindow.Top;
236       info.winBottom = linfo.srWindow.Bottom;
237       info.dwWinSize.Y = 1 + linfo.srWindow.Bottom - linfo.srWindow.Top;
238       info.dwWinSize.X = 1 + linfo.srWindow.Right - linfo.srWindow.Left;
239       info.dwCursorPosition = linfo.dwCursorPosition;
240       info.wAttributes = linfo.wAttributes;
241     }
242   else
243     {
244       memset (&info, 0, sizeof info);
245       info.dwWinSize.Y = 25;
246       info.dwWinSize.X = 80;
247       info.winBottom = 24;
248     }
249
250   return ret;
251 }
252
253 void
254 fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
255 {
256   SMALL_RECT sr1, sr2;
257   CHAR_INFO fill;
258   COORD dest;
259
260   (void)fillin_info ();
261   sr1.Left = x1 >= 0 ? x1 : info.dwWinSize.X - 1;
262   if (y1 == 0)
263     sr1.Top = info.winTop;
264   else
265     sr1.Top = y1 > 0 ? y1 : info.winBottom;
266   sr1.Right = x2 >= 0 ? x2 : info.dwWinSize.X - 1;
267   if (y2 == 0)
268     sr1.Bottom = info.winTop;
269   else
270     sr1.Bottom = y2 > 0 ? y2 : info.winBottom;
271   sr2.Top = srTop;
272   sr2.Left = 0;
273   sr2.Bottom = srBottom;
274   sr2.Right = info.dwWinSize.X - 1;
275   if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom)
276     sr1.Bottom = sr2.Bottom;
277   dest.X = xn >= 0 ? xn : info.dwWinSize.X - 1;
278   if (yn == 0)
279     dest.Y = info.winTop;
280   else
281     dest.Y = yn > 0 ? yn : info.winBottom;
282   fill.Char.AsciiChar = ' ';
283   fill.Attributes = default_color;
284   ScrollConsoleScreenBuffer (get_output_handle (), &sr1, &sr2, dest, &fill);
285
286   /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
287    * is more than half of screen, filling doesn't work as expected */
288
289   if (sr1.Top != sr1.Bottom)
290     if (dest.Y <= sr1.Top)      /* forward scroll */
291       clear_screen (0, 1 + dest.Y + sr1.Bottom - sr1.Top, sr2.Right, sr2.Bottom);
292     else                        /* reverse scroll */
293       clear_screen (0, sr1.Top, sr2.Right, dest.Y - 1);
294 }
295
296 int
297 fhandler_console::open (const char *, int flags, mode_t)
298 {
299   HANDLE h;
300
301   tcinit (get_tty_stuff ());
302
303   set_io_handle (INVALID_HANDLE_VALUE);
304   set_output_handle (INVALID_HANDLE_VALUE);
305
306   set_flags (flags);
307
308   /* Open the input handle as handle_ */
309   h = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE,
310                    FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
311                    OPEN_EXISTING, 0, 0);
312
313   if (h == INVALID_HANDLE_VALUE)
314     {
315       __seterrno ();
316       return 0;
317     }
318   set_io_handle (h);
319   set_r_no_interrupt (1);       // Handled explicitly in read code
320
321   h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
322                    FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none,
323                    OPEN_EXISTING, 0, 0);
324
325   if (h == INVALID_HANDLE_VALUE)
326     {
327       __seterrno ();
328       return 0;
329     }
330   set_output_handle (h);
331
332   if (fillin_info ())
333     default_color = info.wAttributes;
334
335   DWORD cflags;
336   if (GetConsoleMode (get_io_handle (), &cflags))
337     {
338       cflags |= ENABLE_PROCESSED_INPUT;
339       SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT | cflags);
340     }
341
342   TTYCLEARF (RSTCONS);
343   set_ctty (TTY_CONSOLE, flags);
344   debug_printf("opened conin$ %p, conout$ %p",
345                 get_io_handle (), get_output_handle ());
346
347   return 1;
348 }
349
350 int
351 fhandler_console::close (void)
352 {
353   CloseHandle (get_io_handle ());
354   CloseHandle (get_output_handle ());
355   set_io_handle (INVALID_HANDLE_VALUE);
356   set_output_handle (INVALID_HANDLE_VALUE);
357   return 0;
358 }
359
360 /*
361  * Special console dup to duplicate input and output
362  * handles.
363  */
364
365 int
366 fhandler_console::dup (fhandler_base *child)
367 {
368   fhandler_console *fhc = (fhandler_console *) child;
369
370   if (!fhc->open(get_name (), get_flags (), 0))
371     system_printf ("error opening console, %E");
372
373   fhc->state_ = state_;
374   fhc->default_color = default_color;
375
376   return 0;
377 }
378
379 int
380 fhandler_console::ioctl (unsigned int cmd, void *buf)
381 {
382   switch (cmd)
383     {
384       case TIOCGWINSZ:
385         int st;
386
387         st = fillin_info ();
388         if (st)
389           {
390             /* *not* the buffer size, the actual screen size... */
391             /* based on Left Top Right Bottom of srWindow */
392             ((struct winsize *) buf)->ws_row = info.dwWinSize.Y;
393             ((struct winsize *) buf)->ws_col = info.dwWinSize.X;
394             syscall_printf ("WINSZ: (row=%d,col=%d)",
395                            ((struct winsize *) buf)->ws_row,
396                            ((struct winsize *) buf)->ws_col);
397             return 0;
398           }
399         else
400           {
401             syscall_printf ("WINSZ failed");
402             __seterrno ();
403             return -1;
404           }
405         return 0;
406       case TIOCSWINSZ:
407         (void) bg_check (SIGTTOU);
408         return 0;
409     }
410
411   return fhandler_base::ioctl (cmd, buf);
412 }
413
414 int
415 fhandler_console::tcflush (int queue)
416 {
417   int res = 0;
418   if (queue == TCIFLUSH
419       || queue == TCIOFLUSH)
420     {
421       if (!FlushConsoleInputBuffer (get_io_handle ()))
422         {
423           __seterrno ();
424           res = -1;
425         }
426     }
427   return res;
428 }
429
430 int
431 fhandler_console::output_tcsetattr (int, struct termios const *t)
432 {
433   /* Ignore the optional_actions stuff, since all output is emitted
434      instantly */
435
436   /* Enable/disable LF -> CRLF conversions */
437   set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
438
439   /* All the output bits we can ignore */
440
441   DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
442
443   int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
444   syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)",
445                   res, t, flags, t->c_lflag, t->c_oflag);
446   return res;
447 }
448
449 int
450 fhandler_console::input_tcsetattr (int, struct termios const *t)
451 {
452   /* Ignore the optional_actions stuff, since all output is emitted
453      instantly */
454
455   DWORD oflags;
456
457   if (!GetConsoleMode (get_io_handle (), &oflags))
458     oflags = 0;
459   DWORD flags = 0;
460
461   /* Enable/disable LF -> CRLF conversions */
462   set_r_binary ((t->c_iflag & INLCR) ? 0 : 1);
463
464   /* There's some disparity between what we need and what's
465      available.  We've got ECHO and ICANON, they've
466      got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
467
468   tc->ti = *t;
469
470   if (t->c_lflag & ECHO)
471     {
472       flags |= ENABLE_ECHO_INPUT;
473     }
474   if (t->c_lflag & ICANON)
475     {
476       flags |= ENABLE_LINE_INPUT;
477     }
478
479   if (flags & ENABLE_ECHO_INPUT
480       && !(flags & ENABLE_LINE_INPUT))
481     {
482       /* This is illegal, so turn off the echo here, and fake it
483          when we read the characters */
484
485       flags &= ~ENABLE_ECHO_INPUT;
486     }
487
488   if (t->c_lflag & ISIG)
489     {
490       flags |= ENABLE_PROCESSED_INPUT;
491     }
492   /* What about ENABLE_WINDOW_INPUT
493      and ENABLE_MOUSE_INPUT   ? */
494
495   if (use_tty)
496     {
497       flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
498       tc->ti.c_iflag = 0;
499       tc->ti.c_lflag = 0;
500     }
501
502   flags |= ENABLE_WINDOW_INPUT;
503
504   int res;
505   if (flags == oflags)
506     res = 0;
507   else
508     {
509       res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1;
510       if (res < 0)
511         __seterrno ();
512       syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
513                       res, t, flags, t->c_lflag, t->c_iflag);
514     }
515
516   TTYCLEARF (RSTCONS);
517   return res;
518 }
519
520 int
521 fhandler_console::tcsetattr (int a, struct termios const *t)
522 {
523   int res = output_tcsetattr (a, t);
524   if (res != 0)
525     return res;
526   return input_tcsetattr (a, t);
527 }
528
529 int
530 fhandler_console::tcgetattr (struct termios *t)
531 {
532   int res;
533   *t = tc->ti;
534
535   t->c_cflag |= CS8;
536
537 #if 0
538   if (!get_r_binary ())
539     t->c_iflag |= IGNCR;
540   if (!get_w_binary ())
541     t->c_oflag |= ONLCR;
542 #endif
543
544   DWORD flags;
545
546   if (!GetConsoleMode (get_io_handle (), &flags))
547     {
548       __seterrno ();
549       res = -1;
550     }
551   else
552     {
553       if (flags & ENABLE_ECHO_INPUT)
554         t->c_lflag |= ECHO;
555
556       if (flags & ENABLE_LINE_INPUT)
557         t->c_lflag |= ICANON;
558
559       if (flags & ENABLE_PROCESSED_INPUT)
560         t->c_lflag |= ISIG;
561
562       /* What about ENABLE_WINDOW_INPUT
563          and ENABLE_MOUSE_INPUT   ? */
564
565       /* All the output bits we can ignore */
566       res = 0;
567     }
568   syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p",
569                  res, t, flags, t->c_lflag, t->c_iflag);
570   return res;
571 }
572
573 /*
574  * Constructor.
575  */
576
577 fhandler_console::fhandler_console (const char *name) :
578   fhandler_termios (FH_CONSOLE, name, -1)
579 {
580   set_cb (sizeof *this);
581   state_ = normal;
582   set_need_fork_fixup ();
583 }
584
585 /*
586  * Clear the screen context from x1/y1 to x2/y2 cell.
587  * Negative values represents current screen dimensions
588  */
589 void
590 fhandler_console::clear_screen (int x1, int y1, int x2, int y2)
591 {
592   COORD tlc;
593   DWORD done;
594   int num;
595
596   (void)fillin_info ();
597
598   if (x1 < 0)
599     x1 = info.dwWinSize.X-1;
600   if (y1 < 0)
601     y1 = info.winBottom;
602   if (x2 < 0)
603     x2 = info.dwWinSize.X-1;
604   if (y2 < 0)
605     y2 = info.winBottom;
606
607   num = abs (y1 - y2) * info.dwWinSize.X + abs (x1 - x2) + 1;
608
609   if ((y2 * info.dwWinSize.X + x2) > (y1 * info.dwWinSize.X + x1))
610     {
611       tlc.X = x1;
612       tlc.Y = y1;
613     }
614   else
615     {
616       tlc.X = x2;
617       tlc.Y = y2;
618     }
619   FillConsoleOutputCharacterA (get_output_handle (), ' ',
620                                num,
621                                tlc,
622                                &done);
623   FillConsoleOutputAttribute (get_output_handle (),
624                                default_color,
625                                num,
626                                tlc,
627                                &done);
628 }
629
630 void
631 fhandler_console::cursor_set (BOOL rel_to_top, int x, int y)
632 {
633   COORD pos;
634
635   (void)fillin_info ();
636   if (y > info.winBottom)
637     y = info.winBottom;
638   else if (y < 0)
639     y = 0;
640   else if (rel_to_top)
641     y += info.winTop;
642
643   if (x > info.dwWinSize.X)
644     x = info.dwWinSize.X - 1;
645   else if (x < 0)
646     x = 0;
647
648   pos.X = x;
649   pos.Y = y;
650   SetConsoleCursorPosition (get_output_handle (), pos);
651 }
652
653 void
654 fhandler_console::cursor_rel (int x, int y)
655 {
656   fillin_info ();
657   x += info.dwCursorPosition.X;
658   y += info.dwCursorPosition.Y;
659   cursor_set (FALSE, x, y);
660 }
661
662 void
663 fhandler_console::cursor_get (int *x, int *y)
664 {
665   fillin_info ();
666   *y = info.dwCursorPosition.Y;
667   *x = info.dwCursorPosition.X;
668 }
669
670 #define BAK 1
671 #define ESC 2
672 #define NOR 0
673 #define IGN 4
674 #if 0
675 #define ERR 5
676 #else
677 #define ERR NOR
678 #endif
679 #define DWN 6
680 #define BEL 7
681 #define TAB 8 /* We should't let the console deal with these */
682 #define CR 13
683 #define LF 10
684
685 static const char base_chars[256] =
686 {
687 /*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL,
688 /*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR,  ERR, IGN,
689 /*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR,
690 /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
691 /*   !  "  #  $  %  &  '  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
692 /*(  )  *  +  ,  -  .  /  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
693 /*0  1  2  3  4  5  6  7  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
694 /*8  9  :  ;  <  =  >  ?  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
695 /*@  A  B  C  D  E  F  G  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
696 /*H  I  J  K  L  M  N  O  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
697 /*P  Q  R  S  T  U  V  W  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
698 /*X  Y  Z  [  \  ]  ^  _  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
699 /*`  a  b  c  d  e  f  g  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
700 /*h  i  j  k  l  m  n  o  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
701 /*p  q  r  s  t  u  v  w  */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
702 /*x  y  z  {  |  }  ~  7F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
703 /*80 81 82 83 84 85 86 87 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
704 /*88 89 8A 8B 8C 8D 8E 8F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
705 /*90 91 92 93 94 95 96 97 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
706 /*98 99 9A 9B 9C 9D 9E 9F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
707 /*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
708 /*A8 A9 AA AB AC AD AE AF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
709 /*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
710 /*B8 B9 BA BB BC BD BE BF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
711 /*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
712 /*C8 C9 CA CB CC CD CE CF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
713 /*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
714 /*D8 D9 DA DB DC DD DE DF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
715 /*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
716 /*E8 E9 EA EB EC ED EE EF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
717 /*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
718 /*F8 F9 FA FB FC FD FE FF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR };
719
720 /*#define syscall_printf small_printf*/
721
722 static int savex, savey; /* for CSI s, CSI u */
723
724 void
725 fhandler_console::char_command (char c)
726 {
727   // Keep the background intensity with the colr since there doesn't seem
728   // to be a way to set this with termcap/terminfo.
729   static int fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
730                                    FOREGROUND_RED),
731              bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
732                                    BACKGROUND_RED | BACKGROUND_INTENSITY),
733                          bold = default_color & FOREGROUND_INTENSITY;
734   int x, y;
735   char buf[40];
736
737   switch (c)
738     {
739     case 'm':   /* Set Graphics Rendition */
740        int i;
741
742        for (i = 0; i <= nargs_; i++)
743          switch (args_[i])
744            {
745              case 0:    /* normal color */
746                fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
747                                      FOREGROUND_RED);
748                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
749                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
750                bold = default_color & FOREGROUND_INTENSITY;
751                break;
752              case 1:    /* bold */
753                fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
754                                      FOREGROUND_RED);
755                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
756                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
757                bold = FOREGROUND_INTENSITY;
758                break;
759              case 4:    /* underline - simulate with cyan */
760                fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
761                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
762                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
763                bold = default_color & FOREGROUND_INTENSITY;
764                break;
765              case 5:    /* blink mode */
766                fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
767                                      FOREGROUND_RED);
768                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
769                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
770                bold = default_color & FOREGROUND_INTENSITY;
771                break;
772              case 7:    /* reverse */
773                fg = (default_color & BACKGROUND_BLUE) ? FOREGROUND_BLUE : 0;
774                fg |= (default_color & BACKGROUND_GREEN) ? FOREGROUND_GREEN : 0;
775                fg |= (default_color & BACKGROUND_RED) ? FOREGROUND_RED : 0;
776                fg |= (default_color & BACKGROUND_INTENSITY) ?
777                                              FOREGROUND_INTENSITY : 0;
778                bg = (default_color & FOREGROUND_BLUE) ? BACKGROUND_BLUE : 0;
779                bg |= (default_color & FOREGROUND_GREEN) ? BACKGROUND_GREEN : 0;
780                bg |= (default_color & FOREGROUND_RED) ? BACKGROUND_RED : 0;
781                bg |= (default_color & FOREGROUND_INTENSITY) ?
782                                              BACKGROUND_INTENSITY : 0;
783                break;
784              case 8:    /* invisible */
785                fg = (default_color & BACKGROUND_BLUE) ? FOREGROUND_BLUE : 0;
786                fg |= (default_color & BACKGROUND_GREEN) ? FOREGROUND_GREEN : 0;
787                fg |= (default_color & BACKGROUND_RED) ? FOREGROUND_RED : 0;
788                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
789                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
790                bold = (default_color & BACKGROUND_INTENSITY) ?
791                                                    FOREGROUND_INTENSITY : 0;
792                break;
793              case 9:    /* dim */
794                fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
795                                      FOREGROUND_RED);
796                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
797                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
798                bold = (fg == 0) ? FOREGROUND_INTENSITY : 0;
799                break;
800              case 30:           /* BLACK foreground */
801                fg = 0;
802                break;
803              case 31:           /* RED foreground */
804                fg = FOREGROUND_RED;
805                break;
806              case 32:           /* GREEN foreground */
807                fg = FOREGROUND_GREEN;
808                break;
809              case 33:           /* YELLOW foreground */
810                fg = FOREGROUND_RED | FOREGROUND_GREEN;
811                break;
812              case 34:           /* BLUE foreground */
813                fg = FOREGROUND_BLUE;
814                break;
815              case 35:           /* MAGENTA foreground */
816                fg = FOREGROUND_RED | FOREGROUND_BLUE;
817                break;
818              case 36:           /* CYAN foreground */
819                fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
820                break;
821              case 37:           /* WHITE foreg */
822                fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
823                break;
824              case 40:           /* BLACK background */
825                bg = 0;
826                break;
827              case 41:           /* RED background */
828                bg = BACKGROUND_RED;
829                break;
830              case 42:           /* GREEN background */
831                bg = BACKGROUND_GREEN;
832                break;
833              case 43:           /* YELLOW background */
834                bg = BACKGROUND_RED | BACKGROUND_GREEN;
835                break;
836              case 44:           /* BLUE background */
837                bg = BACKGROUND_BLUE;
838                break;
839              case 45:           /* MAGENTA background */
840                bg = BACKGROUND_RED | BACKGROUND_BLUE;
841                break;
842              case 46:           /* CYAN background */
843                bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
844                break;
845              case 47:    /* WHITE background */
846                bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
847                break;
848              default:
849                fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
850                                      FOREGROUND_RED);
851                bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
852                                      BACKGROUND_RED | BACKGROUND_INTENSITY);
853                bold = default_color & FOREGROUND_INTENSITY;
854                break;
855            }
856          SetConsoleTextAttribute (get_output_handle (), fg | bg | bold);
857       break;
858     case 'h':
859     case 'l':
860       /* Ignore */
861       break;
862     case 'J':
863       switch (args_[0])
864         {
865         case 0:                 /* Clear to end of screen */
866           cursor_get (&x, &y);
867           clear_screen (x, y, -1, -1);
868           break;
869         case 1:                 /* Clear from beginning of screen to cursor */
870           cursor_get (&x, &y);
871           clear_screen (0, 0, x, y);
872           break;
873         case 2:                 /* Clear screen */
874           clear_screen (0, 0, -1, -1);
875           cursor_set (TRUE, 0,0);
876           break;
877         default:
878           goto bad_escape;
879         }
880       break;
881
882     case 'A':
883       cursor_rel (0, -(args_[0] ? args_[0] : 1));
884       break;
885     case 'B':
886       cursor_rel (0, args_[0] ? args_[0] : 1);
887       break;
888     case 'C':
889       cursor_rel (args_[0] ? args_[0] : 1, 0);
890       break;
891     case 'D':
892       cursor_rel (-(args_[0] ? args_[0] : 1),0);
893       break;
894     case 'K':
895       switch (args_[0])
896         {
897           case 0:               /* Clear to end of line */
898             cursor_get (&x, &y);
899             clear_screen (x, y, -1, y);
900             break;
901           case 2:               /* Clear line */
902             cursor_get (&x, &y);
903             clear_screen (0, y, -1, y);
904             break;
905           case 1:               /* Clear from bol to cursor */
906             cursor_get (&x, &y);
907             clear_screen (0, y, x, y);
908             break;
909           default:
910             goto bad_escape;
911         }
912       break;
913     case 'H':
914     case 'f':
915       cursor_set (TRUE, (args_[1] ? args_[1] : 1) - 1,
916                         (args_[0] ? args_[0] : 1) - 1);
917       break;
918     case 'G':   /* hpa - position cursor at column n - 1 */
919       cursor_get (&x, &y);
920       cursor_set (FALSE, (args_[0] ? args_[0] - 1 : 0), y);
921       break;
922     case 'd':   /* vpa - position cursor at line n */
923       cursor_get (&x, &y);
924       cursor_set (TRUE, x, (args_[0] ? args_[0] - 1 : 0));
925       break;
926     case 's':   /* Save cursor position */
927       cursor_get (&savex, &savey);
928       break;
929     case 'u':   /* Restore cursor position */
930       cursor_set (FALSE, savex, savey);
931       break;
932     case 'I':   /* TAB */
933       cursor_get (&x, &y);
934       cursor_set (FALSE, 8*(x/8+1), y);
935       break;
936     case 'L':                           /* AL - insert blank lines */
937       args_[0] = args_[0] ? args_[0] : 1;
938       cursor_get (&x, &y);
939       scroll_screen (0, y, -1, -1, 0, y + args_[0]);
940       break;
941     case 'M':                           /* DL - delete lines */
942       args_[0] = args_[0] ? args_[0] : 1;
943       cursor_get (&x, &y);
944       scroll_screen (0, y + args_[0], -1, -1, 0, y);
945       break;
946     case '@':                           /* IC - insert chars */
947       args_[0] = args_[0] ? args_[0] : 1;
948       cursor_get (&x, &y);
949       scroll_screen (x, y, -1, y, x + args_[0], y);
950       break;
951     case 'P':                           /* DC - delete chars */
952       args_[0] = args_[0] ? args_[0] : 1;
953       cursor_get (&x, &y);
954       scroll_screen (x + args_[0], y, -1, y, x, y);
955       break;
956     case 'S':                           /* SF - Scroll forward */
957       args_[0] = args_[0] ? args_[0] : 1;
958       scroll_screen(0, args_[0], -1, -1, 0, 0);
959       break;
960     case 'T':                           /* SR - Scroll down */
961       fillin_info ();
962       args_[0] = args_[0] ? args_[0] : 1;
963       scroll_screen (0, 0, -1, -1, 0, info.winTop + args_[0]);
964       break;
965     case 'X':                           /* ec - erase chars */
966       args_[0] = args_[0] ? args_[0] : 1;
967       cursor_get (&x, &y);
968       scroll_screen (x + args_[0], y, -1, y, x, y);
969       scroll_screen (x, y, -1, y, x + args_[0], y);
970       break;
971     case 'Z':                           /* Back tab */
972       cursor_get (&x, &y);
973       cursor_set (FALSE, ((8 * (x / 8 + 1)) - 8), y);
974       break;
975     case 'b':                           /* Repeat char #1 #2 times */
976       while (args_[1]--)
977         WriteFile (get_output_handle (), &args_[0], 1, (DWORD *) &x, 0);
978       break;
979     case 'c':                           /* u9 - Terminal enquire string */
980       strcpy (buf, "\033[?6c");
981       puts_readahead (buf);
982       break;
983     case 'n':
984       switch (args_[0])
985         {
986         case 6:                         /* u7 - Cursor position request */
987           cursor_get (&x, &y);
988           y -= info.winTop;
989           /* x -= info.winLeft;         // not available yet */
990           __small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
991           puts_readahead (buf);
992           break;
993     default:
994           goto bad_escape;
995         }
996       break;
997     case 'r':                           /* Set Scroll region */
998       scroll_region.Top = args_[0] ? args_[0] - 1 : 0;
999       scroll_region.Bottom = args_[1] ? args_[1] - 1 : -1;
1000       cursor_set (TRUE, 0, 0);
1001       break;
1002     case 'g':                           /* TAB set/clear */
1003       break;
1004     default:
1005 bad_escape:
1006       break;
1007     }
1008 }
1009
1010 const unsigned char *
1011 fhandler_console::write_normal (const unsigned char *src,
1012                                 const unsigned char *end)
1013 {
1014   /* Scan forward to see what a char which needs special treatment */
1015   DWORD done;
1016   const unsigned char *found = src;
1017
1018   while (found < end)
1019     {
1020       if (base_chars[*found] != NOR)
1021         break;
1022       found++;
1023     }
1024   /* Print all the base ones out */
1025   if (found != src)
1026     {
1027       if (! WriteFile (get_output_handle (), src,  found - src, &done, 0))
1028         {
1029           debug_printf ("write failed, handle %p", get_output_handle ());
1030           __seterrno ();
1031           return 0;
1032         }
1033       src += done;
1034     }
1035   if (src < end)
1036     {
1037       int x, y;
1038       switch (base_chars[*src])
1039         {
1040         case BEL:
1041           Beep (412, 100);
1042           break;
1043         case ESC:
1044           state_ = gotesc;
1045           break;
1046         case DWN:               /* WriteFile("\n") always adds CR... */
1047           cursor_get (&x, &y);
1048           if (y >= srBottom)
1049             {
1050               if (y < info.winBottom || scroll_region.Top)
1051                 {
1052                   scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
1053                   y--;
1054                 }
1055               else
1056                 WriteFile (get_output_handle (), "\n", 1, &done, 0);
1057             }
1058           if (!get_w_binary ())
1059             x = 0;
1060           cursor_set (FALSE, x, y + 1);
1061           break;
1062         case BAK:
1063           cursor_rel (-1, 0);
1064           break;
1065         case IGN:
1066           cursor_rel (1, 0);
1067           break;
1068         case CR:
1069           cursor_get (&x, &y);
1070           cursor_set (FALSE, 0, y);
1071           break;
1072         case ERR:
1073           WriteFile (get_output_handle (), src, 1, &done, 0);
1074           break;
1075         case TAB:
1076           cursor_get (&x, &y);
1077           cursor_set (FALSE, 8 * (x / 8 + 1), y);
1078           break;
1079         }
1080       src ++;
1081     }
1082   return src;
1083 }
1084
1085 int
1086 fhandler_console::write (const void *vsrc, size_t len)
1087 {
1088   /* Run and check for ansi sequences */
1089   unsigned const char *src = (unsigned char *) vsrc;
1090   unsigned const char *end = src + len;
1091   static NO_COPY unsigned rarg;
1092   static NO_COPY char my_title_buf[TITLESIZE + 1];
1093
1094   debug_printf ("%x, %d", vsrc, len);
1095
1096   while (src < end)
1097     {
1098       debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ',
1099                     state_);
1100       switch (state_)
1101         {
1102         case normal:
1103           src = write_normal (src, end);
1104           if (src == 0) /* write_normal fail */
1105             return -1;
1106           break;
1107         case gotesc:
1108           if (*src == '[')
1109             {
1110               state_ = gotsquare;
1111               for (nargs_ = 0; nargs_ < MAXARGS; nargs_++)
1112                 args_[nargs_] = 0;
1113               nargs_ = 0;
1114             }
1115           else if (*src == ']')
1116             {
1117               rarg = 0;
1118               my_title_buf[0] = '\0';
1119               state_ = gotrsquare;
1120             }
1121           else if (*src == 'M')         /* Reverse Index */
1122             {
1123               fillin_info ();
1124               scroll_screen (0, 0, -1, -1, 0, info.winTop + 1);
1125               state_ = normal;
1126             }
1127           else if (*src == 'c')         /* Reset Linux terminal */
1128             {
1129               clear_screen (0, 0, -1, -1);
1130               cursor_set (TRUE, 0, 0);
1131               state_ = normal;
1132             }
1133           else if (*src == '8')         /* Restore cursor position */
1134             {
1135               cursor_set (FALSE, savex, savey);
1136               state_ = normal;
1137             }
1138           else if (*src == '7')         /* Save cursor position */
1139             {
1140               cursor_get (&savex, &savey);
1141               state_ = normal;
1142             }
1143           else if (*src == 'R')
1144               state_ = normal;
1145           else
1146             {
1147               state_ = normal;
1148             }
1149           src++;
1150           break;
1151         case gotarg1:
1152           if (isdigit (*src))
1153             {
1154               args_[nargs_] = args_[nargs_] * 10 + *src - '0';
1155               src++;
1156             }
1157           else if (*src == ';')
1158             {
1159               src++;
1160               nargs_++;
1161               if (nargs_ >= MAXARGS)
1162                 nargs_--;
1163             }
1164           else
1165             {
1166               state_ = gotcommand;
1167             }
1168           break;
1169         case gotcommand:
1170           char_command (*src++);
1171           state_ = normal;
1172           break;
1173         case gotrsquare:
1174           if (isdigit(*src))
1175             rarg = rarg * 10 + (*src - '0');
1176           else if (*src == ';' && (rarg == 2 || rarg == 0))
1177             state_ = gettitle;
1178           else
1179             state_ = eattitle;
1180           src++;
1181           break;
1182         case eattitle:
1183         case gettitle:
1184           {
1185             int n = strlen (my_title_buf);
1186             if (*src < ' ' || *src >= '\177')
1187               {
1188                 if (*src == '\007' && state_ == gettitle)
1189                   {
1190                     if (old_title)
1191                       strcpy (old_title, my_title_buf);
1192                     set_console_title (my_title_buf);
1193                   }
1194                 state_ = normal;
1195               }
1196             else if (n < TITLESIZE)
1197               {
1198                 my_title_buf[n++] = *src;
1199                 my_title_buf[n] = '\0';
1200               }
1201             src++;
1202             break;
1203           }
1204         case gotsquare:
1205           if (*src == ';')
1206             {
1207               state_ = gotarg1;
1208               nargs_++;
1209               src++;
1210             }
1211           else if (isalpha (*src))
1212             {
1213               state_ = gotcommand;
1214             }
1215           else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
1216             {
1217               /* ignore any extra chars between [ and first arg or command */
1218               src++;
1219             }
1220           else
1221             state_ = gotarg1;
1222           break;
1223         }
1224     }
1225   syscall_printf ("%d = write_console (,..%d)", len, len);
1226
1227   return len;
1228 }
1229
1230 static struct {
1231   int vk;
1232   const char *val[4];
1233 } keytable[] = {
1234                /* NORMAL */  /* SHIFT */    /* CTRL */       /* ALT */
1235   {VK_LEFT,     {"\033[D",      NULL,           NULL,           NULL}},
1236   {VK_RIGHT,    {"\033[C",      NULL,           NULL,           NULL}},
1237   {VK_UP,       {"\033[A",      NULL,           NULL,           NULL}},
1238   {VK_DOWN,     {"\033[B",      NULL,           NULL,           NULL}},
1239   {VK_PRIOR,    {"\033[5~",     NULL,           NULL,           NULL}},
1240   {VK_NEXT,     {"\033[6~",     NULL,           NULL,           NULL}},
1241   {VK_HOME,     {"\033[1~",     NULL,           NULL,           NULL}},
1242   {VK_END,      {"\033[4~",     NULL,           NULL,           NULL}},
1243   {VK_INSERT,   {"\033[2~",     NULL,           NULL,           NULL}},
1244   {VK_DELETE,   {"\033[3~",     NULL,           NULL,           NULL}},
1245   {VK_F1,       {"\033[[A",     "\033[23~",     NULL,           NULL}},
1246   {VK_F2,       {"\033[[B",     "\033[24~",     NULL,           NULL}},
1247   {VK_F3,       {"\033[[C",     "\033[25~",     NULL,           NULL}},
1248   {VK_F4,       {"\033[[D",     "\033[26~",     NULL,           NULL}},
1249   {VK_F5,       {"\033[[E",     "\033[28~",     NULL,           NULL}},
1250   {VK_F6,       {"\033[17~",    "\033[29~",     "\036",         NULL}},
1251   {VK_F7,       {"\033[18~",    "\033[31~",     NULL,           NULL}},
1252   {VK_F8,       {"\033[19~",    "\033[32~",     NULL,           NULL}},
1253   {VK_F9,       {"\033[20~",    "\033[33~",     NULL,           NULL}},
1254   {VK_F10,      {"\033[21~",    "\033[34~",     NULL,           NULL}},
1255   {VK_F11,      {"\033[23~",    NULL,           NULL,           NULL}},
1256   {VK_F12,      {"\033[24~",    NULL,           NULL,           NULL}},
1257   {VK_NUMPAD5,  {"\033[G",      NULL,           NULL,           NULL}},
1258   {'6',         {NULL,          NULL,           "\036",         NULL}},
1259   {0,           {"",            NULL,           NULL,           NULL}}
1260 };
1261
1262 const char *
1263 get_nonascii_key (INPUT_RECORD& input_rec)
1264 {
1265 #define NORMAL  0
1266 #define SHIFT   1
1267 #define CONTROL 2
1268 #define ALT     3
1269   int modifier_index = NORMAL;
1270
1271   if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
1272     modifier_index = SHIFT;
1273   else if (input_rec.Event.KeyEvent.dwControlKeyState &
1274                 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
1275     modifier_index = CONTROL;
1276   else if (input_rec.Event.KeyEvent.dwControlKeyState &
1277                 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
1278     modifier_index = ALT;
1279
1280   for (int i = 0; keytable[i].vk; i++)
1281     if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
1282       return keytable[i].val[modifier_index];
1283
1284   return NULL;
1285 }
1286
1287 void
1288 fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
1289 {
1290   this->fhandler_termios::init (f, bin, a);
1291
1292   /* Ensure both input and output console handles are open */
1293   int mode = 0;
1294
1295   a &= GENERIC_READ | GENERIC_WRITE;
1296   if (a == GENERIC_READ)
1297     mode = O_RDONLY;
1298   if (a == GENERIC_WRITE)
1299     mode = O_WRONLY;
1300   if (a == (GENERIC_READ | GENERIC_WRITE))
1301     mode = O_RDWR;
1302   open (0, mode);
1303   if (f != INVALID_HANDLE_VALUE)
1304     CloseHandle (f);    /* Reopened by open */
1305
1306   output_tcsetattr (0, &tc->ti);
1307 }
1308
1309 int
1310 fhandler_console::igncr_enabled (void)
1311 {
1312   return tc->ti.c_iflag & IGNCR;
1313 }
1314
1315 void
1316 fhandler_console::set_close_on_exec (int val)
1317 {
1318   this->fhandler_base::set_close_on_exec (val);
1319   set_inheritance (output_handle, val);
1320 }
1321
1322 void
1323 fhandler_console::fixup_after_fork (HANDLE)
1324 {
1325   HANDLE h = get_handle ();
1326   HANDLE oh = get_output_handle ();
1327
1328   /* Windows does not allow duplication of console handles between processes
1329      so open the console explicitly. */
1330
1331   if (!open(get_name (), get_flags (), 0))
1332     system_printf ("error opening console after fork, %E");
1333
1334   if (!get_close_on_exec ())
1335     {
1336       CloseHandle (h);
1337       CloseHandle (oh);
1338     }
1339 }
1340
1341 void __stdcall
1342 set_console_title (char *title)
1343 {
1344   int rc;
1345   char buf[257];
1346   strncpy(buf, title, sizeof(buf) - 1);
1347   buf[sizeof(buf) - 1] = '\0';
1348   if ((rc = WaitForSingleObject (title_mutex, 15000)) != WAIT_OBJECT_0)
1349     sigproc_printf ("wait for title mutex failed rc %d, %E", rc);
1350   SetConsoleTitle (buf);
1351   ReleaseMutex (title_mutex);
1352   debug_printf ("title '%s'", buf);
1353 }
1354
1355 int
1356 fhandler_console::de_linearize (const char *buf, const char *unix_name,
1357                                 const char *win32_name)
1358 {
1359   int res = fhandler_base::de_linearize (buf, unix_name, win32_name);
1360   HANDLE h = get_handle ();
1361   HANDLE oh = get_output_handle ();
1362
1363   if (!open(get_name (), get_flags (), 0))
1364     {
1365       int sawerr = 0;
1366       if (!get_io_handle ())
1367         {
1368           system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1369           sawerr = 1;
1370         }
1371       if (!get_output_handle ())
1372         {
1373           system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1374           sawerr = 1;
1375         }
1376
1377       if (!sawerr)
1378         system_printf ("error opening console after exec, errno %d, %E", get_errno ());
1379     }
1380
1381   CloseHandle (h);
1382   CloseHandle (oh);
1383   return res;
1384 }