aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/Makefile.in2
-rw-r--r--gdb/cli/cli-interp.c138
-rw-r--r--gdb/interps.c484
-rw-r--r--gdb/interps.h73
-rw-r--r--gdb/mi/mi-interp.c412
-rw-r--r--gdb/mi/mi-main.h33
6 files changed, 1141 insertions, 1 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4a67706..c5de436 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -145,7 +145,7 @@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
#
SUBDIR_CLI_OBS = \
cli-dump.o \
- cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
+ cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o \
cli-interp.o
SUBDIR_CLI_SRCS = \
cli/cli-dump.c \
diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
new file mode 100644
index 0000000..e2116e7
--- /dev/null
+++ b/gdb/cli/cli-interp.c
@@ -0,0 +1,138 @@
+/* CLI Definitions for GDB, the GNU debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "interps.h"
+#include "wrapper.h"
+#include "event-top.h"
+#include "ui-out.h"
+#include "cli-out.h"
+#include "top.h" /* for "execute_command" */
+#include "gdb_string.h"
+
+struct ui_out *cli_uiout;
+
+/* These are the ui_out and the interpreter for the console interpreter. */
+
+/* Longjmp-safe wrapper for "execute_command" */
+static int do_captured_execute_command (struct ui_out *uiout, void *data);
+static enum gdb_rc safe_execute_command (struct ui_out *uiout, char *command,
+ int from_tty);
+struct captured_execute_command_args
+{
+ char *command;
+ int from_tty;
+};
+
+/* These implement the cli out interpreter: */
+
+static void *
+cli_interpreter_init (void)
+{
+ return NULL;
+}
+
+static int
+cli_interpreter_resume (void *data)
+{
+ /*sync_execution = 1; */
+ gdb_setup_readline ();
+ return 1;
+}
+
+static int
+cli_interpreter_suspend (void *data)
+{
+ gdb_disable_readline ();
+ return 1;
+}
+
+/* Don't display the prompt if we are set quiet. */
+static int
+cli_interpreter_display_prompt_p (void *data)
+{
+ if (interp_quiet_p (NULL))
+ return 0;
+ else
+ return 1;
+}
+
+static int
+cli_interpreter_exec (void *data, const char *command_str)
+{
+ int result;
+ struct ui_file *old_stream;
+
+ /* FIXME: cagney/2003-02-01: Need to const char *propogate
+ safe_execute_command. */
+ char *str = strcpy (alloca (strlen (command_str) + 1), command_str);
+
+ /* gdb_stdout could change between the time cli_uiout was initialized
+ and now. Since we're probably using a different interpreter which has
+ a new ui_file for gdb_stdout, use that one instead of the default.
+
+ It is important that it gets reset everytime, since the user could
+ set gdb to use a different interpreter. */
+ old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+ result = safe_execute_command (cli_uiout, str, 1);
+ cli_out_set_stream (cli_uiout, old_stream);
+ return result;
+}
+
+static int
+do_captured_execute_command (struct ui_out *uiout, void *data)
+{
+ struct captured_execute_command_args *args =
+ (struct captured_execute_command_args *) data;
+ execute_command (args->command, args->from_tty);
+ return GDB_RC_OK;
+}
+
+static enum gdb_rc
+safe_execute_command (struct ui_out *uiout, char *command, int from_tty)
+{
+ struct captured_execute_command_args args;
+ args.command = command;
+ args.from_tty = from_tty;
+ return catch_exceptions (uiout, do_captured_execute_command, &args,
+ NULL, RETURN_MASK_ALL);
+}
+
+
+/* standard gdb initialization hook */
+void
+_initialize_cli_interp (void)
+{
+ static const struct interp_procs procs = {
+ cli_interpreter_init, /* init_proc */
+ cli_interpreter_resume, /* resume_proc */
+ cli_interpreter_suspend, /* suspend_proc */
+ cli_interpreter_exec, /* exec_proc */
+ cli_interpreter_display_prompt_p /* prompt_proc_p */
+ };
+ struct interp *cli_interp;
+
+ /* Create a default uiout builder for the CLI. */
+ cli_uiout = cli_out_new (gdb_stdout);
+ cli_interp = interp_new (INTERP_CONSOLE, NULL, cli_uiout, &procs);
+
+ interp_add (cli_interp);
+}
diff --git a/gdb/interps.c b/gdb/interps.c
new file mode 100644
index 0000000..551f416
--- /dev/null
+++ b/gdb/interps.c
@@ -0,0 +1,484 @@
+/* Manages interpreters for GDB, the GNU debugger.
+
+ Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This is just a first cut at separating out the "interpreter"
+ functions of gdb into self-contained modules. There are a couple
+ of open areas that need to be sorted out:
+
+ 1) The interpreter explicitly contains a UI_OUT, and can insert itself
+ into the event loop, but it doesn't explicitly contain hooks for readline.
+ I did this because it seems to me many interpreters won't want to use
+ the readline command interface, and it is probably simpler to just let
+ them take over the input in their resume proc. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "ui-out.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "interps.h"
+#include "completer.h"
+#include "gdb_string.h"
+#include "gdb-events.h"
+#include "gdb_assert.h"
+#include "top.h" /* For command_loop. */
+
+struct interp
+{
+ /* This is the name in "-i=" and set interpreter. */
+ const char *name;
+
+ /* Interpreters are stored in a linked list, this is the next
+ one... */
+ struct interp *next;
+
+ /* This is a cookie that an instance of the interpreter can use.
+ This is a bit confused right now as the exact initialization
+ sequence for it, and how it relates to the interpreter's uiout
+ object is a bit confused. */
+ void *data;
+
+ /* Has the init_proc been run? */
+ int inited;
+
+ /* This is the ui_out used to collect results for this interpreter.
+ It can be a formatter for stdout, as is the case for the console
+ & mi outputs, or it might be a result formatter. */
+ struct ui_out *interpreter_out;
+
+ const struct interp_procs *procs;
+ int quiet_p;
+};
+
+/* Functions local to this file. */
+static void initialize_interps (void);
+static char **interpreter_completer (char *text, char *word);
+
+/* The magic initialization routine for this module. */
+
+void _initialize_interpreter (void);
+
+/* Variables local to this file: */
+
+static struct interp *interp_list = NULL;
+static struct interp *current_interpreter = NULL;
+
+static int interpreter_initialized = 0;
+
+/* interp_new - This allocates space for a new interpreter,
+ fills the fields from the inputs, and returns a pointer to the
+ interpreter. */
+struct interp *
+interp_new (const char *name, void *data, struct ui_out *uiout,
+ const struct interp_procs *procs)
+{
+ struct interp *new_interp;
+
+ new_interp = XMALLOC (struct interp);
+
+ new_interp->name = xstrdup (name);
+ new_interp->data = data;
+ new_interp->interpreter_out = uiout;
+ new_interp->quiet_p = 0;
+ new_interp->procs = procs;
+ new_interp->inited = 0;
+
+ return new_interp;
+}
+
+/* Add interpreter INTERP to the gdb interpreter list. The
+ interpreter must not have previously been added. */
+void
+interp_add (struct interp *interp)
+{
+ if (!interpreter_initialized)
+ initialize_interps ();
+
+ gdb_assert (interp_lookup (interp->name) == NULL);
+
+ interp->next = interp_list;
+ interp_list = interp;
+}
+
+/* This sets the current interpreter to be INTERP. If INTERP has not
+ been initialized, then this will also run the init proc. If the
+ init proc is successful, return 1, if it fails, set the old
+ interpreter back in place and return 0. If we can't restore the
+ old interpreter, then raise an internal error, since we are in
+ pretty bad shape at this point. */
+int
+interp_set (struct interp *interp)
+{
+ struct interp *old_interp = current_interpreter;
+ int first_time = 0;
+
+
+ char buffer[64];
+
+ if (current_interpreter != NULL)
+ {
+ do_all_continuations ();
+ ui_out_flush (uiout);
+ if (current_interpreter->procs->suspend_proc
+ && !current_interpreter->procs->suspend_proc (current_interpreter->
+ data))
+ {
+ error ("Could not suspend interpreter \"%s\"\n",
+ current_interpreter->name);
+ }
+ }
+ else
+ {
+ first_time = 1;
+ }
+
+ current_interpreter = interp;
+
+ /* We use interpreter_p for the "set interpreter" variable, so we need
+ to make sure we have a malloc'ed copy for the set command to free. */
+ if (interpreter_p != NULL
+ && strcmp (current_interpreter->name, interpreter_p) != 0)
+ {
+ xfree (interpreter_p);
+
+ interpreter_p = xstrdup (current_interpreter->name);
+ }
+
+ uiout = interp->interpreter_out;
+
+ /* Run the init proc. If it fails, try to restore the old interp. */
+
+ if (!interp->inited)
+ {
+ if (interp->procs->init_proc != NULL)
+ {
+ interp->data = interp->procs->init_proc ();
+ }
+ interp->inited = 1;
+ }
+
+ /* Clear out any installed interpreter hooks/event handlers. */
+ clear_interpreter_hooks ();
+
+ if (interp->procs->resume_proc != NULL
+ && (!interp->procs->resume_proc (interp->data)))
+ {
+ if (!interp_set (old_interp))
+ internal_error (__FILE__, __LINE__,
+ "Failed to initialize new interp \"%s\" %s",
+ interp->name, "and could not restore old interp!\n");
+ return 0;
+ }
+
+ /* Finally, put up the new prompt to show that we are indeed here.
+ Also, display_gdb_prompt for the console does some readline magic
+ which is needed for the console interpreter, at least... */
+
+ if (!first_time)
+ {
+ if (!interp_quiet_p (interp))
+ {
+ sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
+ interp->name);
+ ui_out_text (uiout, buffer);
+ }
+ display_gdb_prompt (NULL);
+ }
+
+ return 1;
+}
+
+/* interp_lookup - Looks up the interpreter for NAME. If no such
+ interpreter exists, return NULL, otherwise return a pointer to the
+ interpreter. */
+struct interp *
+interp_lookup (const char *name)
+{
+ struct interp *interp;
+
+ if (name == NULL || strlen (name) == 0)
+ return NULL;
+
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ {
+ if (strcmp (interp->name, name) == 0)
+ return interp;
+ }
+
+ return NULL;
+}
+
+/* Returns the current interpreter. */
+
+struct ui_out *
+interp_ui_out (struct interp *interp)
+{
+ if (interp != NULL)
+ return interp->interpreter_out;
+
+ return current_interpreter->interpreter_out;
+}
+
+/* Returns true if the current interp is the passed in name. */
+int
+current_interp_named_p (const char *interp_name)
+{
+ if (current_interpreter)
+ return (strcmp (current_interpreter->name, interp_name) == 0);
+
+ return 0;
+}
+
+/* This is called in display_gdb_prompt. If the proc returns a zero
+ value, display_gdb_prompt will return without displaying the
+ prompt. */
+int
+current_interp_display_prompt_p (void)
+{
+ if (current_interpreter == NULL
+ || current_interpreter->procs->prompt_proc_p == NULL)
+ return 0;
+ else
+ return current_interpreter->procs->prompt_proc_p (current_interpreter->
+ data);
+}
+
+/* Run the current command interpreter's main loop. */
+void
+current_interp_command_loop (void)
+{
+ /* Somewhat messy. For the moment prop up all the old ways of
+ selecting the command loop. `command_loop_hook' should be
+ deprecated. */
+ if (command_loop_hook != NULL)
+ command_loop_hook ();
+ else if (current_interpreter != NULL
+ && current_interpreter->procs->command_loop_proc != NULL)
+ current_interpreter->procs->command_loop_proc (current_interpreter->data);
+ else
+ command_loop ();
+}
+
+int
+interp_quiet_p (struct interp *interp)
+{
+ if (interp != NULL)
+ return interp->quiet_p;
+ else
+ return current_interpreter->quiet_p;
+}
+
+int
+interp_set_quiet (struct interp *interp, int quiet)
+{
+ int old_val = interp->quiet_p;
+ interp->quiet_p = quiet;
+ return old_val;
+}
+
+/* interp_exec - This executes COMMAND_STR in the current
+ interpreter. */
+int
+interp_exec_p (struct interp *interp)
+{
+ return interp->procs->exec_proc != NULL;
+}
+
+int
+interp_exec (struct interp *interp, const char *command_str)
+{
+ if (interp->procs->exec_proc != NULL)
+ {
+ return interp->procs->exec_proc (interp->data, command_str);
+ }
+ return 0;
+}
+
+/* A convenience routine that nulls out all the
+ common command hooks. Use it when removing your interpreter in its
+ suspend proc. */
+void
+clear_interpreter_hooks ()
+{
+ init_ui_hook = 0;
+ print_frame_info_listing_hook = 0;
+ /*print_frame_more_info_hook = 0; */
+ query_hook = 0;
+ warning_hook = 0;
+ create_breakpoint_hook = 0;
+ delete_breakpoint_hook = 0;
+ modify_breakpoint_hook = 0;
+ interactive_hook = 0;
+ registers_changed_hook = 0;
+ readline_begin_hook = 0;
+ readline_hook = 0;
+ readline_end_hook = 0;
+ register_changed_hook = 0;
+ memory_changed_hook = 0;
+ context_hook = 0;
+ target_wait_hook = 0;
+ call_command_hook = 0;
+ error_hook = 0;
+ error_begin_hook = 0;
+ command_loop_hook = 0;
+ clear_gdb_event_hooks ();
+}
+
+/* This is a lazy init routine, called the first time
+ the interpreter module is used. I put it here just in case, but I haven't
+ thought of a use for it yet. I will probably bag it soon, since I don't
+ think it will be necessary. */
+static void
+initialize_interps (void)
+{
+ interpreter_initialized = 1;
+ /* Don't know if anything needs to be done here... */
+}
+
+void
+interpreter_exec_cmd (char *args, int from_tty)
+{
+ struct interp *old_interp, *interp_to_use;
+ char **prules = NULL;
+ char **trule = NULL;
+ unsigned int nrules;
+ unsigned int i;
+ int old_quiet, use_quiet;
+
+ prules = buildargv (args);
+ if (prules == NULL)
+ {
+ error ("unable to parse arguments");
+ }
+
+ nrules = 0;
+ if (prules != NULL)
+ {
+ for (trule = prules; *trule != NULL; trule++)
+ {
+ nrules++;
+ }
+ }
+
+ if (nrules < 2)
+ error ("usage: interpreter-exec <interpreter> [ <command> ... ]");
+
+ old_interp = current_interpreter;
+
+ interp_to_use = interp_lookup (prules[0]);
+ if (interp_to_use == NULL)
+ error ("Could not find interpreter \"%s\".", prules[0]);
+
+ /* Temporarily set interpreters quiet */
+ old_quiet = interp_set_quiet (old_interp, 1);
+ use_quiet = interp_set_quiet (interp_to_use, 1);
+
+ if (!interp_set (interp_to_use))
+ error ("Could not switch to interpreter \"%s\".", prules[0]);
+
+ for (i = 1; i < nrules; i++)
+ {
+ if (!interp_exec (interp_to_use, prules[i]))
+ {
+ interp_set (old_interp);
+ interp_set_quiet (interp_to_use, old_quiet);
+ error ("error in command: \"%s\".", prules[i]);
+ break;
+ }
+ }
+
+ interp_set (old_interp);
+ interp_set_quiet (interp_to_use, use_quiet);
+ interp_set_quiet (old_interp, old_quiet);
+}
+
+/* List the possible interpreters which could complete the given text. */
+static char **
+interpreter_completer (char *text, char *word)
+{
+ int alloced = 0;
+ int textlen;
+ int num_matches;
+ char **matches;
+ struct interp *interp;
+
+ /* We expect only a very limited number of interpreters, so just
+ allocate room for all of them. */
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ ++alloced;
+ matches = (char **) xmalloc (alloced * sizeof (char *));
+
+ num_matches = 0;
+ textlen = strlen (text);
+ for (interp = interp_list; interp != NULL; interp = interp->next)
+ {
+ if (strncmp (interp->name, text, textlen) == 0)
+ {
+ matches[num_matches] =
+ (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
+ if (word == text)
+ strcpy (matches[num_matches], interp->name);
+ else if (word > text)
+ {
+ /* Return some portion of interp->name */
+ strcpy (matches[num_matches], interp->name + (word - text));
+ }
+ else
+ {
+ /* Return some of text plus interp->name */
+ strncpy (matches[num_matches], word, text - word);
+ matches[num_matches][text - word] = '\0';
+ strcat (matches[num_matches], interp->name);
+ }
+ ++num_matches;
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ xfree (matches);
+ matches = NULL;
+ }
+ else if (num_matches < alloced)
+ {
+ matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
+ * sizeof (char *)));
+ matches[num_matches] = NULL;
+ }
+
+ return matches;
+}
+
+/* This just adds the "interpreter-exec" command. */
+void
+_initialize_interpreter (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_cmd ("interpreter-exec", class_support,
+ interpreter_exec_cmd,
+ "Execute a command in an interpreter. It takes two arguments:\n\
+The first argument is the name of the interpreter to use.\n\
+The second argument is the command to execute.\n", &cmdlist);
+ set_cmd_completer (c, interpreter_completer);
+}
diff --git a/gdb/interps.h b/gdb/interps.h
new file mode 100644
index 0000000..21362f4
--- /dev/null
+++ b/gdb/interps.h
@@ -0,0 +1,73 @@
+/* Manages interpreters for GDB, the GNU debugger.
+
+ Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+ Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef INTERPS_H
+#define INTERPS_H
+
+struct ui_out;
+struct interp;
+
+extern int interp_resume (struct interp *interp);
+extern int interp_suspend (struct interp *interp);
+extern int interp_prompt_p (struct interp *interp);
+extern int interp_exec_p (struct interp *interp);
+extern int interp_exec (struct interp *interp, const char *command);
+extern int interp_quiet_p (struct interp *interp);
+
+typedef void *(interp_init_ftype) (void);
+typedef int (interp_resume_ftype) (void *data);
+typedef int (interp_suspend_ftype) (void *data);
+typedef int (interp_prompt_p_ftype) (void *data);
+typedef int (interp_exec_ftype) (void *data, const char *command);
+typedef int (interp_command_loop_ftype) (void *data);
+
+struct interp_procs
+{
+ interp_init_ftype *init_proc;
+ interp_resume_ftype *resume_proc;
+ interp_suspend_ftype *suspend_proc;
+ interp_exec_ftype *exec_proc;
+ interp_prompt_p_ftype *prompt_proc_p;
+ interp_command_loop_ftype *command_loop_proc;
+};
+
+extern struct interp *interp_new (const char *name, void *data,
+ struct ui_out *uiout,
+ const struct interp_procs *procs);
+extern void interp_add (struct interp *interp);
+extern int interp_set (struct interp *interp);
+extern struct interp *interp_lookup (const char *name);
+extern struct ui_out *interp_ui_out (struct interp *interp);
+
+extern int current_interp_named_p (const char *name);
+extern int current_interp_display_prompt_p (void);
+extern void current_interp_command_loop (void);
+
+extern void clear_interpreter_hooks ();
+
+/* well-known interpreters */
+#define INTERP_CONSOLE "console"
+#define INTERP_MI1 "mi1"
+#define INTERP_MI "mi"
+
+#endif
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
new file mode 100644
index 0000000..bf5873a
--- /dev/null
+++ b/gdb/mi/mi-interp.c
@@ -0,0 +1,412 @@
+/* MI Interpreter Definitions and Commands for GDB, the GNU debugger.
+
+ Copyright 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "interps.h"
+#include "event-top.h"
+#include "event-loop.h"
+#include "inferior.h"
+#include "ui-out.h"
+#include "top.h"
+
+#include "mi-main.h"
+#include "mi-cmds.h"
+#include "mi-out.h"
+#include "mi-console.h"
+
+struct mi_interp
+{
+ /* MI's output channels */
+ struct ui_file *out;
+ struct ui_file *err;
+ struct ui_file *log;
+ struct ui_file *targ;
+ struct ui_file *event_channel;
+
+ /* This is the interpreter for the mi... */
+ struct interp *mi2_interp;
+ struct interp *mi1_interp;
+ struct interp *mi_interp;
+};
+
+/* These are the interpreter setup, etc. functions for the MI interpreter */
+static void mi_execute_command_wrapper (char *cmd);
+static void mi_command_loop (int mi_version);
+static char *mi_input (char *);
+
+/* These are hooks that we put in place while doing interpreter_exec
+ so we can report interesting things that happened "behind the mi's
+ back" in this command */
+static int mi_interp_query_hook (const char *ctlstr, va_list ap);
+static char *mi_interp_read_one_line_hook (char *prompt, int repeat,
+ char *anno);
+
+static void mi2_command_loop (void);
+static void mi1_command_loop (void);
+
+static void mi_insert_notify_hooks (void);
+static void mi_remove_notify_hooks (void);
+
+static void *
+mi_interpreter_init (void)
+{
+ struct mi_interp *mi = XMALLOC (struct mi_interp);
+
+ /* Why is this a part of the mi architecture? */
+
+ mi_setup_architecture_data ();
+
+ /* HACK: We need to force stdout/stderr to point at the console. This avoids
+ any potential side effects caused by legacy code that is still
+ using the TUI / fputs_unfiltered_hook. So we set up output channels for
+ this now, and swap them in when we are run. */
+
+ raw_stdout = stdio_fileopen (stdout);
+
+ /* Create MI channels */
+ mi->out = mi_console_file_new (raw_stdout, "~", '"');
+ mi->err = mi_console_file_new (raw_stdout, "&", '"');
+ mi->log = mi->err;
+ mi->targ = mi_console_file_new (raw_stdout, "@", '"');
+ mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
+
+ return mi;
+}
+
+static int
+mi_interpreter_resume (void *data)
+{
+ struct mi_interp *mi = data;
+ /* As per hack note in mi_interpreter_init, swap in the output channels... */
+
+ gdb_setup_readline ();
+
+ if (event_loop_p)
+ {
+ /* These overwrite some of the initialization done in
+ _intialize_event_loop. */
+ call_readline = gdb_readline2;
+ input_handler = mi_execute_command_wrapper;
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ async_command_editing_p = 0;
+ /* FIXME: This is a total hack for now. PB's use of the MI implicitly
+ relies on a bug in the async support which allows asynchronous
+ commands to leak through the commmand loop. The bug involves
+ (but is not limited to) the fact that sync_execution was
+ erroneously initialized to 0. Duplicate by initializing it
+ thus here... */
+ sync_execution = 0;
+ }
+
+ gdb_stdout = mi->out;
+ /* Route error and log output through the MI */
+ gdb_stderr = mi->err;
+ gdb_stdlog = mi->log;
+ /* Route target output through the MI. */
+ gdb_stdtarg = mi->targ;
+
+ /* Replace all the hooks that we know about. There really needs to
+ be a better way of doing this... */
+ clear_interpreter_hooks ();
+
+ show_load_progress = mi_load_progress;
+
+ /* If we're _the_ interpreter, take control. */
+ if (current_interp_named_p (INTERP_MI1))
+ command_loop_hook = mi1_command_loop;
+ else if (current_interp_named_p (INTERP_MI))
+ command_loop_hook = mi2_command_loop;
+ else
+ return 0;
+
+ return 1;
+}
+
+static int
+mi_interpreter_suspend (void *data)
+{
+ gdb_disable_readline ();
+ return 1;
+}
+
+static int
+mi_interpreter_exec (void *data, const char *command)
+{
+ char *tmp = alloca (strlen (command) + 1);
+ strcpy (tmp, command);
+ mi_execute_command_wrapper (tmp);
+ return 1;
+}
+
+/* Never display the default gdb prompt in mi case. */
+static int
+mi_interpreter_prompt_p (void *data)
+{
+ return 0;
+}
+
+static void
+mi_interpreter_exec_continuation (struct continuation_arg *arg)
+{
+ bpstat_do_actions (&stop_bpstat);
+ if (!target_executing)
+ {
+ fputs_unfiltered ("*stopped", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ do_exec_cleanups (ALL_CLEANUPS);
+ }
+ else if (target_can_async_p ())
+ {
+ add_continuation (mi_interpreter_exec_continuation, NULL);
+ }
+}
+
+enum mi_cmd_result
+mi_cmd_interpreter_exec (char *command, char **argv, int argc)
+{
+ struct interp *interp_to_use;
+ enum mi_cmd_result result = MI_CMD_DONE;
+ int i;
+ struct interp_procs *procs;
+
+ if (argc < 2)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
+ return MI_CMD_ERROR;
+ }
+
+ interp_to_use = interp_lookup (argv[0]);
+ if (interp_to_use == NULL)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: could not find interpreter \"%s\"",
+ argv[0]);
+ return MI_CMD_ERROR;
+ }
+
+ if (!interp_exec_p (interp_to_use))
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
+ argv[0]);
+ return MI_CMD_ERROR;
+ }
+
+ /* Insert the MI out hooks, making sure to also call the interpreter's hooks
+ if it has any. */
+ /* KRS: We shouldn't need this... Events should be installed and they should
+ just ALWAYS fire something out down the MI channel... */
+ mi_insert_notify_hooks ();
+
+ /* Now run the code... */
+
+ for (i = 1; i < argc; i++)
+ {
+ char *buff = NULL;
+ /* Do this in a cleaner way... We want to force execution to be
+ asynchronous for commands that run the target. */
+ if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
+ {
+ int len = strlen (argv[i]);
+ buff = xmalloc (len + 2);
+ memcpy (buff, argv[i], len);
+ buff[len] = '&';
+ buff[len + 1] = '\0';
+ }
+
+ /* We had to set sync_execution = 0 for the mi (well really for Project
+ Builder's use of the mi - particularly so interrupting would work.
+ But for console commands to work, we need to initialize it to 1 -
+ since that is what the cli expects - before running the command,
+ and then set it back to 0 when we are done. */
+ sync_execution = 1;
+ if (interp_exec (interp_to_use, argv[i]) < 0)
+ {
+ mi_error_last_message ();
+ result = MI_CMD_ERROR;
+ break;
+ }
+ xfree (buff);
+ do_exec_error_cleanups (ALL_CLEANUPS);
+ sync_execution = 0;
+ }
+
+ mi_remove_notify_hooks ();
+
+ /* Okay, now let's see if the command set the inferior going...
+ Tricky point - have to do this AFTER resetting the interpreter, since
+ changing the interpreter will clear out all the continuations for
+ that interpreter... */
+
+ if (target_can_async_p () && target_executing)
+ {
+ fputs_unfiltered ("^running\n", raw_stdout);
+ add_continuation (mi_interpreter_exec_continuation, NULL);
+ }
+
+ return result;
+}
+
+/*
+ * mi_insert_notify_hooks - This inserts a number of hooks that are meant to produce
+ * async-notify ("=") MI messages while running commands in another interpreter
+ * using mi_interpreter_exec. The canonical use for this is to allow access to
+ * the gdb CLI interpreter from within the MI, while still producing MI style output
+ * when actions in the CLI command change gdb's state.
+*/
+
+static void
+mi_insert_notify_hooks (void)
+{
+ query_hook = mi_interp_query_hook;
+}
+
+static void
+mi_remove_notify_hooks ()
+{
+ query_hook = NULL;
+}
+
+static int
+mi_interp_query_hook (const char *ctlstr, va_list ap)
+{
+ return 1;
+}
+
+static char *
+mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
+{
+ static char buff[256];
+ printf_unfiltered ("=read-one-line,prompt=\"%s\"\n", prompt);
+ gdb_flush (gdb_stdout);
+ (void) fgets (buff, sizeof (buff), stdin);
+ buff[(strlen (buff) - 1)] = 0;
+ return buff;
+}
+
+static void
+output_control_change_notification (char *notification)
+{
+ printf_unfiltered ("^");
+ printf_unfiltered ("%s\n", notification);
+ gdb_flush (gdb_stdout);
+}
+
+static void
+mi_execute_command_wrapper (char *cmd)
+{
+ mi_execute_command (cmd, stdin == instream);
+}
+
+static void
+mi1_command_loop (void)
+{
+ mi_command_loop (1);
+}
+
+static void
+mi2_command_loop (void)
+{
+ mi_command_loop (2);
+}
+
+static void
+mi_command_loop (int mi_version)
+{
+#if 0
+ /* HACK: Force stdout/stderr to point at the console. This avoids
+ any potential side effects caused by legacy code that is still
+ using the TUI / fputs_unfiltered_hook */
+ raw_stdout = stdio_fileopen (stdout);
+ /* Route normal output through the MIx */
+ gdb_stdout = mi_console_file_new (raw_stdout, "~", '"');
+ /* Route error and log output through the MI */
+ gdb_stderr = mi_console_file_new (raw_stdout, "&", '"');
+ gdb_stdlog = gdb_stderr;
+ /* Route target output through the MI. */
+ gdb_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+ /* HACK: Poke the ui_out table directly. Should we be creating a
+ mi_out object wired up to the above gdb_stdout / gdb_stderr? */
+ uiout = mi_out_new (mi_version);
+ /* HACK: Override any other interpreter hooks. We need to create a
+ real event table and pass in that. */
+ init_ui_hook = 0;
+ /* command_loop_hook = 0; */
+ print_frame_info_listing_hook = 0;
+ query_hook = 0;
+ warning_hook = 0;
+ create_breakpoint_hook = 0;
+ delete_breakpoint_hook = 0;
+ modify_breakpoint_hook = 0;
+ interactive_hook = 0;
+ registers_changed_hook = 0;
+ readline_begin_hook = 0;
+ readline_hook = 0;
+ readline_end_hook = 0;
+ register_changed_hook = 0;
+ memory_changed_hook = 0;
+ context_hook = 0;
+ target_wait_hook = 0;
+ call_command_hook = 0;
+ error_hook = 0;
+ error_begin_hook = 0;
+ show_load_progress = mi_load_progress;
+#endif
+ /* Turn off 8 bit strings in quoted output. Any character with the
+ high bit set is printed using C's octal format. */
+ sevenbit_strings = 1;
+ /* Tell the world that we're alive */
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ if (!event_loop_p)
+ simplified_command_loop (mi_input, mi_execute_command);
+ else
+ start_event_loop ();
+}
+
+static char *
+mi_input (char *buf)
+{
+ return gdb_readline (NULL);
+}
+
+void
+_initialize_mi_interp (void)
+{
+ static const struct interp_procs procs =
+ {
+ mi_interpreter_init, /* init_proc */
+ mi_interpreter_resume, /* resume_proc */
+ mi_interpreter_suspend, /* suspend_proc */
+ mi_interpreter_exec, /* exec_proc */
+ mi_interpreter_prompt_p /* prompt_proc_p */
+ };
+
+ /* Create MI1 interpreter */
+ interp_add (interp_new (INTERP_MI1, NULL, mi_out_new (1), &procs));
+
+ interp_add (interp_new (INTERP_MI, NULL, mi_out_new (3), &procs));
+}
diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h
new file mode 100644
index 0000000..8e504c6
--- /dev/null
+++ b/gdb/mi/mi-main.h
@@ -0,0 +1,33 @@
+/* MI Internal Functions for GDB, the GNU debugger.
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef MI_MAIN_H
+#define MI_MAIN_H
+
+extern void mi_setup_architecture_data (void);
+
+extern void mi_load_progress (const char *section_name,
+ unsigned long sent_so_far,
+ unsigned long total_section,
+ unsigned long total_sent,
+ unsigned long grand_total);
+#endif
+