diff options
author | Simon Marchi <simon.marchi@efficios.com> | 2023-04-28 14:27:11 -0400 |
---|---|---|
committer | Simon Marchi <simon.marchi@efficios.com> | 2023-05-01 15:40:54 -0400 |
commit | 13d03262f25bfbf15e4a5f1d867cca243c7ee3ca (patch) | |
tree | 882bd6ca945e1ab7f1bc31f64b2b425b382a9271 /gdb/ui.c | |
parent | 7d3b43a15bd4267b5782ca40c0bb1dec1fa3f476 (diff) | |
download | binutils-13d03262f25bfbf15e4a5f1d867cca243c7ee3ca.zip binutils-13d03262f25bfbf15e4a5f1d867cca243c7ee3ca.tar.gz binutils-13d03262f25bfbf15e4a5f1d867cca243c7ee3ca.tar.bz2 |
gdb: move struct ui and related things to ui.{c,h}
I'd like to move some things so they become methods on struct ui. But
first, I think that struct ui and the related things are big enough to
deserve their own file, instead of being scattered through top.{c,h} and
event-top.c.
Change-Id: I15594269ace61fd76ef80a7b58f51ff3ab6979bc
Diffstat (limited to 'gdb/ui.c')
-rw-r--r-- | gdb/ui.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/gdb/ui.c b/gdb/ui.c new file mode 100644 index 0000000..5fe0012 --- /dev/null +++ b/gdb/ui.c @@ -0,0 +1,251 @@ +/* Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "ui.h" + +#include "cli/cli-cmds.h" +#include "event-top.h" +#include "gdbsupport/buildargv.h" +#include "gdbsupport/filestuff.h" +#include "gdbsupport/gdb_file.h" +#include "gdbsupport/scoped_fd.h" +#include "interps.h" +#include "pager.h" +#include "main.h" +#include "top.h" + +/* See top.h. */ + +struct ui *main_ui; +struct ui *current_ui; +struct ui *ui_list; + +/* The highest UI number ever assigned. */ + +static int highest_ui_num; + +/* See top.h. */ + +ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_) + : num (++highest_ui_num), + stdin_stream (instream_), + instream (instream_), + outstream (outstream_), + errstream (errstream_), + input_fd (fileno (instream)), + m_input_interactive_p (ISATTY (instream)), + m_gdb_stdout (new pager_file (new stdio_file (outstream))), + m_gdb_stdin (new stdio_file (instream)), + m_gdb_stderr (new stderr_file (errstream)), + m_gdb_stdlog (new timestamped_file (m_gdb_stderr)) +{ + unbuffer_stream (instream_); + + if (ui_list == NULL) + ui_list = this; + else + { + struct ui *last; + + for (last = ui_list; last->next != NULL; last = last->next) + ; + last->next = this; + } +} + +ui::~ui () +{ + struct ui *ui, *uiprev; + + uiprev = NULL; + + for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next) + if (ui == this) + break; + + gdb_assert (ui != NULL); + + if (uiprev != NULL) + uiprev->next = next; + else + ui_list = next; + + delete m_gdb_stdin; + delete m_gdb_stdout; + delete m_gdb_stderr; +} + + +/* Returns whether GDB is running on an interactive terminal. */ + +bool +ui::input_interactive_p () const +{ + if (batch_flag) + return false; + + if (interactive_mode != AUTO_BOOLEAN_AUTO) + return interactive_mode == AUTO_BOOLEAN_TRUE; + + return m_input_interactive_p; +} + + +/* When there is an event ready on the stdin file descriptor, instead + of calling readline directly throught the callback function, or + instead of calling gdb_readline_no_editing_callback, give gdb a + chance to detect errors and do something. */ + +static void +stdin_event_handler (int error, gdb_client_data client_data) +{ + struct ui *ui = (struct ui *) client_data; + + if (error) + { + /* Switch to the main UI, so diagnostics always go there. */ + current_ui = main_ui; + + ui->unregister_file_handler (); + if (main_ui == ui) + { + /* If stdin died, we may as well kill gdb. */ + gdb_printf (gdb_stderr, _("error detected on stdin\n")); + quit_command ((char *) 0, 0); + } + else + { + /* Simply delete the UI. */ + delete ui; + } + } + else + { + /* Switch to the UI whose input descriptor woke up the event + loop. */ + current_ui = ui; + + /* This makes sure a ^C immediately followed by further input is + always processed in that order. E.g,. with input like + "^Cprint 1\n", the SIGINT handler runs, marks the async + signal handler, and then select/poll may return with stdin + ready, instead of -1/EINTR. The + gdb.base/double-prompt-target-event-error.exp test exercises + this. */ + QUIT; + + do + { + call_stdin_event_handler_again_p = 0; + ui->call_readline (client_data); + } + while (call_stdin_event_handler_again_p != 0); + } +} + +/* See top.h. */ + +void +ui::register_file_handler () +{ + if (input_fd != -1) + add_file_handler (input_fd, stdin_event_handler, this, + string_printf ("ui-%d", num), true); +} + +/* See top.h. */ + +void +ui::unregister_file_handler () +{ + if (input_fd != -1) + delete_file_handler (input_fd); +} + +/* Open file named NAME for read/write, making sure not to make it the + controlling terminal. */ + +static gdb_file_up +open_terminal_stream (const char *name) +{ + scoped_fd fd = gdb_open_cloexec (name, O_RDWR | O_NOCTTY, 0); + if (fd.get () < 0) + perror_with_name (_("opening terminal failed")); + + return fd.to_file ("w+"); +} + +/* Implementation of the "new-ui" command. */ + +static void +new_ui_command (const char *args, int from_tty) +{ + int argc; + const char *interpreter_name; + const char *tty_name; + + dont_repeat (); + + gdb_argv argv (args); + argc = argv.count (); + + if (argc < 2) + error (_("Usage: new-ui INTERPRETER TTY")); + + interpreter_name = argv[0]; + tty_name = argv[1]; + + { + scoped_restore save_ui = make_scoped_restore (¤t_ui); + + /* Open specified terminal. Note: we used to open it three times, + once for each of stdin/stdout/stderr, but that does not work + with Windows named pipes. */ + gdb_file_up stream = open_terminal_stream (tty_name); + + std::unique_ptr<ui> ui + (new struct ui (stream.get (), stream.get (), stream.get ())); + + ui->async = 1; + + current_ui = ui.get (); + + set_top_level_interpreter (interpreter_name); + + interp_pre_command_loop (top_level_interpreter ()); + + /* Make sure the file is not closed. */ + stream.release (); + + ui.release (); + } + + gdb_printf ("New UI allocated\n"); +} + +void _initialize_ui (); +void +_initialize_ui () +{ + cmd_list_element *c = add_cmd ("new-ui", class_support, new_ui_command, _("\ +Create a new UI.\n\ +Usage: new-ui INTERPRETER TTY\n\ +The first argument is the name of the interpreter to run.\n\ +The second argument is the terminal the UI runs on."), &cmdlist); + set_cmd_completer (c, interpreter_completer); +} |