aboutsummaryrefslogtreecommitdiff
path: root/gdb/event-top.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-03-09 18:25:00 +0000
committerPedro Alves <palves@redhat.com>2016-03-09 18:25:00 +0000
commitb69d38afdea34e4fecab5ea47ffe1e594e0b6233 (patch)
tree301f91f19eb5968ab8b281eb1510be71f40200c8 /gdb/event-top.c
parent2669cade3dcebf5d572bcd535cf21934cbc1633c (diff)
downloadgdb-b69d38afdea34e4fecab5ea47ffe1e594e0b6233.zip
gdb-b69d38afdea34e4fecab5ea47ffe1e594e0b6233.tar.gz
gdb-b69d38afdea34e4fecab5ea47ffe1e594e0b6233.tar.bz2
Command line input handling TLC
I didn't manage to usefully split this further into smaller independent pieces, so: - Use "struct buffer" more. - Split out the responsibility of composing a complete command line from multiple input lines split with backslash ( E.g.: (gdb) print \ 1 + \ 2 $1 = 3 (gdb) ) to a separate function. Note we don't need the separate readline_input_state and more_to_come globals at all. They were just obfuscating the logic. - Factor out the tricky mostly duplicated code in command_line_handler and command_line_input. gdb/ChangeLog 2016-03-09 Pedro Alves <palves@redhat.com> * event-top.c (more_to_come): Delete. (struct readline_input_state): Delete. (readline_input_state): Delete. (get_command_line_buffer): New function. (command_handler): Update comments. Don't handle NULL commands here. Do not execute commented lines. (command_line_append_input_line): New function. (handle_line_of_input): New function, partly based on command_line_handler and command_line_input. (command_line_handler): Rewrite. * event-top.h (command_handler): New declaration. (command_loop): Defer command execution to command_handler. (command_line_input): Update comments. Simplify, using struct buffer and handle_line_of_input. * top.h (struct buffer): New forward declaration. (handle_line_of_input): New declaration.
Diffstat (limited to 'gdb/event-top.c')
-rw-r--r--gdb/event-top.c340
1 files changed, 164 insertions, 176 deletions
diff --git a/gdb/event-top.c b/gdb/event-top.c
index f112c52..eb4f0b9 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -49,7 +49,6 @@
static void rl_callback_read_char_wrapper (gdb_client_data client_data);
static void command_line_handler (char *rl);
static void change_line_handler (void);
-static void command_handler (char *command);
static char *top_level_prompt (void);
/* Signal handlers. */
@@ -140,20 +139,6 @@ static struct async_signal_handler *sigtstp_token;
#endif
static struct async_signal_handler *async_sigterm_token;
-/* Structure to save a partially entered command. This is used when
- the user types '\' at the end of a command line. This is necessary
- because each line of input is handled by a different call to
- command_line_handler, and normally there is no state retained
- between different calls. */
-static int more_to_come = 0;
-
-struct readline_input_state
- {
- char *linebuffer;
- char *linebuffer_ptr;
- }
-readline_input_state;
-
/* This hook is called by rl_callback_read_char_wrapper after each
character is processed. */
void (*after_char_processing_hook) (void);
@@ -383,6 +368,24 @@ top_level_prompt (void)
return xstrdup (prompt);
}
+/* Get a pointer to the command line buffer. This is used to
+ construct a whole line of input from partial input. */
+
+static struct buffer *
+get_command_line_buffer (void)
+{
+ static struct buffer line_buffer;
+ static int line_buffer_initialized;
+
+ if (!line_buffer_initialized)
+ {
+ buffer_init (&line_buffer);
+ line_buffer_initialized = 1;
+ }
+
+ return &line_buffer;
+}
+
/* 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
@@ -436,152 +439,122 @@ async_disable_stdin (void)
}
-/* Handles a gdb command. This function is called by
- command_line_handler, which has processed one or more input lines
- into COMMAND. */
-/* NOTE: 1999-04-30 This is the asynchronous version of the command_loop
- function. The command_loop function will be obsolete when we
- switch to use the event loop at every execution of gdb. */
-static void
+/* Handle a gdb command line. This function is called when
+ handle_line_of_input has concatenated one or more input lines into
+ a whole command. */
+
+void
command_handler (char *command)
{
struct cleanup *stat_chain;
+ char *c;
clear_quit_flag ();
if (instream == stdin)
reinitialize_more_filter ();
- /* If readline returned a NULL command, it means that the connection
- with the terminal is gone. This happens at the end of a
- testsuite run, after Expect has hung up but GDB is still alive.
- In such a case, we just quit gdb killing the inferior program
- too. */
- if (command == 0)
- {
- printf_unfiltered ("quit\n");
- execute_command ("quit", stdin == instream);
- }
-
stat_chain = make_command_stats_cleanup (1);
- execute_command (command, instream == stdin);
+ /* Do not execute commented lines. */
+ for (c = command; *c == ' ' || *c == '\t'; c++)
+ ;
+ if (c[0] != '#')
+ {
+ execute_command (command, instream == stdin);
- /* Do any commands attached to breakpoint we stopped at. */
- bpstat_do_actions ();
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions ();
+ }
do_cleanups (stat_chain);
}
-/* Handle a complete line of input. This is called by the callback
- mechanism within the readline library. Deal with incomplete
- commands as well, by saving the partial input in a global
- buffer. */
+/* Append RL, an input line returned by readline or one of its
+ emulations, to CMD_LINE_BUFFER. Returns the command line if we
+ have a whole command line ready to be processed by the command
+ interpreter or NULL if the command line isn't complete yet (input
+ line ends in a backslash). Takes ownership of RL. */
-/* NOTE: 1999-04-30 This is the asynchronous version of the
- command_line_input function; command_line_input will become
- obsolete once we use the event loop as the default mechanism in
- GDB. */
-static void
-command_line_handler (char *rl)
+static char *
+command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl)
{
- static char *linebuffer = 0;
- static unsigned linelength = 0;
- char *p;
- char *p1;
- char *nline;
- int repeat = (instream == stdin);
+ char *cmd;
+ size_t len;
- if (annotation_level > 1 && instream == stdin)
- printf_unfiltered (("\n\032\032post-prompt\n"));
+ len = strlen (rl);
- if (linebuffer == 0)
+ if (len > 0 && rl[len - 1] == '\\')
{
- linelength = 80;
- linebuffer = (char *) xmalloc (linelength);
- linebuffer[0] = '\0';
+ /* Don't copy the backslash and wait for more. */
+ buffer_grow (cmd_line_buffer, rl, len - 1);
+ cmd = NULL;
}
-
- p = linebuffer;
-
- if (more_to_come)
+ else
{
- strcpy (linebuffer, readline_input_state.linebuffer);
- p = readline_input_state.linebuffer_ptr;
- xfree (readline_input_state.linebuffer);
- more_to_come = 0;
+ /* Copy whole line including terminating null, and we're
+ done. */
+ buffer_grow (cmd_line_buffer, rl, len + 1);
+ cmd = cmd_line_buffer->buffer;
}
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, handle_stop_sig);
-#endif
+ /* Allocated in readline. */
+ xfree (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. */
- wrap_here ("");
- gdb_flush (gdb_stdout);
- gdb_flush (gdb_stderr);
+ return cmd;
+}
- if (source_file_name != NULL)
- ++source_line_number;
+/* Handle a line of input coming from readline.
- /* If we are in this case, then command_handler will call quit
- and exit from gdb. */
- if (!rl || rl == (char *) EOF)
- {
- command_handler (0);
- return; /* Lint. */
- }
- 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++;
+ If the read line ends with a continuation character (backslash),
+ save the partial input in CMD_LINE_BUFFER (except the backslash),
+ and return NULL. Otherwise, save the partial input and return a
+ pointer to CMD_LINE_BUFFER's buffer (null terminated), indicating a
+ whole command line is ready to be executed.
- xfree (rl); /* Allocated in readline. */
+ Returns EOF on end of file.
- if (p > linebuffer && *(p - 1) == '\\')
- {
- *p = '\0';
- p--; /* Put on top of '\'. */
+ If REPEAT, handle command repetitions:
- readline_input_state.linebuffer = xstrdup (linebuffer);
- readline_input_state.linebuffer_ptr = p;
+ - If the input command line is NOT empty, the command returned is
+ copied into the global 'saved_command_line' var so that it can
+ be repeated later.
- /* We will not invoke a execute_command if there is more
- input expected to complete the command. So, we need to
- print an empty prompt here. */
- more_to_come = 1;
- display_gdb_prompt ("");
- return;
- }
+ - OTOH, if the input command line IS empty, return the previously
+ saved command instead of the empty input line.
+*/
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, SIG_DFL);
-#endif
+char *
+handle_line_of_input (struct buffer *cmd_line_buffer,
+ char *rl, int repeat, char *annotation_suffix)
+{
+ char *p1;
+ char *cmd;
+
+ if (rl == NULL)
+ return (char *) EOF;
+
+ cmd = command_line_append_input_line (cmd_line_buffer, rl);
+ if (cmd == NULL)
+ return NULL;
+
+ /* We have a complete command line now. Prepare for the next
+ command, but leave ownership of memory to the buffer . */
+ cmd_line_buffer->used_size = 0;
+
+ if (annotation_level > 1 && instream == stdin)
+ {
+ printf_unfiltered (("\n\032\032post-"));
+ puts_unfiltered (annotation_suffix);
+ printf_unfiltered (("\n"));
+ }
-#define SERVER_COMMAND_LENGTH 7
- server_command =
- (p - linebuffer > SERVER_COMMAND_LENGTH)
- && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
- if (server_command)
+#define SERVER_COMMAND_PREFIX "server "
+ if (startswith (cmd, SERVER_COMMAND_PREFIX))
{
- /* 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';
- command_handler (linebuffer + SERVER_COMMAND_LENGTH);
- display_gdb_prompt (0);
- return;
+ /* Note that we don't set `saved_command_line'. Between this
+ and the check in dont_repeat, this insures that repeating
+ will still do the right thing. */
+ return cmd + strlen (SERVER_COMMAND_PREFIX);
}
/* Do history expansion if that is wished. */
@@ -591,10 +564,11 @@ command_line_handler (char *rl)
char *history_value;
int expanded;
- *p = '\0'; /* Insert null now. */
- expanded = history_expand (linebuffer, &history_value);
+ expanded = history_expand (cmd, &history_value);
if (expanded)
{
+ size_t len;
+
/* Print the changes. */
printf_unfiltered ("%s\n", history_value);
@@ -602,67 +576,81 @@ command_line_handler (char *rl)
if (expanded < 0)
{
xfree (history_value);
- return;
+ return cmd;
}
- if (strlen (history_value) > linelength)
- {
- linelength = strlen (history_value) + 1;
- linebuffer = (char *) xrealloc (linebuffer, linelength);
- }
- strcpy (linebuffer, history_value);
- p = linebuffer + strlen (linebuffer);
+
+ /* history_expand returns an allocated string. Just replace
+ our buffer with it. */
+ len = strlen (history_value);
+ xfree (buffer_finish (cmd_line_buffer));
+ cmd_line_buffer->buffer = history_value;
+ cmd_line_buffer->buffer_size = len + 1;
+ cmd = history_value;
}
- 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 && *p != '\\')
- {
- command_handler (saved_command_line);
- display_gdb_prompt (0);
- return;
- }
+ previous command, return the previously saved command. */
+ for (p1 = cmd; *p1 == ' ' || *p1 == '\t'; p1++)
+ ;
+ if (repeat && *p1 == '\0')
+ return saved_command_line;
+
+ /* Add command to history if appropriate. Note: lines consisting
+ solely of comments are also added to the command history. This
+ is useful when you type a command, and then realize you don't
+ want to execute it quite yet. You can comment out the command
+ and then later fetch it from the value history and remove the
+ '#'. The kill ring is probably better, but some people are in
+ the habit of commenting things out. */
+ if (*cmd != '\0' && input_from_terminal_p ())
+ gdb_add_history (cmd);
- for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
- if (repeat && !*p1)
+ /* Save into global buffer if appropriate. */
+ if (repeat)
{
- command_handler (saved_command_line);
- display_gdb_prompt (0);
- return;
+ xfree (saved_command_line);
+ saved_command_line = xstrdup (cmd);
+ return saved_command_line;
}
+ else
+ return cmd;
+}
- *p = 0;
+/* Handle a complete line of input. This is called by the callback
+ mechanism within the readline library. Deal with incomplete
+ commands as well, by saving the partial input in a global
+ buffer.
- /* Add line to history if appropriate. */
- if (*linebuffer && input_from_terminal_p ())
- gdb_add_history (linebuffer);
+ NOTE: This is the asynchronous version of the command_line_input
+ function. */
- /* Note: lines consisting solely of comments are added to the command
- history. This is useful when you type a command, and then
- realize you don't want to execute it quite yet. You can comment
- out the command and then later fetch it from the value history
- and remove the '#'. The kill ring is probably better, but some
- people are in the habit of commenting things out. */
- if (*p1 == '#')
- *p1 = '\0'; /* Found a comment. */
+void
+command_line_handler (char *rl)
+{
+ struct buffer *line_buffer = get_command_line_buffer ();
+ char *cmd;
- /* Save into global buffer if appropriate. */
- if (repeat)
+ cmd = handle_line_of_input (line_buffer, rl, instream == stdin, "prompt");
+ if (cmd == (char *) EOF)
{
- xfree (saved_command_line);
- saved_command_line = xstrdup (linebuffer);
- if (!more_to_come)
- {
- command_handler (saved_command_line);
- display_gdb_prompt (0);
- }
- return;
+ /* stdin closed. The connection with the terminal is gone.
+ This happens at the end of a testsuite run, after Expect has
+ hung up but GDB is still alive. In such a case, we just quit
+ gdb killing the inferior program too. */
+ printf_unfiltered ("quit\n");
+ execute_command ("quit", stdin == instream);
+ }
+ else if (cmd == NULL)
+ {
+ /* We don't have a full line yet. Print an empty prompt. */
+ display_gdb_prompt ("");
+ }
+ else
+ {
+ command_handler (cmd);
+ display_gdb_prompt (0);
}
-
- command_handler (linebuffer);
- display_gdb_prompt (0);
- return;
}
/* Does reading of input from terminal w/o the editing features