3 Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 Should the constructor call tcinit() explicitly rather than having
13 it sprinkled throughout here? */
15 #include <sys/termios.h>
25 * Scroll the screen context.
28 * xn, yn - new ul corner
29 * Negative values represents current screen dimensions
34 } scroll_region = {0, -1};
36 #define srTop (info.winTop + scroll_region.Top)
37 #define srBottom ((scroll_region.Bottom < 0) ? info.winBottom : info.winTop + scroll_region.Bottom)
39 #define use_tty ISSTATE (myself, PID_USETTY)
41 const char * get_nonascii_key (INPUT_RECORD& input_rec);
43 HANDLE console_shared_h;
45 static tty_min NO_COPY *shared_console_info = NULL;
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)
52 if (shared_console_info && !force)
53 return shared_console_info;
55 shared_console_info = (tty_min *) open_shared (NULL, console_shared_h,
56 sizeof (*shared_console_info),
58 ProtectHandle (console_shared_h);
59 shared_console_info->setntty (TTY_CONSOLE);
60 shared_console_info->setsid (myself->sid);
61 return shared_console_info;
64 /* Return the tty structure associated with a given tty number. If the
65 tty number is < 0, just return a dummy record. */
67 tty_list::get_tty (int n)
71 return get_tty_stuff ();
73 return &cygwin_shared->tty.ttys[n];
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. */
83 set_console_state_for_spawn ()
85 HANDLE h = CreateFileA ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
86 &sec_none_nih, OPEN_EXISTING,
87 FILE_ATTRIBUTE_NORMAL, NULL);
89 if (h == INVALID_HANDLE_VALUE || h == NULL)
92 if (shared_console_info != NULL)
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);
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);
112 fhandler_console::read (void *pv, size_t buflen)
117 HANDLE h = get_io_handle ();
119 #define buf ((char *) pv)
124 int copied_chars = get_readahead_into_buffer (buf, buflen);
137 w4[1] = signal_arrived;
144 if ((bgres = bg_check (SIGTTIN)) <= 0)
147 switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE))
151 case WAIT_OBJECT_0 + 1:
152 set_sig_errno (EINTR);
159 INPUT_RECORD input_rec;
162 if (!ReadConsoleInput (h, &input_rec, 1, &nread))
164 syscall_printf ("ReadConsoleInput failed, %E");
166 return -1; /* seems to be failure */
169 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
171 /* check if we're just disposing of this one */
173 if (input_rec.EventType == WINDOW_BUFFER_SIZE_EVENT)
175 kill_pgrp (tc->getpgid (), SIGWINCH);
178 if (input_rec.EventType != KEY_EVENT ||
179 !input_rec.Event.KeyEvent.bKeyDown)
182 if (ich == 0) /* arrow/function keys */
184 toadd = get_nonascii_key (input_rec);
187 nread = strlen (toadd);
189 else if (!(input_rec.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED))
195 tmp[1] = tolower (ich);
200 if (line_edit (toadd, nread))
206 if ((ch = get_readahead ()) < 0)
210 buf[copied_chars++] = (unsigned char)(ch & 0xff);
223 COORD dwCursorPosition;
228 fhandler_console::fillin_info (void)
231 CONSOLE_SCREEN_BUFFER_INFO linfo;
233 if ((ret = GetConsoleScreenBufferInfo (get_output_handle(), &linfo)))
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;
244 memset (&info, 0, sizeof info);
245 info.dwWinSize.Y = 25;
246 info.dwWinSize.X = 80;
254 fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
260 (void)fillin_info ();
261 sr1.Left = x1 >= 0 ? x1 : info.dwWinSize.X - 1;
263 sr1.Top = info.winTop;
265 sr1.Top = y1 > 0 ? y1 : info.winBottom;
266 sr1.Right = x2 >= 0 ? x2 : info.dwWinSize.X - 1;
268 sr1.Bottom = info.winTop;
270 sr1.Bottom = y2 > 0 ? y2 : info.winBottom;
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;
279 dest.Y = info.winTop;
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);
286 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
287 * is more than half of screen, filling doesn't work as expected */
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);
297 fhandler_console::open (const char *, int flags, mode_t)
301 tcinit (get_tty_stuff ());
303 set_io_handle (INVALID_HANDLE_VALUE);
304 set_output_handle (INVALID_HANDLE_VALUE);
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);
313 if (h == INVALID_HANDLE_VALUE)
319 set_r_no_interrupt (1); // Handled explicitly in read code
321 h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
322 FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none,
323 OPEN_EXISTING, 0, 0);
325 if (h == INVALID_HANDLE_VALUE)
330 set_output_handle (h);
333 default_color = info.wAttributes;
336 if (GetConsoleMode (get_io_handle (), &cflags))
338 cflags |= ENABLE_PROCESSED_INPUT;
339 SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT | cflags);
343 set_ctty (TTY_CONSOLE, flags);
344 debug_printf("opened conin$ %p, conout$ %p",
345 get_io_handle (), get_output_handle ());
351 fhandler_console::close (void)
353 CloseHandle (get_io_handle ());
354 CloseHandle (get_output_handle ());
355 set_io_handle (INVALID_HANDLE_VALUE);
356 set_output_handle (INVALID_HANDLE_VALUE);
361 * Special console dup to duplicate input and output
366 fhandler_console::dup (fhandler_base *child)
368 fhandler_console *fhc = (fhandler_console *) child;
370 if (!fhc->open(get_name (), get_flags (), 0))
371 system_printf ("error opening console, %E");
373 fhc->state_ = state_;
374 fhc->default_color = default_color;
380 fhandler_console::ioctl (unsigned int cmd, void *buf)
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);
401 syscall_printf ("WINSZ failed");
407 (void) bg_check (SIGTTOU);
411 return fhandler_base::ioctl (cmd, buf);
415 fhandler_console::tcflush (int queue)
418 if (queue == TCIFLUSH
419 || queue == TCIOFLUSH)
421 if (!FlushConsoleInputBuffer (get_io_handle ()))
431 fhandler_console::output_tcsetattr (int, struct termios const *t)
433 /* Ignore the optional_actions stuff, since all output is emitted
436 /* Enable/disable LF -> CRLF conversions */
437 set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1);
439 /* All the output bits we can ignore */
441 DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
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);
450 fhandler_console::input_tcsetattr (int, struct termios const *t)
452 /* Ignore the optional_actions stuff, since all output is emitted
457 if (!GetConsoleMode (get_io_handle (), &oflags))
461 /* Enable/disable LF -> CRLF conversions */
462 set_r_binary ((t->c_iflag & INLCR) ? 0 : 1);
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. */
470 if (t->c_lflag & ECHO)
472 flags |= ENABLE_ECHO_INPUT;
474 if (t->c_lflag & ICANON)
476 flags |= ENABLE_LINE_INPUT;
479 if (flags & ENABLE_ECHO_INPUT
480 && !(flags & ENABLE_LINE_INPUT))
482 /* This is illegal, so turn off the echo here, and fake it
483 when we read the characters */
485 flags &= ~ENABLE_ECHO_INPUT;
488 if (t->c_lflag & ISIG)
490 flags |= ENABLE_PROCESSED_INPUT;
492 /* What about ENABLE_WINDOW_INPUT
493 and ENABLE_MOUSE_INPUT ? */
497 flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
502 flags |= ENABLE_WINDOW_INPUT;
509 res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1;
512 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
513 res, t, flags, t->c_lflag, t->c_iflag);
521 fhandler_console::tcsetattr (int a, struct termios const *t)
523 int res = output_tcsetattr (a, t);
526 return input_tcsetattr (a, t);
530 fhandler_console::tcgetattr (struct termios *t)
538 if (!get_r_binary ())
540 if (!get_w_binary ())
546 if (!GetConsoleMode (get_io_handle (), &flags))
553 if (flags & ENABLE_ECHO_INPUT)
556 if (flags & ENABLE_LINE_INPUT)
557 t->c_lflag |= ICANON;
559 if (flags & ENABLE_PROCESSED_INPUT)
562 /* What about ENABLE_WINDOW_INPUT
563 and ENABLE_MOUSE_INPUT ? */
565 /* All the output bits we can ignore */
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);
577 fhandler_console::fhandler_console (const char *name) :
578 fhandler_termios (FH_CONSOLE, name, -1)
580 set_cb (sizeof *this);
582 set_need_fork_fixup ();
586 * Clear the screen context from x1/y1 to x2/y2 cell.
587 * Negative values represents current screen dimensions
590 fhandler_console::clear_screen (int x1, int y1, int x2, int y2)
596 (void)fillin_info ();
599 x1 = info.dwWinSize.X-1;
603 x2 = info.dwWinSize.X-1;
607 num = abs (y1 - y2) * info.dwWinSize.X + abs (x1 - x2) + 1;
609 if ((y2 * info.dwWinSize.X + x2) > (y1 * info.dwWinSize.X + x1))
619 FillConsoleOutputCharacterA (get_output_handle (), ' ',
623 FillConsoleOutputAttribute (get_output_handle (),
631 fhandler_console::cursor_set (BOOL rel_to_top, int x, int y)
635 (void)fillin_info ();
636 if (y > info.winBottom)
643 if (x > info.dwWinSize.X)
644 x = info.dwWinSize.X - 1;
650 SetConsoleCursorPosition (get_output_handle (), pos);
654 fhandler_console::cursor_rel (int x, int y)
657 x += info.dwCursorPosition.X;
658 y += info.dwCursorPosition.Y;
659 cursor_set (FALSE, x, y);
663 fhandler_console::cursor_get (int *x, int *y)
666 *y = info.dwCursorPosition.Y;
667 *x = info.dwCursorPosition.X;
681 #define TAB 8 /* We should't let the console deal with these */
685 static const char base_chars[256] =
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 };
720 /*#define syscall_printf small_printf*/
722 static int savex, savey; /* for CSI s, CSI u */
725 fhandler_console::char_command (char c)
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 |
731 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
732 BACKGROUND_RED | BACKGROUND_INTENSITY),
733 bold = default_color & FOREGROUND_INTENSITY;
739 case 'm': /* Set Graphics Rendition */
742 for (i = 0; i <= nargs_; i++)
745 case 0: /* normal color */
746 fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
748 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
749 BACKGROUND_RED | BACKGROUND_INTENSITY);
750 bold = default_color & FOREGROUND_INTENSITY;
753 fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
755 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
756 BACKGROUND_RED | BACKGROUND_INTENSITY);
757 bold = FOREGROUND_INTENSITY;
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;
765 case 5: /* blink mode */
766 fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
768 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
769 BACKGROUND_RED | BACKGROUND_INTENSITY);
770 bold = default_color & FOREGROUND_INTENSITY;
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;
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;
794 fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
796 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
797 BACKGROUND_RED | BACKGROUND_INTENSITY);
798 bold = (fg == 0) ? FOREGROUND_INTENSITY : 0;
800 case 30: /* BLACK foreground */
803 case 31: /* RED foreground */
806 case 32: /* GREEN foreground */
807 fg = FOREGROUND_GREEN;
809 case 33: /* YELLOW foreground */
810 fg = FOREGROUND_RED | FOREGROUND_GREEN;
812 case 34: /* BLUE foreground */
813 fg = FOREGROUND_BLUE;
815 case 35: /* MAGENTA foreground */
816 fg = FOREGROUND_RED | FOREGROUND_BLUE;
818 case 36: /* CYAN foreground */
819 fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
821 case 37: /* WHITE foreg */
822 fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
824 case 40: /* BLACK background */
827 case 41: /* RED background */
830 case 42: /* GREEN background */
831 bg = BACKGROUND_GREEN;
833 case 43: /* YELLOW background */
834 bg = BACKGROUND_RED | BACKGROUND_GREEN;
836 case 44: /* BLUE background */
837 bg = BACKGROUND_BLUE;
839 case 45: /* MAGENTA background */
840 bg = BACKGROUND_RED | BACKGROUND_BLUE;
842 case 46: /* CYAN background */
843 bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
845 case 47: /* WHITE background */
846 bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
849 fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN |
851 bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN |
852 BACKGROUND_RED | BACKGROUND_INTENSITY);
853 bold = default_color & FOREGROUND_INTENSITY;
856 SetConsoleTextAttribute (get_output_handle (), fg | bg | bold);
865 case 0: /* Clear to end of screen */
867 clear_screen (x, y, -1, -1);
869 case 1: /* Clear from beginning of screen to cursor */
871 clear_screen (0, 0, x, y);
873 case 2: /* Clear screen */
874 clear_screen (0, 0, -1, -1);
875 cursor_set (TRUE, 0,0);
883 cursor_rel (0, -(args_[0] ? args_[0] : 1));
886 cursor_rel (0, args_[0] ? args_[0] : 1);
889 cursor_rel (args_[0] ? args_[0] : 1, 0);
892 cursor_rel (-(args_[0] ? args_[0] : 1),0);
897 case 0: /* Clear to end of line */
899 clear_screen (x, y, -1, y);
901 case 2: /* Clear line */
903 clear_screen (0, y, -1, y);
905 case 1: /* Clear from bol to cursor */
907 clear_screen (0, y, x, y);
915 cursor_set (TRUE, (args_[1] ? args_[1] : 1) - 1,
916 (args_[0] ? args_[0] : 1) - 1);
918 case 'G': /* hpa - position cursor at column n - 1 */
920 cursor_set (FALSE, (args_[0] ? args_[0] - 1 : 0), y);
922 case 'd': /* vpa - position cursor at line n */
924 cursor_set (TRUE, x, (args_[0] ? args_[0] - 1 : 0));
926 case 's': /* Save cursor position */
927 cursor_get (&savex, &savey);
929 case 'u': /* Restore cursor position */
930 cursor_set (FALSE, savex, savey);
934 cursor_set (FALSE, 8*(x/8+1), y);
936 case 'L': /* AL - insert blank lines */
937 args_[0] = args_[0] ? args_[0] : 1;
939 scroll_screen (0, y, -1, -1, 0, y + args_[0]);
941 case 'M': /* DL - delete lines */
942 args_[0] = args_[0] ? args_[0] : 1;
944 scroll_screen (0, y + args_[0], -1, -1, 0, y);
946 case '@': /* IC - insert chars */
947 args_[0] = args_[0] ? args_[0] : 1;
949 scroll_screen (x, y, -1, y, x + args_[0], y);
951 case 'P': /* DC - delete chars */
952 args_[0] = args_[0] ? args_[0] : 1;
954 scroll_screen (x + args_[0], y, -1, y, x, y);
956 case 'S': /* SF - Scroll forward */
957 args_[0] = args_[0] ? args_[0] : 1;
958 scroll_screen(0, args_[0], -1, -1, 0, 0);
960 case 'T': /* SR - Scroll down */
962 args_[0] = args_[0] ? args_[0] : 1;
963 scroll_screen (0, 0, -1, -1, 0, info.winTop + args_[0]);
965 case 'X': /* ec - erase chars */
966 args_[0] = args_[0] ? args_[0] : 1;
968 scroll_screen (x + args_[0], y, -1, y, x, y);
969 scroll_screen (x, y, -1, y, x + args_[0], y);
971 case 'Z': /* Back tab */
973 cursor_set (FALSE, ((8 * (x / 8 + 1)) - 8), y);
975 case 'b': /* Repeat char #1 #2 times */
977 WriteFile (get_output_handle (), &args_[0], 1, (DWORD *) &x, 0);
979 case 'c': /* u9 - Terminal enquire string */
980 strcpy (buf, "\033[?6c");
981 puts_readahead (buf);
986 case 6: /* u7 - Cursor position request */
989 /* x -= info.winLeft; // not available yet */
990 __small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
991 puts_readahead (buf);
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);
1002 case 'g': /* TAB set/clear */
1010 const unsigned char *
1011 fhandler_console::write_normal (const unsigned char *src,
1012 const unsigned char *end)
1014 /* Scan forward to see what a char which needs special treatment */
1016 const unsigned char *found = src;
1020 if (base_chars[*found] != NOR)
1024 /* Print all the base ones out */
1027 if (! WriteFile (get_output_handle (), src, found - src, &done, 0))
1029 debug_printf ("write failed, handle %p", get_output_handle ());
1038 switch (base_chars[*src])
1046 case DWN: /* WriteFile("\n") always adds CR... */
1047 cursor_get (&x, &y);
1050 if (y < info.winBottom || scroll_region.Top)
1052 scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
1056 WriteFile (get_output_handle (), "\n", 1, &done, 0);
1058 if (!get_w_binary ())
1060 cursor_set (FALSE, x, y + 1);
1069 cursor_get (&x, &y);
1070 cursor_set (FALSE, 0, y);
1073 WriteFile (get_output_handle (), src, 1, &done, 0);
1076 cursor_get (&x, &y);
1077 cursor_set (FALSE, 8 * (x / 8 + 1), y);
1086 fhandler_console::write (const void *vsrc, size_t len)
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];
1094 debug_printf ("%x, %d", vsrc, len);
1098 debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ',
1103 src = write_normal (src, end);
1104 if (src == 0) /* write_normal fail */
1111 for (nargs_ = 0; nargs_ < MAXARGS; nargs_++)
1115 else if (*src == ']')
1118 my_title_buf[0] = '\0';
1119 state_ = gotrsquare;
1121 else if (*src == 'M') /* Reverse Index */
1124 scroll_screen (0, 0, -1, -1, 0, info.winTop + 1);
1127 else if (*src == 'c') /* Reset Linux terminal */
1129 clear_screen (0, 0, -1, -1);
1130 cursor_set (TRUE, 0, 0);
1133 else if (*src == '8') /* Restore cursor position */
1135 cursor_set (FALSE, savex, savey);
1138 else if (*src == '7') /* Save cursor position */
1140 cursor_get (&savex, &savey);
1143 else if (*src == 'R')
1154 args_[nargs_] = args_[nargs_] * 10 + *src - '0';
1157 else if (*src == ';')
1161 if (nargs_ >= MAXARGS)
1166 state_ = gotcommand;
1170 char_command (*src++);
1175 rarg = rarg * 10 + (*src - '0');
1176 else if (*src == ';' && (rarg == 2 || rarg == 0))
1185 int n = strlen (my_title_buf);
1186 if (*src < ' ' || *src >= '\177')
1188 if (*src == '\007' && state_ == gettitle)
1191 strcpy (old_title, my_title_buf);
1192 set_console_title (my_title_buf);
1196 else if (n < TITLESIZE)
1198 my_title_buf[n++] = *src;
1199 my_title_buf[n] = '\0';
1211 else if (isalpha (*src))
1213 state_ = gotcommand;
1215 else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
1217 /* ignore any extra chars between [ and first arg or command */
1225 syscall_printf ("%d = write_console (,..%d)", len, len);
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}}
1263 get_nonascii_key (INPUT_RECORD& input_rec)
1269 int modifier_index = NORMAL;
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;
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];
1288 fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
1290 this->fhandler_termios::init (f, bin, a);
1292 /* Ensure both input and output console handles are open */
1295 a &= GENERIC_READ | GENERIC_WRITE;
1296 if (a == GENERIC_READ)
1298 if (a == GENERIC_WRITE)
1300 if (a == (GENERIC_READ | GENERIC_WRITE))
1303 if (f != INVALID_HANDLE_VALUE)
1304 CloseHandle (f); /* Reopened by open */
1306 output_tcsetattr (0, &tc->ti);
1310 fhandler_console::igncr_enabled (void)
1312 return tc->ti.c_iflag & IGNCR;
1316 fhandler_console::set_close_on_exec (int val)
1318 this->fhandler_base::set_close_on_exec (val);
1319 set_inheritance (output_handle, val);
1323 fhandler_console::fixup_after_fork (HANDLE)
1325 HANDLE h = get_handle ();
1326 HANDLE oh = get_output_handle ();
1328 /* Windows does not allow duplication of console handles between processes
1329 so open the console explicitly. */
1331 if (!open(get_name (), get_flags (), 0))
1332 system_printf ("error opening console after fork, %E");
1334 if (!get_close_on_exec ())
1342 set_console_title (char *title)
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);
1356 fhandler_console::de_linearize (const char *buf, const char *unix_name,
1357 const char *win32_name)
1359 int res = fhandler_base::de_linearize (buf, unix_name, win32_name);
1360 HANDLE h = get_handle ();
1361 HANDLE oh = get_output_handle ();
1363 if (!open(get_name (), get_flags (), 0))
1366 if (!get_io_handle ())
1368 system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1371 if (!get_output_handle ())
1373 system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1378 system_printf ("error opening console after exec, errno %d, %E", get_errno ());