Re: [RFC] Interpreters (~final) (fwd)

Keith Seitz
2002-09-23T19:44:12Z

[-- Attachment #1: Type: TEXT/PLAIN, Size: 401 bytes --]

On Mon, 23 Sep 2002, Keith Seitz wrote:

> I'll let you know when I have something "simpler".

Ok, well, it isn't much simpler. I whacked a couple of bug fixes, docs,
and testsuites. You should be able to run mi-cli.exp with this jumbo
patch, but you will get a couple of false failures, since I did not
include the mi-support.exp changes to support async event notifications.

Good luck...
Keith

[-- Attachment #2: Type: TEXT/PLAIN, Size: 83422 bytes --]

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.263
diff -p -r1.263 Makefile.in
*** Makefile.in 20 Sep 2002 18:14:49 -0000 1.263
--- Makefile.in 23 Sep 2002 19:37:36 -0000
*************** LIBICONV = @LIBICONV@
*** 145,155 ****
# CLI sub directory definitons
#
SUBDIR_CLI_OBS = \
! cli-dump.o \
! cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
SUBDIR_CLI_SRCS = \
! cli/cli-dump.c \
! cli/cli-decode.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
cli/cli-utils.c
SUBDIR_CLI_DEPS =
SUBDIR_CLI_INITS = \
--- 145,155 ----
# CLI sub directory definitons
#
SUBDIR_CLI_OBS = \
! cli-dump.o cli-decode.o \
! cli-interp.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
SUBDIR_CLI_SRCS = \
! cli/cli-dump.c cli/cli-decode.c \
! cli/cli-interp.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
cli/cli-utils.c
SUBDIR_CLI_DEPS =
SUBDIR_CLI_INITS = \
*************** SUBDIR_CLI_UNINSTALL=
*** 167,179 ****
SUBDIR_MI_OBS = \
mi-out.o mi-console.o \
mi-cmds.o mi-cmd-var.o mi-cmd-break.o mi-cmd-stack.o \
! mi-cmd-disas.o \
mi-main.o mi-parse.o mi-getopt.o
SUBDIR_MI_SRCS = \
mi/mi-out.c mi/mi-console.c \
mi/mi-cmds.c \
mi/mi-cmd-var.c mi/mi-cmd-break.c mi/mi-cmd-stack.c \
! mi/mi-cmd-disas.c \
mi/mi-main.c mi/mi-parse.c mi/mi-getopt.c
SUBDIR_MI_DEPS =
SUBDIR_MI_INITS = \
--- 167,179 ----
SUBDIR_MI_OBS = \
mi-out.o mi-console.o \
mi-cmds.o mi-cmd-var.o mi-cmd-break.o mi-cmd-stack.o \
! mi-cmd-disas.o mi-events.o mi-interp.o \
mi-main.o mi-parse.o mi-getopt.o
SUBDIR_MI_SRCS = \
mi/mi-out.c mi/mi-console.c \
mi/mi-cmds.c \
mi/mi-cmd-var.c mi/mi-cmd-break.c mi/mi-cmd-stack.c \
! mi/mi-cmd-disas.c mi/mi-events.c mi/mi-interp.c \
mi/mi-main.c mi/mi-parse.c mi/mi-getopt.c
SUBDIR_MI_DEPS =
SUBDIR_MI_INITS = \
*************** SFILES = ada-exp.y ada-lang.c ada-typepr
*** 540,546 ****
findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c osabi.c \
inf-loop.c infcmd.c inflow.c infrun.c language.c \
kod.c kod-cisco.c \
! ui-out.c cli-out.c \
varobj.c wrapper.c \
jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
--- 540,546 ----
findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c osabi.c \
inf-loop.c infcmd.c inflow.c infrun.c language.c \
kod.c kod-cisco.c \
! ui-out.c cli-out.c interps.c \
varobj.c wrapper.c \
jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
*************** i386_tdep_h = i386-tdep.h $(osabi_h)
*** 671,676 ****
--- 671,677 ----
i387_tdep_h = i387-tdep.h
inf_loop_h = inf-loop.h
inferior_h = inferior.h $(breakpoint_h) $(target_h)
+ interps_h = interps.h
jv_lang_h = jv-lang.h
kod_h = kod.h
language_h = language.h
*************** cli_utils_h = $(srcdir)/cli/cli-utils.h
*** 747,752 ****
--- 748,754 ----
# gdb/mi/ headers
#

+ mi_h = $(srcdir)/mi/mi.h
mi_cmds_h = $(srcdir)/mi/mi-cmds.h
mi_console_h = $(srcdir)/mi/mi-console.h
mi_getopt_h = $(srcdir)/mi/mi-getopt.h
*************** COMMON_OBS = version.o blockframe.o brea
*** 841,847 ****
dbxread.o coffread.o elfread.o \
dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
c-lang.o f-lang.o \
! ui-out.o cli-out.o \
varobj.o wrapper.o \
jv-lang.o jv-valprint.o jv-typeprint.o \
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
--- 843,849 ----
dbxread.o coffread.o elfread.o \
dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
c-lang.o f-lang.o \
! ui-out.o cli-out.o interps.o \
varobj.o wrapper.o \
jv-lang.o jv-valprint.o jv-typeprint.o \
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
*************** eval.o: eval.c $(defs_h) $(gdb_string_h)
*** 1660,1666 ****
event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
$(gdb_string_h)
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
! $(terminal_h) $(event_loop_h) $(event_top_h) $(gdbcmd_h)
exec.o: exec.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) $(gdbcmd_h) \
$(language_h) $(symfile_h) $(objfiles_h) $(completer_h) $(value_h) \
$(gdb_string_h) $(gdbcore_h) $(gdb_stat_h) $(xcoffsolib_h)
--- 1662,1668 ----
event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
$(gdb_string_h)
event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
! $(terminal_h) $(event_loop_h) $(event_top_h) $(gdbcmd_h) $(interps_h)
exec.o: exec.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) $(gdbcmd_h) \
$(language_h) $(symfile_h) $(objfiles_h) $(completer_h) $(value_h) \
$(gdb_string_h) $(gdbcore_h) $(gdb_stat_h) $(xcoffsolib_h)
*************** inftarg.o: inftarg.c $(defs_h) $(frame_h
*** 1809,1814 ****
--- 1811,1818 ----
$(gdbcore_h) $(command_h) $(gdb_stat_h) $(gdb_wait_h)
infttrace.o: infttrace.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
$(gdb_string_h) $(gdb_wait_h) $(command_h) $(gdbcore_h)
+ interps.o: interps.c $(defs_h) $(gdbcmd_h) $(ui_out_h) $(event_loop_h) \
+ $(event_top_h) $(interps_h) $(gdb_h) $(wrapper_h) $(gdb_events_h)
irix4-nat.o: irix4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(regcache_h) \
$(gregset_h)
irix5-nat.o: irix5-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \
*************** cli-dump.o: $(srcdir)/cli/cli-dump.c $(d
*** 2324,2329 ****
--- 2328,2336 ----
$(cli_decode_h) $(cli_cmds_h) $(value_h) $(completer_h) \
$(cli_dump_h) $(gdb_assert_h) $(target_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-dump.c
+ cli-interp.o: $(srcdir)/cli/cli-interp.c $(defs_h) $(value_h) \
+ $(wrapper_h) $(event_top_h) $(ui_out_h) $(cli_out_h)
+ $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-interp.c
cli-script.o: $(srcdir)/cli/cli-script.c $(defs_h) $(value_h) $(language_h) \
$(ui_out_h) $(gdb_string_h) $(top_h) $(cli_cmds_h) $(cli_decode_h) \
$(cli_script_h)
*************** mi-cmds.o: $(srcdir)/mi/mi-cmds.c $(defs
*** 2441,2449 ****
--- 2448,2463 ----
mi-console.o: $(srcdir)/mi/mi-console.c $(defs_h) $(mi_console_h) \
$(gdb_string_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-console.c
+ mi-events.o: $(srcdir)/mi/mi-events.c $(defs_h) $(ui_out_h) $(interps_h) \
+ $(gdb_h) $(breakpoint_h) $(mi_h)
+ $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-events.c
mi-getopt.o: $(srcdir)/mi/mi-getopt.c $(defs_h) $(mi_getopt_h) \
$(gdb_string_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-getopt.c
+ mi-interp.o: $(srcdir)/mi/mi-interp.c $(defs_h) $(interps_h) \
+ $(event_top_h) $(event_loop_h) $(inferior_h) $(ui_out_h) \
+ $(top_h) $(mi_h) $(mi_cmds_h) $(mi_out_h) $(mi_console_h)
+ $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-interp.c
mi-main.o: $(srcdir)/mi/mi-main.c $(defs_h) $(target_h) $(inferior_h) \
$(gdb_string_h) $(top_h) $(gdbthread_h) $(mi_cmds_h) $(mi_parse_h) \
$(mi_getopt_h) $(mi_console_h) $(ui_out_h) $(mi_out_h) \
Index: cli-out.c
===================================================================
RCS file: /cvs/src/src/gdb/cli-out.c,v
retrieving revision 1.14
diff -p -r1.14 cli-out.c
*** cli-out.c 19 Mar 2002 02:51:04 -0000 1.14
--- cli-out.c 23 Sep 2002 19:37:36 -0000
*************** cli_out_new (struct ui_file *stream)
*** 365,370 ****
--- 365,379 ----
return ui_out_new (&cli_ui_out_impl, data, flags);
}

+ struct ui_file *
+ cli_out_set_stream (struct ui_out *uiout, struct ui_file *stream)
+ {
+ struct ui_out_data *data = ui_out_data (uiout);
+ struct ui_file *old = data->stream;
+ data->stream = stream;
+ return old;
+ }
+
/* standard gdb initialization hook */
void
_initialize_cli_out (void)
Index: cli-out.h
===================================================================
RCS file: /cvs/src/src/gdb/cli-out.h,v
retrieving revision 1.2
diff -p -r1.2 cli-out.h
*** cli-out.h 6 Mar 2001 08:21:06 -0000 1.2
--- cli-out.h 23 Sep 2002 19:37:36 -0000
***************
*** 23,27 ****
#define CLI_OUT_H

extern struct ui_out *cli_out_new (struct ui_file *stream);
!
#endif
--- 23,28 ----
#define CLI_OUT_H

extern struct ui_out *cli_out_new (struct ui_file *stream);
! extern struct ui_file *cli_out_set_stream (struct ui_out *uiout,
! struct ui_file *stream);
#endif
Index: event-loop.c
===================================================================
RCS file: /cvs/src/src/gdb/event-loop.c,v
retrieving revision 1.19
diff -p -r1.19 event-loop.c
*** event-loop.c 10 Sep 2002 19:53:24 -0000 1.19
--- event-loop.c 23 Sep 2002 19:37:37 -0000
***************
*** 22,27 ****
--- 22,28 ----
#include "defs.h"
#include "event-loop.h"
#include "event-top.h"
+ #include "interps.h"

#ifdef HAVE_POLL
#if defined (HAVE_POLL_H)
*************** static void create_file_handler (int fd,
*** 210,215 ****
--- 211,217 ----
static void invoke_async_signal_handler (void);
static void handle_file_event (int event_file_desc);
static int gdb_wait_for_event (void);
+ static int gdb_do_one_event (void *data);
static int check_async_ready (void);
static void async_queue_event (gdb_event * event_ptr, queue_position position);
static gdb_event *create_file_event (int fd);
*************** process_event (void)
*** 345,351 ****
can happen if there are no event sources to wait for). If an error
occurs catch_errors() which calls this function returns zero. */

! int
gdb_do_one_event (void *data)
{
/* Any events already waiting in the queue? */
--- 347,353 ----
can happen if there are no event sources to wait for). If an error
occurs catch_errors() which calls this function returns zero. */

! static int
gdb_do_one_event (void *data)
{
/* Any events already waiting in the queue? */
*************** start_event_loop (void)
*** 392,401 ****
longer any event sources registered. */
while (1)
{
! int result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
! if (result < 0)
break;
! if (result == 0)
{
/* FIXME: this should really be a call to a hook that is
interface specific, because interfaces can display the
--- 394,416 ----
longer any event sources registered. */
while (1)
{
! int gdb_result, interp_result;
!
! gdb_result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
! if (gdb_result < 0)
break;
!
! interp_result = catch_errors (interpreter_do_one_event, 0, "", RETURN_MASK_ALL);
! if (interp_result < 0)
! {
! /* FIXME - kill the interpreter */
! }
!
! /* If we long-jumped out of do_one_event, we probably
! didn't get around to resetting the prompt, which leaves
! readline in a messed-up state. Reset it here. */
!
! if (gdb_result == 0)
{
/* FIXME: this should really be a call to a hook that is
interface specific, because interfaces can display the
Index: event-top.c
===================================================================
RCS file: /cvs/src/src/gdb/event-top.c,v
retrieving revision 1.22
diff -p -r1.22 event-top.c
*** event-top.c 3 Jul 2002 20:27:12 -0000 1.22
--- event-top.c 23 Sep 2002 19:37:37 -0000
***************
*** 26,31 ****
--- 26,32 ----
#include "terminal.h" /* for job_control */
#include "event-loop.h"
#include "event-top.h"
+ #include "interps.h"
#include <signal.h>

/* For dont_repeat() */
*************** display_gdb_prompt (char *new_prompt)
*** 252,258 ****

/* When an alternative interpreter has been installed, do not
display the comand prompt. */
! if (interpreter_p)
return;

if (target_executing && sync_execution)
--- 253,259 ----

/* When an alternative interpreter has been installed, do not
display the comand prompt. */
! if (gdb_interpreter_display_prompt (new_prompt))
return;

if (target_executing && sync_execution)
*************** set_async_prompt (char *args, int from_t
*** 1113,1126 ****
PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
}

/* Set things up for readline to be invoked via the alternate
interface, i.e. via a callback function (rl_callback_read_char),
and hook up instream to the event loop. */
void
! _initialize_event_loop (void)
{
if (event_loop_p)
{
/* If the input stream is connected to a terminal, turn on
editing. */
if (ISATTY (instream))
--- 1114,1144 ----
PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
}

+ void
+ _initialize_event_loop (void)
+ {
+ /* Tell gdb to use the cli_command_loop as the main loop. */
+ if (event_loop_p && command_loop_hook == NULL)
+ command_loop_hook = cli_command_loop;
+ }
+
/* Set things up for readline to be invoked via the alternate
interface, i.e. via a callback function (rl_callback_read_char),
and hook up instream to the event loop. */
void
! gdb_setup_readline (void)
{
+ /* This function is a noop for the async case. The assumption is that
+ the async setup is ALL done in gdb_init, and we would only mess it up
+ here. The async stuff should really go away over time. */
+
if (event_loop_p)
{
+ gdb_stdout = stdio_fileopen (stdout);
+ gdb_stderr = stdio_fileopen (stderr);
+ gdb_stdlog = gdb_stderr; /* for moment */
+ gdb_stdtarg = gdb_stderr; /* for moment */
+
/* If the input stream is connected to a terminal, turn on
editing. */
if (ISATTY (instream))
*************** _initialize_event_loop (void)
*** 1153,1161 ****
register it with the event loop. */
input_fd = fileno (instream);

- /* Tell gdb to use the cli_command_loop as the main loop. */
- command_loop_hook = cli_command_loop;
-
/* Now we need to create the event sources for the input file
descriptor. */
/* At this point in time, this is the only event source that we
--- 1171,1176 ----
*************** _initialize_event_loop (void)
*** 1166,1168 ****
--- 1181,1211 ----
add_file_handler (input_fd, stdin_event_handler, 0);
}
}
+
+ /* Disable command input through the standard CLI channels. Used in
+ the suspend proc for interpreters that use the standard gdb readline
+ interface, like the cli & the mi. */
+
+ void
+ gdb_disable_readline (void)
+ {
+ if (event_loop_p)
+ {
+ /* FIXME - It is too heavyweight to delete and remake these
+ every time you run an interpreter that needs readline.
+ It is probably better to have the interpreters cache these,
+ which in turn means that this needs to be moved into interpreter
+ specific code. */
+
+ #if 0
+ ui_file_delete (gdb_stdout);
+ ui_file_delete (gdb_stderr);
+ gdb_stdlog = NULL;
+ gdb_stdtarg = NULL;
+ #endif
+
+ rl_callback_handler_remove ();
+ delete_file_handler (input_fd);
+ }
+ }
+
Index: event-top.h
===================================================================
RCS file: /cvs/src/src/gdb/event-top.h,v
retrieving revision 1.4
diff -p -r1.4 event-top.h
*** event-top.h 27 Nov 2001 04:15:09 -0000 1.4
--- event-top.h 23 Sep 2002 19:37:37 -0000
*************** struct prompts
*** 71,76 ****
--- 71,78 ----
FIXME: these should really go into top.h. */

extern void display_gdb_prompt (char *new_prompt);
+ extern void gdb_setup_readline (void);
+ extern void gdb_disable_readline (void);
extern void async_init_signals (void);
extern void set_async_editing_command (char *args, int from_tty,
struct cmd_list_element *c);
Index: interps.c
===================================================================
RCS file: interps.c
diff -N interps.c
*** interps.c 1 Jan 1970 00:00:00 -0000
--- interps.c 23 Sep 2002 19:37:37 -0000
***************
*** 0 ****
--- 1,661 ----
+ /* Manages interpreters for gdb.
+ Copyright 2000, 2002 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.
+
+ 2) The event loop insertion is probably wrong. I just inserted a
+ do_one_event alongside gdb's do_one_event. This probably will lead
+ to one or the other event loop getting starved. It would be better
+ to provide conversion functions for the gdb file handlers, and when
+ an interpreter starts up, it grabs all the gdb created file handlers
+ and inserts them into its select. This is more complicated, however,
+ and I have run out of time for now.
+ */
+
+ #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"
+
+ struct gdb_interpreter
+ {
+ char *name; /* This is the name in "-i=" and set interpreter. */
+ struct gdb_interpreter *next; /* Interpreters are stored in a linked list,
+ this is the next one... */
+ void *data; /* This is a cookie that the instance of the
+ interpreter can use, for instance to call
+ itself in hook functions */
+ int inited; /* Has the init_proc been run? */
+ struct ui_out *interpreter_out; /* 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 gdb_interpreter_procs procs;
+ int quiet_p;
+ };
+
+ /* Functions local to this file. */
+ static void initialize_interps (void);
+
+ static void set_interpreter_cmd (char *args, int from_tty,
+ struct cmd_list_element *c);
+ static void list_interpreter_cmd (char *args, int from_tty);
+ static void do_set_interpreter (int not_an_fd);
+ 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 gdb_interpreter *interp_list = NULL;
+ static struct gdb_interpreter *current_interpreter = NULL;
+
+ static int interpreter_initialized = 0;
+
+ /* gdb_new_interpreter - This allocates space for a new interpreter,
+ fills the fields from the inputs, and returns a pointer to the
+ interpreter. */
+
+ struct gdb_interpreter *
+ gdb_new_interpreter (char *name,
+ void *data,
+ struct ui_out *uiout,
+ struct gdb_interpreter_procs *procs)
+ {
+ struct gdb_interpreter *new_interp;
+
+ new_interp =
+ (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));
+
+ new_interp->name = xstrdup (name);
+ new_interp->data = data;
+ new_interp->interpreter_out = uiout;
+ new_interp->quiet_p = 0;
+ new_interp->procs.init_proc = procs->init_proc;
+ new_interp->procs.resume_proc = procs->resume_proc;
+ new_interp->procs.do_one_event_proc = procs->do_one_event_proc;
+ new_interp->procs.suspend_proc = procs->suspend_proc;
+ new_interp->procs.delete_proc = procs->delete_proc;
+ new_interp->procs.exec_proc = procs->exec_proc;
+ new_interp->procs.prompt_proc = procs->prompt_proc;
+ new_interp->inited = 0;
+
+ return new_interp;
+ }
+
+ /* Add interpreter INTERP to the gdb interpreter list. If an
+ interpreter of the same name is already on the list, then
+ the new one is NOT added, and the function returns 0. Otherwise
+ it returns 1. */
+
+ int
+ gdb_add_interpreter (struct gdb_interpreter *interp)
+ {
+ if (!interpreter_initialized)
+ initialize_interps ();
+
+ if (gdb_lookup_interpreter (interp->name) != NULL)
+ return 0;
+
+ interp->next = interp_list;
+ interp_list = interp;
+
+ return 1;
+ }
+
+ /* Looks for the interpreter INTERP in the interpreter list. If it exists,
+ runs the delete_proc, and if this is successful, the INTERP is deleted from
+ the interpreter list and the function returns 1. If the delete_proc fails, the
+ function returns -1 and the interpreter is NOT removed from the list. If the
+ interp is not found, 0 is returned. */
+
+ int
+ gdb_delete_interpreter (struct gdb_interpreter *interp)
+ {
+ struct gdb_interpreter *cur_ptr, *prev_ptr;
+
+ if (!interpreter_initialized)
+ {
+ ui_out_message (uiout, 0,
+ "You can't delete an interp before you have added one!");
+ return -1;
+ }
+
+ if (interp_list == NULL)
+ {
+ ui_out_message (uiout, 0, "No interpreters to delete.");
+ return -1;
+ }
+
+ if (interp_list->next == NULL)
+ {
+ ui_out_message (uiout, 0, "You can't delete gdb's only intepreter.");
+ return -1;
+ }
+
+ for (cur_ptr = interp_list, prev_ptr = NULL;
+ cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next)
+ {
+ if (cur_ptr == interp)
+ {
+ /* Can't currently delete the console interpreter... */
+ if (strcmp (interp->name, "console") == 0)
+ {
+ ui_out_message (uiout, 0,
+ "You can't delete the console interpreter.");
+ return -1;
+ }
+
+ /* If the interpreter is the current interpreter, switch
+ back to the console interpreter */
+
+ if (interp == current_interpreter)
+ {
+ gdb_set_interpreter (gdb_lookup_interpreter ("console"));
+ }
+
+ /* Don't delete the interpreter if its delete proc fails */
+
+ if ((interp->procs.delete_proc != NULL)
+ && (!interp->procs.delete_proc (interp->data)))
+ return -1;
+
+ if (cur_ptr == interp_list)
+ interp_list = cur_ptr->next;
+ else
+ prev_ptr->next = cur_ptr->next;
+
+ break;
+ }
+ }
+
+ if (cur_ptr == NULL)
+ return 0;
+ else
+ return 1;
+ }
+
+ /* 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
+ gdb_set_interpreter (struct gdb_interpreter *interp)
+ {
+ struct gdb_interpreter *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)
+ {
+ if (!interp->procs.init_proc (interp->data))
+ {
+ if (!gdb_set_interpreter (old_interp))
+ internal_error (__FILE__, __LINE__,
+ "Failed to initialize new interp \"%s\" %s",
+ interp->name,
+ "and could not restore old interp!\n");
+ return 0;
+ }
+ else
+ {
+ interp->inited = 1;
+ }
+ }
+ else
+ {
+ 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 (!gdb_set_interpreter (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 (!gdb_interpreter_is_quiet (interp))
+ {
+ sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
+ interp->name);
+ ui_out_text (uiout, buffer);
+ }
+ display_gdb_prompt (NULL);
+ }
+
+ return 1;
+ }
+
+ /*
+ * gdb_lookup_interpreter - Looks up the interpreter for NAME. If
+ * no such interpreter exists, return NULL, otherwise return a pointer
+ * to the interpreter.
+ */
+
+ struct gdb_interpreter *
+ gdb_lookup_interpreter (char *name)
+ {
+ struct gdb_interpreter *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 gdb_interpreter *
+ gdb_current_interpreter ()
+ {
+ return current_interpreter;
+ }
+
+ struct ui_out *
+ gdb_interpreter_ui_out (struct gdb_interpreter *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
+ gdb_current_interpreter_is_named (char *interp_name)
+ {
+ struct gdb_interpreter *current_interp = gdb_current_interpreter ();
+
+ if (current_interp)
+ return (strcmp (current_interp->name, interp_name) == 0);
+
+ return 0;
+ }
+
+ /* This is called in display_gdb_prompt.
+ If the current interpreter defines a prompt_proc, then that proc is
+ run. If the proc returns a non-zero value, display_gdb_prompt will
+ return without itself displaying the prompt. */
+
+ int
+ gdb_interpreter_display_prompt (char *new_prompt)
+ {
+ if (current_interpreter->procs.prompt_proc == NULL)
+ return 0;
+ else
+ return current_interpreter->procs.prompt_proc (current_interpreter->data,
+ new_prompt);
+ }
+
+ int
+ gdb_interpreter_is_quiet (struct gdb_interpreter *interp)
+ {
+ if (interp != NULL)
+ return interp->quiet_p;
+ else
+ return current_interpreter->quiet_p;
+ }
+
+ int
+ gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
+ {
+ int old_val = interp->quiet_p;
+ interp->quiet_p = quiet;
+ return old_val;
+ }
+
+ /* gdb_interpreter_exec - This executes COMMAND_STR in the current
+ interpreter. */
+
+ int
+ gdb_interpreter_exec (char *command_str)
+ {
+ if (current_interpreter->procs.exec_proc != NULL)
+ {
+ return current_interpreter->procs.exec_proc (current_interpreter->data,
+ command_str);
+ }
+
+ return 0;
+ }
+
+ struct gdb_interpreter_procs *
+ gdb_interpreter_get_procs (struct gdb_interpreter *interp)
+ {
+ if (interp != NULL)
+ return &interp->procs;
+
+ return &current_interpreter->procs;
+ }
+
+ void *
+ gdb_interpreter_get_data (struct gdb_interpreter *interp)
+ {
+ if (interp != NULL)
+ return interp->data;
+
+ return current_interpreter->data;
+ }
+
+ int
+ interpreter_do_one_event ()
+ {
+ if (current_interpreter->procs.do_one_event_proc == NULL)
+ return 0;
+
+ return current_interpreter->procs.do_one_event_proc (current_interpreter->
+ data);
+ }
+
+ /* 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... */
+ }
+
+ /* set_interpreter_cmd - This implements "set interpreter foo". */
+
+ static void
+ set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c)
+ {
+ struct gdb_interpreter *interp_ptr;
+
+ dont_repeat ();
+
+ if (cmd_type (c) != set_cmd)
+ return;
+
+ interp_ptr = gdb_lookup_interpreter (interpreter_p);
+ if (interp_ptr != NULL)
+ {
+ if (!gdb_set_interpreter (interp_ptr))
+ error ("\nCould not switch to interpreter \"%s\", %s%s\".\n",
+ interp_ptr->name, "reverting to interpreter \"",
+ current_interpreter->name);
+ }
+ else
+ {
+ char *bad_name = interpreter_p;
+ interpreter_p = xstrdup (current_interpreter->name);
+ error ("Could not find interpreter \"%s\".", bad_name);
+ }
+ }
+
+ /* list_interpreter_cmd - This implements "info interpreters". */
+
+ void
+ list_interpreter_cmd (char *args, int from_tty)
+ {
+ struct gdb_interpreter *interp_ptr;
+
+ ui_out_list_begin (uiout, "interpreters");
+ for (interp_ptr = interp_list; interp_ptr != NULL;
+ interp_ptr = interp_ptr->next)
+ {
+ ui_out_text (uiout, " * ");
+ ui_out_field_string (uiout, "interpreter", interp_ptr->name);
+ ui_out_text (uiout, "\n");
+ }
+ ui_out_list_end (uiout);
+ }
+
+ void
+ interpreter_exec_cmd (char *args, int from_tty)
+ {
+ struct gdb_interpreter *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 = gdb_current_interpreter ();
+
+ interp_to_use = gdb_lookup_interpreter (prules[0]);
+ if (interp_to_use == NULL)
+ error ("Could not find interpreter \"%s\".", prules[0]);
+
+ /* Temporarily set interpreters quiet */
+ old_quiet = gdb_interpreter_set_quiet (old_interp, 1);
+ use_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);
+
+ if (!gdb_set_interpreter (interp_to_use))
+ error ("Could not switch to interpreter \"%s\".", prules[0]);
+
+ for (i = 1; i < nrules; i++)
+ {
+ if (!gdb_interpreter_exec (prules[i]))
+ {
+ gdb_set_interpreter (old_interp);
+ gdb_interpreter_set_quiet (interp_to_use, old_quiet);
+ error
+ ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
+ prules[i]);
+ break;
+ }
+ }
+
+ gdb_set_interpreter (old_interp);
+ gdb_interpreter_set_quiet (interp_to_use, use_quiet);
+ gdb_interpreter_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, textlen;
+ int num_matches;
+ char **matches;
+ struct gdb_interpreter *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 "set interpreter" and "info interpreters" commands. */
+
+ 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);
+ }
Index: interps.h
===================================================================
RCS file: interps.h
diff -N interps.h
*** interps.h 1 Jan 1970 00:00:00 -0000
--- interps.h 23 Sep 2002 19:37:37 -0000
***************
*** 0 ****
--- 1,76 ----
+ /* Manages interpreters for gdb.
+ Copyright 2000,2002 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 GDB_INTERPRETER_H
+ #define GDB_INTERPRETER_H
+
+ typedef int (*interp_init_ftype) (void *data);
+ typedef int (*interp_resume_ftype) (void *data);
+ typedef int (*interp_do_one_event_ftype) (void *data);
+ typedef int (*interp_suspend_ftype) (void *data);
+ typedef int (*interp_delete_ftype) (void *data);
+ typedef int (*interp_prompt_ftype) (void *data, char *new_prompt);
+ typedef int (*interp_exec_ftype) (void *data, char *command);
+
+ struct ui_out;
+ struct gdb_interpreter;
+
+ struct gdb_interpreter_procs
+ {
+ interp_init_ftype init_proc;
+ interp_resume_ftype resume_proc;
+ interp_do_one_event_ftype do_one_event_proc;
+ interp_suspend_ftype suspend_proc;
+ interp_delete_ftype delete_proc;
+ interp_exec_ftype exec_proc;
+ interp_prompt_ftype prompt_proc;
+ };
+
+ extern struct gdb_interpreter
+ *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout,
+ struct gdb_interpreter_procs *procs);
+
+ extern int gdb_add_interpreter (struct gdb_interpreter *interp);
+ extern int gdb_delete_interpreter (struct gdb_interpreter *interp);
+ extern int gdb_set_interpreter (struct gdb_interpreter *interp);
+ extern struct gdb_interpreter *gdb_lookup_interpreter (char *name);
+ extern struct gdb_interpreter *gdb_current_interpreter ();
+ extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
+ extern int gdb_current_interpreter_is_named (char *interp_name);
+ extern int gdb_interpreter_exec (char *command_str);
+ extern int gdb_interpreter_display_prompt (char *new_prompt);
+ extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp,
+ int quiet);
+ extern int gdb_interpreter_is_quiet (struct gdb_interpreter *interp);
+ extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
+ gdb_interpreter
+ *interp);
+ extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
+ extern int interpreter_do_one_event ();
+
+ void clear_interpreter_hooks ();
+
+ /* well-known interpreters */
+ #define GDB_INTERPRETER_CONSOLE "console"
+ #define GDB_INTERPRETER_MI0 "mi0"
+ #define GDB_INTERPRETER_MI1 "mi1"
+ #define GDB_INTERPRETER_MI "mi"
+ #endif /* GDB_INTERPRETER_H */
Index: top.c
===================================================================
RCS file: /cvs/src/src/gdb/top.c,v
retrieving revision 1.67
diff -p -r1.67 top.c
*** top.c 9 Sep 2002 21:03:26 -0000 1.67
--- top.c 23 Sep 2002 19:37:37 -0000
***************
*** 63,68 ****
--- 63,69 ----
#include <ctype.h>
#include "ui-out.h"
#include "cli-out.h"
+ #include "interps.h"

/* Default command line prompt. This is overriden in some configs. */

*************** gdb_init (char *argv0)
*** 2126,2142 ****
init_ui_hook (argv0);

/* Install the default UI */
! if (!init_ui_hook)
! {
! uiout = cli_out_new (gdb_stdout);

! /* All the interpreters should have had a look at things by now.
! Initialize the selected interpreter. */
! if (interpreter_p)
! {
! fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n",
! interpreter_p);
! exit (1);
! }
! }
}
--- 2127,2152 ----
init_ui_hook (argv0);

/* Install the default UI */
! /* All the interpreters should have had a look at things by now.
! Initialize the selected interpreter. */
! {
! struct gdb_interpreter *interp;
! if (interpreter_p == NULL)
! interpreter_p = xstrdup (GDB_INTERPRETER_CONSOLE);

! interp = gdb_lookup_interpreter (interpreter_p);
!
! if (interp == NULL)
! {
! fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n",
! interpreter_p);
! exit (1);
! }
! if (!gdb_set_interpreter (interp))
! {
! fprintf_unfiltered (gdb_stderr, "Interpreter `%s' failed to initialize.\n",
! interpreter_p);
! exit (1);
! }
! }
}
Index: wrapper.c
===================================================================
RCS file: /cvs/src/src/gdb/wrapper.c,v
retrieving revision 1.14
diff -p -r1.14 wrapper.c
*** wrapper.c 31 Oct 2001 03:16:04 -0000 1.14
--- wrapper.c 23 Sep 2002 19:37:38 -0000
***************
*** 19,24 ****
--- 19,25 ----
#include "defs.h"
#include "value.h"
#include "wrapper.h"
+ #include "top.h" /* for execute_command */

/* Use this struct to pass arguments to wrapper routines. We assume
(arbitrarily) that no gdb function takes more than ten arguments. */
*************** struct captured_value_struct_elt_args
*** 51,56 ****
--- 52,63 ----
struct value **result_ptr;
};

+ struct captured_execute_command_args
+ {
+ char *command;
+ int from_tty;
+ };
+
static int wrap_parse_exp_1 (char *);

static int wrap_evaluate_expression (char *);
*************** do_captured_value_struct_elt (struct ui_
*** 331,333 ****
--- 338,357 ----
return GDB_RC_OK;
}

+ static int
+ do_captured_execute_command (struct ui_out *uiout, void *data)
+ {
+ struct captured_execute_command_args *args = data;
+ execute_command (args->command, args->from_tty);
+ return GDB_RC_OK;
+ }
+
+ enum gdb_rc
+ gdb_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);
+ }
Index: wrapper.h
===================================================================
RCS file: /cvs/src/src/gdb/wrapper.h,v
retrieving revision 1.12
diff -p -r1.12 wrapper.h
*** wrapper.h 31 Oct 2001 03:16:04 -0000 1.12
--- wrapper.h 23 Sep 2002 19:37:38 -0000
***************
*** 21,26 ****
--- 21,30 ----
#include "gdb.h"

struct value;
+ struct block;
+ struct expression;
+ struct ui_out;
+ struct type;

/* Use this struct to pass arguments to wrapper routines. */
struct gdb_wrapper_arguments;
*************** extern int gdb_value_ind (struct value *
*** 46,49 ****
--- 50,55 ----

extern int gdb_parse_and_eval_type (char *, int, struct type **);

+ extern enum gdb_rc gdb_execute_command (struct ui_out *uiout, char *command,
+ int from_tty);
#endif /* WRAPPER_H */
Index: cli/cli-interp.c
===================================================================
RCS file: cli/cli-interp.c
diff -N cli/cli-interp.c
*** cli/cli-interp.c 1 Jan 1970 00:00:00 -0000
--- cli/cli-interp.c 23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,127 ----
+ /* CLI Definitions for GDB
+ Copyright 2002 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"
+
+ /* Prototypes for the CLI Interpreter functions */
+
+ int cli_interpreter_init (void *data);
+ int cli_interpreter_resume (void *data);
+ int cli_interpreter_do_one_event (void *data);
+ int cli_interpreter_suspend (void *data);
+ int cli_interpreter_delete (void *data);
+ int cli_interpreter_exec (void *data, char *command_str);
+ int cli_interpreter_display_prompt (void *data, char *new_prompt);
+
+ /* These are the ui_out and the interpreter for the console interpreter. */
+ static struct ui_out *cli_uiout;
+ static struct gdb_interpreter *cli_interp;
+
+ /* These implement the cli out interpreter: */
+
+ int
+ cli_interpreter_init (void *data)
+ {
+ return 1;
+ }
+
+ int
+ cli_interpreter_resume (void *data)
+ {
+ /*sync_execution = 1;*/
+ gdb_setup_readline ();
+ return 1;
+ }
+
+ int
+ cli_interpreter_do_one_event (void *data)
+ {
+ return 1;
+ }
+
+ int
+ cli_interpreter_suspend (void *data)
+ {
+ gdb_disable_readline ();
+ return 1;
+ }
+
+ int
+ cli_interpreter_delete (void *data)
+ {
+ return 1;
+ }
+
+ int
+ cli_interpreter_display_prompt (void *data, char *new_prompt)
+ {
+ if (gdb_interpreter_is_quiet (NULL))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ int
+ cli_interpreter_exec (void *data, char *command_str)
+ {
+ int result;
+ struct ui_file *old_stream;
+
+ /* 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 = gdb_execute_command (cli_uiout, command_str, 1);
+ cli_out_set_stream (cli_uiout, old_stream);
+ return result;
+ }
+
+ /* standard gdb initialization hook */
+ void
+ _initialize_cli_interp (void)
+ {
+ struct gdb_interpreter_procs procs = {
+ cli_interpreter_init, /* init_proc */
+ cli_interpreter_resume, /* resume_proc */
+ cli_interpreter_do_one_event, /* do_one_event_proc */
+ cli_interpreter_suspend, /* suspend_proc */
+ cli_interpreter_delete, /* delete_proc */
+ cli_interpreter_exec, /* exec_proc */
+ cli_interpreter_display_prompt /* prompt_proc */
+ };
+
+ /* Create a default uiout builder for the CLI. */
+ cli_uiout = cli_out_new (gdb_stdout);
+ cli_interp = gdb_new_interpreter (GDB_INTERPRETER_CONSOLE, NULL, cli_uiout,
+ &procs);
+ gdb_add_interpreter (cli_interp);
+ }
Index: mi/mi-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmds.c,v
retrieving revision 1.8
diff -p -r1.8 mi-cmds.c
*** mi/mi-cmds.c 6 Mar 2001 08:21:45 -0000 1.8
--- mi/mi-cmds.c 23 Sep 2002 19:37:38 -0000
*************** struct mi_cmd mi_cmds[] =
*** 88,93 ****
--- 88,94 ----
{"gdb-show", "show %s", 0},
{"gdb-source", 0, 0},
{"gdb-version", "show version", 0},
+ {"interpreter-exec", 0, 0, mi_cmd_interpreter_exec},
{"kod-info", 0, 0},
{"kod-list", 0, 0},
{"kod-list-object-types", 0, 0},
Index: mi/mi-cmds.h
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmds.h,v
retrieving revision 1.5
diff -p -r1.5 mi-cmds.h
*** mi/mi-cmds.h 6 Mar 2001 08:21:45 -0000 1.5
--- mi/mi-cmds.h 23 Sep 2002 19:37:38 -0000
*************** extern mi_cmd_args_ftype mi_cmd_exec_ste
*** 75,80 ****
--- 75,81 ----
extern mi_cmd_args_ftype mi_cmd_exec_until;
extern mi_cmd_args_ftype mi_cmd_exec_interrupt;
extern mi_cmd_argv_ftype mi_cmd_gdb_exit;
+ extern mi_cmd_argv_ftype mi_cmd_interpreter_exec;
extern mi_cmd_argv_ftype mi_cmd_stack_info_depth;
extern mi_cmd_argv_ftype mi_cmd_stack_list_args;
extern mi_cmd_argv_ftype mi_cmd_stack_list_frames;
*************** extern int mi_debug_p;
*** 122,125 ****
--- 123,129 ----
/* Raw console output - FIXME: should this be a parameter? */
extern struct ui_file *raw_stdout;

+ extern char *mi_error_message;
+ extern void mi_error_last_message (void);
+ extern void mi_execute_command (char *cmd, int from_tty);
#endif
Index: mi/mi-console.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-console.c,v
retrieving revision 1.8
diff -p -r1.8 mi-console.c
*** mi/mi-console.c 19 Mar 2002 02:51:08 -0000 1.8
--- mi/mi-console.c 23 Sep 2002 19:37:38 -0000
*************** struct mi_console_file
*** 37,49 ****
struct ui_file *raw;
struct ui_file *buffer;
const char *prefix;
};

int mi_console_file_magic;

struct ui_file *
mi_console_file_new (struct ui_file *raw,
! const char *prefix)
{
struct ui_file *ui_file = ui_file_new ();
struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
--- 37,50 ----
struct ui_file *raw;
struct ui_file *buffer;
const char *prefix;
+ char quote;
};

int mi_console_file_magic;

struct ui_file *
mi_console_file_new (struct ui_file *raw,
! const char *prefix, char quote)
{
struct ui_file *ui_file = ui_file_new ();
struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
*************** mi_console_file_new (struct ui_file *raw
*** 51,56 ****
--- 52,58 ----
mi_console->raw = raw;
mi_console->buffer = mem_fileopen ();
mi_console->prefix = prefix;
+ mi_console->quote = quote;
set_ui_file_fputs (ui_file, mi_console_file_fputs);
set_ui_file_flush (ui_file, mi_console_file_flush);
set_ui_file_data (ui_file, mi_console, mi_console_file_delete);
*************** mi_console_raw_packet (void *data,
*** 96,104 ****
if (length_buf > 0)
{
fputs_unfiltered (mi_console->prefix, mi_console->raw);
! fputs_unfiltered ("\"", mi_console->raw);
! fputstrn_unfiltered (buf, length_buf, '"', mi_console->raw);
! fputs_unfiltered ("\"\n", mi_console->raw);
gdb_flush (mi_console->raw);
}
}
--- 98,114 ----
if (length_buf > 0)
{
fputs_unfiltered (mi_console->prefix, mi_console->raw);
! if (mi_console->quote)
! {
! fputs_unfiltered ("\"", mi_console->raw);
! fputstrn_unfiltered (buf, length_buf, mi_console->quote, mi_console->raw);
! fputs_unfiltered ("\"\n", mi_console->raw);
! }
! else
! {
! fputstrn_unfiltered (buf, length_buf, 0, mi_console->raw);
! fputs_unfiltered ("\n", mi_console->raw);
! }
gdb_flush (mi_console->raw);
}
}
Index: mi/mi-console.h
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-console.h,v
retrieving revision 1.4
diff -p -r1.4 mi-console.h
*** mi/mi-console.h 6 Mar 2001 08:21:45 -0000 1.4
--- mi/mi-console.h 23 Sep 2002 19:37:38 -0000
***************
*** 22,27 ****
#ifndef MI_CONSOLE_H
#define MI_CONSOLE_H

! extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix);

#endif
--- 22,28 ----
#ifndef MI_CONSOLE_H
#define MI_CONSOLE_H

! extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix,
! char quote);

#endif
Index: mi/mi-events.c
===================================================================
RCS file: mi/mi-events.c
diff -N mi/mi-events.c
*** mi/mi-events.c 1 Jan 1970 00:00:00 -0000
--- mi/mi-events.c 23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,120 ----
+ /* MI Event Handlers
+ Copyright 2002 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 "ui-out.h"
+ #include "interps.h"
+ #include "gdb.h"
+ #include "breakpoint.h"
+
+ #include "mi.h"
+
+ void
+ mi_interp_stack_changed_hook (void)
+ {
+ struct ui_out *saved_ui_out = uiout;
+ struct mi_out *tmp_mi_out;
+
+ if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+ uiout = gdb_interpreter_ui_out (mi0_interp);
+ else
+ uiout = gdb_interpreter_ui_out (mi_interp);
+
+ ui_out_list_begin (uiout, "MI_HOOK_RESULT");
+ ui_out_field_string (uiout, "HOOK_TYPE", "stack_changed");
+ ui_out_list_end (uiout);
+ uiout = saved_ui_out;
+ }
+
+ static void
+ event_notify (const char *string, ...)
+ {
+ va_list args;
+
+ if (!gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ {
+ va_start (args, string);
+ vfprintf_unfiltered (mi_event_channel, string, args);
+ va_end (args);
+ gdb_flush (mi_event_channel);
+ }
+ }
+
+ /* breakpoint-create,number=bpnum */
+ void
+ mi_create_breakpoint (int bpnum)
+ {
+ event_notify ("breakpoint-create,number=\"%d\"", bpnum);
+ }
+
+ void
+ mi_modify_breakpoint (int bpnum)
+ {
+ event_notify ("breakpoint-modify,number=\"%d\"", bpnum);
+ }
+
+ void
+ mi_delete_breakpoint (int bpnum)
+ {
+ event_notify ("breakpoint-delete,number=\"%d\"", bpnum);
+ }
+
+ void
+ mi_create_tracepoint (int tpnum)
+ {
+ event_notify ("tracepoint-create,number=\"%d\"", tpnum);
+ }
+
+ void
+ mi_modify_tracepoint (int tpnum)
+ {
+ event_notify ("tracepoint-modify,number=\"%d\"", tpnum);
+ }
+
+ void
+ mi_delete_tracepoint (int tpnum)
+ {
+ event_notify ("tracepoint-delete,number=\"%d\"", tpnum);
+ }
+
+ void
+ mi_architecture_changed (void)
+ {
+ event_notify ("architecture-changed");
+ }
+
+ void
+ mi_target_changed (void)
+ {
+ event_notify ("target-changed");
+ }
+
+ void
+ mi_selected_frame_level_changed (int level)
+ {
+ event_notify ("selected-frame-level-changed,level=\"%d\"", level);
+ }
+
+ void
+ mi_context_changed (int thread_id)
+ {
+ event_notify ("context-changed,thread=\"%d\"", thread_id);
+ }
Index: mi/mi-interp.c
===================================================================
RCS file: mi/mi-interp.c
diff -N mi/mi-interp.c
*** mi/mi-interp.c 1 Jan 1970 00:00:00 -0000
--- mi/mi-interp.c 23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,477 ----
+ /* MI Interpreter Definitions and Commands
+ Copyright 2002 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 "event-top.h"
+ #include "event-loop.h"
+ #include "inferior.h"
+ #include "ui-out.h"
+ #include "top.h"
+
+ #include "mi.h"
+ #include "mi-cmds.h"
+ #include "mi-out.h"
+ #include "mi-console.h"
+
+ /* MI's output channels */
+ struct ui_file *mi_stdout;
+ struct ui_file *mi_stderr;
+ struct ui_file *mi_stdlog;
+ struct ui_file *mi_stdtarg;
+ struct ui_file *mi_event_channel;
+
+ /* This is the interpreter for the mi... */
+ struct gdb_interpreter *mi0_interp;
+ struct gdb_interpreter *mi1_interp;
+ struct gdb_interpreter *mi_interp;
+
+ /* These are the interpreter setup, etc. functions for the MI interpreter */
+ static int mi_interpreter_init (void *data);
+ static int mi_interpreter_resume (void *data);
+ static int mi_interpreter_do_one_event (void *data);
+ static int mi_interpreter_suspend (void *data);
+ static int mi_interpreter_delete (void *data);
+ static int mi_interpreter_exec (void *data, char *command);
+ static int mi_interpreter_prompt (void *data, char *new_prompt);
+
+ 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 mi0_command_loop (void);
+ static void mi1_command_loop (void);
+
+ static void mi_insert_notify_hooks (void);
+ static void mi_remove_notify_hooks (void);
+
+ static struct gdb_events mi_event_handlers =
+ {
+ mi_create_breakpoint,
+ mi_delete_breakpoint,
+ mi_modify_breakpoint,
+ mi_create_tracepoint,
+ mi_delete_tracepoint,
+ mi_modify_tracepoint,
+ mi_architecture_changed,
+ mi_target_changed,
+ mi_selected_frame_level_changed
+ };
+
+ static int
+ mi_interpreter_init (void *data)
+ {
+ static struct gdb_events handlers;
+
+ /* 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_stdout = mi_console_file_new (raw_stdout, "~", '"');
+ mi_stderr = mi_console_file_new (raw_stdout, "&", '"');
+ mi_stdlog = mi_stderr;
+ mi_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+ mi_event_channel = mi_console_file_new (raw_stdout, "=", 0);
+
+ return 1;
+ }
+
+ static int
+ mi_interpreter_resume (void *data)
+ {
+ /* As per hack note in mi_interpreter_init, swap in the output channels... */
+
+ gdb_setup_readline ();
+ mi_register_gdbarch_swap ();
+
+ 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_stdout;
+ /* Route error and log output through the MI */
+ gdb_stderr = mi_stderr;
+ gdb_stdlog = mi_stdlog;
+ /* Route target output through the MI. */
+ gdb_stdtarg = mi_stdtarg;
+
+ /* Replace all the hooks that we know about. There really needs to be a better way
+ of doing this... */
+ clear_interpreter_hooks ();
+ set_gdb_event_hooks (&mi_event_handlers);
+
+ show_load_progress = mi_load_progress;
+
+ /* If we're _the_ interpreter, take control. */
+ if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+ command_loop_hook = mi0_command_loop;
+ else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ command_loop_hook = mi1_command_loop;
+ else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI))
+ command_loop_hook = mi1_command_loop;
+ else
+ return 0;
+
+ return 1;
+ }
+
+ static int
+ mi_interpreter_suspend (void *data)
+ {
+ gdb_disable_readline ();
+ return 1;
+ }
+
+ static int
+ mi_interpreter_delete (void *data)
+ {
+ return 1;
+ }
+
+ static int
+ mi_interpreter_exec (void *data, char *command)
+ {
+ mi_execute_command_wrapper (command);
+ return 1;
+ }
+
+ static int
+ mi_interpreter_prompt (void *data, char *new_prompt)
+ {
+ return 1;
+ }
+
+ static int
+ mi_do_one_event (void *data)
+ {
+ return 1;
+ }
+
+ 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 gdb_interpreter *interp_to_use;
+ enum mi_cmd_result result = MI_CMD_DONE;
+ int i;
+ struct gdb_interpreter_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 = gdb_lookup_interpreter (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;
+ }
+
+ procs = gdb_interpreter_get_procs (interp_to_use);
+ if (!procs->exec_proc)
+ {
+ 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 (procs->exec_proc (gdb_interpreter_get_data (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
+ mi0_command_loop (void)
+ {
+ mi_command_loop (0);
+ }
+
+ static void
+ mi1_command_loop (void)
+ {
+ mi_command_loop (1);
+ }
+
+ 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)
+ {
+ struct gdb_interpreter_procs procs =
+ {
+ mi_interpreter_init, /* init_proc */
+ mi_interpreter_resume, /* resume_proc */
+ NULL, /* do_one_event_proc */
+ mi_interpreter_suspend, /* suspend_proc */
+ mi_interpreter_delete, /* delete_proc */
+ mi_interpreter_exec, /* exec_proc */
+ mi_interpreter_prompt /* prompt_proc */
+ };
+
+ /* Create MI0 interpreter */
+ if (mi0_interp == NULL)
+ {
+ mi0_interp =
+ gdb_new_interpreter (GDB_INTERPRETER_MI0, NULL, mi_out_new (0),
+ &procs);
+ if (mi0_interp == NULL)
+ error
+ ("Couldn't allocate a new interpreter for the mi0 interpreter\n");
+ if (gdb_add_interpreter (mi0_interp) != 1)
+ error ("Couldn't add the mi0 interpreter to gdb.\n");
+ }
+
+ /* Create MI1 interpreter */
+ if (mi1_interp == NULL)
+ {
+ mi1_interp =
+ gdb_new_interpreter (GDB_INTERPRETER_MI1, NULL, mi_out_new (1),
+ &procs);
+ if (mi1_interp == NULL)
+ error
+ ("Couldn't allocate a new interpreter for the mi1 interpreter\n");
+ if (gdb_add_interpreter (mi1_interp) != 1)
+ error ("Couldn't add the mi1 interpreter to gdb.\n");
+ }
+
+ /* Create MI2 interpreter */
+ if (mi_interp == NULL)
+ {
+ mi_interp =
+ gdb_new_interpreter (GDB_INTERPRETER_MI, NULL, mi_out_new (2),
+ &procs);
+ if (mi_interp == NULL)
+ error
+ ("Couldn't allocate a new interpreter for the mi interpreter\n");
+ if (gdb_add_interpreter (mi_interp) != 1)
+ error ("Couldn't add the mi interpreter to gdb.\n");
+ }
+ }
Index: mi/mi-main.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
retrieving revision 1.31
diff -p -r1.31 mi-main.c
*** mi/mi-main.c 11 Sep 2002 21:49:04 -0000 1.31
--- mi/mi-main.c 23 Sep 2002 19:37:38 -0000
***************
*** 33,38 ****
--- 33,39 ----
#include "mi-console.h"
#include "ui-out.h"
#include "mi-out.h"
+ #include "interps.h"
#include "event-loop.h"
#include "event-top.h"
#include "gdbcore.h" /* for write_memory() */
*************** struct ui_file *raw_stdout;
*** 77,103 ****
/* The token of the last asynchronous command */
static char *last_async_command;
static char *previous_async_command;
! static char *mi_error_message;
static char *old_regs;

extern void _initialize_mi_main (void);
! static char *mi_input (char *);
! static void mi_execute_command (char *cmd, int from_tty);
static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);

static void mi_execute_cli_command (const char *cli, char *args);
static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
- static void mi_execute_command_wrapper (char *cmd);

void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);

static int register_changed_p (int regnum);
static int get_register (int regnum, int format);
! static 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);

/* FIXME: these should go in some .h file, but infcmd.c doesn't have a
corresponding .h file. These wrappers will be obsolete anyway, once
--- 78,102 ----
/* The token of the last asynchronous command */
static char *last_async_command;
static char *previous_async_command;
! char *mi_error_message;
static char *old_regs;

extern void _initialize_mi_main (void);
! void mi_execute_command (char *cmd, int from_tty);
static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);

static void mi_execute_cli_command (const char *cli, char *args);
static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);

void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);

static int register_changed_p (int regnum);
static int get_register (int regnum, int format);
! 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);

/* FIXME: these should go in some .h file, but infcmd.c doesn't have a
corresponding .h file. These wrappers will be obsolete anyway, once
*************** static void mi_load_progress (const char
*** 105,110 ****
--- 104,118 ----
extern void interrupt_target_command_wrapper (char *, int);
extern void return_command_wrapper (char *, int);

+ /* A helper function which will set mi_error_message to error_last_message. */
+ void
+ mi_error_last_message (void)
+ {
+ char *s = error_last_message ();
+ xasprintf (&mi_error_message, s);
+ xfree (s);
+ }
+
/* Command implementations. FIXME: Is this libgdb? No. This is the MI
layer that calls libgdb. Any operation used in the below should be
formalized. */
*************** mi_execute_command (char *cmd, int from_
*** 1165,1171 ****
struct mi_parse *command;
struct captured_mi_execute_command_args args;
struct ui_out *saved_uiout = uiout;
! int result, rc;

/* This is to handle EOF (^D). We just quit gdb. */
/* FIXME: we should call some API function here. */
--- 1173,1179 ----
struct mi_parse *command;
struct captured_mi_execute_command_args args;
struct ui_out *saved_uiout = uiout;
! int result;

/* This is to handle EOF (^D). We just quit gdb. */
/* FIXME: we should call some API function here. */
*************** mi_cmd_execute (struct mi_parse *parse)
*** 1273,1284 ****
}
}

- static void
- mi_execute_command_wrapper (char *cmd)
- {
- mi_execute_command (cmd, stdin == instream);
- }
-
/* FIXME: This is just a hack so we can get some extra commands going.
We don't want to channel things through the CLI, but call libgdb directly */
/* Use only for synchronous commands */
--- 1281,1286 ----
*************** mi_exec_async_cli_cmd_continuation (stru
*** 1381,1393 ****
do_exec_cleanups (ALL_CLEANUPS);
}

! static char *
! mi_input (char *buf)
! {
! return gdb_readline (NULL);
! }
!
! static void
mi_load_progress (const char *section_name,
unsigned long sent_so_far,
unsigned long total_section,
--- 1383,1389 ----
do_exec_cleanups (ALL_CLEANUPS);
}

! void
mi_load_progress (const char *section_name,
unsigned long sent_so_far,
unsigned long total_section,
*************** mi_load_progress (const char *section_na
*** 1456,1573 ****
}
}

! static void
! mi_command_loop (int mi_version)
! {
! /* 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;
!
! /* 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 void
! mi0_command_loop (void)
! {
! mi_command_loop (0);
! }
!
! static void
! mi1_command_loop (void)
! {
! mi_command_loop (1);
! }
!
! static void
! setup_architecture_data (void)
{
/* don't trust REGISTER_BYTES to be zero. */
old_regs = xmalloc (REGISTER_BYTES + 1);
memset (old_regs, 0, REGISTER_BYTES + 1);
}

- static void
- mi_init_ui (char *arg0)
- {
- /* Eventually this will contain code that takes control of the
- console. */
- }
-
void
! _initialize_mi_main (void)
{
- if (interpreter_p == NULL)
- return;
-
- /* If we're _the_ interpreter, take control. */
- if (strcmp (interpreter_p, "mi0") == 0)
- command_loop_hook = mi0_command_loop;
- else if (strcmp (interpreter_p, "mi") == 0
- || strcmp (interpreter_p, "mi1") == 0)
- command_loop_hook = mi1_command_loop;
- else
- return;
-
- init_ui_hook = mi_init_ui;
- setup_architecture_data ();
register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
! register_gdbarch_swap (NULL, 0, setup_architecture_data);
! 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: Should we notify main that we are here as a possible
! interpreter? */
}
--- 1452,1468 ----
}
}

! void
! mi_setup_architecture_data (void)
{
/* don't trust REGISTER_BYTES to be zero. */
old_regs = xmalloc (REGISTER_BYTES + 1);
memset (old_regs, 0, REGISTER_BYTES + 1);
}

void
! mi_register_gdbarch_swap (void)
{
register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
! register_gdbarch_swap (NULL, 0, mi_setup_architecture_data);
}
Index: mi/mi.h
===================================================================
RCS file: mi/mi.h
diff -N mi/mi.h
*** mi/mi.h 1 Jan 1970 00:00:00 -0000
--- mi/mi.h 23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,59 ----
+ /* MI Internal Functions
+ Copyright 2002 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_H
+ #define MI_H
+ /* The mi interpreters. */
+ struct ui_file;
+ struct breakpoint;
+ struct gdb_interpreter;
+ extern struct gdb_interpreter *mi_interp;
+ extern struct gdb_interpreter *mi0_interp;
+
+ extern void mi_setup_architecture_data (void);
+ extern void mi_register_gdbarch_swap (void);
+
+ /* MI's output channels */
+ extern struct ui_file *mi_stdout;
+ extern struct ui_file *mi_stderr;
+ extern struct ui_file *mi_stdlog;
+ extern struct ui_file *mi_stdtarg;
+ extern struct ui_file *mi_event_channel;
+
+ /* Events/Hooks */
+ 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);
+ extern void mi_interp_frame_changed_hook (int new_frame_number);
+ extern void mi_interp_context_hook (int thread_id);
+
+ extern void mi_create_breakpoint (int bpnum);
+ extern void mi_modify_breakpoint (int bpnum);
+ extern void mi_delete_breakpoint (int bpnum);
+ extern void mi_create_tracepoint (int bpnum);
+ extern void mi_modify_tracepoint (int bpnum);
+ extern void mi_delete_tracepoint (int bpnum);
+ extern void mi_architecture_changed (void);
+ extern void mi_target_changed (void);
+ extern void mi_selected_frame_level_changed (int level);
+ extern void mi_context_changed (int thread_id);
+ #endif /* MI_H */