X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ftop.c;h=295b6806deff22a61a7ae7df7e0f5c3192e28ca0;hb=ec13808ef07550f8a5f87fad1945739da1f10c81;hp=3e88ac6490bd13442d9712011d84265427526e29;hpb=18206ca3f9367f1488cdfc1475f8da072e7e9636;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/top.c b/gdb/top.c index 3e88ac6490..295b6806de 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. @@ -49,6 +49,9 @@ #include "observer.h" #include "maint.h" #include "filenames.h" +#include "frame.h" +#include "buffer.h" +#include "gdb_select.h" /* readline include files. */ #include "readline/readline.h" @@ -71,6 +74,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 @@ -83,6 +90,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; @@ -105,13 +128,6 @@ 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; @@ -123,17 +139,9 @@ 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 @@ -242,6 +250,175 @@ 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. */ + +struct ui * +new_ui (FILE *instream, FILE *outstream, FILE *errstream) +{ + struct ui *ui; + + ui = XCNEW (struct ui); + + ui->num = ++highest_ui_num; + ui->stdin_stream = instream; + ui->instream = instream; + ui->outstream = outstream; + ui->errstream = errstream; + + ui->input_fd = fileno (ui->instream); + + ui->input_interactive_p = ISATTY (ui->instream); + + ui->m_gdb_stdin = new stdio_file (ui->instream); + ui->m_gdb_stdout = new stdio_file (ui->outstream); + ui->m_gdb_stderr = new stderr_file (ui->errstream); + ui->m_gdb_stdlog = ui->m_gdb_stderr; + + ui->prompt_state = PROMPT_NEEDED; + + if (ui_list == NULL) + ui_list = ui; + else + { + struct ui *last; + + for (last = ui_list; last->next != NULL; last = last->next) + ; + last->next = ui; + } + + return ui; +} + +static void +free_ui (struct ui *ui) +{ + delete ui->m_gdb_stdin; + delete ui->m_gdb_stdout; + delete ui->m_gdb_stderr; + + xfree (ui); +} + +void +delete_ui (struct ui *todel) +{ + struct ui *ui, *uiprev; + + uiprev = NULL; + + for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next) + if (ui == todel) + break; + + gdb_assert (ui != NULL); + + if (uiprev != NULL) + uiprev->next = ui->next; + else + ui_list = ui->next; + + free_ui (ui); +} + +/* Cleanup that deletes a UI. */ + +static void +delete_ui_cleanup (void *void_ui) +{ + struct ui *ui = (struct ui *) void_ui; + + delete_ui (ui); +} + +/* See top.h. */ + +struct cleanup * +make_delete_ui_cleanup (struct ui *ui) +{ + return make_cleanup (delete_ui_cleanup, ui); +} + +/* Open file named NAME for read/write, making sure not to make it the + controlling terminal. */ + +static FILE * +open_terminal_stream (const char *name) +{ + int fd; + + fd = open (name, O_RDWR | O_NOCTTY); + if (fd < 0) + perror_with_name (_("opening terminal failed")); + + return fdopen (fd, "w+"); +} + +/* Implementation of the "new-ui" command. */ + +static void +new_ui_command (char *args, int from_tty) +{ + struct ui *ui; + struct interp *interp; + FILE *stream[3] = { NULL, NULL, NULL }; + int i; + int res; + int argc; + char **argv; + const char *interpreter_name; + const char *tty_name; + struct cleanup *success_chain; + struct cleanup *failure_chain; + + dont_repeat (); + + argv = gdb_buildargv (args); + success_chain = make_cleanup_freeargv (argv); + argc = countargv (argv); + + if (argc < 2) + error (_("usage: new-ui ")); + + interpreter_name = argv[0]; + tty_name = argv[1]; + + { + scoped_restore save_ui = make_scoped_restore (¤t_ui); + + failure_chain = make_cleanup (null_cleanup, NULL); + + /* Open specified terminal, once for each of + stdin/stdout/stderr. */ + for (i = 0; i < 3; i++) + { + stream[i] = open_terminal_stream (tty_name); + make_cleanup_fclose (stream[i]); + } + + ui = new_ui (stream[0], stream[1], stream[2]); + make_cleanup (delete_ui_cleanup, ui); + + ui->async = 1; + + current_ui = ui; + + set_top_level_interpreter (interpreter_name); + + interp_pre_command_loop (top_level_interpreter ()); + + discard_cleanups (failure_chain); + + /* This restores the previous UI and frees argv. */ + do_cleanups (success_chain); + } + + printf_unfiltered ("New UI allocated\n"); +} + /* Handler for SIGHUP. */ #ifdef SIGHUP @@ -276,19 +453,36 @@ quit_cover (void) void do_restore_instream_cleanup (void *stream) { + struct ui *ui = current_ui; + /* Restore the previous input stream. */ - instream = stream; + ui->instream = (FILE *) stream; } /* Read commands from STREAM. */ void read_command_file (FILE *stream) { + struct ui *ui = current_ui; struct cleanup *cleanups; - cleanups = make_cleanup (do_restore_instream_cleanup, instream); - instream = stream; - command_loop (); + cleanups = make_cleanup (do_restore_instream_cleanup, ui->instream); + ui->instream = stream; + + /* 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); + } + do_cleanups (cleanups); } @@ -298,7 +492,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 @@ -329,10 +523,11 @@ void check_frame_language_change (void) { static int warned = 0; + struct frame_info *frame; /* First make sure that a new frame has been selected, in case the command or the hooks changed the program state. */ - deprecated_safe_get_selected_frame (); + frame = deprecated_safe_get_selected_frame (); if (current_language != expected_language) { if (language_mode == language_mode_auto && info_verbose) @@ -352,7 +547,7 @@ check_frame_language_change (void) { enum language flang; - flang = get_frame_language (); + flang = get_frame_language (frame); if (!warned && flang != language_unknown && flang != current_language->la_language) @@ -365,6 +560,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) { @@ -372,12 +581,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. @@ -413,7 +620,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; @@ -483,92 +690,40 @@ 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 (); + scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0); - 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); + string_file str_file; - 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); + current_uiout->redirect (&str_file); + 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; + 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); - retval = ui_file_xstrdup (str_file, NULL); - do_cleanups (cleanup); - return retval; + 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. */ @@ -580,89 +735,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 @@ -752,6 +923,16 @@ static char *gdb_readline_wrapper_result; return. */ static void (*saved_after_char_processing_hook) (void); + +/* See top.h. */ + +int +gdb_in_secondary_prompt_p (struct ui *ui) +{ + return ui->secondary_prompt_depth > 0; +} + + /* This function is called when readline has seen a complete line of text. */ @@ -774,7 +955,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 (); } @@ -790,12 +971,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 @@ -806,6 +990,8 @@ gdb_readline_wrapper_cleanup (void *arg) gdb_readline_wrapper_result = NULL; gdb_readline_wrapper_done = 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; @@ -819,26 +1005,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 = xmalloc (sizeof (*cleanup)); - cleanup->handler_orig = input_handler; - input_handler = gdb_readline_wrapper_line; + cleanup = XNEW (struct gdb_readline_wrapper_cleanup); + 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 (); + 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) (); @@ -960,7 +1158,7 @@ gdb_safe_append_history (void) struct cleanup *old_chain; local_history_filename - = xstrprintf ("%s-gdb%d~", history_filename, getpid ()); + = xstrprintf ("%s-gdb%ld~", history_filename, (long) getpid ()); old_chain = make_cleanup (xfree, local_history_filename); ret = rename (history_filename, local_history_filename); @@ -1004,43 +1202,40 @@ gdb_safe_append_history (void) 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) { - 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 @@ -1052,18 +1247,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); @@ -1071,6 +1263,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. */ @@ -1081,7 +1275,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); @@ -1089,50 +1283,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; } @@ -1140,83 +1320,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. */ @@ -1232,7 +1337,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 @@ -1411,7 +1516,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) @@ -1442,7 +1547,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; @@ -1465,29 +1570,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 @@ -1496,19 +1590,25 @@ quit_confirm (void) static void undo_terminal_modifications_before_exit (void) { + 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; @@ -1517,16 +1617,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. */ @@ -1558,9 +1654,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) { @@ -1582,25 +1694,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 @@ -1813,13 +1936,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 +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_async_command_editing_p (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) +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 @@ -1874,14 +2008,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; @@ -1914,14 +2046,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, _("\ @@ -2001,6 +2133,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