X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftop.c;h=af27fcbcb0e3ea77b6dc3fe6bfb3dbc759dbcba8;hb=8cff8730f43548d17530c9d31aac1d381351addc;hp=65143d1bba355f41be6e40d5b700d6561fd4d849;hpb=8d7493201cf01c9836403695f67f7e157341bfd5;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/top.c b/gdb/top.c index 65143d1bba..af27fcbcb0 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -1,6 +1,6 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright (C) 1986-2015 Free Software Foundation, Inc. + Copyright (C) 1986-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -35,6 +35,7 @@ #include "value.h" #include "language.h" #include "terminal.h" /* For job_control. */ +#include "job-control.h" #include "annotate.h" #include "completer.h" #include "top.h" @@ -50,6 +51,8 @@ #include "maint.h" #include "filenames.h" #include "frame.h" +#include "buffer.h" +#include "gdb_select.h" /* readline include files. */ #include "readline/readline.h" @@ -72,6 +75,10 @@ # include "tui/tui.h" #endif +#ifndef O_NOCTTY +# define O_NOCTTY 0 +#endif + extern void initialize_all_files (void); #define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt @@ -84,6 +91,22 @@ extern void initialize_all_files (void); #define DEFAULT_PROMPT "(gdb) " #endif +/* Generate a function that exports a pointer to a field of the + current UI. */ + +#define gen_ret_current_ui_field_ptr(type, name) \ +type * \ +current_ui_## name ## _ptr (void) \ +{ \ + return ¤t_ui->m_ ## name; \ +} + +gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdout) +gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdin) +gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stderr) +gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdlog) +gen_ret_current_ui_field_ptr (struct ui_out *, current_uiout) + /* Initialization file name for gdb. This is host-dependent. */ const char gdbinit[] = GDBINIT; @@ -106,35 +129,13 @@ show_confirm (struct ui_file *file, int from_tty, value); } -/* stdio stream that command input is being read from. Set to stdin - normally. Set by source_command to the file we are sourcing. Set - to NULL if we are executing a user-defined command or interacting - via a GUI. */ - -FILE *instream; - -/* Flag to indicate whether a user defined command is currently running. */ - -int in_user_command; - /* Current working directory. */ char *current_directory; -/* The directory name is actually stored here (usually). */ -char gdb_dirbuf[1024]; - -/* Function to call before reading a command, if nonzero. - The function receives two args: an input stream, - and a prompt string. */ - -void (*window_hook) (FILE *, char *); - -/* Buffer used for reading command lines, and the size - allocated for it so far. */ - +/* The last command line executed on the console. Used for command + repetitions. */ char *saved_command_line; -int saved_command_line_size = 100; /* Nonzero if the current command is modified by "server ". This affects things like recording into the command history, commands @@ -211,7 +212,7 @@ void (*deprecated_warning_hook) (const char *, va_list); called to notify the GUI that we are done with the interaction window and it can close it. */ -void (*deprecated_readline_begin_hook) (char *, ...); +void (*deprecated_readline_begin_hook) (const char *, ...); char *(*deprecated_readline_hook) (const char *); void (*deprecated_readline_end_hook) (void); @@ -243,6 +244,138 @@ void (*deprecated_call_command_hook) (struct cmd_list_element * c, void (*deprecated_context_hook) (int id); +/* The highest UI number ever assigned. */ +static int highest_ui_num; + +/* See top.h. */ + +ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_) + : next (nullptr), + num (++highest_ui_num), + call_readline (nullptr), + input_handler (nullptr), + command_editing (0), + interp_info (nullptr), + async (0), + secondary_prompt_depth (0), + stdin_stream (instream_), + instream (instream_), + outstream (outstream_), + errstream (errstream_), + input_fd (fileno (instream)), + input_interactive_p (ISATTY (instream)), + prompt_state (PROMPT_NEEDED), + m_gdb_stdout (new stdio_file (outstream)), + m_gdb_stdin (new stdio_file (instream)), + m_gdb_stderr (new stderr_file (errstream)), + m_gdb_stdlog (m_gdb_stderr), + m_current_uiout (nullptr) +{ + buffer_init (&line_buffer); + + 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; +} + +/* 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) +{ + int fd; + + fd = gdb_open_cloexec (name, O_RDWR | O_NOCTTY, 0); + if (fd < 0) + perror_with_name (_("opening terminal failed")); + + return gdb_file_up (fdopen (fd, "w+")); +} + +/* Implementation of the "new-ui" command. */ + +static void +new_ui_command (const char *args, int from_tty) +{ + struct interp *interp; + gdb_file_up stream[3]; + int i; + int res; + 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_name = argv[0]; + tty_name = argv[1]; + + { + scoped_restore save_ui = make_scoped_restore (¤t_ui); + + /* Open specified terminal, once for each of + stdin/stdout/stderr. */ + for (i = 0; i < 3; i++) + stream[i] = open_terminal_stream (tty_name); + + std::unique_ptr ui + (new struct ui (stream[0].get (), stream[1].get (), stream[2].get ())); + + ui->async = 1; + + current_ui = ui.get (); + + set_top_level_interpreter (interpreter_name); + + interp_pre_command_loop (top_level_interpreter ()); + + /* Make sure the files are not closed. */ + stream[0].release (); + stream[1].release (); + stream[2].release (); + + ui.release (); + } + + printf_unfiltered ("New UI allocated\n"); +} + /* Handler for SIGHUP. */ #ifdef SIGHUP @@ -271,26 +404,28 @@ quit_cover (void) event-top.c into this file, top.c. */ /* static */ const char *source_file_name; -/* Clean up on error during a "source" command (or execution of a - user-defined command). */ - -void -do_restore_instream_cleanup (void *stream) -{ - /* Restore the previous input stream. */ - instream = stream; -} - /* Read commands from STREAM. */ void read_command_file (FILE *stream) { - struct cleanup *cleanups; + struct ui *ui = current_ui; + + scoped_restore save_instream + = make_scoped_restore (&ui->instream, stream); - cleanups = make_cleanup (do_restore_instream_cleanup, instream); - instream = stream; - command_loop (); - do_cleanups (cleanups); + /* Read commands from `instream' and execute them until end of file + or error reading instream. */ + + while (ui->instream != NULL && !feof (ui->instream)) + { + char *command; + + /* Get a command-line. This calls the readline package. */ + command = command_line_input (NULL, 0, NULL); + if (command == NULL) + break; + command_handler (command); + } } void (*pre_init_ui_hook) (void); @@ -299,7 +434,7 @@ void (*pre_init_ui_hook) (void); static void do_chdir_cleanup (void *old_dir) { - chdir (old_dir); + chdir ((const char *) old_dir); xfree (old_dir); } #endif @@ -367,6 +502,20 @@ check_frame_language_change (void) /* See top.h. */ +void +wait_sync_command_done (void) +{ + /* Processing events may change the current UI. */ + scoped_restore save_ui = make_scoped_restore (¤t_ui); + struct ui *ui = current_ui; + + while (gdb_do_one_event () >= 0) + if (ui->prompt_state != PROMPT_BLOCKED) + break; +} + +/* See top.h. */ + void maybe_wait_sync_command_done (int was_sync) { @@ -374,12 +523,10 @@ maybe_wait_sync_command_done (int was_sync) command's list, running command hooks or similars), and we just ran a synchronous command that started the target, wait for that command to end. */ - if (!interpreter_async && !was_sync && sync_execution) - { - while (gdb_do_one_event () >= 0) - if (!sync_execution) - break; - } + if (!current_ui->async + && !was_sync + && current_ui->prompt_state == PROMPT_BLOCKED) + wait_sync_command_done (); } /* Execute the line P as a command, in the current user context. @@ -415,7 +562,7 @@ execute_command (char *p, int from_tty) { const char *cmd = p; char *arg; - int was_sync = sync_execution; + int was_sync = current_ui->prompt_state == PROMPT_BLOCKED; line = p; @@ -485,92 +632,38 @@ execute_command (char *p, int from_tty) returned string, do not display it to the screen. BATCH_FLAG will be temporarily set to true. */ -char * +std::string execute_command_to_string (char *p, int from_tty) { - struct ui_file *str_file; - struct cleanup *cleanup; - char *retval; - /* GDB_STDOUT should be better already restored during these restoration callbacks. */ - cleanup = set_batch_flag_and_make_cleanup_restore_page_info (); - - make_cleanup_restore_integer (&interpreter_async); - interpreter_async = 0; - - str_file = mem_fileopen (); + set_batch_flag_and_restore_page_info save_page_info; - make_cleanup_ui_file_delete (str_file); - make_cleanup_restore_ui_file (&gdb_stdout); - make_cleanup_restore_ui_file (&gdb_stderr); - make_cleanup_restore_ui_file (&gdb_stdlog); - make_cleanup_restore_ui_file (&gdb_stdtarg); - make_cleanup_restore_ui_file (&gdb_stdtargerr); + scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); - if (ui_out_redirect (current_uiout, str_file) < 0) - warning (_("Current output protocol does not support redirection")); - else - make_cleanup_ui_out_redirect_pop (current_uiout); - - gdb_stdout = str_file; - gdb_stderr = str_file; - gdb_stdlog = str_file; - gdb_stdtarg = str_file; - gdb_stdtargerr = str_file; - - execute_command (p, from_tty); - - retval = ui_file_xstrdup (str_file, NULL); + string_file str_file; - do_cleanups (cleanup); - - return retval; + { + current_uiout->redirect (&str_file); + ui_out_redirect_pop redirect_popper (current_uiout); + + scoped_restore save_stdout + = make_scoped_restore (&gdb_stdout, &str_file); + scoped_restore save_stderr + = make_scoped_restore (&gdb_stderr, &str_file); + scoped_restore save_stdlog + = make_scoped_restore (&gdb_stdlog, &str_file); + scoped_restore save_stdtarg + = make_scoped_restore (&gdb_stdtarg, &str_file); + scoped_restore save_stdtargerr + = make_scoped_restore (&gdb_stdtargerr, &str_file); + + execute_command (p, from_tty); + } + + return std::move (str_file.string ()); } -/* Read commands from `instream' and execute them - until end of file or error reading instream. */ - -void -command_loop (void) -{ - struct cleanup *old_chain; - char *command; - int stdin_is_tty = ISATTY (stdin); - - while (instream && !feof (instream)) - { - if (window_hook && instream == stdin) - (*window_hook) (instream, get_prompt ()); - - clear_quit_flag (); - if (instream == stdin && stdin_is_tty) - reinitialize_more_filter (); - old_chain = make_cleanup (null_cleanup, 0); - - /* Get a command-line. This calls the readline package. */ - command = command_line_input (instream == stdin ? - get_prompt () : (char *) NULL, - instream == stdin, "prompt"); - if (command == 0) - { - do_cleanups (old_chain); - return; - } - - make_command_stats_cleanup (1); - - /* Do not execute commented lines. */ - if (command[0] != '#') - { - execute_command (command, instream == stdin); - - /* Do any commands attached to breakpoint we are stopped at. */ - bpstat_do_actions (); - } - do_cleanups (old_chain); - } -} /* When nonzero, cause dont_repeat to do nothing. This should only be set via prevent_dont_repeat. */ @@ -582,89 +675,105 @@ static int suppress_dont_repeat = 0; void dont_repeat (void) { + struct ui *ui = current_ui; + if (suppress_dont_repeat || server_command) return; /* If we aren't reading from standard input, we are saving the last thing read from stdin in line and don't want to delete it. Null lines won't repeat here in any case. */ - if (instream == stdin) + if (ui->instream == ui->stdin_stream) *saved_command_line = 0; } /* Prevent dont_repeat from working, and return a cleanup that restores the previous state. */ -struct cleanup * +scoped_restore_tmpl prevent_dont_repeat (void) { - struct cleanup *result = make_cleanup_restore_integer (&suppress_dont_repeat); - - suppress_dont_repeat = 1; - return result; + return make_scoped_restore (&suppress_dont_repeat, 1); } /* Read a line from the stream "instream" without command line editing. - It prints PROMPT_ARG once at the start. + It prints PROMPT once at the start. Action is compatible with "readline", e.g. space for the result is malloc'd and should be freed by the caller. A NULL return means end of file. */ -char * -gdb_readline (const char *prompt_arg) + +static char * +gdb_readline_no_editing (const char *prompt) { - int c; - char *result; - int input_index = 0; - int result_size = 80; + struct buffer line_buffer; + struct ui *ui = current_ui; + /* Read from stdin if we are executing a user defined command. This + is the right thing for prompt_for_continue, at least. */ + FILE *stream = ui->instream != NULL ? ui->instream : stdin; + int fd = fileno (stream); - if (prompt_arg) + buffer_init (&line_buffer); + + if (prompt != NULL) { /* Don't use a _filtered function here. It causes the assumed character position to be off, since the newline we read from the user is not accounted for. */ - fputs_unfiltered (prompt_arg, gdb_stdout); + fputs_unfiltered (prompt, gdb_stdout); gdb_flush (gdb_stdout); } - result = (char *) xmalloc (result_size); - while (1) { - /* Read from stdin if we are executing a user defined command. - This is the right thing for prompt_for_continue, at least. */ - c = fgetc (instream ? instream : stdin); + int c; + int numfds; + fd_set readfds; + + QUIT; + + /* Wait until at least one byte of data is available. Control-C + can interrupt interruptible_select, but not fgetc. */ + FD_ZERO (&readfds); + FD_SET (fd, &readfds); + if (interruptible_select (fd + 1, &readfds, NULL, NULL, NULL) == -1) + { + if (errno == EINTR) + { + /* If this was ctrl-c, the QUIT above handles it. */ + continue; + } + perror_with_name (("select")); + } + + c = fgetc (stream); if (c == EOF) { - if (input_index > 0) + if (line_buffer.used_size > 0) /* The last line does not end with a newline. Return it, and if we are called again fgetc will still return EOF and we'll return NULL then. */ break; - xfree (result); + xfree (buffer_finish (&line_buffer)); return NULL; } if (c == '\n') { - if (input_index > 0 && result[input_index - 1] == '\r') - input_index--; + if (line_buffer.used_size > 0 + && line_buffer.buffer[line_buffer.used_size - 1] == '\r') + line_buffer.used_size--; break; } - result[input_index++] = c; - while (input_index >= result_size) - { - result_size *= 2; - result = (char *) xrealloc (result, result_size); - } + buffer_grow_char (&line_buffer, c); } - result[input_index++] = '\0'; - return result; + buffer_grow_char (&line_buffer, '\0'); + return buffer_finish (&line_buffer); } /* Variables which control command line editing and history @@ -755,17 +864,12 @@ static char *gdb_readline_wrapper_result; static void (*saved_after_char_processing_hook) (void); -/* The number of nested readline secondary prompts that are currently - active. */ - -static int gdb_secondary_prompt_depth = 0; - /* See top.h. */ int -gdb_in_secondary_prompt_p (void) +gdb_in_secondary_prompt_p (struct ui *ui) { - return gdb_secondary_prompt_depth > 0; + return ui->secondary_prompt_depth > 0; } @@ -791,7 +895,7 @@ gdb_readline_wrapper_line (char *line) we're handling an asynchronous target event and running in the background, just before returning to the event loop to process further input (or more target events). */ - if (async_command_editing_p) + if (current_ui->command_editing) gdb_rl_callback_handler_remove (); } @@ -807,12 +911,15 @@ struct gdb_readline_wrapper_cleanup static void gdb_readline_wrapper_cleanup (void *arg) { - struct gdb_readline_wrapper_cleanup *cleanup = arg; + struct ui *ui = current_ui; + struct gdb_readline_wrapper_cleanup *cleanup + = (struct gdb_readline_wrapper_cleanup *) arg; - rl_already_prompted = cleanup->already_prompted_orig; + if (ui->command_editing) + rl_already_prompted = cleanup->already_prompted_orig; - gdb_assert (input_handler == gdb_readline_wrapper_line); - input_handler = cleanup->handler_orig; + gdb_assert (ui->input_handler == gdb_readline_wrapper_line); + ui->input_handler = cleanup->handler_orig; /* Don't restore our input handler in readline yet. That would make readline prep the terminal (putting it in raw mode), while the @@ -823,8 +930,8 @@ gdb_readline_wrapper_cleanup (void *arg) gdb_readline_wrapper_result = NULL; gdb_readline_wrapper_done = 0; - gdb_secondary_prompt_depth--; - gdb_assert (gdb_secondary_prompt_depth >= 0); + ui->secondary_prompt_depth--; + gdb_assert (ui->secondary_prompt_depth >= 0); after_char_processing_hook = saved_after_char_processing_hook; saved_after_char_processing_hook = NULL; @@ -838,27 +945,38 @@ gdb_readline_wrapper_cleanup (void *arg) char * gdb_readline_wrapper (const char *prompt) { + struct ui *ui = current_ui; struct cleanup *back_to; struct gdb_readline_wrapper_cleanup *cleanup; char *retval; cleanup = XNEW (struct gdb_readline_wrapper_cleanup); - cleanup->handler_orig = input_handler; - input_handler = gdb_readline_wrapper_line; + cleanup->handler_orig = ui->input_handler; + ui->input_handler = gdb_readline_wrapper_line; - cleanup->already_prompted_orig = rl_already_prompted; + if (ui->command_editing) + cleanup->already_prompted_orig = rl_already_prompted; + else + cleanup->already_prompted_orig = 0; cleanup->target_is_async_orig = target_is_async_p (); - gdb_secondary_prompt_depth++; + ui->secondary_prompt_depth++; back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup); + /* Processing events may change the current UI. */ + scoped_restore save_ui = make_scoped_restore (¤t_ui); + if (cleanup->target_is_async_orig) target_async (0); - /* Display our prompt and prevent double prompt display. */ - display_gdb_prompt (prompt); - rl_already_prompted = 1; + /* Display our prompt and prevent double prompt display. Don't pass + down a NULL prompt, since that has special meaning for + display_gdb_prompt -- it indicates a request to print the primary + prompt, while we want a secondary prompt here. */ + display_gdb_prompt (prompt != NULL ? prompt : ""); + if (ui->command_editing) + rl_already_prompted = 1; if (after_char_processing_hook) (*after_char_processing_hook) (); @@ -976,19 +1094,16 @@ static void gdb_safe_append_history (void) { int ret, saved_errno; - char *local_history_filename; - struct cleanup *old_chain; - local_history_filename - = xstrprintf ("%s-gdb%d~", history_filename, getpid ()); - old_chain = make_cleanup (xfree, local_history_filename); + std::string local_history_filename + = string_printf ("%s-gdb%ld~", history_filename, (long) getpid ()); - ret = rename (history_filename, local_history_filename); + ret = rename (history_filename, local_history_filename.c_str ()); saved_errno = errno; if (ret < 0 && saved_errno != ENOENT) { warning (_("Could not rename %s to %s: %s"), - history_filename, local_history_filename, + history_filename, local_history_filename.c_str (), safe_strerror (saved_errno)); } else @@ -1004,63 +1119,60 @@ gdb_safe_append_history (void) to move it back anyway. Otherwise a global history file would never get created! */ gdb_assert (saved_errno == ENOENT); - write_history (local_history_filename); + write_history (local_history_filename.c_str ()); } else { - append_history (command_count, local_history_filename); + append_history (command_count, local_history_filename.c_str ()); if (history_is_stifled ()) - history_truncate_file (local_history_filename, history_max_entries); + history_truncate_file (local_history_filename.c_str (), + history_max_entries); } - ret = rename (local_history_filename, history_filename); + ret = rename (local_history_filename.c_str (), history_filename); saved_errno = errno; if (ret < 0 && saved_errno != EEXIST) warning (_("Could not rename %s to %s: %s"), - local_history_filename, history_filename, + local_history_filename.c_str (), history_filename, safe_strerror (saved_errno)); } - - do_cleanups (old_chain); } -/* Read one line from the command input stream `instream' - into the local static buffer `linebuffer' (whose current length - is `linelength'). - The buffer is made bigger as necessary. - Returns the address of the start of the line. +/* Read one line from the command input stream `instream' into a local + static buffer. The buffer is made bigger as necessary. Returns + the address of the start of the line. NULL is returned for end of file. - *If* the instream == stdin & stdin is a terminal, the line read - is copied into the file line saver (global var char *line, - length linesize) so that it can be duplicated. + *If* input is from an interactive stream (stdin), the line read is + copied into the global 'saved_command_line' so that it can be + repeated. - This routine either uses fancy command line editing or - simple input as the user has requested. */ + This routine either uses fancy command line editing or simple input + as the user has requested. */ char * -command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) +command_line_input (const char *prompt_arg, int repeat, + const char *annotation_suffix) { - static char *linebuffer = 0; - static unsigned linelength = 0; + static struct buffer cmd_line_buffer; + static int cmd_line_buffer_initialized; + struct ui *ui = current_ui; const char *prompt = prompt_arg; - char *p; - char *p1; - char *rl; - char *nline; - char got_eof = 0; + char *cmd; + int from_tty = ui->instream == ui->stdin_stream; /* The annotation suffix must be non-NULL. */ if (annotation_suffix == NULL) annotation_suffix = ""; - if (annotation_level > 1 && instream == stdin) + if (from_tty && annotation_level > 1) { char *local_prompt; - local_prompt = alloca ((prompt == NULL ? 0 : strlen (prompt)) - + strlen (annotation_suffix) + 40); + local_prompt + = (char *) alloca ((prompt == NULL ? 0 : strlen (prompt)) + + strlen (annotation_suffix) + 40); if (prompt == NULL) local_prompt[0] = '\0'; else @@ -1072,18 +1184,15 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) prompt = local_prompt; } - if (linebuffer == 0) + if (!cmd_line_buffer_initialized) { - linelength = 80; - linebuffer = (char *) xmalloc (linelength); + buffer_init (&cmd_line_buffer); + cmd_line_buffer_initialized = 1; } - p = linebuffer; + /* Starting a new command line. */ + cmd_line_buffer.used_size = 0; - /* Control-C quits instantly if typed while in this loop - since it should not wait until the user types a newline. */ - immediate_quit++; - QUIT; #ifdef STOP_SIGNAL if (job_control) signal (STOP_SIGNAL, handle_stop_sig); @@ -1091,6 +1200,8 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) while (1) { + char *rl; + /* Make sure that all output has been output. Some machines may let you get away with leaving out some of the gdb_flush, but not all. */ @@ -1101,7 +1212,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) if (source_file_name != NULL) ++source_line_number; - if (annotation_level > 1 && instream == stdin) + if (from_tty && annotation_level > 1) { puts_unfiltered ("\n\032\032pre-"); puts_unfiltered (annotation_suffix); @@ -1109,50 +1220,36 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) } /* Don't use fancy stuff if not talking to stdin. */ - if (deprecated_readline_hook && input_from_terminal_p ()) + if (deprecated_readline_hook + && from_tty + && input_interactive_p (current_ui)) { rl = (*deprecated_readline_hook) (prompt); } - else if (command_editing_p && input_from_terminal_p ()) + else if (command_editing_p + && from_tty + && input_interactive_p (current_ui)) { rl = gdb_readline_wrapper (prompt); } else { - rl = gdb_readline (prompt); - } - - if (annotation_level > 1 && instream == stdin) - { - puts_unfiltered ("\n\032\032post-"); - puts_unfiltered (annotation_suffix); - puts_unfiltered ("\n"); + rl = gdb_readline_no_editing (prompt); } - if (!rl || rl == (char *) EOF) + cmd = handle_line_of_input (&cmd_line_buffer, rl, + repeat, annotation_suffix); + if (cmd == (char *) EOF) { - got_eof = 1; + cmd = NULL; break; } - if (strlen (rl) + 1 + (p - linebuffer) > linelength) - { - linelength = strlen (rl) + 1 + (p - linebuffer); - nline = (char *) xrealloc (linebuffer, linelength); - p += nline - linebuffer; - linebuffer = nline; - } - p1 = rl; - /* Copy line. Don't copy null at end. (Leaves line alone - if this was just a newline). */ - while (*p1) - *p++ = *p1++; - - xfree (rl); /* Allocated in readline. */ - - if (p == linebuffer || *(p - 1) != '\\') + if (cmd != NULL) break; - p--; /* Put on top of '\'. */ + /* Got partial input. I.e., got a line that ends with a + continuation character (backslash). Suppress printing the + prompt again. */ prompt = NULL; } @@ -1160,83 +1257,8 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix) if (job_control) signal (STOP_SIGNAL, SIG_DFL); #endif - immediate_quit--; - - if (got_eof) - return NULL; - -#define SERVER_COMMAND_LENGTH 7 - server_command = - (p - linebuffer > SERVER_COMMAND_LENGTH) - && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0; - if (server_command) - { - /* Note that we don't set `line'. Between this and the check in - dont_repeat, this insures that repeating will still do the - right thing. */ - *p = '\0'; - return linebuffer + SERVER_COMMAND_LENGTH; - } - - /* Do history expansion if that is wished. */ - if (history_expansion_p && instream == stdin - && ISATTY (instream)) - { - char *history_value; - int expanded; - - *p = '\0'; /* Insert null now. */ - expanded = history_expand (linebuffer, &history_value); - if (expanded) - { - /* Print the changes. */ - printf_unfiltered ("%s\n", history_value); - - /* If there was an error, call this function again. */ - if (expanded < 0) - { - xfree (history_value); - return command_line_input (prompt, repeat, - annotation_suffix); - } - if (strlen (history_value) > linelength) - { - linelength = strlen (history_value) + 1; - linebuffer = (char *) xrealloc (linebuffer, linelength); - } - strcpy (linebuffer, history_value); - p = linebuffer + strlen (linebuffer); - } - xfree (history_value); - } - - /* If we just got an empty line, and that is supposed to repeat the - previous command, return the value in the global buffer. */ - if (repeat && p == linebuffer) - return saved_command_line; - for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++); - if (repeat && !*p1) - return saved_command_line; - - *p = 0; - - /* Add line to history if appropriate. */ - if (*linebuffer && input_from_terminal_p ()) - gdb_add_history (linebuffer); - - /* Save into global buffer if appropriate. */ - if (repeat) - { - if (linelength > saved_command_line_size) - { - saved_command_line = xrealloc (saved_command_line, linelength); - saved_command_line_size = linelength; - } - strcpy (saved_command_line, linebuffer); - return saved_command_line; - } - return linebuffer; + return cmd; } /* Print the GDB banner. */ @@ -1252,7 +1274,7 @@ print_gdb_version (struct ui_file *stream) /* Second line is a copyright notice. */ fprintf_filtered (stream, - "Copyright (C) 2015 Free Software Foundation, Inc.\n"); + "Copyright (C) 2017 Free Software Foundation, Inc.\n"); /* Following the copyright is a brief statement that the program is free software, that users are free to copy and change it on @@ -1431,7 +1453,7 @@ struct qt_args static int kill_or_detach (struct inferior *inf, void *args) { - struct qt_args *qt = args; + struct qt_args *qt = (struct qt_args *) args; struct thread_info *thread; if (inf->pid == 0) @@ -1462,7 +1484,7 @@ kill_or_detach (struct inferior *inf, void *args) static int print_inferior_quit_action (struct inferior *inf, void *arg) { - struct ui_file *stb = arg; + struct ui_file *stb = (struct ui_file *) arg; if (inf->pid == 0) return 0; @@ -1485,29 +1507,18 @@ print_inferior_quit_action (struct inferior *inf, void *arg) int quit_confirm (void) { - struct ui_file *stb; - struct cleanup *old_chain; - char *str; - int qr; - /* Don't even ask if we're only debugging a core file inferior. */ if (!have_live_inferiors ()) return 1; /* Build the query string as a single string. */ - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); + string_file stb; - fprintf_filtered (stb, _("A debugging session is active.\n\n")); - iterate_over_inferiors (print_inferior_quit_action, stb); - fprintf_filtered (stb, _("\nQuit anyway? ")); + stb.puts (_("A debugging session is active.\n\n")); + iterate_over_inferiors (print_inferior_quit_action, &stb); + stb.puts (_("\nQuit anyway? ")); - str = ui_file_xstrdup (stb, NULL); - make_cleanup (xfree, str); - - qr = query ("%s", str); - do_cleanups (old_chain); - return qr; + return query ("%s", stb.c_str ()); } /* Prepare to exit GDB cleanly by undoing any changes made to the @@ -1516,19 +1527,25 @@ quit_confirm (void) static void undo_terminal_modifications_before_exit (void) { - target_terminal_ours (); + struct ui *saved_top_level = current_ui; + + target_terminal::ours (); + + current_ui = main_ui; + #if defined(TUI) tui_disable (); #endif - if (async_command_editing_p) - gdb_disable_readline (); + gdb_disable_readline (); + + current_ui = saved_top_level; } /* Quit without asking for confirmation. */ void -quit_force (char *args, int from_tty) +quit_force (int *exit_arg, int from_tty) { int exit_code = 0; struct qt_args qt; @@ -1537,16 +1554,12 @@ quit_force (char *args, int from_tty) /* An optional expression may be used to cause gdb to terminate with the value of that expression. */ - if (args) - { - struct value *val = parse_and_eval (args); - - exit_code = (int) value_as_long (val); - } + if (exit_arg) + exit_code = *exit_arg; else if (return_child_result) exit_code = return_child_result_value; - qt.args = args; + qt.args = NULL; qt.from_tty = from_tty; /* We want to handle any quit errors and exit regardless. */ @@ -1578,9 +1591,25 @@ quit_force (char *args, int from_tty) /* Save the history information if it is appropriate to do so. */ TRY { - if (write_history_p && history_filename - && input_from_terminal_p ()) - gdb_safe_append_history (); + if (write_history_p && history_filename) + { + struct ui *ui; + int save = 0; + + /* History is currently shared between all UIs. If there's + any UI with a terminal, save history. */ + ALL_UIS (ui) + { + if (input_interactive_p (ui)) + { + save = 1; + break; + } + } + + if (save) + gdb_safe_append_history (); + } } CATCH (ex, RETURN_MASK_ALL) { @@ -1602,25 +1631,36 @@ quit_force (char *args, int from_tty) exit (exit_code); } -/* Returns whether GDB is running on a terminal and input is - currently coming from that terminal. */ +/* The value of the "interactive-mode" setting. */ +static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO; + +/* Implement the "show interactive-mode" option. */ + +static void +show_interactive_mode (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + if (interactive_mode == AUTO_BOOLEAN_AUTO) + fprintf_filtered (file, "Debugger's interactive mode " + "is %s (currently %s).\n", + value, input_interactive_p (current_ui) ? "on" : "off"); + else + fprintf_filtered (file, "Debugger's interactive mode is %s.\n", value); +} + +/* Returns whether GDB is running on an interactive terminal. */ int -input_from_terminal_p (void) +input_interactive_p (struct ui *ui) { if (batch_flag) return 0; - if (gdb_has_a_terminal () && instream == stdin) - return 1; - - /* If INSTREAM is unset, and we are not in a user command, we - must be in Insight. That's like having a terminal, for our - purposes. */ - if (instream == NULL && !in_user_command) - return 1; + if (interactive_mode != AUTO_BOOLEAN_AUTO) + return interactive_mode == AUTO_BOOLEAN_TRUE; - return 0; + return ui->input_interactive_p; } static void @@ -1833,13 +1873,24 @@ show_prompt (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Gdb's prompt is \"%s\".\n"), value); } +/* "set editing" command. */ + static void -show_async_command_editing_p (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) +set_editing (char *args, int from_tty, struct cmd_list_element *c) +{ + change_line_handler (set_editing_cmd_var); + /* Update the control variable so that MI's =cmd-param-changed event + shows the correct value. */ + set_editing_cmd_var = current_ui->command_editing; +} + +static void +show_editing (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { fprintf_filtered (file, _("Editing of command lines as " "they are typed is %s.\n"), - value); + current_ui->command_editing ? _("on") : _("off")); } static void @@ -1894,14 +1945,12 @@ set_history_filename (char *args, int from_tty, struct cmd_list_element *c) static void init_main (void) { + struct cmd_list_element *c; + /* Initialize the prompt to a simple "(gdb) " prompt or to whatever the DEFAULT_PROMPT is. */ set_prompt (DEFAULT_PROMPT); - /* Set things up for annotation_level > 1, if the user ever decides - to use it. */ - async_annotation_suffix = "prompt"; - /* Set the important stuff up for command editing. */ command_editing_p = 1; history_expansion_p = 0; @@ -1909,8 +1958,8 @@ init_main (void) /* Setup important stuff for command line editing. */ rl_completion_word_break_hook = gdb_completion_word_break_characters; - rl_completion_entry_function = readline_line_completion_function; - rl_completer_word_break_characters = default_word_break_characters (); + rl_attempted_completion_function = gdb_rl_attempted_completion_function; + set_rl_completer_word_break_characters (default_word_break_characters ()); rl_completer_quote_characters = get_gdb_completer_quote_characters (); rl_completion_display_matches_hook = cli_display_match_list; rl_readline_name = "gdb"; @@ -1934,14 +1983,14 @@ used inside of user-defined commands that should not be repeated when\n\ hitting return.")); add_setshow_boolean_cmd ("editing", class_support, - &async_command_editing_p, _("\ + &set_editing_cmd_var, _("\ Set editing of command lines as they are typed."), _("\ Show editing of command lines as they are typed."), _("\ Use \"on\" to enable the editing, and \"off\" to disable it.\n\ Without an argument, command line editing is enabled. To edit, use\n\ EMACS-like or VI-like commands like control-P or ESC."), - set_async_editing_command, - show_async_command_editing_p, + set_editing, + show_editing, &setlist, &showlist); add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\ @@ -2021,6 +2070,26 @@ When set, GDB uses the specified path to search for data files."), set_gdb_datadir, show_gdb_datadir, &setlist, &showlist); + + add_setshow_auto_boolean_cmd ("interactive-mode", class_support, + &interactive_mode, _("\ +Set whether GDB's standard input is a terminal."), _("\ +Show whether GDB's standard input is a terminal."), _("\ +If on, GDB assumes that standard input is a terminal. In practice, it\n\ +means that GDB should wait for the user to answer queries associated to\n\ +commands entered at the command prompt. If off, GDB assumes that standard\n\ +input is not a terminal, and uses the default answer to all queries.\n\ +If auto (the default), determine which mode to use based on the standard\n\ +input settings."), + NULL, + show_interactive_mode, + &setlist, &showlist); + + c = add_cmd ("new-ui", class_support, new_ui_command, _("\ +Create a new UI. It takes two arguments:\n\ +The first argument is the name of the interpreter to run.\n\ +The second argument is the terminal the UI runs on.\n"), &cmdlist); + set_cmd_completer (c, interpreter_completer); } void