This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 02/23] Command line input handling TLC
- From: Pedro Alves <palves at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 3 Feb 2016 16:43:37 +0000
- Subject: [PATCH 02/23] Command line input handling TLC
- Authentication-results: sourceware.org; auth=none
- References: <1454517838-7784-1-git-send-email-palves at redhat dot com>
The main motivation here was factor out all the globals used by the
line input handling code to a structure, so that we can keep multiple
instances of that. But I found that this code is a lot messier than
it needs to be, hence this patch cleans things up significantly in the
process as well.
---
gdb/common/buffer.h | 8 +
gdb/defs.h | 2 -
gdb/event-top.c | 457 ++++++++++++++++++++++------------------------------
gdb/event-top.h | 5 +-
gdb/inflow.c | 2 +-
gdb/inflow.h | 4 +
gdb/main.c | 3 +-
gdb/mi/mi-interp.c | 2 +-
gdb/top.c | 239 ++++++---------------------
gdb/top.h | 7 +-
10 files changed, 267 insertions(+), 462 deletions(-)
diff --git a/gdb/common/buffer.h b/gdb/common/buffer.h
index 2a47db4..bad2c3a 100644
--- a/gdb/common/buffer.h
+++ b/gdb/common/buffer.h
@@ -31,6 +31,14 @@ struct buffer
accommodate the new data. */
void buffer_grow (struct buffer *buffer, const char *data, size_t size);
+/* Append CH to the end of BUFFER. Grows the buffer to accommodate
+ the new data. */
+static inline void
+buffer_grow_char (struct buffer *buffer, char c)
+{
+ buffer_grow (buffer, &c, 1);
+}
+
/* Release any memory held by BUFFER. */
void buffer_free (struct buffer *buffer);
diff --git a/gdb/defs.h b/gdb/defs.h
index f6ffeac..b94df30 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -285,8 +285,6 @@ extern void print_transfer_performance (struct ui_file *stream,
typedef void initialize_file_ftype (void);
-extern char *gdb_readline (const char *);
-
extern char *gdb_readline_wrapper (const char *);
extern char *command_line_input (const char *, int, char *);
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 2309cce..969124e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -37,6 +37,9 @@
#include "gdbcmd.h" /* for dont_repeat() */
#include "annotate.h"
#include "maint.h"
+#include "inflow.h"
+#include "serial.h"
+#include "buffer.h"
/* readline include files. */
#include "readline/readline.h"
@@ -48,7 +51,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. */
@@ -107,10 +109,6 @@ void (*call_readline) (gdb_client_data);
loop as default engine, and event-top.c is merged into top.c. */
int async_command_editing_p;
-/* This is the annotation suffix that will be used when the
- annotation_level is 2. */
-char *async_annotation_suffix;
-
/* This is used to display the notification of the completion of an
asynchronous execution command. */
int exec_done_display_p = 0;
@@ -143,20 +141,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);
@@ -211,7 +195,7 @@ change_line_handler (void)
{
/* Turn off editing by using gdb_readline2. */
gdb_rl_callback_handler_remove ();
- call_readline = gdb_readline2;
+ call_readline = gdb_readline_callback_no_editing;
/* Set up the command handler as well, in case we are called as
first thing from .gdbinit. */
@@ -363,55 +347,45 @@ display_gdb_prompt (const char *new_prompt)
static char *
top_level_prompt (void)
{
- char *prefix;
- char *prompt = NULL;
- char *suffix;
- char *composed_prompt;
- size_t prompt_length;
+ char *prompt;
/* Give observers a chance of changing the prompt. E.g., the python
`gdb.prompt_hook' is installed as an observer. */
observer_notify_before_prompt (get_prompt ());
- prompt = xstrdup (get_prompt ());
+ prompt = get_prompt ();
if (annotation_level >= 2)
{
/* Prefix needs to have new line at end. */
- prefix = (char *) alloca (strlen (async_annotation_suffix) + 10);
- strcpy (prefix, "\n\032\032pre-");
- strcat (prefix, async_annotation_suffix);
- strcat (prefix, "\n");
+ const char prefix[] = "\n\032\032pre-prompt\n";
/* Suffix needs to have a new line at end and \032 \032 at
beginning. */
- suffix = (char *) alloca (strlen (async_annotation_suffix) + 6);
- strcpy (suffix, "\n\032\032");
- strcat (suffix, async_annotation_suffix);
- strcat (suffix, "\n");
- }
- else
- {
- prefix = "";
- suffix = "";
+ const char suffix[] = "\n\032\032prompt\n";
+
+ return concat (prefix, prompt, suffix, NULL);
}
- prompt_length = strlen (prefix) + strlen (prompt) + strlen (suffix);
- composed_prompt = (char *) xmalloc (prompt_length + 1);
+ return xstrdup (prompt);
+}
- strcpy (composed_prompt, prefix);
- strcat (composed_prompt, prompt);
- strcat (composed_prompt, suffix);
+/* Get a pointer to the command line builder. This is to used to
+ construct a whole line of input from partial input. */
- xfree (prompt);
+static struct buffer *
+get_line_builder (void)
+{
+ static struct buffer line_builder;
- return composed_prompt;
+ return &line_builder;
}
-/* When there is an event ready on the stdin file desriptor, instead
+/* 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_readline2, give gdb a chance to detect
errors and do something. */
+
void
stdin_event_handler (int error, gdb_client_data client_data)
{
@@ -460,156 +434,120 @@ 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 to the buffer maintained by CMD_BUILDER. Returns false if
+ more input is expected (line ends in a backslash), true if we have
+ a whole command line. 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 *
+cmd_builder_append (struct buffer *cmd_builder, 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)
+ len = strlen (rl);
+
+ if (len > 0 && rl[len - 1] == '\\')
{
- printf_unfiltered (("\n\032\032post-"));
- puts_unfiltered (async_annotation_suffix);
- printf_unfiltered (("\n"));
+ /* Don't copy the backslash and wait for more. */
+ buffer_grow (cmd_builder, rl, len - 1);
+ cmd = NULL;
}
-
- if (linebuffer == 0)
+ else
{
- linelength = 80;
- linebuffer = (char *) xmalloc (linelength);
- linebuffer[0] = '\0';
+ /* Copy whole line including terminating null, and we're
+ done. */
+ buffer_grow (cmd_builder, rl, len + 1);
+ cmd = cmd_builder->buffer;
}
- p = linebuffer;
+ /* Allocated in readline. */
+ xfree (rl);
- if (more_to_come)
- {
- strcpy (linebuffer, readline_input_state.linebuffer);
- p = readline_input_state.linebuffer_ptr;
- xfree (readline_input_state.linebuffer);
- more_to_come = 0;
- }
+ return cmd;
+}
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, handle_stop_sig);
-#endif
+/* Handle a line of input coming from readline.
- /* 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);
+ If the read line ends with a continuation character (backslash),
+ save the partial input in CMD_BUILDER (except the backslash), and
+ return NULL. Otherwise, save the partial input and return a
+ pointer to CMD_BUILDER's buffer (null terminated), indicating a
+ whole command line is ready to be executed.
- if (source_file_name != NULL)
- ++source_line_number;
+ Returns EOF on end of file.
- /* 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 REPEAT, handle command repetitions:
- xfree (rl); /* Allocated in readline. */
+ - 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.
- if (p > linebuffer && *(p - 1) == '\\')
- {
- *p = '\0';
- p--; /* Put on top of '\'. */
+ - OTOH, if the input command line IS empty, return the previously
+ saved command instead of the empty input line.
+*/
- readline_input_state.linebuffer = xstrdup (linebuffer);
- readline_input_state.linebuffer_ptr = p;
+char *
+handle_line_of_input (struct buffer *cmd_builder,
+ char *rl, int repeat, char *annotation_suffix)
+{
+ char *p1;
+ char *cmd;
- /* 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;
- }
+ if (rl == NULL)
+ return (char *) EOF;
-#ifdef STOP_SIGNAL
- if (job_control)
- signal (STOP_SIGNAL, SIG_DFL);
-#endif
+ cmd = cmd_builder_append (cmd_builder, 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_builder->used_size = 0;
-#define SERVER_COMMAND_LENGTH 7
- server_command =
- (p - linebuffer > SERVER_COMMAND_LENGTH)
- && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
- if (server_command)
+ if (annotation_level > 1 && instream == stdin)
{
- /* 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;
+ printf_unfiltered (("\n\032\032post-"));
+ puts_unfiltered (annotation_suffix);
+ printf_unfiltered (("\n"));
+ }
+
+#define SERVER_COMMAND_PREFIX "server "
+ if (startswith (cmd, SERVER_COMMAND_PREFIX))
+ {
+ /* 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. */
@@ -619,10 +557,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);
@@ -630,102 +569,93 @@ 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_builder));
+ cmd_builder->buffer = history_value;
+ cmd_builder->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 && 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 *cmd_builder = get_line_builder ();
+ char *cmd;
- /* Save into global buffer if appropriate. */
- if (repeat)
+ cmd = handle_line_of_input (cmd_builder, rl, instream == stdin, "prompt");
+ if (cmd == (char *) EOF)
{
- if (linelength > saved_command_line_size)
- {
- saved_command_line
- = (char *) xrealloc (saved_command_line, linelength);
- saved_command_line_size = linelength;
- }
- strcpy (saved_command_line, 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
- provided by the readline library. */
+ provided by the readline library. Calls the line input handler
+ once we have a whole input line. */
-/* NOTE: 1999-04-30 Asynchronous version of gdb_readline; gdb_readline
- will become obsolete when the event loop is made the default
- execution for gdb. */
void
-gdb_readline2 (gdb_client_data client_data)
+gdb_readline_callback_no_editing (gdb_client_data client_data)
{
+ struct buffer *builder = get_line_builder ();
int c;
- char *result;
- int input_index = 0;
- int result_size = 80;
- static int done_once = 0;
-
- /* Unbuffer the input stream, so that, later on, the calls to fgetc
- fetch only one char at the time from the stream. The fgetc's will
- get up to the first newline, but there may be more chars in the
- stream after '\n'. If we buffer the input and fgetc drains the
- stream, getting stuff beyond the newline as well, a select, done
- afterwards will not trigger. */
- if (!done_once && !ISATTY (instream))
- {
- setbuf (instream, NULL);
- done_once = 1;
- }
-
- result = (char *) xmalloc (result_size);
+ char *r;
/* We still need the while loop here, even though it would seem
obvious to invoke gdb_readline2 at every character entered. If
@@ -736,39 +666,44 @@ gdb_readline2 (gdb_client_data client_data)
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);
+ /* A non-blocking read. */
+ c = serial_readchar (stdin_serial, 0);
- if (c == EOF)
+ if (c == SERIAL_ERROR)
{
- if (input_index > 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);
- (*input_handler) (0);
+ /* No chars left. Go back to event loop. */
return;
}
- if (c == '\n')
+ if (c == SERIAL_EOF)
{
- if (input_index > 0 && result[input_index - 1] == '\r')
- input_index--;
- break;
+ if (builder->used_size > 0)
+ {
+ /* The last line does not end with a newline. Return
+ it, and if we are called again serial_readchar will
+ still return EOF and we'll signal error then. */
+ break;
+ }
+ xfree (buffer_finish (builder));
+ (*input_handler) (NULL);
+ return;
}
- result[input_index++] = c;
- while (input_index >= result_size)
+ if (c == '\n')
{
- result_size *= 2;
- result = (char *) xrealloc (result, result_size);
+ if (builder->used_size > 0
+ && builder->buffer[builder->used_size - 1] == '\r')
+ builder->used_size--;
+ break;
}
+
+ buffer_grow_char (builder, c);
}
- result[input_index++] = '\0';
- (*input_handler) (result);
+ buffer_grow_char (builder, '\0');
+
+ r = buffer_finish (builder);
+ (*input_handler) (r);
}
@@ -1055,7 +990,7 @@ gdb_setup_readline (void)
else
{
async_command_editing_p = 0;
- call_readline = gdb_readline2;
+ call_readline = gdb_readline_callback_no_editing;
}
/* When readline has read an end-of-line character, it passes the
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 4f20770..44e2041 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -34,6 +34,8 @@ extern void async_init_signals (void);
extern void set_async_editing_command (char *args, int from_tty,
struct cmd_list_element *c);
+extern void command_handler (char *command);
+
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
#ifndef STOP_SIGNAL
#include <signal.h>
@@ -44,7 +46,6 @@ extern void handle_stop_sig (int sig);
#endif
extern void handle_sigint (int sig);
extern void handle_sigterm (int sig);
-extern void gdb_readline2 (void *client_data);
extern void async_request_quit (void *arg);
extern void stdin_event_handler (int error, void *client_data);
extern void async_disable_stdin (void);
@@ -55,13 +56,13 @@ extern void async_enable_stdin (void);
extern int async_command_editing_p;
extern int exec_done_display_p;
-extern char *async_annotation_suffix;
extern struct prompts the_prompts;
extern void (*call_readline) (void *);
extern void (*input_handler) (char *);
extern int input_fd;
extern void (*after_char_processing_hook) (void);
extern int call_stdin_event_handler_again_p;
+extern void gdb_readline_callback_no_editing (void *client_data);
/* Wrappers for rl_callback_handler_remove and
rl_callback_handler_install that keep track of whether the callback
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 4c80dbd..4ccd806 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -48,7 +48,7 @@ static void child_terminal_ours_1 (int);
/* Record terminal status separately for debugger and inferior. */
-static struct serial *stdin_serial;
+struct serial *stdin_serial;
/* Terminal related info we need to keep track of. Each inferior
holds an instance of this structure --- we save it whenever the
diff --git a/gdb/inflow.h b/gdb/inflow.h
index 0d0242e..1c2278e 100644
--- a/gdb/inflow.h
+++ b/gdb/inflow.h
@@ -33,4 +33,8 @@
extern PROCESS_GROUP_TYPE inferior_process_group (void);
#endif
+/* The serial object that wraps stdin. */
+
+extern struct serial *stdin_serial;
+
#endif /* inflow.h */
diff --git a/gdb/main.c b/gdb/main.c
index a338b90..93ed98f 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -506,8 +506,7 @@ captured_main (void *data)
ndir = 0;
clear_quit_flag ();
- saved_command_line = (char *) xmalloc (saved_command_line_size);
- saved_command_line[0] = '\0';
+ saved_command_line = (char *) xstrdup ("");
instream = stdin;
#ifdef __MINGW32__
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 7f42367..80c8259 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -181,7 +181,7 @@ mi_interpreter_resume (void *data)
/* These overwrite some of the initialization done in
_intialize_event_loop. */
- call_readline = gdb_readline2;
+ call_readline = gdb_readline_callback_no_editing;
input_handler = mi_execute_command_input_handler;
async_command_editing_p = 0;
/* FIXME: This is a total hack for now. PB's use of the MI
diff --git a/gdb/top.c b/gdb/top.c
index ed200ba..8e5489e 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -67,6 +67,7 @@
#include "cli-out.h"
#include "tracepoint.h"
#include "inf-loop.h"
+#include "buffer.h"
#if defined(TUI)
# include "tui/tui.h"
@@ -124,17 +125,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
@@ -540,40 +533,17 @@ execute_command_to_string (char *p, int from_tty)
void
command_loop (void)
{
- struct cleanup *old_chain;
- char *command;
-
while (instream && !feof (instream))
{
- if (window_hook && instream == stdin)
- (*window_hook) (instream, get_prompt ());
-
- clear_quit_flag ();
- if (instream == stdin)
- reinitialize_more_filter ();
- old_chain = make_cleanup (null_cleanup, 0);
+ char *command;
/* 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);
+ if (command == NULL)
+ return;
+ command_handler (command);
}
}
@@ -612,64 +582,60 @@ prevent_dont_repeat (void)
/* 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_builder;
+
+ buffer_init (&line_builder);
- if (prompt_arg)
+ 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)
{
+ int c;
+
/* 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);
if (c == EOF)
{
- if (input_index > 0)
+ if (line_builder.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_builder));
return NULL;
}
if (c == '\n')
{
- if (input_index > 0 && result[input_index - 1] == '\r')
- input_index--;
+ if (line_builder.used_size > 0
+ && line_builder.buffer[line_builder.used_size - 1] == '\r')
+ line_builder.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_builder, c);
}
- result[input_index++] = '\0';
- return result;
+ buffer_grow_char (&line_builder, '\0');
+ return buffer_finish (&line_builder);
}
/* Variables which control command line editing and history
@@ -1030,32 +996,28 @@ 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* the instream == stdin & stdin is a terminal, 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 builder;
const char *prompt = prompt_arg;
- char *p;
- char *p1;
- char *rl;
- char *nline;
- char got_eof = 0;
+ char *cmd;
+
+ /* Starting a new command line. */
+ builder.used_size = 0;
/* The annotation suffix must be non-NULL. */
if (annotation_suffix == NULL)
@@ -1079,14 +1041,6 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
prompt = local_prompt;
}
- if (linebuffer == 0)
- {
- linelength = 80;
- linebuffer = (char *) xmalloc (linelength);
- }
-
- p = linebuffer;
-
/* Control-C quits instantly if typed while in this loop
since it should not wait until the user types a newline. */
immediate_quit++;
@@ -1098,6 +1052,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. */
@@ -1126,40 +1082,18 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
}
else
{
- rl = gdb_readline (prompt);
+ rl = gdb_readline_no_editing (prompt);
}
- if (annotation_level > 1 && instream == stdin)
+ cmd = handle_line_of_input (&builder, rl, repeat, annotation_suffix);
+ if (cmd == (char *) EOF)
{
- puts_unfiltered ("\n\032\032post-");
- puts_unfiltered (annotation_suffix);
- puts_unfiltered ("\n");
- }
-
- if (!rl || rl == (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 '\'. */
prompt = NULL;
}
@@ -1169,82 +1103,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
#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
- = (char *) 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. */
@@ -1906,10 +1765,6 @@ init_main (void)
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;
diff --git a/gdb/top.h b/gdb/top.h
index c450c6e..d5f1464 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -20,9 +20,10 @@
#ifndef TOP_H
#define TOP_H
+struct buffer;
+
/* From top.c. */
extern char *saved_command_line;
-extern int saved_command_line_size;
extern FILE *instream;
extern int in_user_command;
extern int confirm;
@@ -98,4 +99,8 @@ extern void set_verbose (char *, int, struct cmd_list_element *);
extern void do_restore_instream_cleanup (void *stream);
+extern char *handle_line_of_input (struct buffer *builder,
+ char *rl, int repeat,
+ char *annotation_suffix);
+
#endif
--
1.9.3