1 /* TUI support I/O functions.
2 
3    Copyright (C) 1998-2024 Free Software Foundation, Inc.
4 
5    Contributed by Hewlett-Packard Company.
6 
7    This file is part of GDB.
8 
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.
13 
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.
18 
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/>.  */
21 
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"
48 
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"
53 
54 #ifdef __MINGW32__
55 static SHORT ncurses_norm_attr;
56 #endif
57 
58 static int tui_getc (FILE *fp);
59 
60 static int
key_is_start_sequence(int ch)61 key_is_start_sequence (int ch)
62 {
63   return (ch == 27);
64 }
65 
66 /* Use definition from readline 4.3.  */
67 #undef CTRL_CHAR
68 #define CTRL_CHAR(c) \
69      ((c) < control_character_threshold && (((c) & 0x80) == 0))
70 
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.
74 
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).
82 
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.
86 
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.
96 
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.  */
102 
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 */
108 
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;
114 
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;
120 
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;
128 
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
136 
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.  */
140 
141 static void
do_tui_putc(WINDOW * w,char c)142 do_tui_putc (WINDOW *w, char c)
143 {
144   /* Expand TABs, since ncurses on MS-Windows doesn't.  */
145   if (c == '\t')
146     {
147       int col;
148 
149       col = getcurx (w);
150       do
151           {
152             waddch (w, ' ');
153             col++;
154           }
155       while ((col % 8) != 0);
156     }
157   else
158     waddch (w, c);
159 }
160 
161 /* Update the cached value of the command window's start line based on
162    the window's current Y coordinate.  */
163 
164 static void
update_cmdwin_start_line()165 update_cmdwin_start_line ()
166 {
167   TUI_CMD_WIN->start_line = getcury (TUI_CMD_WIN->handle.get ());
168 }
169 
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.  */
173 
174 static void
tui_putc(char c)175 tui_putc (char c)
176 {
177   do_tui_putc (TUI_CMD_WIN->handle.get (), c);
178   update_cmdwin_start_line ();
179 }
180 
181 /* This maps colors to their corresponding color index.  */
182 
183 static std::map<ui_file_style::color, int> color_map;
184 
185 /* This holds a pair of colors and is used to track the mapping
186    between a color pair index and the actual colors.  */
187 
188 struct color_pair
189 {
190   int fg;
191   int bg;
192 
193   bool operator< (const color_pair &o) const
194   {
195     return fg < o.fg || (fg == o.fg && bg < o.bg);
196   }
197 };
198 
199 /* This maps pairs of colors to their corresponding color pair
200    index.  */
201 
202 static std::map<color_pair, int> color_pair_map;
203 
204 /* This is indexed by ANSI color offset from the base color, and holds
205    the corresponding curses color constant.  */
206 
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
216 };
217 
218 /* Given a color, find its index.  */
219 
220 static bool
get_color(const ui_file_style::color & color,int * result)221 get_color (const ui_file_style::color &color, int *result)
222 {
223   if (color.is_none ())
224     *result = -1;
225   else if (color.is_basic ())
226     *result = curses_colors[color.get_value ()];
227   else
228     {
229       auto it = color_map.find (color);
230       if (it == color_map.end ())
231           {
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;
244           }
245       else
246           *result = it->second;
247     }
248   return true;
249 }
250 
251 /* The most recently emitted color pair.  */
252 
253 static int last_color_pair = -1;
254 
255 /* The most recently applied style.  */
256 
257 static ui_file_style last_style;
258 
259 /* If true, we're highlighting the current source line in reverse
260    video mode.  */
261 static bool reverse_mode_p = false;
262 
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);
267 
268 /* Given two colors, return their color pair index; making a new one
269    if necessary.  */
270 
271 static int
get_color_pair(int fg,int bg)272 get_color_pair (int fg, int bg)
273 {
274   color_pair c = { fg, bg };
275   auto it = color_pair_map.find (c);
276   if (it == color_pair_map.end ())
277     {
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;
288     }
289   return it->second;
290 }
291 
292 /* Apply STYLE to W.  */
293 
294 void
tui_apply_style(WINDOW * w,ui_file_style style)295 tui_apply_style (WINDOW *w, ui_file_style style)
296 {
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));
305 
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 ())
309     {
310       int fgi, bgi;
311       if (get_color (fg, &fgi) && get_color (bg, &bgi))
312           {
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;
328           }
329     }
330 
331   switch (style.get_intensity ())
332     {
333     case ui_file_style::NORMAL:
334       break;
335 
336     case ui_file_style::BOLD:
337       wattron (w, A_BOLD);
338       break;
339 
340     case ui_file_style::DIM:
341       wattron (w, A_DIM);
342       break;
343 
344     default:
345       gdb_assert_not_reached ("invalid intensity");
346     }
347 
348   if (style.is_reverse ())
349     wattron (w, A_REVERSE);
350 
351   last_style = style;
352 }
353 
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.  */
359 
360 static size_t
apply_ansi_escape(WINDOW * w,const char * buf)361 apply_ansi_escape (WINDOW *w, const char *buf)
362 {
363   ui_file_style style = last_style;
364   size_t n_read;
365 
366   if (!style.parse (buf, &n_read))
367     return n_read;
368 
369   if (reverse_mode_p)
370     {
371       if (!style_tui_current_position)
372           return n_read;
373 
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.
382 
383            Notes on the approach:
384 
385             - there's no portable way to know which colors the default
386               fb/bg colors map to.
387 
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.
391       */
392       if (!style.is_default ())
393           {
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);
398           }
399 
400       /* Enable A_REVERSE.  */
401       style.set_reverse (true);
402     }
403 
404   tui_apply_style (w, style);
405   return n_read;
406 }
407 
408 /* See tui.io.h.  */
409 
410 void
tui_set_reverse_mode(WINDOW * w,bool reverse)411 tui_set_reverse_mode (WINDOW *w, bool reverse)
412 {
413   ui_file_style style = last_style;
414 
415   reverse_mode_p = reverse;
416 
417   if (reverse)
418     {
419       reverse_save_bg = style.get_background ();
420       reverse_save_fg = style.get_foreground ();
421 
422       if (!style_tui_current_position)
423           {
424             /* Switch to default style (reversed) while highlighting the
425                current position.  */
426             style = {};
427           }
428     }
429   else
430     {
431       style.set_bg (reverse_save_bg);
432       style.set_fg (reverse_save_fg);
433     }
434 
435   style.set_reverse (reverse);
436 
437   tui_apply_style (w, style);
438 }
439 
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.  */
443 
444 void
tui_write(const char * buf,size_t length)445 tui_write (const char *buf, size_t length)
446 {
447   /* We need this to be \0-terminated for the regexp matching.  */
448   std::string copy (buf, length);
449   tui_puts (copy.c_str ());
450 }
451 
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.  */
455 
456 void
tui_puts(const char * string,WINDOW * w)457 tui_puts (const char *string, WINDOW *w)
458 {
459   if (w == nullptr)
460     w = TUI_CMD_WIN->handle.get ();
461 
462   while (true)
463     {
464       const char *next = strpbrk (string, "\n\1\2\033\t");
465 
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);
470 
471       /* We finished.  */
472       if (next == nullptr)
473           break;
474 
475       char c = *next;
476       switch (c)
477           {
478           case '\1':
479           case '\2':
480             /* Ignore these, they are readline escape-marking
481                sequences.  */
482             ++next;
483             break;
484 
485           case '\n':
486           case '\t':
487             do_tui_putc (w, c);
488             ++next;
489             break;
490 
491           case '\033':
492             {
493               size_t bytes_read = apply_ansi_escape (w, next);
494               if (bytes_read > 0)
495                 next += bytes_read;
496               else
497                 {
498                     /* Just drop the escape.  */
499                     ++next;
500                 }
501             }
502             break;
503 
504           default:
505             gdb_assert_not_reached ("missing case in tui_puts");
506           }
507 
508       string = next;
509     }
510 
511   if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
512     update_cmdwin_start_line ();
513 }
514 
515 static void
tui_puts_internal(WINDOW * w,const char * string,int * height)516 tui_puts_internal (WINDOW *w, const char *string, int *height)
517 {
518   char c;
519   int prev_col = 0;
520   bool saw_nl = false;
521 
522   while ((c = *string++) != 0)
523     {
524       if (c == '\1' || c == '\2')
525           {
526             /* Ignore these, they are readline escape-marking
527                sequences.  */
528             continue;
529           }
530 
531       if (c == '\033')
532           {
533             size_t bytes_read = apply_ansi_escape (w, string - 1);
534             if (bytes_read > 0)
535               {
536                 string = string + bytes_read - 1;
537                 continue;
538               }
539           }
540 
541       if (c == '\n')
542           saw_nl = true;
543 
544       do_tui_putc (w, c);
545 
546       if (height != nullptr)
547           {
548             int col = getcurx (w);
549             if (col <= prev_col)
550               ++*height;
551             prev_col = col;
552           }
553     }
554 
555   if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
556     update_cmdwin_start_line ();
557   if (saw_nl)
558     wrefresh (w);
559 }
560 
561 /* Readline callback.
562    Redisplay the command line with its prompt after readline has
563    changed the edited text.  */
564 void
tui_redisplay_readline(void)565 tui_redisplay_readline (void)
566 {
567   const char *prompt;
568 
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);
577 
578   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
579     prompt = "";
580   else
581     prompt = rl_display_prompt;
582 
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);
591 
592   int prev_col = getcurx (w);
593   for (int in = 0; in <= rl_end; in++)
594     {
595       unsigned char c;
596 
597       if (in == rl_point)
598           {
599             getyx (w, c_line, c_pos);
600           }
601 
602       if (in == rl_end)
603           break;
604 
605       c = (unsigned char) rl_line_buffer[in];
606       if (CTRL_CHAR (c) || c == RUBOUT)
607           {
608             waddch (w, '^');
609             waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
610           }
611       else if (c == '\t')
612           {
613             /* Expand TABs, since ncurses on MS-Windows doesn't.  */
614             int col = getcurx (w);
615             do
616               {
617                 waddch (w, ' ');
618                 col++;
619               } while ((col % 8) != 0);
620           }
621       else
622           {
623             waddch (w, c);
624           }
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;
631     }
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;
637 
638   wrefresh (w);
639   fflush(stdout);
640 }
641 
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
tui_prep_terminal(int notused1)646 tui_prep_terminal (int notused1)
647 {
648 #ifdef NCURSES_MOUSE_VERSION
649   if (tui_enable_mouse)
650     mousemask (ALL_MOUSE_EVENTS, NULL);
651 #endif
652 }
653 
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
tui_deprep_terminal(void)657 tui_deprep_terminal (void)
658 {
659 #ifdef NCURSES_MOUSE_VERSION
660   mousemask (0, NULL);
661 #endif
662 }
663 
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
tui_readline_output(int error,gdb_client_data data)668 tui_readline_output (int error, gdb_client_data data)
669 {
670   int size;
671   char buf[256];
672 
673   size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
674   if (size > 0 && tui_active)
675     {
676       buf[size] = 0;
677       tui_puts (buf);
678     }
679 }
680 #endif
681 
682 /* TUI version of displayer.crlf.  */
683 
684 static void
tui_mld_crlf(const struct match_list_displayer * displayer)685 tui_mld_crlf (const struct match_list_displayer *displayer)
686 {
687   tui_putc ('\n');
688 }
689 
690 /* TUI version of displayer.putch.  */
691 
692 static void
tui_mld_putch(const struct match_list_displayer * displayer,int ch)693 tui_mld_putch (const struct match_list_displayer *displayer, int ch)
694 {
695   tui_putc (ch);
696 }
697 
698 /* TUI version of displayer.puts.  */
699 
700 static void
tui_mld_puts(const struct match_list_displayer * displayer,const char * s)701 tui_mld_puts (const struct match_list_displayer *displayer, const char *s)
702 {
703   tui_puts (s);
704 }
705 
706 /* TUI version of displayer.flush.  */
707 
708 static void
tui_mld_flush(const struct match_list_displayer * displayer)709 tui_mld_flush (const struct match_list_displayer *displayer)
710 {
711   wrefresh (TUI_CMD_WIN->handle.get ());
712 }
713 
714 /* TUI version of displayer.erase_entire_line.  */
715 
716 static void
tui_mld_erase_entire_line(const struct match_list_displayer * displayer)717 tui_mld_erase_entire_line (const struct match_list_displayer *displayer)
718 {
719   WINDOW *w = TUI_CMD_WIN->handle.get ();
720   int cur_y = getcury (w);
721 
722   wmove (w, cur_y, 0);
723   wclrtoeol (w);
724   wmove (w, cur_y, 0);
725 }
726 
727 /* TUI version of displayer.beep.  */
728 
729 static void
tui_mld_beep(const struct match_list_displayer * displayer)730 tui_mld_beep (const struct match_list_displayer *displayer)
731 {
732   beep ();
733 }
734 
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.  */
740 
741 static int
gdb_wgetch(WINDOW * win)742 gdb_wgetch (WINDOW *win)
743 {
744   nonl ();
745   int r = wgetch (win);
746   nl ();
747   return r;
748 }
749 
750 /* Helper function for tui_mld_read_key.
751    This temporarily replaces tui_getc for use during tab-completion
752    match list display.  */
753 
754 static int
tui_mld_getc(FILE * fp)755 tui_mld_getc (FILE *fp)
756 {
757   WINDOW *w = TUI_CMD_WIN->handle.get ();
758   int c = gdb_wgetch (w);
759 
760   return c;
761 }
762 
763 /* TUI version of displayer.read_key.  */
764 
765 static int
tui_mld_read_key(const struct match_list_displayer * displayer)766 tui_mld_read_key (const struct match_list_displayer *displayer)
767 {
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 ();
772 }
773 
774 /* TUI version of rl_completion_display_matches_hook.
775    See gdb_display_match_list for a description of the arguments.  */
776 
777 static void
tui_rl_display_match_list(char ** matches,int len,int max)778 tui_rl_display_match_list (char **matches, int len, int max)
779 {
780   struct match_list_displayer displayer;
781 
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;
790 
791   gdb_display_match_list (matches, len, max, &displayer);
792 }
793 
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
tui_setup_io(int mode)803 tui_setup_io (int mode)
804 {
805   extern int _rl_echoing_p;
806 
807   if (mode)
808     {
809       /* Ensure that readline has been initialized before saving any
810            of its variables.  */
811       tui_ensure_readline_initialized ();
812 
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;
830 
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);
836 
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       current_uiout = tui_out;
843 
844       /* Save tty for SIGCONT.  */
845       savetty ();
846     }
847   else
848     {
849       /* Restore gdb output.  */
850       gdb_stdout = tui_old_stdout;
851       gdb_stderr = tui_old_stderr;
852       gdb_stdlog = tui_old_stdlog;
853       gdb_stdtarg = gdb_stderr;
854       current_uiout = tui_old_uiout;
855 
856       /* Restore readline.  */
857       rl_redisplay_function = tui_old_rl_redisplay_function;
858       rl_deprep_term_function = tui_old_rl_deprep_terminal;
859       rl_prep_term_function = tui_old_rl_prep_terminal;
860       rl_getc_function = tui_old_rl_getc_function;
861       rl_completion_display_matches_hook = tui_old_rl_display_matches_hook;
862       rl_outstream = tui_old_rl_outstream;
863       _rl_echoing_p = tui_old_rl_echoing_p;
864       rl_already_prompted = 0;
865 
866       /* Save tty for SIGCONT.  */
867       savetty ();
868 
869       /* Clean up color information.  */
870       last_color_pair = -1;
871       last_style = ui_file_style ();
872       color_map.clear ();
873       color_pair_map.clear ();
874     }
875 }
876 
877 #ifdef SIGCONT
878 /* Catch SIGCONT to restore the terminal and refresh the screen.  */
879 static void
tui_cont_sig(int sig)880 tui_cont_sig (int sig)
881 {
882   if (tui_active)
883     {
884       /* Restore the terminal setting because another process (shell)
885            might have changed it.  */
886       resetty ();
887 
888       /* Force a refresh of the screen.  */
889       tui_refresh_all_win ();
890     }
891   signal (sig, tui_cont_sig);
892 }
893 #endif
894 
895 /* Initialize the IO for gdb in curses mode.  */
896 void
tui_initialize_io(void)897 tui_initialize_io (void)
898 {
899 #ifdef SIGCONT
900   signal (SIGCONT, tui_cont_sig);
901 #endif
902 
903   /* Create tui output streams.  */
904   tui_stdout = new pager_file (new tui_file (stdout, true));
905   tui_stderr = new tui_file (stderr, false);
906   tui_stdlog = new timestamped_file (tui_stderr);
907   tui_out = new cli_ui_out (tui_stdout, 0);
908 
909   /* Create the default UI.  */
910   tui_old_uiout = new cli_ui_out (gdb_stdout);
911 
912 #ifdef TUI_USE_PIPE_FOR_READLINE
913   /* Temporary solution for readline writing to stdout: redirect
914      readline output in a pipe, read that pipe and output the content
915      in the curses command window.  */
916   if (gdb_pipe_cloexec (tui_readline_pipe) != 0)
917     error (_("Cannot create pipe for readline"));
918 
919   tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
920   if (tui_rl_outstream == 0)
921     error (_("Cannot redirect readline output"));
922 
923   setvbuf (tui_rl_outstream, NULL, _IOLBF, 0);
924 
925 #ifdef O_NONBLOCK
926   (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
927 #else
928 #ifdef O_NDELAY
929   (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
930 #endif
931 #endif
932   add_file_handler (tui_readline_pipe[0], tui_readline_output, 0, "tui");
933 #else
934   tui_rl_outstream = stdout;
935 #endif
936 
937 #ifdef __MINGW32__
938   /* MS-Windows port of ncurses doesn't support default foreground and
939      background colors, so we must record the default colors at startup.  */
940   HANDLE hstdout = (HANDLE)_get_osfhandle (fileno (stdout));
941   DWORD cmode;
942   CONSOLE_SCREEN_BUFFER_INFO csbi;
943 
944   if (hstdout != INVALID_HANDLE_VALUE
945       && GetConsoleMode (hstdout, &cmode) != 0
946       && GetConsoleScreenBufferInfo (hstdout, &csbi))
947     ncurses_norm_attr = csbi.wAttributes;
948 #endif
949 }
950 
951 /* Dispatch the correct tui function based upon the mouse event.  */
952 
953 #ifdef NCURSES_MOUSE_VERSION
954 
955 static void
tui_dispatch_mouse_event()956 tui_dispatch_mouse_event ()
957 {
958   MEVENT mev;
959   if (getmouse (&mev) != OK)
960     return;
961 
962   for (tui_win_info *wi : all_tui_windows ())
963     if (mev.x > wi->x && mev.x < wi->x + wi->width - 1
964           && mev.y > wi->y && mev.y < wi->y + wi->height - 1)
965       {
966           if ((mev.bstate & BUTTON1_CLICKED) != 0
967               || (mev.bstate & BUTTON2_CLICKED) != 0
968               || (mev.bstate & BUTTON3_CLICKED) != 0)
969             {
970               int button = (mev.bstate & BUTTON1_CLICKED) != 0 ? 1
971                 :         ((mev.bstate & BUTTON2_CLICKED) != 0 ? 2
972                                : 3);
973               wi->click (mev.x - wi->x - 1, mev.y - wi->y - 1, button);
974             }
975 #ifdef BUTTON5_PRESSED
976           else if ((mev.bstate & BUTTON4_PRESSED) != 0)
977             wi->backward_scroll (3);
978           else if ((mev.bstate & BUTTON5_PRESSED) != 0)
979             wi->forward_scroll (3);
980 #endif
981           break;
982       }
983 }
984 
985 #endif
986 
987 /* Dispatch the correct tui function based upon the control
988    character.  */
989 static unsigned int
tui_dispatch_ctrl_char(unsigned int ch)990 tui_dispatch_ctrl_char (unsigned int ch)
991 {
992   struct tui_win_info *win_info = tui_win_with_focus ();
993 
994   /* If no window has the focus, or if the focus window can't scroll,
995      just pass the character through.  */
996   if (win_info == NULL || !win_info->can_scroll ())
997     return ch;
998 
999   switch (ch)
1000     {
1001     case KEY_NPAGE:
1002       win_info->forward_scroll (0);
1003       break;
1004     case KEY_PPAGE:
1005       win_info->backward_scroll (0);
1006       break;
1007     case KEY_DOWN:
1008     case KEY_SF:
1009       win_info->forward_scroll (1);
1010       break;
1011     case KEY_UP:
1012     case KEY_SR:
1013       win_info->backward_scroll (1);
1014       break;
1015     case KEY_RIGHT:
1016       win_info->left_scroll (1);
1017       break;
1018     case KEY_LEFT:
1019       win_info->right_scroll (1);
1020       break;
1021     default:
1022       /* We didn't recognize the character as a control character, so pass it
1023            through.  */
1024       return ch;
1025     }
1026 
1027   /* We intercepted the control character, so return 0 (which readline
1028      will interpret as a no-op).  */
1029   return 0;
1030 }
1031 
1032 /* See tui-io.h.   */
1033 
1034 void
tui_inject_newline_into_command_window()1035 tui_inject_newline_into_command_window ()
1036 {
1037   gdb_assert (tui_active);
1038 
1039   WINDOW *w = TUI_CMD_WIN->handle.get ();
1040 
1041   /* When hitting return with an empty input, gdb executes the last
1042      command.  If we emit a newline, this fills up the command window
1043      with empty lines with gdb prompt at beginning.  Instead of that,
1044      stay on the same line but provide a visual effect to show the
1045      user we recognized the command.  */
1046   if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
1047     {
1048       wmove (w, getcury (w), 0);
1049 
1050       /* Clear the line.  This will blink the gdb prompt since
1051            it will be redrawn at the same line.  */
1052       wclrtoeol (w);
1053       wrefresh (w);
1054       napms (20);
1055     }
1056   else
1057     {
1058       /* Move cursor to the end of the command line before emitting the
1059            newline.  We need to do so because when ncurses outputs a newline
1060            it truncates any text that appears past the end of the cursor.  */
1061       int px, py;
1062       getyx (w, py, px);
1063       px += rl_end - rl_point;
1064       py += px / TUI_CMD_WIN->width;
1065       px %= TUI_CMD_WIN->width;
1066       wmove (w, py, px);
1067       tui_putc ('\n');
1068     }
1069 }
1070 
1071 /* If we're passing an escape sequence to readline, this points to a
1072    string holding the remaining characters of the sequence to pass.
1073    We advance the pointer one character at a time until '\0' is
1074    reached.  */
1075 static const char *cur_seq = nullptr;
1076 
1077 /* Set CUR_SEQ to point at the current sequence to pass to readline,
1078    setup to call the input handler again so we complete the sequence
1079    shortly, and return the first character to start the sequence.  */
1080 
1081 static int
start_sequence(const char * seq)1082 start_sequence (const char *seq)
1083 {
1084   call_stdin_event_handler_again_p = 1;
1085   cur_seq = seq + 1;
1086   return seq[0];
1087 }
1088 
1089 /* Main worker for tui_getc.  Get a character from the command window.
1090    This is called from the readline package, but wrapped in a
1091    try/catch by tui_getc.  */
1092 
1093 static int
tui_getc_1(FILE * fp)1094 tui_getc_1 (FILE *fp)
1095 {
1096   int ch;
1097   WINDOW *w;
1098 
1099   w = TUI_CMD_WIN->handle.get ();
1100 
1101 #ifdef TUI_USE_PIPE_FOR_READLINE
1102   /* Flush readline output.  */
1103   tui_readline_output (0, 0);
1104 #endif
1105 
1106   /* We enable keypad mode so that curses's wgetch processes mouse
1107      escape sequences.  In keypad mode, wgetch also processes the
1108      escape sequences for keys such as up/down etc. and returns KEY_UP
1109      / KEY_DOWN etc.  When we have the focus on the command window
1110      though, we want to pass the raw up/down etc. escape codes to
1111      readline so readline understands them.  */
1112   if (cur_seq != nullptr)
1113     {
1114       ch = *cur_seq++;
1115 
1116       /* If we've reached the end of the string, we're done with the
1117            sequence.  Otherwise, setup to get back here again for
1118            another character.  */
1119       if (*cur_seq == '\0')
1120           cur_seq = nullptr;
1121       else
1122           call_stdin_event_handler_again_p = 1;
1123       return ch;
1124     }
1125   else
1126     ch = gdb_wgetch (w);
1127 
1128   /* Handle prev/next/up/down here.  */
1129   ch = tui_dispatch_ctrl_char (ch);
1130 
1131 #ifdef NCURSES_MOUSE_VERSION
1132   if (ch == KEY_MOUSE)
1133     {
1134       tui_dispatch_mouse_event ();
1135       return 0;
1136     }
1137 #endif
1138 
1139   /* Translate curses keys back to escape sequences so that readline
1140      can understand them.  We do this irrespective of which window has
1141      the focus.  If e.g., we're focused on a non-command window, then
1142      the up/down keys will already have been filtered by
1143      tui_dispatch_ctrl_char.  Keys that haven't been intercepted will
1144      be passed down to readline.  */
1145   if (current_ui->command_editing)
1146     {
1147       /* For the standard arrow keys + home/end, hardcode sequences
1148            readline understands.  See bind_arrow_keys_internal in
1149            readline/readline.c.  */
1150       switch (ch)
1151           {
1152           case KEY_UP:
1153             return start_sequence ("\033[A");
1154           case KEY_DOWN:
1155             return start_sequence ("\033[B");
1156           case KEY_RIGHT:
1157             return start_sequence ("\033[C");
1158           case KEY_LEFT:
1159             return start_sequence ("\033[D");
1160           case KEY_HOME:
1161             return start_sequence ("\033[H");
1162           case KEY_END:
1163             return start_sequence ("\033[F");
1164 
1165           /* del and ins are unfortunately not hardcoded in readline for
1166              all systems.  */
1167 
1168           case KEY_DC: /* del */
1169 #ifdef __MINGW32__
1170             return start_sequence ("\340S");
1171 #else
1172             return start_sequence ("\033[3~");
1173 #endif
1174 
1175           case KEY_IC: /* ins */
1176 #if defined __MINGW32__
1177             return start_sequence ("\340R");
1178 #else
1179             return start_sequence ("\033[2~");
1180 #endif
1181           }
1182 
1183       /* Keycodes above KEY_MAX are not guaranteed to be stable.
1184            Compare keyname instead.  */
1185       if (ch >= KEY_MAX)
1186           {
1187             std::string_view name;
1188             const char *name_str = keyname (ch);
1189             if (name_str != nullptr)
1190               name = std::string_view (name_str);
1191 
1192             /* The following sequences are hardcoded in readline as
1193                well.  */
1194 
1195             /* ctrl-arrow keys */
1196             if (name == "kLFT5") /* ctrl-left */
1197               return start_sequence ("\033[1;5D");
1198             else if (name == "kRIT5") /* ctrl-right */
1199               return start_sequence ("\033[1;5C");
1200             else if (name == "kDC5") /* ctrl-del */
1201               return start_sequence ("\033[3;5~");
1202 
1203             /* alt-arrow keys */
1204             else if (name == "kLFT3") /* alt-left */
1205               return start_sequence ("\033[1;3D");
1206             else if (name == "kRIT3") /* alt-right */
1207               return start_sequence ("\033[1;3C");
1208           }
1209     }
1210 
1211   /* Handle the CTRL-L refresh for each window.  */
1212   if (ch == '\f')
1213     {
1214       tui_refresh_all_win ();
1215       return ch;
1216     }
1217 
1218   if (ch == KEY_BACKSPACE)
1219     return '\b';
1220 
1221   if (current_ui->command_editing && key_is_start_sequence (ch))
1222     {
1223       int ch_pending;
1224 
1225       nodelay (w, TRUE);
1226       ch_pending = gdb_wgetch (w);
1227       nodelay (w, FALSE);
1228 
1229       /* If we have pending input following a start sequence, call the stdin
1230            event handler again because ncurses may have already read and stored
1231            the input into its internal buffer, meaning that we won't get an stdin
1232            event for it.  If we don't compensate for this missed stdin event, key
1233            sequences as Alt_F (^[f) will not behave promptly.
1234 
1235            (We only compensates for the missed 2nd byte of a key sequence because
1236            2-byte sequences are by far the most commonly used. ncurses may have
1237            buffered a larger, 3+-byte key sequence though it remains to be seen
1238            whether it is useful to compensate for all the bytes of such
1239            sequences.)  */
1240       if (ch_pending != ERR)
1241           {
1242             ungetch (ch_pending);
1243             call_stdin_event_handler_again_p = 1;
1244           }
1245     }
1246 
1247   if (ch > 0xff)
1248     {
1249       /* Readline doesn't understand non-8-bit curses keys, filter
1250            them out.  */
1251       return 0;
1252     }
1253 
1254   return ch;
1255 }
1256 
1257 /* Get a character from the command window.  This is called from the
1258    readline package.  */
1259 
1260 static int
tui_getc(FILE * fp)1261 tui_getc (FILE *fp)
1262 {
1263   try
1264     {
1265       return tui_getc_1 (fp);
1266     }
1267   catch (const gdb_exception_forced_quit &ex)
1268     {
1269       /* As noted below, it's not safe to let an exception escape
1270            to newline, so, for this case, reset the quit flag for
1271            later QUIT checking.  */
1272       set_force_quit_flag ();
1273       return 0;
1274     }
1275   catch (const gdb_exception &ex)
1276     {
1277       /* Just in case, don't ever let an exception escape to readline.
1278            This shouldn't ever happen, but if it does, print the
1279            exception instead of just crashing GDB.  */
1280       exception_print (gdb_stderr, ex);
1281 
1282       /* If we threw an exception, it's because we recognized the
1283            character.  */
1284       return 0;
1285     }
1286 }
1287