Update readelf's display of RELR sections to include the number of locations relocated
[binutils-gdb.git] / gdb / tui / tui-io.c
blob2673397cc46bb1e85aba7353987c31cb554c9e93
1 /* TUI support I/O functions.
3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "target.h"
23 #include "gdbsupport/event-loop.h"
24 #include "event-top.h"
25 #include "command.h"
26 #include "top.h"
27 #include "ui.h"
28 #include "tui/tui.h"
29 #include "tui/tui-data.h"
30 #include "tui/tui-io.h"
31 #include "tui/tui-command.h"
32 #include "tui/tui-win.h"
33 #include "tui/tui-wingeneral.h"
34 #include "tui/tui-file.h"
35 #include "ui-out.h"
36 #include "cli-out.h"
37 #include <fcntl.h>
38 #include <signal.h>
39 #ifdef __MINGW32__
40 #include <windows.h>
41 #endif
42 #include "gdbsupport/filestuff.h"
43 #include "completer.h"
44 #include "gdb_curses.h"
45 #include <map>
46 #include "pager.h"
47 #include "gdbsupport/gdb-checked-static-cast.h"
49 /* This redefines CTRL if it is not already defined, so it must come
50 after terminal state releated include files like <term.h> and
51 "gdb_curses.h". */
52 #include "readline/readline.h"
54 #ifdef __MINGW32__
55 static SHORT ncurses_norm_attr;
56 #endif
58 static int tui_getc (FILE *fp);
60 static int
61 key_is_start_sequence (int ch)
63 return (ch == 27);
66 /* Use definition from readline 4.3. */
67 #undef CTRL_CHAR
68 #define CTRL_CHAR(c) \
69 ((c) < control_character_threshold && (((c) & 0x80) == 0))
71 /* This file controls the IO interactions between gdb and curses.
72 When the TUI is enabled, gdb has two modes a curses and a standard
73 mode.
75 In curses mode, the gdb outputs are made in a curses command
76 window. For this, the gdb_stdout and gdb_stderr are redirected to
77 the specific ui_file implemented by TUI. The output is handled by
78 tui_puts(). The input is also controlled by curses with
79 tui_getc(). The readline library uses this function to get its
80 input. Several readline hooks are installed to redirect readline
81 output to the TUI (see also the note below).
83 In normal mode, the gdb outputs are restored to their origin, that
84 is as if TUI is not used. Readline also uses its original getc()
85 function with stdin.
87 Note SCz/2001-07-21: the current readline is not clean in its
88 management of the output. Even if we install a redisplay handler,
89 it sometimes writes on a stdout file. It is important to redirect
90 every output produced by readline, otherwise the curses window will
91 be garbled. This is implemented with a pipe that TUI reads and
92 readline writes to. A gdb input handler is created so that reading
93 the pipe is handled automatically. This will probably not work on
94 non-Unix platforms. The best fix is to make readline clean enough
95 so that is never write on stdout.
97 Note SCz/2002-09-01: we now use more readline hooks and it seems
98 that with them we don't need the pipe anymore (verified by creating
99 the pipe and closing its end so that write causes a SIGPIPE). The
100 old pipe code is still there and can be conditionally removed by
101 #undef TUI_USE_PIPE_FOR_READLINE. */
103 /* For gdb 5.3, prefer to continue the pipe hack as a backup wheel. */
104 #ifdef HAVE_PIPE
105 #define TUI_USE_PIPE_FOR_READLINE
106 #endif
107 /* #undef TUI_USE_PIPE_FOR_READLINE */
109 /* TUI output files. */
110 static struct ui_file *tui_stdout;
111 static struct ui_file *tui_stderr;
112 static struct ui_file *tui_stdlog;
113 struct ui_out *tui_out;
115 /* GDB output files in non-curses mode. */
116 static struct ui_file *tui_old_stdout;
117 static struct ui_file *tui_old_stderr;
118 static struct ui_file *tui_old_stdlog;
119 cli_ui_out *tui_old_uiout;
121 /* Readline previous hooks. */
122 static rl_getc_func_t *tui_old_rl_getc_function;
123 static rl_voidfunc_t *tui_old_rl_redisplay_function;
124 static rl_vintfunc_t *tui_old_rl_prep_terminal;
125 static rl_voidfunc_t *tui_old_rl_deprep_terminal;
126 static rl_compdisp_func_t *tui_old_rl_display_matches_hook;
127 static int tui_old_rl_echoing_p;
129 /* Readline output stream.
130 Should be removed when readline is clean. */
131 static FILE *tui_rl_outstream;
132 static FILE *tui_old_rl_outstream;
133 #ifdef TUI_USE_PIPE_FOR_READLINE
134 static int tui_readline_pipe[2];
135 #endif
137 /* Print a character in the curses command window. The output is
138 buffered. It is up to the caller to refresh the screen if
139 necessary. */
141 static void
142 do_tui_putc (WINDOW *w, char c)
144 /* Expand TABs, since ncurses on MS-Windows doesn't. */
145 if (c == '\t')
147 int col;
149 col = getcurx (w);
152 waddch (w, ' ');
153 col++;
155 while ((col % 8) != 0);
157 else
158 waddch (w, c);
161 /* Update the cached value of the command window's start line based on
162 the window's current Y coordinate. */
164 static void
165 update_cmdwin_start_line ()
167 TUI_CMD_WIN->start_line = getcury (TUI_CMD_WIN->handle.get ());
170 /* Print a character in the curses command window. The output is
171 buffered. It is up to the caller to refresh the screen if
172 necessary. */
174 static void
175 tui_putc (char c)
177 do_tui_putc (TUI_CMD_WIN->handle.get (), c);
178 update_cmdwin_start_line ();
181 /* This maps colors to their corresponding color index. */
183 static std::map<ui_file_style::color, int> color_map;
185 /* This holds a pair of colors and is used to track the mapping
186 between a color pair index and the actual colors. */
188 struct color_pair
190 int fg;
191 int bg;
193 bool operator< (const color_pair &o) const
195 return fg < o.fg || (fg == o.fg && bg < o.bg);
199 /* This maps pairs of colors to their corresponding color pair
200 index. */
202 static std::map<color_pair, int> color_pair_map;
204 /* This is indexed by ANSI color offset from the base color, and holds
205 the corresponding curses color constant. */
207 static const int curses_colors[] = {
208 COLOR_BLACK,
209 COLOR_RED,
210 COLOR_GREEN,
211 COLOR_YELLOW,
212 COLOR_BLUE,
213 COLOR_MAGENTA,
214 COLOR_CYAN,
215 COLOR_WHITE
218 /* Given a color, find its index. */
220 static bool
221 get_color (const ui_file_style::color &color, int *result)
223 if (color.is_none ())
224 *result = -1;
225 else if (color.is_basic ())
226 *result = curses_colors[color.get_value ()];
227 else
229 auto it = color_map.find (color);
230 if (it == color_map.end ())
232 /* The first 8 colors are standard. */
233 int next = color_map.size () + 8;
234 if (next >= COLORS)
235 return false;
236 uint8_t rgb[3];
237 color.get_rgb (rgb);
238 /* We store RGB as 0..255, but curses wants 0..1000. */
239 if (init_color (next, rgb[0] * 1000 / 255, rgb[1] * 1000 / 255,
240 rgb[2] * 1000 / 255) == ERR)
241 return false;
242 color_map[color] = next;
243 *result = next;
245 else
246 *result = it->second;
248 return true;
251 /* The most recently emitted color pair. */
253 static int last_color_pair = -1;
255 /* The most recently applied style. */
257 static ui_file_style last_style;
259 /* If true, we're highlighting the current source line in reverse
260 video mode. */
261 static bool reverse_mode_p = false;
263 /* The background/foreground colors before we entered reverse
264 mode. */
265 static ui_file_style::color reverse_save_bg (ui_file_style::NONE);
266 static ui_file_style::color reverse_save_fg (ui_file_style::NONE);
268 /* Given two colors, return their color pair index; making a new one
269 if necessary. */
271 static int
272 get_color_pair (int fg, int bg)
274 color_pair c = { fg, bg };
275 auto it = color_pair_map.find (c);
276 if (it == color_pair_map.end ())
278 /* Color pair 0 is our default color, so new colors start at
279 1. */
280 int next = color_pair_map.size () + 1;
281 /* Curses has a limited number of available color pairs. Fall
282 back to the default if we've used too many. */
283 if (next >= COLOR_PAIRS)
284 return 0;
285 init_pair (next, fg, bg);
286 color_pair_map[c] = next;
287 return next;
289 return it->second;
292 /* Apply STYLE to W. */
294 void
295 tui_apply_style (WINDOW *w, ui_file_style style)
297 /* Reset. */
298 wattron (w, A_NORMAL);
299 wattroff (w, A_BOLD);
300 wattroff (w, A_DIM);
301 wattroff (w, A_REVERSE);
302 if (last_color_pair != -1)
303 wattroff (w, COLOR_PAIR (last_color_pair));
304 wattron (w, COLOR_PAIR (0));
306 const ui_file_style::color &fg = style.get_foreground ();
307 const ui_file_style::color &bg = style.get_background ();
308 if (!fg.is_none () || !bg.is_none ())
310 int fgi, bgi;
311 if (get_color (fg, &fgi) && get_color (bg, &bgi))
313 #ifdef __MINGW32__
314 /* MS-Windows port of ncurses doesn't support implicit
315 default foreground and background colors, so we must
316 specify them explicitly when needed, using the colors we
317 saw at startup. */
318 if (fgi == -1)
319 fgi = ncurses_norm_attr & 15;
320 if (bgi == -1)
321 bgi = (ncurses_norm_attr >> 4) & 15;
322 #endif
323 int pair = get_color_pair (fgi, bgi);
324 if (last_color_pair != -1)
325 wattroff (w, COLOR_PAIR (last_color_pair));
326 wattron (w, COLOR_PAIR (pair));
327 last_color_pair = pair;
331 switch (style.get_intensity ())
333 case ui_file_style::NORMAL:
334 break;
336 case ui_file_style::BOLD:
337 wattron (w, A_BOLD);
338 break;
340 case ui_file_style::DIM:
341 wattron (w, A_DIM);
342 break;
344 default:
345 gdb_assert_not_reached ("invalid intensity");
348 if (style.is_reverse ())
349 wattron (w, A_REVERSE);
351 last_style = style;
354 /* Apply an ANSI escape sequence from BUF to W. BUF must start with
355 the ESC character. If BUF does not start with an ANSI escape,
356 return 0. Otherwise, apply the sequence if it is recognized, or
357 simply ignore it if not. In this case, the number of bytes read
358 from BUF is returned. */
360 static size_t
361 apply_ansi_escape (WINDOW *w, const char *buf)
363 ui_file_style style = last_style;
364 size_t n_read;
366 if (!style.parse (buf, &n_read))
367 return n_read;
369 if (reverse_mode_p)
371 if (!style_tui_current_position)
372 return n_read;
374 /* We want to reverse _only_ the default foreground/background
375 colors. If the foreground color is not the default (because
376 the text was styled), we want to leave it as is. If e.g.,
377 the terminal is fg=BLACK, and bg=WHITE, and the style wants
378 to print text in RED, we want to reverse the background color
379 (print in BLACK), but still print the text in RED. To do
380 that, we enable the A_REVERSE attribute, and re-reverse the
381 parsed-style's fb/bg colors.
383 Notes on the approach:
385 - there's no portable way to know which colors the default
386 fb/bg colors map to.
388 - this approach does the right thing even if you change the
389 terminal colors while GDB is running -- the reversed
390 colors automatically adapt.
392 if (!style.is_default ())
394 ui_file_style::color bg = style.get_background ();
395 ui_file_style::color fg = style.get_foreground ();
396 style.set_fg (bg);
397 style.set_bg (fg);
400 /* Enable A_REVERSE. */
401 style.set_reverse (true);
404 tui_apply_style (w, style);
405 return n_read;
408 /* See tui.io.h. */
410 void
411 tui_set_reverse_mode (WINDOW *w, bool reverse)
413 ui_file_style style = last_style;
415 reverse_mode_p = reverse;
417 if (reverse)
419 reverse_save_bg = style.get_background ();
420 reverse_save_fg = style.get_foreground ();
422 if (!style_tui_current_position)
424 /* Switch to default style (reversed) while highlighting the
425 current position. */
426 style = {};
429 else
431 style.set_bg (reverse_save_bg);
432 style.set_fg (reverse_save_fg);
435 style.set_reverse (reverse);
437 tui_apply_style (w, style);
440 /* Print LENGTH characters from the buffer pointed to by BUF to the
441 curses command window. The output is buffered. It is up to the
442 caller to refresh the screen if necessary. */
444 void
445 tui_write (const char *buf, size_t length)
447 /* We need this to be \0-terminated for the regexp matching. */
448 std::string copy (buf, length);
449 tui_puts (copy.c_str ());
452 /* Print a string in the curses command window. The output is
453 buffered. It is up to the caller to refresh the screen if
454 necessary. */
456 void
457 tui_puts (const char *string, WINDOW *w)
459 if (w == nullptr)
460 w = TUI_CMD_WIN->handle.get ();
462 while (true)
464 const char *next = strpbrk (string, "\n\1\2\033\t");
466 /* Print the plain text prefix. */
467 size_t n_chars = next == nullptr ? strlen (string) : next - string;
468 if (n_chars > 0)
469 waddnstr (w, string, n_chars);
471 /* We finished. */
472 if (next == nullptr)
473 break;
475 char c = *next;
476 switch (c)
478 case '\1':
479 case '\2':
480 /* Ignore these, they are readline escape-marking
481 sequences. */
482 ++next;
483 break;
485 case '\n':
486 case '\t':
487 do_tui_putc (w, c);
488 ++next;
489 break;
491 case '\033':
493 size_t bytes_read = apply_ansi_escape (w, next);
494 if (bytes_read > 0)
495 next += bytes_read;
496 else
498 /* Just drop the escape. */
499 ++next;
502 break;
504 default:
505 gdb_assert_not_reached ("missing case in tui_puts");
508 string = next;
511 if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
512 update_cmdwin_start_line ();
515 static void
516 tui_puts_internal (WINDOW *w, const char *string, int *height)
518 char c;
519 int prev_col = 0;
520 bool saw_nl = false;
522 while ((c = *string++) != 0)
524 if (c == '\1' || c == '\2')
526 /* Ignore these, they are readline escape-marking
527 sequences. */
528 continue;
531 if (c == '\033')
533 size_t bytes_read = apply_ansi_escape (w, string - 1);
534 if (bytes_read > 0)
536 string = string + bytes_read - 1;
537 continue;
541 if (c == '\n')
542 saw_nl = true;
544 do_tui_putc (w, c);
546 if (height != nullptr)
548 int col = getcurx (w);
549 if (col <= prev_col)
550 ++*height;
551 prev_col = col;
555 if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
556 update_cmdwin_start_line ();
557 if (saw_nl)
558 wrefresh (w);
561 /* Readline callback.
562 Redisplay the command line with its prompt after readline has
563 changed the edited text. */
564 void
565 tui_redisplay_readline (void)
567 const char *prompt;
569 /* Detect when we temporarily left SingleKey and now the readline
570 edit buffer is empty, automatically restore the SingleKey
571 mode. The restore must only be done if the command has finished.
572 The command could call prompt_for_continue and we must not
573 restore SingleKey so that the prompt and normal keymap are used. */
574 if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0
575 && !gdb_in_secondary_prompt_p (current_ui))
576 tui_set_key_mode (TUI_SINGLE_KEY_MODE);
578 if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
579 prompt = "";
580 else
581 prompt = rl_display_prompt;
583 int c_pos = -1;
584 int c_line = -1;
585 WINDOW *w = TUI_CMD_WIN->handle.get ();
586 int start_line = TUI_CMD_WIN->start_line;
587 wmove (w, start_line, 0);
588 int height = 1;
589 if (prompt != nullptr)
590 tui_puts_internal (w, prompt, &height);
592 int prev_col = getcurx (w);
593 for (int in = 0; in <= rl_end; in++)
595 unsigned char c;
597 if (in == rl_point)
599 getyx (w, c_line, c_pos);
602 if (in == rl_end)
603 break;
605 c = (unsigned char) rl_line_buffer[in];
606 if (CTRL_CHAR (c) || c == RUBOUT)
608 waddch (w, '^');
609 waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
611 else if (c == '\t')
613 /* Expand TABs, since ncurses on MS-Windows doesn't. */
614 int col = getcurx (w);
617 waddch (w, ' ');
618 col++;
619 } while ((col % 8) != 0);
621 else
623 waddch (w, c);
625 if (c == '\n')
626 TUI_CMD_WIN->start_line = getcury (w);
627 int col = getcurx (w);
628 if (col < prev_col)
629 height++;
630 prev_col = col;
632 wclrtobot (w);
633 TUI_CMD_WIN->start_line = getcury (w);
634 if (c_line >= 0)
635 wmove (w, c_line, c_pos);
636 TUI_CMD_WIN->start_line -= height - 1;
638 wrefresh (w);
639 fflush(stdout);
642 /* Readline callback to prepare the terminal. It is called once each
643 time we enter readline. Terminal is already setup in curses
644 mode. */
645 static void
646 tui_prep_terminal (int notused1)
648 #ifdef NCURSES_MOUSE_VERSION
649 if (tui_enable_mouse)
650 mousemask (ALL_MOUSE_EVENTS, NULL);
651 #endif
654 /* Readline callback to restore the terminal. It is called once each
655 time we leave readline. There is nothing to do in curses mode. */
656 static void
657 tui_deprep_terminal (void)
659 #ifdef NCURSES_MOUSE_VERSION
660 mousemask (0, NULL);
661 #endif
664 #ifdef TUI_USE_PIPE_FOR_READLINE
665 /* Read readline output pipe and feed the command window with it.
666 Should be removed when readline is clean. */
667 static void
668 tui_readline_output (int error, gdb_client_data data)
670 int size;
671 char buf[256];
673 size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
674 if (size > 0 && tui_active)
676 buf[size] = 0;
677 tui_puts (buf);
680 #endif
682 /* TUI version of displayer.crlf. */
684 static void
685 tui_mld_crlf (const struct match_list_displayer *displayer)
687 tui_putc ('\n');
690 /* TUI version of displayer.putch. */
692 static void
693 tui_mld_putch (const struct match_list_displayer *displayer, int ch)
695 tui_putc (ch);
698 /* TUI version of displayer.puts. */
700 static void
701 tui_mld_puts (const struct match_list_displayer *displayer, const char *s)
703 tui_puts (s);
706 /* TUI version of displayer.flush. */
708 static void
709 tui_mld_flush (const struct match_list_displayer *displayer)
711 wrefresh (TUI_CMD_WIN->handle.get ());
714 /* TUI version of displayer.erase_entire_line. */
716 static void
717 tui_mld_erase_entire_line (const struct match_list_displayer *displayer)
719 WINDOW *w = TUI_CMD_WIN->handle.get ();
720 int cur_y = getcury (w);
722 wmove (w, cur_y, 0);
723 wclrtoeol (w);
724 wmove (w, cur_y, 0);
727 /* TUI version of displayer.beep. */
729 static void
730 tui_mld_beep (const struct match_list_displayer *displayer)
732 beep ();
735 /* A wrapper for wgetch that enters nonl mode. We We normally want
736 curses' "nl" mode, but when reading from the user, we'd like to
737 differentiate between C-j and C-m, because some users bind these
738 keys differently in their .inputrc. So, put curses into nonl mode
739 just when reading from the user. See PR tui/20819. */
741 static int
742 gdb_wgetch (WINDOW *win)
744 nonl ();
745 int r = wgetch (win);
746 nl ();
747 return r;
750 /* Helper function for tui_mld_read_key.
751 This temporarily replaces tui_getc for use during tab-completion
752 match list display. */
754 static int
755 tui_mld_getc (FILE *fp)
757 WINDOW *w = TUI_CMD_WIN->handle.get ();
758 int c = gdb_wgetch (w);
760 return c;
763 /* TUI version of displayer.read_key. */
765 static int
766 tui_mld_read_key (const struct match_list_displayer *displayer)
768 /* We can't use tui_getc as we need NEWLINE to not get emitted. */
769 scoped_restore restore_getc_function
770 = make_scoped_restore (&rl_getc_function, tui_mld_getc);
771 return rl_read_key ();
774 /* TUI version of rl_completion_display_matches_hook.
775 See gdb_display_match_list for a description of the arguments. */
777 static void
778 tui_rl_display_match_list (char **matches, int len, int max)
780 struct match_list_displayer displayer;
782 rl_get_screen_size (&displayer.height, &displayer.width);
783 displayer.crlf = tui_mld_crlf;
784 displayer.putch = tui_mld_putch;
785 displayer.puts = tui_mld_puts;
786 displayer.flush = tui_mld_flush;
787 displayer.erase_entire_line = tui_mld_erase_entire_line;
788 displayer.beep = tui_mld_beep;
789 displayer.read_key = tui_mld_read_key;
791 gdb_display_match_list (matches, len, max, &displayer);
794 /* Setup the IO for curses or non-curses mode.
795 - In non-curses mode, readline and gdb use the standard input and
796 standard output/error directly.
797 - In curses mode, the standard output/error is controlled by TUI
798 with the tui_stdout and tui_stderr. The output is redirected in
799 the curses command window. Several readline callbacks are installed
800 so that readline asks for its input to the curses command window
801 with wgetch(). */
802 void
803 tui_setup_io (int mode)
805 extern int _rl_echoing_p;
807 if (mode)
809 /* Ensure that readline has been initialized before saving any
810 of its variables. */
811 tui_ensure_readline_initialized ();
813 /* Redirect readline to TUI. */
814 tui_old_rl_redisplay_function = rl_redisplay_function;
815 tui_old_rl_deprep_terminal = rl_deprep_term_function;
816 tui_old_rl_prep_terminal = rl_prep_term_function;
817 tui_old_rl_getc_function = rl_getc_function;
818 tui_old_rl_display_matches_hook = rl_completion_display_matches_hook;
819 tui_old_rl_outstream = rl_outstream;
820 tui_old_rl_echoing_p = _rl_echoing_p;
821 rl_redisplay_function = tui_redisplay_readline;
822 rl_deprep_term_function = tui_deprep_terminal;
823 rl_prep_term_function = tui_prep_terminal;
824 rl_getc_function = tui_getc;
825 _rl_echoing_p = 0;
826 rl_outstream = tui_rl_outstream;
827 rl_prompt = 0;
828 rl_completion_display_matches_hook = tui_rl_display_match_list;
829 rl_already_prompted = 0;
831 /* Keep track of previous gdb output. */
832 tui_old_stdout = gdb_stdout;
833 tui_old_stderr = gdb_stderr;
834 tui_old_stdlog = gdb_stdlog;
835 tui_old_uiout = gdb::checked_static_cast<cli_ui_out *> (current_uiout);
837 /* Reconfigure gdb output. */
838 gdb_stdout = tui_stdout;
839 gdb_stderr = tui_stderr;
840 gdb_stdlog = tui_stdlog;
841 gdb_stdtarg = gdb_stderr;
842 gdb_stdtargerr = gdb_stderr;
843 current_uiout = tui_out;
845 /* Save tty for SIGCONT. */
846 savetty ();
848 else
850 /* Restore gdb output. */
851 gdb_stdout = tui_old_stdout;
852 gdb_stderr = tui_old_stderr;
853 gdb_stdlog = tui_old_stdlog;
854 gdb_stdtarg = gdb_stderr;
855 gdb_stdtargerr = gdb_stderr;
856 current_uiout = tui_old_uiout;
858 /* Restore readline. */
859 rl_redisplay_function = tui_old_rl_redisplay_function;
860 rl_deprep_term_function = tui_old_rl_deprep_terminal;
861 rl_prep_term_function = tui_old_rl_prep_terminal;
862 rl_getc_function = tui_old_rl_getc_function;
863 rl_completion_display_matches_hook = tui_old_rl_display_matches_hook;
864 rl_outstream = tui_old_rl_outstream;
865 _rl_echoing_p = tui_old_rl_echoing_p;
866 rl_already_prompted = 0;
868 /* Save tty for SIGCONT. */
869 savetty ();
871 /* Clean up color information. */
872 last_color_pair = -1;
873 last_style = ui_file_style ();
874 color_map.clear ();
875 color_pair_map.clear ();
879 #ifdef SIGCONT
880 /* Catch SIGCONT to restore the terminal and refresh the screen. */
881 static void
882 tui_cont_sig (int sig)
884 if (tui_active)
886 /* Restore the terminal setting because another process (shell)
887 might have changed it. */
888 resetty ();
890 /* Force a refresh of the screen. */
891 tui_refresh_all_win ();
893 signal (sig, tui_cont_sig);
895 #endif
897 /* Initialize the IO for gdb in curses mode. */
898 void
899 tui_initialize_io (void)
901 #ifdef SIGCONT
902 signal (SIGCONT, tui_cont_sig);
903 #endif
905 /* Create tui output streams. */
906 tui_stdout = new pager_file (new tui_file (stdout, true));
907 tui_stderr = new tui_file (stderr, false);
908 tui_stdlog = new timestamped_file (tui_stderr);
909 tui_out = new cli_ui_out (tui_stdout, 0);
911 /* Create the default UI. */
912 tui_old_uiout = new cli_ui_out (gdb_stdout);
914 #ifdef TUI_USE_PIPE_FOR_READLINE
915 /* Temporary solution for readline writing to stdout: redirect
916 readline output in a pipe, read that pipe and output the content
917 in the curses command window. */
918 if (gdb_pipe_cloexec (tui_readline_pipe) != 0)
919 error (_("Cannot create pipe for readline"));
921 tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
922 if (tui_rl_outstream == 0)
923 error (_("Cannot redirect readline output"));
925 setvbuf (tui_rl_outstream, NULL, _IOLBF, 0);
927 #ifdef O_NONBLOCK
928 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
929 #else
930 #ifdef O_NDELAY
931 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
932 #endif
933 #endif
934 add_file_handler (tui_readline_pipe[0], tui_readline_output, 0, "tui");
935 #else
936 tui_rl_outstream = stdout;
937 #endif
939 #ifdef __MINGW32__
940 /* MS-Windows port of ncurses doesn't support default foreground and
941 background colors, so we must record the default colors at startup. */
942 HANDLE hstdout = (HANDLE)_get_osfhandle (fileno (stdout));
943 DWORD cmode;
944 CONSOLE_SCREEN_BUFFER_INFO csbi;
946 if (hstdout != INVALID_HANDLE_VALUE
947 && GetConsoleMode (hstdout, &cmode) != 0
948 && GetConsoleScreenBufferInfo (hstdout, &csbi))
949 ncurses_norm_attr = csbi.wAttributes;
950 #endif
953 /* Dispatch the correct tui function based upon the mouse event. */
955 #ifdef NCURSES_MOUSE_VERSION
957 static void
958 tui_dispatch_mouse_event ()
960 MEVENT mev;
961 if (getmouse (&mev) != OK)
962 return;
964 for (tui_win_info *wi : all_tui_windows ())
965 if (mev.x > wi->x && mev.x < wi->x + wi->width - 1
966 && mev.y > wi->y && mev.y < wi->y + wi->height - 1)
968 if ((mev.bstate & BUTTON1_CLICKED) != 0
969 || (mev.bstate & BUTTON2_CLICKED) != 0
970 || (mev.bstate & BUTTON3_CLICKED) != 0)
972 int button = (mev.bstate & BUTTON1_CLICKED) != 0 ? 1
973 : ((mev.bstate & BUTTON2_CLICKED) != 0 ? 2
974 : 3);
975 wi->click (mev.x - wi->x - 1, mev.y - wi->y - 1, button);
977 #ifdef BUTTON5_PRESSED
978 else if ((mev.bstate & BUTTON4_PRESSED) != 0)
979 wi->backward_scroll (3);
980 else if ((mev.bstate & BUTTON5_PRESSED) != 0)
981 wi->forward_scroll (3);
982 #endif
983 break;
987 #endif
989 /* Dispatch the correct tui function based upon the control
990 character. */
991 static unsigned int
992 tui_dispatch_ctrl_char (unsigned int ch)
994 struct tui_win_info *win_info = tui_win_with_focus ();
996 /* If no window has the focus, or if the focus window can't scroll,
997 just pass the character through. */
998 if (win_info == NULL || !win_info->can_scroll ())
999 return ch;
1001 switch (ch)
1003 case KEY_NPAGE:
1004 win_info->forward_scroll (0);
1005 break;
1006 case KEY_PPAGE:
1007 win_info->backward_scroll (0);
1008 break;
1009 case KEY_DOWN:
1010 case KEY_SF:
1011 win_info->forward_scroll (1);
1012 break;
1013 case KEY_UP:
1014 case KEY_SR:
1015 win_info->backward_scroll (1);
1016 break;
1017 case KEY_RIGHT:
1018 win_info->left_scroll (1);
1019 break;
1020 case KEY_LEFT:
1021 win_info->right_scroll (1);
1022 break;
1023 default:
1024 /* We didn't recognize the character as a control character, so pass it
1025 through. */
1026 return ch;
1029 /* We intercepted the control character, so return 0 (which readline
1030 will interpret as a no-op). */
1031 return 0;
1034 /* See tui-io.h. */
1036 void
1037 tui_inject_newline_into_command_window ()
1039 gdb_assert (tui_active);
1041 WINDOW *w = TUI_CMD_WIN->handle.get ();
1043 /* When hitting return with an empty input, gdb executes the last
1044 command. If we emit a newline, this fills up the command window
1045 with empty lines with gdb prompt at beginning. Instead of that,
1046 stay on the same line but provide a visual effect to show the
1047 user we recognized the command. */
1048 if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
1050 wmove (w, getcury (w), 0);
1052 /* Clear the line. This will blink the gdb prompt since
1053 it will be redrawn at the same line. */
1054 wclrtoeol (w);
1055 wrefresh (w);
1056 napms (20);
1058 else
1060 /* Move cursor to the end of the command line before emitting the
1061 newline. We need to do so because when ncurses outputs a newline
1062 it truncates any text that appears past the end of the cursor. */
1063 int px, py;
1064 getyx (w, py, px);
1065 px += rl_end - rl_point;
1066 py += px / TUI_CMD_WIN->width;
1067 px %= TUI_CMD_WIN->width;
1068 wmove (w, py, px);
1069 tui_putc ('\n');
1073 /* If we're passing an escape sequence to readline, this points to a
1074 string holding the remaining characters of the sequence to pass.
1075 We advance the pointer one character at a time until '\0' is
1076 reached. */
1077 static const char *cur_seq = nullptr;
1079 /* Set CUR_SEQ to point at the current sequence to pass to readline,
1080 setup to call the input handler again so we complete the sequence
1081 shortly, and return the first character to start the sequence. */
1083 static int
1084 start_sequence (const char *seq)
1086 call_stdin_event_handler_again_p = 1;
1087 cur_seq = seq + 1;
1088 return seq[0];
1091 /* Main worker for tui_getc. Get a character from the command window.
1092 This is called from the readline package, but wrapped in a
1093 try/catch by tui_getc. */
1095 static int
1096 tui_getc_1 (FILE *fp)
1098 int ch;
1099 WINDOW *w;
1101 w = TUI_CMD_WIN->handle.get ();
1103 #ifdef TUI_USE_PIPE_FOR_READLINE
1104 /* Flush readline output. */
1105 tui_readline_output (0, 0);
1106 #endif
1108 /* We enable keypad mode so that curses's wgetch processes mouse
1109 escape sequences. In keypad mode, wgetch also processes the
1110 escape sequences for keys such as up/down etc. and returns KEY_UP
1111 / KEY_DOWN etc. When we have the focus on the command window
1112 though, we want to pass the raw up/down etc. escape codes to
1113 readline so readline understands them. */
1114 if (cur_seq != nullptr)
1116 ch = *cur_seq++;
1118 /* If we've reached the end of the string, we're done with the
1119 sequence. Otherwise, setup to get back here again for
1120 another character. */
1121 if (*cur_seq == '\0')
1122 cur_seq = nullptr;
1123 else
1124 call_stdin_event_handler_again_p = 1;
1125 return ch;
1127 else
1128 ch = gdb_wgetch (w);
1130 /* Handle prev/next/up/down here. */
1131 ch = tui_dispatch_ctrl_char (ch);
1133 #ifdef NCURSES_MOUSE_VERSION
1134 if (ch == KEY_MOUSE)
1136 tui_dispatch_mouse_event ();
1137 return 0;
1139 #endif
1141 /* Translate curses keys back to escape sequences so that readline
1142 can understand them. We do this irrespective of which window has
1143 the focus. If e.g., we're focused on a non-command window, then
1144 the up/down keys will already have been filtered by
1145 tui_dispatch_ctrl_char. Keys that haven't been intercepted will
1146 be passed down to readline. */
1147 if (current_ui->command_editing)
1149 /* For the standard arrow keys + home/end, hardcode sequences
1150 readline understands. See bind_arrow_keys_internal in
1151 readline/readline.c. */
1152 switch (ch)
1154 case KEY_UP:
1155 return start_sequence ("\033[A");
1156 case KEY_DOWN:
1157 return start_sequence ("\033[B");
1158 case KEY_RIGHT:
1159 return start_sequence ("\033[C");
1160 case KEY_LEFT:
1161 return start_sequence ("\033[D");
1162 case KEY_HOME:
1163 return start_sequence ("\033[H");
1164 case KEY_END:
1165 return start_sequence ("\033[F");
1167 /* del and ins are unfortunately not hardcoded in readline for
1168 all systems. */
1170 case KEY_DC: /* del */
1171 #ifdef __MINGW32__
1172 return start_sequence ("\340S");
1173 #else
1174 return start_sequence ("\033[3~");
1175 #endif
1177 case KEY_IC: /* ins */
1178 #if defined __MINGW32__
1179 return start_sequence ("\340R");
1180 #else
1181 return start_sequence ("\033[2~");
1182 #endif
1185 /* Keycodes above KEY_MAX are not guaranteed to be stable.
1186 Compare keyname instead. */
1187 if (ch >= KEY_MAX)
1189 std::string_view name;
1190 const char *name_str = keyname (ch);
1191 if (name_str != nullptr)
1192 name = std::string_view (name_str);
1194 /* The following sequences are hardcoded in readline as
1195 well. */
1197 /* ctrl-arrow keys */
1198 if (name == "kLFT5") /* ctrl-left */
1199 return start_sequence ("\033[1;5D");
1200 else if (name == "kRIT5") /* ctrl-right */
1201 return start_sequence ("\033[1;5C");
1202 else if (name == "kDC5") /* ctrl-del */
1203 return start_sequence ("\033[3;5~");
1205 /* alt-arrow keys */
1206 else if (name == "kLFT3") /* alt-left */
1207 return start_sequence ("\033[1;3D");
1208 else if (name == "kRIT3") /* alt-right */
1209 return start_sequence ("\033[1;3C");
1213 /* Handle the CTRL-L refresh for each window. */
1214 if (ch == '\f')
1216 tui_refresh_all_win ();
1217 return ch;
1220 if (ch == KEY_BACKSPACE)
1221 return '\b';
1223 if (current_ui->command_editing && key_is_start_sequence (ch))
1225 int ch_pending;
1227 nodelay (w, TRUE);
1228 ch_pending = gdb_wgetch (w);
1229 nodelay (w, FALSE);
1231 /* If we have pending input following a start sequence, call the stdin
1232 event handler again because ncurses may have already read and stored
1233 the input into its internal buffer, meaning that we won't get an stdin
1234 event for it. If we don't compensate for this missed stdin event, key
1235 sequences as Alt_F (^[f) will not behave promptly.
1237 (We only compensates for the missed 2nd byte of a key sequence because
1238 2-byte sequences are by far the most commonly used. ncurses may have
1239 buffered a larger, 3+-byte key sequence though it remains to be seen
1240 whether it is useful to compensate for all the bytes of such
1241 sequences.) */
1242 if (ch_pending != ERR)
1244 ungetch (ch_pending);
1245 call_stdin_event_handler_again_p = 1;
1249 if (ch > 0xff)
1251 /* Readline doesn't understand non-8-bit curses keys, filter
1252 them out. */
1253 return 0;
1256 return ch;
1259 /* Get a character from the command window. This is called from the
1260 readline package. */
1262 static int
1263 tui_getc (FILE *fp)
1267 return tui_getc_1 (fp);
1269 catch (const gdb_exception_forced_quit &ex)
1271 /* As noted below, it's not safe to let an exception escape
1272 to newline, so, for this case, reset the quit flag for
1273 later QUIT checking. */
1274 set_force_quit_flag ();
1275 return 0;
1277 catch (const gdb_exception &ex)
1279 /* Just in case, don't ever let an exception escape to readline.
1280 This shouldn't ever happen, but if it does, print the
1281 exception instead of just crashing GDB. */
1282 exception_print (gdb_stderr, ex);
1284 /* If we threw an exception, it's because we recognized the
1285 character. */
1286 return 0;